1100e2a06SXin LI /* $OpenBSD: netcat.c,v 1.130 2015/07/26 19:12:28 chl Exp $ */ 28c384020SXin LI /* 38c384020SXin LI * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 48c384020SXin LI * 58c384020SXin LI * Redistribution and use in source and binary forms, with or without 68c384020SXin LI * modification, are permitted provided that the following conditions 78c384020SXin LI * are met: 88c384020SXin LI * 98c384020SXin LI * 1. Redistributions of source code must retain the above copyright 108c384020SXin LI * notice, this list of conditions and the following disclaimer. 118c384020SXin LI * 2. Redistributions in binary form must reproduce the above copyright 128c384020SXin LI * notice, this list of conditions and the following disclaimer in the 138c384020SXin LI * documentation and/or other materials provided with the distribution. 148c384020SXin LI * 3. The name of the author may not be used to endorse or promote products 158c384020SXin LI * derived from this software without specific prior written permission. 168c384020SXin LI * 178c384020SXin LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 188c384020SXin LI * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 198c384020SXin LI * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 208c384020SXin LI * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 218c384020SXin LI * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 228c384020SXin LI * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 238c384020SXin LI * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 248c384020SXin LI * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258c384020SXin LI * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 268c384020SXin LI * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2704def624SXin LI * 2804def624SXin LI * $FreeBSD$ 298c384020SXin LI */ 308c384020SXin LI 318c384020SXin LI /* 328c384020SXin LI * Re-written nc(1) for OpenBSD. Original implementation by 338c384020SXin LI * *Hobbit* <hobbit@avian.org>. 348c384020SXin LI */ 358c384020SXin LI 361e62ecedSEdward Tomasz Napierala #include <errno.h> 371e62ecedSEdward Tomasz Napierala #include <stdio.h> 381e62ecedSEdward Tomasz Napierala #include <sys/arb.h> 3904def624SXin LI #include <sys/limits.h> 408c384020SXin LI #include <sys/types.h> 411e62ecedSEdward Tomasz Napierala #include <sys/sbuf.h> 428c384020SXin LI #include <sys/socket.h> 432d5ea05aSXin LI #include <sys/sysctl.h> 441e62ecedSEdward Tomasz Napierala #include <sys/qmath.h> 451e62ecedSEdward Tomasz Napierala #include <sys/stats.h> 468c384020SXin LI #include <sys/time.h> 473ae0125aSXin LI #include <sys/uio.h> 488c384020SXin LI #include <sys/un.h> 498c384020SXin LI 508c384020SXin LI #include <netinet/in.h> 5104def624SXin LI #ifdef IPSEC 528409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h> 5304def624SXin LI #endif 548c384020SXin LI #include <netinet/tcp.h> 552440a458SXin LI #include <netinet/ip.h> 568c384020SXin LI #include <arpa/telnet.h> 578c384020SXin LI 588c384020SXin LI #include <err.h> 597dcaa833SXin LI #include <getopt.h> 60100e2a06SXin LI #include <fcntl.h> 61100e2a06SXin LI #include <limits.h> 628c384020SXin LI #include <netdb.h> 638c384020SXin LI #include <poll.h> 64100e2a06SXin LI #include <signal.h> 658c384020SXin LI #include <stdarg.h> 668c384020SXin LI #include <stdlib.h> 678c384020SXin LI #include <string.h> 688c384020SXin LI #include <unistd.h> 692440a458SXin LI #include "atomicio.h" 708c384020SXin LI 718c384020SXin LI #ifndef SUN_LEN 728c384020SXin LI #define SUN_LEN(su) \ 738c384020SXin LI (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 748c384020SXin LI #endif 758c384020SXin LI 768c384020SXin LI #define PORT_MAX 65535 778c384020SXin LI #define PORT_MAX_LEN 6 7859c7ad52SXin LI #define UNIX_DG_TMP_SOCKET_SIZE 19 798c384020SXin LI 808c54dbfbSXin LI #define POLL_STDIN 0 818c54dbfbSXin LI #define POLL_NETOUT 1 828c54dbfbSXin LI #define POLL_NETIN 2 838c54dbfbSXin LI #define POLL_STDOUT 3 848c54dbfbSXin LI #define BUFSIZE 16384 858c54dbfbSXin LI 868c384020SXin LI /* Command Line Options */ 878c384020SXin LI int dflag; /* detached, no stdin */ 883ae0125aSXin LI int Fflag; /* fdpass sock to stdout */ 89bdb0aaa1SXin LI unsigned int iflag; /* Interval Flag */ 908c384020SXin LI int kflag; /* More than one connect */ 918c384020SXin LI int lflag; /* Bind to local port */ 92*04a3ca71SMark Johnston int FreeBSD_lb; /* Use SO_REUSEPORT_LB */ 931e62ecedSEdward Tomasz Napierala int FreeBSD_Mflag; /* Measure using stats(3) */ 940772266eSXin LI int Nflag; /* shutdown() network socket */ 958c384020SXin LI int nflag; /* Don't do name look up */ 967dcaa833SXin LI int FreeBSD_Oflag; /* Do not use TCP options */ 97d0415892SMark Johnston int FreeBSD_sctp; /* Use SCTP */ 98d4b3aefdSPietro Cerutti int FreeBSD_crlf; /* Convert LF to CRLF */ 992440a458SXin LI char *Pflag; /* Proxy username */ 1008c384020SXin LI char *pflag; /* Localport flag */ 1018c384020SXin LI int rflag; /* Random ports flag */ 1028c384020SXin LI char *sflag; /* Source Address */ 1038c384020SXin LI int tflag; /* Telnet Emulation */ 1048c384020SXin LI int uflag; /* UDP - Default to TCP */ 1058c384020SXin LI int vflag; /* Verbosity */ 1068c384020SXin LI int xflag; /* Socks proxy */ 1078c384020SXin LI int zflag; /* Port Scan Flag */ 1088c384020SXin LI int Dflag; /* sodebug */ 1097dcaa833SXin LI int Iflag; /* TCP receive buffer size */ 1107dcaa833SXin LI int Oflag; /* TCP send buffer size */ 1118c384020SXin LI int Sflag; /* TCP MD5 signature option */ 1122440a458SXin LI int Tflag = -1; /* IP Type of Service */ 1133ae0125aSXin LI int rtableid = -1; 1148c384020SXin LI 1158c384020SXin LI int timeout = -1; 1168c384020SXin LI int family = AF_UNSPEC; 117cef7ab70STom Jones int tun_fd = -1; 1188c384020SXin LI char *portlist[PORT_MAX+1]; 11959c7ad52SXin LI char *unix_dg_tmp_socket; 1208c384020SXin LI 1218c384020SXin LI void atelnet(int, unsigned char *, unsigned int); 1228c384020SXin LI void build_ports(char *); 1238c384020SXin LI void help(void); 1248c384020SXin LI int local_listen(char *, char *, struct addrinfo); 1258c384020SXin LI void readwrite(int); 1263ae0125aSXin LI void fdpass(int nfd) __attribute__((noreturn)); 1272440a458SXin LI int remote_connect(const char *, const char *, struct addrinfo); 128ac3ea910SXin LI int timeout_connect(int, const struct sockaddr *, socklen_t); 1292440a458SXin LI int socks_connect(const char *, const char *, struct addrinfo, 1302440a458SXin LI const char *, const char *, struct addrinfo, int, const char *); 1318c384020SXin LI int udptest(int); 13259c7ad52SXin LI int unix_bind(char *); 1338c384020SXin LI int unix_connect(char *); 1348c384020SXin LI int unix_listen(char *); 1351e62ecedSEdward Tomasz Napierala void FreeBSD_stats_setup(int); 1361e62ecedSEdward Tomasz Napierala void FreeBSD_stats_print(int); 1378c54dbfbSXin LI void set_common_sockopts(int, int); 138ac3ea910SXin LI int map_tos(char *, int *); 13952dba105SXin LI void report_connect(const struct sockaddr *, socklen_t); 1408c384020SXin LI void usage(int); 141d4b3aefdSPietro Cerutti ssize_t write_wrapper(int, const void *, size_t); 142d4b3aefdSPietro Cerutti ssize_t drainbuf(int, unsigned char *, size_t *, int); 1438c54dbfbSXin LI ssize_t fillbuf(int, unsigned char *, size_t *); 1448c384020SXin LI 14504def624SXin LI #ifdef IPSEC 146fcf59617SAndrey V. Elsukov void add_ipsec_policy(int, int, char *); 14704def624SXin LI 14804def624SXin LI char *ipsec_policy[2]; 14904def624SXin LI #endif 15004def624SXin LI 151cef7ab70STom Jones enum { 152cef7ab70STom Jones FREEBSD_TUN = CHAR_MAX, /* avoid collision with return values from getopt */ 153cef7ab70STom Jones }; 154cef7ab70STom Jones 1558c384020SXin LI int 1568c384020SXin LI main(int argc, char *argv[]) 1578c384020SXin LI { 15804def624SXin LI int ch, s, ret, socksv, ipsec_count; 1592d5ea05aSXin LI int numfibs; 1602d5ea05aSXin LI size_t intsize = sizeof(int); 161bdb0aaa1SXin LI char *host, *uport; 1628c384020SXin LI struct addrinfo hints; 1638c384020SXin LI struct servent *sv; 1648c384020SXin LI socklen_t len; 1658c384020SXin LI struct sockaddr_storage cliaddr; 1668c384020SXin LI char *proxy; 167cef7ab70STom Jones const char *errstr, *proxyhost = "", *proxyport = NULL, *tundev = NULL; 1688c384020SXin LI struct addrinfo proxyhints; 16959c7ad52SXin LI char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; 1707dcaa833SXin LI struct option longopts[] = { 171d4b3aefdSPietro Cerutti { "crlf", no_argument, &FreeBSD_crlf, 1 }, 172*04a3ca71SMark Johnston { "lb", no_argument, &FreeBSD_lb, 1 }, 1737dcaa833SXin LI { "no-tcpopt", no_argument, &FreeBSD_Oflag, 1 }, 174d0415892SMark Johnston { "sctp", no_argument, &FreeBSD_sctp, 1 }, 175cef7ab70STom Jones { "tun", required_argument, NULL, FREEBSD_TUN }, 1767dcaa833SXin LI { NULL, 0, NULL, 0 } 1777dcaa833SXin LI }; 1788c384020SXin LI 1798c384020SXin LI ret = 1; 18004def624SXin LI ipsec_count = 0; 1818c384020SXin LI s = 0; 1828c384020SXin LI socksv = 5; 1838c384020SXin LI host = NULL; 1848c384020SXin LI uport = NULL; 1858c384020SXin LI sv = NULL; 1868c384020SXin LI 187100e2a06SXin LI signal(SIGPIPE, SIG_IGN); 188100e2a06SXin LI 1897dcaa833SXin LI while ((ch = getopt_long(argc, argv, 1901e62ecedSEdward Tomasz Napierala "46DdEe:FhI:i:klMNnoO:P:p:rSs:tT:UuV:vw:X:x:z", 1917dcaa833SXin LI longopts, NULL)) != -1) { 1928c384020SXin LI switch (ch) { 1938c384020SXin LI case '4': 1948c384020SXin LI family = AF_INET; 1958c384020SXin LI break; 1968c384020SXin LI case '6': 1978c384020SXin LI family = AF_INET6; 1988c384020SXin LI break; 1998c384020SXin LI case 'U': 2008c384020SXin LI family = AF_UNIX; 2018c384020SXin LI break; 2028c384020SXin LI case 'X': 2038c384020SXin LI if (strcasecmp(optarg, "connect") == 0) 2048c384020SXin LI socksv = -1; /* HTTP proxy CONNECT */ 2058c384020SXin LI else if (strcmp(optarg, "4") == 0) 2068c384020SXin LI socksv = 4; /* SOCKS v.4 */ 2078c384020SXin LI else if (strcmp(optarg, "5") == 0) 2088c384020SXin LI socksv = 5; /* SOCKS v.5 */ 2098c384020SXin LI else 2108c384020SXin LI errx(1, "unsupported proxy protocol"); 2118c384020SXin LI break; 2128c384020SXin LI case 'd': 2138c384020SXin LI dflag = 1; 2148c384020SXin LI break; 21504def624SXin LI case 'e': 21604def624SXin LI #ifdef IPSEC 21704def624SXin LI ipsec_policy[ipsec_count++ % 2] = optarg; 21804def624SXin LI #else 21904def624SXin LI errx(1, "IPsec support unavailable."); 22004def624SXin LI #endif 22104def624SXin LI break; 22204def624SXin LI case 'E': 22304def624SXin LI #ifdef IPSEC 22404def624SXin LI ipsec_policy[0] = "in ipsec esp/transport//require"; 22504def624SXin LI ipsec_policy[1] = "out ipsec esp/transport//require"; 22604def624SXin LI #else 22704def624SXin LI errx(1, "IPsec support unavailable."); 22804def624SXin LI #endif 22904def624SXin LI break; 2303ae0125aSXin LI case 'F': 2313ae0125aSXin LI Fflag = 1; 2323ae0125aSXin LI break; 2338c384020SXin LI case 'h': 2348c384020SXin LI help(); 2358c384020SXin LI break; 2368c384020SXin LI case 'i': 237bdb0aaa1SXin LI iflag = strtonum(optarg, 0, UINT_MAX, &errstr); 238bdb0aaa1SXin LI if (errstr) 239bdb0aaa1SXin LI errx(1, "interval %s: %s", errstr, optarg); 2408c384020SXin LI break; 2418c384020SXin LI case 'k': 2428c384020SXin LI kflag = 1; 2438c384020SXin LI break; 2448c384020SXin LI case 'l': 2458c384020SXin LI lflag = 1; 2468c384020SXin LI break; 2471e62ecedSEdward Tomasz Napierala case 'M': 2481e62ecedSEdward Tomasz Napierala #ifndef WITH_STATS 2491e62ecedSEdward Tomasz Napierala errx(1, "-M requires stats(3) support"); 2501e62ecedSEdward Tomasz Napierala #else 2511e62ecedSEdward Tomasz Napierala FreeBSD_Mflag = 1; 2521e62ecedSEdward Tomasz Napierala #endif 2531e62ecedSEdward Tomasz Napierala break; 2540772266eSXin LI case 'N': 2550772266eSXin LI Nflag = 1; 2560772266eSXin LI break; 2578c384020SXin LI case 'n': 2588c384020SXin LI nflag = 1; 2598c384020SXin LI break; 26004def624SXin LI case 'o': 26155e99985SXin LI fprintf(stderr, "option -o is deprecated.\n"); 26204def624SXin LI break; 2632440a458SXin LI case 'P': 2642440a458SXin LI Pflag = optarg; 2652440a458SXin LI break; 2668c384020SXin LI case 'p': 2678c384020SXin LI pflag = optarg; 2688c384020SXin LI break; 2698c384020SXin LI case 'r': 2708c384020SXin LI rflag = 1; 2718c384020SXin LI break; 2728c384020SXin LI case 's': 2738c384020SXin LI sflag = optarg; 2748c384020SXin LI break; 2758c384020SXin LI case 't': 2768c384020SXin LI tflag = 1; 2778c384020SXin LI break; 2788c384020SXin LI case 'u': 2798c384020SXin LI uflag = 1; 2808c384020SXin LI break; 2812d5ea05aSXin LI case 'V': 2822d5ea05aSXin LI if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 2832d5ea05aSXin LI errx(1, "Multiple FIBS not supported"); 2843ae0125aSXin LI rtableid = (int)strtonum(optarg, 0, 2852d5ea05aSXin LI numfibs - 1, &errstr); 2862d5ea05aSXin LI if (errstr) 2874f2bbc00SXin LI errx(1, "rtable %s: %s", errstr, optarg); 2882d5ea05aSXin LI break; 2898c384020SXin LI case 'v': 2908c384020SXin LI vflag = 1; 2918c384020SXin LI break; 2928c384020SXin LI case 'w': 293bdb0aaa1SXin LI timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); 294bdb0aaa1SXin LI if (errstr) 295bdb0aaa1SXin LI errx(1, "timeout %s: %s", errstr, optarg); 2968c384020SXin LI timeout *= 1000; 2978c384020SXin LI break; 2988c384020SXin LI case 'x': 2998c384020SXin LI xflag = 1; 3008c384020SXin LI if ((proxy = strdup(optarg)) == NULL) 3018c384020SXin LI err(1, NULL); 3028c384020SXin LI break; 3038c384020SXin LI case 'z': 3048c384020SXin LI zflag = 1; 3058c384020SXin LI break; 3068c384020SXin LI case 'D': 3078c384020SXin LI Dflag = 1; 3088c384020SXin LI break; 3097dcaa833SXin LI case 'I': 3107dcaa833SXin LI Iflag = strtonum(optarg, 1, 65536 << 14, &errstr); 3117dcaa833SXin LI if (errstr != NULL) 3127dcaa833SXin LI errx(1, "TCP receive window %s: %s", 3137dcaa833SXin LI errstr, optarg); 3147dcaa833SXin LI break; 3157dcaa833SXin LI case 'O': 3167dcaa833SXin LI Oflag = strtonum(optarg, 1, 65536 << 14, &errstr); 3177dcaa833SXin LI if (errstr != NULL) { 3187dcaa833SXin LI if (strcmp(errstr, "invalid") != 0) 3197dcaa833SXin LI errx(1, "TCP send window %s: %s", 3207dcaa833SXin LI errstr, optarg); 3217dcaa833SXin LI } 3227dcaa833SXin LI break; 3238c384020SXin LI case 'S': 3248c384020SXin LI Sflag = 1; 3258c384020SXin LI break; 3262440a458SXin LI case 'T': 327ac3ea910SXin LI errstr = NULL; 328ac3ea910SXin LI errno = 0; 329ac3ea910SXin LI if (map_tos(optarg, &Tflag)) 330ac3ea910SXin LI break; 331ac3ea910SXin LI if (strlen(optarg) > 1 && optarg[0] == '0' && 332ac3ea910SXin LI optarg[1] == 'x') 333ac3ea910SXin LI Tflag = (int)strtol(optarg, NULL, 16); 334ac3ea910SXin LI else 335ac3ea910SXin LI Tflag = (int)strtonum(optarg, 0, 255, 336ac3ea910SXin LI &errstr); 337ac3ea910SXin LI if (Tflag < 0 || Tflag > 255 || errstr || errno) 338ac3ea910SXin LI errx(1, "illegal tos value %s", optarg); 3392440a458SXin LI break; 340cef7ab70STom Jones case FREEBSD_TUN: 341cef7ab70STom Jones tundev = optarg; 342cef7ab70STom Jones break; 343d0415892SMark Johnston case 0: 344d0415892SMark Johnston /* Long option. */ 345d0415892SMark Johnston break; 3468c384020SXin LI default: 3478c384020SXin LI usage(1); 3488c384020SXin LI } 3498c384020SXin LI } 3508c384020SXin LI argc -= optind; 3518c384020SXin LI argv += optind; 3528c384020SXin LI 3538c384020SXin LI /* Cruft to make sure options are clean, and used properly. */ 3548c384020SXin LI if (argv[0] && !argv[1] && family == AF_UNIX) { 3558c384020SXin LI host = argv[0]; 3568c384020SXin LI uport = NULL; 3578c384020SXin LI } else if (argv[0] && !argv[1]) { 3588c384020SXin LI if (!lflag) 3598c384020SXin LI usage(1); 3608c384020SXin LI uport = argv[0]; 3618c384020SXin LI host = NULL; 3628c384020SXin LI } else if (argv[0] && argv[1]) { 3638c384020SXin LI host = argv[0]; 3648c384020SXin LI uport = argv[1]; 3658c384020SXin LI } else 3668c384020SXin LI usage(1); 3678c384020SXin LI 3688c384020SXin LI if (lflag && sflag) 3698c384020SXin LI errx(1, "cannot use -s and -l"); 3708c384020SXin LI if (lflag && pflag) 3718c384020SXin LI errx(1, "cannot use -p and -l"); 3728c384020SXin LI if (lflag && zflag) 3738c384020SXin LI errx(1, "cannot use -z and -l"); 3748c384020SXin LI if (!lflag && kflag) 3758c384020SXin LI errx(1, "must use -l with -k"); 376*04a3ca71SMark Johnston if (!lflag && FreeBSD_lb) 377*04a3ca71SMark Johnston errx(1, "must use -l with --lb"); 378d0415892SMark Johnston if (FreeBSD_sctp) { 379d0415892SMark Johnston if (uflag) 380d0415892SMark Johnston errx(1, "cannot use -u and --sctp"); 381d0415892SMark Johnston if (family == AF_UNIX) 382d0415892SMark Johnston errx(1, "cannot use -U and --sctp"); 383d0415892SMark Johnston } 384cef7ab70STom Jones if (tundev != NULL) { 385cef7ab70STom Jones if (!uflag) 386cef7ab70STom Jones errx(1, "must use --tun with -u"); 387cef7ab70STom Jones tun_fd = open(tundev, O_RDWR); 388cef7ab70STom Jones if (tun_fd == -1) 389cef7ab70STom Jones errx(1, "unable to open tun device %s", tundev); 390cef7ab70STom Jones } 3918c384020SXin LI 39259c7ad52SXin LI /* Get name of temporary socket for unix datagram client */ 39359c7ad52SXin LI if ((family == AF_UNIX) && uflag && !lflag) { 39459c7ad52SXin LI if (sflag) { 39559c7ad52SXin LI unix_dg_tmp_socket = sflag; 39659c7ad52SXin LI } else { 39759c7ad52SXin LI strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", 39859c7ad52SXin LI UNIX_DG_TMP_SOCKET_SIZE); 39959c7ad52SXin LI if (mktemp(unix_dg_tmp_socket_buf) == NULL) 40059c7ad52SXin LI err(1, "mktemp"); 40159c7ad52SXin LI unix_dg_tmp_socket = unix_dg_tmp_socket_buf; 40259c7ad52SXin LI } 40359c7ad52SXin LI } 40459c7ad52SXin LI 4058c384020SXin LI /* Initialize addrinfo structure. */ 4068c384020SXin LI if (family != AF_UNIX) { 4078c384020SXin LI memset(&hints, 0, sizeof(struct addrinfo)); 4088c384020SXin LI hints.ai_family = family; 4098c384020SXin LI hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 410d0415892SMark Johnston hints.ai_protocol = uflag ? IPPROTO_UDP : 411d0415892SMark Johnston FreeBSD_sctp ? IPPROTO_SCTP : IPPROTO_TCP; 4128c384020SXin LI if (nflag) 4138c384020SXin LI hints.ai_flags |= AI_NUMERICHOST; 4148c384020SXin LI } 4158c384020SXin LI 4168c384020SXin LI if (xflag) { 4178c384020SXin LI if (uflag) 4188c384020SXin LI errx(1, "no proxy support for UDP mode"); 4198c384020SXin LI 420d0415892SMark Johnston if (FreeBSD_sctp) 421d0415892SMark Johnston errx(1, "no proxy support for SCTP mode"); 422d0415892SMark Johnston 4238c384020SXin LI if (lflag) 4248c384020SXin LI errx(1, "no proxy support for listen"); 4258c384020SXin LI 4268c384020SXin LI if (family == AF_UNIX) 4278c384020SXin LI errx(1, "no proxy support for unix sockets"); 4288c384020SXin LI 4298c384020SXin LI /* XXX IPv6 transport to proxy would probably work */ 4308c384020SXin LI if (family == AF_INET6) 4318c384020SXin LI errx(1, "no proxy support for IPv6"); 4328c384020SXin LI 4338c384020SXin LI if (sflag) 4348c384020SXin LI errx(1, "no proxy support for local source address"); 4358c384020SXin LI 4368c384020SXin LI proxyhost = strsep(&proxy, ":"); 4378c384020SXin LI proxyport = proxy; 4388c384020SXin LI 4398c384020SXin LI memset(&proxyhints, 0, sizeof(struct addrinfo)); 4408c384020SXin LI proxyhints.ai_family = family; 4418c384020SXin LI proxyhints.ai_socktype = SOCK_STREAM; 4428c384020SXin LI proxyhints.ai_protocol = IPPROTO_TCP; 4438c384020SXin LI if (nflag) 4448c384020SXin LI proxyhints.ai_flags |= AI_NUMERICHOST; 4458c384020SXin LI } 4468c384020SXin LI 4478c384020SXin LI if (lflag) { 4488c384020SXin LI int connfd; 4498c384020SXin LI ret = 0; 4508c384020SXin LI 45159c7ad52SXin LI if (family == AF_UNIX) { 45259c7ad52SXin LI if (uflag) 45359c7ad52SXin LI s = unix_bind(host); 45459c7ad52SXin LI else 4558c384020SXin LI s = unix_listen(host); 45659c7ad52SXin LI } 4578c384020SXin LI 4588c384020SXin LI /* Allow only one connection at a time, but stay alive. */ 4598c384020SXin LI for (;;) { 4608c384020SXin LI if (family != AF_UNIX) 4618c384020SXin LI s = local_listen(host, uport, hints); 4628c384020SXin LI if (s < 0) 4638c384020SXin LI err(1, NULL); 4648c384020SXin LI /* 46552dba105SXin LI * For UDP and -k, don't connect the socket, let it 46652dba105SXin LI * receive datagrams from multiple socket pairs. 4678c384020SXin LI */ 46852dba105SXin LI if (uflag && kflag) 46952dba105SXin LI readwrite(s); 47052dba105SXin LI /* 47152dba105SXin LI * For UDP and not -k, we will use recvfrom() initially 47252dba105SXin LI * to wait for a caller, then use the regular functions 47352dba105SXin LI * to talk to the caller. 47452dba105SXin LI */ 47552dba105SXin LI else if (uflag && !kflag) { 4762440a458SXin LI int rv, plen; 4774f2bbc00SXin LI char buf[16384]; 4788c384020SXin LI struct sockaddr_storage z; 4798c384020SXin LI 4808c384020SXin LI len = sizeof(z); 48152dba105SXin LI plen = 2048; 4822440a458SXin LI rv = recvfrom(s, buf, plen, MSG_PEEK, 4838c384020SXin LI (struct sockaddr *)&z, &len); 4848c384020SXin LI if (rv < 0) 4858c384020SXin LI err(1, "recvfrom"); 4868c384020SXin LI 4878c384020SXin LI rv = connect(s, (struct sockaddr *)&z, len); 4888c384020SXin LI if (rv < 0) 4898c384020SXin LI err(1, "connect"); 4908c384020SXin LI 49152dba105SXin LI if (vflag) 49252dba105SXin LI report_connect((struct sockaddr *)&z, len); 49352dba105SXin LI 49459c7ad52SXin LI readwrite(s); 4958c384020SXin LI } else { 4962440a458SXin LI len = sizeof(cliaddr); 4978c384020SXin LI connfd = accept(s, (struct sockaddr *)&cliaddr, 4988c384020SXin LI &len); 4990772266eSXin LI if (connfd == -1) { 5000772266eSXin LI /* For now, all errnos are fatal */ 50152dba105SXin LI err(1, "accept"); 5020772266eSXin LI } 50352dba105SXin LI if (vflag) 50452dba105SXin LI report_connect((struct sockaddr *)&cliaddr, len); 50552dba105SXin LI 5061e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag) 5071e62ecedSEdward Tomasz Napierala FreeBSD_stats_setup(connfd); 5088c384020SXin LI readwrite(connfd); 5098c384020SXin LI close(connfd); 51059c7ad52SXin LI } 51159c7ad52SXin LI 5128c384020SXin LI if (family != AF_UNIX) 5138c384020SXin LI close(s); 51459c7ad52SXin LI else if (uflag) { 51559c7ad52SXin LI if (connect(s, NULL, 0) < 0) 51659c7ad52SXin LI err(1, "connect"); 51759c7ad52SXin LI } 5188c384020SXin LI 5198c384020SXin LI if (!kflag) 5208c384020SXin LI break; 5218c384020SXin LI } 5228c384020SXin LI } else if (family == AF_UNIX) { 5238c384020SXin LI ret = 0; 5248c384020SXin LI 5258c384020SXin LI if ((s = unix_connect(host)) > 0 && !zflag) { 5268c384020SXin LI readwrite(s); 5278c384020SXin LI close(s); 5288c384020SXin LI } else 5298c384020SXin LI ret = 1; 5308c384020SXin LI 53159c7ad52SXin LI if (uflag) 53259c7ad52SXin LI unlink(unix_dg_tmp_socket); 5338c384020SXin LI exit(ret); 5348c384020SXin LI 5358c384020SXin LI } else { 5368c384020SXin LI int i = 0; 5378c384020SXin LI 5388c384020SXin LI /* Construct the portlist[] array. */ 5398c384020SXin LI build_ports(uport); 5408c384020SXin LI 5418c384020SXin LI /* Cycle through portlist, connecting to each port. */ 5428c384020SXin LI for (i = 0; portlist[i] != NULL; i++) { 5438c384020SXin LI if (s) 5448c384020SXin LI close(s); 5458c384020SXin LI 5468c384020SXin LI if (xflag) 5478c384020SXin LI s = socks_connect(host, portlist[i], hints, 5482440a458SXin LI proxyhost, proxyport, proxyhints, socksv, 5492440a458SXin LI Pflag); 5508c384020SXin LI else 5518c384020SXin LI s = remote_connect(host, portlist[i], hints); 5528c384020SXin LI 5538c384020SXin LI if (s < 0) 5548c384020SXin LI continue; 5558c384020SXin LI 5568c384020SXin LI ret = 0; 5578c384020SXin LI if (vflag || zflag) { 5588c384020SXin LI /* For UDP, make sure we are connected. */ 5598c384020SXin LI if (uflag) { 5608c384020SXin LI if (udptest(s) == -1) { 5618c384020SXin LI ret = 1; 5628c384020SXin LI continue; 5638c384020SXin LI } 5648c384020SXin LI } 5658c384020SXin LI 5668c384020SXin LI /* Don't look up port if -n. */ 5678c384020SXin LI if (nflag) 5688c384020SXin LI sv = NULL; 5698c384020SXin LI else { 5708c384020SXin LI sv = getservbyport( 5718c384020SXin LI ntohs(atoi(portlist[i])), 5728c384020SXin LI uflag ? "udp" : "tcp"); 5738c384020SXin LI } 5748c384020SXin LI 57526bf9c3bSXin LI fprintf(stderr, 57626bf9c3bSXin LI "Connection to %s %s port [%s/%s] " 57726bf9c3bSXin LI "succeeded!\n", host, portlist[i], 57826bf9c3bSXin LI uflag ? "udp" : "tcp", 5798c384020SXin LI sv ? sv->s_name : "*"); 5808c384020SXin LI } 5813ae0125aSXin LI if (Fflag) 5823ae0125aSXin LI fdpass(s); 5833ae0125aSXin LI else if (!zflag) 5848c384020SXin LI readwrite(s); 5858c384020SXin LI } 5868c384020SXin LI } 5878c384020SXin LI 5888c384020SXin LI if (s) 5898c384020SXin LI close(s); 590cef7ab70STom Jones if (tun_fd != -1) 591cef7ab70STom Jones close(tun_fd); 5928c384020SXin LI 5938c384020SXin LI exit(ret); 5948c384020SXin LI } 5958c384020SXin LI 5968c384020SXin LI /* 59759c7ad52SXin LI * unix_bind() 59859c7ad52SXin LI * Returns a unix socket bound to the given path 59959c7ad52SXin LI */ 60059c7ad52SXin LI int 60159c7ad52SXin LI unix_bind(char *path) 60259c7ad52SXin LI { 60359c7ad52SXin LI struct sockaddr_un sun; 60459c7ad52SXin LI int s; 60559c7ad52SXin LI 60659c7ad52SXin LI /* Create unix domain socket. */ 60759c7ad52SXin LI if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, 60859c7ad52SXin LI 0)) < 0) 60959c7ad52SXin LI return (-1); 61059c7ad52SXin LI 61159c7ad52SXin LI memset(&sun, 0, sizeof(struct sockaddr_un)); 61259c7ad52SXin LI sun.sun_family = AF_UNIX; 61359c7ad52SXin LI 61459c7ad52SXin LI if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 61559c7ad52SXin LI sizeof(sun.sun_path)) { 61659c7ad52SXin LI close(s); 61759c7ad52SXin LI errno = ENAMETOOLONG; 61859c7ad52SXin LI return (-1); 61959c7ad52SXin LI } 62059c7ad52SXin LI 62159c7ad52SXin LI if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { 62259c7ad52SXin LI close(s); 62359c7ad52SXin LI return (-1); 62459c7ad52SXin LI } 62559c7ad52SXin LI return (s); 62659c7ad52SXin LI } 62759c7ad52SXin LI 62859c7ad52SXin LI /* 6298c384020SXin LI * unix_connect() 6308c384020SXin LI * Returns a socket connected to a local unix socket. Returns -1 on failure. 6318c384020SXin LI */ 6328c384020SXin LI int 6338c384020SXin LI unix_connect(char *path) 6348c384020SXin LI { 6358c384020SXin LI struct sockaddr_un sun; 6368c384020SXin LI int s; 6378c384020SXin LI 63859c7ad52SXin LI if (uflag) { 63959c7ad52SXin LI if ((s = unix_bind(unix_dg_tmp_socket)) < 0) 64059c7ad52SXin LI return (-1); 64159c7ad52SXin LI } else { 6428c384020SXin LI if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 6438c384020SXin LI return (-1); 64459c7ad52SXin LI } 6455abd6fdcSXin LI (void)fcntl(s, F_SETFD, FD_CLOEXEC); 6468c384020SXin LI 6478c384020SXin LI memset(&sun, 0, sizeof(struct sockaddr_un)); 6488c384020SXin LI sun.sun_family = AF_UNIX; 6498c384020SXin LI 6508c384020SXin LI if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 6518c384020SXin LI sizeof(sun.sun_path)) { 6528c384020SXin LI close(s); 6538c384020SXin LI errno = ENAMETOOLONG; 6548c384020SXin LI return (-1); 6558c384020SXin LI } 6568c384020SXin LI if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { 6578c384020SXin LI close(s); 6588c384020SXin LI return (-1); 6598c384020SXin LI } 6608c384020SXin LI return (s); 6618c384020SXin LI 6628c384020SXin LI } 6638c384020SXin LI 6648c384020SXin LI /* 6658c384020SXin LI * unix_listen() 6668c384020SXin LI * Create a unix domain socket, and listen on it. 6678c384020SXin LI */ 6688c384020SXin LI int 6698c384020SXin LI unix_listen(char *path) 6708c384020SXin LI { 6718c384020SXin LI int s; 67259c7ad52SXin LI if ((s = unix_bind(path)) < 0) 6738c384020SXin LI return (-1); 6748c384020SXin LI 6758c384020SXin LI if (listen(s, 5) < 0) { 6768c384020SXin LI close(s); 6778c384020SXin LI return (-1); 6788c384020SXin LI } 6798c384020SXin LI return (s); 6808c384020SXin LI } 6818c384020SXin LI 6828c384020SXin LI /* 6838c384020SXin LI * remote_connect() 6848c384020SXin LI * Returns a socket connected to a remote host. Properly binds to a local 6858c384020SXin LI * port or source address if needed. Returns -1 on failure. 6868c384020SXin LI */ 6878c384020SXin LI int 6882440a458SXin LI remote_connect(const char *host, const char *port, struct addrinfo hints) 6898c384020SXin LI { 6908c384020SXin LI struct addrinfo *res, *res0; 6917dcaa833SXin LI int s, error, on = 1; 6928c384020SXin LI 6938c384020SXin LI if ((error = getaddrinfo(host, port, &hints, &res))) 6948c384020SXin LI errx(1, "getaddrinfo: %s", gai_strerror(error)); 6958c384020SXin LI 6968c384020SXin LI res0 = res; 6978c384020SXin LI do { 6988c384020SXin LI if ((s = socket(res0->ai_family, res0->ai_socktype, 6998c384020SXin LI res0->ai_protocol)) < 0) 7008c384020SXin LI continue; 7018c384020SXin LI 7023ae0125aSXin LI if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB, 7033ae0125aSXin LI &rtableid, sizeof(rtableid)) == -1)) 7043ae0125aSXin LI err(1, "setsockopt SO_SETFIB"); 7052d5ea05aSXin LI 7068c384020SXin LI /* Bind to a local port or source address if specified. */ 7078c384020SXin LI if (sflag || pflag) { 7088c384020SXin LI struct addrinfo ahints, *ares; 7098c384020SXin LI 7106856a5e3SXin LI /* try IP_BINDANY, but don't insist */ 7116856a5e3SXin LI setsockopt(s, IPPROTO_IP, IP_BINDANY, &on, sizeof(on)); 7128c384020SXin LI memset(&ahints, 0, sizeof(struct addrinfo)); 7138c384020SXin LI ahints.ai_family = res0->ai_family; 7148c384020SXin LI ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 7158c384020SXin LI ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 7168c384020SXin LI ahints.ai_flags = AI_PASSIVE; 7178c384020SXin LI if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) 7188c384020SXin LI errx(1, "getaddrinfo: %s", gai_strerror(error)); 7198c384020SXin LI 7208c384020SXin LI if (bind(s, (struct sockaddr *)ares->ai_addr, 7218c384020SXin LI ares->ai_addrlen) < 0) 722a5570ae0SXin LI err(1, "bind failed"); 7238c384020SXin LI freeaddrinfo(ares); 7248c384020SXin LI } 7252440a458SXin LI 7268c54dbfbSXin LI set_common_sockopts(s, res0->ai_family); 7278c384020SXin LI 728ac3ea910SXin LI if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 7298c384020SXin LI break; 7308c384020SXin LI else if (vflag) 7318c384020SXin LI warn("connect to %s port %s (%s) failed", host, port, 7328c384020SXin LI uflag ? "udp" : "tcp"); 7338c384020SXin LI 7348c384020SXin LI close(s); 7358c384020SXin LI s = -1; 7368c384020SXin LI } while ((res0 = res0->ai_next) != NULL); 7378c384020SXin LI 7388c384020SXin LI freeaddrinfo(res); 7398c384020SXin LI 7408c384020SXin LI return (s); 7418c384020SXin LI } 7428c384020SXin LI 743ac3ea910SXin LI int 744ac3ea910SXin LI timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) 745ac3ea910SXin LI { 746ac3ea910SXin LI struct pollfd pfd; 747ac3ea910SXin LI socklen_t optlen; 748ac3ea910SXin LI int flags, optval; 749ac3ea910SXin LI int ret; 750ac3ea910SXin LI 751ac3ea910SXin LI if (timeout != -1) { 752ac3ea910SXin LI flags = fcntl(s, F_GETFL, 0); 753ac3ea910SXin LI if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 754ac3ea910SXin LI err(1, "set non-blocking mode"); 755ac3ea910SXin LI } 756ac3ea910SXin LI 757ac3ea910SXin LI if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { 758ac3ea910SXin LI pfd.fd = s; 759ac3ea910SXin LI pfd.events = POLLOUT; 760ac3ea910SXin LI if ((ret = poll(&pfd, 1, timeout)) == 1) { 761ac3ea910SXin LI optlen = sizeof(optval); 762ac3ea910SXin LI if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, 763ac3ea910SXin LI &optval, &optlen)) == 0) { 764ac3ea910SXin LI errno = optval; 765ac3ea910SXin LI ret = optval == 0 ? 0 : -1; 766ac3ea910SXin LI } 767ac3ea910SXin LI } else if (ret == 0) { 768ac3ea910SXin LI errno = ETIMEDOUT; 769ac3ea910SXin LI ret = -1; 770ac3ea910SXin LI } else 771ac3ea910SXin LI err(1, "poll failed"); 772ac3ea910SXin LI } 773ac3ea910SXin LI 774ac3ea910SXin LI if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) 775ac3ea910SXin LI err(1, "restoring flags"); 776ac3ea910SXin LI 777ac3ea910SXin LI return (ret); 778ac3ea910SXin LI } 779ac3ea910SXin LI 7808c384020SXin LI /* 7818c384020SXin LI * local_listen() 7828c384020SXin LI * Returns a socket listening on a local port, binds to specified source 7838c384020SXin LI * address. Returns -1 on failure. 7848c384020SXin LI */ 7858c384020SXin LI int 7868c384020SXin LI local_listen(char *host, char *port, struct addrinfo hints) 7878c384020SXin LI { 7888c384020SXin LI struct addrinfo *res, *res0; 7898c384020SXin LI int s, ret, x = 1; 7908c384020SXin LI int error; 7918c384020SXin LI 7928c384020SXin LI /* Allow nodename to be null. */ 7938c384020SXin LI hints.ai_flags |= AI_PASSIVE; 7948c384020SXin LI 7958c384020SXin LI /* 7968c384020SXin LI * In the case of binding to a wildcard address 7978c384020SXin LI * default to binding to an ipv4 address. 7988c384020SXin LI */ 7998c384020SXin LI if (host == NULL && hints.ai_family == AF_UNSPEC) 8008c384020SXin LI hints.ai_family = AF_INET; 8018c384020SXin LI 8028c384020SXin LI if ((error = getaddrinfo(host, port, &hints, &res))) 8038c384020SXin LI errx(1, "getaddrinfo: %s", gai_strerror(error)); 8048c384020SXin LI 8058c384020SXin LI res0 = res; 8068c384020SXin LI do { 807*04a3ca71SMark Johnston int opt; 808*04a3ca71SMark Johnston 8098c384020SXin LI if ((s = socket(res0->ai_family, res0->ai_socktype, 8102440a458SXin LI res0->ai_protocol)) < 0) 8118c384020SXin LI continue; 8128c384020SXin LI 813a5570ae0SXin LI if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB, 8143ae0125aSXin LI &rtableid, sizeof(rtableid)) == -1)) 8153ae0125aSXin LI err(1, "setsockopt SO_SETFIB"); 8162d5ea05aSXin LI 817*04a3ca71SMark Johnston opt = FreeBSD_lb != 0 ? SO_REUSEPORT_LB : SO_REUSEPORT; 818*04a3ca71SMark Johnston ret = setsockopt(s, SOL_SOCKET, opt, &x, sizeof(x)); 8198c384020SXin LI if (ret == -1) 8208c384020SXin LI err(1, NULL); 821fcf59617SAndrey V. Elsukov 8227dcaa833SXin LI if (FreeBSD_Oflag) { 823bc38f653SBruce M Simpson if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, 8247dcaa833SXin LI &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1) 825bc38f653SBruce M Simpson err(1, "disable TCP options"); 826bc38f653SBruce M Simpson } 8278c384020SXin LI 8288c54dbfbSXin LI set_common_sockopts(s, res0->ai_family); 8298c54dbfbSXin LI 8308c384020SXin LI if (bind(s, (struct sockaddr *)res0->ai_addr, 8318c384020SXin LI res0->ai_addrlen) == 0) 8328c384020SXin LI break; 8338c384020SXin LI 8348c384020SXin LI close(s); 8358c384020SXin LI s = -1; 8368c384020SXin LI } while ((res0 = res0->ai_next) != NULL); 8378c384020SXin LI 8388c384020SXin LI if (!uflag && s != -1) { 8398c384020SXin LI if (listen(s, 1) < 0) 8408c384020SXin LI err(1, "listen"); 8418c384020SXin LI } 8428c384020SXin LI 8438c384020SXin LI freeaddrinfo(res); 8448c384020SXin LI 8458c384020SXin LI return (s); 8468c384020SXin LI } 8478c384020SXin LI 8488c384020SXin LI /* 8498c384020SXin LI * readwrite() 8508c384020SXin LI * Loop that polls on the network file descriptor and stdin. 8518c384020SXin LI */ 8528c384020SXin LI void 8538c54dbfbSXin LI readwrite(int net_fd) 8548c384020SXin LI { 8558c54dbfbSXin LI struct pollfd pfd[4]; 8568c54dbfbSXin LI int stdin_fd = STDIN_FILENO; 8578c54dbfbSXin LI int stdout_fd = STDOUT_FILENO; 8588c54dbfbSXin LI unsigned char netinbuf[BUFSIZE]; 8598c54dbfbSXin LI size_t netinbufpos = 0; 8608c54dbfbSXin LI unsigned char stdinbuf[BUFSIZE]; 8618c54dbfbSXin LI size_t stdinbufpos = 0; 8628c54dbfbSXin LI int n, num_fds; 8631e62ecedSEdward Tomasz Napierala int stats_printed = 0; 8648c54dbfbSXin LI ssize_t ret; 8652440a458SXin LI 8668c54dbfbSXin LI /* don't read from stdin if requested */ 8678c54dbfbSXin LI if (dflag) 8688c54dbfbSXin LI stdin_fd = -1; 8698c384020SXin LI 8708c54dbfbSXin LI /* stdin */ 871cef7ab70STom Jones pfd[POLL_STDIN].fd = (tun_fd != -1) ? tun_fd : stdin_fd; 8728c54dbfbSXin LI pfd[POLL_STDIN].events = POLLIN; 8738c384020SXin LI 8748c54dbfbSXin LI /* network out */ 8758c54dbfbSXin LI pfd[POLL_NETOUT].fd = net_fd; 8768c54dbfbSXin LI pfd[POLL_NETOUT].events = 0; 8778c384020SXin LI 8788c54dbfbSXin LI /* network in */ 8798c54dbfbSXin LI pfd[POLL_NETIN].fd = net_fd; 8808c54dbfbSXin LI pfd[POLL_NETIN].events = POLLIN; 8818c54dbfbSXin LI 8828c54dbfbSXin LI /* stdout */ 883cef7ab70STom Jones pfd[POLL_STDOUT].fd = (tun_fd != -1) ? tun_fd : stdout_fd; 8848c54dbfbSXin LI pfd[POLL_STDOUT].events = 0; 8858c54dbfbSXin LI 8868c54dbfbSXin LI while (1) { 8878c54dbfbSXin LI /* both inputs are gone, buffers are empty, we are done */ 8888c54dbfbSXin LI if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 8898c54dbfbSXin LI && stdinbufpos == 0 && netinbufpos == 0) { 8901e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag && !stats_printed) 8911e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(net_fd); 8928c54dbfbSXin LI close(net_fd); 8938c54dbfbSXin LI return; 8948c54dbfbSXin LI } 8958c54dbfbSXin LI /* both outputs are gone, we can't continue */ 8968c54dbfbSXin LI if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { 8971e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag && !stats_printed) 8981e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(net_fd); 8998c54dbfbSXin LI close(net_fd); 9008c54dbfbSXin LI return; 9018c54dbfbSXin LI } 9028c54dbfbSXin LI /* listen and net in gone, queues empty, done */ 9038c54dbfbSXin LI if (lflag && pfd[POLL_NETIN].fd == -1 9048c54dbfbSXin LI && stdinbufpos == 0 && netinbufpos == 0) { 9051e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag && !stats_printed) 9061e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(net_fd); 9078c54dbfbSXin LI close(net_fd); 9088c54dbfbSXin LI return; 9098c54dbfbSXin LI } 9108c54dbfbSXin LI 9118c54dbfbSXin LI /* help says -i is for "wait between lines sent". We read and 9128c54dbfbSXin LI * write arbitrary amounts of data, and we don't want to start 9138c54dbfbSXin LI * scanning for newlines, so this is as good as it gets */ 9148c384020SXin LI if (iflag) 9158c384020SXin LI sleep(iflag); 9168c384020SXin LI 9178c54dbfbSXin LI /* poll */ 9188c54dbfbSXin LI num_fds = poll(pfd, 4, timeout); 9198c54dbfbSXin LI 9208c54dbfbSXin LI /* treat poll errors */ 9218c54dbfbSXin LI if (num_fds == -1) { 9228c54dbfbSXin LI close(net_fd); 9238c54dbfbSXin LI err(1, "polling error"); 9248c384020SXin LI } 9258c384020SXin LI 9268c54dbfbSXin LI /* timeout happened */ 9271e62ecedSEdward Tomasz Napierala if (num_fds == 0) { 9281e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag) 9291e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(net_fd); 9308c384020SXin LI return; 9311e62ecedSEdward Tomasz Napierala } 9328c384020SXin LI 9338c54dbfbSXin LI /* treat socket error conditions */ 9348c54dbfbSXin LI for (n = 0; n < 4; n++) { 9358c54dbfbSXin LI if (pfd[n].revents & (POLLERR|POLLNVAL)) { 9368c54dbfbSXin LI pfd[n].fd = -1; 9378c384020SXin LI } 9388c384020SXin LI } 9398c54dbfbSXin LI /* reading is possible after HUP */ 9408c54dbfbSXin LI if (pfd[POLL_STDIN].events & POLLIN && 9418c54dbfbSXin LI pfd[POLL_STDIN].revents & POLLHUP && 9428c54dbfbSXin LI ! (pfd[POLL_STDIN].revents & POLLIN)) 9438c54dbfbSXin LI pfd[POLL_STDIN].fd = -1; 9448c384020SXin LI 9458c54dbfbSXin LI if (pfd[POLL_NETIN].events & POLLIN && 9468c54dbfbSXin LI pfd[POLL_NETIN].revents & POLLHUP && 9478c54dbfbSXin LI ! (pfd[POLL_NETIN].revents & POLLIN)) 9488c54dbfbSXin LI pfd[POLL_NETIN].fd = -1; 9498c54dbfbSXin LI 9508c54dbfbSXin LI if (pfd[POLL_NETOUT].revents & POLLHUP) { 9510772266eSXin LI if (Nflag) 9528c54dbfbSXin LI shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); 9538c54dbfbSXin LI pfd[POLL_NETOUT].fd = -1; 9548c54dbfbSXin LI } 9558c54dbfbSXin LI /* if HUP, stop watching stdout */ 9568c54dbfbSXin LI if (pfd[POLL_STDOUT].revents & POLLHUP) 9578c54dbfbSXin LI pfd[POLL_STDOUT].fd = -1; 9588c54dbfbSXin LI /* if no net out, stop watching stdin */ 9598c54dbfbSXin LI if (pfd[POLL_NETOUT].fd == -1) 9608c54dbfbSXin LI pfd[POLL_STDIN].fd = -1; 9618c54dbfbSXin LI /* if no stdout, stop watching net in */ 9628c54dbfbSXin LI if (pfd[POLL_STDOUT].fd == -1) { 9638c54dbfbSXin LI if (pfd[POLL_NETIN].fd != -1) 9648c54dbfbSXin LI shutdown(pfd[POLL_NETIN].fd, SHUT_RD); 9658c54dbfbSXin LI pfd[POLL_NETIN].fd = -1; 9668c54dbfbSXin LI } 9678c54dbfbSXin LI 9688c54dbfbSXin LI /* try to read from stdin */ 9698c54dbfbSXin LI if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { 9708c54dbfbSXin LI ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, 9718c54dbfbSXin LI &stdinbufpos); 9728c54dbfbSXin LI /* error or eof on stdin - remove from pfd */ 9738c54dbfbSXin LI if (ret == 0 || ret == -1) 9748c54dbfbSXin LI pfd[POLL_STDIN].fd = -1; 9758c54dbfbSXin LI /* read something - poll net out */ 9768c54dbfbSXin LI if (stdinbufpos > 0) 9778c54dbfbSXin LI pfd[POLL_NETOUT].events = POLLOUT; 9788c54dbfbSXin LI /* filled buffer - remove self from polling */ 9798c54dbfbSXin LI if (stdinbufpos == BUFSIZE) 9808c54dbfbSXin LI pfd[POLL_STDIN].events = 0; 9818c54dbfbSXin LI } 9828c54dbfbSXin LI /* try to write to network */ 9838c54dbfbSXin LI if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { 9848c54dbfbSXin LI ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, 985d4b3aefdSPietro Cerutti &stdinbufpos, FreeBSD_crlf); 9868c54dbfbSXin LI if (ret == -1) 9878c54dbfbSXin LI pfd[POLL_NETOUT].fd = -1; 9888c54dbfbSXin LI /* buffer empty - remove self from polling */ 9898c54dbfbSXin LI if (stdinbufpos == 0) 9908c54dbfbSXin LI pfd[POLL_NETOUT].events = 0; 9918c54dbfbSXin LI /* buffer no longer full - poll stdin again */ 9928c54dbfbSXin LI if (stdinbufpos < BUFSIZE) 9938c54dbfbSXin LI pfd[POLL_STDIN].events = POLLIN; 9948c54dbfbSXin LI } 9958c54dbfbSXin LI /* try to read from network */ 9968c54dbfbSXin LI if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { 9978c54dbfbSXin LI ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, 9988c54dbfbSXin LI &netinbufpos); 9998c54dbfbSXin LI if (ret == -1) 10008c54dbfbSXin LI pfd[POLL_NETIN].fd = -1; 10018c54dbfbSXin LI /* eof on net in - remove from pfd */ 10028c54dbfbSXin LI if (ret == 0) { 10038c54dbfbSXin LI shutdown(pfd[POLL_NETIN].fd, SHUT_RD); 10048c54dbfbSXin LI pfd[POLL_NETIN].fd = -1; 10058c54dbfbSXin LI } 10068c54dbfbSXin LI /* read something - poll stdout */ 10078c54dbfbSXin LI if (netinbufpos > 0) 10088c54dbfbSXin LI pfd[POLL_STDOUT].events = POLLOUT; 10098c54dbfbSXin LI /* filled buffer - remove self from polling */ 10108c54dbfbSXin LI if (netinbufpos == BUFSIZE) 10118c54dbfbSXin LI pfd[POLL_NETIN].events = 0; 10128c54dbfbSXin LI /* handle telnet */ 10138c54dbfbSXin LI if (tflag) 10148c54dbfbSXin LI atelnet(pfd[POLL_NETIN].fd, netinbuf, 10158c54dbfbSXin LI netinbufpos); 10168c54dbfbSXin LI } 10178c54dbfbSXin LI /* try to write to stdout */ 10188c54dbfbSXin LI if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { 10198c54dbfbSXin LI ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, 1020d4b3aefdSPietro Cerutti &netinbufpos, 0); 10218c54dbfbSXin LI if (ret == -1) 10228c54dbfbSXin LI pfd[POLL_STDOUT].fd = -1; 10238c54dbfbSXin LI /* buffer empty - remove self from polling */ 10248c54dbfbSXin LI if (netinbufpos == 0) 10258c54dbfbSXin LI pfd[POLL_STDOUT].events = 0; 10268c54dbfbSXin LI /* buffer no longer full - poll net in again */ 10278c54dbfbSXin LI if (netinbufpos < BUFSIZE) 10288c54dbfbSXin LI pfd[POLL_NETIN].events = POLLIN; 10298c54dbfbSXin LI } 10308c54dbfbSXin LI 10318c54dbfbSXin LI /* stdin gone and queue empty? */ 10328c54dbfbSXin LI if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { 10331e62ecedSEdward Tomasz Napierala if (pfd[POLL_NETOUT].fd != -1 && Nflag) { 10341e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag) { 10351e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(net_fd); 10361e62ecedSEdward Tomasz Napierala stats_printed = 1; 10371e62ecedSEdward Tomasz Napierala } 10388c54dbfbSXin LI shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); 10391e62ecedSEdward Tomasz Napierala } 10408c54dbfbSXin LI pfd[POLL_NETOUT].fd = -1; 10418c54dbfbSXin LI } 10428c54dbfbSXin LI /* net in gone and queue empty? */ 10438c54dbfbSXin LI if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { 10448c54dbfbSXin LI pfd[POLL_STDOUT].fd = -1; 10458c384020SXin LI } 10468c384020SXin LI } 10478c384020SXin LI } 10488c54dbfbSXin LI 10498c54dbfbSXin LI ssize_t 1050d4b3aefdSPietro Cerutti write_wrapper(int fd, const void *buf, size_t buflen) 10518c54dbfbSXin LI { 1052d4b3aefdSPietro Cerutti ssize_t n = write(fd, buf, buflen); 10538c54dbfbSXin LI /* don't treat EAGAIN, EINTR as error */ 1054d4b3aefdSPietro Cerutti return (n == -1 && (errno == EAGAIN || errno == EINTR)) ? -2 : n; 1055d4b3aefdSPietro Cerutti } 1056d4b3aefdSPietro Cerutti 1057d4b3aefdSPietro Cerutti ssize_t 1058d4b3aefdSPietro Cerutti drainbuf(int fd, unsigned char *buf, size_t *bufpos, int crlf) 1059d4b3aefdSPietro Cerutti { 1060d4b3aefdSPietro Cerutti ssize_t n = *bufpos, n2 = 0; 1061d4b3aefdSPietro Cerutti ssize_t adjust; 1062d4b3aefdSPietro Cerutti unsigned char *lf = NULL; 1063d4b3aefdSPietro Cerutti 1064d4b3aefdSPietro Cerutti if (crlf) { 1065d4b3aefdSPietro Cerutti lf = memchr(buf, '\n', *bufpos); 1066d4b3aefdSPietro Cerutti if (lf && (lf == buf || *(lf - 1) != '\r')) 1067d4b3aefdSPietro Cerutti n = lf - buf; 1068d4b3aefdSPietro Cerutti else 1069d4b3aefdSPietro Cerutti lf = NULL; 1070d4b3aefdSPietro Cerutti } 1071d4b3aefdSPietro Cerutti 1072d4b3aefdSPietro Cerutti if (n != 0) { 1073d4b3aefdSPietro Cerutti n = write_wrapper(fd, buf, n); 10748c54dbfbSXin LI if (n <= 0) 10758c54dbfbSXin LI return n; 1076d4b3aefdSPietro Cerutti } 1077d4b3aefdSPietro Cerutti 1078d4b3aefdSPietro Cerutti if (lf) { 1079d4b3aefdSPietro Cerutti n2 = write_wrapper(fd, "\r\n", 2); 1080d4b3aefdSPietro Cerutti if (n2 <= 0) 1081d4b3aefdSPietro Cerutti return n2; 1082d4b3aefdSPietro Cerutti n += 1; 1083d4b3aefdSPietro Cerutti } 1084d4b3aefdSPietro Cerutti 10858c54dbfbSXin LI /* adjust buffer */ 10868c54dbfbSXin LI adjust = *bufpos - n; 10878c54dbfbSXin LI if (adjust > 0) 10888c54dbfbSXin LI memmove(buf, buf + n, adjust); 10898c54dbfbSXin LI *bufpos -= n; 10908c54dbfbSXin LI return n; 10918c54dbfbSXin LI } 10928c54dbfbSXin LI 10938c54dbfbSXin LI 10948c54dbfbSXin LI ssize_t 10958c54dbfbSXin LI fillbuf(int fd, unsigned char *buf, size_t *bufpos) 10968c54dbfbSXin LI { 10978c54dbfbSXin LI size_t num = BUFSIZE - *bufpos; 10988c54dbfbSXin LI ssize_t n; 10998c54dbfbSXin LI 11008c54dbfbSXin LI n = read(fd, buf + *bufpos, num); 11018c54dbfbSXin LI /* don't treat EAGAIN, EINTR as error */ 11028c54dbfbSXin LI if (n == -1 && (errno == EAGAIN || errno == EINTR)) 11038c54dbfbSXin LI n = -2; 11048c54dbfbSXin LI if (n <= 0) 11058c54dbfbSXin LI return n; 11068c54dbfbSXin LI *bufpos += n; 11078c54dbfbSXin LI return n; 11088c384020SXin LI } 11098c384020SXin LI 11103ae0125aSXin LI /* 11113ae0125aSXin LI * fdpass() 11123ae0125aSXin LI * Pass the connected file descriptor to stdout and exit. 11133ae0125aSXin LI */ 11143ae0125aSXin LI void 11153ae0125aSXin LI fdpass(int nfd) 11163ae0125aSXin LI { 11173ae0125aSXin LI struct msghdr mh; 11183ae0125aSXin LI union { 11193ae0125aSXin LI struct cmsghdr hdr; 11203ae0125aSXin LI char buf[CMSG_SPACE(sizeof(int))]; 11213ae0125aSXin LI } cmsgbuf; 11223ae0125aSXin LI struct cmsghdr *cmsg; 11233ae0125aSXin LI struct iovec iov; 11243ae0125aSXin LI char c = '\0'; 11253ae0125aSXin LI ssize_t r; 11263ae0125aSXin LI struct pollfd pfd; 11273ae0125aSXin LI 11283ae0125aSXin LI /* Avoid obvious stupidity */ 11293ae0125aSXin LI if (isatty(STDOUT_FILENO)) 11303ae0125aSXin LI errx(1, "Cannot pass file descriptor to tty"); 11313ae0125aSXin LI 11323ae0125aSXin LI bzero(&mh, sizeof(mh)); 11333ae0125aSXin LI bzero(&cmsgbuf, sizeof(cmsgbuf)); 11343ae0125aSXin LI bzero(&iov, sizeof(iov)); 11353ae0125aSXin LI 11363ae0125aSXin LI mh.msg_control = (caddr_t)&cmsgbuf.buf; 11373ae0125aSXin LI mh.msg_controllen = sizeof(cmsgbuf.buf); 11383ae0125aSXin LI cmsg = CMSG_FIRSTHDR(&mh); 11393ae0125aSXin LI cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 11403ae0125aSXin LI cmsg->cmsg_level = SOL_SOCKET; 11413ae0125aSXin LI cmsg->cmsg_type = SCM_RIGHTS; 11423ae0125aSXin LI *(int *)CMSG_DATA(cmsg) = nfd; 11433ae0125aSXin LI 11443ae0125aSXin LI iov.iov_base = &c; 11453ae0125aSXin LI iov.iov_len = 1; 11463ae0125aSXin LI mh.msg_iov = &iov; 11473ae0125aSXin LI mh.msg_iovlen = 1; 11483ae0125aSXin LI 11493ae0125aSXin LI bzero(&pfd, sizeof(pfd)); 11503ae0125aSXin LI pfd.fd = STDOUT_FILENO; 1151100e2a06SXin LI pfd.events = POLLOUT; 11523ae0125aSXin LI for (;;) { 11533ae0125aSXin LI r = sendmsg(STDOUT_FILENO, &mh, 0); 11543ae0125aSXin LI if (r == -1) { 11553ae0125aSXin LI if (errno == EAGAIN || errno == EINTR) { 11563ae0125aSXin LI if (poll(&pfd, 1, -1) == -1) 11573ae0125aSXin LI err(1, "poll"); 11583ae0125aSXin LI continue; 11593ae0125aSXin LI } 11603ae0125aSXin LI err(1, "sendmsg"); 1161100e2a06SXin LI } else if (r != 1) 11623ae0125aSXin LI errx(1, "sendmsg: unexpected return value %zd", r); 11633ae0125aSXin LI else 11643ae0125aSXin LI break; 11653ae0125aSXin LI } 11663ae0125aSXin LI exit(0); 11673ae0125aSXin LI } 11683ae0125aSXin LI 11698c384020SXin LI /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ 11708c384020SXin LI void 11718c384020SXin LI atelnet(int nfd, unsigned char *buf, unsigned int size) 11728c384020SXin LI { 11738c384020SXin LI unsigned char *p, *end; 11748c384020SXin LI unsigned char obuf[4]; 11758c384020SXin LI 117626bf9c3bSXin LI if (size < 3) 117726bf9c3bSXin LI return; 117826bf9c3bSXin LI end = buf + size - 2; 11798c384020SXin LI 11808c384020SXin LI for (p = buf; p < end; p++) { 11818c384020SXin LI if (*p != IAC) 118226bf9c3bSXin LI continue; 11838c384020SXin LI 11848c384020SXin LI obuf[0] = IAC; 11858c384020SXin LI p++; 11868c384020SXin LI if ((*p == WILL) || (*p == WONT)) 11878c384020SXin LI obuf[1] = DONT; 118826bf9c3bSXin LI else if ((*p == DO) || (*p == DONT)) 11898c384020SXin LI obuf[1] = WONT; 119026bf9c3bSXin LI else 119126bf9c3bSXin LI continue; 119226bf9c3bSXin LI 11938c384020SXin LI p++; 11948c384020SXin LI obuf[2] = *p; 11952440a458SXin LI if (atomicio(vwrite, nfd, obuf, 3) != 3) 11962440a458SXin LI warn("Write Error!"); 11978c384020SXin LI } 11988c384020SXin LI } 11998c384020SXin LI 12008c384020SXin LI /* 12018c384020SXin LI * build_ports() 1202ac3ea910SXin LI * Build an array of ports in portlist[], listing each port 12038c384020SXin LI * that we should try to connect to. 12048c384020SXin LI */ 12058c384020SXin LI void 12068c384020SXin LI build_ports(char *p) 12078c384020SXin LI { 1208bdb0aaa1SXin LI const char *errstr; 1209bdb0aaa1SXin LI char *n; 12108c384020SXin LI int hi, lo, cp; 12118c384020SXin LI int x = 0; 12128c384020SXin LI 12138c384020SXin LI if ((n = strchr(p, '-')) != NULL) { 12148c384020SXin LI *n = '\0'; 12158c384020SXin LI n++; 12168c384020SXin LI 12178c384020SXin LI /* Make sure the ports are in order: lowest->highest. */ 1218bdb0aaa1SXin LI hi = strtonum(n, 1, PORT_MAX, &errstr); 1219bdb0aaa1SXin LI if (errstr) 1220bdb0aaa1SXin LI errx(1, "port number %s: %s", errstr, n); 1221bdb0aaa1SXin LI lo = strtonum(p, 1, PORT_MAX, &errstr); 1222bdb0aaa1SXin LI if (errstr) 1223bdb0aaa1SXin LI errx(1, "port number %s: %s", errstr, p); 12248c384020SXin LI 12258c384020SXin LI if (lo > hi) { 12268c384020SXin LI cp = hi; 12278c384020SXin LI hi = lo; 12288c384020SXin LI lo = cp; 12298c384020SXin LI } 12308c384020SXin LI 12318c384020SXin LI /* Load ports sequentially. */ 12328c384020SXin LI for (cp = lo; cp <= hi; cp++) { 12338c384020SXin LI portlist[x] = calloc(1, PORT_MAX_LEN); 12348c384020SXin LI if (portlist[x] == NULL) 12358c384020SXin LI err(1, NULL); 12368c384020SXin LI snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); 12378c384020SXin LI x++; 12388c384020SXin LI } 12398c384020SXin LI 12408c384020SXin LI /* Randomly swap ports. */ 12418c384020SXin LI if (rflag) { 12428c384020SXin LI int y; 12438c384020SXin LI char *c; 12448c384020SXin LI 12458c384020SXin LI for (x = 0; x <= (hi - lo); x++) { 12468c384020SXin LI y = (arc4random() & 0xFFFF) % (hi - lo); 12478c384020SXin LI c = portlist[x]; 12488c384020SXin LI portlist[x] = portlist[y]; 12498c384020SXin LI portlist[y] = c; 12508c384020SXin LI } 12518c384020SXin LI } 12528c384020SXin LI } else { 1253bdb0aaa1SXin LI hi = strtonum(p, 1, PORT_MAX, &errstr); 1254bdb0aaa1SXin LI if (errstr) 1255bdb0aaa1SXin LI errx(1, "port number %s: %s", errstr, p); 12564f2bbc00SXin LI portlist[0] = strdup(p); 12578c384020SXin LI if (portlist[0] == NULL) 12588c384020SXin LI err(1, NULL); 12598c384020SXin LI } 12608c384020SXin LI } 12618c384020SXin LI 12628c384020SXin LI /* 12638c384020SXin LI * udptest() 12648c384020SXin LI * Do a few writes to see if the UDP port is there. 1265ac3ea910SXin LI * Fails once PF state table is full. 12668c384020SXin LI */ 12678c384020SXin LI int 12688c384020SXin LI udptest(int s) 12698c384020SXin LI { 12708c384020SXin LI int i, ret; 12718c384020SXin LI 12728c384020SXin LI for (i = 0; i <= 3; i++) { 12738c384020SXin LI if (write(s, "X", 1) == 1) 12748c384020SXin LI ret = 1; 12758c384020SXin LI else 12768c384020SXin LI ret = -1; 12778c384020SXin LI } 12788c384020SXin LI return (ret); 12798c384020SXin LI } 12808c384020SXin LI 12818c384020SXin LI void 12821e62ecedSEdward Tomasz Napierala FreeBSD_stats_setup(int s) 12831e62ecedSEdward Tomasz Napierala { 12841e62ecedSEdward Tomasz Napierala 12851e62ecedSEdward Tomasz Napierala if (setsockopt(s, IPPROTO_TCP, TCP_STATS, 12861e62ecedSEdward Tomasz Napierala &FreeBSD_Mflag, sizeof(FreeBSD_Mflag)) == -1) { 12871e62ecedSEdward Tomasz Napierala if (errno == EOPNOTSUPP) { 12881e62ecedSEdward Tomasz Napierala warnx("getsockopt(TCP_STATS) failed; " 12891e62ecedSEdward Tomasz Napierala "kernel built without \"options STATS\"?"); 12901e62ecedSEdward Tomasz Napierala } 12911e62ecedSEdward Tomasz Napierala err(1, "enable TCP_STATS gathering"); 12921e62ecedSEdward Tomasz Napierala } 12931e62ecedSEdward Tomasz Napierala } 12941e62ecedSEdward Tomasz Napierala 12951e62ecedSEdward Tomasz Napierala void 12961e62ecedSEdward Tomasz Napierala FreeBSD_stats_print(int s) 12971e62ecedSEdward Tomasz Napierala { 12981e62ecedSEdward Tomasz Napierala #ifdef WITH_STATS 12991e62ecedSEdward Tomasz Napierala struct statsblob *statsb; 13001e62ecedSEdward Tomasz Napierala struct sbuf *sb; 13011e62ecedSEdward Tomasz Napierala socklen_t sockoptlen; 13021e62ecedSEdward Tomasz Napierala int error; 13031e62ecedSEdward Tomasz Napierala 13041e62ecedSEdward Tomasz Napierala /* 13051e62ecedSEdward Tomasz Napierala * This usleep is a workaround for TCP_STATS reporting 13061e62ecedSEdward Tomasz Napierala * incorrect values for TXPB. 13071e62ecedSEdward Tomasz Napierala */ 13081e62ecedSEdward Tomasz Napierala usleep(100000); 13091e62ecedSEdward Tomasz Napierala 13101e62ecedSEdward Tomasz Napierala sockoptlen = 2048; 13111e62ecedSEdward Tomasz Napierala statsb = malloc(sockoptlen); 13121e62ecedSEdward Tomasz Napierala if (statsb == NULL) 13131e62ecedSEdward Tomasz Napierala err(1, "malloc"); 13141e62ecedSEdward Tomasz Napierala error = getsockopt(s, IPPROTO_TCP, TCP_STATS, statsb, &sockoptlen); 13151e62ecedSEdward Tomasz Napierala if (error != 0) { 13161e62ecedSEdward Tomasz Napierala if (errno == EOVERFLOW && statsb->cursz > sockoptlen) { 13171e62ecedSEdward Tomasz Napierala /* Retry with a larger size. */ 13181e62ecedSEdward Tomasz Napierala sockoptlen = statsb->cursz; 13191e62ecedSEdward Tomasz Napierala statsb = realloc(statsb, sockoptlen); 13201e62ecedSEdward Tomasz Napierala if (statsb == NULL) 13211e62ecedSEdward Tomasz Napierala err(1, "realloc"); 13221e62ecedSEdward Tomasz Napierala error = getsockopt(s, IPPROTO_TCP, TCP_STATS, 13231e62ecedSEdward Tomasz Napierala statsb, &sockoptlen); 13241e62ecedSEdward Tomasz Napierala } 13251e62ecedSEdward Tomasz Napierala if (error != 0) 13261e62ecedSEdward Tomasz Napierala err(1, "getsockopt"); 13271e62ecedSEdward Tomasz Napierala } 13281e62ecedSEdward Tomasz Napierala 13291e62ecedSEdward Tomasz Napierala sb = sbuf_new_auto(); 13301e62ecedSEdward Tomasz Napierala error = stats_blob_tostr(statsb, sb, SB_STRFMT_JSON, SB_TOSTR_META); 13311e62ecedSEdward Tomasz Napierala if (error != 0) 13321e62ecedSEdward Tomasz Napierala errc(1, error, "stats_blob_tostr"); 13331e62ecedSEdward Tomasz Napierala 13341e62ecedSEdward Tomasz Napierala error = sbuf_finish(sb); 13351e62ecedSEdward Tomasz Napierala if (error != 0) 13361e62ecedSEdward Tomasz Napierala err(1, "sbuf_finish"); 13371e62ecedSEdward Tomasz Napierala 13381e62ecedSEdward Tomasz Napierala fprintf(stderr, "%s\n", sbuf_data(sb)); 13391e62ecedSEdward Tomasz Napierala #endif 13401e62ecedSEdward Tomasz Napierala } 13411e62ecedSEdward Tomasz Napierala 13421e62ecedSEdward Tomasz Napierala void 13438c54dbfbSXin LI set_common_sockopts(int s, int af) 13442440a458SXin LI { 13452440a458SXin LI int x = 1; 13462440a458SXin LI 13472440a458SXin LI if (Sflag) { 13482440a458SXin LI if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, 13492440a458SXin LI &x, sizeof(x)) == -1) 13502440a458SXin LI err(1, NULL); 13512440a458SXin LI } 13522440a458SXin LI if (Dflag) { 13532440a458SXin LI if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 13542440a458SXin LI &x, sizeof(x)) == -1) 13552440a458SXin LI err(1, NULL); 13562440a458SXin LI } 13572440a458SXin LI if (Tflag != -1) { 13588c54dbfbSXin LI int proto, option; 13598c54dbfbSXin LI 13608c54dbfbSXin LI if (af == AF_INET6) { 13618c54dbfbSXin LI proto = IPPROTO_IPV6; 13628c54dbfbSXin LI option = IPV6_TCLASS; 13638c54dbfbSXin LI } else { 13648c54dbfbSXin LI proto = IPPROTO_IP; 13658c54dbfbSXin LI option = IP_TOS; 13668c54dbfbSXin LI } 13678c54dbfbSXin LI 13688c54dbfbSXin LI if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1) 13692440a458SXin LI err(1, "set IP ToS"); 13702440a458SXin LI } 13717dcaa833SXin LI if (Iflag) { 13727dcaa833SXin LI if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 13737dcaa833SXin LI &Iflag, sizeof(Iflag)) == -1) 13747dcaa833SXin LI err(1, "set TCP receive buffer size"); 13757dcaa833SXin LI } 1376bc38f653SBruce M Simpson if (Oflag) { 13777dcaa833SXin LI if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 1378bc38f653SBruce M Simpson &Oflag, sizeof(Oflag)) == -1) 13797dcaa833SXin LI err(1, "set TCP send buffer size"); 13807dcaa833SXin LI } 13817dcaa833SXin LI if (FreeBSD_Oflag) { 13827dcaa833SXin LI if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, 13837dcaa833SXin LI &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1) 1384bc38f653SBruce M Simpson err(1, "disable TCP options"); 1385bc38f653SBruce M Simpson } 13861e62ecedSEdward Tomasz Napierala if (FreeBSD_Mflag) 13871e62ecedSEdward Tomasz Napierala FreeBSD_stats_setup(s); 1388fcf59617SAndrey V. Elsukov #ifdef IPSEC 1389fcf59617SAndrey V. Elsukov if (ipsec_policy[0] != NULL) 1390fcf59617SAndrey V. Elsukov add_ipsec_policy(s, af, ipsec_policy[0]); 1391fcf59617SAndrey V. Elsukov if (ipsec_policy[1] != NULL) 1392fcf59617SAndrey V. Elsukov add_ipsec_policy(s, af, ipsec_policy[1]); 1393fcf59617SAndrey V. Elsukov #endif 13942440a458SXin LI } 13952440a458SXin LI 13962440a458SXin LI int 1397ac3ea910SXin LI map_tos(char *s, int *val) 13982440a458SXin LI { 1399ac3ea910SXin LI /* DiffServ Codepoints and other TOS mappings */ 1400ac3ea910SXin LI const struct toskeywords { 1401ac3ea910SXin LI const char *keyword; 1402ac3ea910SXin LI int val; 1403ac3ea910SXin LI } *t, toskeywords[] = { 1404ac3ea910SXin LI { "af11", IPTOS_DSCP_AF11 }, 1405ac3ea910SXin LI { "af12", IPTOS_DSCP_AF12 }, 1406ac3ea910SXin LI { "af13", IPTOS_DSCP_AF13 }, 1407ac3ea910SXin LI { "af21", IPTOS_DSCP_AF21 }, 1408ac3ea910SXin LI { "af22", IPTOS_DSCP_AF22 }, 1409ac3ea910SXin LI { "af23", IPTOS_DSCP_AF23 }, 1410ac3ea910SXin LI { "af31", IPTOS_DSCP_AF31 }, 1411ac3ea910SXin LI { "af32", IPTOS_DSCP_AF32 }, 1412ac3ea910SXin LI { "af33", IPTOS_DSCP_AF33 }, 1413ac3ea910SXin LI { "af41", IPTOS_DSCP_AF41 }, 1414ac3ea910SXin LI { "af42", IPTOS_DSCP_AF42 }, 1415ac3ea910SXin LI { "af43", IPTOS_DSCP_AF43 }, 1416ac3ea910SXin LI { "critical", IPTOS_PREC_CRITIC_ECP }, 1417ac3ea910SXin LI { "cs0", IPTOS_DSCP_CS0 }, 1418ac3ea910SXin LI { "cs1", IPTOS_DSCP_CS1 }, 1419ac3ea910SXin LI { "cs2", IPTOS_DSCP_CS2 }, 1420ac3ea910SXin LI { "cs3", IPTOS_DSCP_CS3 }, 1421ac3ea910SXin LI { "cs4", IPTOS_DSCP_CS4 }, 1422ac3ea910SXin LI { "cs5", IPTOS_DSCP_CS5 }, 1423ac3ea910SXin LI { "cs6", IPTOS_DSCP_CS6 }, 1424ac3ea910SXin LI { "cs7", IPTOS_DSCP_CS7 }, 1425ac3ea910SXin LI { "ef", IPTOS_DSCP_EF }, 1426ac3ea910SXin LI { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 1427ac3ea910SXin LI { "lowdelay", IPTOS_LOWDELAY }, 1428ac3ea910SXin LI { "netcontrol", IPTOS_PREC_NETCONTROL }, 1429ac3ea910SXin LI { "reliability", IPTOS_RELIABILITY }, 1430ac3ea910SXin LI { "throughput", IPTOS_THROUGHPUT }, 1431ac3ea910SXin LI { NULL, -1 }, 1432ac3ea910SXin LI }; 14332440a458SXin LI 1434ac3ea910SXin LI for (t = toskeywords; t->keyword != NULL; t++) { 1435ac3ea910SXin LI if (strcmp(s, t->keyword) == 0) { 1436ac3ea910SXin LI *val = t->val; 1437ac3ea910SXin LI return (1); 1438ac3ea910SXin LI } 1439ac3ea910SXin LI } 14402440a458SXin LI 1441ac3ea910SXin LI return (0); 14422440a458SXin LI } 14432440a458SXin LI 14442440a458SXin LI void 144552dba105SXin LI report_connect(const struct sockaddr *sa, socklen_t salen) 144652dba105SXin LI { 144752dba105SXin LI char remote_host[NI_MAXHOST]; 144852dba105SXin LI char remote_port[NI_MAXSERV]; 144952dba105SXin LI int herr; 145052dba105SXin LI int flags = NI_NUMERICSERV; 145152dba105SXin LI 145252dba105SXin LI if (nflag) 145352dba105SXin LI flags |= NI_NUMERICHOST; 145452dba105SXin LI 145552dba105SXin LI if ((herr = getnameinfo(sa, salen, 145652dba105SXin LI remote_host, sizeof(remote_host), 145752dba105SXin LI remote_port, sizeof(remote_port), 145852dba105SXin LI flags)) != 0) { 145952dba105SXin LI if (herr == EAI_SYSTEM) 146052dba105SXin LI err(1, "getnameinfo"); 146152dba105SXin LI else 146252dba105SXin LI errx(1, "getnameinfo: %s", gai_strerror(herr)); 146352dba105SXin LI } 146452dba105SXin LI 146552dba105SXin LI fprintf(stderr, 146652dba105SXin LI "Connection from %s %s " 146752dba105SXin LI "received!\n", remote_host, remote_port); 146852dba105SXin LI } 146952dba105SXin LI 147052dba105SXin LI void 14718c384020SXin LI help(void) 14728c384020SXin LI { 14738c384020SXin LI usage(0); 14748c384020SXin LI fprintf(stderr, "\tCommand Summary:\n\ 14758c384020SXin LI \t-4 Use IPv4\n\ 1476b6642dadSAntoine Brodin \t-6 Use IPv6\n\ 1477d4b3aefdSPietro Cerutti \t--crlf Convert LF into CRLF when sending data over the network\n\ 1478b6642dadSAntoine Brodin \t-D Enable the debug socket option\n\ 1479b6642dadSAntoine Brodin \t-d Detach from stdin\n"); 148004def624SXin LI #ifdef IPSEC 148104def624SXin LI fprintf(stderr, "\ 1482b6642dadSAntoine Brodin \t-E Use IPsec ESP\n\ 1483b6642dadSAntoine Brodin \t-e policy Use specified IPsec policy\n"); 148404def624SXin LI #endif 148504def624SXin LI fprintf(stderr, "\ 14863ae0125aSXin LI \t-F Pass socket fd\n\ 14878c384020SXin LI \t-h This help text\n\ 14887dcaa833SXin LI \t-I length TCP receive buffer length\n\ 14898c384020SXin LI \t-i secs\t Delay interval for lines sent, ports scanned\n\ 14908c384020SXin LI \t-k Keep inbound sockets open for multiple connects\n\ 14918c384020SXin LI \t-l Listen mode, for inbound connects\n\ 14920772266eSXin LI \t-N Shutdown the network socket after EOF on stdin\n\ 14938c384020SXin LI \t-n Suppress name/port resolutions\n\ 14947dcaa833SXin LI \t--no-tcpopt Disable TCP options\n\ 1495d0415892SMark Johnston \t--sctp\t SCTP mode\n\ 1496cef7ab70STom Jones \t--tun tundev Use tun device rather than stdio\n\ 14977dcaa833SXin LI \t-O length TCP send buffer length\n\ 14982440a458SXin LI \t-P proxyuser\tUsername for proxy authentication\n\ 14998c384020SXin LI \t-p port\t Specify local port for remote connects\n\ 15008c384020SXin LI \t-r Randomize remote ports\n\ 15018c384020SXin LI \t-S Enable the TCP MD5 signature option\n\ 15028c384020SXin LI \t-s addr\t Local source address\n\ 1503ac3ea910SXin LI \t-T toskeyword\tSet IP Type of Service\n\ 15048c384020SXin LI \t-t Answer TELNET negotiation\n\ 15058c384020SXin LI \t-U Use UNIX domain socket\n\ 15068c384020SXin LI \t-u UDP mode\n\ 15074f2bbc00SXin LI \t-V rtable Specify alternate routing table\n\ 15088c384020SXin LI \t-v Verbose\n\ 15098c384020SXin LI \t-w secs\t Timeout for connects and final net reads\n\ 15108c384020SXin LI \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ 15118c384020SXin LI \t-x addr[:port]\tSpecify proxy address and port\n\ 15128c384020SXin LI \t-z Zero-I/O mode [used for scanning]\n\ 15138c384020SXin LI Port numbers can be individual or ranges: lo-hi [inclusive]\n"); 151404def624SXin LI #ifdef IPSEC 1515d0415892SMark Johnston fprintf(stderr, "\tSee ipsec_set_policy(3) for -e argument format\n"); 151604def624SXin LI #endif 15178c384020SXin LI exit(1); 15188c384020SXin LI } 15198c384020SXin LI 152004def624SXin LI #ifdef IPSEC 152104def624SXin LI void 1522fcf59617SAndrey V. Elsukov add_ipsec_policy(int s, int af, char *policy) 152304def624SXin LI { 152404def624SXin LI char *raw; 152504def624SXin LI int e; 152604def624SXin LI 152704def624SXin LI raw = ipsec_set_policy(policy, strlen(policy)); 152804def624SXin LI if (raw == NULL) 152904def624SXin LI errx(1, "ipsec_set_policy `%s': %s", policy, 153004def624SXin LI ipsec_strerror()); 1531fcf59617SAndrey V. Elsukov if (af == AF_INET) 153204def624SXin LI e = setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, raw, 153304def624SXin LI ipsec_get_policylen(raw)); 1534fcf59617SAndrey V. Elsukov if (af == AF_INET6) 1535fcf59617SAndrey V. Elsukov e = setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, raw, 1536fcf59617SAndrey V. Elsukov ipsec_get_policylen(raw)); 153704def624SXin LI if (e < 0) 153804def624SXin LI err(1, "ipsec policy cannot be configured"); 153904def624SXin LI free(raw); 154004def624SXin LI if (vflag) 154104def624SXin LI fprintf(stderr, "ipsec policy configured: `%s'\n", policy); 154204def624SXin LI return; 154304def624SXin LI } 154404def624SXin LI #endif /* IPSEC */ 154504def624SXin LI 15468c384020SXin LI void 15478c384020SXin LI usage(int ret) 15488c384020SXin LI { 15491a9dc239SXin LI fprintf(stderr, 155004def624SXin LI #ifdef IPSEC 15513ae0125aSXin LI "usage: nc [-46DdEFhklNnrStUuvz] [-e policy] [-I length] [-i interval] [-O length]\n" 155204def624SXin LI #else 15533ae0125aSXin LI "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" 155404def624SXin LI #endif 1555d0415892SMark Johnston "\t [--no-tcpopt] [--sctp]\n" 155659c7ad52SXin LI "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" 1557cef7ab70STom Jones "\t [--tun tundev] [-V rtable] [-w timeout] [-X proxy_protocol]\n" 155859c7ad52SXin LI "\t [-x proxy_address[:port]] [destination] [port]\n"); 15598c384020SXin LI if (ret) 15608c384020SXin LI exit(1); 15618c384020SXin LI } 1562