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