1*bc5531deSDag-Erling Smørgrav /* $OpenBSD: netcat.c,v 1.126 2014/10/30 16:08:31 tedu Exp $ */ 2*bc5531deSDag-Erling Smørgrav /* 3*bc5531deSDag-Erling Smørgrav * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 4*bc5531deSDag-Erling Smørgrav * 5*bc5531deSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 6*bc5531deSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 7*bc5531deSDag-Erling Smørgrav * are met: 8*bc5531deSDag-Erling Smørgrav * 9*bc5531deSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 10*bc5531deSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 11*bc5531deSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 12*bc5531deSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 13*bc5531deSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 14*bc5531deSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 15*bc5531deSDag-Erling Smørgrav * derived from this software without specific prior written permission. 16*bc5531deSDag-Erling Smørgrav * 17*bc5531deSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18*bc5531deSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19*bc5531deSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20*bc5531deSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21*bc5531deSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22*bc5531deSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23*bc5531deSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*bc5531deSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25*bc5531deSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26*bc5531deSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*bc5531deSDag-Erling Smørgrav */ 28*bc5531deSDag-Erling Smørgrav 29*bc5531deSDag-Erling Smørgrav /* 30*bc5531deSDag-Erling Smørgrav * Re-written nc(1) for OpenBSD. Original implementation by 31*bc5531deSDag-Erling Smørgrav * *Hobbit* <hobbit@avian.org>. 32*bc5531deSDag-Erling Smørgrav */ 33*bc5531deSDag-Erling Smørgrav 34*bc5531deSDag-Erling Smørgrav #include "includes.h" 35*bc5531deSDag-Erling Smørgrav 36*bc5531deSDag-Erling Smørgrav #include <sys/types.h> 37*bc5531deSDag-Erling Smørgrav #include <sys/socket.h> 38*bc5531deSDag-Erling Smørgrav #include <sys/time.h> 39*bc5531deSDag-Erling Smørgrav #include <sys/uio.h> 40*bc5531deSDag-Erling Smørgrav #include <sys/un.h> 41*bc5531deSDag-Erling Smørgrav 42*bc5531deSDag-Erling Smørgrav #include <netinet/in.h> 43*bc5531deSDag-Erling Smørgrav #include <netinet/tcp.h> 44*bc5531deSDag-Erling Smørgrav #include <netinet/ip.h> 45*bc5531deSDag-Erling Smørgrav #include <arpa/telnet.h> 46*bc5531deSDag-Erling Smørgrav 47*bc5531deSDag-Erling Smørgrav #include <errno.h> 48*bc5531deSDag-Erling Smørgrav #include <netdb.h> 49*bc5531deSDag-Erling Smørgrav #include <stdarg.h> 50*bc5531deSDag-Erling Smørgrav #include <stdio.h> 51*bc5531deSDag-Erling Smørgrav #include <stdlib.h> 52*bc5531deSDag-Erling Smørgrav #include <string.h> 53*bc5531deSDag-Erling Smørgrav #include <unistd.h> 54*bc5531deSDag-Erling Smørgrav #include <fcntl.h> 55*bc5531deSDag-Erling Smørgrav #include <limits.h> 56*bc5531deSDag-Erling Smørgrav #include "atomicio.h" 57*bc5531deSDag-Erling Smørgrav 58*bc5531deSDag-Erling Smørgrav #ifdef HAVE_POLL_H 59*bc5531deSDag-Erling Smørgrav #include <poll.h> 60*bc5531deSDag-Erling Smørgrav #else 61*bc5531deSDag-Erling Smørgrav # ifdef HAVE_SYS_POLL_H 62*bc5531deSDag-Erling Smørgrav # include <sys/poll.h> 63*bc5531deSDag-Erling Smørgrav # endif 64*bc5531deSDag-Erling Smørgrav #endif 65*bc5531deSDag-Erling Smørgrav 66*bc5531deSDag-Erling Smørgrav #ifndef SUN_LEN 67*bc5531deSDag-Erling Smørgrav #define SUN_LEN(su) \ 68*bc5531deSDag-Erling Smørgrav (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 69*bc5531deSDag-Erling Smørgrav #endif 70*bc5531deSDag-Erling Smørgrav 71*bc5531deSDag-Erling Smørgrav #define PORT_MAX 65535 72*bc5531deSDag-Erling Smørgrav #define PORT_MAX_LEN 6 73*bc5531deSDag-Erling Smørgrav #define UNIX_DG_TMP_SOCKET_SIZE 19 74*bc5531deSDag-Erling Smørgrav 75*bc5531deSDag-Erling Smørgrav #define POLL_STDIN 0 76*bc5531deSDag-Erling Smørgrav #define POLL_NETOUT 1 77*bc5531deSDag-Erling Smørgrav #define POLL_NETIN 2 78*bc5531deSDag-Erling Smørgrav #define POLL_STDOUT 3 79*bc5531deSDag-Erling Smørgrav #define BUFSIZE 16384 80*bc5531deSDag-Erling Smørgrav 81*bc5531deSDag-Erling Smørgrav /* Command Line Options */ 82*bc5531deSDag-Erling Smørgrav int dflag; /* detached, no stdin */ 83*bc5531deSDag-Erling Smørgrav int Fflag; /* fdpass sock to stdout */ 84*bc5531deSDag-Erling Smørgrav unsigned int iflag; /* Interval Flag */ 85*bc5531deSDag-Erling Smørgrav int kflag; /* More than one connect */ 86*bc5531deSDag-Erling Smørgrav int lflag; /* Bind to local port */ 87*bc5531deSDag-Erling Smørgrav int Nflag; /* shutdown() network socket */ 88*bc5531deSDag-Erling Smørgrav int nflag; /* Don't do name look up */ 89*bc5531deSDag-Erling Smørgrav char *Pflag; /* Proxy username */ 90*bc5531deSDag-Erling Smørgrav char *pflag; /* Localport flag */ 91*bc5531deSDag-Erling Smørgrav int rflag; /* Random ports flag */ 92*bc5531deSDag-Erling Smørgrav char *sflag; /* Source Address */ 93*bc5531deSDag-Erling Smørgrav int tflag; /* Telnet Emulation */ 94*bc5531deSDag-Erling Smørgrav int uflag; /* UDP - Default to TCP */ 95*bc5531deSDag-Erling Smørgrav int vflag; /* Verbosity */ 96*bc5531deSDag-Erling Smørgrav int xflag; /* Socks proxy */ 97*bc5531deSDag-Erling Smørgrav int zflag; /* Port Scan Flag */ 98*bc5531deSDag-Erling Smørgrav int Dflag; /* sodebug */ 99*bc5531deSDag-Erling Smørgrav int Iflag; /* TCP receive buffer size */ 100*bc5531deSDag-Erling Smørgrav int Oflag; /* TCP send buffer size */ 101*bc5531deSDag-Erling Smørgrav int Sflag; /* TCP MD5 signature option */ 102*bc5531deSDag-Erling Smørgrav int Tflag = -1; /* IP Type of Service */ 103*bc5531deSDag-Erling Smørgrav int rtableid = -1; 104*bc5531deSDag-Erling Smørgrav 105*bc5531deSDag-Erling Smørgrav int timeout = -1; 106*bc5531deSDag-Erling Smørgrav int family = AF_UNSPEC; 107*bc5531deSDag-Erling Smørgrav char *portlist[PORT_MAX+1]; 108*bc5531deSDag-Erling Smørgrav char *unix_dg_tmp_socket; 109*bc5531deSDag-Erling Smørgrav 110*bc5531deSDag-Erling Smørgrav void atelnet(int, unsigned char *, unsigned int); 111*bc5531deSDag-Erling Smørgrav void build_ports(char *); 112*bc5531deSDag-Erling Smørgrav void help(void); 113*bc5531deSDag-Erling Smørgrav int local_listen(char *, char *, struct addrinfo); 114*bc5531deSDag-Erling Smørgrav void readwrite(int); 115*bc5531deSDag-Erling Smørgrav void fdpass(int nfd) __attribute__((noreturn)); 116*bc5531deSDag-Erling Smørgrav int remote_connect(const char *, const char *, struct addrinfo); 117*bc5531deSDag-Erling Smørgrav int timeout_connect(int, const struct sockaddr *, socklen_t); 118*bc5531deSDag-Erling Smørgrav int socks_connect(const char *, const char *, struct addrinfo, 119*bc5531deSDag-Erling Smørgrav const char *, const char *, struct addrinfo, int, const char *); 120*bc5531deSDag-Erling Smørgrav int udptest(int); 121*bc5531deSDag-Erling Smørgrav int unix_bind(char *); 122*bc5531deSDag-Erling Smørgrav int unix_connect(char *); 123*bc5531deSDag-Erling Smørgrav int unix_listen(char *); 124*bc5531deSDag-Erling Smørgrav void set_common_sockopts(int); 125*bc5531deSDag-Erling Smørgrav int map_tos(char *, int *); 126*bc5531deSDag-Erling Smørgrav void report_connect(const struct sockaddr *, socklen_t); 127*bc5531deSDag-Erling Smørgrav void usage(int); 128*bc5531deSDag-Erling Smørgrav ssize_t drainbuf(int, unsigned char *, size_t *); 129*bc5531deSDag-Erling Smørgrav ssize_t fillbuf(int, unsigned char *, size_t *); 130*bc5531deSDag-Erling Smørgrav 131*bc5531deSDag-Erling Smørgrav static void err(int, const char *, ...) __attribute__((format(printf, 2, 3))); 132*bc5531deSDag-Erling Smørgrav static void errx(int, const char *, ...) __attribute__((format(printf, 2, 3))); 133*bc5531deSDag-Erling Smørgrav static void warn(const char *, ...) __attribute__((format(printf, 1, 2))); 134*bc5531deSDag-Erling Smørgrav 135*bc5531deSDag-Erling Smørgrav static void 136*bc5531deSDag-Erling Smørgrav err(int r, const char *fmt, ...) 137*bc5531deSDag-Erling Smørgrav { 138*bc5531deSDag-Erling Smørgrav va_list args; 139*bc5531deSDag-Erling Smørgrav 140*bc5531deSDag-Erling Smørgrav va_start(args, fmt); 141*bc5531deSDag-Erling Smørgrav fprintf(stderr, "%s: ", strerror(errno)); 142*bc5531deSDag-Erling Smørgrav vfprintf(stderr, fmt, args); 143*bc5531deSDag-Erling Smørgrav fputc('\n', stderr); 144*bc5531deSDag-Erling Smørgrav va_end(args); 145*bc5531deSDag-Erling Smørgrav exit(r); 146*bc5531deSDag-Erling Smørgrav } 147*bc5531deSDag-Erling Smørgrav 148*bc5531deSDag-Erling Smørgrav static void 149*bc5531deSDag-Erling Smørgrav errx(int r, const char *fmt, ...) 150*bc5531deSDag-Erling Smørgrav { 151*bc5531deSDag-Erling Smørgrav va_list args; 152*bc5531deSDag-Erling Smørgrav 153*bc5531deSDag-Erling Smørgrav va_start(args, fmt); 154*bc5531deSDag-Erling Smørgrav vfprintf(stderr, fmt, args); 155*bc5531deSDag-Erling Smørgrav fputc('\n', stderr); 156*bc5531deSDag-Erling Smørgrav va_end(args); 157*bc5531deSDag-Erling Smørgrav exit(r); 158*bc5531deSDag-Erling Smørgrav } 159*bc5531deSDag-Erling Smørgrav 160*bc5531deSDag-Erling Smørgrav static void 161*bc5531deSDag-Erling Smørgrav warn(const char *fmt, ...) 162*bc5531deSDag-Erling Smørgrav { 163*bc5531deSDag-Erling Smørgrav va_list args; 164*bc5531deSDag-Erling Smørgrav 165*bc5531deSDag-Erling Smørgrav va_start(args, fmt); 166*bc5531deSDag-Erling Smørgrav fprintf(stderr, "%s: ", strerror(errno)); 167*bc5531deSDag-Erling Smørgrav vfprintf(stderr, fmt, args); 168*bc5531deSDag-Erling Smørgrav fputc('\n', stderr); 169*bc5531deSDag-Erling Smørgrav va_end(args); 170*bc5531deSDag-Erling Smørgrav } 171*bc5531deSDag-Erling Smørgrav 172*bc5531deSDag-Erling Smørgrav int 173*bc5531deSDag-Erling Smørgrav main(int argc, char *argv[]) 174*bc5531deSDag-Erling Smørgrav { 175*bc5531deSDag-Erling Smørgrav int ch, s, ret, socksv; 176*bc5531deSDag-Erling Smørgrav char *host, *uport; 177*bc5531deSDag-Erling Smørgrav struct addrinfo hints; 178*bc5531deSDag-Erling Smørgrav struct servent *sv; 179*bc5531deSDag-Erling Smørgrav socklen_t len; 180*bc5531deSDag-Erling Smørgrav struct sockaddr_storage cliaddr; 181*bc5531deSDag-Erling Smørgrav char *proxy = NULL; 182*bc5531deSDag-Erling Smørgrav const char *errstr, *proxyhost = "", *proxyport = NULL; 183*bc5531deSDag-Erling Smørgrav struct addrinfo proxyhints; 184*bc5531deSDag-Erling Smørgrav char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; 185*bc5531deSDag-Erling Smørgrav 186*bc5531deSDag-Erling Smørgrav ret = 1; 187*bc5531deSDag-Erling Smørgrav s = 0; 188*bc5531deSDag-Erling Smørgrav socksv = 5; 189*bc5531deSDag-Erling Smørgrav host = NULL; 190*bc5531deSDag-Erling Smørgrav uport = NULL; 191*bc5531deSDag-Erling Smørgrav sv = NULL; 192*bc5531deSDag-Erling Smørgrav 193*bc5531deSDag-Erling Smørgrav while ((ch = getopt(argc, argv, 194*bc5531deSDag-Erling Smørgrav "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) { 195*bc5531deSDag-Erling Smørgrav switch (ch) { 196*bc5531deSDag-Erling Smørgrav case '4': 197*bc5531deSDag-Erling Smørgrav family = AF_INET; 198*bc5531deSDag-Erling Smørgrav break; 199*bc5531deSDag-Erling Smørgrav case '6': 200*bc5531deSDag-Erling Smørgrav family = AF_INET6; 201*bc5531deSDag-Erling Smørgrav break; 202*bc5531deSDag-Erling Smørgrav case 'U': 203*bc5531deSDag-Erling Smørgrav family = AF_UNIX; 204*bc5531deSDag-Erling Smørgrav break; 205*bc5531deSDag-Erling Smørgrav case 'X': 206*bc5531deSDag-Erling Smørgrav if (strcasecmp(optarg, "connect") == 0) 207*bc5531deSDag-Erling Smørgrav socksv = -1; /* HTTP proxy CONNECT */ 208*bc5531deSDag-Erling Smørgrav else if (strcmp(optarg, "4") == 0) 209*bc5531deSDag-Erling Smørgrav socksv = 4; /* SOCKS v.4 */ 210*bc5531deSDag-Erling Smørgrav else if (strcmp(optarg, "5") == 0) 211*bc5531deSDag-Erling Smørgrav socksv = 5; /* SOCKS v.5 */ 212*bc5531deSDag-Erling Smørgrav else 213*bc5531deSDag-Erling Smørgrav errx(1, "unsupported proxy protocol"); 214*bc5531deSDag-Erling Smørgrav break; 215*bc5531deSDag-Erling Smørgrav case 'd': 216*bc5531deSDag-Erling Smørgrav dflag = 1; 217*bc5531deSDag-Erling Smørgrav break; 218*bc5531deSDag-Erling Smørgrav case 'F': 219*bc5531deSDag-Erling Smørgrav Fflag = 1; 220*bc5531deSDag-Erling Smørgrav break; 221*bc5531deSDag-Erling Smørgrav case 'h': 222*bc5531deSDag-Erling Smørgrav help(); 223*bc5531deSDag-Erling Smørgrav break; 224*bc5531deSDag-Erling Smørgrav case 'i': 225*bc5531deSDag-Erling Smørgrav iflag = strtonum(optarg, 0, UINT_MAX, &errstr); 226*bc5531deSDag-Erling Smørgrav if (errstr) 227*bc5531deSDag-Erling Smørgrav errx(1, "interval %s: %s", errstr, optarg); 228*bc5531deSDag-Erling Smørgrav break; 229*bc5531deSDag-Erling Smørgrav case 'k': 230*bc5531deSDag-Erling Smørgrav kflag = 1; 231*bc5531deSDag-Erling Smørgrav break; 232*bc5531deSDag-Erling Smørgrav case 'l': 233*bc5531deSDag-Erling Smørgrav lflag = 1; 234*bc5531deSDag-Erling Smørgrav break; 235*bc5531deSDag-Erling Smørgrav case 'N': 236*bc5531deSDag-Erling Smørgrav Nflag = 1; 237*bc5531deSDag-Erling Smørgrav break; 238*bc5531deSDag-Erling Smørgrav case 'n': 239*bc5531deSDag-Erling Smørgrav nflag = 1; 240*bc5531deSDag-Erling Smørgrav break; 241*bc5531deSDag-Erling Smørgrav case 'P': 242*bc5531deSDag-Erling Smørgrav Pflag = optarg; 243*bc5531deSDag-Erling Smørgrav break; 244*bc5531deSDag-Erling Smørgrav case 'p': 245*bc5531deSDag-Erling Smørgrav pflag = optarg; 246*bc5531deSDag-Erling Smørgrav break; 247*bc5531deSDag-Erling Smørgrav case 'r': 248*bc5531deSDag-Erling Smørgrav rflag = 1; 249*bc5531deSDag-Erling Smørgrav break; 250*bc5531deSDag-Erling Smørgrav case 's': 251*bc5531deSDag-Erling Smørgrav sflag = optarg; 252*bc5531deSDag-Erling Smørgrav break; 253*bc5531deSDag-Erling Smørgrav case 't': 254*bc5531deSDag-Erling Smørgrav tflag = 1; 255*bc5531deSDag-Erling Smørgrav break; 256*bc5531deSDag-Erling Smørgrav case 'u': 257*bc5531deSDag-Erling Smørgrav uflag = 1; 258*bc5531deSDag-Erling Smørgrav break; 259*bc5531deSDag-Erling Smørgrav #ifdef SO_RTABLE 260*bc5531deSDag-Erling Smørgrav case 'V': 261*bc5531deSDag-Erling Smørgrav rtableid = (int)strtonum(optarg, 0, 262*bc5531deSDag-Erling Smørgrav RT_TABLEID_MAX, &errstr); 263*bc5531deSDag-Erling Smørgrav if (errstr) 264*bc5531deSDag-Erling Smørgrav errx(1, "rtable %s: %s", errstr, optarg); 265*bc5531deSDag-Erling Smørgrav break; 266*bc5531deSDag-Erling Smørgrav #endif 267*bc5531deSDag-Erling Smørgrav case 'v': 268*bc5531deSDag-Erling Smørgrav vflag = 1; 269*bc5531deSDag-Erling Smørgrav break; 270*bc5531deSDag-Erling Smørgrav case 'w': 271*bc5531deSDag-Erling Smørgrav timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); 272*bc5531deSDag-Erling Smørgrav if (errstr) 273*bc5531deSDag-Erling Smørgrav errx(1, "timeout %s: %s", errstr, optarg); 274*bc5531deSDag-Erling Smørgrav timeout *= 1000; 275*bc5531deSDag-Erling Smørgrav break; 276*bc5531deSDag-Erling Smørgrav case 'x': 277*bc5531deSDag-Erling Smørgrav xflag = 1; 278*bc5531deSDag-Erling Smørgrav if ((proxy = strdup(optarg)) == NULL) 279*bc5531deSDag-Erling Smørgrav errx(1, "strdup"); 280*bc5531deSDag-Erling Smørgrav break; 281*bc5531deSDag-Erling Smørgrav case 'z': 282*bc5531deSDag-Erling Smørgrav zflag = 1; 283*bc5531deSDag-Erling Smørgrav break; 284*bc5531deSDag-Erling Smørgrav case 'D': 285*bc5531deSDag-Erling Smørgrav Dflag = 1; 286*bc5531deSDag-Erling Smørgrav break; 287*bc5531deSDag-Erling Smørgrav case 'I': 288*bc5531deSDag-Erling Smørgrav Iflag = strtonum(optarg, 1, 65536 << 14, &errstr); 289*bc5531deSDag-Erling Smørgrav if (errstr != NULL) 290*bc5531deSDag-Erling Smørgrav errx(1, "TCP receive window %s: %s", 291*bc5531deSDag-Erling Smørgrav errstr, optarg); 292*bc5531deSDag-Erling Smørgrav break; 293*bc5531deSDag-Erling Smørgrav case 'O': 294*bc5531deSDag-Erling Smørgrav Oflag = strtonum(optarg, 1, 65536 << 14, &errstr); 295*bc5531deSDag-Erling Smørgrav if (errstr != NULL) 296*bc5531deSDag-Erling Smørgrav errx(1, "TCP send window %s: %s", 297*bc5531deSDag-Erling Smørgrav errstr, optarg); 298*bc5531deSDag-Erling Smørgrav break; 299*bc5531deSDag-Erling Smørgrav case 'S': 300*bc5531deSDag-Erling Smørgrav Sflag = 1; 301*bc5531deSDag-Erling Smørgrav break; 302*bc5531deSDag-Erling Smørgrav case 'T': 303*bc5531deSDag-Erling Smørgrav errstr = NULL; 304*bc5531deSDag-Erling Smørgrav errno = 0; 305*bc5531deSDag-Erling Smørgrav if (map_tos(optarg, &Tflag)) 306*bc5531deSDag-Erling Smørgrav break; 307*bc5531deSDag-Erling Smørgrav if (strlen(optarg) > 1 && optarg[0] == '0' && 308*bc5531deSDag-Erling Smørgrav optarg[1] == 'x') 309*bc5531deSDag-Erling Smørgrav Tflag = (int)strtol(optarg, NULL, 16); 310*bc5531deSDag-Erling Smørgrav else 311*bc5531deSDag-Erling Smørgrav Tflag = (int)strtonum(optarg, 0, 255, 312*bc5531deSDag-Erling Smørgrav &errstr); 313*bc5531deSDag-Erling Smørgrav if (Tflag < 0 || Tflag > 255 || errstr || errno) 314*bc5531deSDag-Erling Smørgrav errx(1, "illegal tos value %s", optarg); 315*bc5531deSDag-Erling Smørgrav break; 316*bc5531deSDag-Erling Smørgrav default: 317*bc5531deSDag-Erling Smørgrav usage(1); 318*bc5531deSDag-Erling Smørgrav } 319*bc5531deSDag-Erling Smørgrav } 320*bc5531deSDag-Erling Smørgrav argc -= optind; 321*bc5531deSDag-Erling Smørgrav argv += optind; 322*bc5531deSDag-Erling Smørgrav 323*bc5531deSDag-Erling Smørgrav /* Cruft to make sure options are clean, and used properly. */ 324*bc5531deSDag-Erling Smørgrav if (argv[0] && !argv[1] && family == AF_UNIX) { 325*bc5531deSDag-Erling Smørgrav host = argv[0]; 326*bc5531deSDag-Erling Smørgrav uport = NULL; 327*bc5531deSDag-Erling Smørgrav } else if (argv[0] && !argv[1]) { 328*bc5531deSDag-Erling Smørgrav if (!lflag) 329*bc5531deSDag-Erling Smørgrav usage(1); 330*bc5531deSDag-Erling Smørgrav uport = argv[0]; 331*bc5531deSDag-Erling Smørgrav host = NULL; 332*bc5531deSDag-Erling Smørgrav } else if (argv[0] && argv[1]) { 333*bc5531deSDag-Erling Smørgrav host = argv[0]; 334*bc5531deSDag-Erling Smørgrav uport = argv[1]; 335*bc5531deSDag-Erling Smørgrav } else 336*bc5531deSDag-Erling Smørgrav usage(1); 337*bc5531deSDag-Erling Smørgrav 338*bc5531deSDag-Erling Smørgrav if (lflag && sflag) 339*bc5531deSDag-Erling Smørgrav errx(1, "cannot use -s and -l"); 340*bc5531deSDag-Erling Smørgrav if (lflag && pflag) 341*bc5531deSDag-Erling Smørgrav errx(1, "cannot use -p and -l"); 342*bc5531deSDag-Erling Smørgrav if (lflag && zflag) 343*bc5531deSDag-Erling Smørgrav errx(1, "cannot use -z and -l"); 344*bc5531deSDag-Erling Smørgrav if (!lflag && kflag) 345*bc5531deSDag-Erling Smørgrav errx(1, "must use -l with -k"); 346*bc5531deSDag-Erling Smørgrav 347*bc5531deSDag-Erling Smørgrav /* Get name of temporary socket for unix datagram client */ 348*bc5531deSDag-Erling Smørgrav if ((family == AF_UNIX) && uflag && !lflag) { 349*bc5531deSDag-Erling Smørgrav if (sflag) { 350*bc5531deSDag-Erling Smørgrav unix_dg_tmp_socket = sflag; 351*bc5531deSDag-Erling Smørgrav } else { 352*bc5531deSDag-Erling Smørgrav strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", 353*bc5531deSDag-Erling Smørgrav UNIX_DG_TMP_SOCKET_SIZE); 354*bc5531deSDag-Erling Smørgrav if (mktemp(unix_dg_tmp_socket_buf) == NULL) 355*bc5531deSDag-Erling Smørgrav err(1, "mktemp"); 356*bc5531deSDag-Erling Smørgrav unix_dg_tmp_socket = unix_dg_tmp_socket_buf; 357*bc5531deSDag-Erling Smørgrav } 358*bc5531deSDag-Erling Smørgrav } 359*bc5531deSDag-Erling Smørgrav 360*bc5531deSDag-Erling Smørgrav /* Initialize addrinfo structure. */ 361*bc5531deSDag-Erling Smørgrav if (family != AF_UNIX) { 362*bc5531deSDag-Erling Smørgrav memset(&hints, 0, sizeof(struct addrinfo)); 363*bc5531deSDag-Erling Smørgrav hints.ai_family = family; 364*bc5531deSDag-Erling Smørgrav hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 365*bc5531deSDag-Erling Smørgrav hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 366*bc5531deSDag-Erling Smørgrav if (nflag) 367*bc5531deSDag-Erling Smørgrav hints.ai_flags |= AI_NUMERICHOST; 368*bc5531deSDag-Erling Smørgrav } 369*bc5531deSDag-Erling Smørgrav 370*bc5531deSDag-Erling Smørgrav if (xflag) { 371*bc5531deSDag-Erling Smørgrav if (uflag) 372*bc5531deSDag-Erling Smørgrav errx(1, "no proxy support for UDP mode"); 373*bc5531deSDag-Erling Smørgrav 374*bc5531deSDag-Erling Smørgrav if (lflag) 375*bc5531deSDag-Erling Smørgrav errx(1, "no proxy support for listen"); 376*bc5531deSDag-Erling Smørgrav 377*bc5531deSDag-Erling Smørgrav if (family == AF_UNIX) 378*bc5531deSDag-Erling Smørgrav errx(1, "no proxy support for unix sockets"); 379*bc5531deSDag-Erling Smørgrav 380*bc5531deSDag-Erling Smørgrav /* XXX IPv6 transport to proxy would probably work */ 381*bc5531deSDag-Erling Smørgrav if (family == AF_INET6) 382*bc5531deSDag-Erling Smørgrav errx(1, "no proxy support for IPv6"); 383*bc5531deSDag-Erling Smørgrav 384*bc5531deSDag-Erling Smørgrav if (sflag) 385*bc5531deSDag-Erling Smørgrav errx(1, "no proxy support for local source address"); 386*bc5531deSDag-Erling Smørgrav 387*bc5531deSDag-Erling Smørgrav proxyhost = strsep(&proxy, ":"); 388*bc5531deSDag-Erling Smørgrav proxyport = proxy; 389*bc5531deSDag-Erling Smørgrav 390*bc5531deSDag-Erling Smørgrav memset(&proxyhints, 0, sizeof(struct addrinfo)); 391*bc5531deSDag-Erling Smørgrav proxyhints.ai_family = family; 392*bc5531deSDag-Erling Smørgrav proxyhints.ai_socktype = SOCK_STREAM; 393*bc5531deSDag-Erling Smørgrav proxyhints.ai_protocol = IPPROTO_TCP; 394*bc5531deSDag-Erling Smørgrav if (nflag) 395*bc5531deSDag-Erling Smørgrav proxyhints.ai_flags |= AI_NUMERICHOST; 396*bc5531deSDag-Erling Smørgrav } 397*bc5531deSDag-Erling Smørgrav 398*bc5531deSDag-Erling Smørgrav if (lflag) { 399*bc5531deSDag-Erling Smørgrav int connfd; 400*bc5531deSDag-Erling Smørgrav ret = 0; 401*bc5531deSDag-Erling Smørgrav 402*bc5531deSDag-Erling Smørgrav if (family == AF_UNIX) { 403*bc5531deSDag-Erling Smørgrav if (uflag) 404*bc5531deSDag-Erling Smørgrav s = unix_bind(host); 405*bc5531deSDag-Erling Smørgrav else 406*bc5531deSDag-Erling Smørgrav s = unix_listen(host); 407*bc5531deSDag-Erling Smørgrav } 408*bc5531deSDag-Erling Smørgrav 409*bc5531deSDag-Erling Smørgrav /* Allow only one connection at a time, but stay alive. */ 410*bc5531deSDag-Erling Smørgrav for (;;) { 411*bc5531deSDag-Erling Smørgrav if (family != AF_UNIX) 412*bc5531deSDag-Erling Smørgrav s = local_listen(host, uport, hints); 413*bc5531deSDag-Erling Smørgrav if (s < 0) 414*bc5531deSDag-Erling Smørgrav err(1, "local_listen"); 415*bc5531deSDag-Erling Smørgrav /* 416*bc5531deSDag-Erling Smørgrav * For UDP and -k, don't connect the socket, let it 417*bc5531deSDag-Erling Smørgrav * receive datagrams from multiple socket pairs. 418*bc5531deSDag-Erling Smørgrav */ 419*bc5531deSDag-Erling Smørgrav if (uflag && kflag) 420*bc5531deSDag-Erling Smørgrav readwrite(s); 421*bc5531deSDag-Erling Smørgrav /* 422*bc5531deSDag-Erling Smørgrav * For UDP and not -k, we will use recvfrom() initially 423*bc5531deSDag-Erling Smørgrav * to wait for a caller, then use the regular functions 424*bc5531deSDag-Erling Smørgrav * to talk to the caller. 425*bc5531deSDag-Erling Smørgrav */ 426*bc5531deSDag-Erling Smørgrav else if (uflag && !kflag) { 427*bc5531deSDag-Erling Smørgrav int rv, plen; 428*bc5531deSDag-Erling Smørgrav char buf[16384]; 429*bc5531deSDag-Erling Smørgrav struct sockaddr_storage z; 430*bc5531deSDag-Erling Smørgrav 431*bc5531deSDag-Erling Smørgrav len = sizeof(z); 432*bc5531deSDag-Erling Smørgrav plen = 2048; 433*bc5531deSDag-Erling Smørgrav rv = recvfrom(s, buf, plen, MSG_PEEK, 434*bc5531deSDag-Erling Smørgrav (struct sockaddr *)&z, &len); 435*bc5531deSDag-Erling Smørgrav if (rv < 0) 436*bc5531deSDag-Erling Smørgrav err(1, "recvfrom"); 437*bc5531deSDag-Erling Smørgrav 438*bc5531deSDag-Erling Smørgrav rv = connect(s, (struct sockaddr *)&z, len); 439*bc5531deSDag-Erling Smørgrav if (rv < 0) 440*bc5531deSDag-Erling Smørgrav err(1, "connect"); 441*bc5531deSDag-Erling Smørgrav 442*bc5531deSDag-Erling Smørgrav if (vflag) 443*bc5531deSDag-Erling Smørgrav report_connect((struct sockaddr *)&z, len); 444*bc5531deSDag-Erling Smørgrav 445*bc5531deSDag-Erling Smørgrav readwrite(s); 446*bc5531deSDag-Erling Smørgrav } else { 447*bc5531deSDag-Erling Smørgrav len = sizeof(cliaddr); 448*bc5531deSDag-Erling Smørgrav connfd = accept(s, (struct sockaddr *)&cliaddr, 449*bc5531deSDag-Erling Smørgrav &len); 450*bc5531deSDag-Erling Smørgrav if (connfd == -1) { 451*bc5531deSDag-Erling Smørgrav /* For now, all errnos are fatal */ 452*bc5531deSDag-Erling Smørgrav err(1, "accept"); 453*bc5531deSDag-Erling Smørgrav } 454*bc5531deSDag-Erling Smørgrav if (vflag) 455*bc5531deSDag-Erling Smørgrav report_connect((struct sockaddr *)&cliaddr, len); 456*bc5531deSDag-Erling Smørgrav 457*bc5531deSDag-Erling Smørgrav readwrite(connfd); 458*bc5531deSDag-Erling Smørgrav close(connfd); 459*bc5531deSDag-Erling Smørgrav } 460*bc5531deSDag-Erling Smørgrav 461*bc5531deSDag-Erling Smørgrav if (family != AF_UNIX) 462*bc5531deSDag-Erling Smørgrav close(s); 463*bc5531deSDag-Erling Smørgrav else if (uflag) { 464*bc5531deSDag-Erling Smørgrav if (connect(s, NULL, 0) < 0) 465*bc5531deSDag-Erling Smørgrav err(1, "connect"); 466*bc5531deSDag-Erling Smørgrav } 467*bc5531deSDag-Erling Smørgrav 468*bc5531deSDag-Erling Smørgrav if (!kflag) 469*bc5531deSDag-Erling Smørgrav break; 470*bc5531deSDag-Erling Smørgrav } 471*bc5531deSDag-Erling Smørgrav } else if (family == AF_UNIX) { 472*bc5531deSDag-Erling Smørgrav ret = 0; 473*bc5531deSDag-Erling Smørgrav 474*bc5531deSDag-Erling Smørgrav if ((s = unix_connect(host)) > 0 && !zflag) { 475*bc5531deSDag-Erling Smørgrav readwrite(s); 476*bc5531deSDag-Erling Smørgrav close(s); 477*bc5531deSDag-Erling Smørgrav } else 478*bc5531deSDag-Erling Smørgrav ret = 1; 479*bc5531deSDag-Erling Smørgrav 480*bc5531deSDag-Erling Smørgrav if (uflag) 481*bc5531deSDag-Erling Smørgrav unlink(unix_dg_tmp_socket); 482*bc5531deSDag-Erling Smørgrav exit(ret); 483*bc5531deSDag-Erling Smørgrav 484*bc5531deSDag-Erling Smørgrav } else { 485*bc5531deSDag-Erling Smørgrav int i = 0; 486*bc5531deSDag-Erling Smørgrav 487*bc5531deSDag-Erling Smørgrav /* Construct the portlist[] array. */ 488*bc5531deSDag-Erling Smørgrav build_ports(uport); 489*bc5531deSDag-Erling Smørgrav 490*bc5531deSDag-Erling Smørgrav /* Cycle through portlist, connecting to each port. */ 491*bc5531deSDag-Erling Smørgrav for (i = 0; portlist[i] != NULL; i++) { 492*bc5531deSDag-Erling Smørgrav if (s) 493*bc5531deSDag-Erling Smørgrav close(s); 494*bc5531deSDag-Erling Smørgrav 495*bc5531deSDag-Erling Smørgrav if (xflag) 496*bc5531deSDag-Erling Smørgrav s = socks_connect(host, portlist[i], hints, 497*bc5531deSDag-Erling Smørgrav proxyhost, proxyport, proxyhints, socksv, 498*bc5531deSDag-Erling Smørgrav Pflag); 499*bc5531deSDag-Erling Smørgrav else 500*bc5531deSDag-Erling Smørgrav s = remote_connect(host, portlist[i], hints); 501*bc5531deSDag-Erling Smørgrav 502*bc5531deSDag-Erling Smørgrav if (s < 0) 503*bc5531deSDag-Erling Smørgrav continue; 504*bc5531deSDag-Erling Smørgrav 505*bc5531deSDag-Erling Smørgrav ret = 0; 506*bc5531deSDag-Erling Smørgrav if (vflag || zflag) { 507*bc5531deSDag-Erling Smørgrav /* For UDP, make sure we are connected. */ 508*bc5531deSDag-Erling Smørgrav if (uflag) { 509*bc5531deSDag-Erling Smørgrav if (udptest(s) == -1) { 510*bc5531deSDag-Erling Smørgrav ret = 1; 511*bc5531deSDag-Erling Smørgrav continue; 512*bc5531deSDag-Erling Smørgrav } 513*bc5531deSDag-Erling Smørgrav } 514*bc5531deSDag-Erling Smørgrav 515*bc5531deSDag-Erling Smørgrav /* Don't look up port if -n. */ 516*bc5531deSDag-Erling Smørgrav if (nflag) 517*bc5531deSDag-Erling Smørgrav sv = NULL; 518*bc5531deSDag-Erling Smørgrav else { 519*bc5531deSDag-Erling Smørgrav sv = getservbyport( 520*bc5531deSDag-Erling Smørgrav ntohs(atoi(portlist[i])), 521*bc5531deSDag-Erling Smørgrav uflag ? "udp" : "tcp"); 522*bc5531deSDag-Erling Smørgrav } 523*bc5531deSDag-Erling Smørgrav 524*bc5531deSDag-Erling Smørgrav fprintf(stderr, 525*bc5531deSDag-Erling Smørgrav "Connection to %s %s port [%s/%s] " 526*bc5531deSDag-Erling Smørgrav "succeeded!\n", host, portlist[i], 527*bc5531deSDag-Erling Smørgrav uflag ? "udp" : "tcp", 528*bc5531deSDag-Erling Smørgrav sv ? sv->s_name : "*"); 529*bc5531deSDag-Erling Smørgrav } 530*bc5531deSDag-Erling Smørgrav if (Fflag) 531*bc5531deSDag-Erling Smørgrav fdpass(s); 532*bc5531deSDag-Erling Smørgrav else if (!zflag) 533*bc5531deSDag-Erling Smørgrav readwrite(s); 534*bc5531deSDag-Erling Smørgrav } 535*bc5531deSDag-Erling Smørgrav } 536*bc5531deSDag-Erling Smørgrav 537*bc5531deSDag-Erling Smørgrav if (s) 538*bc5531deSDag-Erling Smørgrav close(s); 539*bc5531deSDag-Erling Smørgrav 540*bc5531deSDag-Erling Smørgrav exit(ret); 541*bc5531deSDag-Erling Smørgrav } 542*bc5531deSDag-Erling Smørgrav 543*bc5531deSDag-Erling Smørgrav /* 544*bc5531deSDag-Erling Smørgrav * unix_bind() 545*bc5531deSDag-Erling Smørgrav * Returns a unix socket bound to the given path 546*bc5531deSDag-Erling Smørgrav */ 547*bc5531deSDag-Erling Smørgrav int 548*bc5531deSDag-Erling Smørgrav unix_bind(char *path) 549*bc5531deSDag-Erling Smørgrav { 550*bc5531deSDag-Erling Smørgrav struct sockaddr_un sun_sa; 551*bc5531deSDag-Erling Smørgrav int s; 552*bc5531deSDag-Erling Smørgrav 553*bc5531deSDag-Erling Smørgrav /* Create unix domain socket. */ 554*bc5531deSDag-Erling Smørgrav if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, 555*bc5531deSDag-Erling Smørgrav 0)) < 0) 556*bc5531deSDag-Erling Smørgrav return (-1); 557*bc5531deSDag-Erling Smørgrav 558*bc5531deSDag-Erling Smørgrav memset(&sun_sa, 0, sizeof(struct sockaddr_un)); 559*bc5531deSDag-Erling Smørgrav sun_sa.sun_family = AF_UNIX; 560*bc5531deSDag-Erling Smørgrav 561*bc5531deSDag-Erling Smørgrav if (strlcpy(sun_sa.sun_path, path, sizeof(sun_sa.sun_path)) >= 562*bc5531deSDag-Erling Smørgrav sizeof(sun_sa.sun_path)) { 563*bc5531deSDag-Erling Smørgrav close(s); 564*bc5531deSDag-Erling Smørgrav errno = ENAMETOOLONG; 565*bc5531deSDag-Erling Smørgrav return (-1); 566*bc5531deSDag-Erling Smørgrav } 567*bc5531deSDag-Erling Smørgrav 568*bc5531deSDag-Erling Smørgrav if (bind(s, (struct sockaddr *)&sun_sa, SUN_LEN(&sun_sa)) < 0) { 569*bc5531deSDag-Erling Smørgrav close(s); 570*bc5531deSDag-Erling Smørgrav return (-1); 571*bc5531deSDag-Erling Smørgrav } 572*bc5531deSDag-Erling Smørgrav return (s); 573*bc5531deSDag-Erling Smørgrav } 574*bc5531deSDag-Erling Smørgrav 575*bc5531deSDag-Erling Smørgrav /* 576*bc5531deSDag-Erling Smørgrav * unix_connect() 577*bc5531deSDag-Erling Smørgrav * Returns a socket connected to a local unix socket. Returns -1 on failure. 578*bc5531deSDag-Erling Smørgrav */ 579*bc5531deSDag-Erling Smørgrav int 580*bc5531deSDag-Erling Smørgrav unix_connect(char *path) 581*bc5531deSDag-Erling Smørgrav { 582*bc5531deSDag-Erling Smørgrav struct sockaddr_un sun_sa; 583*bc5531deSDag-Erling Smørgrav int s; 584*bc5531deSDag-Erling Smørgrav 585*bc5531deSDag-Erling Smørgrav if (uflag) { 586*bc5531deSDag-Erling Smørgrav if ((s = unix_bind(unix_dg_tmp_socket)) < 0) 587*bc5531deSDag-Erling Smørgrav return (-1); 588*bc5531deSDag-Erling Smørgrav } else { 589*bc5531deSDag-Erling Smørgrav if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 590*bc5531deSDag-Erling Smørgrav return (-1); 591*bc5531deSDag-Erling Smørgrav } 592*bc5531deSDag-Erling Smørgrav (void)fcntl(s, F_SETFD, FD_CLOEXEC); 593*bc5531deSDag-Erling Smørgrav 594*bc5531deSDag-Erling Smørgrav memset(&sun_sa, 0, sizeof(struct sockaddr_un)); 595*bc5531deSDag-Erling Smørgrav sun_sa.sun_family = AF_UNIX; 596*bc5531deSDag-Erling Smørgrav 597*bc5531deSDag-Erling Smørgrav if (strlcpy(sun_sa.sun_path, path, sizeof(sun_sa.sun_path)) >= 598*bc5531deSDag-Erling Smørgrav sizeof(sun_sa.sun_path)) { 599*bc5531deSDag-Erling Smørgrav close(s); 600*bc5531deSDag-Erling Smørgrav errno = ENAMETOOLONG; 601*bc5531deSDag-Erling Smørgrav return (-1); 602*bc5531deSDag-Erling Smørgrav } 603*bc5531deSDag-Erling Smørgrav if (connect(s, (struct sockaddr *)&sun_sa, SUN_LEN(&sun_sa)) < 0) { 604*bc5531deSDag-Erling Smørgrav close(s); 605*bc5531deSDag-Erling Smørgrav return (-1); 606*bc5531deSDag-Erling Smørgrav } 607*bc5531deSDag-Erling Smørgrav return (s); 608*bc5531deSDag-Erling Smørgrav 609*bc5531deSDag-Erling Smørgrav } 610*bc5531deSDag-Erling Smørgrav 611*bc5531deSDag-Erling Smørgrav /* 612*bc5531deSDag-Erling Smørgrav * unix_listen() 613*bc5531deSDag-Erling Smørgrav * Create a unix domain socket, and listen on it. 614*bc5531deSDag-Erling Smørgrav */ 615*bc5531deSDag-Erling Smørgrav int 616*bc5531deSDag-Erling Smørgrav unix_listen(char *path) 617*bc5531deSDag-Erling Smørgrav { 618*bc5531deSDag-Erling Smørgrav int s; 619*bc5531deSDag-Erling Smørgrav if ((s = unix_bind(path)) < 0) 620*bc5531deSDag-Erling Smørgrav return (-1); 621*bc5531deSDag-Erling Smørgrav 622*bc5531deSDag-Erling Smørgrav if (listen(s, 5) < 0) { 623*bc5531deSDag-Erling Smørgrav close(s); 624*bc5531deSDag-Erling Smørgrav return (-1); 625*bc5531deSDag-Erling Smørgrav } 626*bc5531deSDag-Erling Smørgrav return (s); 627*bc5531deSDag-Erling Smørgrav } 628*bc5531deSDag-Erling Smørgrav 629*bc5531deSDag-Erling Smørgrav /* 630*bc5531deSDag-Erling Smørgrav * remote_connect() 631*bc5531deSDag-Erling Smørgrav * Returns a socket connected to a remote host. Properly binds to a local 632*bc5531deSDag-Erling Smørgrav * port or source address if needed. Returns -1 on failure. 633*bc5531deSDag-Erling Smørgrav */ 634*bc5531deSDag-Erling Smørgrav int 635*bc5531deSDag-Erling Smørgrav remote_connect(const char *host, const char *port, struct addrinfo hints) 636*bc5531deSDag-Erling Smørgrav { 637*bc5531deSDag-Erling Smørgrav struct addrinfo *res, *res0; 638*bc5531deSDag-Erling Smørgrav int s, error; 639*bc5531deSDag-Erling Smørgrav #if defined(SO_RTABLE) || defined(SO_BINDANY) 640*bc5531deSDag-Erling Smørgrav int on = 1; 641*bc5531deSDag-Erling Smørgrav #endif 642*bc5531deSDag-Erling Smørgrav 643*bc5531deSDag-Erling Smørgrav if ((error = getaddrinfo(host, port, &hints, &res))) 644*bc5531deSDag-Erling Smørgrav errx(1, "getaddrinfo: %s", gai_strerror(error)); 645*bc5531deSDag-Erling Smørgrav 646*bc5531deSDag-Erling Smørgrav res0 = res; 647*bc5531deSDag-Erling Smørgrav do { 648*bc5531deSDag-Erling Smørgrav if ((s = socket(res0->ai_family, res0->ai_socktype, 649*bc5531deSDag-Erling Smørgrav res0->ai_protocol)) < 0) 650*bc5531deSDag-Erling Smørgrav continue; 651*bc5531deSDag-Erling Smørgrav 652*bc5531deSDag-Erling Smørgrav #ifdef SO_RTABLE 653*bc5531deSDag-Erling Smørgrav if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE, 654*bc5531deSDag-Erling Smørgrav &rtableid, sizeof(rtableid)) == -1)) 655*bc5531deSDag-Erling Smørgrav err(1, "setsockopt SO_RTABLE"); 656*bc5531deSDag-Erling Smørgrav #endif 657*bc5531deSDag-Erling Smørgrav /* Bind to a local port or source address if specified. */ 658*bc5531deSDag-Erling Smørgrav if (sflag || pflag) { 659*bc5531deSDag-Erling Smørgrav struct addrinfo ahints, *ares; 660*bc5531deSDag-Erling Smørgrav 661*bc5531deSDag-Erling Smørgrav #ifdef SO_BINDANY 662*bc5531deSDag-Erling Smørgrav /* try SO_BINDANY, but don't insist */ 663*bc5531deSDag-Erling Smørgrav setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)); 664*bc5531deSDag-Erling Smørgrav #endif 665*bc5531deSDag-Erling Smørgrav memset(&ahints, 0, sizeof(struct addrinfo)); 666*bc5531deSDag-Erling Smørgrav ahints.ai_family = res0->ai_family; 667*bc5531deSDag-Erling Smørgrav ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; 668*bc5531deSDag-Erling Smørgrav ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; 669*bc5531deSDag-Erling Smørgrav ahints.ai_flags = AI_PASSIVE; 670*bc5531deSDag-Erling Smørgrav if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) 671*bc5531deSDag-Erling Smørgrav errx(1, "getaddrinfo: %s", gai_strerror(error)); 672*bc5531deSDag-Erling Smørgrav 673*bc5531deSDag-Erling Smørgrav if (bind(s, (struct sockaddr *)ares->ai_addr, 674*bc5531deSDag-Erling Smørgrav ares->ai_addrlen) < 0) 675*bc5531deSDag-Erling Smørgrav err(1, "bind failed"); 676*bc5531deSDag-Erling Smørgrav freeaddrinfo(ares); 677*bc5531deSDag-Erling Smørgrav } 678*bc5531deSDag-Erling Smørgrav 679*bc5531deSDag-Erling Smørgrav set_common_sockopts(s); 680*bc5531deSDag-Erling Smørgrav 681*bc5531deSDag-Erling Smørgrav if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 682*bc5531deSDag-Erling Smørgrav break; 683*bc5531deSDag-Erling Smørgrav else if (vflag) 684*bc5531deSDag-Erling Smørgrav warn("connect to %s port %s (%s) failed", host, port, 685*bc5531deSDag-Erling Smørgrav uflag ? "udp" : "tcp"); 686*bc5531deSDag-Erling Smørgrav 687*bc5531deSDag-Erling Smørgrav close(s); 688*bc5531deSDag-Erling Smørgrav s = -1; 689*bc5531deSDag-Erling Smørgrav } while ((res0 = res0->ai_next) != NULL); 690*bc5531deSDag-Erling Smørgrav 691*bc5531deSDag-Erling Smørgrav freeaddrinfo(res); 692*bc5531deSDag-Erling Smørgrav 693*bc5531deSDag-Erling Smørgrav return (s); 694*bc5531deSDag-Erling Smørgrav } 695*bc5531deSDag-Erling Smørgrav 696*bc5531deSDag-Erling Smørgrav int 697*bc5531deSDag-Erling Smørgrav timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) 698*bc5531deSDag-Erling Smørgrav { 699*bc5531deSDag-Erling Smørgrav struct pollfd pfd; 700*bc5531deSDag-Erling Smørgrav socklen_t optlen; 701*bc5531deSDag-Erling Smørgrav int flags = 0, optval; 702*bc5531deSDag-Erling Smørgrav int ret; 703*bc5531deSDag-Erling Smørgrav 704*bc5531deSDag-Erling Smørgrav if (timeout != -1) { 705*bc5531deSDag-Erling Smørgrav flags = fcntl(s, F_GETFL, 0); 706*bc5531deSDag-Erling Smørgrav if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) 707*bc5531deSDag-Erling Smørgrav err(1, "set non-blocking mode"); 708*bc5531deSDag-Erling Smørgrav } 709*bc5531deSDag-Erling Smørgrav 710*bc5531deSDag-Erling Smørgrav if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { 711*bc5531deSDag-Erling Smørgrav pfd.fd = s; 712*bc5531deSDag-Erling Smørgrav pfd.events = POLLOUT; 713*bc5531deSDag-Erling Smørgrav if ((ret = poll(&pfd, 1, timeout)) == 1) { 714*bc5531deSDag-Erling Smørgrav optlen = sizeof(optval); 715*bc5531deSDag-Erling Smørgrav if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, 716*bc5531deSDag-Erling Smørgrav &optval, &optlen)) == 0) { 717*bc5531deSDag-Erling Smørgrav errno = optval; 718*bc5531deSDag-Erling Smørgrav ret = optval == 0 ? 0 : -1; 719*bc5531deSDag-Erling Smørgrav } 720*bc5531deSDag-Erling Smørgrav } else if (ret == 0) { 721*bc5531deSDag-Erling Smørgrav errno = ETIMEDOUT; 722*bc5531deSDag-Erling Smørgrav ret = -1; 723*bc5531deSDag-Erling Smørgrav } else 724*bc5531deSDag-Erling Smørgrav err(1, "poll failed"); 725*bc5531deSDag-Erling Smørgrav } 726*bc5531deSDag-Erling Smørgrav 727*bc5531deSDag-Erling Smørgrav if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) 728*bc5531deSDag-Erling Smørgrav err(1, "restoring flags"); 729*bc5531deSDag-Erling Smørgrav 730*bc5531deSDag-Erling Smørgrav return (ret); 731*bc5531deSDag-Erling Smørgrav } 732*bc5531deSDag-Erling Smørgrav 733*bc5531deSDag-Erling Smørgrav /* 734*bc5531deSDag-Erling Smørgrav * local_listen() 735*bc5531deSDag-Erling Smørgrav * Returns a socket listening on a local port, binds to specified source 736*bc5531deSDag-Erling Smørgrav * address. Returns -1 on failure. 737*bc5531deSDag-Erling Smørgrav */ 738*bc5531deSDag-Erling Smørgrav int 739*bc5531deSDag-Erling Smørgrav local_listen(char *host, char *port, struct addrinfo hints) 740*bc5531deSDag-Erling Smørgrav { 741*bc5531deSDag-Erling Smørgrav struct addrinfo *res, *res0; 742*bc5531deSDag-Erling Smørgrav int s, ret, x = 1; 743*bc5531deSDag-Erling Smørgrav int error; 744*bc5531deSDag-Erling Smørgrav 745*bc5531deSDag-Erling Smørgrav /* Allow nodename to be null. */ 746*bc5531deSDag-Erling Smørgrav hints.ai_flags |= AI_PASSIVE; 747*bc5531deSDag-Erling Smørgrav 748*bc5531deSDag-Erling Smørgrav /* 749*bc5531deSDag-Erling Smørgrav * In the case of binding to a wildcard address 750*bc5531deSDag-Erling Smørgrav * default to binding to an ipv4 address. 751*bc5531deSDag-Erling Smørgrav */ 752*bc5531deSDag-Erling Smørgrav if (host == NULL && hints.ai_family == AF_UNSPEC) 753*bc5531deSDag-Erling Smørgrav hints.ai_family = AF_INET; 754*bc5531deSDag-Erling Smørgrav 755*bc5531deSDag-Erling Smørgrav if ((error = getaddrinfo(host, port, &hints, &res))) 756*bc5531deSDag-Erling Smørgrav errx(1, "getaddrinfo: %s", gai_strerror(error)); 757*bc5531deSDag-Erling Smørgrav 758*bc5531deSDag-Erling Smørgrav res0 = res; 759*bc5531deSDag-Erling Smørgrav do { 760*bc5531deSDag-Erling Smørgrav if ((s = socket(res0->ai_family, res0->ai_socktype, 761*bc5531deSDag-Erling Smørgrav res0->ai_protocol)) < 0) 762*bc5531deSDag-Erling Smørgrav continue; 763*bc5531deSDag-Erling Smørgrav 764*bc5531deSDag-Erling Smørgrav #ifdef SO_RTABLE 765*bc5531deSDag-Erling Smørgrav if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE, 766*bc5531deSDag-Erling Smørgrav &rtableid, sizeof(rtableid)) == -1)) 767*bc5531deSDag-Erling Smørgrav err(1, "setsockopt SO_RTABLE"); 768*bc5531deSDag-Erling Smørgrav #endif 769*bc5531deSDag-Erling Smørgrav #ifdef SO_REUSEPORT 770*bc5531deSDag-Erling Smørgrav ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); 771*bc5531deSDag-Erling Smørgrav if (ret == -1) 772*bc5531deSDag-Erling Smørgrav err(1, "setsockopt"); 773*bc5531deSDag-Erling Smørgrav #endif 774*bc5531deSDag-Erling Smørgrav set_common_sockopts(s); 775*bc5531deSDag-Erling Smørgrav 776*bc5531deSDag-Erling Smørgrav if (bind(s, (struct sockaddr *)res0->ai_addr, 777*bc5531deSDag-Erling Smørgrav res0->ai_addrlen) == 0) 778*bc5531deSDag-Erling Smørgrav break; 779*bc5531deSDag-Erling Smørgrav 780*bc5531deSDag-Erling Smørgrav close(s); 781*bc5531deSDag-Erling Smørgrav s = -1; 782*bc5531deSDag-Erling Smørgrav } while ((res0 = res0->ai_next) != NULL); 783*bc5531deSDag-Erling Smørgrav 784*bc5531deSDag-Erling Smørgrav if (!uflag && s != -1) { 785*bc5531deSDag-Erling Smørgrav if (listen(s, 1) < 0) 786*bc5531deSDag-Erling Smørgrav err(1, "listen"); 787*bc5531deSDag-Erling Smørgrav } 788*bc5531deSDag-Erling Smørgrav 789*bc5531deSDag-Erling Smørgrav freeaddrinfo(res); 790*bc5531deSDag-Erling Smørgrav 791*bc5531deSDag-Erling Smørgrav return (s); 792*bc5531deSDag-Erling Smørgrav } 793*bc5531deSDag-Erling Smørgrav 794*bc5531deSDag-Erling Smørgrav /* 795*bc5531deSDag-Erling Smørgrav * readwrite() 796*bc5531deSDag-Erling Smørgrav * Loop that polls on the network file descriptor and stdin. 797*bc5531deSDag-Erling Smørgrav */ 798*bc5531deSDag-Erling Smørgrav void 799*bc5531deSDag-Erling Smørgrav readwrite(int net_fd) 800*bc5531deSDag-Erling Smørgrav { 801*bc5531deSDag-Erling Smørgrav struct pollfd pfd[4]; 802*bc5531deSDag-Erling Smørgrav int stdin_fd = STDIN_FILENO; 803*bc5531deSDag-Erling Smørgrav int stdout_fd = STDOUT_FILENO; 804*bc5531deSDag-Erling Smørgrav unsigned char netinbuf[BUFSIZE]; 805*bc5531deSDag-Erling Smørgrav size_t netinbufpos = 0; 806*bc5531deSDag-Erling Smørgrav unsigned char stdinbuf[BUFSIZE]; 807*bc5531deSDag-Erling Smørgrav size_t stdinbufpos = 0; 808*bc5531deSDag-Erling Smørgrav int n, num_fds; 809*bc5531deSDag-Erling Smørgrav ssize_t ret; 810*bc5531deSDag-Erling Smørgrav 811*bc5531deSDag-Erling Smørgrav /* don't read from stdin if requested */ 812*bc5531deSDag-Erling Smørgrav if (dflag) 813*bc5531deSDag-Erling Smørgrav stdin_fd = -1; 814*bc5531deSDag-Erling Smørgrav 815*bc5531deSDag-Erling Smørgrav /* stdin */ 816*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].fd = stdin_fd; 817*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].events = POLLIN; 818*bc5531deSDag-Erling Smørgrav 819*bc5531deSDag-Erling Smørgrav /* network out */ 820*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].fd = net_fd; 821*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].events = 0; 822*bc5531deSDag-Erling Smørgrav 823*bc5531deSDag-Erling Smørgrav /* network in */ 824*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].fd = net_fd; 825*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].events = POLLIN; 826*bc5531deSDag-Erling Smørgrav 827*bc5531deSDag-Erling Smørgrav /* stdout */ 828*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].fd = stdout_fd; 829*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].events = 0; 830*bc5531deSDag-Erling Smørgrav 831*bc5531deSDag-Erling Smørgrav while (1) { 832*bc5531deSDag-Erling Smørgrav /* both inputs are gone, buffers are empty, we are done */ 833*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 834*bc5531deSDag-Erling Smørgrav && stdinbufpos == 0 && netinbufpos == 0) { 835*bc5531deSDag-Erling Smørgrav close(net_fd); 836*bc5531deSDag-Erling Smørgrav return; 837*bc5531deSDag-Erling Smørgrav } 838*bc5531deSDag-Erling Smørgrav /* both outputs are gone, we can't continue */ 839*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { 840*bc5531deSDag-Erling Smørgrav close(net_fd); 841*bc5531deSDag-Erling Smørgrav return; 842*bc5531deSDag-Erling Smørgrav } 843*bc5531deSDag-Erling Smørgrav /* listen and net in gone, queues empty, done */ 844*bc5531deSDag-Erling Smørgrav if (lflag && pfd[POLL_NETIN].fd == -1 845*bc5531deSDag-Erling Smørgrav && stdinbufpos == 0 && netinbufpos == 0) { 846*bc5531deSDag-Erling Smørgrav close(net_fd); 847*bc5531deSDag-Erling Smørgrav return; 848*bc5531deSDag-Erling Smørgrav } 849*bc5531deSDag-Erling Smørgrav 850*bc5531deSDag-Erling Smørgrav /* help says -i is for "wait between lines sent". We read and 851*bc5531deSDag-Erling Smørgrav * write arbitrary amounts of data, and we don't want to start 852*bc5531deSDag-Erling Smørgrav * scanning for newlines, so this is as good as it gets */ 853*bc5531deSDag-Erling Smørgrav if (iflag) 854*bc5531deSDag-Erling Smørgrav sleep(iflag); 855*bc5531deSDag-Erling Smørgrav 856*bc5531deSDag-Erling Smørgrav /* poll */ 857*bc5531deSDag-Erling Smørgrav num_fds = poll(pfd, 4, timeout); 858*bc5531deSDag-Erling Smørgrav 859*bc5531deSDag-Erling Smørgrav /* treat poll errors */ 860*bc5531deSDag-Erling Smørgrav if (num_fds == -1) { 861*bc5531deSDag-Erling Smørgrav close(net_fd); 862*bc5531deSDag-Erling Smørgrav err(1, "polling error"); 863*bc5531deSDag-Erling Smørgrav } 864*bc5531deSDag-Erling Smørgrav 865*bc5531deSDag-Erling Smørgrav /* timeout happened */ 866*bc5531deSDag-Erling Smørgrav if (num_fds == 0) 867*bc5531deSDag-Erling Smørgrav return; 868*bc5531deSDag-Erling Smørgrav 869*bc5531deSDag-Erling Smørgrav /* treat socket error conditions */ 870*bc5531deSDag-Erling Smørgrav for (n = 0; n < 4; n++) { 871*bc5531deSDag-Erling Smørgrav if (pfd[n].revents & (POLLERR|POLLNVAL)) { 872*bc5531deSDag-Erling Smørgrav pfd[n].fd = -1; 873*bc5531deSDag-Erling Smørgrav } 874*bc5531deSDag-Erling Smørgrav } 875*bc5531deSDag-Erling Smørgrav /* reading is possible after HUP */ 876*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDIN].events & POLLIN && 877*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].revents & POLLHUP && 878*bc5531deSDag-Erling Smørgrav ! (pfd[POLL_STDIN].revents & POLLIN)) 879*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].fd = -1; 880*bc5531deSDag-Erling Smørgrav 881*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETIN].events & POLLIN && 882*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].revents & POLLHUP && 883*bc5531deSDag-Erling Smørgrav ! (pfd[POLL_NETIN].revents & POLLIN)) 884*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].fd = -1; 885*bc5531deSDag-Erling Smørgrav 886*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETOUT].revents & POLLHUP) { 887*bc5531deSDag-Erling Smørgrav if (Nflag) 888*bc5531deSDag-Erling Smørgrav shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); 889*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].fd = -1; 890*bc5531deSDag-Erling Smørgrav } 891*bc5531deSDag-Erling Smørgrav /* if HUP, stop watching stdout */ 892*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDOUT].revents & POLLHUP) 893*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].fd = -1; 894*bc5531deSDag-Erling Smørgrav /* if no net out, stop watching stdin */ 895*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETOUT].fd == -1) 896*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].fd = -1; 897*bc5531deSDag-Erling Smørgrav /* if no stdout, stop watching net in */ 898*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDOUT].fd == -1) { 899*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETIN].fd != -1) 900*bc5531deSDag-Erling Smørgrav shutdown(pfd[POLL_NETIN].fd, SHUT_RD); 901*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].fd = -1; 902*bc5531deSDag-Erling Smørgrav } 903*bc5531deSDag-Erling Smørgrav 904*bc5531deSDag-Erling Smørgrav /* try to read from stdin */ 905*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { 906*bc5531deSDag-Erling Smørgrav ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, 907*bc5531deSDag-Erling Smørgrav &stdinbufpos); 908*bc5531deSDag-Erling Smørgrav /* error or eof on stdin - remove from pfd */ 909*bc5531deSDag-Erling Smørgrav if (ret == 0 || ret == -1) 910*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].fd = -1; 911*bc5531deSDag-Erling Smørgrav /* read something - poll net out */ 912*bc5531deSDag-Erling Smørgrav if (stdinbufpos > 0) 913*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].events = POLLOUT; 914*bc5531deSDag-Erling Smørgrav /* filled buffer - remove self from polling */ 915*bc5531deSDag-Erling Smørgrav if (stdinbufpos == BUFSIZE) 916*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].events = 0; 917*bc5531deSDag-Erling Smørgrav } 918*bc5531deSDag-Erling Smørgrav /* try to write to network */ 919*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { 920*bc5531deSDag-Erling Smørgrav ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, 921*bc5531deSDag-Erling Smørgrav &stdinbufpos); 922*bc5531deSDag-Erling Smørgrav if (ret == -1) 923*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].fd = -1; 924*bc5531deSDag-Erling Smørgrav /* buffer empty - remove self from polling */ 925*bc5531deSDag-Erling Smørgrav if (stdinbufpos == 0) 926*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].events = 0; 927*bc5531deSDag-Erling Smørgrav /* buffer no longer full - poll stdin again */ 928*bc5531deSDag-Erling Smørgrav if (stdinbufpos < BUFSIZE) 929*bc5531deSDag-Erling Smørgrav pfd[POLL_STDIN].events = POLLIN; 930*bc5531deSDag-Erling Smørgrav } 931*bc5531deSDag-Erling Smørgrav /* try to read from network */ 932*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { 933*bc5531deSDag-Erling Smørgrav ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, 934*bc5531deSDag-Erling Smørgrav &netinbufpos); 935*bc5531deSDag-Erling Smørgrav if (ret == -1) 936*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].fd = -1; 937*bc5531deSDag-Erling Smørgrav /* eof on net in - remove from pfd */ 938*bc5531deSDag-Erling Smørgrav if (ret == 0) { 939*bc5531deSDag-Erling Smørgrav shutdown(pfd[POLL_NETIN].fd, SHUT_RD); 940*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].fd = -1; 941*bc5531deSDag-Erling Smørgrav } 942*bc5531deSDag-Erling Smørgrav /* read something - poll stdout */ 943*bc5531deSDag-Erling Smørgrav if (netinbufpos > 0) 944*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].events = POLLOUT; 945*bc5531deSDag-Erling Smørgrav /* filled buffer - remove self from polling */ 946*bc5531deSDag-Erling Smørgrav if (netinbufpos == BUFSIZE) 947*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].events = 0; 948*bc5531deSDag-Erling Smørgrav /* handle telnet */ 949*bc5531deSDag-Erling Smørgrav if (tflag) 950*bc5531deSDag-Erling Smørgrav atelnet(pfd[POLL_NETIN].fd, netinbuf, 951*bc5531deSDag-Erling Smørgrav netinbufpos); 952*bc5531deSDag-Erling Smørgrav } 953*bc5531deSDag-Erling Smørgrav /* try to write to stdout */ 954*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { 955*bc5531deSDag-Erling Smørgrav ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, 956*bc5531deSDag-Erling Smørgrav &netinbufpos); 957*bc5531deSDag-Erling Smørgrav if (ret == -1) 958*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].fd = -1; 959*bc5531deSDag-Erling Smørgrav /* buffer empty - remove self from polling */ 960*bc5531deSDag-Erling Smørgrav if (netinbufpos == 0) 961*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].events = 0; 962*bc5531deSDag-Erling Smørgrav /* buffer no longer full - poll net in again */ 963*bc5531deSDag-Erling Smørgrav if (netinbufpos < BUFSIZE) 964*bc5531deSDag-Erling Smørgrav pfd[POLL_NETIN].events = POLLIN; 965*bc5531deSDag-Erling Smørgrav } 966*bc5531deSDag-Erling Smørgrav 967*bc5531deSDag-Erling Smørgrav /* stdin gone and queue empty? */ 968*bc5531deSDag-Erling Smørgrav if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { 969*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETOUT].fd != -1 && Nflag) 970*bc5531deSDag-Erling Smørgrav shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); 971*bc5531deSDag-Erling Smørgrav pfd[POLL_NETOUT].fd = -1; 972*bc5531deSDag-Erling Smørgrav } 973*bc5531deSDag-Erling Smørgrav /* net in gone and queue empty? */ 974*bc5531deSDag-Erling Smørgrav if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { 975*bc5531deSDag-Erling Smørgrav pfd[POLL_STDOUT].fd = -1; 976*bc5531deSDag-Erling Smørgrav } 977*bc5531deSDag-Erling Smørgrav } 978*bc5531deSDag-Erling Smørgrav } 979*bc5531deSDag-Erling Smørgrav 980*bc5531deSDag-Erling Smørgrav ssize_t 981*bc5531deSDag-Erling Smørgrav drainbuf(int fd, unsigned char *buf, size_t *bufpos) 982*bc5531deSDag-Erling Smørgrav { 983*bc5531deSDag-Erling Smørgrav ssize_t n; 984*bc5531deSDag-Erling Smørgrav ssize_t adjust; 985*bc5531deSDag-Erling Smørgrav 986*bc5531deSDag-Erling Smørgrav n = write(fd, buf, *bufpos); 987*bc5531deSDag-Erling Smørgrav /* don't treat EAGAIN, EINTR as error */ 988*bc5531deSDag-Erling Smørgrav if (n == -1 && (errno == EAGAIN || errno == EINTR)) 989*bc5531deSDag-Erling Smørgrav n = -2; 990*bc5531deSDag-Erling Smørgrav if (n <= 0) 991*bc5531deSDag-Erling Smørgrav return n; 992*bc5531deSDag-Erling Smørgrav /* adjust buffer */ 993*bc5531deSDag-Erling Smørgrav adjust = *bufpos - n; 994*bc5531deSDag-Erling Smørgrav if (adjust > 0) 995*bc5531deSDag-Erling Smørgrav memmove(buf, buf + n, adjust); 996*bc5531deSDag-Erling Smørgrav *bufpos -= n; 997*bc5531deSDag-Erling Smørgrav return n; 998*bc5531deSDag-Erling Smørgrav } 999*bc5531deSDag-Erling Smørgrav 1000*bc5531deSDag-Erling Smørgrav 1001*bc5531deSDag-Erling Smørgrav ssize_t 1002*bc5531deSDag-Erling Smørgrav fillbuf(int fd, unsigned char *buf, size_t *bufpos) 1003*bc5531deSDag-Erling Smørgrav { 1004*bc5531deSDag-Erling Smørgrav size_t num = BUFSIZE - *bufpos; 1005*bc5531deSDag-Erling Smørgrav ssize_t n; 1006*bc5531deSDag-Erling Smørgrav 1007*bc5531deSDag-Erling Smørgrav n = read(fd, buf + *bufpos, num); 1008*bc5531deSDag-Erling Smørgrav /* don't treat EAGAIN, EINTR as error */ 1009*bc5531deSDag-Erling Smørgrav if (n == -1 && (errno == EAGAIN || errno == EINTR)) 1010*bc5531deSDag-Erling Smørgrav n = -2; 1011*bc5531deSDag-Erling Smørgrav if (n <= 0) 1012*bc5531deSDag-Erling Smørgrav return n; 1013*bc5531deSDag-Erling Smørgrav *bufpos += n; 1014*bc5531deSDag-Erling Smørgrav return n; 1015*bc5531deSDag-Erling Smørgrav } 1016*bc5531deSDag-Erling Smørgrav 1017*bc5531deSDag-Erling Smørgrav /* 1018*bc5531deSDag-Erling Smørgrav * fdpass() 1019*bc5531deSDag-Erling Smørgrav * Pass the connected file descriptor to stdout and exit. 1020*bc5531deSDag-Erling Smørgrav */ 1021*bc5531deSDag-Erling Smørgrav void 1022*bc5531deSDag-Erling Smørgrav fdpass(int nfd) 1023*bc5531deSDag-Erling Smørgrav { 1024*bc5531deSDag-Erling Smørgrav #if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) 1025*bc5531deSDag-Erling Smørgrav struct msghdr msg; 1026*bc5531deSDag-Erling Smørgrav #ifndef HAVE_ACCRIGHTS_IN_MSGHDR 1027*bc5531deSDag-Erling Smørgrav union { 1028*bc5531deSDag-Erling Smørgrav struct cmsghdr hdr; 1029*bc5531deSDag-Erling Smørgrav char buf[CMSG_SPACE(sizeof(int))]; 1030*bc5531deSDag-Erling Smørgrav } cmsgbuf; 1031*bc5531deSDag-Erling Smørgrav struct cmsghdr *cmsg; 1032*bc5531deSDag-Erling Smørgrav #endif 1033*bc5531deSDag-Erling Smørgrav struct iovec vec; 1034*bc5531deSDag-Erling Smørgrav char ch = '\0'; 1035*bc5531deSDag-Erling Smørgrav struct pollfd pfd; 1036*bc5531deSDag-Erling Smørgrav ssize_t r; 1037*bc5531deSDag-Erling Smørgrav 1038*bc5531deSDag-Erling Smørgrav memset(&msg, 0, sizeof(msg)); 1039*bc5531deSDag-Erling Smørgrav #ifdef HAVE_ACCRIGHTS_IN_MSGHDR 1040*bc5531deSDag-Erling Smørgrav msg.msg_accrights = (caddr_t)&nfd; 1041*bc5531deSDag-Erling Smørgrav msg.msg_accrightslen = sizeof(nfd); 1042*bc5531deSDag-Erling Smørgrav #else 1043*bc5531deSDag-Erling Smørgrav memset(&cmsgbuf, 0, sizeof(cmsgbuf)); 1044*bc5531deSDag-Erling Smørgrav msg.msg_control = (caddr_t)&cmsgbuf.buf; 1045*bc5531deSDag-Erling Smørgrav msg.msg_controllen = sizeof(cmsgbuf.buf); 1046*bc5531deSDag-Erling Smørgrav cmsg = CMSG_FIRSTHDR(&msg); 1047*bc5531deSDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 1048*bc5531deSDag-Erling Smørgrav cmsg->cmsg_level = SOL_SOCKET; 1049*bc5531deSDag-Erling Smørgrav cmsg->cmsg_type = SCM_RIGHTS; 1050*bc5531deSDag-Erling Smørgrav *(int *)CMSG_DATA(cmsg) = nfd; 1051*bc5531deSDag-Erling Smørgrav #endif 1052*bc5531deSDag-Erling Smørgrav 1053*bc5531deSDag-Erling Smørgrav vec.iov_base = &ch; 1054*bc5531deSDag-Erling Smørgrav vec.iov_len = 1; 1055*bc5531deSDag-Erling Smørgrav msg.msg_iov = &vec; 1056*bc5531deSDag-Erling Smørgrav msg.msg_iovlen = 1; 1057*bc5531deSDag-Erling Smørgrav 1058*bc5531deSDag-Erling Smørgrav bzero(&pfd, sizeof(pfd)); 1059*bc5531deSDag-Erling Smørgrav pfd.fd = STDOUT_FILENO; 1060*bc5531deSDag-Erling Smørgrav for (;;) { 1061*bc5531deSDag-Erling Smørgrav r = sendmsg(STDOUT_FILENO, &msg, 0); 1062*bc5531deSDag-Erling Smørgrav if (r == -1) { 1063*bc5531deSDag-Erling Smørgrav if (errno == EAGAIN || errno == EINTR) { 1064*bc5531deSDag-Erling Smørgrav pfd.events = POLLOUT; 1065*bc5531deSDag-Erling Smørgrav if (poll(&pfd, 1, -1) == -1) 1066*bc5531deSDag-Erling Smørgrav err(1, "poll"); 1067*bc5531deSDag-Erling Smørgrav continue; 1068*bc5531deSDag-Erling Smørgrav } 1069*bc5531deSDag-Erling Smørgrav err(1, "sendmsg"); 1070*bc5531deSDag-Erling Smørgrav } else if (r == -1) 1071*bc5531deSDag-Erling Smørgrav errx(1, "sendmsg: unexpected return value %zd", r); 1072*bc5531deSDag-Erling Smørgrav else 1073*bc5531deSDag-Erling Smørgrav break; 1074*bc5531deSDag-Erling Smørgrav } 1075*bc5531deSDag-Erling Smørgrav exit(0); 1076*bc5531deSDag-Erling Smørgrav #else 1077*bc5531deSDag-Erling Smørgrav errx(1, "%s: file descriptor passing not supported", __func__); 1078*bc5531deSDag-Erling Smørgrav #endif 1079*bc5531deSDag-Erling Smørgrav } 1080*bc5531deSDag-Erling Smørgrav 1081*bc5531deSDag-Erling Smørgrav /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ 1082*bc5531deSDag-Erling Smørgrav void 1083*bc5531deSDag-Erling Smørgrav atelnet(int nfd, unsigned char *buf, unsigned int size) 1084*bc5531deSDag-Erling Smørgrav { 1085*bc5531deSDag-Erling Smørgrav unsigned char *p, *end; 1086*bc5531deSDag-Erling Smørgrav unsigned char obuf[4]; 1087*bc5531deSDag-Erling Smørgrav 1088*bc5531deSDag-Erling Smørgrav if (size < 3) 1089*bc5531deSDag-Erling Smørgrav return; 1090*bc5531deSDag-Erling Smørgrav end = buf + size - 2; 1091*bc5531deSDag-Erling Smørgrav 1092*bc5531deSDag-Erling Smørgrav for (p = buf; p < end; p++) { 1093*bc5531deSDag-Erling Smørgrav if (*p != IAC) 1094*bc5531deSDag-Erling Smørgrav continue; 1095*bc5531deSDag-Erling Smørgrav 1096*bc5531deSDag-Erling Smørgrav obuf[0] = IAC; 1097*bc5531deSDag-Erling Smørgrav p++; 1098*bc5531deSDag-Erling Smørgrav if ((*p == WILL) || (*p == WONT)) 1099*bc5531deSDag-Erling Smørgrav obuf[1] = DONT; 1100*bc5531deSDag-Erling Smørgrav else if ((*p == DO) || (*p == DONT)) 1101*bc5531deSDag-Erling Smørgrav obuf[1] = WONT; 1102*bc5531deSDag-Erling Smørgrav else 1103*bc5531deSDag-Erling Smørgrav continue; 1104*bc5531deSDag-Erling Smørgrav 1105*bc5531deSDag-Erling Smørgrav p++; 1106*bc5531deSDag-Erling Smørgrav obuf[2] = *p; 1107*bc5531deSDag-Erling Smørgrav if (atomicio(vwrite, nfd, obuf, 3) != 3) 1108*bc5531deSDag-Erling Smørgrav warn("Write Error!"); 1109*bc5531deSDag-Erling Smørgrav } 1110*bc5531deSDag-Erling Smørgrav } 1111*bc5531deSDag-Erling Smørgrav 1112*bc5531deSDag-Erling Smørgrav /* 1113*bc5531deSDag-Erling Smørgrav * build_ports() 1114*bc5531deSDag-Erling Smørgrav * Build an array of ports in portlist[], listing each port 1115*bc5531deSDag-Erling Smørgrav * that we should try to connect to. 1116*bc5531deSDag-Erling Smørgrav */ 1117*bc5531deSDag-Erling Smørgrav void 1118*bc5531deSDag-Erling Smørgrav build_ports(char *p) 1119*bc5531deSDag-Erling Smørgrav { 1120*bc5531deSDag-Erling Smørgrav const char *errstr; 1121*bc5531deSDag-Erling Smørgrav char *n; 1122*bc5531deSDag-Erling Smørgrav int hi, lo, cp; 1123*bc5531deSDag-Erling Smørgrav int x = 0; 1124*bc5531deSDag-Erling Smørgrav 1125*bc5531deSDag-Erling Smørgrav if ((n = strchr(p, '-')) != NULL) { 1126*bc5531deSDag-Erling Smørgrav *n = '\0'; 1127*bc5531deSDag-Erling Smørgrav n++; 1128*bc5531deSDag-Erling Smørgrav 1129*bc5531deSDag-Erling Smørgrav /* Make sure the ports are in order: lowest->highest. */ 1130*bc5531deSDag-Erling Smørgrav hi = strtonum(n, 1, PORT_MAX, &errstr); 1131*bc5531deSDag-Erling Smørgrav if (errstr) 1132*bc5531deSDag-Erling Smørgrav errx(1, "port number %s: %s", errstr, n); 1133*bc5531deSDag-Erling Smørgrav lo = strtonum(p, 1, PORT_MAX, &errstr); 1134*bc5531deSDag-Erling Smørgrav if (errstr) 1135*bc5531deSDag-Erling Smørgrav errx(1, "port number %s: %s", errstr, p); 1136*bc5531deSDag-Erling Smørgrav 1137*bc5531deSDag-Erling Smørgrav if (lo > hi) { 1138*bc5531deSDag-Erling Smørgrav cp = hi; 1139*bc5531deSDag-Erling Smørgrav hi = lo; 1140*bc5531deSDag-Erling Smørgrav lo = cp; 1141*bc5531deSDag-Erling Smørgrav } 1142*bc5531deSDag-Erling Smørgrav 1143*bc5531deSDag-Erling Smørgrav /* Load ports sequentially. */ 1144*bc5531deSDag-Erling Smørgrav for (cp = lo; cp <= hi; cp++) { 1145*bc5531deSDag-Erling Smørgrav portlist[x] = calloc(1, PORT_MAX_LEN); 1146*bc5531deSDag-Erling Smørgrav if (portlist[x] == NULL) 1147*bc5531deSDag-Erling Smørgrav errx(1, "calloc"); 1148*bc5531deSDag-Erling Smørgrav snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); 1149*bc5531deSDag-Erling Smørgrav x++; 1150*bc5531deSDag-Erling Smørgrav } 1151*bc5531deSDag-Erling Smørgrav 1152*bc5531deSDag-Erling Smørgrav /* Randomly swap ports. */ 1153*bc5531deSDag-Erling Smørgrav if (rflag) { 1154*bc5531deSDag-Erling Smørgrav int y; 1155*bc5531deSDag-Erling Smørgrav char *c; 1156*bc5531deSDag-Erling Smørgrav 1157*bc5531deSDag-Erling Smørgrav for (x = 0; x <= (hi - lo); x++) { 1158*bc5531deSDag-Erling Smørgrav y = (arc4random() & 0xFFFF) % (hi - lo); 1159*bc5531deSDag-Erling Smørgrav c = portlist[x]; 1160*bc5531deSDag-Erling Smørgrav portlist[x] = portlist[y]; 1161*bc5531deSDag-Erling Smørgrav portlist[y] = c; 1162*bc5531deSDag-Erling Smørgrav } 1163*bc5531deSDag-Erling Smørgrav } 1164*bc5531deSDag-Erling Smørgrav } else { 1165*bc5531deSDag-Erling Smørgrav hi = strtonum(p, 1, PORT_MAX, &errstr); 1166*bc5531deSDag-Erling Smørgrav if (errstr) 1167*bc5531deSDag-Erling Smørgrav errx(1, "port number %s: %s", errstr, p); 1168*bc5531deSDag-Erling Smørgrav portlist[0] = strdup(p); 1169*bc5531deSDag-Erling Smørgrav if (portlist[0] == NULL) 1170*bc5531deSDag-Erling Smørgrav errx(1, "strdup"); 1171*bc5531deSDag-Erling Smørgrav } 1172*bc5531deSDag-Erling Smørgrav } 1173*bc5531deSDag-Erling Smørgrav 1174*bc5531deSDag-Erling Smørgrav /* 1175*bc5531deSDag-Erling Smørgrav * udptest() 1176*bc5531deSDag-Erling Smørgrav * Do a few writes to see if the UDP port is there. 1177*bc5531deSDag-Erling Smørgrav * Fails once PF state table is full. 1178*bc5531deSDag-Erling Smørgrav */ 1179*bc5531deSDag-Erling Smørgrav int 1180*bc5531deSDag-Erling Smørgrav udptest(int s) 1181*bc5531deSDag-Erling Smørgrav { 1182*bc5531deSDag-Erling Smørgrav int i, ret; 1183*bc5531deSDag-Erling Smørgrav 1184*bc5531deSDag-Erling Smørgrav for (i = 0; i <= 3; i++) { 1185*bc5531deSDag-Erling Smørgrav if (write(s, "X", 1) == 1) 1186*bc5531deSDag-Erling Smørgrav ret = 1; 1187*bc5531deSDag-Erling Smørgrav else 1188*bc5531deSDag-Erling Smørgrav ret = -1; 1189*bc5531deSDag-Erling Smørgrav } 1190*bc5531deSDag-Erling Smørgrav return (ret); 1191*bc5531deSDag-Erling Smørgrav } 1192*bc5531deSDag-Erling Smørgrav 1193*bc5531deSDag-Erling Smørgrav void 1194*bc5531deSDag-Erling Smørgrav set_common_sockopts(int s) 1195*bc5531deSDag-Erling Smørgrav { 1196*bc5531deSDag-Erling Smørgrav int x = 1; 1197*bc5531deSDag-Erling Smørgrav 1198*bc5531deSDag-Erling Smørgrav #ifdef TCP_MD5SIG 1199*bc5531deSDag-Erling Smørgrav if (Sflag) { 1200*bc5531deSDag-Erling Smørgrav if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, 1201*bc5531deSDag-Erling Smørgrav &x, sizeof(x)) == -1) 1202*bc5531deSDag-Erling Smørgrav err(1, "setsockopt"); 1203*bc5531deSDag-Erling Smørgrav } 1204*bc5531deSDag-Erling Smørgrav #endif 1205*bc5531deSDag-Erling Smørgrav if (Dflag) { 1206*bc5531deSDag-Erling Smørgrav if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 1207*bc5531deSDag-Erling Smørgrav &x, sizeof(x)) == -1) 1208*bc5531deSDag-Erling Smørgrav err(1, "setsockopt"); 1209*bc5531deSDag-Erling Smørgrav } 1210*bc5531deSDag-Erling Smørgrav if (Tflag != -1) { 1211*bc5531deSDag-Erling Smørgrav if (setsockopt(s, IPPROTO_IP, IP_TOS, 1212*bc5531deSDag-Erling Smørgrav &Tflag, sizeof(Tflag)) == -1) 1213*bc5531deSDag-Erling Smørgrav err(1, "set IP ToS"); 1214*bc5531deSDag-Erling Smørgrav } 1215*bc5531deSDag-Erling Smørgrav if (Iflag) { 1216*bc5531deSDag-Erling Smørgrav if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 1217*bc5531deSDag-Erling Smørgrav &Iflag, sizeof(Iflag)) == -1) 1218*bc5531deSDag-Erling Smørgrav err(1, "set TCP receive buffer size"); 1219*bc5531deSDag-Erling Smørgrav } 1220*bc5531deSDag-Erling Smørgrav if (Oflag) { 1221*bc5531deSDag-Erling Smørgrav if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 1222*bc5531deSDag-Erling Smørgrav &Oflag, sizeof(Oflag)) == -1) 1223*bc5531deSDag-Erling Smørgrav err(1, "set TCP send buffer size"); 1224*bc5531deSDag-Erling Smørgrav } 1225*bc5531deSDag-Erling Smørgrav } 1226*bc5531deSDag-Erling Smørgrav 1227*bc5531deSDag-Erling Smørgrav int 1228*bc5531deSDag-Erling Smørgrav map_tos(char *s, int *val) 1229*bc5531deSDag-Erling Smørgrav { 1230*bc5531deSDag-Erling Smørgrav /* DiffServ Codepoints and other TOS mappings */ 1231*bc5531deSDag-Erling Smørgrav const struct toskeywords { 1232*bc5531deSDag-Erling Smørgrav const char *keyword; 1233*bc5531deSDag-Erling Smørgrav int val; 1234*bc5531deSDag-Erling Smørgrav } *t, toskeywords[] = { 1235*bc5531deSDag-Erling Smørgrav { "af11", IPTOS_DSCP_AF11 }, 1236*bc5531deSDag-Erling Smørgrav { "af12", IPTOS_DSCP_AF12 }, 1237*bc5531deSDag-Erling Smørgrav { "af13", IPTOS_DSCP_AF13 }, 1238*bc5531deSDag-Erling Smørgrav { "af21", IPTOS_DSCP_AF21 }, 1239*bc5531deSDag-Erling Smørgrav { "af22", IPTOS_DSCP_AF22 }, 1240*bc5531deSDag-Erling Smørgrav { "af23", IPTOS_DSCP_AF23 }, 1241*bc5531deSDag-Erling Smørgrav { "af31", IPTOS_DSCP_AF31 }, 1242*bc5531deSDag-Erling Smørgrav { "af32", IPTOS_DSCP_AF32 }, 1243*bc5531deSDag-Erling Smørgrav { "af33", IPTOS_DSCP_AF33 }, 1244*bc5531deSDag-Erling Smørgrav { "af41", IPTOS_DSCP_AF41 }, 1245*bc5531deSDag-Erling Smørgrav { "af42", IPTOS_DSCP_AF42 }, 1246*bc5531deSDag-Erling Smørgrav { "af43", IPTOS_DSCP_AF43 }, 1247*bc5531deSDag-Erling Smørgrav { "critical", IPTOS_PREC_CRITIC_ECP }, 1248*bc5531deSDag-Erling Smørgrav { "cs0", IPTOS_DSCP_CS0 }, 1249*bc5531deSDag-Erling Smørgrav { "cs1", IPTOS_DSCP_CS1 }, 1250*bc5531deSDag-Erling Smørgrav { "cs2", IPTOS_DSCP_CS2 }, 1251*bc5531deSDag-Erling Smørgrav { "cs3", IPTOS_DSCP_CS3 }, 1252*bc5531deSDag-Erling Smørgrav { "cs4", IPTOS_DSCP_CS4 }, 1253*bc5531deSDag-Erling Smørgrav { "cs5", IPTOS_DSCP_CS5 }, 1254*bc5531deSDag-Erling Smørgrav { "cs6", IPTOS_DSCP_CS6 }, 1255*bc5531deSDag-Erling Smørgrav { "cs7", IPTOS_DSCP_CS7 }, 1256*bc5531deSDag-Erling Smørgrav { "ef", IPTOS_DSCP_EF }, 1257*bc5531deSDag-Erling Smørgrav { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 1258*bc5531deSDag-Erling Smørgrav { "lowdelay", IPTOS_LOWDELAY }, 1259*bc5531deSDag-Erling Smørgrav { "netcontrol", IPTOS_PREC_NETCONTROL }, 1260*bc5531deSDag-Erling Smørgrav { "reliability", IPTOS_RELIABILITY }, 1261*bc5531deSDag-Erling Smørgrav { "throughput", IPTOS_THROUGHPUT }, 1262*bc5531deSDag-Erling Smørgrav { NULL, -1 }, 1263*bc5531deSDag-Erling Smørgrav }; 1264*bc5531deSDag-Erling Smørgrav 1265*bc5531deSDag-Erling Smørgrav for (t = toskeywords; t->keyword != NULL; t++) { 1266*bc5531deSDag-Erling Smørgrav if (strcmp(s, t->keyword) == 0) { 1267*bc5531deSDag-Erling Smørgrav *val = t->val; 1268*bc5531deSDag-Erling Smørgrav return (1); 1269*bc5531deSDag-Erling Smørgrav } 1270*bc5531deSDag-Erling Smørgrav } 1271*bc5531deSDag-Erling Smørgrav 1272*bc5531deSDag-Erling Smørgrav return (0); 1273*bc5531deSDag-Erling Smørgrav } 1274*bc5531deSDag-Erling Smørgrav 1275*bc5531deSDag-Erling Smørgrav void 1276*bc5531deSDag-Erling Smørgrav report_connect(const struct sockaddr *sa, socklen_t salen) 1277*bc5531deSDag-Erling Smørgrav { 1278*bc5531deSDag-Erling Smørgrav char remote_host[NI_MAXHOST]; 1279*bc5531deSDag-Erling Smørgrav char remote_port[NI_MAXSERV]; 1280*bc5531deSDag-Erling Smørgrav int herr; 1281*bc5531deSDag-Erling Smørgrav int flags = NI_NUMERICSERV; 1282*bc5531deSDag-Erling Smørgrav 1283*bc5531deSDag-Erling Smørgrav if (nflag) 1284*bc5531deSDag-Erling Smørgrav flags |= NI_NUMERICHOST; 1285*bc5531deSDag-Erling Smørgrav 1286*bc5531deSDag-Erling Smørgrav if ((herr = getnameinfo(sa, salen, 1287*bc5531deSDag-Erling Smørgrav remote_host, sizeof(remote_host), 1288*bc5531deSDag-Erling Smørgrav remote_port, sizeof(remote_port), 1289*bc5531deSDag-Erling Smørgrav flags)) != 0) { 1290*bc5531deSDag-Erling Smørgrav if (herr == EAI_SYSTEM) 1291*bc5531deSDag-Erling Smørgrav err(1, "getnameinfo"); 1292*bc5531deSDag-Erling Smørgrav else 1293*bc5531deSDag-Erling Smørgrav errx(1, "getnameinfo: %s", gai_strerror(herr)); 1294*bc5531deSDag-Erling Smørgrav } 1295*bc5531deSDag-Erling Smørgrav 1296*bc5531deSDag-Erling Smørgrav fprintf(stderr, 1297*bc5531deSDag-Erling Smørgrav "Connection from %s %s " 1298*bc5531deSDag-Erling Smørgrav "received!\n", remote_host, remote_port); 1299*bc5531deSDag-Erling Smørgrav } 1300*bc5531deSDag-Erling Smørgrav 1301*bc5531deSDag-Erling Smørgrav void 1302*bc5531deSDag-Erling Smørgrav help(void) 1303*bc5531deSDag-Erling Smørgrav { 1304*bc5531deSDag-Erling Smørgrav usage(0); 1305*bc5531deSDag-Erling Smørgrav fprintf(stderr, "\tCommand Summary:\n\ 1306*bc5531deSDag-Erling Smørgrav \t-4 Use IPv4\n\ 1307*bc5531deSDag-Erling Smørgrav \t-6 Use IPv6\n\ 1308*bc5531deSDag-Erling Smørgrav \t-D Enable the debug socket option\n\ 1309*bc5531deSDag-Erling Smørgrav \t-d Detach from stdin\n\ 1310*bc5531deSDag-Erling Smørgrav \t-F Pass socket fd\n\ 1311*bc5531deSDag-Erling Smørgrav \t-h This help text\n\ 1312*bc5531deSDag-Erling Smørgrav \t-I length TCP receive buffer length\n\ 1313*bc5531deSDag-Erling Smørgrav \t-i secs\t Delay interval for lines sent, ports scanned\n\ 1314*bc5531deSDag-Erling Smørgrav \t-k Keep inbound sockets open for multiple connects\n\ 1315*bc5531deSDag-Erling Smørgrav \t-l Listen mode, for inbound connects\n\ 1316*bc5531deSDag-Erling Smørgrav \t-N Shutdown the network socket after EOF on stdin\n\ 1317*bc5531deSDag-Erling Smørgrav \t-n Suppress name/port resolutions\n\ 1318*bc5531deSDag-Erling Smørgrav \t-O length TCP send buffer length\n\ 1319*bc5531deSDag-Erling Smørgrav \t-P proxyuser\tUsername for proxy authentication\n\ 1320*bc5531deSDag-Erling Smørgrav \t-p port\t Specify local port for remote connects\n\ 1321*bc5531deSDag-Erling Smørgrav \t-r Randomize remote ports\n\ 1322*bc5531deSDag-Erling Smørgrav \t-S Enable the TCP MD5 signature option\n\ 1323*bc5531deSDag-Erling Smørgrav \t-s addr\t Local source address\n\ 1324*bc5531deSDag-Erling Smørgrav \t-T toskeyword\tSet IP Type of Service\n\ 1325*bc5531deSDag-Erling Smørgrav \t-t Answer TELNET negotiation\n\ 1326*bc5531deSDag-Erling Smørgrav \t-U Use UNIX domain socket\n\ 1327*bc5531deSDag-Erling Smørgrav \t-u UDP mode\n\ 1328*bc5531deSDag-Erling Smørgrav \t-V rtable Specify alternate routing table\n\ 1329*bc5531deSDag-Erling Smørgrav \t-v Verbose\n\ 1330*bc5531deSDag-Erling Smørgrav \t-w secs\t Timeout for connects and final net reads\n\ 1331*bc5531deSDag-Erling Smørgrav \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ 1332*bc5531deSDag-Erling Smørgrav \t-x addr[:port]\tSpecify proxy address and port\n\ 1333*bc5531deSDag-Erling Smørgrav \t-z Zero-I/O mode [used for scanning]\n\ 1334*bc5531deSDag-Erling Smørgrav Port numbers can be individual or ranges: lo-hi [inclusive]\n"); 1335*bc5531deSDag-Erling Smørgrav exit(1); 1336*bc5531deSDag-Erling Smørgrav } 1337*bc5531deSDag-Erling Smørgrav 1338*bc5531deSDag-Erling Smørgrav void 1339*bc5531deSDag-Erling Smørgrav usage(int ret) 1340*bc5531deSDag-Erling Smørgrav { 1341*bc5531deSDag-Erling Smørgrav fprintf(stderr, 1342*bc5531deSDag-Erling Smørgrav "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" 1343*bc5531deSDag-Erling Smørgrav "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" 1344*bc5531deSDag-Erling Smørgrav "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" 1345*bc5531deSDag-Erling Smørgrav "\t [-x proxy_address[:port]] [destination] [port]\n"); 1346*bc5531deSDag-Erling Smørgrav if (ret) 1347*bc5531deSDag-Erling Smørgrav exit(1); 1348*bc5531deSDag-Erling Smørgrav } 1349*bc5531deSDag-Erling Smørgrav 1350*bc5531deSDag-Erling Smørgrav /* *** src/usr.bin/nc/socks.c *** */ 1351*bc5531deSDag-Erling Smørgrav 1352*bc5531deSDag-Erling Smørgrav 1353*bc5531deSDag-Erling Smørgrav /* $OpenBSD: socks.c,v 1.20 2012/03/08 09:56:28 espie Exp $ */ 1354*bc5531deSDag-Erling Smørgrav 1355*bc5531deSDag-Erling Smørgrav /* 1356*bc5531deSDag-Erling Smørgrav * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. 1357*bc5531deSDag-Erling Smørgrav * Copyright (c) 2004, 2005 Damien Miller. All rights reserved. 1358*bc5531deSDag-Erling Smørgrav * 1359*bc5531deSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 1360*bc5531deSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 1361*bc5531deSDag-Erling Smørgrav * are met: 1362*bc5531deSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 1363*bc5531deSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 1364*bc5531deSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 1365*bc5531deSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 1366*bc5531deSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 1367*bc5531deSDag-Erling Smørgrav * 1368*bc5531deSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1369*bc5531deSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1370*bc5531deSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1371*bc5531deSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1372*bc5531deSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1373*bc5531deSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1374*bc5531deSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1375*bc5531deSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1376*bc5531deSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1377*bc5531deSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1378*bc5531deSDag-Erling Smørgrav */ 1379*bc5531deSDag-Erling Smørgrav 1380*bc5531deSDag-Erling Smørgrav #include <sys/types.h> 1381*bc5531deSDag-Erling Smørgrav #include <sys/socket.h> 1382*bc5531deSDag-Erling Smørgrav #include <netinet/in.h> 1383*bc5531deSDag-Erling Smørgrav #include <arpa/inet.h> 1384*bc5531deSDag-Erling Smørgrav 1385*bc5531deSDag-Erling Smørgrav #include <errno.h> 1386*bc5531deSDag-Erling Smørgrav #include <netdb.h> 1387*bc5531deSDag-Erling Smørgrav #include <stdio.h> 1388*bc5531deSDag-Erling Smørgrav #include <stdlib.h> 1389*bc5531deSDag-Erling Smørgrav #include <string.h> 1390*bc5531deSDag-Erling Smørgrav #include <unistd.h> 1391*bc5531deSDag-Erling Smørgrav #include <resolv.h> 1392*bc5531deSDag-Erling Smørgrav 1393*bc5531deSDag-Erling Smørgrav #define SOCKS_PORT "1080" 1394*bc5531deSDag-Erling Smørgrav #define HTTP_PROXY_PORT "3128" 1395*bc5531deSDag-Erling Smørgrav #define HTTP_MAXHDRS 64 1396*bc5531deSDag-Erling Smørgrav #define SOCKS_V5 5 1397*bc5531deSDag-Erling Smørgrav #define SOCKS_V4 4 1398*bc5531deSDag-Erling Smørgrav #define SOCKS_NOAUTH 0 1399*bc5531deSDag-Erling Smørgrav #define SOCKS_NOMETHOD 0xff 1400*bc5531deSDag-Erling Smørgrav #define SOCKS_CONNECT 1 1401*bc5531deSDag-Erling Smørgrav #define SOCKS_IPV4 1 1402*bc5531deSDag-Erling Smørgrav #define SOCKS_DOMAIN 3 1403*bc5531deSDag-Erling Smørgrav #define SOCKS_IPV6 4 1404*bc5531deSDag-Erling Smørgrav 1405*bc5531deSDag-Erling Smørgrav int remote_connect(const char *, const char *, struct addrinfo); 1406*bc5531deSDag-Erling Smørgrav int socks_connect(const char *, const char *, struct addrinfo, 1407*bc5531deSDag-Erling Smørgrav const char *, const char *, struct addrinfo, int, 1408*bc5531deSDag-Erling Smørgrav const char *); 1409*bc5531deSDag-Erling Smørgrav 1410*bc5531deSDag-Erling Smørgrav static int 1411*bc5531deSDag-Erling Smørgrav decode_addrport(const char *h, const char *p, struct sockaddr *addr, 1412*bc5531deSDag-Erling Smørgrav socklen_t addrlen, int v4only, int numeric) 1413*bc5531deSDag-Erling Smørgrav { 1414*bc5531deSDag-Erling Smørgrav int r; 1415*bc5531deSDag-Erling Smørgrav struct addrinfo hints, *res; 1416*bc5531deSDag-Erling Smørgrav 1417*bc5531deSDag-Erling Smørgrav bzero(&hints, sizeof(hints)); 1418*bc5531deSDag-Erling Smørgrav hints.ai_family = v4only ? PF_INET : PF_UNSPEC; 1419*bc5531deSDag-Erling Smørgrav hints.ai_flags = numeric ? AI_NUMERICHOST : 0; 1420*bc5531deSDag-Erling Smørgrav hints.ai_socktype = SOCK_STREAM; 1421*bc5531deSDag-Erling Smørgrav r = getaddrinfo(h, p, &hints, &res); 1422*bc5531deSDag-Erling Smørgrav /* Don't fatal when attempting to convert a numeric address */ 1423*bc5531deSDag-Erling Smørgrav if (r != 0) { 1424*bc5531deSDag-Erling Smørgrav if (!numeric) { 1425*bc5531deSDag-Erling Smørgrav errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p, 1426*bc5531deSDag-Erling Smørgrav gai_strerror(r)); 1427*bc5531deSDag-Erling Smørgrav } 1428*bc5531deSDag-Erling Smørgrav return (-1); 1429*bc5531deSDag-Erling Smørgrav } 1430*bc5531deSDag-Erling Smørgrav if (addrlen < res->ai_addrlen) { 1431*bc5531deSDag-Erling Smørgrav freeaddrinfo(res); 1432*bc5531deSDag-Erling Smørgrav errx(1, "internal error: addrlen < res->ai_addrlen"); 1433*bc5531deSDag-Erling Smørgrav } 1434*bc5531deSDag-Erling Smørgrav memcpy(addr, res->ai_addr, res->ai_addrlen); 1435*bc5531deSDag-Erling Smørgrav freeaddrinfo(res); 1436*bc5531deSDag-Erling Smørgrav return (0); 1437*bc5531deSDag-Erling Smørgrav } 1438*bc5531deSDag-Erling Smørgrav 1439*bc5531deSDag-Erling Smørgrav static int 1440*bc5531deSDag-Erling Smørgrav proxy_read_line(int fd, char *buf, size_t bufsz) 1441*bc5531deSDag-Erling Smørgrav { 1442*bc5531deSDag-Erling Smørgrav size_t off; 1443*bc5531deSDag-Erling Smørgrav 1444*bc5531deSDag-Erling Smørgrav for(off = 0;;) { 1445*bc5531deSDag-Erling Smørgrav if (off >= bufsz) 1446*bc5531deSDag-Erling Smørgrav errx(1, "proxy read too long"); 1447*bc5531deSDag-Erling Smørgrav if (atomicio(read, fd, buf + off, 1) != 1) 1448*bc5531deSDag-Erling Smørgrav err(1, "proxy read"); 1449*bc5531deSDag-Erling Smørgrav /* Skip CR */ 1450*bc5531deSDag-Erling Smørgrav if (buf[off] == '\r') 1451*bc5531deSDag-Erling Smørgrav continue; 1452*bc5531deSDag-Erling Smørgrav if (buf[off] == '\n') { 1453*bc5531deSDag-Erling Smørgrav buf[off] = '\0'; 1454*bc5531deSDag-Erling Smørgrav break; 1455*bc5531deSDag-Erling Smørgrav } 1456*bc5531deSDag-Erling Smørgrav off++; 1457*bc5531deSDag-Erling Smørgrav } 1458*bc5531deSDag-Erling Smørgrav return (off); 1459*bc5531deSDag-Erling Smørgrav } 1460*bc5531deSDag-Erling Smørgrav 1461*bc5531deSDag-Erling Smørgrav static const char * 1462*bc5531deSDag-Erling Smørgrav getproxypass(const char *proxyuser, const char *proxyhost) 1463*bc5531deSDag-Erling Smørgrav { 1464*bc5531deSDag-Erling Smørgrav char prompt[512]; 1465*bc5531deSDag-Erling Smørgrav static char pw[256]; 1466*bc5531deSDag-Erling Smørgrav 1467*bc5531deSDag-Erling Smørgrav snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ", 1468*bc5531deSDag-Erling Smørgrav proxyuser, proxyhost); 1469*bc5531deSDag-Erling Smørgrav if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL) 1470*bc5531deSDag-Erling Smørgrav errx(1, "Unable to read proxy passphrase"); 1471*bc5531deSDag-Erling Smørgrav return (pw); 1472*bc5531deSDag-Erling Smørgrav } 1473*bc5531deSDag-Erling Smørgrav 1474*bc5531deSDag-Erling Smørgrav int 1475*bc5531deSDag-Erling Smørgrav socks_connect(const char *host, const char *port, 1476*bc5531deSDag-Erling Smørgrav struct addrinfo hints __attribute__ ((__unused__)), 1477*bc5531deSDag-Erling Smørgrav const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, 1478*bc5531deSDag-Erling Smørgrav int socksv, const char *proxyuser) 1479*bc5531deSDag-Erling Smørgrav { 1480*bc5531deSDag-Erling Smørgrav int proxyfd, r, authretry = 0; 1481*bc5531deSDag-Erling Smørgrav size_t hlen, wlen = 0; 1482*bc5531deSDag-Erling Smørgrav unsigned char buf[1024]; 1483*bc5531deSDag-Erling Smørgrav size_t cnt; 1484*bc5531deSDag-Erling Smørgrav struct sockaddr_storage addr; 1485*bc5531deSDag-Erling Smørgrav struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; 1486*bc5531deSDag-Erling Smørgrav struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; 1487*bc5531deSDag-Erling Smørgrav in_port_t serverport; 1488*bc5531deSDag-Erling Smørgrav const char *proxypass = NULL; 1489*bc5531deSDag-Erling Smørgrav 1490*bc5531deSDag-Erling Smørgrav if (proxyport == NULL) 1491*bc5531deSDag-Erling Smørgrav proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; 1492*bc5531deSDag-Erling Smørgrav 1493*bc5531deSDag-Erling Smørgrav /* Abuse API to lookup port */ 1494*bc5531deSDag-Erling Smørgrav if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr, 1495*bc5531deSDag-Erling Smørgrav sizeof(addr), 1, 1) == -1) 1496*bc5531deSDag-Erling Smørgrav errx(1, "unknown port \"%.64s\"", port); 1497*bc5531deSDag-Erling Smørgrav serverport = in4->sin_port; 1498*bc5531deSDag-Erling Smørgrav 1499*bc5531deSDag-Erling Smørgrav again: 1500*bc5531deSDag-Erling Smørgrav if (authretry++ > 3) 1501*bc5531deSDag-Erling Smørgrav errx(1, "Too many authentication failures"); 1502*bc5531deSDag-Erling Smørgrav 1503*bc5531deSDag-Erling Smørgrav proxyfd = remote_connect(proxyhost, proxyport, proxyhints); 1504*bc5531deSDag-Erling Smørgrav 1505*bc5531deSDag-Erling Smørgrav if (proxyfd < 0) 1506*bc5531deSDag-Erling Smørgrav return (-1); 1507*bc5531deSDag-Erling Smørgrav 1508*bc5531deSDag-Erling Smørgrav if (socksv == 5) { 1509*bc5531deSDag-Erling Smørgrav if (decode_addrport(host, port, (struct sockaddr *)&addr, 1510*bc5531deSDag-Erling Smørgrav sizeof(addr), 0, 1) == -1) 1511*bc5531deSDag-Erling Smørgrav addr.ss_family = 0; /* used in switch below */ 1512*bc5531deSDag-Erling Smørgrav 1513*bc5531deSDag-Erling Smørgrav /* Version 5, one method: no authentication */ 1514*bc5531deSDag-Erling Smørgrav buf[0] = SOCKS_V5; 1515*bc5531deSDag-Erling Smørgrav buf[1] = 1; 1516*bc5531deSDag-Erling Smørgrav buf[2] = SOCKS_NOAUTH; 1517*bc5531deSDag-Erling Smørgrav cnt = atomicio(vwrite, proxyfd, buf, 3); 1518*bc5531deSDag-Erling Smørgrav if (cnt != 3) 1519*bc5531deSDag-Erling Smørgrav err(1, "write failed (%zu/3)", cnt); 1520*bc5531deSDag-Erling Smørgrav 1521*bc5531deSDag-Erling Smørgrav cnt = atomicio(read, proxyfd, buf, 2); 1522*bc5531deSDag-Erling Smørgrav if (cnt != 2) 1523*bc5531deSDag-Erling Smørgrav err(1, "read failed (%zu/3)", cnt); 1524*bc5531deSDag-Erling Smørgrav 1525*bc5531deSDag-Erling Smørgrav if (buf[1] == SOCKS_NOMETHOD) 1526*bc5531deSDag-Erling Smørgrav errx(1, "authentication method negotiation failed"); 1527*bc5531deSDag-Erling Smørgrav 1528*bc5531deSDag-Erling Smørgrav switch (addr.ss_family) { 1529*bc5531deSDag-Erling Smørgrav case 0: 1530*bc5531deSDag-Erling Smørgrav /* Version 5, connect: domain name */ 1531*bc5531deSDag-Erling Smørgrav 1532*bc5531deSDag-Erling Smørgrav /* Max domain name length is 255 bytes */ 1533*bc5531deSDag-Erling Smørgrav hlen = strlen(host); 1534*bc5531deSDag-Erling Smørgrav if (hlen > 255) 1535*bc5531deSDag-Erling Smørgrav errx(1, "host name too long for SOCKS5"); 1536*bc5531deSDag-Erling Smørgrav buf[0] = SOCKS_V5; 1537*bc5531deSDag-Erling Smørgrav buf[1] = SOCKS_CONNECT; 1538*bc5531deSDag-Erling Smørgrav buf[2] = 0; 1539*bc5531deSDag-Erling Smørgrav buf[3] = SOCKS_DOMAIN; 1540*bc5531deSDag-Erling Smørgrav buf[4] = hlen; 1541*bc5531deSDag-Erling Smørgrav memcpy(buf + 5, host, hlen); 1542*bc5531deSDag-Erling Smørgrav memcpy(buf + 5 + hlen, &serverport, sizeof serverport); 1543*bc5531deSDag-Erling Smørgrav wlen = 7 + hlen; 1544*bc5531deSDag-Erling Smørgrav break; 1545*bc5531deSDag-Erling Smørgrav case AF_INET: 1546*bc5531deSDag-Erling Smørgrav /* Version 5, connect: IPv4 address */ 1547*bc5531deSDag-Erling Smørgrav buf[0] = SOCKS_V5; 1548*bc5531deSDag-Erling Smørgrav buf[1] = SOCKS_CONNECT; 1549*bc5531deSDag-Erling Smørgrav buf[2] = 0; 1550*bc5531deSDag-Erling Smørgrav buf[3] = SOCKS_IPV4; 1551*bc5531deSDag-Erling Smørgrav memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); 1552*bc5531deSDag-Erling Smørgrav memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port); 1553*bc5531deSDag-Erling Smørgrav wlen = 10; 1554*bc5531deSDag-Erling Smørgrav break; 1555*bc5531deSDag-Erling Smørgrav case AF_INET6: 1556*bc5531deSDag-Erling Smørgrav /* Version 5, connect: IPv6 address */ 1557*bc5531deSDag-Erling Smørgrav buf[0] = SOCKS_V5; 1558*bc5531deSDag-Erling Smørgrav buf[1] = SOCKS_CONNECT; 1559*bc5531deSDag-Erling Smørgrav buf[2] = 0; 1560*bc5531deSDag-Erling Smørgrav buf[3] = SOCKS_IPV6; 1561*bc5531deSDag-Erling Smørgrav memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr); 1562*bc5531deSDag-Erling Smørgrav memcpy(buf + 20, &in6->sin6_port, 1563*bc5531deSDag-Erling Smørgrav sizeof in6->sin6_port); 1564*bc5531deSDag-Erling Smørgrav wlen = 22; 1565*bc5531deSDag-Erling Smørgrav break; 1566*bc5531deSDag-Erling Smørgrav default: 1567*bc5531deSDag-Erling Smørgrav errx(1, "internal error: silly AF"); 1568*bc5531deSDag-Erling Smørgrav } 1569*bc5531deSDag-Erling Smørgrav 1570*bc5531deSDag-Erling Smørgrav cnt = atomicio(vwrite, proxyfd, buf, wlen); 1571*bc5531deSDag-Erling Smørgrav if (cnt != wlen) 1572*bc5531deSDag-Erling Smørgrav err(1, "write failed (%zu/%zu)", cnt, wlen); 1573*bc5531deSDag-Erling Smørgrav 1574*bc5531deSDag-Erling Smørgrav cnt = atomicio(read, proxyfd, buf, 4); 1575*bc5531deSDag-Erling Smørgrav if (cnt != 4) 1576*bc5531deSDag-Erling Smørgrav err(1, "read failed (%zu/4)", cnt); 1577*bc5531deSDag-Erling Smørgrav if (buf[1] != 0) 1578*bc5531deSDag-Erling Smørgrav errx(1, "connection failed, SOCKS error %d", buf[1]); 1579*bc5531deSDag-Erling Smørgrav switch (buf[3]) { 1580*bc5531deSDag-Erling Smørgrav case SOCKS_IPV4: 1581*bc5531deSDag-Erling Smørgrav cnt = atomicio(read, proxyfd, buf + 4, 6); 1582*bc5531deSDag-Erling Smørgrav if (cnt != 6) 1583*bc5531deSDag-Erling Smørgrav err(1, "read failed (%zu/6)", cnt); 1584*bc5531deSDag-Erling Smørgrav break; 1585*bc5531deSDag-Erling Smørgrav case SOCKS_IPV6: 1586*bc5531deSDag-Erling Smørgrav cnt = atomicio(read, proxyfd, buf + 4, 18); 1587*bc5531deSDag-Erling Smørgrav if (cnt != 18) 1588*bc5531deSDag-Erling Smørgrav err(1, "read failed (%zu/18)", cnt); 1589*bc5531deSDag-Erling Smørgrav break; 1590*bc5531deSDag-Erling Smørgrav default: 1591*bc5531deSDag-Erling Smørgrav errx(1, "connection failed, unsupported address type"); 1592*bc5531deSDag-Erling Smørgrav } 1593*bc5531deSDag-Erling Smørgrav } else if (socksv == 4) { 1594*bc5531deSDag-Erling Smørgrav /* This will exit on lookup failure */ 1595*bc5531deSDag-Erling Smørgrav decode_addrport(host, port, (struct sockaddr *)&addr, 1596*bc5531deSDag-Erling Smørgrav sizeof(addr), 1, 0); 1597*bc5531deSDag-Erling Smørgrav 1598*bc5531deSDag-Erling Smørgrav /* Version 4 */ 1599*bc5531deSDag-Erling Smørgrav buf[0] = SOCKS_V4; 1600*bc5531deSDag-Erling Smørgrav buf[1] = SOCKS_CONNECT; /* connect */ 1601*bc5531deSDag-Erling Smørgrav memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port); 1602*bc5531deSDag-Erling Smørgrav memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); 1603*bc5531deSDag-Erling Smørgrav buf[8] = 0; /* empty username */ 1604*bc5531deSDag-Erling Smørgrav wlen = 9; 1605*bc5531deSDag-Erling Smørgrav 1606*bc5531deSDag-Erling Smørgrav cnt = atomicio(vwrite, proxyfd, buf, wlen); 1607*bc5531deSDag-Erling Smørgrav if (cnt != wlen) 1608*bc5531deSDag-Erling Smørgrav err(1, "write failed (%zu/%zu)", cnt, wlen); 1609*bc5531deSDag-Erling Smørgrav 1610*bc5531deSDag-Erling Smørgrav cnt = atomicio(read, proxyfd, buf, 8); 1611*bc5531deSDag-Erling Smørgrav if (cnt != 8) 1612*bc5531deSDag-Erling Smørgrav err(1, "read failed (%zu/8)", cnt); 1613*bc5531deSDag-Erling Smørgrav if (buf[1] != 90) 1614*bc5531deSDag-Erling Smørgrav errx(1, "connection failed, SOCKS error %d", buf[1]); 1615*bc5531deSDag-Erling Smørgrav } else if (socksv == -1) { 1616*bc5531deSDag-Erling Smørgrav /* HTTP proxy CONNECT */ 1617*bc5531deSDag-Erling Smørgrav 1618*bc5531deSDag-Erling Smørgrav /* Disallow bad chars in hostname */ 1619*bc5531deSDag-Erling Smørgrav if (strcspn(host, "\r\n\t []:") != strlen(host)) 1620*bc5531deSDag-Erling Smørgrav errx(1, "Invalid hostname"); 1621*bc5531deSDag-Erling Smørgrav 1622*bc5531deSDag-Erling Smørgrav /* Try to be sane about numeric IPv6 addresses */ 1623*bc5531deSDag-Erling Smørgrav if (strchr(host, ':') != NULL) { 1624*bc5531deSDag-Erling Smørgrav r = snprintf(buf, sizeof(buf), 1625*bc5531deSDag-Erling Smørgrav "CONNECT [%s]:%d HTTP/1.0\r\n", 1626*bc5531deSDag-Erling Smørgrav host, ntohs(serverport)); 1627*bc5531deSDag-Erling Smørgrav } else { 1628*bc5531deSDag-Erling Smørgrav r = snprintf(buf, sizeof(buf), 1629*bc5531deSDag-Erling Smørgrav "CONNECT %s:%d HTTP/1.0\r\n", 1630*bc5531deSDag-Erling Smørgrav host, ntohs(serverport)); 1631*bc5531deSDag-Erling Smørgrav } 1632*bc5531deSDag-Erling Smørgrav if (r == -1 || (size_t)r >= sizeof(buf)) 1633*bc5531deSDag-Erling Smørgrav errx(1, "hostname too long"); 1634*bc5531deSDag-Erling Smørgrav r = strlen(buf); 1635*bc5531deSDag-Erling Smørgrav 1636*bc5531deSDag-Erling Smørgrav cnt = atomicio(vwrite, proxyfd, buf, r); 1637*bc5531deSDag-Erling Smørgrav if (cnt != (size_t)r) 1638*bc5531deSDag-Erling Smørgrav err(1, "write failed (%zu/%d)", cnt, r); 1639*bc5531deSDag-Erling Smørgrav 1640*bc5531deSDag-Erling Smørgrav if (authretry > 1) { 1641*bc5531deSDag-Erling Smørgrav char resp[1024]; 1642*bc5531deSDag-Erling Smørgrav 1643*bc5531deSDag-Erling Smørgrav proxypass = getproxypass(proxyuser, proxyhost); 1644*bc5531deSDag-Erling Smørgrav r = snprintf(buf, sizeof(buf), "%s:%s", 1645*bc5531deSDag-Erling Smørgrav proxyuser, proxypass); 1646*bc5531deSDag-Erling Smørgrav if (r == -1 || (size_t)r >= sizeof(buf) || 1647*bc5531deSDag-Erling Smørgrav b64_ntop(buf, strlen(buf), resp, 1648*bc5531deSDag-Erling Smørgrav sizeof(resp)) == -1) 1649*bc5531deSDag-Erling Smørgrav errx(1, "Proxy username/password too long"); 1650*bc5531deSDag-Erling Smørgrav r = snprintf(buf, sizeof(buf), "Proxy-Authorization: " 1651*bc5531deSDag-Erling Smørgrav "Basic %s\r\n", resp); 1652*bc5531deSDag-Erling Smørgrav if (r == -1 || (size_t)r >= sizeof(buf)) 1653*bc5531deSDag-Erling Smørgrav errx(1, "Proxy auth response too long"); 1654*bc5531deSDag-Erling Smørgrav r = strlen(buf); 1655*bc5531deSDag-Erling Smørgrav if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != (size_t)r) 1656*bc5531deSDag-Erling Smørgrav err(1, "write failed (%zu/%d)", cnt, r); 1657*bc5531deSDag-Erling Smørgrav } 1658*bc5531deSDag-Erling Smørgrav 1659*bc5531deSDag-Erling Smørgrav /* Terminate headers */ 1660*bc5531deSDag-Erling Smørgrav if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2) 1661*bc5531deSDag-Erling Smørgrav err(1, "write failed (2/%d)", r); 1662*bc5531deSDag-Erling Smørgrav 1663*bc5531deSDag-Erling Smørgrav /* Read status reply */ 1664*bc5531deSDag-Erling Smørgrav proxy_read_line(proxyfd, buf, sizeof(buf)); 1665*bc5531deSDag-Erling Smørgrav if (proxyuser != NULL && 1666*bc5531deSDag-Erling Smørgrav strncmp(buf, "HTTP/1.0 407 ", 12) == 0) { 1667*bc5531deSDag-Erling Smørgrav if (authretry > 1) { 1668*bc5531deSDag-Erling Smørgrav fprintf(stderr, "Proxy authentication " 1669*bc5531deSDag-Erling Smørgrav "failed\n"); 1670*bc5531deSDag-Erling Smørgrav } 1671*bc5531deSDag-Erling Smørgrav close(proxyfd); 1672*bc5531deSDag-Erling Smørgrav goto again; 1673*bc5531deSDag-Erling Smørgrav } else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0 && 1674*bc5531deSDag-Erling Smørgrav strncmp(buf, "HTTP/1.1 200 ", 12) != 0) 1675*bc5531deSDag-Erling Smørgrav errx(1, "Proxy error: \"%s\"", buf); 1676*bc5531deSDag-Erling Smørgrav 1677*bc5531deSDag-Erling Smørgrav /* Headers continue until we hit an empty line */ 1678*bc5531deSDag-Erling Smørgrav for (r = 0; r < HTTP_MAXHDRS; r++) { 1679*bc5531deSDag-Erling Smørgrav proxy_read_line(proxyfd, buf, sizeof(buf)); 1680*bc5531deSDag-Erling Smørgrav if (*buf == '\0') 1681*bc5531deSDag-Erling Smørgrav break; 1682*bc5531deSDag-Erling Smørgrav } 1683*bc5531deSDag-Erling Smørgrav if (*buf != '\0') 1684*bc5531deSDag-Erling Smørgrav errx(1, "Too many proxy headers received"); 1685*bc5531deSDag-Erling Smørgrav } else 1686*bc5531deSDag-Erling Smørgrav errx(1, "Unknown proxy protocol %d", socksv); 1687*bc5531deSDag-Erling Smørgrav 1688*bc5531deSDag-Erling Smørgrav return (proxyfd); 1689*bc5531deSDag-Erling Smørgrav } 1690*bc5531deSDag-Erling Smørgrav 1691