1294288Sdelphij/* $OpenBSD: netcat.c,v 1.130 2015/07/26 19:12:28 chl Exp $ */ 2141261Sdelphij/* 3141261Sdelphij * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 4141261Sdelphij * 5141261Sdelphij * Redistribution and use in source and binary forms, with or without 6141261Sdelphij * modification, are permitted provided that the following conditions 7141261Sdelphij * are met: 8141261Sdelphij * 9141261Sdelphij * 1. Redistributions of source code must retain the above copyright 10141261Sdelphij * notice, this list of conditions and the following disclaimer. 11141261Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 12141261Sdelphij * notice, this list of conditions and the following disclaimer in the 13141261Sdelphij * documentation and/or other materials provided with the distribution. 14141261Sdelphij * 3. The name of the author may not be used to endorse or promote products 15141261Sdelphij * derived from this software without specific prior written permission. 16141261Sdelphij * 17141261Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18141261Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19141261Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20141261Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21141261Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22141261Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23141261Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24141261Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25141261Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26141261Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27141394Sdelphij * 28141394Sdelphij * $FreeBSD: releng/10.3/contrib/netcat/netcat.c 294288 2016-01-18 19:42:05Z delphij $ 29141261Sdelphij */ 30141261Sdelphij 31141261Sdelphij/* 32141261Sdelphij * Re-written nc(1) for OpenBSD. Original implementation by 33141261Sdelphij * *Hobbit* <hobbit@avian.org>. 34141261Sdelphij */ 35141261Sdelphij 36141394Sdelphij#include <sys/limits.h> 37141261Sdelphij#include <sys/types.h> 38141261Sdelphij#include <sys/socket.h> 39202640Sdelphij#include <sys/sysctl.h> 40141261Sdelphij#include <sys/time.h> 41264911Sdelphij#include <sys/uio.h> 42141261Sdelphij#include <sys/un.h> 43141261Sdelphij 44141261Sdelphij#include <netinet/in.h> 45141394Sdelphij#ifdef IPSEC 46171135Sgnn#include <netipsec/ipsec.h> 47141394Sdelphij#endif 48141261Sdelphij#include <netinet/tcp.h> 49158798Sdelphij#include <netinet/ip.h> 50141261Sdelphij#include <arpa/telnet.h> 51141261Sdelphij 52141261Sdelphij#include <err.h> 53141261Sdelphij#include <errno.h> 54186343Sdelphij#include <getopt.h> 55294288Sdelphij#include <fcntl.h> 56294288Sdelphij#include <limits.h> 57141261Sdelphij#include <netdb.h> 58141261Sdelphij#include <poll.h> 59294288Sdelphij#include <signal.h> 60141261Sdelphij#include <stdarg.h> 61141261Sdelphij#include <stdio.h> 62141261Sdelphij#include <stdlib.h> 63141261Sdelphij#include <string.h> 64141261Sdelphij#include <unistd.h> 65158798Sdelphij#include "atomicio.h" 66141261Sdelphij 67141261Sdelphij#ifndef SUN_LEN 68141261Sdelphij#define SUN_LEN(su) \ 69141261Sdelphij (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 70141261Sdelphij#endif 71141261Sdelphij 72141261Sdelphij#define PORT_MAX 65535 73141261Sdelphij#define PORT_MAX_LEN 6 74221793Sdelphij#define UNIX_DG_TMP_SOCKET_SIZE 19 75141261Sdelphij 76283270Sdelphij#define POLL_STDIN 0 77283270Sdelphij#define POLL_NETOUT 1 78283270Sdelphij#define POLL_NETIN 2 79283270Sdelphij#define POLL_STDOUT 3 80283270Sdelphij#define BUFSIZE 16384 81283270Sdelphij 82141261Sdelphij/* Command Line Options */ 83141261Sdelphijint dflag; /* detached, no stdin */ 84264911Sdelphijint Fflag; /* fdpass sock to stdout */ 85167964Sdelphijunsigned int iflag; /* Interval Flag */ 86141261Sdelphijint kflag; /* More than one connect */ 87141261Sdelphijint lflag; /* Bind to local port */ 88249499Sdelphijint Nflag; /* shutdown() network socket */ 89141261Sdelphijint nflag; /* Don't do name look up */ 90186343Sdelphijint FreeBSD_Oflag; /* Do not use TCP options */ 91158798Sdelphijchar *Pflag; /* Proxy username */ 92141261Sdelphijchar *pflag; /* Localport flag */ 93141261Sdelphijint rflag; /* Random ports flag */ 94141261Sdelphijchar *sflag; /* Source Address */ 95141261Sdelphijint tflag; /* Telnet Emulation */ 96141261Sdelphijint uflag; /* UDP - Default to TCP */ 97141261Sdelphijint vflag; /* Verbosity */ 98141261Sdelphijint xflag; /* Socks proxy */ 99141261Sdelphijint zflag; /* Port Scan Flag */ 100141261Sdelphijint Dflag; /* sodebug */ 101186343Sdelphijint Iflag; /* TCP receive buffer size */ 102186343Sdelphijint Oflag; /* TCP send buffer size */ 103141261Sdelphijint Sflag; /* TCP MD5 signature option */ 104158798Sdelphijint Tflag = -1; /* IP Type of Service */ 105264911Sdelphijint rtableid = -1; 106141261Sdelphij 107141261Sdelphijint timeout = -1; 108141261Sdelphijint family = AF_UNSPEC; 109141261Sdelphijchar *portlist[PORT_MAX+1]; 110221793Sdelphijchar *unix_dg_tmp_socket; 111141261Sdelphij 112141261Sdelphijvoid atelnet(int, unsigned char *, unsigned int); 113141261Sdelphijvoid build_ports(char *); 114141261Sdelphijvoid help(void); 115141261Sdelphijint local_listen(char *, char *, struct addrinfo); 116141261Sdelphijvoid readwrite(int); 117264911Sdelphijvoid fdpass(int nfd) __attribute__((noreturn)); 118158798Sdelphijint remote_connect(const char *, const char *, struct addrinfo); 119235037Sdelphijint timeout_connect(int, const struct sockaddr *, socklen_t); 120158798Sdelphijint socks_connect(const char *, const char *, struct addrinfo, 121158798Sdelphij const char *, const char *, struct addrinfo, int, const char *); 122141261Sdelphijint udptest(int); 123221793Sdelphijint unix_bind(char *); 124141261Sdelphijint unix_connect(char *); 125141261Sdelphijint unix_listen(char *); 126283270Sdelphijvoid set_common_sockopts(int, int); 127235037Sdelphijint map_tos(char *, int *); 128241906Sdelphijvoid report_connect(const struct sockaddr *, socklen_t); 129141261Sdelphijvoid usage(int); 130283270Sdelphijssize_t drainbuf(int, unsigned char *, size_t *); 131283270Sdelphijssize_t fillbuf(int, unsigned char *, size_t *); 132141261Sdelphij 133141394Sdelphij#ifdef IPSEC 134141394Sdelphijvoid add_ipsec_policy(int, char *); 135141394Sdelphij 136141394Sdelphijchar *ipsec_policy[2]; 137141394Sdelphij#endif 138141394Sdelphij 139141261Sdelphijint 140141261Sdelphijmain(int argc, char *argv[]) 141141261Sdelphij{ 142141394Sdelphij int ch, s, ret, socksv, ipsec_count; 143202640Sdelphij int numfibs; 144202640Sdelphij size_t intsize = sizeof(int); 145167964Sdelphij char *host, *uport; 146141261Sdelphij struct addrinfo hints; 147141261Sdelphij struct servent *sv; 148141261Sdelphij socklen_t len; 149141261Sdelphij struct sockaddr_storage cliaddr; 150141261Sdelphij char *proxy; 151167964Sdelphij const char *errstr, *proxyhost = "", *proxyport = NULL; 152141261Sdelphij struct addrinfo proxyhints; 153221793Sdelphij char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; 154186343Sdelphij struct option longopts[] = { 155186343Sdelphij { "no-tcpopt", no_argument, &FreeBSD_Oflag, 1 }, 156186343Sdelphij { NULL, 0, NULL, 0 } 157186343Sdelphij }; 158141261Sdelphij 159141261Sdelphij ret = 1; 160141394Sdelphij ipsec_count = 0; 161141261Sdelphij s = 0; 162141261Sdelphij socksv = 5; 163141261Sdelphij host = NULL; 164141261Sdelphij uport = NULL; 165141261Sdelphij sv = NULL; 166141261Sdelphij 167294288Sdelphij signal(SIGPIPE, SIG_IGN); 168294288Sdelphij 169186343Sdelphij while ((ch = getopt_long(argc, argv, 170264911Sdelphij "46DdEe:FhI:i:klNnoO:P:p:rSs:tT:UuV:vw:X:x:z", 171186343Sdelphij longopts, NULL)) != -1) { 172141261Sdelphij switch (ch) { 173141261Sdelphij case '4': 174141261Sdelphij family = AF_INET; 175141261Sdelphij break; 176141261Sdelphij case '6': 177141261Sdelphij family = AF_INET6; 178141261Sdelphij break; 179141261Sdelphij case 'U': 180141261Sdelphij family = AF_UNIX; 181141261Sdelphij break; 182141261Sdelphij case 'X': 183141261Sdelphij if (strcasecmp(optarg, "connect") == 0) 184141261Sdelphij socksv = -1; /* HTTP proxy CONNECT */ 185141261Sdelphij else if (strcmp(optarg, "4") == 0) 186141261Sdelphij socksv = 4; /* SOCKS v.4 */ 187141261Sdelphij else if (strcmp(optarg, "5") == 0) 188141261Sdelphij socksv = 5; /* SOCKS v.5 */ 189141261Sdelphij else 190141261Sdelphij errx(1, "unsupported proxy protocol"); 191141261Sdelphij break; 192141261Sdelphij case 'd': 193141261Sdelphij dflag = 1; 194141261Sdelphij break; 195141394Sdelphij case 'e': 196141394Sdelphij#ifdef IPSEC 197141394Sdelphij ipsec_policy[ipsec_count++ % 2] = optarg; 198141394Sdelphij#else 199141394Sdelphij errx(1, "IPsec support unavailable."); 200141394Sdelphij#endif 201141394Sdelphij break; 202141394Sdelphij case 'E': 203141394Sdelphij#ifdef IPSEC 204141394Sdelphij ipsec_policy[0] = "in ipsec esp/transport//require"; 205141394Sdelphij ipsec_policy[1] = "out ipsec esp/transport//require"; 206141394Sdelphij#else 207141394Sdelphij errx(1, "IPsec support unavailable."); 208141394Sdelphij#endif 209141394Sdelphij break; 210264911Sdelphij case 'F': 211264911Sdelphij Fflag = 1; 212264911Sdelphij break; 213141261Sdelphij case 'h': 214141261Sdelphij help(); 215141261Sdelphij break; 216141261Sdelphij case 'i': 217167964Sdelphij iflag = strtonum(optarg, 0, UINT_MAX, &errstr); 218167964Sdelphij if (errstr) 219167964Sdelphij errx(1, "interval %s: %s", errstr, optarg); 220141261Sdelphij break; 221141261Sdelphij case 'k': 222141261Sdelphij kflag = 1; 223141261Sdelphij break; 224141261Sdelphij case 'l': 225141261Sdelphij lflag = 1; 226141261Sdelphij break; 227249499Sdelphij case 'N': 228249499Sdelphij Nflag = 1; 229249499Sdelphij break; 230141261Sdelphij case 'n': 231141261Sdelphij nflag = 1; 232141261Sdelphij break; 233141394Sdelphij case 'o': 234206675Sdelphij fprintf(stderr, "option -o is deprecated.\n"); 235141394Sdelphij break; 236158798Sdelphij case 'P': 237158798Sdelphij Pflag = optarg; 238158798Sdelphij break; 239141261Sdelphij case 'p': 240141261Sdelphij pflag = optarg; 241141261Sdelphij break; 242141261Sdelphij case 'r': 243141261Sdelphij rflag = 1; 244141261Sdelphij break; 245141261Sdelphij case 's': 246141261Sdelphij sflag = optarg; 247141261Sdelphij break; 248141261Sdelphij case 't': 249141261Sdelphij tflag = 1; 250141261Sdelphij break; 251141261Sdelphij case 'u': 252141261Sdelphij uflag = 1; 253141261Sdelphij break; 254202640Sdelphij case 'V': 255202640Sdelphij if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 256202640Sdelphij errx(1, "Multiple FIBS not supported"); 257264911Sdelphij rtableid = (int)strtonum(optarg, 0, 258202640Sdelphij numfibs - 1, &errstr); 259202640Sdelphij if (errstr) 260214047Sdelphij errx(1, "rtable %s: %s", errstr, optarg); 261202640Sdelphij break; 262141261Sdelphij case 'v': 263141261Sdelphij vflag = 1; 264141261Sdelphij break; 265141261Sdelphij case 'w': 266167964Sdelphij timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); 267167964Sdelphij if (errstr) 268167964Sdelphij errx(1, "timeout %s: %s", errstr, optarg); 269141261Sdelphij timeout *= 1000; 270141261Sdelphij break; 271141261Sdelphij case 'x': 272141261Sdelphij xflag = 1; 273141261Sdelphij if ((proxy = strdup(optarg)) == NULL) 274141261Sdelphij err(1, NULL); 275141261Sdelphij break; 276141261Sdelphij case 'z': 277141261Sdelphij zflag = 1; 278141261Sdelphij break; 279141261Sdelphij case 'D': 280141261Sdelphij Dflag = 1; 281141261Sdelphij break; 282186343Sdelphij case 'I': 283186343Sdelphij Iflag = strtonum(optarg, 1, 65536 << 14, &errstr); 284186343Sdelphij if (errstr != NULL) 285186343Sdelphij errx(1, "TCP receive window %s: %s", 286186343Sdelphij errstr, optarg); 287186343Sdelphij break; 288186343Sdelphij case 'O': 289186343Sdelphij Oflag = strtonum(optarg, 1, 65536 << 14, &errstr); 290186343Sdelphij if (errstr != NULL) { 291186343Sdelphij if (strcmp(errstr, "invalid") != 0) 292186343Sdelphij errx(1, "TCP send window %s: %s", 293186343Sdelphij errstr, optarg); 294186343Sdelphij } 295186343Sdelphij break; 296141261Sdelphij case 'S': 297141261Sdelphij Sflag = 1; 298141261Sdelphij break; 299158798Sdelphij case 'T': 300235037Sdelphij errstr = NULL; 301235037Sdelphij errno = 0; 302235037Sdelphij if (map_tos(optarg, &Tflag)) 303235037Sdelphij break; 304235037Sdelphij if (strlen(optarg) > 1 && optarg[0] == '0' && 305235037Sdelphij optarg[1] == 'x') 306235037Sdelphij Tflag = (int)strtol(optarg, NULL, 16); 307235037Sdelphij else 308235037Sdelphij Tflag = (int)strtonum(optarg, 0, 255, 309235037Sdelphij &errstr); 310235037Sdelphij if (Tflag < 0 || Tflag > 255 || errstr || errno) 311235037Sdelphij errx(1, "illegal tos value %s", optarg); 312158798Sdelphij break; 313141261Sdelphij default: 314141261Sdelphij usage(1); 315141261Sdelphij } 316141261Sdelphij } 317141261Sdelphij argc -= optind; 318141261Sdelphij argv += optind; 319141261Sdelphij 320141261Sdelphij /* Cruft to make sure options are clean, and used properly. */ 321141261Sdelphij if (argv[0] && !argv[1] && family == AF_UNIX) { 322141261Sdelphij host = argv[0]; 323141261Sdelphij uport = NULL; 324141261Sdelphij } else if (argv[0] && !argv[1]) { 325141261Sdelphij if (!lflag) 326141261Sdelphij usage(1); 327141261Sdelphij uport = argv[0]; 328141261Sdelphij host = NULL; 329141261Sdelphij } else if (argv[0] && argv[1]) { 330141261Sdelphij host = argv[0]; 331141261Sdelphij uport = argv[1]; 332141261Sdelphij } else 333141261Sdelphij usage(1); 334141261Sdelphij 335141261Sdelphij if (lflag && sflag) 336141261Sdelphij errx(1, "cannot use -s and -l"); 337141261Sdelphij if (lflag && pflag) 338141261Sdelphij errx(1, "cannot use -p and -l"); 339141261Sdelphij if (lflag && zflag) 340141261Sdelphij errx(1, "cannot use -z and -l"); 341141261Sdelphij if (!lflag && kflag) 342141261Sdelphij errx(1, "must use -l with -k"); 343141261Sdelphij 344221793Sdelphij /* Get name of temporary socket for unix datagram client */ 345221793Sdelphij if ((family == AF_UNIX) && uflag && !lflag) { 346221793Sdelphij if (sflag) { 347221793Sdelphij unix_dg_tmp_socket = sflag; 348221793Sdelphij } else { 349221793Sdelphij strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", 350221793Sdelphij UNIX_DG_TMP_SOCKET_SIZE); 351221793Sdelphij if (mktemp(unix_dg_tmp_socket_buf) == NULL) 352221793Sdelphij err(1, "mktemp"); 353221793Sdelphij unix_dg_tmp_socket = unix_dg_tmp_socket_buf; 354221793Sdelphij } 355221793Sdelphij } 356221793Sdelphij 357141261Sdelphij /* Initialize addrinfo structure. */ 358141261Sdelphij if (family != AF_UNIX) { 359141261Sdelphij memset(&hints, 0, sizeof(struct addrinfo)); 360141261Sdelphij hints.ai_family = family; 361141261Sdelphij hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 362141261Sdelphij hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 363141261Sdelphij if (nflag) 364141261Sdelphij hints.ai_flags |= AI_NUMERICHOST; 365141261Sdelphij } 366141261Sdelphij 367141261Sdelphij if (xflag) { 368141261Sdelphij if (uflag) 369141261Sdelphij errx(1, "no proxy support for UDP mode"); 370141261Sdelphij 371141261Sdelphij if (lflag) 372141261Sdelphij errx(1, "no proxy support for listen"); 373141261Sdelphij 374141261Sdelphij if (family == AF_UNIX) 375141261Sdelphij errx(1, "no proxy support for unix sockets"); 376141261Sdelphij 377141261Sdelphij /* XXX IPv6 transport to proxy would probably work */ 378141261Sdelphij if (family == AF_INET6) 379141261Sdelphij errx(1, "no proxy support for IPv6"); 380141261Sdelphij 381141261Sdelphij if (sflag) 382141261Sdelphij errx(1, "no proxy support for local source address"); 383141261Sdelphij 384141261Sdelphij proxyhost = strsep(&proxy, ":"); 385141261Sdelphij proxyport = proxy; 386141261Sdelphij 387141261Sdelphij memset(&proxyhints, 0, sizeof(struct addrinfo)); 388141261Sdelphij proxyhints.ai_family = family; 389141261Sdelphij proxyhints.ai_socktype = SOCK_STREAM; 390141261Sdelphij proxyhints.ai_protocol = IPPROTO_TCP; 391141261Sdelphij if (nflag) 392141261Sdelphij proxyhints.ai_flags |= AI_NUMERICHOST; 393141261Sdelphij } 394141261Sdelphij 395141261Sdelphij if (lflag) { 396141261Sdelphij int connfd; 397141261Sdelphij ret = 0; 398141261Sdelphij 399221793Sdelphij if (family == AF_UNIX) { 400221793Sdelphij if (uflag) 401221793Sdelphij s = unix_bind(host); 402221793Sdelphij else 403221793Sdelphij s = unix_listen(host); 404221793Sdelphij } 405141261Sdelphij 406141261Sdelphij /* Allow only one connection at a time, but stay alive. */ 407141261Sdelphij for (;;) { 408141261Sdelphij if (family != AF_UNIX) 409141261Sdelphij s = local_listen(host, uport, hints); 410141261Sdelphij if (s < 0) 411141261Sdelphij err(1, NULL); 412141261Sdelphij /* 413241906Sdelphij * For UDP and -k, don't connect the socket, let it 414241906Sdelphij * receive datagrams from multiple socket pairs. 415141261Sdelphij */ 416241906Sdelphij if (uflag && kflag) 417241906Sdelphij readwrite(s); 418241906Sdelphij /* 419241906Sdelphij * For UDP and not -k, we will use recvfrom() initially 420241906Sdelphij * to wait for a caller, then use the regular functions 421241906Sdelphij * to talk to the caller. 422241906Sdelphij */ 423241906Sdelphij else if (uflag && !kflag) { 424158798Sdelphij int rv, plen; 425214047Sdelphij char buf[16384]; 426141261Sdelphij struct sockaddr_storage z; 427141261Sdelphij 428141261Sdelphij len = sizeof(z); 429241906Sdelphij plen = 2048; 430158798Sdelphij rv = recvfrom(s, buf, plen, MSG_PEEK, 431141261Sdelphij (struct sockaddr *)&z, &len); 432141261Sdelphij if (rv < 0) 433141261Sdelphij err(1, "recvfrom"); 434141261Sdelphij 435141261Sdelphij rv = connect(s, (struct sockaddr *)&z, len); 436141261Sdelphij if (rv < 0) 437141261Sdelphij err(1, "connect"); 438141261Sdelphij 439241906Sdelphij if (vflag) 440241906Sdelphij report_connect((struct sockaddr *)&z, len); 441241906Sdelphij 442221793Sdelphij readwrite(s); 443141261Sdelphij } else { 444158798Sdelphij len = sizeof(cliaddr); 445141261Sdelphij connfd = accept(s, (struct sockaddr *)&cliaddr, 446141261Sdelphij &len); 447249499Sdelphij if (connfd == -1) { 448249499Sdelphij /* For now, all errnos are fatal */ 449283270Sdelphij err(1, "accept"); 450249499Sdelphij } 451241906Sdelphij if (vflag) 452241906Sdelphij report_connect((struct sockaddr *)&cliaddr, len); 453241906Sdelphij 454221793Sdelphij readwrite(connfd); 455221793Sdelphij close(connfd); 456141261Sdelphij } 457141261Sdelphij 458141261Sdelphij if (family != AF_UNIX) 459141261Sdelphij close(s); 460221793Sdelphij else if (uflag) { 461221793Sdelphij if (connect(s, NULL, 0) < 0) 462221793Sdelphij err(1, "connect"); 463221793Sdelphij } 464141261Sdelphij 465141261Sdelphij if (!kflag) 466141261Sdelphij break; 467141261Sdelphij } 468141261Sdelphij } else if (family == AF_UNIX) { 469141261Sdelphij ret = 0; 470141261Sdelphij 471141261Sdelphij if ((s = unix_connect(host)) > 0 && !zflag) { 472141261Sdelphij readwrite(s); 473141261Sdelphij close(s); 474141261Sdelphij } else 475141261Sdelphij ret = 1; 476141261Sdelphij 477221793Sdelphij if (uflag) 478221793Sdelphij unlink(unix_dg_tmp_socket); 479141261Sdelphij exit(ret); 480141261Sdelphij 481141261Sdelphij } else { 482141261Sdelphij int i = 0; 483141261Sdelphij 484141261Sdelphij /* Construct the portlist[] array. */ 485141261Sdelphij build_ports(uport); 486141261Sdelphij 487141261Sdelphij /* Cycle through portlist, connecting to each port. */ 488141261Sdelphij for (i = 0; portlist[i] != NULL; i++) { 489141261Sdelphij if (s) 490141261Sdelphij close(s); 491141261Sdelphij 492141261Sdelphij if (xflag) 493141261Sdelphij s = socks_connect(host, portlist[i], hints, 494158798Sdelphij proxyhost, proxyport, proxyhints, socksv, 495158798Sdelphij Pflag); 496141261Sdelphij else 497141261Sdelphij s = remote_connect(host, portlist[i], hints); 498141261Sdelphij 499141261Sdelphij if (s < 0) 500141261Sdelphij continue; 501141261Sdelphij 502141261Sdelphij ret = 0; 503141261Sdelphij if (vflag || zflag) { 504141261Sdelphij /* For UDP, make sure we are connected. */ 505141261Sdelphij if (uflag) { 506141261Sdelphij if (udptest(s) == -1) { 507141261Sdelphij ret = 1; 508141261Sdelphij continue; 509141261Sdelphij } 510141261Sdelphij } 511141261Sdelphij 512141261Sdelphij /* Don't look up port if -n. */ 513141261Sdelphij if (nflag) 514141261Sdelphij sv = NULL; 515141261Sdelphij else { 516141261Sdelphij sv = getservbyport( 517141261Sdelphij ntohs(atoi(portlist[i])), 518141261Sdelphij uflag ? "udp" : "tcp"); 519141261Sdelphij } 520141261Sdelphij 521205561Sdelphij fprintf(stderr, 522205561Sdelphij "Connection to %s %s port [%s/%s] " 523205561Sdelphij "succeeded!\n", host, portlist[i], 524205561Sdelphij uflag ? "udp" : "tcp", 525141261Sdelphij sv ? sv->s_name : "*"); 526141261Sdelphij } 527264911Sdelphij if (Fflag) 528264911Sdelphij fdpass(s); 529264911Sdelphij else if (!zflag) 530141261Sdelphij readwrite(s); 531141261Sdelphij } 532141261Sdelphij } 533141261Sdelphij 534141261Sdelphij if (s) 535141261Sdelphij close(s); 536141261Sdelphij 537141261Sdelphij exit(ret); 538141261Sdelphij} 539141261Sdelphij 540141261Sdelphij/* 541221793Sdelphij * unix_bind() 542221793Sdelphij * Returns a unix socket bound to the given path 543141261Sdelphij */ 544141261Sdelphijint 545221793Sdelphijunix_bind(char *path) 546141261Sdelphij{ 547141261Sdelphij struct sockaddr_un sun; 548141261Sdelphij int s; 549141261Sdelphij 550221793Sdelphij /* Create unix domain socket. */ 551221793Sdelphij if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, 552221793Sdelphij 0)) < 0) 553141261Sdelphij return (-1); 554141261Sdelphij 555141261Sdelphij memset(&sun, 0, sizeof(struct sockaddr_un)); 556141261Sdelphij sun.sun_family = AF_UNIX; 557141261Sdelphij 558141261Sdelphij if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 559141261Sdelphij sizeof(sun.sun_path)) { 560141261Sdelphij close(s); 561141261Sdelphij errno = ENAMETOOLONG; 562141261Sdelphij return (-1); 563141261Sdelphij } 564221793Sdelphij 565221793Sdelphij if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { 566141261Sdelphij close(s); 567141261Sdelphij return (-1); 568141261Sdelphij } 569141261Sdelphij return (s); 570141261Sdelphij} 571141261Sdelphij 572141261Sdelphij/* 573221793Sdelphij * unix_connect() 574221793Sdelphij * Returns a socket connected to a local unix socket. Returns -1 on failure. 575141261Sdelphij */ 576141261Sdelphijint 577221793Sdelphijunix_connect(char *path) 578141261Sdelphij{ 579141261Sdelphij struct sockaddr_un sun; 580141261Sdelphij int s; 581141261Sdelphij 582221793Sdelphij if (uflag) { 583221793Sdelphij if ((s = unix_bind(unix_dg_tmp_socket)) < 0) 584221793Sdelphij return (-1); 585221793Sdelphij } else { 586221793Sdelphij if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 587221793Sdelphij return (-1); 588221793Sdelphij } 589264911Sdelphij (void)fcntl(s, F_SETFD, FD_CLOEXEC); 590141261Sdelphij 591141261Sdelphij memset(&sun, 0, sizeof(struct sockaddr_un)); 592141261Sdelphij sun.sun_family = AF_UNIX; 593141261Sdelphij 594141261Sdelphij if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 595141261Sdelphij sizeof(sun.sun_path)) { 596141261Sdelphij close(s); 597141261Sdelphij errno = ENAMETOOLONG; 598141261Sdelphij return (-1); 599141261Sdelphij } 600221793Sdelphij if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { 601141261Sdelphij close(s); 602141261Sdelphij return (-1); 603141261Sdelphij } 604221793Sdelphij return (s); 605141261Sdelphij 606221793Sdelphij} 607221793Sdelphij 608221793Sdelphij/* 609221793Sdelphij * unix_listen() 610221793Sdelphij * Create a unix domain socket, and listen on it. 611221793Sdelphij */ 612221793Sdelphijint 613221793Sdelphijunix_listen(char *path) 614221793Sdelphij{ 615221793Sdelphij int s; 616221793Sdelphij if ((s = unix_bind(path)) < 0) 617221793Sdelphij return (-1); 618221793Sdelphij 619141261Sdelphij if (listen(s, 5) < 0) { 620141261Sdelphij close(s); 621141261Sdelphij return (-1); 622141261Sdelphij } 623141261Sdelphij return (s); 624141261Sdelphij} 625141261Sdelphij 626141261Sdelphij/* 627141261Sdelphij * remote_connect() 628141261Sdelphij * Returns a socket connected to a remote host. Properly binds to a local 629141261Sdelphij * port or source address if needed. Returns -1 on failure. 630141261Sdelphij */ 631141261Sdelphijint 632158798Sdelphijremote_connect(const char *host, const char *port, struct addrinfo hints) 633141261Sdelphij{ 634141261Sdelphij struct addrinfo *res, *res0; 635186343Sdelphij int s, error, on = 1; 636141261Sdelphij 637141261Sdelphij if ((error = getaddrinfo(host, port, &hints, &res))) 638141261Sdelphij errx(1, "getaddrinfo: %s", gai_strerror(error)); 639141261Sdelphij 640141261Sdelphij res0 = res; 641141261Sdelphij do { 642141261Sdelphij if ((s = socket(res0->ai_family, res0->ai_socktype, 643141261Sdelphij res0->ai_protocol)) < 0) 644141261Sdelphij continue; 645141394Sdelphij#ifdef IPSEC 646141394Sdelphij if (ipsec_policy[0] != NULL) 647141394Sdelphij add_ipsec_policy(s, ipsec_policy[0]); 648141394Sdelphij if (ipsec_policy[1] != NULL) 649141394Sdelphij add_ipsec_policy(s, ipsec_policy[1]); 650141394Sdelphij#endif 651141261Sdelphij 652264911Sdelphij if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB, 653264911Sdelphij &rtableid, sizeof(rtableid)) == -1)) 654264911Sdelphij err(1, "setsockopt SO_SETFIB"); 655202640Sdelphij 656141261Sdelphij /* Bind to a local port or source address if specified. */ 657141261Sdelphij if (sflag || pflag) { 658141261Sdelphij struct addrinfo ahints, *ares; 659141261Sdelphij 660206689Sdelphij /* try IP_BINDANY, but don't insist */ 661206689Sdelphij setsockopt(s, IPPROTO_IP, IP_BINDANY, &on, sizeof(on)); 662141261Sdelphij memset(&ahints, 0, sizeof(struct addrinfo)); 663141261Sdelphij ahints.ai_family = res0->ai_family; 664141261Sdelphij ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 665141261Sdelphij ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 666141261Sdelphij ahints.ai_flags = AI_PASSIVE; 667141261Sdelphij if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) 668141261Sdelphij errx(1, "getaddrinfo: %s", gai_strerror(error)); 669141261Sdelphij 670141261Sdelphij if (bind(s, (struct sockaddr *)ares->ai_addr, 671141261Sdelphij ares->ai_addrlen) < 0) 672274263Sdelphij err(1, "bind failed"); 673141261Sdelphij freeaddrinfo(ares); 674141261Sdelphij } 675141261Sdelphij 676283270Sdelphij set_common_sockopts(s, res0->ai_family); 677158798Sdelphij 678235037Sdelphij if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 679141261Sdelphij break; 680141261Sdelphij else if (vflag) 681141261Sdelphij warn("connect to %s port %s (%s) failed", host, port, 682141261Sdelphij uflag ? "udp" : "tcp"); 683141261Sdelphij 684141261Sdelphij close(s); 685141261Sdelphij s = -1; 686141261Sdelphij } while ((res0 = res0->ai_next) != NULL); 687141261Sdelphij 688141261Sdelphij freeaddrinfo(res); 689141261Sdelphij 690141261Sdelphij return (s); 691141261Sdelphij} 692141261Sdelphij 693235037Sdelphijint 694235037Sdelphijtimeout_connect(int s, const struct sockaddr *name, socklen_t namelen) 695235037Sdelphij{ 696235037Sdelphij struct pollfd pfd; 697235037Sdelphij socklen_t optlen; 698235037Sdelphij int flags, optval; 699235037Sdelphij int ret; 700235037Sdelphij 701235037Sdelphij if (timeout != -1) { 702235037Sdelphij flags = fcntl(s, F_GETFL, 0); 703235037Sdelphij if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 704235037Sdelphij err(1, "set non-blocking mode"); 705235037Sdelphij } 706235037Sdelphij 707235037Sdelphij if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { 708235037Sdelphij pfd.fd = s; 709235037Sdelphij pfd.events = POLLOUT; 710235037Sdelphij if ((ret = poll(&pfd, 1, timeout)) == 1) { 711235037Sdelphij optlen = sizeof(optval); 712235037Sdelphij if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, 713235037Sdelphij &optval, &optlen)) == 0) { 714235037Sdelphij errno = optval; 715235037Sdelphij ret = optval == 0 ? 0 : -1; 716235037Sdelphij } 717235037Sdelphij } else if (ret == 0) { 718235037Sdelphij errno = ETIMEDOUT; 719235037Sdelphij ret = -1; 720235037Sdelphij } else 721235037Sdelphij err(1, "poll failed"); 722235037Sdelphij } 723235037Sdelphij 724235037Sdelphij if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) 725235037Sdelphij err(1, "restoring flags"); 726235037Sdelphij 727235037Sdelphij return (ret); 728235037Sdelphij} 729235037Sdelphij 730141261Sdelphij/* 731141261Sdelphij * local_listen() 732141261Sdelphij * Returns a socket listening on a local port, binds to specified source 733141261Sdelphij * address. Returns -1 on failure. 734141261Sdelphij */ 735141261Sdelphijint 736141261Sdelphijlocal_listen(char *host, char *port, struct addrinfo hints) 737141261Sdelphij{ 738141261Sdelphij struct addrinfo *res, *res0; 739141261Sdelphij int s, ret, x = 1; 740141261Sdelphij int error; 741141261Sdelphij 742141261Sdelphij /* Allow nodename to be null. */ 743141261Sdelphij hints.ai_flags |= AI_PASSIVE; 744141261Sdelphij 745141261Sdelphij /* 746141261Sdelphij * In the case of binding to a wildcard address 747141261Sdelphij * default to binding to an ipv4 address. 748141261Sdelphij */ 749141261Sdelphij if (host == NULL && hints.ai_family == AF_UNSPEC) 750141261Sdelphij hints.ai_family = AF_INET; 751141261Sdelphij 752141261Sdelphij if ((error = getaddrinfo(host, port, &hints, &res))) 753141261Sdelphij errx(1, "getaddrinfo: %s", gai_strerror(error)); 754141261Sdelphij 755141261Sdelphij res0 = res; 756141261Sdelphij do { 757141261Sdelphij if ((s = socket(res0->ai_family, res0->ai_socktype, 758158798Sdelphij res0->ai_protocol)) < 0) 759141261Sdelphij continue; 760141261Sdelphij 761274263Sdelphij if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB, 762264911Sdelphij &rtableid, sizeof(rtableid)) == -1)) 763264911Sdelphij err(1, "setsockopt SO_SETFIB"); 764202640Sdelphij 765141261Sdelphij ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); 766141261Sdelphij if (ret == -1) 767141261Sdelphij err(1, NULL); 768141394Sdelphij#ifdef IPSEC 769141394Sdelphij if (ipsec_policy[0] != NULL) 770141394Sdelphij add_ipsec_policy(s, ipsec_policy[0]); 771141394Sdelphij if (ipsec_policy[1] != NULL) 772141394Sdelphij add_ipsec_policy(s, ipsec_policy[1]); 773141394Sdelphij#endif 774186343Sdelphij if (FreeBSD_Oflag) { 775177837Sbms if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, 776186343Sdelphij &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1) 777177837Sbms err(1, "disable TCP options"); 778177837Sbms } 779141261Sdelphij 780283270Sdelphij set_common_sockopts(s, res0->ai_family); 781283270Sdelphij 782141261Sdelphij if (bind(s, (struct sockaddr *)res0->ai_addr, 783141261Sdelphij res0->ai_addrlen) == 0) 784141261Sdelphij break; 785141261Sdelphij 786141261Sdelphij close(s); 787141261Sdelphij s = -1; 788141261Sdelphij } while ((res0 = res0->ai_next) != NULL); 789141261Sdelphij 790141261Sdelphij if (!uflag && s != -1) { 791141261Sdelphij if (listen(s, 1) < 0) 792141261Sdelphij err(1, "listen"); 793141261Sdelphij } 794141261Sdelphij 795141261Sdelphij freeaddrinfo(res); 796141261Sdelphij 797141261Sdelphij return (s); 798141261Sdelphij} 799141261Sdelphij 800141261Sdelphij/* 801141261Sdelphij * readwrite() 802141261Sdelphij * Loop that polls on the network file descriptor and stdin. 803141261Sdelphij */ 804141261Sdelphijvoid 805283270Sdelphijreadwrite(int net_fd) 806141261Sdelphij{ 807283270Sdelphij struct pollfd pfd[4]; 808283270Sdelphij int stdin_fd = STDIN_FILENO; 809283270Sdelphij int stdout_fd = STDOUT_FILENO; 810283270Sdelphij unsigned char netinbuf[BUFSIZE]; 811283270Sdelphij size_t netinbufpos = 0; 812283270Sdelphij unsigned char stdinbuf[BUFSIZE]; 813283270Sdelphij size_t stdinbufpos = 0; 814283270Sdelphij int n, num_fds; 815283270Sdelphij ssize_t ret; 816141261Sdelphij 817283270Sdelphij /* don't read from stdin if requested */ 818283270Sdelphij if (dflag) 819283270Sdelphij stdin_fd = -1; 820158798Sdelphij 821283270Sdelphij /* stdin */ 822283270Sdelphij pfd[POLL_STDIN].fd = stdin_fd; 823283270Sdelphij pfd[POLL_STDIN].events = POLLIN; 824141261Sdelphij 825283270Sdelphij /* network out */ 826283270Sdelphij pfd[POLL_NETOUT].fd = net_fd; 827283270Sdelphij pfd[POLL_NETOUT].events = 0; 828141261Sdelphij 829283270Sdelphij /* network in */ 830283270Sdelphij pfd[POLL_NETIN].fd = net_fd; 831283270Sdelphij pfd[POLL_NETIN].events = POLLIN; 832283270Sdelphij 833283270Sdelphij /* stdout */ 834283270Sdelphij pfd[POLL_STDOUT].fd = stdout_fd; 835283270Sdelphij pfd[POLL_STDOUT].events = 0; 836283270Sdelphij 837283270Sdelphij while (1) { 838283270Sdelphij /* both inputs are gone, buffers are empty, we are done */ 839283270Sdelphij if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 840283270Sdelphij && stdinbufpos == 0 && netinbufpos == 0) { 841283270Sdelphij close(net_fd); 842283270Sdelphij return; 843283270Sdelphij } 844283270Sdelphij /* both outputs are gone, we can't continue */ 845283270Sdelphij if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { 846283270Sdelphij close(net_fd); 847283270Sdelphij return; 848283270Sdelphij } 849283270Sdelphij /* listen and net in gone, queues empty, done */ 850283270Sdelphij if (lflag && pfd[POLL_NETIN].fd == -1 851283270Sdelphij && stdinbufpos == 0 && netinbufpos == 0) { 852283270Sdelphij close(net_fd); 853283270Sdelphij return; 854283270Sdelphij } 855283270Sdelphij 856283270Sdelphij /* help says -i is for "wait between lines sent". We read and 857283270Sdelphij * write arbitrary amounts of data, and we don't want to start 858283270Sdelphij * scanning for newlines, so this is as good as it gets */ 859141261Sdelphij if (iflag) 860141261Sdelphij sleep(iflag); 861141261Sdelphij 862283270Sdelphij /* poll */ 863283270Sdelphij num_fds = poll(pfd, 4, timeout); 864283270Sdelphij 865283270Sdelphij /* treat poll errors */ 866283270Sdelphij if (num_fds == -1) { 867283270Sdelphij close(net_fd); 868283270Sdelphij err(1, "polling error"); 869141261Sdelphij } 870141261Sdelphij 871283270Sdelphij /* timeout happened */ 872283270Sdelphij if (num_fds == 0) 873141261Sdelphij return; 874141261Sdelphij 875283270Sdelphij /* treat socket error conditions */ 876283270Sdelphij for (n = 0; n < 4; n++) { 877283270Sdelphij if (pfd[n].revents & (POLLERR|POLLNVAL)) { 878283270Sdelphij pfd[n].fd = -1; 879141261Sdelphij } 880141261Sdelphij } 881283270Sdelphij /* reading is possible after HUP */ 882283270Sdelphij if (pfd[POLL_STDIN].events & POLLIN && 883283270Sdelphij pfd[POLL_STDIN].revents & POLLHUP && 884283270Sdelphij ! (pfd[POLL_STDIN].revents & POLLIN)) 885283270Sdelphij pfd[POLL_STDIN].fd = -1; 886141261Sdelphij 887283270Sdelphij if (pfd[POLL_NETIN].events & POLLIN && 888283270Sdelphij pfd[POLL_NETIN].revents & POLLHUP && 889283270Sdelphij ! (pfd[POLL_NETIN].revents & POLLIN)) 890283270Sdelphij pfd[POLL_NETIN].fd = -1; 891283270Sdelphij 892283270Sdelphij if (pfd[POLL_NETOUT].revents & POLLHUP) { 893283270Sdelphij if (Nflag) 894283270Sdelphij shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); 895283270Sdelphij pfd[POLL_NETOUT].fd = -1; 896283270Sdelphij } 897283270Sdelphij /* if HUP, stop watching stdout */ 898283270Sdelphij if (pfd[POLL_STDOUT].revents & POLLHUP) 899283270Sdelphij pfd[POLL_STDOUT].fd = -1; 900283270Sdelphij /* if no net out, stop watching stdin */ 901283270Sdelphij if (pfd[POLL_NETOUT].fd == -1) 902283270Sdelphij pfd[POLL_STDIN].fd = -1; 903283270Sdelphij /* if no stdout, stop watching net in */ 904283270Sdelphij if (pfd[POLL_STDOUT].fd == -1) { 905283270Sdelphij if (pfd[POLL_NETIN].fd != -1) 906283270Sdelphij shutdown(pfd[POLL_NETIN].fd, SHUT_RD); 907283270Sdelphij pfd[POLL_NETIN].fd = -1; 908283270Sdelphij } 909283270Sdelphij 910283270Sdelphij /* try to read from stdin */ 911283270Sdelphij if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { 912283270Sdelphij ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, 913283270Sdelphij &stdinbufpos); 914283270Sdelphij /* error or eof on stdin - remove from pfd */ 915283270Sdelphij if (ret == 0 || ret == -1) 916283270Sdelphij pfd[POLL_STDIN].fd = -1; 917283270Sdelphij /* read something - poll net out */ 918283270Sdelphij if (stdinbufpos > 0) 919283270Sdelphij pfd[POLL_NETOUT].events = POLLOUT; 920283270Sdelphij /* filled buffer - remove self from polling */ 921283270Sdelphij if (stdinbufpos == BUFSIZE) 922283270Sdelphij pfd[POLL_STDIN].events = 0; 923283270Sdelphij } 924283270Sdelphij /* try to write to network */ 925283270Sdelphij if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { 926283270Sdelphij ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, 927283270Sdelphij &stdinbufpos); 928283270Sdelphij if (ret == -1) 929283270Sdelphij pfd[POLL_NETOUT].fd = -1; 930283270Sdelphij /* buffer empty - remove self from polling */ 931283270Sdelphij if (stdinbufpos == 0) 932283270Sdelphij pfd[POLL_NETOUT].events = 0; 933283270Sdelphij /* buffer no longer full - poll stdin again */ 934283270Sdelphij if (stdinbufpos < BUFSIZE) 935283270Sdelphij pfd[POLL_STDIN].events = POLLIN; 936283270Sdelphij } 937283270Sdelphij /* try to read from network */ 938283270Sdelphij if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { 939283270Sdelphij ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, 940283270Sdelphij &netinbufpos); 941283270Sdelphij if (ret == -1) 942283270Sdelphij pfd[POLL_NETIN].fd = -1; 943283270Sdelphij /* eof on net in - remove from pfd */ 944283270Sdelphij if (ret == 0) { 945283270Sdelphij shutdown(pfd[POLL_NETIN].fd, SHUT_RD); 946283270Sdelphij pfd[POLL_NETIN].fd = -1; 947141261Sdelphij } 948283270Sdelphij /* read something - poll stdout */ 949283270Sdelphij if (netinbufpos > 0) 950283270Sdelphij pfd[POLL_STDOUT].events = POLLOUT; 951283270Sdelphij /* filled buffer - remove self from polling */ 952283270Sdelphij if (netinbufpos == BUFSIZE) 953283270Sdelphij pfd[POLL_NETIN].events = 0; 954283270Sdelphij /* handle telnet */ 955283270Sdelphij if (tflag) 956283270Sdelphij atelnet(pfd[POLL_NETIN].fd, netinbuf, 957283270Sdelphij netinbufpos); 958141261Sdelphij } 959283270Sdelphij /* try to write to stdout */ 960283270Sdelphij if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { 961283270Sdelphij ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, 962283270Sdelphij &netinbufpos); 963283270Sdelphij if (ret == -1) 964283270Sdelphij pfd[POLL_STDOUT].fd = -1; 965283270Sdelphij /* buffer empty - remove self from polling */ 966283270Sdelphij if (netinbufpos == 0) 967283270Sdelphij pfd[POLL_STDOUT].events = 0; 968283270Sdelphij /* buffer no longer full - poll net in again */ 969283270Sdelphij if (netinbufpos < BUFSIZE) 970283270Sdelphij pfd[POLL_NETIN].events = POLLIN; 971283270Sdelphij } 972283270Sdelphij 973283270Sdelphij /* stdin gone and queue empty? */ 974283270Sdelphij if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { 975283270Sdelphij if (pfd[POLL_NETOUT].fd != -1 && Nflag) 976283270Sdelphij shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); 977283270Sdelphij pfd[POLL_NETOUT].fd = -1; 978283270Sdelphij } 979283270Sdelphij /* net in gone and queue empty? */ 980283270Sdelphij if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { 981283270Sdelphij pfd[POLL_STDOUT].fd = -1; 982283270Sdelphij } 983141261Sdelphij } 984141261Sdelphij} 985141261Sdelphij 986283270Sdelphijssize_t 987283270Sdelphijdrainbuf(int fd, unsigned char *buf, size_t *bufpos) 988283270Sdelphij{ 989283270Sdelphij ssize_t n; 990283270Sdelphij ssize_t adjust; 991283270Sdelphij 992283270Sdelphij n = write(fd, buf, *bufpos); 993283270Sdelphij /* don't treat EAGAIN, EINTR as error */ 994283270Sdelphij if (n == -1 && (errno == EAGAIN || errno == EINTR)) 995283270Sdelphij n = -2; 996283270Sdelphij if (n <= 0) 997283270Sdelphij return n; 998283270Sdelphij /* adjust buffer */ 999283270Sdelphij adjust = *bufpos - n; 1000283270Sdelphij if (adjust > 0) 1001283270Sdelphij memmove(buf, buf + n, adjust); 1002283270Sdelphij *bufpos -= n; 1003283270Sdelphij return n; 1004283270Sdelphij} 1005283270Sdelphij 1006283270Sdelphij 1007283270Sdelphijssize_t 1008283270Sdelphijfillbuf(int fd, unsigned char *buf, size_t *bufpos) 1009283270Sdelphij{ 1010283270Sdelphij size_t num = BUFSIZE - *bufpos; 1011283270Sdelphij ssize_t n; 1012283270Sdelphij 1013283270Sdelphij n = read(fd, buf + *bufpos, num); 1014283270Sdelphij /* don't treat EAGAIN, EINTR as error */ 1015283270Sdelphij if (n == -1 && (errno == EAGAIN || errno == EINTR)) 1016283270Sdelphij n = -2; 1017283270Sdelphij if (n <= 0) 1018283270Sdelphij return n; 1019283270Sdelphij *bufpos += n; 1020283270Sdelphij return n; 1021283270Sdelphij} 1022283270Sdelphij 1023264911Sdelphij/* 1024264911Sdelphij * fdpass() 1025264911Sdelphij * Pass the connected file descriptor to stdout and exit. 1026264911Sdelphij */ 1027264911Sdelphijvoid 1028264911Sdelphijfdpass(int nfd) 1029264911Sdelphij{ 1030264911Sdelphij struct msghdr mh; 1031264911Sdelphij union { 1032264911Sdelphij struct cmsghdr hdr; 1033264911Sdelphij char buf[CMSG_SPACE(sizeof(int))]; 1034264911Sdelphij } cmsgbuf; 1035264911Sdelphij struct cmsghdr *cmsg; 1036264911Sdelphij struct iovec iov; 1037264911Sdelphij char c = '\0'; 1038264911Sdelphij ssize_t r; 1039264911Sdelphij struct pollfd pfd; 1040264911Sdelphij 1041264911Sdelphij /* Avoid obvious stupidity */ 1042264911Sdelphij if (isatty(STDOUT_FILENO)) 1043264911Sdelphij errx(1, "Cannot pass file descriptor to tty"); 1044264911Sdelphij 1045264911Sdelphij bzero(&mh, sizeof(mh)); 1046264911Sdelphij bzero(&cmsgbuf, sizeof(cmsgbuf)); 1047264911Sdelphij bzero(&iov, sizeof(iov)); 1048264911Sdelphij 1049264911Sdelphij mh.msg_control = (caddr_t)&cmsgbuf.buf; 1050264911Sdelphij mh.msg_controllen = sizeof(cmsgbuf.buf); 1051264911Sdelphij cmsg = CMSG_FIRSTHDR(&mh); 1052264911Sdelphij cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 1053264911Sdelphij cmsg->cmsg_level = SOL_SOCKET; 1054264911Sdelphij cmsg->cmsg_type = SCM_RIGHTS; 1055264911Sdelphij *(int *)CMSG_DATA(cmsg) = nfd; 1056264911Sdelphij 1057264911Sdelphij iov.iov_base = &c; 1058264911Sdelphij iov.iov_len = 1; 1059264911Sdelphij mh.msg_iov = &iov; 1060264911Sdelphij mh.msg_iovlen = 1; 1061264911Sdelphij 1062264911Sdelphij bzero(&pfd, sizeof(pfd)); 1063264911Sdelphij pfd.fd = STDOUT_FILENO; 1064294288Sdelphij pfd.events = POLLOUT; 1065264911Sdelphij for (;;) { 1066264911Sdelphij r = sendmsg(STDOUT_FILENO, &mh, 0); 1067264911Sdelphij if (r == -1) { 1068264911Sdelphij if (errno == EAGAIN || errno == EINTR) { 1069264911Sdelphij if (poll(&pfd, 1, -1) == -1) 1070264911Sdelphij err(1, "poll"); 1071264911Sdelphij continue; 1072264911Sdelphij } 1073264911Sdelphij err(1, "sendmsg"); 1074294288Sdelphij } else if (r != 1) 1075264911Sdelphij errx(1, "sendmsg: unexpected return value %zd", r); 1076264911Sdelphij else 1077264911Sdelphij break; 1078264911Sdelphij } 1079264911Sdelphij exit(0); 1080264911Sdelphij} 1081264911Sdelphij 1082141261Sdelphij/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ 1083141261Sdelphijvoid 1084141261Sdelphijatelnet(int nfd, unsigned char *buf, unsigned int size) 1085141261Sdelphij{ 1086141261Sdelphij unsigned char *p, *end; 1087141261Sdelphij unsigned char obuf[4]; 1088141261Sdelphij 1089205561Sdelphij if (size < 3) 1090205561Sdelphij return; 1091205561Sdelphij end = buf + size - 2; 1092141261Sdelphij 1093141261Sdelphij for (p = buf; p < end; p++) { 1094141261Sdelphij if (*p != IAC) 1095205561Sdelphij continue; 1096141261Sdelphij 1097141261Sdelphij obuf[0] = IAC; 1098141261Sdelphij p++; 1099141261Sdelphij if ((*p == WILL) || (*p == WONT)) 1100141261Sdelphij obuf[1] = DONT; 1101205561Sdelphij else if ((*p == DO) || (*p == DONT)) 1102141261Sdelphij obuf[1] = WONT; 1103205561Sdelphij else 1104205561Sdelphij continue; 1105205561Sdelphij 1106205561Sdelphij p++; 1107205561Sdelphij obuf[2] = *p; 1108205561Sdelphij if (atomicio(vwrite, nfd, obuf, 3) != 3) 1109205561Sdelphij warn("Write Error!"); 1110141261Sdelphij } 1111141261Sdelphij} 1112141261Sdelphij 1113141261Sdelphij/* 1114141261Sdelphij * build_ports() 1115235037Sdelphij * Build an array of ports in portlist[], listing each port 1116141261Sdelphij * that we should try to connect to. 1117141261Sdelphij */ 1118141261Sdelphijvoid 1119141261Sdelphijbuild_ports(char *p) 1120141261Sdelphij{ 1121167964Sdelphij const char *errstr; 1122167964Sdelphij char *n; 1123141261Sdelphij int hi, lo, cp; 1124141261Sdelphij int x = 0; 1125141261Sdelphij 1126141261Sdelphij if ((n = strchr(p, '-')) != NULL) { 1127141261Sdelphij *n = '\0'; 1128141261Sdelphij n++; 1129141261Sdelphij 1130141261Sdelphij /* Make sure the ports are in order: lowest->highest. */ 1131167964Sdelphij hi = strtonum(n, 1, PORT_MAX, &errstr); 1132167964Sdelphij if (errstr) 1133167964Sdelphij errx(1, "port number %s: %s", errstr, n); 1134167964Sdelphij lo = strtonum(p, 1, PORT_MAX, &errstr); 1135167964Sdelphij if (errstr) 1136167964Sdelphij errx(1, "port number %s: %s", errstr, p); 1137141261Sdelphij 1138141261Sdelphij if (lo > hi) { 1139141261Sdelphij cp = hi; 1140141261Sdelphij hi = lo; 1141141261Sdelphij lo = cp; 1142141261Sdelphij } 1143141261Sdelphij 1144141261Sdelphij /* Load ports sequentially. */ 1145141261Sdelphij for (cp = lo; cp <= hi; cp++) { 1146141261Sdelphij portlist[x] = calloc(1, PORT_MAX_LEN); 1147141261Sdelphij if (portlist[x] == NULL) 1148141261Sdelphij err(1, NULL); 1149141261Sdelphij snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); 1150141261Sdelphij x++; 1151141261Sdelphij } 1152141261Sdelphij 1153141261Sdelphij /* Randomly swap ports. */ 1154141261Sdelphij if (rflag) { 1155141261Sdelphij int y; 1156141261Sdelphij char *c; 1157141261Sdelphij 1158141261Sdelphij for (x = 0; x <= (hi - lo); x++) { 1159141261Sdelphij y = (arc4random() & 0xFFFF) % (hi - lo); 1160141261Sdelphij c = portlist[x]; 1161141261Sdelphij portlist[x] = portlist[y]; 1162141261Sdelphij portlist[y] = c; 1163141261Sdelphij } 1164141261Sdelphij } 1165141261Sdelphij } else { 1166167964Sdelphij hi = strtonum(p, 1, PORT_MAX, &errstr); 1167167964Sdelphij if (errstr) 1168167964Sdelphij errx(1, "port number %s: %s", errstr, p); 1169214047Sdelphij portlist[0] = strdup(p); 1170141261Sdelphij if (portlist[0] == NULL) 1171141261Sdelphij err(1, NULL); 1172141261Sdelphij } 1173141261Sdelphij} 1174141261Sdelphij 1175141261Sdelphij/* 1176141261Sdelphij * udptest() 1177141261Sdelphij * Do a few writes to see if the UDP port is there. 1178235037Sdelphij * Fails once PF state table is full. 1179141261Sdelphij */ 1180141261Sdelphijint 1181141261Sdelphijudptest(int s) 1182141261Sdelphij{ 1183141261Sdelphij int i, ret; 1184141261Sdelphij 1185141261Sdelphij for (i = 0; i <= 3; i++) { 1186141261Sdelphij if (write(s, "X", 1) == 1) 1187141261Sdelphij ret = 1; 1188141261Sdelphij else 1189141261Sdelphij ret = -1; 1190141261Sdelphij } 1191141261Sdelphij return (ret); 1192141261Sdelphij} 1193141261Sdelphij 1194141261Sdelphijvoid 1195283270Sdelphijset_common_sockopts(int s, int af) 1196158798Sdelphij{ 1197158798Sdelphij int x = 1; 1198158798Sdelphij 1199158798Sdelphij if (Sflag) { 1200158798Sdelphij if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, 1201158798Sdelphij &x, sizeof(x)) == -1) 1202158798Sdelphij err(1, NULL); 1203158798Sdelphij } 1204158798Sdelphij if (Dflag) { 1205158798Sdelphij if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 1206158798Sdelphij &x, sizeof(x)) == -1) 1207158798Sdelphij err(1, NULL); 1208158798Sdelphij } 1209158798Sdelphij if (Tflag != -1) { 1210283270Sdelphij int proto, option; 1211283270Sdelphij 1212283270Sdelphij if (af == AF_INET6) { 1213283270Sdelphij proto = IPPROTO_IPV6; 1214283270Sdelphij option = IPV6_TCLASS; 1215283270Sdelphij } else { 1216283270Sdelphij proto = IPPROTO_IP; 1217283270Sdelphij option = IP_TOS; 1218283270Sdelphij } 1219283270Sdelphij 1220283270Sdelphij if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1) 1221158798Sdelphij err(1, "set IP ToS"); 1222158798Sdelphij } 1223186343Sdelphij if (Iflag) { 1224186343Sdelphij if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 1225186343Sdelphij &Iflag, sizeof(Iflag)) == -1) 1226186343Sdelphij err(1, "set TCP receive buffer size"); 1227186343Sdelphij } 1228177837Sbms if (Oflag) { 1229186343Sdelphij if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 1230186343Sdelphij &Oflag, sizeof(Oflag)) == -1) 1231186343Sdelphij err(1, "set TCP send buffer size"); 1232186343Sdelphij } 1233186343Sdelphij if (FreeBSD_Oflag) { 1234177837Sbms if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, 1235186343Sdelphij &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1) 1236177837Sbms err(1, "disable TCP options"); 1237177837Sbms } 1238158798Sdelphij} 1239158798Sdelphij 1240158798Sdelphijint 1241235037Sdelphijmap_tos(char *s, int *val) 1242158798Sdelphij{ 1243235037Sdelphij /* DiffServ Codepoints and other TOS mappings */ 1244235037Sdelphij const struct toskeywords { 1245235037Sdelphij const char *keyword; 1246235037Sdelphij int val; 1247235037Sdelphij } *t, toskeywords[] = { 1248235037Sdelphij { "af11", IPTOS_DSCP_AF11 }, 1249235037Sdelphij { "af12", IPTOS_DSCP_AF12 }, 1250235037Sdelphij { "af13", IPTOS_DSCP_AF13 }, 1251235037Sdelphij { "af21", IPTOS_DSCP_AF21 }, 1252235037Sdelphij { "af22", IPTOS_DSCP_AF22 }, 1253235037Sdelphij { "af23", IPTOS_DSCP_AF23 }, 1254235037Sdelphij { "af31", IPTOS_DSCP_AF31 }, 1255235037Sdelphij { "af32", IPTOS_DSCP_AF32 }, 1256235037Sdelphij { "af33", IPTOS_DSCP_AF33 }, 1257235037Sdelphij { "af41", IPTOS_DSCP_AF41 }, 1258235037Sdelphij { "af42", IPTOS_DSCP_AF42 }, 1259235037Sdelphij { "af43", IPTOS_DSCP_AF43 }, 1260235037Sdelphij { "critical", IPTOS_PREC_CRITIC_ECP }, 1261235037Sdelphij { "cs0", IPTOS_DSCP_CS0 }, 1262235037Sdelphij { "cs1", IPTOS_DSCP_CS1 }, 1263235037Sdelphij { "cs2", IPTOS_DSCP_CS2 }, 1264235037Sdelphij { "cs3", IPTOS_DSCP_CS3 }, 1265235037Sdelphij { "cs4", IPTOS_DSCP_CS4 }, 1266235037Sdelphij { "cs5", IPTOS_DSCP_CS5 }, 1267235037Sdelphij { "cs6", IPTOS_DSCP_CS6 }, 1268235037Sdelphij { "cs7", IPTOS_DSCP_CS7 }, 1269235037Sdelphij { "ef", IPTOS_DSCP_EF }, 1270235037Sdelphij { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 1271235037Sdelphij { "lowdelay", IPTOS_LOWDELAY }, 1272235037Sdelphij { "netcontrol", IPTOS_PREC_NETCONTROL }, 1273235037Sdelphij { "reliability", IPTOS_RELIABILITY }, 1274235037Sdelphij { "throughput", IPTOS_THROUGHPUT }, 1275235037Sdelphij { NULL, -1 }, 1276235037Sdelphij }; 1277158798Sdelphij 1278235037Sdelphij for (t = toskeywords; t->keyword != NULL; t++) { 1279235037Sdelphij if (strcmp(s, t->keyword) == 0) { 1280235037Sdelphij *val = t->val; 1281235037Sdelphij return (1); 1282235037Sdelphij } 1283235037Sdelphij } 1284158798Sdelphij 1285235037Sdelphij return (0); 1286158798Sdelphij} 1287158798Sdelphij 1288158798Sdelphijvoid 1289241906Sdelphijreport_connect(const struct sockaddr *sa, socklen_t salen) 1290241906Sdelphij{ 1291241906Sdelphij char remote_host[NI_MAXHOST]; 1292241906Sdelphij char remote_port[NI_MAXSERV]; 1293241906Sdelphij int herr; 1294241906Sdelphij int flags = NI_NUMERICSERV; 1295241906Sdelphij 1296241906Sdelphij if (nflag) 1297241906Sdelphij flags |= NI_NUMERICHOST; 1298241906Sdelphij 1299241906Sdelphij if ((herr = getnameinfo(sa, salen, 1300241906Sdelphij remote_host, sizeof(remote_host), 1301241906Sdelphij remote_port, sizeof(remote_port), 1302241906Sdelphij flags)) != 0) { 1303241906Sdelphij if (herr == EAI_SYSTEM) 1304241906Sdelphij err(1, "getnameinfo"); 1305241906Sdelphij else 1306241906Sdelphij errx(1, "getnameinfo: %s", gai_strerror(herr)); 1307241906Sdelphij } 1308241906Sdelphij 1309241906Sdelphij fprintf(stderr, 1310241906Sdelphij "Connection from %s %s " 1311241906Sdelphij "received!\n", remote_host, remote_port); 1312241906Sdelphij} 1313241906Sdelphij 1314241906Sdelphijvoid 1315141261Sdelphijhelp(void) 1316141261Sdelphij{ 1317141261Sdelphij usage(0); 1318141261Sdelphij fprintf(stderr, "\tCommand Summary:\n\ 1319141261Sdelphij \t-4 Use IPv4\n\ 1320178927Santoine \t-6 Use IPv6\n\ 1321178927Santoine \t-D Enable the debug socket option\n\ 1322178927Santoine \t-d Detach from stdin\n"); 1323141394Sdelphij#ifdef IPSEC 1324141394Sdelphij fprintf(stderr, "\ 1325178927Santoine \t-E Use IPsec ESP\n\ 1326178927Santoine \t-e policy Use specified IPsec policy\n"); 1327141394Sdelphij#endif 1328141394Sdelphij fprintf(stderr, "\ 1329264911Sdelphij \t-F Pass socket fd\n\ 1330141261Sdelphij \t-h This help text\n\ 1331186343Sdelphij \t-I length TCP receive buffer length\n\ 1332141261Sdelphij \t-i secs\t Delay interval for lines sent, ports scanned\n\ 1333141261Sdelphij \t-k Keep inbound sockets open for multiple connects\n\ 1334141261Sdelphij \t-l Listen mode, for inbound connects\n\ 1335249499Sdelphij \t-N Shutdown the network socket after EOF on stdin\n\ 1336141261Sdelphij \t-n Suppress name/port resolutions\n\ 1337186343Sdelphij \t--no-tcpopt Disable TCP options\n\ 1338186343Sdelphij \t-O length TCP send buffer length\n\ 1339158798Sdelphij \t-P proxyuser\tUsername for proxy authentication\n\ 1340141261Sdelphij \t-p port\t Specify local port for remote connects\n\ 1341141261Sdelphij \t-r Randomize remote ports\n\ 1342141261Sdelphij \t-S Enable the TCP MD5 signature option\n\ 1343141261Sdelphij \t-s addr\t Local source address\n\ 1344235037Sdelphij \t-T toskeyword\tSet IP Type of Service\n\ 1345141261Sdelphij \t-t Answer TELNET negotiation\n\ 1346141261Sdelphij \t-U Use UNIX domain socket\n\ 1347141261Sdelphij \t-u UDP mode\n\ 1348214047Sdelphij \t-V rtable Specify alternate routing table\n\ 1349141261Sdelphij \t-v Verbose\n\ 1350141261Sdelphij \t-w secs\t Timeout for connects and final net reads\n\ 1351141261Sdelphij \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ 1352141261Sdelphij \t-x addr[:port]\tSpecify proxy address and port\n\ 1353141261Sdelphij \t-z Zero-I/O mode [used for scanning]\n\ 1354141261Sdelphij Port numbers can be individual or ranges: lo-hi [inclusive]\n"); 1355141394Sdelphij#ifdef IPSEC 1356141394Sdelphij fprintf(stderr, "See ipsec_set_policy(3) for -e argument format\n"); 1357141394Sdelphij#endif 1358141261Sdelphij exit(1); 1359141261Sdelphij} 1360141261Sdelphij 1361141394Sdelphij#ifdef IPSEC 1362141261Sdelphijvoid 1363141394Sdelphijadd_ipsec_policy(int s, char *policy) 1364141394Sdelphij{ 1365141394Sdelphij char *raw; 1366141394Sdelphij int e; 1367141394Sdelphij 1368141394Sdelphij raw = ipsec_set_policy(policy, strlen(policy)); 1369141394Sdelphij if (raw == NULL) 1370141394Sdelphij errx(1, "ipsec_set_policy `%s': %s", policy, 1371141394Sdelphij ipsec_strerror()); 1372141394Sdelphij e = setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, raw, 1373141394Sdelphij ipsec_get_policylen(raw)); 1374141394Sdelphij if (e < 0) 1375141394Sdelphij err(1, "ipsec policy cannot be configured"); 1376141394Sdelphij free(raw); 1377141394Sdelphij if (vflag) 1378141394Sdelphij fprintf(stderr, "ipsec policy configured: `%s'\n", policy); 1379141394Sdelphij return; 1380141394Sdelphij} 1381141394Sdelphij#endif /* IPSEC */ 1382141394Sdelphij 1383141394Sdelphijvoid 1384141261Sdelphijusage(int ret) 1385141261Sdelphij{ 1386193008Sdelphij fprintf(stderr, 1387141394Sdelphij#ifdef IPSEC 1388264911Sdelphij "usage: nc [-46DdEFhklNnrStUuvz] [-e policy] [-I length] [-i interval] [-O length]\n" 1389141394Sdelphij#else 1390264911Sdelphij "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" 1391141394Sdelphij#endif 1392221793Sdelphij "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" 1393214047Sdelphij "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" 1394221793Sdelphij "\t [-x proxy_address[:port]] [destination] [port]\n"); 1395141261Sdelphij if (ret) 1396141261Sdelphij exit(1); 1397141261Sdelphij} 1398