void SV_initServer(int maxConnections, unsigned short port, socketProtocol_t protocol, networkStatus_t *status)
{
	if (currentNetworkMode() != NETWORK_MODE_LOCAL)
	{
		if (status)
		{
			status->error = NETWORK_ERROR_UNAUTHORIZED_ACTION;
			status->socketError = 0;
		}
		return;
	}

	if (!createHostSocket(maxConnections, port, protocol, status))
	{
		return;
	}

	if (status)
	{
		status->error = NETWORK_ERROR_NONE;
		status->socketError = 0;
	}
}
Пример #2
0
int pptp_manager(int argc, char **argv)
{
        int firstOpen = -1;
        int ctrl_pid;
        socklen_t addrsize;

        int hostSocket;
        fd_set connSet;

        int rc, sig_fd;

        rc = sigpipe_create();
        if (rc < 0) {
                syslog(LOG_ERR, "MGR: unable to setup sigchld pipe!");
                syslog_perror("sigpipe_create");
                exit(-1);
        }
        
        sigpipe_assign(SIGCHLD);
        sigpipe_assign(SIGTERM);
        sig_fd = sigpipe_fd();

        /* openlog() not required, done in pptpd.c */

        syslog(LOG_INFO, "MGR: Manager process started");

        if (!pptp_delegate) {
                syslog(LOG_INFO, "MGR: Maximum of %d connections available", 
                       pptp_connections);
        }

        /* Connect the host socket and activate it for listening */
        if (createHostSocket(&hostSocket) < 0) {
                syslog(LOG_ERR, "MGR: Couldn't create host socket");
                syslog_perror("createHostSocket");
                exit(-1);
        }

        while (1) {
                int max_fd;
                FD_ZERO(&connSet);
                if (pptp_delegate) {
                        FD_SET(hostSocket, &connSet);
                } else {
                        firstOpen = slot_find_empty();
                        if (firstOpen == -1) {
                                syslog(LOG_ERR, "MGR: No free connection slots or IPs - no more clients can connect!");
                        } else {
                                FD_SET(hostSocket, &connSet);
                        }
                }
                max_fd = hostSocket;

                FD_SET(sig_fd, &connSet);
                if (max_fd < sig_fd) max_fd = sig_fd;

                while (1) {
                        if (select(max_fd + 1, &connSet, NULL, NULL, NULL) != -1) break;
                        if (errno == EINTR) continue;
                        syslog(LOG_ERR, "MGR: Error with manager select()!");
                        syslog_perror("select");
                        exit(-1);
                }

                if (FD_ISSET(sig_fd, &connSet)) {       /* SIGCHLD */
                        int signum = sigpipe_read();
                        if (signum == SIGCHLD)
                                sigchld_responder(signum);
                        else if (signum == SIGTERM)
                        {
                                if (!keep_connections) sigterm_responder();
                                    return signum;
                        }
                }

                if (FD_ISSET(hostSocket, &connSet)) {   /* A call came! */
                        int clientSocket;
                        struct sockaddr_in client_addr;

                        /* Accept call and launch PPTPCTRL */
                        addrsize = sizeof(client_addr);
                        clientSocket = accept(hostSocket, (struct sockaddr *) &client_addr, &addrsize);

#ifdef HAVE_LIBWRAP
                        if (clientSocket != -1) {
                                struct request_info r;
                                request_init(&r, RQ_DAEMON, "pptpd", RQ_FILE, clientSocket, NULL);
                                fromhost(&r);
                                if (!hosts_access(&r)) {
                                        /* send a permission denied message? this is a tcp wrapper
                                         * type deny so probably best to just drop it immediately like
                                         * this, as tcp wrappers usually do.
                                         */
                                        close(clientSocket);
                                        /* this would never be file descriptor 0, so use it as a error
                                         * value
                                         */
                                        clientSocket = 0;
                                }
                        }
#endif
                        if (clientSocket == -1) {
                                /* accept failed, but life goes on... */
                                syslog(LOG_ERR, "MGR: accept() failed");
                                syslog_perror("accept");
                        } else if (clientSocket != 0) {
                                fd_set rfds;
                                struct timeval tv;
                                struct pptp_header ph;

                                /* TODO: this select below prevents
                                   other connections from being
                                   processed during the wait for the
                                   first data packet from the
                                   client. */

                                /*
                                 * DOS protection: get a peek at the first packet
                                 * and do some checks on it before we continue.
                                 * A 10 second timeout on the first packet seems reasonable
                                 * to me,  if anything looks sus,  throw it away.
                                 */

                                FD_ZERO(&rfds);
                                FD_SET(clientSocket, &rfds);
                                tv.tv_sec = pptp_stimeout;
                                tv.tv_usec = 0;
                                if (select(clientSocket + 1, &rfds, NULL, NULL, &tv) <= 0) {
                                        syslog(LOG_ERR, "MGR: dropped slow initial connection");
                                        close(clientSocket);
                                        continue;
                                }

                                if (recv(clientSocket, &ph, sizeof(ph), MSG_PEEK) !=
                                                sizeof(ph)) {
                                        syslog(LOG_ERR, "MGR: dropped small initial connection");
                                        close(clientSocket);
                                        continue;
                                }

                                ph.length = ntohs(ph.length);
                                ph.pptp_type = ntohs(ph.pptp_type);
                                ph.magic = ntohl(ph.magic);
                                ph.ctrl_type = ntohs(ph.ctrl_type);

                                if (ph.length <= 0 || ph.length > PPTP_MAX_CTRL_PCKT_SIZE) {
                                        syslog(LOG_WARNING, "MGR: initial packet length %d outside "
                                                        "(0 - %d)",  ph.length, PPTP_MAX_CTRL_PCKT_SIZE);
                                        goto dos_exit;
                                }

                                if (ph.magic != PPTP_MAGIC_COOKIE) {
                                        syslog(LOG_WARNING, "MGR: initial packet bad magic");
                                        goto dos_exit;
                                }

                                if (ph.pptp_type != PPTP_CTRL_MESSAGE) {
                                        syslog(LOG_WARNING, "MGR: initial packet has bad type");
                                        goto dos_exit;
                                }

                                if (ph.ctrl_type != START_CTRL_CONN_RQST) {
                                        syslog(LOG_WARNING, "MGR: initial packet has bad ctrl type "
                                                        "0x%x", ph.ctrl_type);
                dos_exit:
                                        close(clientSocket);
                                        continue;
                                }

#ifndef HAVE_FORK
                                switch (ctrl_pid = vfork()) {
#else
                                switch (ctrl_pid = fork()) {
#endif
                                case -1:        /* error */
                                        syslog(LOG_ERR, "MGR: fork() failed launching " PPTP_CTRL_BIN);
                                        close(clientSocket);
                                        break;

                                case 0: /* child */
                                        close(hostSocket);
                                        if (pptp_debug)
                                                syslog(LOG_DEBUG, "MGR: Launching " PPTP_CTRL_BIN " to handle client");
                                        connectCall(clientSocket, !pptp_delegate ? firstOpen : 0);
                                        _exit(1);
                                        /* NORETURN */
                                default:        /* parent */
                                        close(clientSocket);
                                        unique_call_id += MAX_CALLS_PER_TCP_LINK;
                                        if (!pptp_delegate)
                                                slot_set_pid(firstOpen, ctrl_pid);
                                        break;
                                }
                        }
                }               /* FD_ISSET(hostSocket, &connSet) */
        }                       /* while (1) */
}                               /* pptp_manager() */

/*
 * Author: Kevin Thayer
 * 
 * This creates a socket to listen on, sets the max # of pending connections and 
 * various other options.
 * 
 * Returns the fd of the host socket.
 * 
 * The function return values are:
 * 0 for sucessful
 * -1 for bad socket creation
 * -2 for bad socket options
 * -3 for bad bind
 * -4 for bad listen
 */
static int createHostSocket(int *hostSocket)
{
        int opt = 1;
        struct sockaddr_in address;
#ifdef HAVE_GETSERVBYNAME
        struct servent *serv;
#endif

        /* create the master socket and check it worked */
        if ((*hostSocket = vrf_socket(vrf, AF_INET, SOCK_STREAM, 0)) <= 0)
                return -1;

        /* set master socket to allow daemon to be restarted with connections active  */
        if (setsockopt(*hostSocket, SOL_SOCKET, SO_REUSEADDR,
                       (char *) &opt, sizeof(opt)) < 0)
                return -2;

        /* set up socket */
        memset(&address, 0, sizeof(address));
        address.sin_family = AF_INET;
        if(bindaddr)
                address.sin_addr.s_addr = inet_addr(bindaddr);
        else
                address.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_GETSERVBYNAME
        if ((serv = getservbyname("pptp", "tcp")) != NULL) {
                address.sin_port = serv->s_port;
        } else
#endif
                address.sin_port = htons(PPTP_PORT);

        /* bind the socket to the pptp port */
        if (bind(*hostSocket, (struct sockaddr *) &address, sizeof(address)) < 0)
                return -3;

        /* minimal backlog to avoid DoS */
        if (listen(*hostSocket, 3) < 0)
                return -4;

        return 0;
}