Ejemplo n.º 1
0
unsigned char *buildsrcrte(struct in_addr dstaddr, struct in_addr routes[],
                  int numroutes, int ptr, size_t *len)
{
    int x;
    unsigned char *opts, *p;

    *len = (numroutes + 1) * sizeof(struct in_addr) + 4;

    if (numroutes > 8)
        bye("Bad number of routes passed to buildsrcrte().");

    opts = (unsigned char *) safe_malloc(*len);
    p = opts;

    zmem(opts, *len);

    *p++ = 0x01; /* IPOPT_NOP, for alignment */
    *p++ = 0x83; /* IPOPT_LSRR */
    *p++ = (char) (*len - 1); /* subtract nop */
    *p++ = (char) ptr;

    for (x = 0; x < numroutes; x++) {
        memcpy(p, &routes[x], sizeof(routes[x]));
        p += sizeof(routes[x]);
    }

    memcpy(p, &dstaddr, sizeof(dstaddr));

    return opts;
}
Ejemplo n.º 2
0
/* Depending on verbosity, print a message that a connection was established. */
static void connect_report(nsock_iod nsi)
{
    union sockaddr_u peer;
    zmem(&peer, sizeof(peer.storage));

    nsi_getlastcommunicationinfo(nsi, NULL, NULL, NULL,
        &peer.sockaddr, sizeof(peer.storage));

    if (o.verbose) {
#ifdef HAVE_OPENSSL
        if (nsi_checkssl(nsi)) {
            X509 *cert;
            X509_NAME *subject;
            char digest_buf[SHA1_STRING_LENGTH + 1];
            char *fp;

            loguser("SSL connection to %s:%hu.", inet_socktop(&peer), nsi_peerport(nsi));

            cert = SSL_get_peer_certificate((SSL *) nsi_getssl(nsi));
            ncat_assert(cert != NULL);

            subject = X509_get_subject_name(cert);
            if (subject != NULL) {
                char buf[256];
                int n;

                n = X509_NAME_get_text_by_NID(subject, NID_organizationName, buf, sizeof(buf));
                if (n >= 0 && n <= sizeof(buf) - 1)
                    loguser_noprefix(" %s", buf);
            }

            loguser_noprefix("\n");

            fp = ssl_cert_fp_str_sha1(cert, digest_buf, sizeof(digest_buf));
            ncat_assert(fp == digest_buf);
            loguser("SHA-1 fingerprint: %s\n", digest_buf);
        } else {
#if HAVE_SYS_UN_H
            if (peer.sockaddr.sa_family == AF_UNIX)
                loguser("Connected to %s.\n", peer.un.sun_path);
            else
#endif
                loguser("Connected to %s:%hu.\n", inet_socktop(&peer), nsi_peerport(nsi));
        }
#else
#if HAVE_SYS_UN_H
        if (peer.sockaddr.sa_family == AF_UNIX)
            loguser("Connected to %s.\n", peer.un.sun_path);
        else
#endif
            loguser("Connected to %s:%hu.\n", inet_socktop(&peer), nsi_peerport(nsi));
#endif
    }
}
Ejemplo n.º 3
0
/* this function will return in what format the target
 * host is specified. It will return:
 * 1 - for ipv4,
 * 2 - for ipv6,
 * -1 - for hostname
 * this has to work even if there is no IPv6 support on
 * local system, proxy may support it.
 */
