15570Svk199839 /* $OpenBSD: netcat.c,v 1.89 2007/02/20 14:11:17 jmc Exp $ */ 25570Svk199839 /* 35570Svk199839 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 45570Svk199839 * 55570Svk199839 * Redistribution and use in source and binary forms, with or without 65570Svk199839 * modification, are permitted provided that the following conditions 75570Svk199839 * are met: 85570Svk199839 * 95570Svk199839 * 1. Redistributions of source code must retain the above copyright 105570Svk199839 * notice, this list of conditions and the following disclaimer. 115570Svk199839 * 2. Redistributions in binary form must reproduce the above copyright 125570Svk199839 * notice, this list of conditions and the following disclaimer in the 135570Svk199839 * documentation and/or other materials provided with the distribution. 145570Svk199839 * 3. The name of the author may not be used to endorse or promote products 155570Svk199839 * derived from this software without specific prior written permission. 165570Svk199839 * 175570Svk199839 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 185570Svk199839 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 195570Svk199839 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 205570Svk199839 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 215570Svk199839 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 225570Svk199839 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235570Svk199839 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245570Svk199839 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255570Svk199839 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 265570Svk199839 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275570Svk199839 */ 285570Svk199839 295570Svk199839 /* 305570Svk199839 * Re-written nc(1) for OpenBSD. Original implementation by 315570Svk199839 * *Hobbit* <hobbit@avian.org>. 325570Svk199839 */ 335570Svk199839 34*5830Svk199839 /* 35*5830Svk199839 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 36*5830Svk199839 * Use is subject to license terms. 37*5830Svk199839 */ 38*5830Svk199839 395570Svk199839 #pragma ident "%Z%%M% %I% %E% SMI" 405570Svk199839 415570Svk199839 #include <sys/types.h> 425570Svk199839 #include <sys/socket.h> 435570Svk199839 #include <sys/time.h> 445570Svk199839 #include <sys/un.h> 455570Svk199839 465570Svk199839 #include <netinet/in.h> 475570Svk199839 #include <netinet/in_systm.h> 485570Svk199839 #include <netinet/tcp.h> 495570Svk199839 #include <netinet/ip.h> 505570Svk199839 #include <arpa/telnet.h> 515570Svk199839 525570Svk199839 #include <err.h> 535570Svk199839 #include <errno.h> 545570Svk199839 #include <netdb.h> 555570Svk199839 #include <poll.h> 565570Svk199839 #include <stdarg.h> 575570Svk199839 #include <stdio.h> 585570Svk199839 #include <stdlib.h> 595570Svk199839 #include <string.h> 605570Svk199839 #include <unistd.h> 615570Svk199839 #include <fcntl.h> 625570Svk199839 #include <limits.h> 635570Svk199839 #include <signal.h> 645570Svk199839 655570Svk199839 #include "atomicio.h" 665570Svk199839 #include "strtonum.h" 675570Svk199839 685570Svk199839 #ifndef SUN_LEN 695570Svk199839 #define SUN_LEN(su) \ 705570Svk199839 (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path)) 715570Svk199839 #endif 725570Svk199839 735570Svk199839 #define PORT_MIN 1 745570Svk199839 #define PORT_MAX 65535 755570Svk199839 #define PORT_MAX_LEN 6 765570Svk199839 775570Svk199839 /* Command Line Options */ 785570Svk199839 int dflag; /* detached, no stdin */ 795570Svk199839 unsigned int iflag; /* Interval Flag */ 805570Svk199839 int kflag; /* More than one connect */ 815570Svk199839 int lflag; /* Bind to local port */ 825570Svk199839 int nflag; /* Don't do name lookup */ 835570Svk199839 char *Pflag; /* Proxy username */ 845570Svk199839 char *pflag; /* Localport flag */ 855570Svk199839 int rflag; /* Random ports flag */ 865570Svk199839 char *sflag; /* Source Address */ 875570Svk199839 int tflag; /* Telnet Emulation */ 885570Svk199839 int uflag; /* UDP - Default to TCP */ 895570Svk199839 int vflag; /* Verbosity */ 905570Svk199839 int xflag; /* Socks proxy */ 915570Svk199839 int Xflag; /* indicator of Socks version set */ 925570Svk199839 int zflag; /* Port Scan Flag */ 935570Svk199839 int Dflag; /* sodebug */ 945570Svk199839 int Tflag = -1; /* IP Type of Service */ 955570Svk199839 965570Svk199839 int timeout = -1; 975570Svk199839 int family = AF_UNSPEC; 985570Svk199839 char *portlist[PORT_MAX+1]; 995570Svk199839 1005570Svk199839 void atelnet(int, unsigned char *, unsigned int); 1015570Svk199839 void build_ports(char *); 1025570Svk199839 void help(void); 1035570Svk199839 int local_listen(char *, char *, struct addrinfo); 1045570Svk199839 void readwrite(int); 1055570Svk199839 int remote_connect(const char *, const char *, struct addrinfo); 1065570Svk199839 int socks_connect(const char *, const char *, 1075570Svk199839 const char *, const char *, struct addrinfo, int, const char *); 1085570Svk199839 int udptest(int); 1095570Svk199839 int unix_connect(char *); 1105570Svk199839 int unix_listen(char *); 1115570Svk199839 void set_common_sockopts(int); 1125570Svk199839 int parse_iptos(char *); 1135570Svk199839 void usage(int); 114*5830Svk199839 char *print_addr(char *, size_t, struct sockaddr *, int, int); 1155570Svk199839 1165570Svk199839 int 1175570Svk199839 main(int argc, char *argv[]) 1185570Svk199839 { 1195570Svk199839 int ch, s, ret, socksv; 1205570Svk199839 char *host, *uport, *proxy; 1215570Svk199839 struct addrinfo hints; 1225570Svk199839 struct servent *sv; 1235570Svk199839 socklen_t len; 1245570Svk199839 struct sockaddr_storage cliaddr; 1255570Svk199839 const char *errstr, *proxyhost = "", *proxyport = NULL; 1265570Svk199839 struct addrinfo proxyhints; 1275570Svk199839 1285570Svk199839 ret = 1; 1295570Svk199839 s = 0; 1305570Svk199839 socksv = 5; 1315570Svk199839 host = NULL; 1325570Svk199839 uport = NULL; 1335570Svk199839 sv = NULL; 1345570Svk199839 1355570Svk199839 while ((ch = getopt(argc, argv, 1365570Svk199839 "46Ddhi:klnP:p:rs:T:tUuvw:X:x:z")) != -1) { 1375570Svk199839 switch (ch) { 1385570Svk199839 case '4': 1395570Svk199839 family = AF_INET; 1405570Svk199839 break; 1415570Svk199839 case '6': 1425570Svk199839 family = AF_INET6; 1435570Svk199839 break; 1445570Svk199839 case 'U': 1455570Svk199839 family = AF_UNIX; 1465570Svk199839 break; 1475570Svk199839 case 'X': 1485570Svk199839 Xflag = 1; 1495570Svk199839 if (strcasecmp(optarg, "connect") == 0) 1505570Svk199839 socksv = -1; /* HTTP proxy CONNECT */ 1515570Svk199839 else if (strcmp(optarg, "4") == 0) 1525570Svk199839 socksv = 4; /* SOCKS v.4 */ 1535570Svk199839 else if (strcmp(optarg, "5") == 0) 1545570Svk199839 socksv = 5; /* SOCKS v.5 */ 1555570Svk199839 else 1565570Svk199839 errx(1, "unsupported proxy protocol"); 1575570Svk199839 break; 1585570Svk199839 case 'd': 1595570Svk199839 dflag = 1; 1605570Svk199839 break; 1615570Svk199839 case 'h': 1625570Svk199839 help(); 1635570Svk199839 break; 1645570Svk199839 case 'i': 1655570Svk199839 iflag = strtonum(optarg, 0, UINT_MAX, &errstr); 1665570Svk199839 if (errstr) 1675570Svk199839 errx(1, "interval %s: %s", errstr, optarg); 1685570Svk199839 break; 1695570Svk199839 case 'k': 1705570Svk199839 kflag = 1; 1715570Svk199839 break; 1725570Svk199839 case 'l': 1735570Svk199839 lflag = 1; 1745570Svk199839 break; 1755570Svk199839 case 'n': 1765570Svk199839 nflag = 1; 1775570Svk199839 break; 1785570Svk199839 case 'P': 1795570Svk199839 Pflag = optarg; 1805570Svk199839 break; 1815570Svk199839 case 'p': 1825570Svk199839 pflag = optarg; 1835570Svk199839 break; 1845570Svk199839 case 'r': 1855570Svk199839 rflag = 1; 1865570Svk199839 break; 1875570Svk199839 case 's': 1885570Svk199839 sflag = optarg; 1895570Svk199839 break; 1905570Svk199839 case 't': 1915570Svk199839 tflag = 1; 1925570Svk199839 break; 1935570Svk199839 case 'u': 1945570Svk199839 uflag = 1; 1955570Svk199839 break; 1965570Svk199839 case 'v': 1975570Svk199839 vflag = 1; 1985570Svk199839 break; 1995570Svk199839 case 'w': 2005570Svk199839 timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); 2015570Svk199839 if (errstr) 2025570Svk199839 errx(1, "timeout %s: %s", errstr, optarg); 2035570Svk199839 timeout *= 1000; 2045570Svk199839 break; 2055570Svk199839 case 'x': 2065570Svk199839 xflag = 1; 2075570Svk199839 if ((proxy = strdup(optarg)) == NULL) 2085570Svk199839 err(1, NULL); 2095570Svk199839 break; 2105570Svk199839 case 'z': 2115570Svk199839 zflag = 1; 2125570Svk199839 break; 2135570Svk199839 case 'D': 2145570Svk199839 Dflag = 1; 2155570Svk199839 break; 2165570Svk199839 case 'T': 2175570Svk199839 Tflag = parse_iptos(optarg); 2185570Svk199839 break; 2195570Svk199839 default: 2205570Svk199839 usage(1); 2215570Svk199839 } 2225570Svk199839 } 2235570Svk199839 argc -= optind; 2245570Svk199839 argv += optind; 2255570Svk199839 2265570Svk199839 /* Cruft to make sure options are clean, and used properly. */ 2275570Svk199839 if (argv[0] && !argv[1] && family == AF_UNIX) { 2285570Svk199839 if (uflag) 2295570Svk199839 errx(1, "cannot use -u and -U"); 2305570Svk199839 host = argv[0]; 2315570Svk199839 uport = NULL; 2325570Svk199839 } else if (argv[0] && !argv[1]) { 2335570Svk199839 if (!lflag) 2345570Svk199839 usage(1); 2355570Svk199839 uport = argv[0]; 2365570Svk199839 host = NULL; 2375570Svk199839 } else if (argv[0] && argv[1]) { 2385570Svk199839 if (family == AF_UNIX) 2395570Svk199839 usage(1); 2405570Svk199839 host = argv[0]; 2415570Svk199839 uport = argv[1]; 2425570Svk199839 } else { 2435570Svk199839 if (!(lflag && pflag)) 2445570Svk199839 usage(1); 2455570Svk199839 } 2465570Svk199839 2475570Svk199839 if (lflag && sflag) 2485570Svk199839 errx(1, "cannot use -s and -l"); 2495570Svk199839 if (lflag && rflag) 2505570Svk199839 errx(1, "cannot use -r and -l"); 2515570Svk199839 if (lflag && pflag) { 2525570Svk199839 if (uport) 2535570Svk199839 usage(1); 2545570Svk199839 uport = pflag; 2555570Svk199839 } 2565570Svk199839 if (lflag && zflag) 2575570Svk199839 errx(1, "cannot use -z and -l"); 2585570Svk199839 if (!lflag && kflag) 2595570Svk199839 errx(1, "must use -l with -k"); 2605570Svk199839 if (lflag && (Pflag || xflag || Xflag)) 2615570Svk199839 errx(1, "cannot use -l with -P, -X or -x"); 2625570Svk199839 2635570Svk199839 /* Initialize addrinfo structure. */ 2645570Svk199839 if (family != AF_UNIX) { 2655570Svk199839 (void) memset(&hints, 0, sizeof (struct addrinfo)); 2665570Svk199839 hints.ai_family = family; 2675570Svk199839 hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 2685570Svk199839 hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 2695570Svk199839 if (nflag) 2705570Svk199839 hints.ai_flags |= AI_NUMERICHOST; 2715570Svk199839 } 2725570Svk199839 2735570Svk199839 if (xflag) { 2745570Svk199839 if (uflag) 2755570Svk199839 errx(1, "no proxy support for UDP mode"); 2765570Svk199839 2775570Svk199839 if (lflag) 2785570Svk199839 errx(1, "no proxy support for listen"); 2795570Svk199839 2805570Svk199839 if (family == AF_UNIX) 2815570Svk199839 errx(1, "no proxy support for unix sockets"); 2825570Svk199839 2835570Svk199839 if (family == AF_INET6) 2845570Svk199839 errx(1, "no proxy support for IPv6"); 2855570Svk199839 2865570Svk199839 if (sflag) 2875570Svk199839 errx(1, "no proxy support for local source address"); 2885570Svk199839 2895570Svk199839 if ((proxyhost = strtok(proxy, ":")) == NULL) 2905570Svk199839 errx(1, "missing port specification"); 2915570Svk199839 proxyport = strtok(NULL, ":"); 2925570Svk199839 2935570Svk199839 (void) memset(&proxyhints, 0, sizeof (struct addrinfo)); 2945570Svk199839 proxyhints.ai_family = family; 2955570Svk199839 proxyhints.ai_socktype = SOCK_STREAM; 2965570Svk199839 proxyhints.ai_protocol = IPPROTO_TCP; 2975570Svk199839 if (nflag) 2985570Svk199839 proxyhints.ai_flags |= AI_NUMERICHOST; 2995570Svk199839 } 3005570Svk199839 3015570Svk199839 if (lflag) { 3025570Svk199839 int connfd; 3035570Svk199839 ret = 0; 3045570Svk199839 3055570Svk199839 if (family == AF_UNIX) 3065570Svk199839 s = unix_listen(host); 3075570Svk199839 3085570Svk199839 /* Allow only one connection at a time, but stay alive. */ 3095570Svk199839 for (;;) { 3105570Svk199839 if (family != AF_UNIX) 3115570Svk199839 s = local_listen(host, uport, hints); 3125570Svk199839 if (s < 0) 3135570Svk199839 err(1, NULL); 3145570Svk199839 /* 3155570Svk199839 * For UDP, we will use recvfrom() initially 3165570Svk199839 * to wait for a caller, then use the regular 3175570Svk199839 * functions to talk to the caller. 3185570Svk199839 */ 3195570Svk199839 if (uflag) { 3205570Svk199839 int rv, plen; 3215570Svk199839 char buf[8192]; 3225570Svk199839 struct sockaddr_storage z; 3235570Svk199839 3245570Svk199839 len = sizeof (z); 3255570Svk199839 plen = 1024; 3265570Svk199839 rv = recvfrom(s, buf, plen, MSG_PEEK, 3275570Svk199839 (struct sockaddr *)&z, &len); 3285570Svk199839 if (rv < 0) 3295570Svk199839 err(1, "recvfrom"); 3305570Svk199839 3315570Svk199839 rv = connect(s, (struct sockaddr *)&z, len); 3325570Svk199839 if (rv < 0) 3335570Svk199839 err(1, "connect"); 3345570Svk199839 3355570Svk199839 connfd = s; 3365570Svk199839 } else { 3375570Svk199839 len = sizeof (cliaddr); 3385570Svk199839 connfd = accept(s, (struct sockaddr *)&cliaddr, 3395570Svk199839 &len); 340*5830Svk199839 if ((connfd != -1) && vflag) { 341*5830Svk199839 char ntop[NI_MAXHOST + NI_MAXSERV]; 342*5830Svk199839 (void) fprintf(stderr, 343*5830Svk199839 "Received connection from %s\n", 344*5830Svk199839 print_addr(ntop, sizeof (ntop), 345*5830Svk199839 (struct sockaddr *)&cliaddr, len, 346*5830Svk199839 nflag ? NI_NUMERICHOST : 0)); 347*5830Svk199839 } 3485570Svk199839 } 3495570Svk199839 3505570Svk199839 readwrite(connfd); 3515570Svk199839 (void) close(connfd); 3525570Svk199839 if (family != AF_UNIX) 3535570Svk199839 (void) close(s); 3545570Svk199839 3555570Svk199839 if (!kflag) 3565570Svk199839 break; 3575570Svk199839 } 3585570Svk199839 } else if (family == AF_UNIX) { 3595570Svk199839 ret = 0; 3605570Svk199839 3615570Svk199839 if ((s = unix_connect(host)) > 0 && !zflag) { 3625570Svk199839 readwrite(s); 3635570Svk199839 (void) close(s); 3645570Svk199839 } else 3655570Svk199839 ret = 1; 3665570Svk199839 3675570Svk199839 exit(ret); 3685570Svk199839 3695570Svk199839 } else { /* AF_INET or AF_INET6 */ 3705570Svk199839 int i = 0; 3715570Svk199839 3725570Svk199839 /* Construct the portlist[] array. */ 3735570Svk199839 build_ports(uport); 3745570Svk199839 3755570Svk199839 /* Cycle through portlist, connecting to each port. */ 3765570Svk199839 for (i = 0; portlist[i] != NULL; i++) { 3775570Svk199839 if (s) 3785570Svk199839 (void) close(s); 3795570Svk199839 3805570Svk199839 if (xflag) 3815570Svk199839 s = socks_connect(host, portlist[i], 3825570Svk199839 proxyhost, proxyport, proxyhints, socksv, 3835570Svk199839 Pflag); 3845570Svk199839 else 3855570Svk199839 s = remote_connect(host, portlist[i], hints); 3865570Svk199839 3875570Svk199839 if (s < 0) 3885570Svk199839 continue; 3895570Svk199839 3905570Svk199839 ret = 0; 3915570Svk199839 if (vflag || zflag) { 3925570Svk199839 /* For UDP, make sure we are connected. */ 3935570Svk199839 if (uflag) { 3945570Svk199839 if (udptest(s) == -1) { 3955570Svk199839 ret = 1; 3965570Svk199839 continue; 3975570Svk199839 } 3985570Svk199839 } 3995570Svk199839 4005570Svk199839 /* Don't look up port if -n. */ 4015570Svk199839 if (nflag) 4025570Svk199839 sv = NULL; 4035570Svk199839 else { 4045570Svk199839 sv = getservbyport( 4055570Svk199839 ntohs(atoi(portlist[i])), 4065570Svk199839 uflag ? "udp" : "tcp"); 4075570Svk199839 } 4085570Svk199839 409*5830Svk199839 (void) fprintf(stderr, "Connection to %s %s " 4105570Svk199839 "port [%s/%s] succeeded!\n", 4115570Svk199839 host, portlist[i], uflag ? "udp" : "tcp", 4125570Svk199839 sv ? sv->s_name : "*"); 4135570Svk199839 } 4145570Svk199839 if (!zflag) 4155570Svk199839 readwrite(s); 4165570Svk199839 } 4175570Svk199839 } 4185570Svk199839 4195570Svk199839 if (s) 4205570Svk199839 (void) close(s); 4215570Svk199839 4225570Svk199839 return (ret); 4235570Svk199839 } 4245570Svk199839 4255570Svk199839 /* 426*5830Svk199839 * print IP address and (optionally) a port 427*5830Svk199839 */ 428*5830Svk199839 char * 429*5830Svk199839 print_addr(char *ntop, size_t ntlen, struct sockaddr *addr, int len, int flags) 430*5830Svk199839 { 431*5830Svk199839 char port[NI_MAXSERV]; 432*5830Svk199839 int e; 433*5830Svk199839 434*5830Svk199839 /* print port always as number */ 435*5830Svk199839 if ((e = getnameinfo(addr, len, ntop, ntlen, 436*5830Svk199839 port, sizeof (port), flags|NI_NUMERICSERV)) != 0) { 437*5830Svk199839 return ((char *)gai_strerror(e)); 438*5830Svk199839 } 439*5830Svk199839 440*5830Svk199839 (void) snprintf(ntop, ntlen, "%s port %s", ntop, port); 441*5830Svk199839 442*5830Svk199839 return (ntop); 443*5830Svk199839 } 444*5830Svk199839 445*5830Svk199839 /* 4465570Svk199839 * unix_connect() 4475570Svk199839 * Returns a socket connected to a local unix socket. Returns -1 on failure. 4485570Svk199839 */ 4495570Svk199839 int 4505570Svk199839 unix_connect(char *path) 4515570Svk199839 { 4525570Svk199839 struct sockaddr_un sunaddr; 4535570Svk199839 int s; 4545570Svk199839 4555570Svk199839 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 4565570Svk199839 return (-1); 4575570Svk199839 4585570Svk199839 (void) memset(&sunaddr, 0, sizeof (struct sockaddr_un)); 4595570Svk199839 sunaddr.sun_family = AF_UNIX; 4605570Svk199839 4615570Svk199839 if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >= 4625570Svk199839 sizeof (sunaddr.sun_path)) { 4635570Svk199839 (void) close(s); 4645570Svk199839 errno = ENAMETOOLONG; 4655570Svk199839 return (-1); 4665570Svk199839 } 4675570Svk199839 if (connect(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) { 4685570Svk199839 (void) close(s); 4695570Svk199839 return (-1); 4705570Svk199839 } 4715570Svk199839 return (s); 4725570Svk199839 } 4735570Svk199839 4745570Svk199839 /* 4755570Svk199839 * unix_listen() 4765570Svk199839 * Create a unix domain socket, and listen on it. 4775570Svk199839 */ 4785570Svk199839 int 4795570Svk199839 unix_listen(char *path) 4805570Svk199839 { 4815570Svk199839 struct sockaddr_un sunaddr; 4825570Svk199839 int s; 4835570Svk199839 4845570Svk199839 /* Create unix domain socket. */ 4855570Svk199839 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 4865570Svk199839 return (-1); 4875570Svk199839 4885570Svk199839 (void) memset(&sunaddr, 0, sizeof (struct sockaddr_un)); 4895570Svk199839 sunaddr.sun_family = AF_UNIX; 4905570Svk199839 4915570Svk199839 if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >= 4925570Svk199839 sizeof (sunaddr.sun_path)) { 4935570Svk199839 (void) close(s); 4945570Svk199839 errno = ENAMETOOLONG; 4955570Svk199839 return (-1); 4965570Svk199839 } 4975570Svk199839 4985570Svk199839 if (bind(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) { 4995570Svk199839 (void) close(s); 5005570Svk199839 return (-1); 5015570Svk199839 } 5025570Svk199839 5035570Svk199839 if (listen(s, 5) < 0) { 5045570Svk199839 (void) close(s); 5055570Svk199839 return (-1); 5065570Svk199839 } 5075570Svk199839 return (s); 5085570Svk199839 } 5095570Svk199839 5105570Svk199839 /* 5115570Svk199839 * remote_connect() 5125570Svk199839 * Returns a socket connected to a remote host. Properly binds to a local 5135570Svk199839 * port or source address if needed. Returns -1 on failure. 5145570Svk199839 */ 5155570Svk199839 int 5165570Svk199839 remote_connect(const char *host, const char *port, struct addrinfo hints) 5175570Svk199839 { 5185570Svk199839 struct addrinfo *res, *res0; 5195570Svk199839 int s, error; 5205570Svk199839 5215570Svk199839 if ((error = getaddrinfo(host, port, &hints, &res))) 5225570Svk199839 errx(1, "getaddrinfo: %s", gai_strerror(error)); 5235570Svk199839 5245570Svk199839 res0 = res; 5255570Svk199839 do { 5265570Svk199839 if ((s = socket(res0->ai_family, res0->ai_socktype, 5275570Svk199839 res0->ai_protocol)) < 0) { 5285570Svk199839 warn("failed to create socket"); 5295570Svk199839 continue; 5305570Svk199839 } 5315570Svk199839 5325570Svk199839 /* Bind to a local port or source address if specified. */ 5335570Svk199839 if (sflag || pflag) { 5345570Svk199839 struct addrinfo ahints, *ares; 5355570Svk199839 5365570Svk199839 (void) memset(&ahints, 0, sizeof (struct addrinfo)); 5375570Svk199839 ahints.ai_family = res0->ai_family; 5385570Svk199839 ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 5395570Svk199839 ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 5405570Svk199839 ahints.ai_flags = AI_PASSIVE; 5415570Svk199839 if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) 5425570Svk199839 errx(1, "getaddrinfo: %s", gai_strerror(error)); 5435570Svk199839 5445570Svk199839 if (bind(s, (struct sockaddr *)ares->ai_addr, 5455570Svk199839 ares->ai_addrlen) < 0) 5465570Svk199839 errx(1, "bind failed: %s", strerror(errno)); 5475570Svk199839 freeaddrinfo(ares); 548*5830Svk199839 549*5830Svk199839 if (vflag && !lflag) { 550*5830Svk199839 if (sflag != NULL) 551*5830Svk199839 (void) fprintf(stderr, 552*5830Svk199839 "Using source address: %s\n", 553*5830Svk199839 sflag); 554*5830Svk199839 if (pflag != NULL) 555*5830Svk199839 (void) fprintf(stderr, 556*5830Svk199839 "Using source port: %s\n", pflag); 557*5830Svk199839 } 5585570Svk199839 } 5595570Svk199839 5605570Svk199839 set_common_sockopts(s); 5615570Svk199839 5625570Svk199839 if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 5635570Svk199839 break; 564*5830Svk199839 else if (vflag) { 565*5830Svk199839 char ntop[NI_MAXHOST + NI_MAXSERV]; 566*5830Svk199839 warn("connect to %s [host %s] (%s) failed", 567*5830Svk199839 print_addr(ntop, sizeof (ntop), 568*5830Svk199839 res0->ai_addr, res0->ai_addrlen, NI_NUMERICHOST), 569*5830Svk199839 host, uflag ? "udp" : "tcp"); 570*5830Svk199839 } 5715570Svk199839 5725570Svk199839 (void) close(s); 5735570Svk199839 s = -1; 5745570Svk199839 } while ((res0 = res0->ai_next) != NULL); 5755570Svk199839 5765570Svk199839 freeaddrinfo(res); 5775570Svk199839 5785570Svk199839 return (s); 5795570Svk199839 } 5805570Svk199839 5815570Svk199839 /* 5825570Svk199839 * local_listen() 5835570Svk199839 * Returns a socket listening on a local port, binds to specified source 5845570Svk199839 * address. Returns -1 on failure. 5855570Svk199839 */ 5865570Svk199839 int 5875570Svk199839 local_listen(char *host, char *port, struct addrinfo hints) 5885570Svk199839 { 5895570Svk199839 struct addrinfo *res, *res0; 5905570Svk199839 int s, ret, x = 1; 5915570Svk199839 int error; 5925570Svk199839 5935570Svk199839 /* Allow nodename to be null. */ 5945570Svk199839 hints.ai_flags |= AI_PASSIVE; 5955570Svk199839 5965570Svk199839 if ((error = getaddrinfo(host, port, &hints, &res))) 5975570Svk199839 errx(1, "getaddrinfo: %s", gai_strerror(error)); 5985570Svk199839 5995570Svk199839 res0 = res; 6005570Svk199839 do { 6015570Svk199839 if ((s = socket(res0->ai_family, res0->ai_socktype, 6025570Svk199839 res0->ai_protocol)) < 0) { 6035570Svk199839 warn("failed to create socket"); 6045570Svk199839 continue; 6055570Svk199839 } 6065570Svk199839 6075570Svk199839 ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)); 6085570Svk199839 if (ret == -1) 6095570Svk199839 err(1, NULL); 6105570Svk199839 6115570Svk199839 set_common_sockopts(s); 6125570Svk199839 6135570Svk199839 if (bind(s, (struct sockaddr *)res0->ai_addr, 6145570Svk199839 res0->ai_addrlen) == 0) 6155570Svk199839 break; 6165570Svk199839 6175570Svk199839 (void) close(s); 6185570Svk199839 s = -1; 6195570Svk199839 } while ((res0 = res0->ai_next) != NULL); 6205570Svk199839 6215570Svk199839 if (!uflag && s != -1) { 6225570Svk199839 if (listen(s, 1) < 0) 6235570Svk199839 err(1, "listen"); 6245570Svk199839 } 6255570Svk199839 6265570Svk199839 freeaddrinfo(res); 6275570Svk199839 6285570Svk199839 return (s); 6295570Svk199839 } 6305570Svk199839 6315570Svk199839 /* 6325570Svk199839 * readwrite() 6335570Svk199839 * Loop that polls on the network file descriptor and stdin. 6345570Svk199839 */ 6355570Svk199839 void 6365570Svk199839 readwrite(int nfd) 6375570Svk199839 { 6385570Svk199839 struct pollfd pfd[2]; 6395570Svk199839 unsigned char buf[8192]; 6405570Svk199839 int n, wfd = fileno(stdin); 6415570Svk199839 int lfd = fileno(stdout); 6425570Svk199839 int plen; 6435570Svk199839 6445570Svk199839 plen = 1024; 6455570Svk199839 6465570Svk199839 /* Setup Network FD */ 6475570Svk199839 pfd[0].fd = nfd; 6485570Svk199839 pfd[0].events = POLLIN; 6495570Svk199839 6505570Svk199839 /* Set up STDIN FD. */ 6515570Svk199839 pfd[1].fd = wfd; 6525570Svk199839 pfd[1].events = POLLIN; 6535570Svk199839 6545570Svk199839 while (pfd[0].fd != -1) { 6555570Svk199839 if (iflag) 6565570Svk199839 (void) sleep(iflag); 6575570Svk199839 6585570Svk199839 if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { 6595570Svk199839 (void) close(nfd); 6605570Svk199839 err(1, "Polling Error"); 6615570Svk199839 } 6625570Svk199839 6635570Svk199839 if (n == 0) 6645570Svk199839 return; 6655570Svk199839 6665570Svk199839 if (pfd[0].revents & (POLLIN|POLLHUP)) { 6675570Svk199839 if ((n = read(nfd, buf, plen)) < 0) 6685570Svk199839 return; 6695570Svk199839 else if (n == 0) { 6705570Svk199839 (void) shutdown(nfd, SHUT_RD); 6715570Svk199839 pfd[0].fd = -1; 6725570Svk199839 pfd[0].events = 0; 6735570Svk199839 } else { 6745570Svk199839 if (tflag) 6755570Svk199839 atelnet(nfd, buf, n); 6765570Svk199839 if (atomicio(vwrite, lfd, buf, n) != n) 6775570Svk199839 return; 6785570Svk199839 } 6795570Svk199839 } 6805570Svk199839 6815570Svk199839 /* 6825570Svk199839 * handle the case of disconnected pipe: after pipe 6835570Svk199839 * is closed (indicated by POLLHUP) there may still 6845570Svk199839 * be some data lingering (POLLIN). After we read 6855570Svk199839 * the data, only POLLHUP remains, read() returns 0 6865570Svk199839 * and we are finished. 6875570Svk199839 */ 6885570Svk199839 if (!dflag && (pfd[1].revents & (POLLIN|POLLHUP))) { 6895570Svk199839 if ((n = read(wfd, buf, plen)) < 0) 6905570Svk199839 return; 6915570Svk199839 else if (n == 0) { 6925570Svk199839 (void) shutdown(nfd, SHUT_WR); 6935570Svk199839 pfd[1].fd = -1; 6945570Svk199839 pfd[1].events = 0; 6955570Svk199839 } else { 6965570Svk199839 if (atomicio(vwrite, nfd, buf, n) != n) 6975570Svk199839 return; 6985570Svk199839 } 6995570Svk199839 } 7005570Svk199839 } 7015570Svk199839 } 7025570Svk199839 7035570Svk199839 /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ 7045570Svk199839 void 7055570Svk199839 atelnet(int nfd, unsigned char *buf, unsigned int size) 7065570Svk199839 { 7075570Svk199839 unsigned char *p, *end; 7085570Svk199839 unsigned char obuf[4]; 7095570Svk199839 7105570Svk199839 end = buf + size; 7115570Svk199839 obuf[0] = '\0'; 7125570Svk199839 7135570Svk199839 for (p = buf; p < end; p++) { 7145570Svk199839 if (*p != IAC) 7155570Svk199839 break; 7165570Svk199839 7175570Svk199839 obuf[0] = IAC; 7185570Svk199839 obuf[1] = 0; 7195570Svk199839 p++; 7205570Svk199839 /* refuse all options */ 7215570Svk199839 if ((*p == WILL) || (*p == WONT)) 7225570Svk199839 obuf[1] = DONT; 7235570Svk199839 if ((*p == DO) || (*p == DONT)) 7245570Svk199839 obuf[1] = WONT; 7255570Svk199839 if (obuf[1]) { 7265570Svk199839 p++; 7275570Svk199839 obuf[2] = *p; 7285570Svk199839 obuf[3] = '\0'; 7295570Svk199839 if (atomicio(vwrite, nfd, obuf, 3) != 3) 7305570Svk199839 warn("Write Error!"); 7315570Svk199839 obuf[0] = '\0'; 7325570Svk199839 } 7335570Svk199839 } 7345570Svk199839 } 7355570Svk199839 7365570Svk199839 /* 7375570Svk199839 * build_ports() 7385570Svk199839 * Build an array of ports in portlist[], listing each port 7395570Svk199839 * that we should try to connect to. 7405570Svk199839 */ 7415570Svk199839 void 7425570Svk199839 build_ports(char *p) 7435570Svk199839 { 7445570Svk199839 const char *errstr; 7455570Svk199839 char *n; 7465570Svk199839 int hi, lo, cp; 7475570Svk199839 int x = 0; 7485570Svk199839 7495570Svk199839 if ((n = strchr(p, '-')) != NULL) { 7505570Svk199839 if (lflag) 7515570Svk199839 errx(1, "Cannot use -l with multiple ports!"); 7525570Svk199839 7535570Svk199839 *n = '\0'; 7545570Svk199839 n++; 7555570Svk199839 7565570Svk199839 /* Make sure the ports are in order: lowest->highest. */ 7575570Svk199839 hi = strtonum(n, PORT_MIN, PORT_MAX, &errstr); 7585570Svk199839 if (errstr) 7595570Svk199839 errx(1, "port number %s: %s", errstr, n); 7605570Svk199839 lo = strtonum(p, PORT_MIN, PORT_MAX, &errstr); 7615570Svk199839 if (errstr) 7625570Svk199839 errx(1, "port number %s: %s", errstr, p); 7635570Svk199839 7645570Svk199839 if (lo > hi) { 7655570Svk199839 cp = hi; 7665570Svk199839 hi = lo; 7675570Svk199839 lo = cp; 7685570Svk199839 } 7695570Svk199839 7705570Svk199839 /* Load ports sequentially. */ 7715570Svk199839 for (cp = lo; cp <= hi; cp++) { 7725570Svk199839 portlist[x] = calloc(1, PORT_MAX_LEN); 7735570Svk199839 if (portlist[x] == NULL) 7745570Svk199839 err(1, NULL); 7755570Svk199839 (void) snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); 7765570Svk199839 x++; 7775570Svk199839 } 7785570Svk199839 7795570Svk199839 /* Randomly swap ports. */ 7805570Svk199839 if (rflag) { 7815570Svk199839 int y; 7825570Svk199839 char *c; 7835570Svk199839 7845570Svk199839 srandom(time((time_t *)0)); 7855570Svk199839 7865570Svk199839 for (x = 0; x <= (hi - lo); x++) { 7875570Svk199839 y = (random() & 0xFFFF) % (hi - lo); 7885570Svk199839 c = portlist[x]; 7895570Svk199839 portlist[x] = portlist[y]; 7905570Svk199839 portlist[y] = c; 7915570Svk199839 } 7925570Svk199839 } 7935570Svk199839 } else { 7945570Svk199839 hi = strtonum(p, PORT_MIN, PORT_MAX, &errstr); 7955570Svk199839 if (errstr) 7965570Svk199839 errx(1, "port number %s: %s", errstr, p); 7975570Svk199839 portlist[0] = calloc(1, PORT_MAX_LEN); 7985570Svk199839 if (portlist[0] == NULL) 7995570Svk199839 err(1, NULL); 8005570Svk199839 portlist[0] = p; 8015570Svk199839 } 8025570Svk199839 } 8035570Svk199839 8045570Svk199839 /* 8055570Svk199839 * udptest() 8065570Svk199839 * Do a few writes to see if the UDP port is there. 8075570Svk199839 * XXX - Better way of doing this? Doesn't work for IPv6. 8085570Svk199839 * Also fails after around 100 ports checked. 8095570Svk199839 */ 8105570Svk199839 int 8115570Svk199839 udptest(int s) 8125570Svk199839 { 8135570Svk199839 int i, ret; 8145570Svk199839 8155570Svk199839 for (i = 0; i <= 3; i++) { 8165570Svk199839 if (write(s, "X", 1) == 1) 8175570Svk199839 ret = 1; 8185570Svk199839 else 8195570Svk199839 ret = -1; 8205570Svk199839 } 8215570Svk199839 return (ret); 8225570Svk199839 } 8235570Svk199839 8245570Svk199839 void 8255570Svk199839 set_common_sockopts(int s) 8265570Svk199839 { 8275570Svk199839 int x = 1; 8285570Svk199839 8295570Svk199839 if (Dflag) { 8305570Svk199839 if (setsockopt(s, SOL_SOCKET, SO_DEBUG, &x, sizeof (x)) == -1) 8315570Svk199839 err(1, NULL); 8325570Svk199839 } 8335570Svk199839 if (Tflag != -1) { 8345570Svk199839 if (setsockopt(s, IPPROTO_IP, IP_TOS, &Tflag, 8355570Svk199839 sizeof (Tflag)) == -1) 8365570Svk199839 err(1, "set IP ToS"); 8375570Svk199839 } 8385570Svk199839 } 8395570Svk199839 8405570Svk199839 int 8415570Svk199839 parse_iptos(char *s) 8425570Svk199839 { 8435570Svk199839 int tos = -1; 8445570Svk199839 8455570Svk199839 if (strcmp(s, "lowdelay") == 0) 8465570Svk199839 return (IPTOS_LOWDELAY); 8475570Svk199839 if (strcmp(s, "throughput") == 0) 8485570Svk199839 return (IPTOS_THROUGHPUT); 8495570Svk199839 if (strcmp(s, "reliability") == 0) 8505570Svk199839 return (IPTOS_RELIABILITY); 8515570Svk199839 8525570Svk199839 if (sscanf(s, "0x%x", (unsigned int *) &tos) != 1 || 8535570Svk199839 tos < 0 || tos > 0xff) 8545570Svk199839 errx(1, "invalid IP Type of Service"); 8555570Svk199839 return (tos); 8565570Svk199839 } 8575570Svk199839 8585570Svk199839 void 8595570Svk199839 help(void) 8605570Svk199839 { 8615570Svk199839 usage(0); 8625570Svk199839 (void) fprintf(stderr, "\tCommand Summary:\n\ 8635570Svk199839 \t-4 Use IPv4\n\ 8645570Svk199839 \t-6 Use IPv6\n\ 8655570Svk199839 \t-D Enable the debug socket option\n\ 8665570Svk199839 \t-d Detach from stdin\n\ 8675570Svk199839 \t-h This help text\n\ 8685570Svk199839 \t-i secs\t Delay interval for lines sent, ports scanned\n\ 8695570Svk199839 \t-k Keep inbound sockets open for multiple connects\n\ 8705570Svk199839 \t-l Listen mode, for inbound connects\n\ 8715570Svk199839 \t-n Suppress name/port resolutions\n\ 8725570Svk199839 \t-P proxyuser\tUsername for proxy authentication\n\ 8735570Svk199839 \t-p port\t Specify local port or listen port\n\ 8745570Svk199839 \t-r Randomize remote ports\n\ 8755570Svk199839 \t-s addr\t Local source address\n\ 8765570Svk199839 \t-T ToS\t Set IP Type of Service\n\ 8775570Svk199839 \t-t Answer TELNET negotiation\n\ 8785570Svk199839 \t-U Use UNIX domain socket\n\ 8795570Svk199839 \t-u UDP mode\n\ 8805570Svk199839 \t-v Verbose\n\ 8815570Svk199839 \t-w secs\t Timeout for connects and final net reads\n\ 8825570Svk199839 \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ 8835570Svk199839 \t-x addr[:port]\tSpecify proxy address and port\n\ 8845570Svk199839 \t-z Zero-I/O mode [used for scanning]\n\ 8855570Svk199839 Port numbers can be individual or ranges: lo-hi [inclusive]\n"); 8865570Svk199839 exit(1); 8875570Svk199839 } 8885570Svk199839 8895570Svk199839 void 8905570Svk199839 usage(int ret) 8915570Svk199839 { 8925570Svk199839 (void) fprintf(stderr, 8935570Svk199839 "usage: nc [-46DdhklnrtUuvz] [-i interval] [-P proxy_username]" 8945570Svk199839 " [-p port]\n"); 8955570Svk199839 (void) fprintf(stderr, 8965570Svk199839 "\t [-s source_ip_address] [-T ToS] [-w timeout]" 8975570Svk199839 " [-X proxy_protocol]\n"); 8985570Svk199839 (void) fprintf(stderr, 8995570Svk199839 "\t [-x proxy_address[:port]] [hostname]" 9005570Svk199839 " [port[s]]\n"); 9015570Svk199839 if (ret) 9025570Svk199839 exit(1); 9035570Svk199839 } 904