1264911Sdelphij/* $OpenBSD: netcat.c,v 1.117 2013/10/26 21:33:29 sthen 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$ 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> 45158798Sdelphij#include <netinet/in_systm.h> 46141394Sdelphij#ifdef IPSEC 47171135Sgnn#include <netipsec/ipsec.h> 48141394Sdelphij#endif 49141261Sdelphij#include <netinet/tcp.h> 50158798Sdelphij#include <netinet/ip.h> 51141261Sdelphij#include <arpa/telnet.h> 52141261Sdelphij 53141261Sdelphij#include <err.h> 54141261Sdelphij#include <errno.h> 55186343Sdelphij#include <getopt.h> 56141261Sdelphij#include <netdb.h> 57141261Sdelphij#include <poll.h> 58141261Sdelphij#include <stdarg.h> 59141261Sdelphij#include <stdio.h> 60141261Sdelphij#include <stdlib.h> 61141261Sdelphij#include <string.h> 62141261Sdelphij#include <unistd.h> 63141261Sdelphij#include <fcntl.h> 64158798Sdelphij#include <limits.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 76141261Sdelphij/* Command Line Options */ 77141261Sdelphijint dflag; /* detached, no stdin */ 78264911Sdelphijint Fflag; /* fdpass sock to stdout */ 79167964Sdelphijunsigned int iflag; /* Interval Flag */ 80141261Sdelphijint kflag; /* More than one connect */ 81141261Sdelphijint lflag; /* Bind to local port */ 82249499Sdelphijint Nflag; /* shutdown() network socket */ 83141261Sdelphijint nflag; /* Don't do name look up */ 84186343Sdelphijint FreeBSD_Oflag; /* Do not use TCP options */ 85158798Sdelphijchar *Pflag; /* Proxy username */ 86141261Sdelphijchar *pflag; /* Localport flag */ 87141261Sdelphijint rflag; /* Random ports flag */ 88141261Sdelphijchar *sflag; /* Source Address */ 89141261Sdelphijint tflag; /* Telnet Emulation */ 90141261Sdelphijint uflag; /* UDP - Default to TCP */ 91141261Sdelphijint vflag; /* Verbosity */ 92141261Sdelphijint xflag; /* Socks proxy */ 93141261Sdelphijint zflag; /* Port Scan Flag */ 94141261Sdelphijint Dflag; /* sodebug */ 95186343Sdelphijint Iflag; /* TCP receive buffer size */ 96186343Sdelphijint Oflag; /* TCP send buffer size */ 97141261Sdelphijint Sflag; /* TCP MD5 signature option */ 98158798Sdelphijint Tflag = -1; /* IP Type of Service */ 99264911Sdelphijint rtableid = -1; 100141261Sdelphij 101141261Sdelphijint timeout = -1; 102141261Sdelphijint family = AF_UNSPEC; 103141261Sdelphijchar *portlist[PORT_MAX+1]; 104221793Sdelphijchar *unix_dg_tmp_socket; 105141261Sdelphij 106141261Sdelphijvoid atelnet(int, unsigned char *, unsigned int); 107141261Sdelphijvoid build_ports(char *); 108141261Sdelphijvoid help(void); 109141261Sdelphijint local_listen(char *, char *, struct addrinfo); 110141261Sdelphijvoid readwrite(int); 111264911Sdelphijvoid fdpass(int nfd) __attribute__((noreturn)); 112158798Sdelphijint remote_connect(const char *, const char *, struct addrinfo); 113235037Sdelphijint timeout_connect(int, const struct sockaddr *, socklen_t); 114158798Sdelphijint socks_connect(const char *, const char *, struct addrinfo, 115158798Sdelphij const char *, const char *, struct addrinfo, int, const char *); 116141261Sdelphijint udptest(int); 117221793Sdelphijint unix_bind(char *); 118141261Sdelphijint unix_connect(char *); 119141261Sdelphijint unix_listen(char *); 120158798Sdelphijvoid set_common_sockopts(int); 121235037Sdelphijint map_tos(char *, int *); 122241906Sdelphijvoid report_connect(const struct sockaddr *, socklen_t); 123141261Sdelphijvoid usage(int); 124141261Sdelphij 125141394Sdelphij#ifdef IPSEC 126141394Sdelphijvoid add_ipsec_policy(int, char *); 127141394Sdelphij 128141394Sdelphijchar *ipsec_policy[2]; 129141394Sdelphij#endif 130141394Sdelphij 131141261Sdelphijint 132141261Sdelphijmain(int argc, char *argv[]) 133141261Sdelphij{ 134141394Sdelphij int ch, s, ret, socksv, ipsec_count; 135202640Sdelphij int numfibs; 136202640Sdelphij size_t intsize = sizeof(int); 137167964Sdelphij char *host, *uport; 138141261Sdelphij struct addrinfo hints; 139141261Sdelphij struct servent *sv; 140141261Sdelphij socklen_t len; 141141261Sdelphij struct sockaddr_storage cliaddr; 142141261Sdelphij char *proxy; 143167964Sdelphij const char *errstr, *proxyhost = "", *proxyport = NULL; 144141261Sdelphij struct addrinfo proxyhints; 145221793Sdelphij char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; 146186343Sdelphij struct option longopts[] = { 147186343Sdelphij { "no-tcpopt", no_argument, &FreeBSD_Oflag, 1 }, 148186343Sdelphij { NULL, 0, NULL, 0 } 149186343Sdelphij }; 150141261Sdelphij 151141261Sdelphij ret = 1; 152141394Sdelphij ipsec_count = 0; 153141261Sdelphij s = 0; 154141261Sdelphij socksv = 5; 155141261Sdelphij host = NULL; 156141261Sdelphij uport = NULL; 157141261Sdelphij sv = NULL; 158264911Sdelphij#if 0 159264911Sdelphij rtableid = getrtable(); 160264911Sdelphij#endif 161141261Sdelphij 162186343Sdelphij while ((ch = getopt_long(argc, argv, 163264911Sdelphij "46DdEe:FhI:i:klNnoO:P:p:rSs:tT:UuV:vw:X:x:z", 164186343Sdelphij longopts, NULL)) != -1) { 165141261Sdelphij switch (ch) { 166141261Sdelphij case '4': 167141261Sdelphij family = AF_INET; 168141261Sdelphij break; 169141261Sdelphij case '6': 170141261Sdelphij family = AF_INET6; 171141261Sdelphij break; 172141261Sdelphij case 'U': 173141261Sdelphij family = AF_UNIX; 174141261Sdelphij break; 175141261Sdelphij case 'X': 176141261Sdelphij if (strcasecmp(optarg, "connect") == 0) 177141261Sdelphij socksv = -1; /* HTTP proxy CONNECT */ 178141261Sdelphij else if (strcmp(optarg, "4") == 0) 179141261Sdelphij socksv = 4; /* SOCKS v.4 */ 180141261Sdelphij else if (strcmp(optarg, "5") == 0) 181141261Sdelphij socksv = 5; /* SOCKS v.5 */ 182141261Sdelphij else 183141261Sdelphij errx(1, "unsupported proxy protocol"); 184141261Sdelphij break; 185141261Sdelphij case 'd': 186141261Sdelphij dflag = 1; 187141261Sdelphij break; 188141394Sdelphij case 'e': 189141394Sdelphij#ifdef IPSEC 190141394Sdelphij ipsec_policy[ipsec_count++ % 2] = optarg; 191141394Sdelphij#else 192141394Sdelphij errx(1, "IPsec support unavailable."); 193141394Sdelphij#endif 194141394Sdelphij break; 195141394Sdelphij case 'E': 196141394Sdelphij#ifdef IPSEC 197141394Sdelphij ipsec_policy[0] = "in ipsec esp/transport//require"; 198141394Sdelphij ipsec_policy[1] = "out ipsec esp/transport//require"; 199141394Sdelphij#else 200141394Sdelphij errx(1, "IPsec support unavailable."); 201141394Sdelphij#endif 202141394Sdelphij break; 203264911Sdelphij case 'F': 204264911Sdelphij Fflag = 1; 205264911Sdelphij break; 206141261Sdelphij case 'h': 207141261Sdelphij help(); 208141261Sdelphij break; 209141261Sdelphij case 'i': 210167964Sdelphij iflag = strtonum(optarg, 0, UINT_MAX, &errstr); 211167964Sdelphij if (errstr) 212167964Sdelphij errx(1, "interval %s: %s", errstr, optarg); 213141261Sdelphij break; 214141261Sdelphij case 'k': 215141261Sdelphij kflag = 1; 216141261Sdelphij break; 217141261Sdelphij case 'l': 218141261Sdelphij lflag = 1; 219141261Sdelphij break; 220249499Sdelphij case 'N': 221249499Sdelphij Nflag = 1; 222249499Sdelphij break; 223141261Sdelphij case 'n': 224141261Sdelphij nflag = 1; 225141261Sdelphij break; 226141394Sdelphij case 'o': 227206675Sdelphij fprintf(stderr, "option -o is deprecated.\n"); 228141394Sdelphij break; 229158798Sdelphij case 'P': 230158798Sdelphij Pflag = optarg; 231158798Sdelphij break; 232141261Sdelphij case 'p': 233141261Sdelphij pflag = optarg; 234141261Sdelphij break; 235141261Sdelphij case 'r': 236141261Sdelphij rflag = 1; 237141261Sdelphij break; 238141261Sdelphij case 's': 239141261Sdelphij sflag = optarg; 240141261Sdelphij break; 241141261Sdelphij case 't': 242141261Sdelphij tflag = 1; 243141261Sdelphij break; 244141261Sdelphij case 'u': 245141261Sdelphij uflag = 1; 246141261Sdelphij break; 247202640Sdelphij case 'V': 248202640Sdelphij if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 249202640Sdelphij errx(1, "Multiple FIBS not supported"); 250264911Sdelphij rtableid = (int)strtonum(optarg, 0, 251202640Sdelphij numfibs - 1, &errstr); 252202640Sdelphij if (errstr) 253214047Sdelphij errx(1, "rtable %s: %s", errstr, optarg); 254202640Sdelphij break; 255141261Sdelphij case 'v': 256141261Sdelphij vflag = 1; 257141261Sdelphij break; 258141261Sdelphij case 'w': 259167964Sdelphij timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); 260167964Sdelphij if (errstr) 261167964Sdelphij errx(1, "timeout %s: %s", errstr, optarg); 262141261Sdelphij timeout *= 1000; 263141261Sdelphij break; 264141261Sdelphij case 'x': 265141261Sdelphij xflag = 1; 266141261Sdelphij if ((proxy = strdup(optarg)) == NULL) 267141261Sdelphij err(1, NULL); 268141261Sdelphij break; 269141261Sdelphij case 'z': 270141261Sdelphij zflag = 1; 271141261Sdelphij break; 272141261Sdelphij case 'D': 273141261Sdelphij Dflag = 1; 274141261Sdelphij break; 275186343Sdelphij case 'I': 276186343Sdelphij Iflag = strtonum(optarg, 1, 65536 << 14, &errstr); 277186343Sdelphij if (errstr != NULL) 278186343Sdelphij errx(1, "TCP receive window %s: %s", 279186343Sdelphij errstr, optarg); 280186343Sdelphij break; 281186343Sdelphij case 'O': 282186343Sdelphij Oflag = strtonum(optarg, 1, 65536 << 14, &errstr); 283186343Sdelphij if (errstr != NULL) { 284186343Sdelphij if (strcmp(errstr, "invalid") != 0) 285186343Sdelphij errx(1, "TCP send window %s: %s", 286186343Sdelphij errstr, optarg); 287186343Sdelphij } 288186343Sdelphij break; 289141261Sdelphij case 'S': 290141261Sdelphij Sflag = 1; 291141261Sdelphij break; 292158798Sdelphij case 'T': 293235037Sdelphij errstr = NULL; 294235037Sdelphij errno = 0; 295235037Sdelphij if (map_tos(optarg, &Tflag)) 296235037Sdelphij break; 297235037Sdelphij if (strlen(optarg) > 1 && optarg[0] == '0' && 298235037Sdelphij optarg[1] == 'x') 299235037Sdelphij Tflag = (int)strtol(optarg, NULL, 16); 300235037Sdelphij else 301235037Sdelphij Tflag = (int)strtonum(optarg, 0, 255, 302235037Sdelphij &errstr); 303235037Sdelphij if (Tflag < 0 || Tflag > 255 || errstr || errno) 304235037Sdelphij errx(1, "illegal tos value %s", optarg); 305158798Sdelphij break; 306141261Sdelphij default: 307141261Sdelphij usage(1); 308141261Sdelphij } 309141261Sdelphij } 310141261Sdelphij argc -= optind; 311141261Sdelphij argv += optind; 312141261Sdelphij 313141261Sdelphij /* Cruft to make sure options are clean, and used properly. */ 314141261Sdelphij if (argv[0] && !argv[1] && family == AF_UNIX) { 315141261Sdelphij host = argv[0]; 316141261Sdelphij uport = NULL; 317141261Sdelphij } else if (argv[0] && !argv[1]) { 318141261Sdelphij if (!lflag) 319141261Sdelphij usage(1); 320141261Sdelphij uport = argv[0]; 321141261Sdelphij host = NULL; 322141261Sdelphij } else if (argv[0] && argv[1]) { 323141261Sdelphij host = argv[0]; 324141261Sdelphij uport = argv[1]; 325141261Sdelphij } else 326141261Sdelphij usage(1); 327141261Sdelphij 328141261Sdelphij if (lflag && sflag) 329141261Sdelphij errx(1, "cannot use -s and -l"); 330141261Sdelphij if (lflag && pflag) 331141261Sdelphij errx(1, "cannot use -p and -l"); 332141261Sdelphij if (lflag && zflag) 333141261Sdelphij errx(1, "cannot use -z and -l"); 334141261Sdelphij if (!lflag && kflag) 335141261Sdelphij errx(1, "must use -l with -k"); 336141261Sdelphij 337221793Sdelphij /* Get name of temporary socket for unix datagram client */ 338221793Sdelphij if ((family == AF_UNIX) && uflag && !lflag) { 339221793Sdelphij if (sflag) { 340221793Sdelphij unix_dg_tmp_socket = sflag; 341221793Sdelphij } else { 342221793Sdelphij strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", 343221793Sdelphij UNIX_DG_TMP_SOCKET_SIZE); 344221793Sdelphij if (mktemp(unix_dg_tmp_socket_buf) == NULL) 345221793Sdelphij err(1, "mktemp"); 346221793Sdelphij unix_dg_tmp_socket = unix_dg_tmp_socket_buf; 347221793Sdelphij } 348221793Sdelphij } 349221793Sdelphij 350141261Sdelphij /* Initialize addrinfo structure. */ 351141261Sdelphij if (family != AF_UNIX) { 352141261Sdelphij memset(&hints, 0, sizeof(struct addrinfo)); 353141261Sdelphij hints.ai_family = family; 354141261Sdelphij hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 355141261Sdelphij hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 356141261Sdelphij if (nflag) 357141261Sdelphij hints.ai_flags |= AI_NUMERICHOST; 358141261Sdelphij } 359141261Sdelphij 360141261Sdelphij if (xflag) { 361141261Sdelphij if (uflag) 362141261Sdelphij errx(1, "no proxy support for UDP mode"); 363141261Sdelphij 364141261Sdelphij if (lflag) 365141261Sdelphij errx(1, "no proxy support for listen"); 366141261Sdelphij 367141261Sdelphij if (family == AF_UNIX) 368141261Sdelphij errx(1, "no proxy support for unix sockets"); 369141261Sdelphij 370141261Sdelphij /* XXX IPv6 transport to proxy would probably work */ 371141261Sdelphij if (family == AF_INET6) 372141261Sdelphij errx(1, "no proxy support for IPv6"); 373141261Sdelphij 374141261Sdelphij if (sflag) 375141261Sdelphij errx(1, "no proxy support for local source address"); 376141261Sdelphij 377141261Sdelphij proxyhost = strsep(&proxy, ":"); 378141261Sdelphij proxyport = proxy; 379141261Sdelphij 380141261Sdelphij memset(&proxyhints, 0, sizeof(struct addrinfo)); 381141261Sdelphij proxyhints.ai_family = family; 382141261Sdelphij proxyhints.ai_socktype = SOCK_STREAM; 383141261Sdelphij proxyhints.ai_protocol = IPPROTO_TCP; 384141261Sdelphij if (nflag) 385141261Sdelphij proxyhints.ai_flags |= AI_NUMERICHOST; 386141261Sdelphij } 387141261Sdelphij 388141261Sdelphij if (lflag) { 389141261Sdelphij int connfd; 390141261Sdelphij ret = 0; 391141261Sdelphij 392221793Sdelphij if (family == AF_UNIX) { 393221793Sdelphij if (uflag) 394221793Sdelphij s = unix_bind(host); 395221793Sdelphij else 396221793Sdelphij s = unix_listen(host); 397221793Sdelphij } 398141261Sdelphij 399141261Sdelphij /* Allow only one connection at a time, but stay alive. */ 400141261Sdelphij for (;;) { 401141261Sdelphij if (family != AF_UNIX) 402141261Sdelphij s = local_listen(host, uport, hints); 403141261Sdelphij if (s < 0) 404141261Sdelphij err(1, NULL); 405141261Sdelphij /* 406241906Sdelphij * For UDP and -k, don't connect the socket, let it 407241906Sdelphij * receive datagrams from multiple socket pairs. 408141261Sdelphij */ 409241906Sdelphij if (uflag && kflag) 410241906Sdelphij readwrite(s); 411241906Sdelphij /* 412241906Sdelphij * For UDP and not -k, we will use recvfrom() initially 413241906Sdelphij * to wait for a caller, then use the regular functions 414241906Sdelphij * to talk to the caller. 415241906Sdelphij */ 416241906Sdelphij else if (uflag && !kflag) { 417158798Sdelphij int rv, plen; 418214047Sdelphij char buf[16384]; 419141261Sdelphij struct sockaddr_storage z; 420141261Sdelphij 421141261Sdelphij len = sizeof(z); 422241906Sdelphij plen = 2048; 423158798Sdelphij rv = recvfrom(s, buf, plen, MSG_PEEK, 424141261Sdelphij (struct sockaddr *)&z, &len); 425141261Sdelphij if (rv < 0) 426141261Sdelphij err(1, "recvfrom"); 427141261Sdelphij 428141261Sdelphij rv = connect(s, (struct sockaddr *)&z, len); 429141261Sdelphij if (rv < 0) 430141261Sdelphij err(1, "connect"); 431141261Sdelphij 432241906Sdelphij if (vflag) 433241906Sdelphij report_connect((struct sockaddr *)&z, len); 434241906Sdelphij 435221793Sdelphij readwrite(s); 436141261Sdelphij } else { 437158798Sdelphij len = sizeof(cliaddr); 438141261Sdelphij connfd = accept(s, (struct sockaddr *)&cliaddr, 439141261Sdelphij &len); 440249499Sdelphij if (connfd == -1) { 441249499Sdelphij /* For now, all errnos are fatal */ 442249499Sdelphij err(1, "accept"); 443249499Sdelphij } 444241906Sdelphij if (vflag) 445241906Sdelphij report_connect((struct sockaddr *)&cliaddr, len); 446241906Sdelphij 447221793Sdelphij readwrite(connfd); 448221793Sdelphij close(connfd); 449141261Sdelphij } 450141261Sdelphij 451141261Sdelphij if (family != AF_UNIX) 452141261Sdelphij close(s); 453221793Sdelphij else if (uflag) { 454221793Sdelphij if (connect(s, NULL, 0) < 0) 455221793Sdelphij err(1, "connect"); 456221793Sdelphij } 457141261Sdelphij 458141261Sdelphij if (!kflag) 459141261Sdelphij break; 460141261Sdelphij } 461141261Sdelphij } else if (family == AF_UNIX) { 462141261Sdelphij ret = 0; 463141261Sdelphij 464141261Sdelphij if ((s = unix_connect(host)) > 0 && !zflag) { 465141261Sdelphij readwrite(s); 466141261Sdelphij close(s); 467141261Sdelphij } else 468141261Sdelphij ret = 1; 469141261Sdelphij 470221793Sdelphij if (uflag) 471221793Sdelphij unlink(unix_dg_tmp_socket); 472141261Sdelphij exit(ret); 473141261Sdelphij 474141261Sdelphij } else { 475141261Sdelphij int i = 0; 476141261Sdelphij 477141261Sdelphij /* Construct the portlist[] array. */ 478141261Sdelphij build_ports(uport); 479141261Sdelphij 480141261Sdelphij /* Cycle through portlist, connecting to each port. */ 481141261Sdelphij for (i = 0; portlist[i] != NULL; i++) { 482141261Sdelphij if (s) 483141261Sdelphij close(s); 484141261Sdelphij 485141261Sdelphij if (xflag) 486141261Sdelphij s = socks_connect(host, portlist[i], hints, 487158798Sdelphij proxyhost, proxyport, proxyhints, socksv, 488158798Sdelphij Pflag); 489141261Sdelphij else 490141261Sdelphij s = remote_connect(host, portlist[i], hints); 491141261Sdelphij 492141261Sdelphij if (s < 0) 493141261Sdelphij continue; 494141261Sdelphij 495141261Sdelphij ret = 0; 496141261Sdelphij if (vflag || zflag) { 497141261Sdelphij /* For UDP, make sure we are connected. */ 498141261Sdelphij if (uflag) { 499141261Sdelphij if (udptest(s) == -1) { 500141261Sdelphij ret = 1; 501141261Sdelphij continue; 502141261Sdelphij } 503141261Sdelphij } 504141261Sdelphij 505141261Sdelphij /* Don't look up port if -n. */ 506141261Sdelphij if (nflag) 507141261Sdelphij sv = NULL; 508141261Sdelphij else { 509141261Sdelphij sv = getservbyport( 510141261Sdelphij ntohs(atoi(portlist[i])), 511141261Sdelphij uflag ? "udp" : "tcp"); 512141261Sdelphij } 513141261Sdelphij 514205561Sdelphij fprintf(stderr, 515205561Sdelphij "Connection to %s %s port [%s/%s] " 516205561Sdelphij "succeeded!\n", host, portlist[i], 517205561Sdelphij uflag ? "udp" : "tcp", 518141261Sdelphij sv ? sv->s_name : "*"); 519141261Sdelphij } 520264911Sdelphij if (Fflag) 521264911Sdelphij fdpass(s); 522264911Sdelphij else if (!zflag) 523141261Sdelphij readwrite(s); 524141261Sdelphij } 525141261Sdelphij } 526141261Sdelphij 527141261Sdelphij if (s) 528141261Sdelphij close(s); 529141261Sdelphij 530141261Sdelphij exit(ret); 531141261Sdelphij} 532141261Sdelphij 533141261Sdelphij/* 534221793Sdelphij * unix_bind() 535221793Sdelphij * Returns a unix socket bound to the given path 536141261Sdelphij */ 537141261Sdelphijint 538221793Sdelphijunix_bind(char *path) 539141261Sdelphij{ 540141261Sdelphij struct sockaddr_un sun; 541141261Sdelphij int s; 542141261Sdelphij 543221793Sdelphij /* Create unix domain socket. */ 544221793Sdelphij if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, 545221793Sdelphij 0)) < 0) 546141261Sdelphij return (-1); 547141261Sdelphij 548141261Sdelphij memset(&sun, 0, sizeof(struct sockaddr_un)); 549141261Sdelphij sun.sun_family = AF_UNIX; 550141261Sdelphij 551141261Sdelphij if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 552141261Sdelphij sizeof(sun.sun_path)) { 553141261Sdelphij close(s); 554141261Sdelphij errno = ENAMETOOLONG; 555141261Sdelphij return (-1); 556141261Sdelphij } 557221793Sdelphij 558221793Sdelphij if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { 559141261Sdelphij close(s); 560141261Sdelphij return (-1); 561141261Sdelphij } 562141261Sdelphij return (s); 563141261Sdelphij} 564141261Sdelphij 565141261Sdelphij/* 566221793Sdelphij * unix_connect() 567221793Sdelphij * Returns a socket connected to a local unix socket. Returns -1 on failure. 568141261Sdelphij */ 569141261Sdelphijint 570221793Sdelphijunix_connect(char *path) 571141261Sdelphij{ 572141261Sdelphij struct sockaddr_un sun; 573141261Sdelphij int s; 574141261Sdelphij 575221793Sdelphij if (uflag) { 576221793Sdelphij if ((s = unix_bind(unix_dg_tmp_socket)) < 0) 577221793Sdelphij return (-1); 578221793Sdelphij } else { 579221793Sdelphij if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 580221793Sdelphij return (-1); 581221793Sdelphij } 582264911Sdelphij (void)fcntl(s, F_SETFD, FD_CLOEXEC); 583141261Sdelphij 584141261Sdelphij memset(&sun, 0, sizeof(struct sockaddr_un)); 585141261Sdelphij sun.sun_family = AF_UNIX; 586141261Sdelphij 587141261Sdelphij if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 588141261Sdelphij sizeof(sun.sun_path)) { 589141261Sdelphij close(s); 590141261Sdelphij errno = ENAMETOOLONG; 591141261Sdelphij return (-1); 592141261Sdelphij } 593221793Sdelphij if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { 594141261Sdelphij close(s); 595141261Sdelphij return (-1); 596141261Sdelphij } 597221793Sdelphij return (s); 598141261Sdelphij 599221793Sdelphij} 600221793Sdelphij 601221793Sdelphij/* 602221793Sdelphij * unix_listen() 603221793Sdelphij * Create a unix domain socket, and listen on it. 604221793Sdelphij */ 605221793Sdelphijint 606221793Sdelphijunix_listen(char *path) 607221793Sdelphij{ 608221793Sdelphij int s; 609221793Sdelphij if ((s = unix_bind(path)) < 0) 610221793Sdelphij return (-1); 611221793Sdelphij 612141261Sdelphij if (listen(s, 5) < 0) { 613141261Sdelphij close(s); 614141261Sdelphij return (-1); 615141261Sdelphij } 616141261Sdelphij return (s); 617141261Sdelphij} 618141261Sdelphij 619141261Sdelphij/* 620141261Sdelphij * remote_connect() 621141261Sdelphij * Returns a socket connected to a remote host. Properly binds to a local 622141261Sdelphij * port or source address if needed. Returns -1 on failure. 623141261Sdelphij */ 624141261Sdelphijint 625158798Sdelphijremote_connect(const char *host, const char *port, struct addrinfo hints) 626141261Sdelphij{ 627141261Sdelphij struct addrinfo *res, *res0; 628186343Sdelphij int s, error, on = 1; 629141261Sdelphij 630141261Sdelphij if ((error = getaddrinfo(host, port, &hints, &res))) 631141261Sdelphij errx(1, "getaddrinfo: %s", gai_strerror(error)); 632141261Sdelphij 633141261Sdelphij res0 = res; 634141261Sdelphij do { 635141261Sdelphij if ((s = socket(res0->ai_family, res0->ai_socktype, 636141261Sdelphij res0->ai_protocol)) < 0) 637141261Sdelphij continue; 638141394Sdelphij#ifdef IPSEC 639141394Sdelphij if (ipsec_policy[0] != NULL) 640141394Sdelphij add_ipsec_policy(s, ipsec_policy[0]); 641141394Sdelphij if (ipsec_policy[1] != NULL) 642141394Sdelphij add_ipsec_policy(s, ipsec_policy[1]); 643141394Sdelphij#endif 644141261Sdelphij 645264911Sdelphij if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB, 646264911Sdelphij &rtableid, sizeof(rtableid)) == -1)) 647264911Sdelphij err(1, "setsockopt SO_SETFIB"); 648202640Sdelphij 649141261Sdelphij /* Bind to a local port or source address if specified. */ 650141261Sdelphij if (sflag || pflag) { 651141261Sdelphij struct addrinfo ahints, *ares; 652141261Sdelphij 653206689Sdelphij /* try IP_BINDANY, but don't insist */ 654206689Sdelphij setsockopt(s, IPPROTO_IP, IP_BINDANY, &on, sizeof(on)); 655141261Sdelphij memset(&ahints, 0, sizeof(struct addrinfo)); 656141261Sdelphij ahints.ai_family = res0->ai_family; 657141261Sdelphij ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 658141261Sdelphij ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 659141261Sdelphij ahints.ai_flags = AI_PASSIVE; 660141261Sdelphij if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) 661141261Sdelphij errx(1, "getaddrinfo: %s", gai_strerror(error)); 662141261Sdelphij 663141261Sdelphij if (bind(s, (struct sockaddr *)ares->ai_addr, 664141261Sdelphij ares->ai_addrlen) < 0) 665141261Sdelphij errx(1, "bind failed: %s", strerror(errno)); 666141261Sdelphij freeaddrinfo(ares); 667141261Sdelphij } 668141261Sdelphij 669158798Sdelphij set_common_sockopts(s); 670158798Sdelphij 671235037Sdelphij if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 672141261Sdelphij break; 673141261Sdelphij else if (vflag) 674141261Sdelphij warn("connect to %s port %s (%s) failed", host, port, 675141261Sdelphij uflag ? "udp" : "tcp"); 676141261Sdelphij 677141261Sdelphij close(s); 678141261Sdelphij s = -1; 679141261Sdelphij } while ((res0 = res0->ai_next) != NULL); 680141261Sdelphij 681141261Sdelphij freeaddrinfo(res); 682141261Sdelphij 683141261Sdelphij return (s); 684141261Sdelphij} 685141261Sdelphij 686235037Sdelphijint 687235037Sdelphijtimeout_connect(int s, const struct sockaddr *name, socklen_t namelen) 688235037Sdelphij{ 689235037Sdelphij struct pollfd pfd; 690235037Sdelphij socklen_t optlen; 691235037Sdelphij int flags, optval; 692235037Sdelphij int ret; 693235037Sdelphij 694235037Sdelphij if (timeout != -1) { 695235037Sdelphij flags = fcntl(s, F_GETFL, 0); 696235037Sdelphij if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 697235037Sdelphij err(1, "set non-blocking mode"); 698235037Sdelphij } 699235037Sdelphij 700235037Sdelphij if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { 701235037Sdelphij pfd.fd = s; 702235037Sdelphij pfd.events = POLLOUT; 703235037Sdelphij if ((ret = poll(&pfd, 1, timeout)) == 1) { 704235037Sdelphij optlen = sizeof(optval); 705235037Sdelphij if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, 706235037Sdelphij &optval, &optlen)) == 0) { 707235037Sdelphij errno = optval; 708235037Sdelphij ret = optval == 0 ? 0 : -1; 709235037Sdelphij } 710235037Sdelphij } else if (ret == 0) { 711235037Sdelphij errno = ETIMEDOUT; 712235037Sdelphij ret = -1; 713235037Sdelphij } else 714235037Sdelphij err(1, "poll failed"); 715235037Sdelphij } 716235037Sdelphij 717235037Sdelphij if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) 718235037Sdelphij err(1, "restoring flags"); 719235037Sdelphij 720235037Sdelphij return (ret); 721235037Sdelphij} 722235037Sdelphij 723141261Sdelphij/* 724141261Sdelphij * local_listen() 725141261Sdelphij * Returns a socket listening on a local port, binds to specified source 726141261Sdelphij * address. Returns -1 on failure. 727141261Sdelphij */ 728141261Sdelphijint 729141261Sdelphijlocal_listen(char *host, char *port, struct addrinfo hints) 730141261Sdelphij{ 731141261Sdelphij struct addrinfo *res, *res0; 732141261Sdelphij int s, ret, x = 1; 733141261Sdelphij int error; 734141261Sdelphij 735141261Sdelphij /* Allow nodename to be null. */ 736141261Sdelphij hints.ai_flags |= AI_PASSIVE; 737141261Sdelphij 738141261Sdelphij /* 739141261Sdelphij * In the case of binding to a wildcard address 740141261Sdelphij * default to binding to an ipv4 address. 741141261Sdelphij */ 742141261Sdelphij if (host == NULL && hints.ai_family == AF_UNSPEC) 743141261Sdelphij hints.ai_family = AF_INET; 744141261Sdelphij 745141261Sdelphij if ((error = getaddrinfo(host, port, &hints, &res))) 746141261Sdelphij errx(1, "getaddrinfo: %s", gai_strerror(error)); 747141261Sdelphij 748141261Sdelphij res0 = res; 749141261Sdelphij do { 750141261Sdelphij if ((s = socket(res0->ai_family, res0->ai_socktype, 751158798Sdelphij res0->ai_protocol)) < 0) 752141261Sdelphij continue; 753141261Sdelphij 754264911Sdelphij if (rtableid >= 0 && (setsockopt(s, IPPROTO_IP, SO_SETFIB, 755264911Sdelphij &rtableid, sizeof(rtableid)) == -1)) 756264911Sdelphij err(1, "setsockopt SO_SETFIB"); 757202640Sdelphij 758141261Sdelphij ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); 759141261Sdelphij if (ret == -1) 760141261Sdelphij err(1, NULL); 761141394Sdelphij#ifdef IPSEC 762141394Sdelphij if (ipsec_policy[0] != NULL) 763141394Sdelphij add_ipsec_policy(s, ipsec_policy[0]); 764141394Sdelphij if (ipsec_policy[1] != NULL) 765141394Sdelphij add_ipsec_policy(s, ipsec_policy[1]); 766141394Sdelphij#endif 767186343Sdelphij if (FreeBSD_Oflag) { 768177837Sbms if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, 769186343Sdelphij &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1) 770177837Sbms err(1, "disable TCP options"); 771177837Sbms } 772141261Sdelphij 773141261Sdelphij if (bind(s, (struct sockaddr *)res0->ai_addr, 774141261Sdelphij res0->ai_addrlen) == 0) 775141261Sdelphij break; 776141261Sdelphij 777141261Sdelphij close(s); 778141261Sdelphij s = -1; 779141261Sdelphij } while ((res0 = res0->ai_next) != NULL); 780141261Sdelphij 781141261Sdelphij if (!uflag && s != -1) { 782141261Sdelphij if (listen(s, 1) < 0) 783141261Sdelphij err(1, "listen"); 784141261Sdelphij } 785141261Sdelphij 786141261Sdelphij freeaddrinfo(res); 787141261Sdelphij 788141261Sdelphij return (s); 789141261Sdelphij} 790141261Sdelphij 791141261Sdelphij/* 792141261Sdelphij * readwrite() 793141261Sdelphij * Loop that polls on the network file descriptor and stdin. 794141261Sdelphij */ 795141261Sdelphijvoid 796141261Sdelphijreadwrite(int nfd) 797141261Sdelphij{ 798141261Sdelphij struct pollfd pfd[2]; 799214047Sdelphij unsigned char buf[16384]; 800158798Sdelphij int n, wfd = fileno(stdin); 801141261Sdelphij int lfd = fileno(stdout); 802158798Sdelphij int plen; 803141261Sdelphij 804241906Sdelphij plen = 2048; 805158798Sdelphij 806141261Sdelphij /* Setup Network FD */ 807141261Sdelphij pfd[0].fd = nfd; 808141261Sdelphij pfd[0].events = POLLIN; 809141261Sdelphij 810141261Sdelphij /* Set up STDIN FD. */ 811141261Sdelphij pfd[1].fd = wfd; 812141261Sdelphij pfd[1].events = POLLIN; 813141261Sdelphij 814141261Sdelphij while (pfd[0].fd != -1) { 815141261Sdelphij if (iflag) 816141261Sdelphij sleep(iflag); 817141261Sdelphij 818141261Sdelphij if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { 819141261Sdelphij close(nfd); 820141261Sdelphij err(1, "Polling Error"); 821141261Sdelphij } 822141261Sdelphij 823141261Sdelphij if (n == 0) 824141261Sdelphij return; 825141261Sdelphij 826141261Sdelphij if (pfd[0].revents & POLLIN) { 827158798Sdelphij if ((n = read(nfd, buf, plen)) < 0) 828141261Sdelphij return; 829141261Sdelphij else if (n == 0) { 830141261Sdelphij shutdown(nfd, SHUT_RD); 831141261Sdelphij pfd[0].fd = -1; 832141261Sdelphij pfd[0].events = 0; 833141261Sdelphij } else { 834141261Sdelphij if (tflag) 835141261Sdelphij atelnet(nfd, buf, n); 836158798Sdelphij if (atomicio(vwrite, lfd, buf, n) != n) 837141261Sdelphij return; 838141261Sdelphij } 839141261Sdelphij } 840141261Sdelphij 841141261Sdelphij if (!dflag && pfd[1].revents & POLLIN) { 842206675Sdelphij if ((n = read(wfd, buf, plen)) < 0) 843141261Sdelphij return; 844206675Sdelphij else if (n == 0) { 845249499Sdelphij if (Nflag) 846249499Sdelphij shutdown(nfd, SHUT_WR); 847141261Sdelphij pfd[1].fd = -1; 848141261Sdelphij pfd[1].events = 0; 849141261Sdelphij } else { 850158798Sdelphij if (atomicio(vwrite, nfd, buf, n) != n) 851141261Sdelphij return; 852141261Sdelphij } 853141261Sdelphij } 854141261Sdelphij } 855141261Sdelphij} 856141261Sdelphij 857264911Sdelphij/* 858264911Sdelphij * fdpass() 859264911Sdelphij * Pass the connected file descriptor to stdout and exit. 860264911Sdelphij */ 861264911Sdelphijvoid 862264911Sdelphijfdpass(int nfd) 863264911Sdelphij{ 864264911Sdelphij struct msghdr mh; 865264911Sdelphij union { 866264911Sdelphij struct cmsghdr hdr; 867264911Sdelphij char buf[CMSG_SPACE(sizeof(int))]; 868264911Sdelphij } cmsgbuf; 869264911Sdelphij struct cmsghdr *cmsg; 870264911Sdelphij struct iovec iov; 871264911Sdelphij char c = '\0'; 872264911Sdelphij ssize_t r; 873264911Sdelphij struct pollfd pfd; 874264911Sdelphij 875264911Sdelphij /* Avoid obvious stupidity */ 876264911Sdelphij if (isatty(STDOUT_FILENO)) 877264911Sdelphij errx(1, "Cannot pass file descriptor to tty"); 878264911Sdelphij 879264911Sdelphij bzero(&mh, sizeof(mh)); 880264911Sdelphij bzero(&cmsgbuf, sizeof(cmsgbuf)); 881264911Sdelphij bzero(&iov, sizeof(iov)); 882264911Sdelphij bzero(&pfd, sizeof(pfd)); 883264911Sdelphij 884264911Sdelphij mh.msg_control = (caddr_t)&cmsgbuf.buf; 885264911Sdelphij mh.msg_controllen = sizeof(cmsgbuf.buf); 886264911Sdelphij cmsg = CMSG_FIRSTHDR(&mh); 887264911Sdelphij cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 888264911Sdelphij cmsg->cmsg_level = SOL_SOCKET; 889264911Sdelphij cmsg->cmsg_type = SCM_RIGHTS; 890264911Sdelphij *(int *)CMSG_DATA(cmsg) = nfd; 891264911Sdelphij 892264911Sdelphij iov.iov_base = &c; 893264911Sdelphij iov.iov_len = 1; 894264911Sdelphij mh.msg_iov = &iov; 895264911Sdelphij mh.msg_iovlen = 1; 896264911Sdelphij 897264911Sdelphij bzero(&pfd, sizeof(pfd)); 898264911Sdelphij pfd.fd = STDOUT_FILENO; 899264911Sdelphij for (;;) { 900264911Sdelphij r = sendmsg(STDOUT_FILENO, &mh, 0); 901264911Sdelphij if (r == -1) { 902264911Sdelphij if (errno == EAGAIN || errno == EINTR) { 903264911Sdelphij pfd.events = POLLOUT; 904264911Sdelphij if (poll(&pfd, 1, -1) == -1) 905264911Sdelphij err(1, "poll"); 906264911Sdelphij continue; 907264911Sdelphij } 908264911Sdelphij err(1, "sendmsg"); 909264911Sdelphij } else if (r == -1) 910264911Sdelphij errx(1, "sendmsg: unexpected return value %zd", r); 911264911Sdelphij else 912264911Sdelphij break; 913264911Sdelphij } 914264911Sdelphij exit(0); 915264911Sdelphij} 916264911Sdelphij 917141261Sdelphij/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ 918141261Sdelphijvoid 919141261Sdelphijatelnet(int nfd, unsigned char *buf, unsigned int size) 920141261Sdelphij{ 921141261Sdelphij unsigned char *p, *end; 922141261Sdelphij unsigned char obuf[4]; 923141261Sdelphij 924205561Sdelphij if (size < 3) 925205561Sdelphij return; 926205561Sdelphij end = buf + size - 2; 927141261Sdelphij 928141261Sdelphij for (p = buf; p < end; p++) { 929141261Sdelphij if (*p != IAC) 930205561Sdelphij continue; 931141261Sdelphij 932141261Sdelphij obuf[0] = IAC; 933141261Sdelphij p++; 934141261Sdelphij if ((*p == WILL) || (*p == WONT)) 935141261Sdelphij obuf[1] = DONT; 936205561Sdelphij else if ((*p == DO) || (*p == DONT)) 937141261Sdelphij obuf[1] = WONT; 938205561Sdelphij else 939205561Sdelphij continue; 940205561Sdelphij 941205561Sdelphij p++; 942205561Sdelphij obuf[2] = *p; 943205561Sdelphij if (atomicio(vwrite, nfd, obuf, 3) != 3) 944205561Sdelphij warn("Write Error!"); 945141261Sdelphij } 946141261Sdelphij} 947141261Sdelphij 948141261Sdelphij/* 949141261Sdelphij * build_ports() 950235037Sdelphij * Build an array of ports in portlist[], listing each port 951141261Sdelphij * that we should try to connect to. 952141261Sdelphij */ 953141261Sdelphijvoid 954141261Sdelphijbuild_ports(char *p) 955141261Sdelphij{ 956167964Sdelphij const char *errstr; 957167964Sdelphij char *n; 958141261Sdelphij int hi, lo, cp; 959141261Sdelphij int x = 0; 960141261Sdelphij 961141261Sdelphij if ((n = strchr(p, '-')) != NULL) { 962141261Sdelphij *n = '\0'; 963141261Sdelphij n++; 964141261Sdelphij 965141261Sdelphij /* Make sure the ports are in order: lowest->highest. */ 966167964Sdelphij hi = strtonum(n, 1, PORT_MAX, &errstr); 967167964Sdelphij if (errstr) 968167964Sdelphij errx(1, "port number %s: %s", errstr, n); 969167964Sdelphij lo = strtonum(p, 1, PORT_MAX, &errstr); 970167964Sdelphij if (errstr) 971167964Sdelphij errx(1, "port number %s: %s", errstr, p); 972141261Sdelphij 973141261Sdelphij if (lo > hi) { 974141261Sdelphij cp = hi; 975141261Sdelphij hi = lo; 976141261Sdelphij lo = cp; 977141261Sdelphij } 978141261Sdelphij 979141261Sdelphij /* Load ports sequentially. */ 980141261Sdelphij for (cp = lo; cp <= hi; cp++) { 981141261Sdelphij portlist[x] = calloc(1, PORT_MAX_LEN); 982141261Sdelphij if (portlist[x] == NULL) 983141261Sdelphij err(1, NULL); 984141261Sdelphij snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); 985141261Sdelphij x++; 986141261Sdelphij } 987141261Sdelphij 988141261Sdelphij /* Randomly swap ports. */ 989141261Sdelphij if (rflag) { 990141261Sdelphij int y; 991141261Sdelphij char *c; 992141261Sdelphij 993141261Sdelphij for (x = 0; x <= (hi - lo); x++) { 994141261Sdelphij y = (arc4random() & 0xFFFF) % (hi - lo); 995141261Sdelphij c = portlist[x]; 996141261Sdelphij portlist[x] = portlist[y]; 997141261Sdelphij portlist[y] = c; 998141261Sdelphij } 999141261Sdelphij } 1000141261Sdelphij } else { 1001167964Sdelphij hi = strtonum(p, 1, PORT_MAX, &errstr); 1002167964Sdelphij if (errstr) 1003167964Sdelphij errx(1, "port number %s: %s", errstr, p); 1004214047Sdelphij portlist[0] = strdup(p); 1005141261Sdelphij if (portlist[0] == NULL) 1006141261Sdelphij err(1, NULL); 1007141261Sdelphij } 1008141261Sdelphij} 1009141261Sdelphij 1010141261Sdelphij/* 1011141261Sdelphij * udptest() 1012141261Sdelphij * Do a few writes to see if the UDP port is there. 1013235037Sdelphij * Fails once PF state table is full. 1014141261Sdelphij */ 1015141261Sdelphijint 1016141261Sdelphijudptest(int s) 1017141261Sdelphij{ 1018141261Sdelphij int i, ret; 1019141261Sdelphij 1020141261Sdelphij for (i = 0; i <= 3; i++) { 1021141261Sdelphij if (write(s, "X", 1) == 1) 1022141261Sdelphij ret = 1; 1023141261Sdelphij else 1024141261Sdelphij ret = -1; 1025141261Sdelphij } 1026141261Sdelphij return (ret); 1027141261Sdelphij} 1028141261Sdelphij 1029141261Sdelphijvoid 1030158798Sdelphijset_common_sockopts(int s) 1031158798Sdelphij{ 1032158798Sdelphij int x = 1; 1033158798Sdelphij 1034158798Sdelphij if (Sflag) { 1035158798Sdelphij if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, 1036158798Sdelphij &x, sizeof(x)) == -1) 1037158798Sdelphij err(1, NULL); 1038158798Sdelphij } 1039158798Sdelphij if (Dflag) { 1040158798Sdelphij if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 1041158798Sdelphij &x, sizeof(x)) == -1) 1042158798Sdelphij err(1, NULL); 1043158798Sdelphij } 1044158798Sdelphij if (Tflag != -1) { 1045158798Sdelphij if (setsockopt(s, IPPROTO_IP, IP_TOS, 1046158798Sdelphij &Tflag, sizeof(Tflag)) == -1) 1047158798Sdelphij err(1, "set IP ToS"); 1048158798Sdelphij } 1049186343Sdelphij if (Iflag) { 1050186343Sdelphij if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 1051186343Sdelphij &Iflag, sizeof(Iflag)) == -1) 1052186343Sdelphij err(1, "set TCP receive buffer size"); 1053186343Sdelphij } 1054177837Sbms if (Oflag) { 1055186343Sdelphij if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 1056186343Sdelphij &Oflag, sizeof(Oflag)) == -1) 1057186343Sdelphij err(1, "set TCP send buffer size"); 1058186343Sdelphij } 1059186343Sdelphij if (FreeBSD_Oflag) { 1060177837Sbms if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, 1061186343Sdelphij &FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1) 1062177837Sbms err(1, "disable TCP options"); 1063177837Sbms } 1064158798Sdelphij} 1065158798Sdelphij 1066158798Sdelphijint 1067235037Sdelphijmap_tos(char *s, int *val) 1068158798Sdelphij{ 1069235037Sdelphij /* DiffServ Codepoints and other TOS mappings */ 1070235037Sdelphij const struct toskeywords { 1071235037Sdelphij const char *keyword; 1072235037Sdelphij int val; 1073235037Sdelphij } *t, toskeywords[] = { 1074235037Sdelphij { "af11", IPTOS_DSCP_AF11 }, 1075235037Sdelphij { "af12", IPTOS_DSCP_AF12 }, 1076235037Sdelphij { "af13", IPTOS_DSCP_AF13 }, 1077235037Sdelphij { "af21", IPTOS_DSCP_AF21 }, 1078235037Sdelphij { "af22", IPTOS_DSCP_AF22 }, 1079235037Sdelphij { "af23", IPTOS_DSCP_AF23 }, 1080235037Sdelphij { "af31", IPTOS_DSCP_AF31 }, 1081235037Sdelphij { "af32", IPTOS_DSCP_AF32 }, 1082235037Sdelphij { "af33", IPTOS_DSCP_AF33 }, 1083235037Sdelphij { "af41", IPTOS_DSCP_AF41 }, 1084235037Sdelphij { "af42", IPTOS_DSCP_AF42 }, 1085235037Sdelphij { "af43", IPTOS_DSCP_AF43 }, 1086235037Sdelphij { "critical", IPTOS_PREC_CRITIC_ECP }, 1087235037Sdelphij { "cs0", IPTOS_DSCP_CS0 }, 1088235037Sdelphij { "cs1", IPTOS_DSCP_CS1 }, 1089235037Sdelphij { "cs2", IPTOS_DSCP_CS2 }, 1090235037Sdelphij { "cs3", IPTOS_DSCP_CS3 }, 1091235037Sdelphij { "cs4", IPTOS_DSCP_CS4 }, 1092235037Sdelphij { "cs5", IPTOS_DSCP_CS5 }, 1093235037Sdelphij { "cs6", IPTOS_DSCP_CS6 }, 1094235037Sdelphij { "cs7", IPTOS_DSCP_CS7 }, 1095235037Sdelphij { "ef", IPTOS_DSCP_EF }, 1096235037Sdelphij { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 1097235037Sdelphij { "lowdelay", IPTOS_LOWDELAY }, 1098235037Sdelphij { "netcontrol", IPTOS_PREC_NETCONTROL }, 1099235037Sdelphij { "reliability", IPTOS_RELIABILITY }, 1100235037Sdelphij { "throughput", IPTOS_THROUGHPUT }, 1101235037Sdelphij { NULL, -1 }, 1102235037Sdelphij }; 1103158798Sdelphij 1104235037Sdelphij for (t = toskeywords; t->keyword != NULL; t++) { 1105235037Sdelphij if (strcmp(s, t->keyword) == 0) { 1106235037Sdelphij *val = t->val; 1107235037Sdelphij return (1); 1108235037Sdelphij } 1109235037Sdelphij } 1110158798Sdelphij 1111235037Sdelphij return (0); 1112158798Sdelphij} 1113158798Sdelphij 1114158798Sdelphijvoid 1115241906Sdelphijreport_connect(const struct sockaddr *sa, socklen_t salen) 1116241906Sdelphij{ 1117241906Sdelphij char remote_host[NI_MAXHOST]; 1118241906Sdelphij char remote_port[NI_MAXSERV]; 1119241906Sdelphij int herr; 1120241906Sdelphij int flags = NI_NUMERICSERV; 1121241906Sdelphij 1122241906Sdelphij if (nflag) 1123241906Sdelphij flags |= NI_NUMERICHOST; 1124241906Sdelphij 1125241906Sdelphij if ((herr = getnameinfo(sa, salen, 1126241906Sdelphij remote_host, sizeof(remote_host), 1127241906Sdelphij remote_port, sizeof(remote_port), 1128241906Sdelphij flags)) != 0) { 1129241906Sdelphij if (herr == EAI_SYSTEM) 1130241906Sdelphij err(1, "getnameinfo"); 1131241906Sdelphij else 1132241906Sdelphij errx(1, "getnameinfo: %s", gai_strerror(herr)); 1133241906Sdelphij } 1134241906Sdelphij 1135241906Sdelphij fprintf(stderr, 1136241906Sdelphij "Connection from %s %s " 1137241906Sdelphij "received!\n", remote_host, remote_port); 1138241906Sdelphij} 1139241906Sdelphij 1140241906Sdelphijvoid 1141141261Sdelphijhelp(void) 1142141261Sdelphij{ 1143141261Sdelphij usage(0); 1144141261Sdelphij fprintf(stderr, "\tCommand Summary:\n\ 1145141261Sdelphij \t-4 Use IPv4\n\ 1146178927Santoine \t-6 Use IPv6\n\ 1147178927Santoine \t-D Enable the debug socket option\n\ 1148178927Santoine \t-d Detach from stdin\n"); 1149141394Sdelphij#ifdef IPSEC 1150141394Sdelphij fprintf(stderr, "\ 1151178927Santoine \t-E Use IPsec ESP\n\ 1152178927Santoine \t-e policy Use specified IPsec policy\n"); 1153141394Sdelphij#endif 1154141394Sdelphij fprintf(stderr, "\ 1155264911Sdelphij \t-F Pass socket fd\n\ 1156141261Sdelphij \t-h This help text\n\ 1157186343Sdelphij \t-I length TCP receive buffer length\n\ 1158141261Sdelphij \t-i secs\t Delay interval for lines sent, ports scanned\n\ 1159141261Sdelphij \t-k Keep inbound sockets open for multiple connects\n\ 1160141261Sdelphij \t-l Listen mode, for inbound connects\n\ 1161249499Sdelphij \t-N Shutdown the network socket after EOF on stdin\n\ 1162141261Sdelphij \t-n Suppress name/port resolutions\n\ 1163186343Sdelphij \t--no-tcpopt Disable TCP options\n\ 1164186343Sdelphij \t-O length TCP send buffer length\n\ 1165158798Sdelphij \t-P proxyuser\tUsername for proxy authentication\n\ 1166141261Sdelphij \t-p port\t Specify local port for remote connects\n\ 1167141261Sdelphij \t-r Randomize remote ports\n\ 1168141261Sdelphij \t-S Enable the TCP MD5 signature option\n\ 1169141261Sdelphij \t-s addr\t Local source address\n\ 1170235037Sdelphij \t-T toskeyword\tSet IP Type of Service\n\ 1171141261Sdelphij \t-t Answer TELNET negotiation\n\ 1172141261Sdelphij \t-U Use UNIX domain socket\n\ 1173141261Sdelphij \t-u UDP mode\n\ 1174214047Sdelphij \t-V rtable Specify alternate routing table\n\ 1175141261Sdelphij \t-v Verbose\n\ 1176141261Sdelphij \t-w secs\t Timeout for connects and final net reads\n\ 1177141261Sdelphij \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ 1178141261Sdelphij \t-x addr[:port]\tSpecify proxy address and port\n\ 1179141261Sdelphij \t-z Zero-I/O mode [used for scanning]\n\ 1180141261Sdelphij Port numbers can be individual or ranges: lo-hi [inclusive]\n"); 1181141394Sdelphij#ifdef IPSEC 1182141394Sdelphij fprintf(stderr, "See ipsec_set_policy(3) for -e argument format\n"); 1183141394Sdelphij#endif 1184141261Sdelphij exit(1); 1185141261Sdelphij} 1186141261Sdelphij 1187141394Sdelphij#ifdef IPSEC 1188141261Sdelphijvoid 1189141394Sdelphijadd_ipsec_policy(int s, char *policy) 1190141394Sdelphij{ 1191141394Sdelphij char *raw; 1192141394Sdelphij int e; 1193141394Sdelphij 1194141394Sdelphij raw = ipsec_set_policy(policy, strlen(policy)); 1195141394Sdelphij if (raw == NULL) 1196141394Sdelphij errx(1, "ipsec_set_policy `%s': %s", policy, 1197141394Sdelphij ipsec_strerror()); 1198141394Sdelphij e = setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, raw, 1199141394Sdelphij ipsec_get_policylen(raw)); 1200141394Sdelphij if (e < 0) 1201141394Sdelphij err(1, "ipsec policy cannot be configured"); 1202141394Sdelphij free(raw); 1203141394Sdelphij if (vflag) 1204141394Sdelphij fprintf(stderr, "ipsec policy configured: `%s'\n", policy); 1205141394Sdelphij return; 1206141394Sdelphij} 1207141394Sdelphij#endif /* IPSEC */ 1208141394Sdelphij 1209141394Sdelphijvoid 1210141261Sdelphijusage(int ret) 1211141261Sdelphij{ 1212193008Sdelphij fprintf(stderr, 1213141394Sdelphij#ifdef IPSEC 1214264911Sdelphij "usage: nc [-46DdEFhklNnrStUuvz] [-e policy] [-I length] [-i interval] [-O length]\n" 1215141394Sdelphij#else 1216264911Sdelphij "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" 1217141394Sdelphij#endif 1218221793Sdelphij "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" 1219214047Sdelphij "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" 1220221793Sdelphij "\t [-x proxy_address[:port]] [destination] [port]\n"); 1221141261Sdelphij if (ret) 1222141261Sdelphij exit(1); 1223141261Sdelphij} 1224