int getaddrfamily(const char *addr)
{
    int ret;
    struct addrinfo hint, *info = 0;

    if (strchr(addr,':'))
      return 2;

    zmem(&hint,sizeof(hint));
    hint.ai_family = AF_UNSPEC;
    hint.ai_flags = AI_NUMERICHOST;
    ret = getaddrinfo(addr, 0, &hint, &info);
    if (ret)
        return -1;
    freeaddrinfo(info);
    return 1;
}
Ejemplo n.º 4
0
/* Convert session data to a neat hexdump logfile */
static int ncat_hexdump(int logfd, const char *data, int len)
{
    const char *p = data;
    char c;
    int i;
    char bytestr[4] = { 0 };
    char addrstr[10] = { 0 };
    char hexstr[16 * 3 + 5] = { 0 };
    char charstr[16 * 1 + 5] = { 0 };
    char outstr[80] = { 0 };

    /* FIXME: needs to be audited closer */
    for (i = 1; i <= len; i++) {
        if (i % 16 == 1) {
            /* Hex address output */
            Snprintf(addrstr, sizeof(addrstr), "%.4x", (u_int) (p - data));
        }

        c = *p;

        /* If the character isn't printable. Control characters, etc. */
        if (isprint((int) (unsigned char) c) == 0)
            c = '.';

        /* hex for output */
        Snprintf(bytestr, sizeof(bytestr), "%02X ", (unsigned char) *p);
        strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);

        /* char for output */
        Snprintf(bytestr, sizeof(bytestr), "%c", c);
        strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1);

        if (i % 16 == 0) {
            /* neatly formatted output */
            Snprintf(outstr, sizeof(outstr), "[%4.4s]   %-50.50s  %s\n",
                     addrstr, hexstr, charstr);

            Write(logfd, outstr, strlen(outstr));
            zmem(outstr, sizeof(outstr));

            hexstr[0] = 0;
            charstr[0] = 0;
        } else if (i % 8 == 0) {
            /* cat whitespaces where necessary */
            strncat(hexstr, "  ", sizeof(hexstr) - strlen(hexstr) - 1);
            strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1);
        }

        /* get the next byte */
        p++;
    }

    /* if there's still data left in the buffer, print it */
    if (strlen(hexstr) > 0) {
        Snprintf(outstr, sizeof(outstr), "[%4.4s]   %-50.50s  %s\n",
                    addrstr, hexstr, charstr);

        Write(logfd, outstr, strlen(outstr));
        zmem(outstr, sizeof(outstr));
    }

    return 1;
}
Ejemplo n.º 5
0
int ncat_connect(void)
{
    nsock_pool mypool;
    int rc;

    /* Unless explicitely asked not to do so, ncat uses the
     * fallback nsock engine to maximize compatibility between
     * operating systems and the different use cases.
     */
    if (!o.nsock_engine)
        nsock_set_default_engine("select");

    /* Create an nsock pool */
    if ((mypool = nsp_new(NULL)) == NULL)
        bye("Failed to create nsock_pool.");

    if (o.debug >= 6)
        nsock_set_loglevel(mypool, NSOCK_LOG_DBG_ALL);
    else if (o.debug >= 3)
        nsock_set_loglevel(mypool, NSOCK_LOG_DBG);
    else if (o.debug >= 1)
        nsock_set_loglevel(mypool, NSOCK_LOG_INFO);
    else
        nsock_set_loglevel(mypool, NSOCK_LOG_ERROR);

    /* Allow connections to broadcast addresses. */
    nsp_setbroadcast(mypool, 1);

#ifdef HAVE_OPENSSL
    set_ssl_ctx_options((SSL_CTX *) nsp_ssl_init(mypool));
#endif

    if (httpconnect.storage.ss_family == AF_UNSPEC
             && socksconnect.storage.ss_family == AF_UNSPEC) {
        /* A non-proxy connection. Create an iod for a new socket. */
        cs.sock_nsi = nsi_new(mypool, NULL);
        if (cs.sock_nsi == NULL)
            bye("Failed to create nsock_iod.");

        if (nsi_set_hostname(cs.sock_nsi, o.target) == -1)
            bye("Failed to set hostname on iod.");

#if HAVE_SYS_UN_H
        /* For DGRAM UNIX socket we have to use source socket */
        if (o.af == AF_UNIX && o.udp)
        {
            if (srcaddr.storage.ss_family != AF_UNIX) {
                char *tmp_name = NULL;
                /* If no source socket was specified, we have to create temporary one. */
                if ((tmp_name = tempnam(NULL, "ncat.")) == NULL)
                    bye("Failed to create name for temporary DGRAM source Unix domain socket (tempnam).");

                srcaddr.un.sun_family = AF_UNIX;
                strncpy(srcaddr.un.sun_path, tmp_name, sizeof(srcaddr.un.sun_path));
                free (tmp_name);
            }
            nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, SUN_LEN((struct sockaddr_un *)&srcaddr.storage));

            if (o.verbose)
                loguser("[%s] used as source DGRAM Unix domain socket.\n", srcaddr.un.sun_path);
        }
        else
#endif
        if (srcaddr.storage.ss_family != AF_UNSPEC)
            nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, sizeof(srcaddr.storage));

        if (o.numsrcrtes) {
            unsigned char *ipopts = NULL;
            size_t ipoptslen = 0;

            if (o.af != AF_INET)
                bye("Sorry, -g can only currently be used with IPv4.");
            ipopts = buildsrcrte(targetss.in.sin_addr, o.srcrtes, o.numsrcrtes, o.srcrteptr, &ipoptslen);

            nsi_set_ipoptions(cs.sock_nsi, ipopts, ipoptslen);
            free(ipopts); /* Nsock has its own copy */
        }

#if HAVE_SYS_UN_H
        if (o.af == AF_UNIX) {
            if (o.udp) {
                nsock_connect_unixsock_datagram(mypool, cs.sock_nsi, connect_handler, NULL,
                                                &targetss.sockaddr,
                                                SUN_LEN((struct sockaddr_un *)&targetss.sockaddr));
            } else {
                nsock_connect_unixsock_stream(mypool, cs.sock_nsi, connect_handler, o.conntimeout,
                                              NULL, &targetss.sockaddr,
                                              SUN_LEN((struct sockaddr_un *)&targetss.sockaddr));
            }
        } else
#endif
        if (o.udp) {
            nsock_connect_udp(mypool, cs.sock_nsi, connect_handler,
                              NULL, &targetss.sockaddr, targetsslen,
                              inet_port(&targetss));
        }
#ifdef HAVE_OPENSSL
        else if (o.sctp && o.ssl) {
            nsock_connect_ssl(mypool, cs.sock_nsi, connect_handler,
                              o.conntimeout, NULL,
                              &targetss.sockaddr, targetsslen,
                              IPPROTO_SCTP, inet_port(&targetss),
                              NULL);
        }
#endif
        else if (o.sctp) {
            nsock_connect_sctp(mypool, cs.sock_nsi, connect_handler,
                              o.conntimeout, NULL,
                              &targetss.sockaddr, targetsslen,
                              inet_port(&targetss));
        }
#ifdef HAVE_OPENSSL
        else if (o.ssl) {
            nsock_connect_ssl(mypool, cs.sock_nsi, connect_handler,
                              o.conntimeout, NULL,
                              &targetss.sockaddr, targetsslen,
                              IPPROTO_TCP, inet_port(&targetss),
                              NULL);
        }
