103100a63Svk199839 /* $OpenBSD: netcat.c,v 1.89 2007/02/20 14:11:17 jmc Exp $ */ 203100a63Svk199839 /* 303100a63Svk199839 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 403100a63Svk199839 * 503100a63Svk199839 * Redistribution and use in source and binary forms, with or without 603100a63Svk199839 * modification, are permitted provided that the following conditions 703100a63Svk199839 * are met: 803100a63Svk199839 * 903100a63Svk199839 * 1. Redistributions of source code must retain the above copyright 1003100a63Svk199839 * notice, this list of conditions and the following disclaimer. 1103100a63Svk199839 * 2. Redistributions in binary form must reproduce the above copyright 1203100a63Svk199839 * notice, this list of conditions and the following disclaimer in the 1303100a63Svk199839 * documentation and/or other materials provided with the distribution. 1403100a63Svk199839 * 3. The name of the author may not be used to endorse or promote products 1503100a63Svk199839 * derived from this software without specific prior written permission. 1603100a63Svk199839 * 1703100a63Svk199839 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1803100a63Svk199839 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1903100a63Svk199839 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2003100a63Svk199839 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2103100a63Svk199839 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2203100a63Svk199839 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2303100a63Svk199839 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2403100a63Svk199839 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2503100a63Svk199839 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2603100a63Svk199839 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2703100a63Svk199839 */ 2803100a63Svk199839 2903100a63Svk199839 /* 3003100a63Svk199839 * Re-written nc(1) for OpenBSD. Original implementation by 3103100a63Svk199839 * *Hobbit* <hobbit@avian.org>. 3203100a63Svk199839 */ 3303100a63Svk199839 34f8c3982aSvk199839 /* 35f8c3982aSvk199839 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 36f8c3982aSvk199839 * Use is subject to license terms. 37f8c3982aSvk199839 */ 38f8c3982aSvk199839 392eef1f2bSErik Trauschke /* 402eef1f2bSErik Trauschke * Portions Copyright 2008 Erik Trauschke 41*1edba515SAndy Fiddaman * Copyright 2024 Oxide Computer Company 422eef1f2bSErik Trauschke */ 4303100a63Svk199839 4403100a63Svk199839 #include <sys/types.h> 4503100a63Svk199839 #include <sys/socket.h> 4603100a63Svk199839 #include <sys/time.h> 4703100a63Svk199839 #include <sys/un.h> 4803100a63Svk199839 4903100a63Svk199839 #include <netinet/in.h> 5003100a63Svk199839 #include <netinet/in_systm.h> 5103100a63Svk199839 #include <netinet/tcp.h> 5203100a63Svk199839 #include <netinet/ip.h> 5303100a63Svk199839 #include <arpa/telnet.h> 5403100a63Svk199839 5503100a63Svk199839 #include <err.h> 5603100a63Svk199839 #include <errno.h> 5703100a63Svk199839 #include <netdb.h> 5803100a63Svk199839 #include <poll.h> 5903100a63Svk199839 #include <stdarg.h> 6003100a63Svk199839 #include <stdio.h> 6103100a63Svk199839 #include <stdlib.h> 6203100a63Svk199839 #include <string.h> 6303100a63Svk199839 #include <unistd.h> 6403100a63Svk199839 #include <fcntl.h> 6503100a63Svk199839 #include <limits.h> 6603100a63Svk199839 #include <signal.h> 6703100a63Svk199839 6803100a63Svk199839 #include "atomicio.h" 6903100a63Svk199839 7003100a63Svk199839 #ifndef SUN_LEN 7103100a63Svk199839 #define SUN_LEN(su) \ 7203100a63Svk199839 (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path)) 7303100a63Svk199839 #endif 7403100a63Svk199839 7503100a63Svk199839 #define PORT_MIN 1 7603100a63Svk199839 #define PORT_MAX 65535 7703100a63Svk199839 #define PORT_MAX_LEN 6 782eef1f2bSErik Trauschke #define PLIST_SZ 32 /* initial capacity of the portlist */ 7903100a63Svk199839 8003100a63Svk199839 /* Command Line Options */ 8103100a63Svk199839 int dflag; /* detached, no stdin */ 8203100a63Svk199839 unsigned int iflag; /* Interval Flag */ 8303100a63Svk199839 int kflag; /* More than one connect */ 8403100a63Svk199839 int lflag; /* Bind to local port */ 8503100a63Svk199839 int nflag; /* Don't do name lookup */ 8603100a63Svk199839 char *Pflag; /* Proxy username */ 8703100a63Svk199839 char *pflag; /* Localport flag */ 8803100a63Svk199839 int rflag; /* Random ports flag */ 8903100a63Svk199839 char *sflag; /* Source Address */ 9003100a63Svk199839 int tflag; /* Telnet Emulation */ 9103100a63Svk199839 int uflag; /* UDP - Default to TCP */ 9203100a63Svk199839 int vflag; /* Verbosity */ 9303100a63Svk199839 int xflag; /* Socks proxy */ 9403100a63Svk199839 int Xflag; /* indicator of Socks version set */ 9503100a63Svk199839 int zflag; /* Port Scan Flag */ 9603100a63Svk199839 int Dflag; /* sodebug */ 97*1edba515SAndy Fiddaman int Sflag; /* TCP MD5 signature option */ 9803100a63Svk199839 int Tflag = -1; /* IP Type of Service */ 9903100a63Svk199839 10003100a63Svk199839 int timeout = -1; 10103100a63Svk199839 int family = AF_UNSPEC; 1022eef1f2bSErik Trauschke 1032eef1f2bSErik Trauschke /* 1042eef1f2bSErik Trauschke * portlist structure 1052eef1f2bSErik Trauschke * Used to store a list of ports given by the user and maintaining 1062eef1f2bSErik Trauschke * information about the number of ports stored. 1072eef1f2bSErik Trauschke */ 1082eef1f2bSErik Trauschke struct { 1092eef1f2bSErik Trauschke uint16_t *list; /* list containing the ports */ 1102eef1f2bSErik Trauschke uint_t listsize; /* capacity of the list (number of entries) */ 1112eef1f2bSErik Trauschke uint_t numports; /* number of ports in the list */ 1122eef1f2bSErik Trauschke } ports; 11303100a63Svk199839 11403100a63Svk199839 void atelnet(int, unsigned char *, unsigned int); 11503100a63Svk199839 void build_ports(char *); 11603100a63Svk199839 void help(void); 11703100a63Svk199839 int local_listen(char *, char *, struct addrinfo); 11803100a63Svk199839 void readwrite(int); 11903100a63Svk199839 int remote_connect(const char *, const char *, struct addrinfo); 12003100a63Svk199839 int socks_connect(const char *, const char *, 12103100a63Svk199839 const char *, const char *, struct addrinfo, int, const char *); 12203100a63Svk199839 int udptest(int); 12303100a63Svk199839 int unix_connect(char *); 12403100a63Svk199839 int unix_listen(char *); 12503100a63Svk199839 void set_common_sockopts(int); 12603100a63Svk199839 int parse_iptos(char *); 12703100a63Svk199839 void usage(int); 128f8c3982aSvk199839 char *print_addr(char *, size_t, struct sockaddr *, int, int); 12903100a63Svk199839 13003100a63Svk199839 int 13103100a63Svk199839 main(int argc, char *argv[]) 13203100a63Svk199839 { 13303100a63Svk199839 int ch, s, ret, socksv; 13403100a63Svk199839 char *host, *uport, *proxy; 13503100a63Svk199839 struct addrinfo hints; 13603100a63Svk199839 struct servent *sv; 13703100a63Svk199839 socklen_t len; 13803100a63Svk199839 struct sockaddr_storage cliaddr; 13903100a63Svk199839 const char *errstr, *proxyhost = "", *proxyport = NULL; 14003100a63Svk199839 struct addrinfo proxyhints; 1412eef1f2bSErik Trauschke char port[PORT_MAX_LEN]; 14203100a63Svk199839 14303100a63Svk199839 ret = 1; 1442eef1f2bSErik Trauschke s = -1; 14503100a63Svk199839 socksv = 5; 14603100a63Svk199839 host = NULL; 14703100a63Svk199839 uport = NULL; 14803100a63Svk199839 sv = NULL; 14903100a63Svk199839 15003100a63Svk199839 while ((ch = getopt(argc, argv, 151*1edba515SAndy Fiddaman "46Ddhi:klnP:p:rs:ST:tUuvw:X:x:z")) != -1) { 15203100a63Svk199839 switch (ch) { 15303100a63Svk199839 case '4': 15403100a63Svk199839 family = AF_INET; 15503100a63Svk199839 break; 15603100a63Svk199839 case '6': 15703100a63Svk199839 family = AF_INET6; 15803100a63Svk199839 break; 15903100a63Svk199839 case 'U': 16003100a63Svk199839 family = AF_UNIX; 16103100a63Svk199839 break; 16203100a63Svk199839 case 'X': 16303100a63Svk199839 Xflag = 1; 16403100a63Svk199839 if (strcasecmp(optarg, "connect") == 0) 16503100a63Svk199839 socksv = -1; /* HTTP proxy CONNECT */ 16603100a63Svk199839 else if (strcmp(optarg, "4") == 0) 16703100a63Svk199839 socksv = 4; /* SOCKS v.4 */ 16803100a63Svk199839 else if (strcmp(optarg, "5") == 0) 16903100a63Svk199839 socksv = 5; /* SOCKS v.5 */ 17003100a63Svk199839 else 17103100a63Svk199839 errx(1, "unsupported proxy protocol"); 17203100a63Svk199839 break; 17303100a63Svk199839 case 'd': 17403100a63Svk199839 dflag = 1; 17503100a63Svk199839 break; 17603100a63Svk199839 case 'h': 17703100a63Svk199839 help(); 17803100a63Svk199839 break; 17903100a63Svk199839 case 'i': 18003100a63Svk199839 iflag = strtonum(optarg, 0, UINT_MAX, &errstr); 18103100a63Svk199839 if (errstr) 18203100a63Svk199839 errx(1, "interval %s: %s", errstr, optarg); 18303100a63Svk199839 break; 18403100a63Svk199839 case 'k': 18503100a63Svk199839 kflag = 1; 18603100a63Svk199839 break; 18703100a63Svk199839 case 'l': 18803100a63Svk199839 lflag = 1; 18903100a63Svk199839 break; 19003100a63Svk199839 case 'n': 19103100a63Svk199839 nflag = 1; 19203100a63Svk199839 break; 19303100a63Svk199839 case 'P': 19403100a63Svk199839 Pflag = optarg; 19503100a63Svk199839 break; 19603100a63Svk199839 case 'p': 19703100a63Svk199839 pflag = optarg; 19803100a63Svk199839 break; 19903100a63Svk199839 case 'r': 20003100a63Svk199839 rflag = 1; 20103100a63Svk199839 break; 20203100a63Svk199839 case 's': 20303100a63Svk199839 sflag = optarg; 20403100a63Svk199839 break; 20503100a63Svk199839 case 't': 20603100a63Svk199839 tflag = 1; 20703100a63Svk199839 break; 20803100a63Svk199839 case 'u': 20903100a63Svk199839 uflag = 1; 21003100a63Svk199839 break; 21103100a63Svk199839 case 'v': 21203100a63Svk199839 vflag = 1; 21303100a63Svk199839 break; 21403100a63Svk199839 case 'w': 21503100a63Svk199839 timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); 21603100a63Svk199839 if (errstr) 21703100a63Svk199839 errx(1, "timeout %s: %s", errstr, optarg); 21803100a63Svk199839 timeout *= 1000; 21903100a63Svk199839 break; 22003100a63Svk199839 case 'x': 22103100a63Svk199839 xflag = 1; 22203100a63Svk199839 if ((proxy = strdup(optarg)) == NULL) 22303100a63Svk199839 err(1, NULL); 22403100a63Svk199839 break; 22503100a63Svk199839 case 'z': 22603100a63Svk199839 zflag = 1; 22703100a63Svk199839 break; 22803100a63Svk199839 case 'D': 22903100a63Svk199839 Dflag = 1; 23003100a63Svk199839 break; 231*1edba515SAndy Fiddaman case 'S': 232*1edba515SAndy Fiddaman Sflag = 1; 233*1edba515SAndy Fiddaman break; 23403100a63Svk199839 case 'T': 23503100a63Svk199839 Tflag = parse_iptos(optarg); 23603100a63Svk199839 break; 23703100a63Svk199839 default: 23803100a63Svk199839 usage(1); 23903100a63Svk199839 } 24003100a63Svk199839 } 24103100a63Svk199839 argc -= optind; 24203100a63Svk199839 argv += optind; 24303100a63Svk199839 24403100a63Svk199839 /* Cruft to make sure options are clean, and used properly. */ 24503100a63Svk199839 if (argv[0] && !argv[1] && family == AF_UNIX) { 24603100a63Svk199839 if (uflag) 24703100a63Svk199839 errx(1, "cannot use -u and -U"); 24803100a63Svk199839 host = argv[0]; 24903100a63Svk199839 uport = NULL; 25003100a63Svk199839 } else if (argv[0] && !argv[1]) { 25103100a63Svk199839 if (!lflag) 25203100a63Svk199839 usage(1); 25303100a63Svk199839 uport = argv[0]; 25403100a63Svk199839 host = NULL; 25503100a63Svk199839 } else if (argv[0] && argv[1]) { 25603100a63Svk199839 if (family == AF_UNIX) 25703100a63Svk199839 usage(1); 25803100a63Svk199839 host = argv[0]; 25903100a63Svk199839 uport = argv[1]; 26003100a63Svk199839 } else { 26103100a63Svk199839 if (!(lflag && pflag)) 26203100a63Svk199839 usage(1); 26303100a63Svk199839 } 26403100a63Svk199839 26563c99f93Svk199839 if (argc > 2) 26663c99f93Svk199839 usage(1); 26763c99f93Svk199839 26803100a63Svk199839 if (lflag && sflag) 26903100a63Svk199839 errx(1, "cannot use -s and -l"); 27003100a63Svk199839 if (lflag && rflag) 27103100a63Svk199839 errx(1, "cannot use -r and -l"); 27263c99f93Svk199839 if (lflag && (timeout >= 0)) 27363c99f93Svk199839 warnx("-w has no effect with -l"); 27403100a63Svk199839 if (lflag && pflag) { 27503100a63Svk199839 if (uport) 27603100a63Svk199839 usage(1); 27703100a63Svk199839 uport = pflag; 27803100a63Svk199839 } 27903100a63Svk199839 if (lflag && zflag) 28003100a63Svk199839 errx(1, "cannot use -z and -l"); 28103100a63Svk199839 if (!lflag && kflag) 28203100a63Svk199839 errx(1, "must use -l with -k"); 28303100a63Svk199839 if (lflag && (Pflag || xflag || Xflag)) 28403100a63Svk199839 errx(1, "cannot use -l with -P, -X or -x"); 28503100a63Svk199839 28603100a63Svk199839 /* Initialize addrinfo structure. */ 28703100a63Svk199839 if (family != AF_UNIX) { 28803100a63Svk199839 (void) memset(&hints, 0, sizeof (struct addrinfo)); 28903100a63Svk199839 hints.ai_family = family; 29003100a63Svk199839 hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 29103100a63Svk199839 hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 29203100a63Svk199839 if (nflag) 29303100a63Svk199839 hints.ai_flags |= AI_NUMERICHOST; 29403100a63Svk199839 } 29503100a63Svk199839 29603100a63Svk199839 if (xflag) { 29703100a63Svk199839 if (uflag) 29803100a63Svk199839 errx(1, "no proxy support for UDP mode"); 29903100a63Svk199839 30003100a63Svk199839 if (lflag) 30103100a63Svk199839 errx(1, "no proxy support for listen"); 30203100a63Svk199839 30303100a63Svk199839 if (family == AF_UNIX) 30403100a63Svk199839 errx(1, "no proxy support for unix sockets"); 30503100a63Svk199839 30603100a63Svk199839 if (family == AF_INET6) 30703100a63Svk199839 errx(1, "no proxy support for IPv6"); 30803100a63Svk199839 30903100a63Svk199839 if (sflag) 31003100a63Svk199839 errx(1, "no proxy support for local source address"); 31103100a63Svk199839 31203100a63Svk199839 if ((proxyhost = strtok(proxy, ":")) == NULL) 31303100a63Svk199839 errx(1, "missing port specification"); 31403100a63Svk199839 proxyport = strtok(NULL, ":"); 31503100a63Svk199839 31603100a63Svk199839 (void) memset(&proxyhints, 0, sizeof (struct addrinfo)); 31703100a63Svk199839 proxyhints.ai_family = family; 31803100a63Svk199839 proxyhints.ai_socktype = SOCK_STREAM; 31903100a63Svk199839 proxyhints.ai_protocol = IPPROTO_TCP; 32003100a63Svk199839 if (nflag) 32103100a63Svk199839 proxyhints.ai_flags |= AI_NUMERICHOST; 32203100a63Svk199839 } 32303100a63Svk199839 32403100a63Svk199839 if (lflag) { 32503100a63Svk199839 int connfd; 32603100a63Svk199839 ret = 0; 32703100a63Svk199839 3282eef1f2bSErik Trauschke if (family == AF_UNIX) { 3292eef1f2bSErik Trauschke if (host == NULL) 3302eef1f2bSErik Trauschke usage(1); 33103100a63Svk199839 s = unix_listen(host); 3322eef1f2bSErik Trauschke } 33303100a63Svk199839 33403100a63Svk199839 /* Allow only one connection at a time, but stay alive. */ 33503100a63Svk199839 for (;;) { 3362eef1f2bSErik Trauschke if (family != AF_UNIX) { 3372eef1f2bSErik Trauschke /* check if uport is valid */ 3382eef1f2bSErik Trauschke if (strtonum(uport, PORT_MIN, PORT_MAX, 3392eef1f2bSErik Trauschke &errstr) == 0) 3402eef1f2bSErik Trauschke errx(1, "port number %s: %s", 3412eef1f2bSErik Trauschke uport, errstr); 34203100a63Svk199839 s = local_listen(host, uport, hints); 3432eef1f2bSErik Trauschke } 34403100a63Svk199839 if (s < 0) 34503100a63Svk199839 err(1, NULL); 34603100a63Svk199839 /* 34703100a63Svk199839 * For UDP, we will use recvfrom() initially 34803100a63Svk199839 * to wait for a caller, then use the regular 34903100a63Svk199839 * functions to talk to the caller. 35003100a63Svk199839 */ 35103100a63Svk199839 if (uflag) { 35203100a63Svk199839 int rv, plen; 35303100a63Svk199839 char buf[8192]; 35403100a63Svk199839 struct sockaddr_storage z; 35503100a63Svk199839 35603100a63Svk199839 len = sizeof (z); 35703100a63Svk199839 plen = 1024; 35803100a63Svk199839 rv = recvfrom(s, buf, plen, MSG_PEEK, 35903100a63Svk199839 (struct sockaddr *)&z, &len); 36003100a63Svk199839 if (rv < 0) 36103100a63Svk199839 err(1, "recvfrom"); 36203100a63Svk199839 36303100a63Svk199839 rv = connect(s, (struct sockaddr *)&z, len); 36403100a63Svk199839 if (rv < 0) 36503100a63Svk199839 err(1, "connect"); 36603100a63Svk199839 36703100a63Svk199839 connfd = s; 36803100a63Svk199839 } else { 36903100a63Svk199839 len = sizeof (cliaddr); 37003100a63Svk199839 connfd = accept(s, (struct sockaddr *)&cliaddr, 37103100a63Svk199839 &len); 372f8c3982aSvk199839 if ((connfd != -1) && vflag) { 373f8c3982aSvk199839 char ntop[NI_MAXHOST + NI_MAXSERV]; 374f8c3982aSvk199839 (void) fprintf(stderr, 375f8c3982aSvk199839 "Received connection from %s\n", 376f8c3982aSvk199839 print_addr(ntop, sizeof (ntop), 377f8c3982aSvk199839 (struct sockaddr *)&cliaddr, len, 378f8c3982aSvk199839 nflag ? NI_NUMERICHOST : 0)); 379f8c3982aSvk199839 } 38003100a63Svk199839 } 38103100a63Svk199839 38203100a63Svk199839 readwrite(connfd); 38303100a63Svk199839 (void) close(connfd); 38403100a63Svk199839 if (family != AF_UNIX) 38503100a63Svk199839 (void) close(s); 38603100a63Svk199839 38703100a63Svk199839 if (!kflag) 38803100a63Svk199839 break; 38903100a63Svk199839 } 39003100a63Svk199839 } else if (family == AF_UNIX) { 39103100a63Svk199839 ret = 0; 39203100a63Svk199839 39303100a63Svk199839 if ((s = unix_connect(host)) > 0 && !zflag) { 39403100a63Svk199839 readwrite(s); 39503100a63Svk199839 (void) close(s); 39603100a63Svk199839 } else 39703100a63Svk199839 ret = 1; 39803100a63Svk199839 39903100a63Svk199839 exit(ret); 40003100a63Svk199839 40103100a63Svk199839 } else { /* AF_INET or AF_INET6 */ 4022eef1f2bSErik Trauschke int i; 40303100a63Svk199839 4042eef1f2bSErik Trauschke /* Construct the portlist. */ 40503100a63Svk199839 build_ports(uport); 40603100a63Svk199839 40703100a63Svk199839 /* Cycle through portlist, connecting to each port. */ 4082eef1f2bSErik Trauschke for (i = 0; i < ports.numports; i++) { 4092eef1f2bSErik Trauschke (void) snprintf(port, sizeof (port), "%u", 4102eef1f2bSErik Trauschke ports.list[i]); 4112eef1f2bSErik Trauschke 4122eef1f2bSErik Trauschke if (s != -1) 41303100a63Svk199839 (void) close(s); 41403100a63Svk199839 41503100a63Svk199839 if (xflag) 4162eef1f2bSErik Trauschke s = socks_connect(host, port, 41703100a63Svk199839 proxyhost, proxyport, proxyhints, socksv, 41803100a63Svk199839 Pflag); 41903100a63Svk199839 else 4202eef1f2bSErik Trauschke s = remote_connect(host, port, hints); 42103100a63Svk199839 42203100a63Svk199839 if (s < 0) 42303100a63Svk199839 continue; 42403100a63Svk199839 42503100a63Svk199839 ret = 0; 42603100a63Svk199839 if (vflag || zflag) { 42703100a63Svk199839 /* For UDP, make sure we are connected. */ 42803100a63Svk199839 if (uflag) { 42903100a63Svk199839 if (udptest(s) == -1) { 43003100a63Svk199839 ret = 1; 43103100a63Svk199839 continue; 43203100a63Svk199839 } 43303100a63Svk199839 } 43403100a63Svk199839 43503100a63Svk199839 /* Don't look up port if -n. */ 43603100a63Svk199839 if (nflag) 43703100a63Svk199839 sv = NULL; 43803100a63Svk199839 else { 43903100a63Svk199839 sv = getservbyport( 4402eef1f2bSErik Trauschke ntohs(ports.list[i]), 44103100a63Svk199839 uflag ? "udp" : "tcp"); 44203100a63Svk199839 } 44303100a63Svk199839 444f8c3982aSvk199839 (void) fprintf(stderr, "Connection to %s %s " 44503100a63Svk199839 "port [%s/%s] succeeded!\n", 4462eef1f2bSErik Trauschke host, port, uflag ? "udp" : "tcp", 44703100a63Svk199839 sv ? sv->s_name : "*"); 44803100a63Svk199839 } 44903100a63Svk199839 if (!zflag) 45003100a63Svk199839 readwrite(s); 45103100a63Svk199839 } 4522eef1f2bSErik Trauschke free(ports.list); 45303100a63Svk199839 } 45403100a63Svk199839 4552eef1f2bSErik Trauschke if (s != -1) 45603100a63Svk199839 (void) close(s); 45703100a63Svk199839 45803100a63Svk199839 return (ret); 45903100a63Svk199839 } 46003100a63Svk199839 46103100a63Svk199839 /* 462f8c3982aSvk199839 * print IP address and (optionally) a port 463f8c3982aSvk199839 */ 464f8c3982aSvk199839 char * 465f8c3982aSvk199839 print_addr(char *ntop, size_t ntlen, struct sockaddr *addr, int len, int flags) 466f8c3982aSvk199839 { 467f8c3982aSvk199839 char port[NI_MAXSERV]; 468f8c3982aSvk199839 int e; 469f8c3982aSvk199839 470f8c3982aSvk199839 /* print port always as number */ 471f8c3982aSvk199839 if ((e = getnameinfo(addr, len, ntop, ntlen, 472f8c3982aSvk199839 port, sizeof (port), flags|NI_NUMERICSERV)) != 0) { 473f8c3982aSvk199839 return ((char *)gai_strerror(e)); 474f8c3982aSvk199839 } 475f8c3982aSvk199839 476afa82053SToomas Soome (void) strlcat(ntop, " port ", ntlen); 477afa82053SToomas Soome (void) strlcat(ntop, port, ntlen); 478f8c3982aSvk199839 479f8c3982aSvk199839 return (ntop); 480f8c3982aSvk199839 } 481f8c3982aSvk199839 482f8c3982aSvk199839 /* 48303100a63Svk199839 * unix_connect() 48403100a63Svk199839 * Returns a socket connected to a local unix socket. Returns -1 on failure. 48503100a63Svk199839 */ 48603100a63Svk199839 int 48703100a63Svk199839 unix_connect(char *path) 48803100a63Svk199839 { 48903100a63Svk199839 struct sockaddr_un sunaddr; 49003100a63Svk199839 int s; 49103100a63Svk199839 49203100a63Svk199839 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 49303100a63Svk199839 return (-1); 49403100a63Svk199839 49503100a63Svk199839 (void) memset(&sunaddr, 0, sizeof (struct sockaddr_un)); 49603100a63Svk199839 sunaddr.sun_family = AF_UNIX; 49703100a63Svk199839 49803100a63Svk199839 if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >= 49903100a63Svk199839 sizeof (sunaddr.sun_path)) { 50003100a63Svk199839 (void) close(s); 50103100a63Svk199839 errno = ENAMETOOLONG; 50203100a63Svk199839 return (-1); 50303100a63Svk199839 } 50403100a63Svk199839 if (connect(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) { 50503100a63Svk199839 (void) close(s); 50603100a63Svk199839 return (-1); 50703100a63Svk199839 } 50803100a63Svk199839 return (s); 50903100a63Svk199839 } 51003100a63Svk199839 51103100a63Svk199839 /* 51203100a63Svk199839 * unix_listen() 51303100a63Svk199839 * Create a unix domain socket, and listen on it. 51403100a63Svk199839 */ 51503100a63Svk199839 int 51603100a63Svk199839 unix_listen(char *path) 51703100a63Svk199839 { 51803100a63Svk199839 struct sockaddr_un sunaddr; 51903100a63Svk199839 int s; 52003100a63Svk199839 52103100a63Svk199839 /* Create unix domain socket. */ 52203100a63Svk199839 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 52303100a63Svk199839 return (-1); 52403100a63Svk199839 52503100a63Svk199839 (void) memset(&sunaddr, 0, sizeof (struct sockaddr_un)); 52603100a63Svk199839 sunaddr.sun_family = AF_UNIX; 52703100a63Svk199839 52803100a63Svk199839 if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >= 52903100a63Svk199839 sizeof (sunaddr.sun_path)) { 53003100a63Svk199839 (void) close(s); 53103100a63Svk199839 errno = ENAMETOOLONG; 53203100a63Svk199839 return (-1); 53303100a63Svk199839 } 53403100a63Svk199839 53503100a63Svk199839 if (bind(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) { 53603100a63Svk199839 (void) close(s); 53703100a63Svk199839 return (-1); 53803100a63Svk199839 } 53903100a63Svk199839 54003100a63Svk199839 if (listen(s, 5) < 0) { 54103100a63Svk199839 (void) close(s); 54203100a63Svk199839 return (-1); 54303100a63Svk199839 } 54403100a63Svk199839 return (s); 54503100a63Svk199839 } 54603100a63Svk199839 54703100a63Svk199839 /* 54803100a63Svk199839 * remote_connect() 54903100a63Svk199839 * Returns a socket connected to a remote host. Properly binds to a local 55003100a63Svk199839 * port or source address if needed. Returns -1 on failure. 55103100a63Svk199839 */ 55203100a63Svk199839 int 55303100a63Svk199839 remote_connect(const char *host, const char *port, struct addrinfo hints) 55403100a63Svk199839 { 55503100a63Svk199839 struct addrinfo *res, *res0; 55603100a63Svk199839 int s, error; 55703100a63Svk199839 55803100a63Svk199839 if ((error = getaddrinfo(host, port, &hints, &res))) 55903100a63Svk199839 errx(1, "getaddrinfo: %s", gai_strerror(error)); 56003100a63Svk199839 56103100a63Svk199839 res0 = res; 56203100a63Svk199839 do { 56303100a63Svk199839 if ((s = socket(res0->ai_family, res0->ai_socktype, 56403100a63Svk199839 res0->ai_protocol)) < 0) { 56503100a63Svk199839 warn("failed to create socket"); 56603100a63Svk199839 continue; 56703100a63Svk199839 } 56803100a63Svk199839 56903100a63Svk199839 /* Bind to a local port or source address if specified. */ 57003100a63Svk199839 if (sflag || pflag) { 57103100a63Svk199839 struct addrinfo ahints, *ares; 57203100a63Svk199839 57303100a63Svk199839 (void) memset(&ahints, 0, sizeof (struct addrinfo)); 57403100a63Svk199839 ahints.ai_family = res0->ai_family; 57503100a63Svk199839 ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 57603100a63Svk199839 ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 57703100a63Svk199839 ahints.ai_flags = AI_PASSIVE; 57803100a63Svk199839 if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) 57903100a63Svk199839 errx(1, "getaddrinfo: %s", gai_strerror(error)); 58003100a63Svk199839 58103100a63Svk199839 if (bind(s, (struct sockaddr *)ares->ai_addr, 58203100a63Svk199839 ares->ai_addrlen) < 0) 58303100a63Svk199839 errx(1, "bind failed: %s", strerror(errno)); 58403100a63Svk199839 freeaddrinfo(ares); 585f8c3982aSvk199839 586f8c3982aSvk199839 if (vflag && !lflag) { 587f8c3982aSvk199839 if (sflag != NULL) 588f8c3982aSvk199839 (void) fprintf(stderr, 589f8c3982aSvk199839 "Using source address: %s\n", 590f8c3982aSvk199839 sflag); 591f8c3982aSvk199839 if (pflag != NULL) 592f8c3982aSvk199839 (void) fprintf(stderr, 593f8c3982aSvk199839 "Using source port: %s\n", pflag); 594f8c3982aSvk199839 } 59503100a63Svk199839 } 59603100a63Svk199839 59703100a63Svk199839 set_common_sockopts(s); 59803100a63Svk199839 59903100a63Svk199839 if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 60003100a63Svk199839 break; 601f8c3982aSvk199839 else if (vflag) { 602f8c3982aSvk199839 char ntop[NI_MAXHOST + NI_MAXSERV]; 603f8c3982aSvk199839 warn("connect to %s [host %s] (%s) failed", 604f8c3982aSvk199839 print_addr(ntop, sizeof (ntop), 605f8c3982aSvk199839 res0->ai_addr, res0->ai_addrlen, NI_NUMERICHOST), 606f8c3982aSvk199839 host, uflag ? "udp" : "tcp"); 607f8c3982aSvk199839 } 60803100a63Svk199839 60903100a63Svk199839 (void) close(s); 61003100a63Svk199839 s = -1; 61103100a63Svk199839 } while ((res0 = res0->ai_next) != NULL); 61203100a63Svk199839 61303100a63Svk199839 freeaddrinfo(res); 61403100a63Svk199839 61503100a63Svk199839 return (s); 61603100a63Svk199839 } 61703100a63Svk199839 61803100a63Svk199839 /* 61903100a63Svk199839 * local_listen() 62003100a63Svk199839 * Returns a socket listening on a local port, binds to specified source 62103100a63Svk199839 * address. Returns -1 on failure. 62203100a63Svk199839 */ 62303100a63Svk199839 int 62403100a63Svk199839 local_listen(char *host, char *port, struct addrinfo hints) 62503100a63Svk199839 { 62603100a63Svk199839 struct addrinfo *res, *res0; 62703100a63Svk199839 int s, ret, x = 1; 62803100a63Svk199839 int error; 62903100a63Svk199839 63003100a63Svk199839 /* Allow nodename to be null. */ 63103100a63Svk199839 hints.ai_flags |= AI_PASSIVE; 63203100a63Svk199839 63303100a63Svk199839 if ((error = getaddrinfo(host, port, &hints, &res))) 63403100a63Svk199839 errx(1, "getaddrinfo: %s", gai_strerror(error)); 63503100a63Svk199839 63603100a63Svk199839 res0 = res; 63703100a63Svk199839 do { 63803100a63Svk199839 if ((s = socket(res0->ai_family, res0->ai_socktype, 63903100a63Svk199839 res0->ai_protocol)) < 0) { 64003100a63Svk199839 warn("failed to create socket"); 64103100a63Svk199839 continue; 64203100a63Svk199839 } 64303100a63Svk199839 64403100a63Svk199839 ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)); 64503100a63Svk199839 if (ret == -1) 64603100a63Svk199839 err(1, NULL); 64703100a63Svk199839 64803100a63Svk199839 set_common_sockopts(s); 64903100a63Svk199839 65003100a63Svk199839 if (bind(s, (struct sockaddr *)res0->ai_addr, 65103100a63Svk199839 res0->ai_addrlen) == 0) 65203100a63Svk199839 break; 65303100a63Svk199839 65403100a63Svk199839 (void) close(s); 65503100a63Svk199839 s = -1; 65603100a63Svk199839 } while ((res0 = res0->ai_next) != NULL); 65703100a63Svk199839 65803100a63Svk199839 if (!uflag && s != -1) { 65903100a63Svk199839 if (listen(s, 1) < 0) 66003100a63Svk199839 err(1, "listen"); 66103100a63Svk199839 } 66203100a63Svk199839 66303100a63Svk199839 freeaddrinfo(res); 66403100a63Svk199839 66503100a63Svk199839 return (s); 66603100a63Svk199839 } 66703100a63Svk199839 66803100a63Svk199839 /* 66903100a63Svk199839 * readwrite() 67003100a63Svk199839 * Loop that polls on the network file descriptor and stdin. 67103100a63Svk199839 */ 67203100a63Svk199839 void 67303100a63Svk199839 readwrite(int nfd) 67403100a63Svk199839 { 67503100a63Svk199839 struct pollfd pfd[2]; 67603100a63Svk199839 unsigned char buf[8192]; 67703100a63Svk199839 int n, wfd = fileno(stdin); 67803100a63Svk199839 int lfd = fileno(stdout); 67903100a63Svk199839 int plen; 68003100a63Svk199839 68103100a63Svk199839 plen = 1024; 68203100a63Svk199839 68303100a63Svk199839 /* Setup Network FD */ 68403100a63Svk199839 pfd[0].fd = nfd; 68503100a63Svk199839 pfd[0].events = POLLIN; 68603100a63Svk199839 68703100a63Svk199839 /* Set up STDIN FD. */ 68803100a63Svk199839 pfd[1].fd = wfd; 68903100a63Svk199839 pfd[1].events = POLLIN; 69003100a63Svk199839 69103100a63Svk199839 while (pfd[0].fd != -1) { 69203100a63Svk199839 if (iflag) 69303100a63Svk199839 (void) sleep(iflag); 69403100a63Svk199839 69503100a63Svk199839 if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { 69603100a63Svk199839 (void) close(nfd); 69703100a63Svk199839 err(1, "Polling Error"); 69803100a63Svk199839 } 69903100a63Svk199839 70003100a63Svk199839 if (n == 0) 70103100a63Svk199839 return; 70203100a63Svk199839 70303100a63Svk199839 if (pfd[0].revents & (POLLIN|POLLHUP)) { 70403100a63Svk199839 if ((n = read(nfd, buf, plen)) < 0) 70503100a63Svk199839 return; 70603100a63Svk199839 else if (n == 0) { 70703100a63Svk199839 (void) shutdown(nfd, SHUT_RD); 70803100a63Svk199839 pfd[0].fd = -1; 70903100a63Svk199839 pfd[0].events = 0; 71003100a63Svk199839 } else { 71103100a63Svk199839 if (tflag) 71203100a63Svk199839 atelnet(nfd, buf, n); 71303100a63Svk199839 if (atomicio(vwrite, lfd, buf, n) != n) 71403100a63Svk199839 return; 71503100a63Svk199839 } 71603100a63Svk199839 } 71703100a63Svk199839 71803100a63Svk199839 /* 71903100a63Svk199839 * handle the case of disconnected pipe: after pipe 72003100a63Svk199839 * is closed (indicated by POLLHUP) there may still 72103100a63Svk199839 * be some data lingering (POLLIN). After we read 72203100a63Svk199839 * the data, only POLLHUP remains, read() returns 0 72303100a63Svk199839 * and we are finished. 72403100a63Svk199839 */ 72503100a63Svk199839 if (!dflag && (pfd[1].revents & (POLLIN|POLLHUP))) { 72603100a63Svk199839 if ((n = read(wfd, buf, plen)) < 0) 72703100a63Svk199839 return; 72803100a63Svk199839 else if (n == 0) { 72903100a63Svk199839 (void) shutdown(nfd, SHUT_WR); 73003100a63Svk199839 pfd[1].fd = -1; 73103100a63Svk199839 pfd[1].events = 0; 73203100a63Svk199839 } else { 73303100a63Svk199839 if (atomicio(vwrite, nfd, buf, n) != n) 73403100a63Svk199839 return; 73503100a63Svk199839 } 73603100a63Svk199839 } 73703100a63Svk199839 } 73803100a63Svk199839 } 73903100a63Svk199839 74003100a63Svk199839 /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ 74103100a63Svk199839 void 74203100a63Svk199839 atelnet(int nfd, unsigned char *buf, unsigned int size) 74303100a63Svk199839 { 74403100a63Svk199839 unsigned char *p, *end; 74503100a63Svk199839 unsigned char obuf[4]; 74603100a63Svk199839 74703100a63Svk199839 end = buf + size; 74803100a63Svk199839 obuf[0] = '\0'; 74903100a63Svk199839 75003100a63Svk199839 for (p = buf; p < end; p++) { 75103100a63Svk199839 if (*p != IAC) 75203100a63Svk199839 break; 75303100a63Svk199839 75403100a63Svk199839 obuf[0] = IAC; 75503100a63Svk199839 obuf[1] = 0; 75603100a63Svk199839 p++; 75703100a63Svk199839 /* refuse all options */ 75803100a63Svk199839 if ((*p == WILL) || (*p == WONT)) 75903100a63Svk199839 obuf[1] = DONT; 76003100a63Svk199839 if ((*p == DO) || (*p == DONT)) 76103100a63Svk199839 obuf[1] = WONT; 76203100a63Svk199839 if (obuf[1]) { 76303100a63Svk199839 p++; 76403100a63Svk199839 obuf[2] = *p; 76503100a63Svk199839 obuf[3] = '\0'; 76603100a63Svk199839 if (atomicio(vwrite, nfd, obuf, 3) != 3) 76703100a63Svk199839 warn("Write Error!"); 76803100a63Svk199839 obuf[0] = '\0'; 76903100a63Svk199839 } 77003100a63Svk199839 } 77103100a63Svk199839 } 77203100a63Svk199839 77303100a63Svk199839 /* 77403100a63Svk199839 * build_ports() 7752eef1f2bSErik Trauschke * Build an array of ports in ports.list[], listing each port 77603100a63Svk199839 * that we should try to connect to. 77703100a63Svk199839 */ 77803100a63Svk199839 void 77903100a63Svk199839 build_ports(char *p) 78003100a63Svk199839 { 78103100a63Svk199839 const char *errstr; 7822eef1f2bSErik Trauschke const char *token; 78303100a63Svk199839 char *n; 7842eef1f2bSErik Trauschke int lo, hi, cp; 7852eef1f2bSErik Trauschke int i; 78603100a63Svk199839 7872eef1f2bSErik Trauschke /* Set up initial portlist. */ 7882eef1f2bSErik Trauschke ports.list = malloc(PLIST_SZ * sizeof (uint16_t)); 7892eef1f2bSErik Trauschke if (ports.list == NULL) 7902eef1f2bSErik Trauschke err(1, NULL); 7912eef1f2bSErik Trauschke ports.listsize = PLIST_SZ; 7922eef1f2bSErik Trauschke ports.numports = 0; 79303100a63Svk199839 7942eef1f2bSErik Trauschke /* Cycle through list of given ports sep. by "," */ 7952eef1f2bSErik Trauschke while ((token = strsep(&p, ",")) != NULL) { 7962eef1f2bSErik Trauschke if (*token == '\0') 7972eef1f2bSErik Trauschke errx(1, "Invalid port/portlist format: " 7982eef1f2bSErik Trauschke "zero length port"); 79903100a63Svk199839 8002eef1f2bSErik Trauschke /* check if it is a range */ 8012eef1f2bSErik Trauschke if ((n = strchr(token, '-')) != NULL) 8022eef1f2bSErik Trauschke *n++ = '\0'; 8032eef1f2bSErik Trauschke 8042eef1f2bSErik Trauschke lo = strtonum(token, PORT_MIN, PORT_MAX, &errstr); 8052eef1f2bSErik Trauschke if (errstr) 8062eef1f2bSErik Trauschke errx(1, "port number %s: %s", errstr, token); 8072eef1f2bSErik Trauschke 8082eef1f2bSErik Trauschke if (n == NULL) { 8092eef1f2bSErik Trauschke hi = lo; 8102eef1f2bSErik Trauschke } else { 81103100a63Svk199839 hi = strtonum(n, PORT_MIN, PORT_MAX, &errstr); 81203100a63Svk199839 if (errstr) 81303100a63Svk199839 errx(1, "port number %s: %s", errstr, n); 81403100a63Svk199839 if (lo > hi) { 81503100a63Svk199839 cp = hi; 81603100a63Svk199839 hi = lo; 81703100a63Svk199839 lo = cp; 81803100a63Svk199839 } 8192eef1f2bSErik Trauschke } 8202eef1f2bSErik Trauschke 8212eef1f2bSErik Trauschke /* 8222eef1f2bSErik Trauschke * Grow the portlist if needed. 8232eef1f2bSErik Trauschke * We double the size and add size of current range 8242eef1f2bSErik Trauschke * to make sure we don't have to resize that often. 8252eef1f2bSErik Trauschke */ 8262eef1f2bSErik Trauschke if (hi - lo + ports.numports + 1 >= ports.listsize) { 8272eef1f2bSErik Trauschke ports.listsize = ports.listsize * 2 + hi - lo; 8282eef1f2bSErik Trauschke ports.list = realloc(ports.list, 8292eef1f2bSErik Trauschke ports.listsize * sizeof (uint16_t)); 8302eef1f2bSErik Trauschke if (ports.list == NULL) 8312eef1f2bSErik Trauschke err(1, NULL); 8322eef1f2bSErik Trauschke } 83303100a63Svk199839 83403100a63Svk199839 /* Load ports sequentially. */ 8352eef1f2bSErik Trauschke for (i = lo; i <= hi; i++) 8362eef1f2bSErik Trauschke ports.list[ports.numports++] = i; 83703100a63Svk199839 } 83803100a63Svk199839 83903100a63Svk199839 /* Randomly swap ports. */ 84003100a63Svk199839 if (rflag) { 84103100a63Svk199839 int y; 8422eef1f2bSErik Trauschke uint16_t u; 84303100a63Svk199839 8442eef1f2bSErik Trauschke if (ports.numports < 2) { 8452eef1f2bSErik Trauschke warnx("can not swap %d port randomly", 8462eef1f2bSErik Trauschke ports.numports); 8472eef1f2bSErik Trauschke return; 84803100a63Svk199839 } 8492eef1f2bSErik Trauschke srandom(time(NULL)); 8502eef1f2bSErik Trauschke for (i = 0; i < ports.numports; i++) { 8512eef1f2bSErik Trauschke y = random() % (ports.numports - 1); 8522eef1f2bSErik Trauschke u = ports.list[i]; 8532eef1f2bSErik Trauschke ports.list[i] = ports.list[y]; 8542eef1f2bSErik Trauschke ports.list[y] = u; 85503100a63Svk199839 } 85603100a63Svk199839 } 85703100a63Svk199839 } 85803100a63Svk199839 85903100a63Svk199839 /* 86003100a63Svk199839 * udptest() 86103100a63Svk199839 * Do a few writes to see if the UDP port is there. 86203100a63Svk199839 * XXX - Better way of doing this? Doesn't work for IPv6. 86303100a63Svk199839 * Also fails after around 100 ports checked. 86403100a63Svk199839 */ 86503100a63Svk199839 int 86603100a63Svk199839 udptest(int s) 86703100a63Svk199839 { 86803100a63Svk199839 int i, ret; 86903100a63Svk199839 87003100a63Svk199839 for (i = 0; i <= 3; i++) { 87103100a63Svk199839 if (write(s, "X", 1) == 1) 87203100a63Svk199839 ret = 1; 87303100a63Svk199839 else 87403100a63Svk199839 ret = -1; 87503100a63Svk199839 } 87603100a63Svk199839 return (ret); 87703100a63Svk199839 } 87803100a63Svk199839 87903100a63Svk199839 void 88003100a63Svk199839 set_common_sockopts(int s) 88103100a63Svk199839 { 88203100a63Svk199839 int x = 1; 88303100a63Svk199839 884*1edba515SAndy Fiddaman if (Sflag) { 885*1edba515SAndy Fiddaman if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, 886*1edba515SAndy Fiddaman &x, sizeof (x)) == -1) { 887*1edba515SAndy Fiddaman err(1, NULL); 888*1edba515SAndy Fiddaman } 889*1edba515SAndy Fiddaman } 890*1edba515SAndy Fiddaman 89103100a63Svk199839 if (Dflag) { 89203100a63Svk199839 if (setsockopt(s, SOL_SOCKET, SO_DEBUG, &x, sizeof (x)) == -1) 89303100a63Svk199839 err(1, NULL); 89403100a63Svk199839 } 89503100a63Svk199839 if (Tflag != -1) { 89603100a63Svk199839 if (setsockopt(s, IPPROTO_IP, IP_TOS, &Tflag, 89703100a63Svk199839 sizeof (Tflag)) == -1) 89803100a63Svk199839 err(1, "set IP ToS"); 89903100a63Svk199839 } 90003100a63Svk199839 } 90103100a63Svk199839 90203100a63Svk199839 int 90303100a63Svk199839 parse_iptos(char *s) 90403100a63Svk199839 { 90503100a63Svk199839 int tos = -1; 90603100a63Svk199839 90703100a63Svk199839 if (strcmp(s, "lowdelay") == 0) 90803100a63Svk199839 return (IPTOS_LOWDELAY); 90903100a63Svk199839 if (strcmp(s, "throughput") == 0) 91003100a63Svk199839 return (IPTOS_THROUGHPUT); 91103100a63Svk199839 if (strcmp(s, "reliability") == 0) 91203100a63Svk199839 return (IPTOS_RELIABILITY); 91303100a63Svk199839 91403100a63Svk199839 if (sscanf(s, "0x%x", (unsigned int *) &tos) != 1 || 91503100a63Svk199839 tos < 0 || tos > 0xff) 91603100a63Svk199839 errx(1, "invalid IP Type of Service"); 91703100a63Svk199839 return (tos); 91803100a63Svk199839 } 91903100a63Svk199839 92003100a63Svk199839 void 92103100a63Svk199839 help(void) 92203100a63Svk199839 { 92303100a63Svk199839 usage(0); 92403100a63Svk199839 (void) fprintf(stderr, "\tCommand Summary:\n\ 92503100a63Svk199839 \t-4 Use IPv4\n\ 92603100a63Svk199839 \t-6 Use IPv6\n\ 92703100a63Svk199839 \t-D Enable the debug socket option\n\ 92803100a63Svk199839 \t-d Detach from stdin\n\ 92903100a63Svk199839 \t-h This help text\n\ 93003100a63Svk199839 \t-i secs\t Delay interval for lines sent, ports scanned\n\ 93103100a63Svk199839 \t-k Keep inbound sockets open for multiple connects\n\ 93203100a63Svk199839 \t-l Listen mode, for inbound connects\n\ 93303100a63Svk199839 \t-n Suppress name/port resolutions\n\ 93403100a63Svk199839 \t-P proxyuser\tUsername for proxy authentication\n\ 93503100a63Svk199839 \t-p port\t Specify local port or listen port\n\ 93603100a63Svk199839 \t-r Randomize remote ports\n\ 93703100a63Svk199839 \t-s addr\t Local source address\n\ 93803100a63Svk199839 \t-T ToS\t Set IP Type of Service\n\ 93903100a63Svk199839 \t-t Answer TELNET negotiation\n\ 94003100a63Svk199839 \t-U Use UNIX domain socket\n\ 94103100a63Svk199839 \t-u UDP mode\n\ 94203100a63Svk199839 \t-v Verbose\n\ 94303100a63Svk199839 \t-w secs\t Timeout for connects and final net reads\n\ 94403100a63Svk199839 \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ 94503100a63Svk199839 \t-x addr[:port]\tSpecify proxy address and port\n\ 94603100a63Svk199839 \t-z Zero-I/O mode [used for scanning]\n\ 9472eef1f2bSErik Trauschke Port numbers can be individuals, ranges (lo-hi; inclusive) and\n\ 9482eef1f2bSErik Trauschke combinations of both separated by comma (e.g. 10,22-25,80)\n"); 94903100a63Svk199839 exit(1); 95003100a63Svk199839 } 95103100a63Svk199839 95203100a63Svk199839 void 95303100a63Svk199839 usage(int ret) 95403100a63Svk199839 { 95503100a63Svk199839 (void) fprintf(stderr, 95603100a63Svk199839 "usage: nc [-46DdhklnrtUuvz] [-i interval] [-P proxy_username]" 95703100a63Svk199839 " [-p port]\n"); 95803100a63Svk199839 (void) fprintf(stderr, 95903100a63Svk199839 "\t [-s source_ip_address] [-T ToS] [-w timeout]" 96003100a63Svk199839 " [-X proxy_protocol]\n"); 96103100a63Svk199839 (void) fprintf(stderr, 96203100a63Svk199839 "\t [-x proxy_address[:port]] [hostname]" 96303100a63Svk199839 " [port[s]]\n"); 96403100a63Svk199839 if (ret) 96503100a63Svk199839 exit(1); 96603100a63Svk199839 } 967