From fc62a633c4c6cf5c08fb6f9c72ccaa56fa517b82 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 19 Sep 2012 16:10:05 +0200 Subject: [PATCH 2/2] Implementation of UNIX-domain sockets for ncat. Implementation of UNIX sockets for ncat using also UNIX-domain sockets functionality from Nsock library. Added new argument "-U". --- ncat/config.h.in | 3 + ncat/configure.ac | 2 +- ncat/ncat.h | 6 + ncat/ncat_connect.c | 62 +++++++++- ncat/ncat_listen.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++++- ncat/ncat_main.c | 87 +++++++++++++- ncat/sockaddr_u.h | 5 + ncat/util.c | 30 +++-- ncat/util.h | 4 + 9 files changed, 515 insertions(+), 17 deletions(-) diff --git a/ncat/config.h.in b/ncat/config.h.in index 01ac1db..3ef265e 100644 --- a/ncat/config.h.in +++ b/ncat/config.h.in @@ -119,6 +119,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UN_H + /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF diff --git a/ncat/configure.ac b/ncat/configure.ac index fffd7c2..b4b5d3e 100644 --- a/ncat/configure.ac +++ b/ncat/configure.ac @@ -37,7 +37,7 @@ AC_PATH_TOOL([STRIP], [strip], [/bin/true]) # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h limits.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/param.h sys/socket.h sys/time.h sys/timeb.h unistd.h]) +AC_CHECK_HEADERS([fcntl.h limits.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/param.h sys/socket.h sys/time.h sys/timeb.h unistd.h sys/un.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STAT diff --git a/ncat/ncat.h b/ncat/ncat.h index 3310a29..73c3a5b 100644 --- a/ncat/ncat.h +++ b/ncat/ncat.h @@ -141,6 +141,12 @@ struct socks4_data { /* defines */ +/* Default path for temporary DATAGRAM UNIX-domain socket */ +#define DEFAULT_TMP_UNIX_DGRAM_SOCKET "/tmp/ncat.XXXXXX" + +/* Size of default path for temporary DATAGRAM UNIX-domain socket */ +#define DEFAULT_TMP_UNIX_DGRAM_SOCKET_SIZE sizeof(DEFAULT_TMP_UNIX_DGRAM_SOCKET) + /* Client-mode timeout for reads, infinite */ #define DEFAULT_READ_TIMEOUT -1 diff --git a/ncat/ncat_connect.c b/ncat/ncat_connect.c index 8905c44..98cfbda 100644 --- a/ncat/ncat_connect.c +++ b/ncat/ncat_connect.c @@ -205,6 +205,7 @@ static void set_ssl_ctx_options(SSL_CTX *ctx) 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)); @@ -236,10 +237,20 @@ static void connect_report(nsock_iod nsi) assert(ssl_cert_fp_str_sha1(cert, digest_buf, sizeof(digest_buf)) != NULL); loguser("SHA-1 fingerprint: %s\n", digest_buf); } else { - loguser("Connected to %s:%hu.\n", inet_socktop(&peer), nsi_peerport(nsi)); +#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 - loguser("Connected to %s:%hu.\n", inet_socktop(&peer), nsi_peerport(nsi)); +#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 } } @@ -461,6 +472,10 @@ bail: int ncat_connect(void) { nsock_pool mypool; int rc; +#if HAVE_SYS_UN_H + char unix_dg_tmp_sock_buff[DEFAULT_TMP_UNIX_DGRAM_SOCKET_SIZE] = DEFAULT_TMP_UNIX_DGRAM_SOCKET; + char *unix_dg_tmp_sock = NULL; +#endif /* Create an nsock pool */ if ((mypool = nsp_new(NULL)) == NULL) @@ -487,6 +502,31 @@ int ncat_connect(void) { 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) { + nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, SUN_LEN((struct sockaddr_un *)&srcaddr.storage)); + unix_dg_tmp_sock = srcaddr.un.sun_path; + } else { + /* If no source socket was specified, we have to + * create temporary one. */ + if (mktemp(unix_dg_tmp_sock_buff) == NULL) + bye("Failed to create name for temporary DGRAM source UNIX-domain socket (mktemp)."); + + srcaddr.un.sun_family = AF_UNIX; + strncpy(srcaddr.un.sun_path, unix_dg_tmp_sock_buff, sizeof(srcaddr.un.sun_path)); + + nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, SUN_LEN((struct sockaddr_un *)&srcaddr.storage)); + unix_dg_tmp_sock = srcaddr.un.sun_path; + } + + if (o.verbose) + loguser("[%s] used as source DGRAM UNIX-domain socket.\n", unix_dg_tmp_sock); + } + else +#endif if (srcaddr.storage.ss_family != AF_UNSPEC) nsi_set_localaddr(cs.sock_nsi, &srcaddr.storage, sizeof(srcaddr.storage)); @@ -502,6 +542,19 @@ int ncat_connect(void) { 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, @@ -623,6 +676,11 @@ int ncat_connect(void) { nsi_get_read_count(cs.sock_nsi), time); } +#if HAVE_SYS_UN_H + if (o.af == AF_UNIX && o.udp) + unlink(unix_dg_tmp_sock); +#endif + nsp_delete(mypool); return rc == NSOCK_LOOP_ERROR ? 1 : 0; diff --git a/ncat/ncat_listen.c b/ncat/ncat_listen.c index ca291eb..56a1c5b 100644 --- a/ncat/ncat_listen.c +++ b/ncat/ncat_listen.c @@ -110,6 +110,10 @@ #include #endif +#if HAVE_SYS_UN_H +#include +#endif + #ifdef HAVE_OPENSSL #include #include @@ -353,8 +357,10 @@ static void handle_connection(int socket_accept) 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); @@ -369,6 +375,10 @@ static void handle_connection(int socket_accept) if (o.verbose) { if (o.chat) loguser("Connection from %s on file descriptor %d.\n", inet_socktop(&remoteaddr), s.fd); +#if HAVE_SYS_UN_H + else if (remoteaddr.sockaddr.sa_family == AF_UNIX) + loguser("Connection from %s.\n", remoteaddr.un.sun_path); +#endif else loguser("Connection from %s.\n", inet_socktop(&remoteaddr)); } @@ -383,7 +393,12 @@ static void handle_connection(int socket_accept) } if (o.verbose) - loguser("Connection from %s:%hu.\n", inet_socktop(&remoteaddr), inet_port(&remoteaddr)); +#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(); @@ -755,8 +770,324 @@ static int ncat_listen_dgram(int proto) return 0; } +#if HAVE_SYS_UN_H + +static int ncat_listen_unixsock_stream(void) +{ + 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); + zmem(&client_fdlist, sizeof(client_fdlist)); + zmem(&broadcast_fdlist, sizeof(broadcast_fdlist)); + + /* 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); + + /* 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, 0, &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; + + if (o.debug > 1) + logdebug("selecting, fdmax %d\n", client_fdlist.fdmax); + + 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); + + if (FD_ISSET(i, &listen_fds)) { + /* we have a new connection request */ + handle_connection(i); + } else if (i == STDIN_FILENO) { + /* 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) { + /* 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; +} + +static int ncat_listen_unixsock_dgram() +{ + 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; + + /* 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); + + /* 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, 0, &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, 0, &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 { + /* 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; +} + +#endif /* HAVE_SYS_UN_H */ + int ncat_listen() { +#if HAVE_SYS_UN_H + if (o.af == AF_UNIX) + if (o.udp) + return ncat_listen_unixsock_dgram(); + else + return ncat_listen_unixsock_stream(); + else +#endif if (o.httpserver) return ncat_http_server(); else if (o.udp) diff --git a/ncat/ncat_main.c b/ncat/ncat_main.c index d7f7c27..16e5fda 100644 --- a/ncat/ncat_main.c +++ b/ncat/ncat_main.c @@ -227,6 +227,9 @@ int main(int argc, char *argv[]) struct option long_options[] = { {"4", no_argument, NULL, '4'}, {"6", no_argument, NULL, '6'}, +#if HAVE_SYS_UN_H + {"unixsock", no_argument, NULL, 'U'}, +#endif {"crlf", no_argument, NULL, 'C'}, {"g", required_argument, NULL, 'g'}, {"G", required_argument, NULL, 'G'}, @@ -284,7 +287,7 @@ int main(int argc, char *argv[]) while (1) { /* handle command line arguments */ int option_index; - int c = getopt_long(argc, argv, "46Cc:e:g:G:i:km:hp:d:lo:x:ts:uvw:n", + int c = getopt_long(argc, argv, "46UCc:e:g:G:i:km:hp:d:lo:x:ts:uvw:n", long_options, &option_index); /* That's the end of the options. */ @@ -302,6 +305,11 @@ int main(int argc, char *argv[]) bye("-6 chosen when IPv6 wasn't compiled in."); #endif break; +#if HAVE_SYS_UN_H + case 'U': + o.af = AF_UNIX; + break; +#endif case 'C': o.crlf = 1; break; @@ -490,6 +498,9 @@ int main(int argc, char *argv[]) "'s' for seconds, 'm' for minutes, or 'h' for hours (e.g. 500ms).\n" " -4 Use IPv4 only\n" " -6 Use IPv6 only\n" +#if HAVE_SYS_UN_H +" -U, --unixsock Use UNIX-domain sockets only\n" +#endif " -C, --crlf Use CRLF for EOL sequence\n" " -c, --sh-exec Executes the given command via /bin/sh\n" " -e, --exec Executes the given command\n" @@ -557,7 +568,33 @@ int main(int argc, char *argv[]) else nbase_set_log(loguser, NULL); - /* Will be AF_INET or AF_INET6 when valid */ +#if HAVE_SYS_UN_H + /* Using UNIX-domain sockets, so do the checks now */ + if (o.af == AF_UNIX) { + if (proxyaddr || o.proxytype) + bye("Proxy option not supported when using UNIX-domain sockets."); + if (o.chat) + bye("Chat option not supported when using UNIX-domain sockets."); +#ifdef HAVE_OPENSSL + if (o.ssl) + bye("SSL option not supported when using UNIX-domain sockets."); +#endif + if (o.nodns) + bye("Not using DNS option with UNIX-domain sockets doesn't make sense."); + if (o.broker) + bye("Connection brokering not supported when using UNIX-domain sockets."); + if (o.allow) + bye("Allowed hosts list not supported when using UNIX-domain sockets."); + if (o.deny) + bye("Denied hosts list not supported when using UNIX-domain sockets."); + if (srcport != -1) + bye("Specifying source port when using UNIX-domain sockets doesn't make sense."); + if (o.numsrcrtes > 0) + bye("Loose source routing not allowed when using UNIX-domain sockets."); + } +#endif /* HAVE_SYS_UN_H */ + + /* Will be AF_INET or AF_INET6 (or AF_UNIX) when valid */ memset(&targetss.storage, 0, sizeof(targetss.storage)); targetss.storage.ss_family = AF_UNSPEC; httpconnect.storage = socksconnect.storage = srcaddr.storage = targetss.storage; @@ -607,6 +644,20 @@ int main(int argc, char *argv[]) if (o.listen) bye("-l and -s are incompatible. Specify the address and port to bind to like you would a host to connect to."); +#if HAVE_SYS_UN_H + /* if using UNIX sockets just copy the path. + * If it's not valid, it will fail later! */ + if (o.af == AF_UNIX) { + if (o.udp) { + srcaddr.un.sun_family = AF_UNIX; + strncpy(srcaddr.un.sun_path, source, sizeof(srcaddr.un.sun_path)); + srcaddrlen = SUN_LEN(&srcaddr.un); + } + else + if (o.verbose) + loguser("Specifying source socket for other than DATAGRAM UNIX-domain sockets have no effect."); + } else +#endif if (!resolve(source, 0, &srcaddr.storage, &srcaddrlen, o.af)) bye("Could not resolve source address %s.", source); } @@ -617,10 +668,24 @@ int main(int argc, char *argv[]) host_list_free(deny_host_list); if (optind == argc) { +#if HAVE_SYS_UN_H + if (o.af == AF_UNIX) + bye("You have to specify a socket to connect to."); +#endif /* Listen defaults to any address and DEFAULT_NCAT_PORT */ if (!o.listen) bye("You must specify a host to connect to."); } else { +#if HAVE_SYS_UN_H + if (o.af == AF_UNIX) { + memset(&targetss.storage, 0, sizeof(struct sockaddr_un)); + targetss.un.sun_family = AF_UNIX; + strncpy(targetss.un.sun_path, argv[optind], sizeof(targetss.un.sun_path)); + targetsslen = SUN_LEN(&targetss.un); + o.target = argv[optind]; + optind++; + } else +#endif /* Resolve hostname if we're given one */ if (strspn(argv[optind], "0123456789") != strlen(argv[optind])) { o.target = argv[optind]; @@ -635,6 +700,12 @@ int main(int argc, char *argv[]) } /* Whatever's left is the port number; there should be at most one. */ +#if HAVE_SYS_UN_H + /* We do not use ports with UNIX-domain sockets. */ + if (o.af == AF_UNIX && optind > argc) + bye("Using UNIX-domain sockets and specifying port doesn't make sense."); +#endif + if (optind + 1 < argc || (o.listen && srcport != -1 && optind + 1 == argc)) { loguser("Got more than one port specification:"); if (o.listen && srcport != -1) @@ -654,11 +725,15 @@ int main(int argc, char *argv[]) o.portno = (unsigned short) long_port; } - if (o.af == AF_INET) - targetss.in.sin_port = htons(o.portno); +#if HAVE_SYS_UN_H + /* If we use UNIX-domain sockets, we have to count with them. */ + if (o.af != AF_UNIX) +#endif + if (o.af == AF_INET) + targetss.in.sin_port = htons(o.portno); #ifdef HAVE_IPV6 - else - targetss.in6.sin6_port = htons(o.portno); + else + targetss.in6.sin6_port = htons(o.portno); #endif if (srcport != -1) { diff --git a/ncat/sockaddr_u.h b/ncat/sockaddr_u.h index 92430f2..c04ebc4 100644 --- a/ncat/sockaddr_u.h +++ b/ncat/sockaddr_u.h @@ -91,11 +91,16 @@ /* $Id:$ */ +#include "ncat_config.h" + #ifndef SOCKADDR_U_H_ #define SOCKADDR_U_H_ union sockaddr_u { struct sockaddr_storage storage; +#if HAVE_SYS_UN_H + struct sockaddr_un un; +#endif struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr sockaddr; diff --git a/ncat/util.c b/ncat/util.c index 54d3b28..9af88c6 100644 --- a/ncat/util.c +++ b/ncat/util.c @@ -403,21 +403,37 @@ int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u) #endif #endif +#if HAVE_SYS_UN_H + if (srcaddr_u->storage.ss_family == AF_UNIX) + sa_len = SUN_LEN(&srcaddr_u->un); + else +#endif #ifdef HAVE_SOCKADDR_SA_LEN - sa_len = srcaddr_u->sockaddr.sa_len; + sa_len = srcaddr_u->sockaddr.sa_len; #else - sa_len = sizeof(*srcaddr_u); + sa_len = sizeof(*srcaddr_u); #endif - if (bind(sock, &srcaddr_u->sockaddr, sa_len) < 0) { - bye("bind to %s:%hu: %s.", inet_socktop(srcaddr_u), - inet_port(srcaddr_u), socket_strerror(socket_errno())); - } + + if (bind(sock, &srcaddr_u->sockaddr, sa_len) < 0) +#if HAVE_SYS_UN_H + if (srcaddr_u->storage.ss_family == AF_UNIX) + bye("bind to %s: %s.", srcaddr_u->un.sun_path, + socket_strerror(socket_errno())); + else +#endif + bye("bind to %s:%hu: %s.", inet_socktop(srcaddr_u), + inet_port(srcaddr_u), socket_strerror(socket_errno())); if (type == SOCK_STREAM) Listen(sock, BACKLOG); if (o.verbose) - loguser("Listening on %s:%hu\n", inet_socktop(srcaddr_u), inet_port(srcaddr_u)); +#if HAVE_SYS_UN_H + if (srcaddr_u->storage.ss_family == AF_UNIX) + loguser("Listening on %s\n", srcaddr_u->un.sun_path); + else +#endif + loguser("Listening on %s:%hu\n", inet_socktop(srcaddr_u), inet_port(srcaddr_u)); return sock; } diff --git a/ncat/util.h b/ncat/util.h index ee7c393..27663f5 100644 --- a/ncat/util.h +++ b/ncat/util.h @@ -101,6 +101,10 @@ #include #endif +#if HAVE_SYS_UN_H +#include +#endif + #ifdef HAVE_OPENSSL #include #endif -- 1.7.11.4