#endif
        else {
            nsock_connect_tcp(mypool, cs.sock_nsi, connect_handler,
                              o.conntimeout, NULL,
                              &targetss.sockaddr, targetsslen,
                              inet_port(&targetss));
        }
    } else {
        /* A proxy connection. */
        static int connect_socket;
        int len;
        char *line;
        size_t n;

        if (httpconnect.storage.ss_family != AF_UNSPEC) {
            connect_socket = do_proxy_http();
            if (connect_socket == -1)
                return 1;
        } else if (socksconnect.storage.ss_family != AF_UNSPEC) {
            struct socket_buffer stateful_buf;
            struct socks4_data socks4msg;
            char socksbuf[8];

            connect_socket = do_connect(SOCK_STREAM);
            if (connect_socket == -1) {
                loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno()));
                return 1;
            }

            socket_buffer_init(&stateful_buf, connect_socket);

            if (o.verbose) {
                loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetss),
                    inet_port(&targetss));
            }

            /* Fill the socks4_data struct */
            zmem(&socks4msg, sizeof(socks4msg));
            socks4msg.version = SOCKS4_VERSION;
            socks4msg.type = SOCKS_CONNECT;
            socks4msg.port = socksconnect.in.sin_port;
            socks4msg.address = socksconnect.in.sin_addr.s_addr;
            if (o.proxy_auth)
                Strncpy(socks4msg.username, (char *) o.proxy_auth, sizeof(socks4msg.username));

            len = 8 + strlen(socks4msg.username) + 1;

            if (send(connect_socket, (char *) &socks4msg, len, 0) < 0) {
                loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno()));
                return 1;
            }
            /* The size of the socks4 response is 8 bytes. So read exactly
               8 bytes from the buffer */
            if (socket_buffer_readcount(&stateful_buf, socksbuf, 8) < 0) {
                loguser("Error: short reponse from proxy.\n");
                return 1;
            }
            if (socksbuf[1] != 90) {
                loguser("Proxy connection failed.\n");
                return 1;
            }

            /* Clear out whatever is left in the socket buffer which may be
               already sent by proxy server along with http response headers. */
            line = socket_buffer_remainder(&stateful_buf, &n);
            /* Write the leftover data to stdout. */
            Write(STDOUT_FILENO, line, n);
        }

        /* Once the proxy negotiation is done, Nsock takes control of the
           socket. */
        cs.sock_nsi = nsi_new2(mypool, connect_socket, NULL);

        /* Create IOD for nsp->stdin */
        if ((cs.stdin_nsi = nsi_new2(mypool, 0, NULL)) == NULL)
            bye("Failed to create stdin nsiod.");

        post_connect(mypool, cs.sock_nsi);
    }

    /* connect */
    rc = nsock_loop(mypool, -1);

    if (o.verbose) {
        struct timeval end_time;
        double time;
        gettimeofday(&end_time, NULL);
        time = TIMEVAL_MSEC_SUBTRACT(end_time, start_time) / 1000.0;
        loguser("%lu bytes sent, %lu bytes received in %.2f seconds.\n",
            nsi_get_write_count(cs.sock_nsi),
            nsi_get_read_count(cs.sock_nsi), time);
    }

#if HAVE_SYS_UN_H
    if (o.af == AF_UNIX && o.udp) {
        if (o.verbose)
            loguser("Deleting source DGRAM Unix domain socket. [%s]\n", srcaddr.un.sun_path);
        unlink(srcaddr.un.sun_path);
    }
#endif

    nsp_delete(mypool);

    return rc == NSOCK_LOOP_ERROR ? 1 : 0;
}
Ejemplo n.º 6
0
/* This is sufficiently different from the TCP code (wrt SSL, etc) that it
 * resides in its own simpler function
 */
static int ncat_listen_dgram(int proto)
{
    struct {
        int fd;
        union sockaddr_u addr;
    } sockfd[NUM_LISTEN_ADDRS];
    int i, fdn = -1;
    int fdmax, nbytes, n, fds_ready;
    char buf[DEFAULT_UDP_BUF_LEN] = { 0 };
    char *tempbuf = NULL;
    fd_set read_fds;
    union sockaddr_u remotess;
    socklen_t sslen = sizeof(remotess.storage);
    struct timeval tv;
    struct timeval *tvp = NULL;
    unsigned int num_sockets;

    for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
        sockfd[i].fd = -1;
        sockfd[i].addr.storage.ss_family = AF_UNSPEC;
    }

    FD_ZERO(&read_fds);

    /* Initialize remotess struct so recvfrom() doesn't hit the fan.. */
    zmem(&remotess.storage, sizeof(remotess.storage));
    remotess.storage.ss_family = o.af;

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

/* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */
#ifndef WIN32
    /* Check whether stdin is closed. Because we treat this fd specially, we
     * can't risk it being reopened for an incoming connection, so we'll hold
     * it open instead. */
    if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) {
      logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n");
      i = open("/dev/null", O_RDONLY);
      if (i >= 0 && i != STDIN_FILENO) {
        /* Oh well, we tried */
        logdebug("Couldn't reserve STDIN_FILENO\n");
        close(i);
      }
    }
#endif

    /* set for selecting udp listening sockets */
    fd_set listen_fds;
    fd_list_t listen_fdlist;
    FD_ZERO(&listen_fds);
    init_fdlist(&listen_fdlist, num_listenaddrs);

    num_sockets = 0;
    for (i = 0; i < num_listenaddrs; i++) {
        /* create the UDP listen sockets */
        sockfd[num_sockets].fd = do_listen(SOCK_DGRAM, proto, &listenaddrs[i]);
        if (sockfd[num_sockets].fd == -1) {
            if (o.debug > 0)
                logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
            continue;
        }
        FD_SET(sockfd[num_sockets].fd, &listen_fds);
        add_fd(&listen_fdlist, sockfd[num_sockets].fd);
        sockfd[num_sockets].addr = listenaddrs[i];
        num_sockets++;
    }
    if (num_sockets == 0) {
        if (num_listenaddrs == 1)
            bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
        else
            bye("Unable to open any listening sockets.");
    }

    if (o.idletimeout > 0)
        tvp = &tv;

    while (1) {
        int i, j, conn_count, socket_n;

        if (fdn != -1) {
            /*remove socket descriptor which is burnt */
            FD_CLR(sockfd[fdn].fd, &listen_fds);
            rm_fd(&listen_fdlist, sockfd[fdn].fd);

            /* Rebuild the udp socket which got burnt */
            sockfd[fdn].fd = do_listen(SOCK_DGRAM, proto, &sockfd[fdn].addr);
            if (sockfd[fdn].fd == -1)
                bye("do_listen: %s", socket_strerror(socket_errno()));
            FD_SET(sockfd[fdn].fd, &listen_fds);
            add_fd(&listen_fdlist, sockfd[fdn].fd);

        }
        fdn = -1;
        socket_n = -1;
        fd_set fds;
        FD_ZERO(&fds);
        while (1) {
            /*
             * We just select to get a list of sockets which we can talk to
             */
            if (o.debug > 1)
                logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
            fds = listen_fds;

            if (o.idletimeout > 0)
                ms_to_timeval(tvp, o.idletimeout);

            fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp);

            if (o.debug > 1)
                logdebug("select returned %d fds ready\n", fds_ready);

            if (fds_ready == 0)
                bye("Idle timeout expired (%d ms).", o.idletimeout);

            /*
             * Figure out which listening socket got a connection. This loop should
             * really call a function for each ready socket instead of breaking on
             * the first one.
             */
            for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) {
                /* Loop through descriptors until there is something ready */
                if (!FD_ISSET(i, &fds))
                    continue;

                /* Check each listening socket */
                for (j = 0; j < num_sockets; j++) {
                    if (i == sockfd[j].fd) {
                        if (o.debug > 1)
                            logdebug("Valid descriptor %d \n", i);
                        fdn = j;
                        socket_n = i;
                        break;
                    }
                }

                /* if we found a valid socket break */
                if (fdn != -1) {
                    fds_ready--;
                    break;
                }
            }

            /* Make sure someone connected */
            if (fdn == -1)
                continue;

            /*
             * We just peek so we can get the client connection details without
             * removing anything from the queue. Sigh.
             */
            nbytes = recvfrom(socket_n, buf, sizeof(buf), MSG_PEEK,
                              &remotess.sockaddr, &sslen);
            if (nbytes < 0) {
                loguser("%s.\n", socket_strerror(socket_errno()));
                close(socket_n);
                return 1;
            }

            /* Check conditions that might cause us to deny the connection. */
            conn_count = get_conn_count();
            if (conn_count >= o.conn_limit) {
                if (o.verbose)
                    loguser("New connection denied: connection limit reached (%d)\n", conn_count);
            } else if (!allow_access(&remotess)) {
                if (o.verbose)
                    loguser("New connection denied: not allowed\n");
            } else {
                /* Good to go. */
                break;
            }

            /* Dump the current datagram */
            nbytes = recv(socket_n, buf, sizeof(buf), 0);
            if (nbytes < 0) {
                loguser("%s.\n", socket_strerror(socket_errno()));
                close(socket_n);
                return 1;
            }
            ncat_log_recv(buf, nbytes);
        }

        if (o.debug > 1)
            logdebug("Valid Connection from %d\n", socket_n);

        conn_inc++;

        /*
         * We're using connected udp. This has the down side of only
         * being able to handle one udp client at a time
         */
        Connect(socket_n, &remotess.sockaddr, sslen);

        /* clean slate for buf */
        zmem(buf, sizeof(buf));

        /* are we executing a command? then do it */
        if (o.cmdexec) {
            struct fdinfo info = { 0 };

            info.fd = socket_n;
            if (o.keepopen)
                netrun(&info, o.cmdexec);
            else
                netexec(&info, o.cmdexec);
            continue;
        }

        FD_SET(socket_n, &read_fds);
        FD_SET(STDIN_FILENO, &read_fds);
        fdmax = socket_n;

        /* stdin -> socket and socket -> stdout */
        while (1) {
            fd_set fds;

            fds = read_fds;

            if (o.debug > 1)
                logdebug("udp select'ing\n");

            if (o.idletimeout > 0)
                ms_to_timeval(tvp, o.idletimeout);

            fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, tvp);

            if (fds_ready == 0)
                bye("Idle timeout expired (%d ms).", o.idletimeout);

            if (FD_ISSET(STDIN_FILENO, &fds)) {
                nbytes = Read(STDIN_FILENO, buf, sizeof(buf));
                if (nbytes <= 0) {
                    if (nbytes < 0 && o.verbose) {
                        logdebug("Error reading from stdin: %s\n", strerror(errno));
                    } else if (nbytes == 0 && o.debug) {
                        logdebug("EOF on stdin\n");
                    }
                    FD_CLR(STDIN_FILENO, &read_fds);
                    if (nbytes < 0)
                        return 1;
                    continue;
                }
                if (o.crlf)
                    fix_line_endings((char *) buf, &nbytes, &tempbuf, &crlf_state);
                if (!o.recvonly) {
                    if (tempbuf != NULL)
                        n = send(socket_n, tempbuf, nbytes, 0);
                    else
                        n = send(socket_n, buf, nbytes, 0);
                    if (n < nbytes) {
                        loguser("%s.\n", socket_strerror(socket_errno()));
                        close(socket_n);
                        return 1;
                    }
                    ncat_log_send(buf, nbytes);
                }
                if (tempbuf != NULL) {
                    free(tempbuf);
                    tempbuf = NULL;
                }
            }
            if (FD_ISSET(socket_n, &fds)) {
                nbytes = recv(socket_n, buf, sizeof(buf), 0);
                if (nbytes < 0) {
                    loguser("%s.\n", socket_strerror(socket_errno()));
                    close(socket_n);
                    return 1;
                }
                ncat_log_recv(buf, nbytes);
                if (!o.sendonly)
                    Write(STDOUT_FILENO, buf, nbytes);
            }

            zmem(buf, sizeof(buf));
        }
    }

    return 0;
}
Ejemplo n.º 7
0
/* Accept a connection on a listening socket. Allow or deny the connection.
   Fork a command if o.cmdexec is set. Otherwise, add the new socket to the
   watch set. */
static void handle_connection(int socket_accept)
{
    union sockaddr_u remoteaddr;
    socklen_t ss_len;
    struct fdinfo s = { 0 };
    int conn_count;

    zmem(&s, sizeof(s));
    zmem(&remoteaddr, sizeof(remoteaddr.storage));

    ss_len = sizeof(remoteaddr.storage);

    errno = 0;
    s.fd = accept(socket_accept, &remoteaddr.sockaddr, &ss_len);

    if (s.fd < 0) {
        if (o.debug)
            logdebug("Error in accept: %s\n", strerror(errno));

        close(s.fd);
        return;
    }

    if (o.verbose) {
#if HAVE_SYS_UN_H
        if (remoteaddr.sockaddr.sa_family == AF_UNIX)
            loguser("Connection from a client on Unix domain socket.\n");
        else
#endif
        if (o.chat)
            loguser("Connection from %s on file descriptor %d.\n", inet_socktop(&remoteaddr), s.fd);
        else
            loguser("Connection from %s.\n", inet_socktop(&remoteaddr));
    }

    if (!o.keepopen && !o.broker) {
        int i;
        for (i = 0; i < num_listenaddrs; i++) {
            Close(listen_socket[i]);
            FD_CLR(listen_socket[i], &master_readfds);
            rm_fd(&client_fdlist, listen_socket[i]);
        }
    }

    if (o.verbose) {
#if HAVE_SYS_UN_H
        if (remoteaddr.sockaddr.sa_family == AF_UNIX)
            loguser("Connection from %s.\n", remoteaddr.un.sun_path);
        else
#endif
            loguser("Connection from %s:%hu.\n", inet_socktop(&remoteaddr), inet_port(&remoteaddr));
    }

    /* Check conditions that might cause us to deny the connection. */
    conn_count = get_conn_count();
    if (conn_count >= o.conn_limit) {
        if (o.verbose)
            loguser("New connection denied: connection limit reached (%d)\n", conn_count);
        Close(s.fd);
        return;
    }
    if (!allow_access(&remoteaddr)) {
        if (o.verbose)
            loguser("New connection denied: not allowed\n");
        Close(s.fd);
        return;
    }

    s.remoteaddr = remoteaddr;

    conn_inc++;

    unblock_socket(s.fd);

#ifdef HAVE_OPENSSL
    if (o.ssl) {
        /* Add the socket to the necessary descriptor lists. */
        FD_SET(s.fd, &sslpending_fds);
        FD_SET(s.fd, &master_readfds);
        FD_SET(s.fd, &master_writefds);
        /* Add it to our list of fds too for maintaining maxfd. */
        if (add_fdinfo(&client_fdlist, &s) < 0)
            bye("add_fdinfo() failed.");
    } else
#endif
        post_handle_connection(s);
}
Ejemplo n.º 8
0
static int ncat_listen_stream(int proto)
{
    int rc, i, fds_ready;
    fd_set listen_fds;
    struct timeval tv;
    struct timeval *tvp = NULL;
    unsigned int num_sockets;

    /* clear out structs */
    FD_ZERO(&master_readfds);
    FD_ZERO(&master_writefds);
    FD_ZERO(&master_broadcastfds);
    FD_ZERO(&listen_fds);
#ifdef HAVE_OPENSSL
    FD_ZERO(&sslpending_fds);
#endif
    zmem(&client_fdlist, sizeof(client_fdlist));
    zmem(&broadcast_fdlist, sizeof(broadcast_fdlist));

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

#ifdef HAVE_OPENSSL
    if (o.ssl)
        setup_ssl_listen();
#endif

/* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */
#ifndef WIN32
    /* Check whether stdin is closed. Because we treat this fd specially, we
     * can't risk it being reopened for an incoming connection, so we'll hold
     * it open instead. */
    if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) {
      logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n");
      rc = open("/dev/null", O_RDONLY);
      if (rc >= 0 && rc != STDIN_FILENO) {
        /* Oh well, we tried */
        logdebug("Couldn't reserve STDIN_FILENO\n");
        close(rc);
      }
    }
#endif

    /* We need a list of fds to keep current fdmax. The second parameter is a
       number added to the supplied connection limit, that will compensate
       maxfds for the added by default listen and stdin sockets. */
    init_fdlist(&client_fdlist, sadd(o.conn_limit, num_listenaddrs + 1));

    for (i = 0; i < NUM_LISTEN_ADDRS; i++)
        listen_socket[i] = -1;

    num_sockets = 0;
    for (i = 0; i < num_listenaddrs; i++) {
        /* setup the main listening socket */
        listen_socket[num_sockets] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]);
        if (listen_socket[num_sockets] == -1) {
            if (o.debug > 0)
                logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
            continue;
        }

        /* Make our listening socket non-blocking because there are timing issues
         * which could cause us to block on accept() even though select() says it's
         * readable.  See UNPv1 2nd ed, p422 for more.
         */
        unblock_socket(listen_socket[num_sockets]);

        /* setup select sets and max fd */
        FD_SET(listen_socket[num_sockets], &master_readfds);
        add_fd(&client_fdlist, listen_socket[num_sockets]);

        FD_SET(listen_socket[num_sockets], &listen_fds);

        num_sockets++;
    }
    if (num_sockets == 0) {
        if (num_listenaddrs == 1)
            bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
        else
            bye("Unable to open any listening sockets.");
    }

    add_fd(&client_fdlist, STDIN_FILENO);

    init_fdlist(&broadcast_fdlist, o.conn_limit);

    if (o.idletimeout > 0)
        tvp = &tv;

    while (1) {
        /* We pass these temporary descriptor sets to fselect, since fselect
           modifies the sets it receives. */
        fd_set readfds = master_readfds, writefds = master_writefds;
        struct fdinfo *fdi = NULL;

        if (o.debug > 1)
            logdebug("selecting, fdmax %d\n", client_fdlist.fdmax);

        if (o.debug > 1 && o.broker)
            logdebug("Broker connection count is %d\n", get_conn_count());

        if (o.idletimeout > 0)
            ms_to_timeval(tvp, o.idletimeout);

        fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, tvp);

        if (o.debug > 1)
            logdebug("select returned %d fds ready\n", fds_ready);

        if (fds_ready == 0)
            bye("Idle timeout expired (%d ms).", o.idletimeout);

        /*
         * FIXME: optimize this loop to look only at the fds in the fd list,
         * doing it this way means that if you have one descriptor that is very
         * large, say 500, and none close to it, that you'll loop many times for
         * nothing.
         */
        for (i = 0; i <= client_fdlist.fdmax && fds_ready > 0; i++) {
            /* Loop through descriptors until there's something to read */
            if (!FD_ISSET(i, &readfds) && !FD_ISSET(i, &writefds))
                continue;

            if (o.debug > 1)
                logdebug("fd %d is ready\n", i);

#ifdef HAVE_OPENSSL
            /* Is this an ssl socket pending a handshake? If so handle it. */
            if (o.ssl && FD_ISSET(i, &sslpending_fds)) {
                FD_CLR(i, &master_readfds);
                FD_CLR(i, &master_writefds);
                fdi = get_fdinfo(&client_fdlist, i);
                ncat_assert(fdi != NULL);
                switch (ssl_handshake(fdi)) {
                case NCAT_SSL_HANDSHAKE_COMPLETED:
                    /* Clear from sslpending_fds once ssl is established */
                    FD_CLR(i, &sslpending_fds);
                    post_handle_connection(*fdi);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_WRITE:
                    FD_SET(i, &master_writefds);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_READ:
                    FD_SET(i, &master_readfds);
                    break;
                case NCAT_SSL_HANDSHAKE_FAILED:
                default:
                    SSL_free(fdi->ssl);
                    Close(fdi->fd);
                    FD_CLR(i, &sslpending_fds);
                    FD_CLR(i, &master_readfds);
                    rm_fd(&client_fdlist, i);
                    /* Are we in single listening mode(without -k)? If so
                       then we should quit also. */
                    if (!o.keepopen && !o.broker)
                        return 1;
                    --conn_inc;
                    break;
                }
            } else
#endif
            if (FD_ISSET(i, &listen_fds)) {
                /* we have a new connection request */
                handle_connection(i);
            } else if (i == STDIN_FILENO) {
                if (o.broker) {
                    read_and_broadcast(i);
                } else {
                    /* Read from stdin and write to all clients. */
                    rc = read_stdin();
                    if (rc == 0) {
                        if (o.proto != IPPROTO_TCP || (o.proto == IPPROTO_TCP && o.sendonly)) {
                            /* There will be nothing more to send. If we're not
                               receiving anything, we can quit here. */
                            return 0;
                        }
                        if (!o.noshutdown) shutdown_sockets(SHUT_WR);
                    }
                    if (rc < 0)
                        return 1;
                }
            } else if (!o.sendonly) {
                if (o.broker) {
                    read_and_broadcast(i);
                } else {
                    /* Read from a client and write to stdout. */
                    rc = read_socket(i);
                    if (rc <= 0 && !o.keepopen)
                        return rc == 0 ? 0 : 1;
                }
            }

            fds_ready--;
        }
    }

    return 0;
}
Ejemplo n.º 9
0
static int handle_connect(struct socket_buffer *client_sock,
    struct http_request *request)
{
    union sockaddr_u su;
    size_t sslen = sizeof(su.storage);
    int maxfd, s, rc;
    char *line;
    size_t len;
    fd_set m, r;

    if (request->uri.port == -1) {
        if (o.verbose)
            logdebug("No port number in CONNECT URI.\n");
        return 400;
    }
    if (o.debug > 1)
        logdebug("CONNECT to %s:%hu.\n", request->uri.host, request->uri.port);

    rc = resolve(request->uri.host, request->uri.port, &su.storage, &sslen, o.af);
    if (rc != 0) {
        if (o.debug) {
            logdebug("Can't resolve name \"%s\": %s.\n",
                request->uri.host, gai_strerror(rc));
        }
        return 504;
    }

    s = Socket(su.storage.ss_family, SOCK_STREAM, IPPROTO_TCP);

    if (connect(s, &su.sockaddr, sslen) == -1) {
        if (o.debug)
            logdebug("Can't connect to %s.\n", inet_socktop(&su));
        Close(s);
        return 504;
    }

    send_string(&client_sock->fdn, http_code2str(200));

    /* Clear out whatever is left in the socket buffer. The client may have
       already sent the first part of its request to the origin server. */
    line = socket_buffer_remainder(client_sock, &len);
    if (send(s, line, len, 0) < 0) {
        if (o.debug)
            logdebug("Error sending %lu leftover bytes: %s.\n", (unsigned long) len, strerror(errno));
        Close(s);
        return 0;
    }

    maxfd = client_sock->fdn.fd < s ? s : client_sock->fdn.fd;
    FD_ZERO(&m);
    FD_SET(client_sock->fdn.fd, &m);
    FD_SET(s, &m);

    errno = 0;

    while (!socket_errno() || socket_errno() == EINTR) {
        char buf[DEFAULT_TCP_BUF_LEN];
        int len, rc;

        r = m;

        fselect(maxfd + 1, &r, NULL, NULL, NULL);

        zmem(buf, sizeof(buf));

        if (FD_ISSET(client_sock->fdn.fd, &r)) {
            do {
                do {
                    len = fdinfo_recv(&client_sock->fdn, buf, sizeof(buf));
                } while (len == -1 && socket_errno() == EINTR);
                if (len <= 0)
                    goto end;

                do {
                    rc = send(s, buf, len, 0);
                } while (rc == -1 && socket_errno() == EINTR);
                if (rc == -1)
                    goto end;
            } while (fdinfo_pending(&client_sock->fdn));
        }

        if (FD_ISSET(s, &r)) {
            do {
                len = recv(s, buf, sizeof(buf), 0);
            } while (len == -1 && socket_errno() == EINTR);
            if (len <= 0)
                goto end;

            do {
                rc = fdinfo_send(&client_sock->fdn, buf, len);
            } while (rc == -1 && socket_errno() == EINTR);
            if (rc == -1)
                goto end;
        }
    }
end:

    close(s);

    return 0;
}
Ejemplo n.º 10
0
/* This is sufficiently different from the TCP code (wrt SSL, etc) that it
 * resides in its own simpler function
 */
static int ncat_listen_dgram(int proto)
{
    int sockfd[NUM_LISTEN_ADDRS];
    int i, fdn = -1;
    int fdmax, nbytes, fds_ready;
    char buf[DEFAULT_UDP_BUF_LEN] = {0};
    char *tempbuf = NULL;
    fd_set read_fds;
    union sockaddr_u remotess;
    socklen_t sslen = sizeof(remotess.storage);

    for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
        sockfd[i] = -1;
    }

    FD_ZERO(&read_fds);

    /* Initialize remotess struct so recvfrom() doesn't hit the fan.. */
    zmem(&remotess.storage, sizeof(remotess.storage));
    remotess.storage.ss_family = o.af;

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

    /* set for selecting udp listening sockets */
    fd_set listen_fds;
    fd_list_t listen_fdlist;
    FD_ZERO(&listen_fds);
    init_fdlist(&listen_fdlist, num_listenaddrs);

    for (i = 0; i < num_listenaddrs; i++) {
        /* create the UDP listen sockets */
        sockfd[i] = do_listen(SOCK_DGRAM, proto, &listenaddrs[i]);
        FD_SET(sockfd[i],&listen_fds);
        add_fd(&listen_fdlist, sockfd[i]);
    }

    while (1) {
        int i, j, conn_count, socket_n;

        if (fdn != -1) {
            /*remove socket descriptor which is burnt */
            FD_CLR(sockfd[fdn], &listen_fds);
            rm_fd(&listen_fdlist, sockfd[fdn]);

            /* Rebuild the udp socket which got burnt */
            sockfd[fdn] = do_listen(SOCK_DGRAM, proto, &listenaddrs[fdn]);
            FD_SET(sockfd[fdn],&listen_fds);
            add_fd(&listen_fdlist, sockfd[fdn]);

        }
        fdn = -1;
        socket_n = -1;
            fd_set fds;
            FD_ZERO(&fds);
        while (1) {
            /*
             * We just select to get a list of sockets which we can talk to
             */
            if (o.debug > 1)
                logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
            fds = listen_fds;
            fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, NULL);

            if (o.debug > 1)
                logdebug("select returned %d fds ready\n", fds_ready);


            /*
             * Figure out which listening socket got a connection. This loop should
             * really call a function for each ready socket instead of breaking on
             * the first one.
             */
            for (i = 0; i <= listen_fdlist.fdmax && fds_ready >0; i++) {
                /* Loop through descriptors until there is something ready */
                if (!FD_ISSET(i, &fds))
                    continue;

                /* Check each listening socket */
                for (j = 0; j < num_listenaddrs; j++) {
                    if (i == sockfd[j]) {
                        if (o.debug >1)
                            logdebug("Valid descriptor %d \n", i);
                        fdn = j;
                        socket_n = i;
                        break;
                    }
                }

                /* if we found a valid socket break */
                if (fdn != -1) {
                    fds_ready--;
                    break;
                }
            }

            /* Make sure someone connected */
            if (fdn == -1)
                continue;

            /*
             * We just peek so we can get the client connection details without
             * removing anything from the queue. Sigh.
             */
            nbytes = Recvfrom(socket_n, buf, sizeof(buf), MSG_PEEK,
                              &remotess.sockaddr, &sslen);

            /* Check conditions that might cause us to deny the connection. */
            conn_count = get_conn_count();
            if (conn_count >= o.conn_limit) {
                if (o.verbose)
                    loguser("New connection denied: connection limit reached (%d)\n", conn_count);
            } else if (!allow_access(&remotess)) {
                if (o.verbose)
                    loguser("New connection denied: not allowed\n");
            } else {
                /* Good to go. */
                break;
            }

            /* Dump the current datagram */
            Recv(socket_n, buf, sizeof(buf), 0);
        }

        if (o.debug > 1)
            logdebug("Valid Connection from %d\n", socket_n);

        conn_inc++;

        /*
         * We're using connected udp. This has the down side of only
         * being able to handle one udp client at a time
         */
        Connect(socket_n, &remotess.sockaddr, sslen);

        /* clean slate for buf */
        zmem(buf, sizeof(buf));

        /* are we executing a command? then do it */
        if (o.cmdexec) {
            struct fdinfo info = { 0 };

            info.fd = socket_n;
            if (o.keepopen)
                netrun(&info, o.cmdexec);
            else
                netexec(&info, o.cmdexec);
            continue;
        }

        FD_SET(socket_n, &read_fds);
        FD_SET(STDIN_FILENO, &read_fds);
        fdmax = socket_n;

        /* stdin -> socket and socket -> stdout */
        while (1) {
            fd_set fds;

            fds = read_fds;

            if (o.debug > 1)
                logdebug("udp select'ing\n");

            fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, NULL);

            if (FD_ISSET(STDIN_FILENO, &fds)) {
                nbytes = Read(STDIN_FILENO, buf, sizeof(buf));
                if (nbytes < 0) {
                    loguser("%s.\n", strerror(errno));
                    return 1;
                } else if (nbytes == 0) {
                    return 0;
                }
                if (o.crlf)
                    fix_line_endings((char *) buf, &nbytes, &tempbuf, &crlf_state);
                if (!o.recvonly) {
                    if (tempbuf != NULL)
                        send(socket_n, tempbuf, nbytes, 0);
                    else
                        send(socket_n, buf, nbytes, 0);
                }
                if (tempbuf != NULL) {
                    free(tempbuf);
                    tempbuf = NULL;
                }
            }
            if (FD_ISSET(socket_n, &fds)) {
                nbytes = recv(socket_n, buf, sizeof(buf), 0);
                if (nbytes < 0) {
                    loguser("%s.\n", socket_strerror(socket_errno()));
                    close(socket_n);
                    return 1;
                }
                if (!o.sendonly)
                    Write(STDOUT_FILENO, buf, nbytes);
            }

            zmem(buf, sizeof(buf));
        }
    }

    return 0;
}
Ejemplo n.º 11
0
static int ncat_listen_stream(int proto)
{
    int rc, i, fds_ready;
    fd_set listen_fds;

    /* clear out structs */
    FD_ZERO(&master_readfds);
    FD_ZERO(&master_writefds);
    FD_ZERO(&master_broadcastfds);
    FD_ZERO(&listen_fds);
#ifdef HAVE_OPENSSL
    FD_ZERO(&sslpending_fds);
#endif
    zmem(&client_fdlist, sizeof(client_fdlist));
    zmem(&broadcast_fdlist, sizeof(broadcast_fdlist));

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

#ifdef HAVE_OPENSSL
    if (o.ssl)
        setup_ssl_listen();
#endif

    /* We need a list of fds to keep current fdmax. The second parameter is a
       number added to the supplied connection limit, that will compensate
       maxfds for the added by default listen and stdin sockets. */
    init_fdlist(&client_fdlist, sadd(o.conn_limit, num_listenaddrs + 1));

    for (i = 0; i < NUM_LISTEN_ADDRS; i++)
        listen_socket[i] = -1;

    for (i = 0; i < num_listenaddrs; i++) {
        /* setup the main listening socket */
        listen_socket[i] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]);

        /* Make our listening socket non-blocking because there are timing issues
         * which could cause us to block on accept() even though select() says it's
         * readable.  See UNPv1 2nd ed, p422 for more.
         */
        unblock_socket(listen_socket[i]);

        /* setup select sets and max fd */
        FD_SET(listen_socket[i], &master_readfds);
        add_fd(&client_fdlist, listen_socket[i]);

        FD_SET(listen_socket[i], &listen_fds);
    }
    add_fd(&client_fdlist, STDIN_FILENO);

    init_fdlist(&broadcast_fdlist, o.conn_limit);

    while (1) {
        /* We pass these temporary descriptor sets to fselect, since fselect
           modifies the sets it receives. */
        fd_set readfds = master_readfds, writefds = master_writefds;
        struct fdinfo *fdi = NULL;

        if (o.debug > 1)
            logdebug("selecting, fdmax %d\n", client_fdlist.fdmax);

        if (o.debug > 1 && o.broker)
            logdebug("Broker connection count is %d\n", get_conn_count());

        fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, NULL);

        if (o.debug > 1)
            logdebug("select returned %d fds ready\n", fds_ready);

        /*
         * FIXME: optimize this loop to look only at the fds in the fd list,
         * doing it this way means that if you have one descriptor that is very
         * large, say 500, and none close to it, that you'll loop many times for
         * nothing.
         */
        for (i = 0; i <= client_fdlist.fdmax && fds_ready > 0; i++) {
            /* Loop through descriptors until there's something to read */
            if (!FD_ISSET(i, &readfds) && !FD_ISSET(i, &writefds))
                continue;

            if (o.debug > 1)
                logdebug("fd %d is ready\n", i);

#ifdef HAVE_OPENSSL
            /* Is this an ssl socket pending a handshake? If so handle it. */
            if (o.ssl && FD_ISSET(i, &sslpending_fds)) {
                FD_CLR(i, &master_readfds);
                FD_CLR(i, &master_writefds);
                fdi = get_fdinfo(&client_fdlist, i);
                switch(ssl_handshake(fdi)){
                case NCAT_SSL_HANDSHAKE_COMPLETED:
                    /* Clear from sslpending_fds once ssl is established */
                    FD_CLR(i, &sslpending_fds);
                    rm_fd(&client_fdlist, i);
                    post_handle_connection(*fdi);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_WRITE:
                    FD_SET(i, &master_writefds);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_READ:
                    FD_SET(i, &master_readfds);
                    break;
                case NCAT_SSL_HANDSHAKE_FAILED:
                default:
                    SSL_free(fdi->ssl);
                    Close(fdi->fd);
                    FD_CLR(i, &sslpending_fds);
                    FD_CLR(i, &master_readfds);
                    rm_fd(&client_fdlist, i);
                    /* Are we in single listening mode(without -k)? If so
                       then we should quit also. */
                    if (!o.keepopen && !o.broker)
                        return 1;
                    --conn_inc;
                    break;
                }
            } else
#endif
            if (FD_ISSET(i, &listen_fds)) {
                /* we have a new connection request */
                handle_connection(i);
            } else if (i == STDIN_FILENO) {
                if(o.broker) {
                    read_and_broadcast(i);
                }else {
                    /* Read from stdin and write to all clients. */
                    rc = read_stdin();
                    if (rc == 0 && o.sendonly)
                        /* There will be nothing more to send. If we're not
                           receiving anything, we can quit here. */
                        return 0;
                    if (rc < 0)
                        return 1;
                }
            } else if (!o.sendonly) {
                if(o.broker) {
                    read_and_broadcast(i);
                }else {
                    /* Read from a client and write to stdout. */
                    rc = read_socket(i);
                    if (rc <= 0 && !o.keepopen)
                        return rc == 0 ? 0 : 1;
                }
            }

            fds_ready--;
        }
    }

    return 0;
}