xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/nc/netcat.c (revision 14a66e5a5df38a62990b14d0672ff8f6f55caa09)
1 /* $OpenBSD: netcat.c,v 1.89 2007/02/20 14:11:17 jmc Exp $ */
2 /*
3  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *   derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Re-written nc(1) for OpenBSD. Original implementation by
31  * *Hobbit* <hobbit@avian.org>.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/time.h>
39 #include <sys/un.h>
40 
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/tcp.h>
44 #include <netinet/ip.h>
45 #include <arpa/telnet.h>
46 
47 #include <err.h>
48 #include <errno.h>
49 #include <netdb.h>
50 #include <poll.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <fcntl.h>
57 #include <limits.h>
58 #include <signal.h>
59 
60 #include "atomicio.h"
61 #include "strtonum.h"
62 
63 #ifndef	SUN_LEN
64 #define	SUN_LEN(su) \
65 	(sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
66 #endif
67 
68 #define	PORT_MIN	1
69 #define	PORT_MAX	65535
70 #define	PORT_MAX_LEN	6
71 
72 /* Command Line Options */
73 int	dflag;		/* detached, no stdin */
74 unsigned int iflag;	/* Interval Flag */
75 int	kflag;		/* More than one connect */
76 int	lflag;		/* Bind to local port */
77 int	nflag;		/* Don't do name lookup */
78 char	*Pflag;		/* Proxy username */
79 char	*pflag;		/* Localport flag */
80 int	rflag;		/* Random ports flag */
81 char	*sflag;		/* Source Address */
82 int	tflag;		/* Telnet Emulation */
83 int	uflag;		/* UDP - Default to TCP */
84 int	vflag;		/* Verbosity */
85 int	xflag;		/* Socks proxy */
86 int	Xflag;		/* indicator of Socks version set */
87 int	zflag;		/* Port Scan Flag */
88 int	Dflag;		/* sodebug */
89 int	Tflag = -1;	/* IP Type of Service */
90 
91 int	timeout = -1;
92 int	family = AF_UNSPEC;
93 char	*portlist[PORT_MAX+1];
94 
95 void	atelnet(int, unsigned char *, unsigned int);
96 void	build_ports(char *);
97 void	help(void);
98 int	local_listen(char *, char *, struct addrinfo);
99 void	readwrite(int);
100 int	remote_connect(const char *, const char *, struct addrinfo);
101 int	socks_connect(const char *, const char *,
102 	    const char *, const char *, struct addrinfo, int, const char *);
103 int	udptest(int);
104 int	unix_connect(char *);
105 int	unix_listen(char *);
106 void	set_common_sockopts(int);
107 int	parse_iptos(char *);
108 void	usage(int);
109 
110 int
111 main(int argc, char *argv[])
112 {
113 	int ch, s, ret, socksv;
114 	char *host, *uport, *proxy;
115 	struct addrinfo hints;
116 	struct servent *sv;
117 	socklen_t len;
118 	struct sockaddr_storage cliaddr;
119 	const char *errstr, *proxyhost = "", *proxyport = NULL;
120 	struct addrinfo proxyhints;
121 
122 	ret = 1;
123 	s = 0;
124 	socksv = 5;
125 	host = NULL;
126 	uport = NULL;
127 	sv = NULL;
128 
129 	while ((ch = getopt(argc, argv,
130 	    "46Ddhi:klnP:p:rs:T:tUuvw:X:x:z")) != -1) {
131 		switch (ch) {
132 		case '4':
133 			family = AF_INET;
134 			break;
135 		case '6':
136 			family = AF_INET6;
137 			break;
138 		case 'U':
139 			family = AF_UNIX;
140 			break;
141 		case 'X':
142 			Xflag = 1;
143 			if (strcasecmp(optarg, "connect") == 0)
144 				socksv = -1; /* HTTP proxy CONNECT */
145 			else if (strcmp(optarg, "4") == 0)
146 				socksv = 4; /* SOCKS v.4 */
147 			else if (strcmp(optarg, "5") == 0)
148 				socksv = 5; /* SOCKS v.5 */
149 			else
150 				errx(1, "unsupported proxy protocol");
151 			break;
152 		case 'd':
153 			dflag = 1;
154 			break;
155 		case 'h':
156 			help();
157 			break;
158 		case 'i':
159 			iflag = strtonum(optarg, 0, UINT_MAX, &errstr);
160 			if (errstr)
161 				errx(1, "interval %s: %s", errstr, optarg);
162 			break;
163 		case 'k':
164 			kflag = 1;
165 			break;
166 		case 'l':
167 			lflag = 1;
168 			break;
169 		case 'n':
170 			nflag = 1;
171 			break;
172 		case 'P':
173 			Pflag = optarg;
174 			break;
175 		case 'p':
176 			pflag = optarg;
177 			break;
178 		case 'r':
179 			rflag = 1;
180 			break;
181 		case 's':
182 			sflag = optarg;
183 			break;
184 		case 't':
185 			tflag = 1;
186 			break;
187 		case 'u':
188 			uflag = 1;
189 			break;
190 		case 'v':
191 			vflag = 1;
192 			break;
193 		case 'w':
194 			timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
195 			if (errstr)
196 				errx(1, "timeout %s: %s", errstr, optarg);
197 			timeout *= 1000;
198 			break;
199 		case 'x':
200 			xflag = 1;
201 			if ((proxy = strdup(optarg)) == NULL)
202 				err(1, NULL);
203 			break;
204 		case 'z':
205 			zflag = 1;
206 			break;
207 		case 'D':
208 			Dflag = 1;
209 			break;
210 		case 'T':
211 			Tflag = parse_iptos(optarg);
212 			break;
213 		default:
214 			usage(1);
215 		}
216 	}
217 	argc -= optind;
218 	argv += optind;
219 
220 	/* Cruft to make sure options are clean, and used properly. */
221 	if (argv[0] && !argv[1] && family == AF_UNIX) {
222 		if (uflag)
223 			errx(1, "cannot use -u and -U");
224 		host = argv[0];
225 		uport = NULL;
226 	} else if (argv[0] && !argv[1]) {
227 		if (!lflag)
228 			usage(1);
229 		uport = argv[0];
230 		host = NULL;
231 	} else if (argv[0] && argv[1]) {
232 		if (family == AF_UNIX)
233 			usage(1);
234 		host = argv[0];
235 		uport = argv[1];
236 	} else {
237 		if (!(lflag && pflag))
238 			usage(1);
239 	}
240 
241 	if (lflag && sflag)
242 		errx(1, "cannot use -s and -l");
243 	if (lflag && rflag)
244 		errx(1, "cannot use -r and -l");
245 	if (lflag && pflag) {
246 		if (uport)
247 			usage(1);
248 		uport = pflag;
249 	}
250 	if (lflag && zflag)
251 		errx(1, "cannot use -z and -l");
252 	if (!lflag && kflag)
253 		errx(1, "must use -l with -k");
254 	if (lflag && (Pflag || xflag || Xflag))
255 		errx(1, "cannot use -l with -P, -X or -x");
256 
257 	/* Initialize addrinfo structure. */
258 	if (family != AF_UNIX) {
259 		(void) memset(&hints, 0, sizeof (struct addrinfo));
260 		hints.ai_family = family;
261 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
262 		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
263 		if (nflag)
264 			hints.ai_flags |= AI_NUMERICHOST;
265 	}
266 
267 	if (xflag) {
268 		if (uflag)
269 			errx(1, "no proxy support for UDP mode");
270 
271 		if (lflag)
272 			errx(1, "no proxy support for listen");
273 
274 		if (family == AF_UNIX)
275 			errx(1, "no proxy support for unix sockets");
276 
277 		if (family == AF_INET6)
278 			errx(1, "no proxy support for IPv6");
279 
280 		if (sflag)
281 			errx(1, "no proxy support for local source address");
282 
283 		if ((proxyhost = strtok(proxy, ":")) == NULL)
284 			errx(1, "missing port specification");
285 		proxyport = strtok(NULL, ":");
286 
287 		(void) memset(&proxyhints, 0, sizeof (struct addrinfo));
288 		proxyhints.ai_family = family;
289 		proxyhints.ai_socktype = SOCK_STREAM;
290 		proxyhints.ai_protocol = IPPROTO_TCP;
291 		if (nflag)
292 			proxyhints.ai_flags |= AI_NUMERICHOST;
293 	}
294 
295 	if (lflag) {
296 		int connfd;
297 		ret = 0;
298 
299 		if (family == AF_UNIX)
300 			s = unix_listen(host);
301 
302 		/* Allow only one connection at a time, but stay alive. */
303 		for (;;) {
304 			if (family != AF_UNIX)
305 				s = local_listen(host, uport, hints);
306 			if (s < 0)
307 				err(1, NULL);
308 			/*
309 			 * For UDP, we will use recvfrom() initially
310 			 * to wait for a caller, then use the regular
311 			 * functions to talk to the caller.
312 			 */
313 			if (uflag) {
314 				int rv, plen;
315 				char buf[8192];
316 				struct sockaddr_storage z;
317 
318 				len = sizeof (z);
319 				plen = 1024;
320 				rv = recvfrom(s, buf, plen, MSG_PEEK,
321 				    (struct sockaddr *)&z, &len);
322 				if (rv < 0)
323 					err(1, "recvfrom");
324 
325 				rv = connect(s, (struct sockaddr *)&z, len);
326 				if (rv < 0)
327 					err(1, "connect");
328 
329 				connfd = s;
330 			} else {
331 				len = sizeof (cliaddr);
332 				connfd = accept(s, (struct sockaddr *)&cliaddr,
333 				    &len);
334 			}
335 
336 			readwrite(connfd);
337 			(void) close(connfd);
338 			if (family != AF_UNIX)
339 				(void) close(s);
340 
341 			if (!kflag)
342 				break;
343 		}
344 	} else if (family == AF_UNIX) {
345 		ret = 0;
346 
347 		if ((s = unix_connect(host)) > 0 && !zflag) {
348 			readwrite(s);
349 			(void) close(s);
350 		} else
351 			ret = 1;
352 
353 		exit(ret);
354 
355 	} else {	/* AF_INET or AF_INET6 */
356 		int i = 0;
357 
358 		/* Construct the portlist[] array. */
359 		build_ports(uport);
360 
361 		/* Cycle through portlist, connecting to each port. */
362 		for (i = 0; portlist[i] != NULL; i++) {
363 			if (s)
364 				(void) close(s);
365 
366 			if (xflag)
367 				s = socks_connect(host, portlist[i],
368 				    proxyhost, proxyport, proxyhints, socksv,
369 				    Pflag);
370 			else
371 				s = remote_connect(host, portlist[i], hints);
372 
373 			if (s < 0)
374 				continue;
375 
376 			ret = 0;
377 			if (vflag || zflag) {
378 				/* For UDP, make sure we are connected. */
379 				if (uflag) {
380 					if (udptest(s) == -1) {
381 						ret = 1;
382 						continue;
383 					}
384 				}
385 
386 				/* Don't look up port if -n. */
387 				if (nflag)
388 					sv = NULL;
389 				else {
390 					sv = getservbyport(
391 					    ntohs(atoi(portlist[i])),
392 					    uflag ? "udp" : "tcp");
393 				}
394 
395 				(void) printf("Connection to %s %s "
396 				    "port [%s/%s] succeeded!\n",
397 				    host, portlist[i], uflag ? "udp" : "tcp",
398 				    sv ? sv->s_name : "*");
399 			}
400 			if (!zflag)
401 				readwrite(s);
402 		}
403 	}
404 
405 	if (s)
406 		(void) close(s);
407 
408 	return (ret);
409 }
410 
411 /*
412  * unix_connect()
413  * Returns a socket connected to a local unix socket. Returns -1 on failure.
414  */
415 int
416 unix_connect(char *path)
417 {
418 	struct sockaddr_un sunaddr;
419 	int s;
420 
421 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
422 		return (-1);
423 
424 	(void) memset(&sunaddr, 0, sizeof (struct sockaddr_un));
425 	sunaddr.sun_family = AF_UNIX;
426 
427 	if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >=
428 	    sizeof (sunaddr.sun_path)) {
429 		(void) close(s);
430 		errno = ENAMETOOLONG;
431 		return (-1);
432 	}
433 	if (connect(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) {
434 		(void) close(s);
435 		return (-1);
436 	}
437 	return (s);
438 }
439 
440 /*
441  * unix_listen()
442  * Create a unix domain socket, and listen on it.
443  */
444 int
445 unix_listen(char *path)
446 {
447 	struct sockaddr_un sunaddr;
448 	int s;
449 
450 	/* Create unix domain socket. */
451 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
452 		return (-1);
453 
454 	(void) memset(&sunaddr, 0, sizeof (struct sockaddr_un));
455 	sunaddr.sun_family = AF_UNIX;
456 
457 	if (strlcpy(sunaddr.sun_path, path, sizeof (sunaddr.sun_path)) >=
458 	    sizeof (sunaddr.sun_path)) {
459 		(void) close(s);
460 		errno = ENAMETOOLONG;
461 		return (-1);
462 	}
463 
464 	if (bind(s, (struct sockaddr *)&sunaddr, SUN_LEN(&sunaddr)) < 0) {
465 		(void) close(s);
466 		return (-1);
467 	}
468 
469 	if (listen(s, 5) < 0) {
470 		(void) close(s);
471 		return (-1);
472 	}
473 	return (s);
474 }
475 
476 /*
477  * remote_connect()
478  * Returns a socket connected to a remote host. Properly binds to a local
479  * port or source address if needed. Returns -1 on failure.
480  */
481 int
482 remote_connect(const char *host, const char *port, struct addrinfo hints)
483 {
484 	struct addrinfo *res, *res0;
485 	int s, error;
486 
487 	if ((error = getaddrinfo(host, port, &hints, &res)))
488 		errx(1, "getaddrinfo: %s", gai_strerror(error));
489 
490 	res0 = res;
491 	do {
492 		if ((s = socket(res0->ai_family, res0->ai_socktype,
493 		    res0->ai_protocol)) < 0) {
494 			warn("failed to create socket");
495 			continue;
496 		}
497 
498 		/* Bind to a local port or source address if specified. */
499 		if (sflag || pflag) {
500 			struct addrinfo ahints, *ares;
501 
502 			(void) memset(&ahints, 0, sizeof (struct addrinfo));
503 			ahints.ai_family = res0->ai_family;
504 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
505 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
506 			ahints.ai_flags = AI_PASSIVE;
507 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
508 				errx(1, "getaddrinfo: %s", gai_strerror(error));
509 
510 			if (bind(s, (struct sockaddr *)ares->ai_addr,
511 			    ares->ai_addrlen) < 0)
512 				errx(1, "bind failed: %s", strerror(errno));
513 			freeaddrinfo(ares);
514 		}
515 
516 		set_common_sockopts(s);
517 
518 		if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
519 			break;
520 		else if (vflag)
521 			warn("connect to %s port %s (%s) failed", host, port,
522 			    uflag ? "udp" : "tcp");
523 
524 		(void) close(s);
525 		s = -1;
526 	} while ((res0 = res0->ai_next) != NULL);
527 
528 	freeaddrinfo(res);
529 
530 	return (s);
531 }
532 
533 /*
534  * local_listen()
535  * Returns a socket listening on a local port, binds to specified source
536  * address. Returns -1 on failure.
537  */
538 int
539 local_listen(char *host, char *port, struct addrinfo hints)
540 {
541 	struct addrinfo *res, *res0;
542 	int s, ret, x = 1;
543 	int error;
544 
545 	/* Allow nodename to be null. */
546 	hints.ai_flags |= AI_PASSIVE;
547 
548 	/*
549 	 * In the case of binding to a wildcard address
550 	 * default to binding to an ipv4 address.
551 	 */
552 	if (host == NULL && hints.ai_family == AF_UNSPEC)
553 		hints.ai_family = AF_INET;
554 
555 	if ((error = getaddrinfo(host, port, &hints, &res)))
556 		errx(1, "getaddrinfo: %s", gai_strerror(error));
557 
558 	res0 = res;
559 	do {
560 		if ((s = socket(res0->ai_family, res0->ai_socktype,
561 		    res0->ai_protocol)) < 0) {
562 			warn("failed to create socket");
563 			continue;
564 		}
565 
566 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
567 		if (ret == -1)
568 			err(1, NULL);
569 
570 		set_common_sockopts(s);
571 
572 		if (bind(s, (struct sockaddr *)res0->ai_addr,
573 		    res0->ai_addrlen) == 0)
574 			break;
575 
576 		(void) close(s);
577 		s = -1;
578 	} while ((res0 = res0->ai_next) != NULL);
579 
580 	if (!uflag && s != -1) {
581 		if (listen(s, 1) < 0)
582 			err(1, "listen");
583 	}
584 
585 	freeaddrinfo(res);
586 
587 	return (s);
588 }
589 
590 /*
591  * readwrite()
592  * Loop that polls on the network file descriptor and stdin.
593  */
594 void
595 readwrite(int nfd)
596 {
597 	struct pollfd pfd[2];
598 	unsigned char buf[8192];
599 	int n, wfd = fileno(stdin);
600 	int lfd = fileno(stdout);
601 	int plen;
602 
603 	plen = 1024;
604 
605 	/* Setup Network FD */
606 	pfd[0].fd = nfd;
607 	pfd[0].events = POLLIN;
608 
609 	/* Set up STDIN FD. */
610 	pfd[1].fd = wfd;
611 	pfd[1].events = POLLIN;
612 
613 	while (pfd[0].fd != -1) {
614 		if (iflag)
615 			(void) sleep(iflag);
616 
617 		if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
618 			(void) close(nfd);
619 			err(1, "Polling Error");
620 		}
621 
622 		if (n == 0)
623 			return;
624 
625 		if (pfd[0].revents & (POLLIN|POLLHUP)) {
626 			if ((n = read(nfd, buf, plen)) < 0)
627 				return;
628 			else if (n == 0) {
629 				(void) shutdown(nfd, SHUT_RD);
630 				pfd[0].fd = -1;
631 				pfd[0].events = 0;
632 			} else {
633 				if (tflag)
634 					atelnet(nfd, buf, n);
635 				if (atomicio(vwrite, lfd, buf, n) != n)
636 					return;
637 			}
638 		}
639 
640 		/*
641 		 * handle the case of disconnected pipe: after pipe
642 		 * is closed (indicated by POLLHUP) there may still
643 		 * be some data lingering (POLLIN). After we read
644 		 * the data, only POLLHUP remains, read() returns 0
645 		 * and we are finished.
646 		 */
647 		if (!dflag && (pfd[1].revents & (POLLIN|POLLHUP))) {
648 			if ((n = read(wfd, buf, plen)) < 0)
649 				return;
650 			else if (n == 0) {
651 				(void) shutdown(nfd, SHUT_WR);
652 				pfd[1].fd = -1;
653 				pfd[1].events = 0;
654 			} else {
655 				if (atomicio(vwrite, nfd, buf, n) != n)
656 					return;
657 			}
658 		}
659 	}
660 }
661 
662 /* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
663 void
664 atelnet(int nfd, unsigned char *buf, unsigned int size)
665 {
666 	unsigned char *p, *end;
667 	unsigned char obuf[4];
668 
669 	end = buf + size;
670 	obuf[0] = '\0';
671 
672 	for (p = buf; p < end; p++) {
673 		if (*p != IAC)
674 			break;
675 
676 		obuf[0] = IAC;
677 		obuf[1] = 0;
678 		p++;
679 		/* refuse all options */
680 		if ((*p == WILL) || (*p == WONT))
681 			obuf[1] = DONT;
682 		if ((*p == DO) || (*p == DONT))
683 			obuf[1] = WONT;
684 		if (obuf[1]) {
685 			p++;
686 			obuf[2] = *p;
687 			obuf[3] = '\0';
688 			if (atomicio(vwrite, nfd, obuf, 3) != 3)
689 				warn("Write Error!");
690 			obuf[0] = '\0';
691 		}
692 	}
693 }
694 
695 /*
696  * build_ports()
697  * Build an array of ports in portlist[], listing each port
698  * that we should try to connect to.
699  */
700 void
701 build_ports(char *p)
702 {
703 	const char *errstr;
704 	char *n;
705 	int hi, lo, cp;
706 	int x = 0;
707 
708 	if ((n = strchr(p, '-')) != NULL) {
709 		if (lflag)
710 			errx(1, "Cannot use -l with multiple ports!");
711 
712 		*n = '\0';
713 		n++;
714 
715 		/* Make sure the ports are in order: lowest->highest. */
716 		hi = strtonum(n, PORT_MIN, PORT_MAX, &errstr);
717 		if (errstr)
718 			errx(1, "port number %s: %s", errstr, n);
719 		lo = strtonum(p, PORT_MIN, PORT_MAX, &errstr);
720 		if (errstr)
721 			errx(1, "port number %s: %s", errstr, p);
722 
723 		if (lo > hi) {
724 			cp = hi;
725 			hi = lo;
726 			lo = cp;
727 		}
728 
729 		/* Load ports sequentially. */
730 		for (cp = lo; cp <= hi; cp++) {
731 			portlist[x] = calloc(1, PORT_MAX_LEN);
732 			if (portlist[x] == NULL)
733 				err(1, NULL);
734 			(void) snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
735 			x++;
736 		}
737 
738 		/* Randomly swap ports. */
739 		if (rflag) {
740 			int y;
741 			char *c;
742 
743 			srandom(time((time_t *)0));
744 
745 			for (x = 0; x <= (hi - lo); x++) {
746 				y = (random() & 0xFFFF) % (hi - lo);
747 				c = portlist[x];
748 				portlist[x] = portlist[y];
749 				portlist[y] = c;
750 			}
751 		}
752 	} else {
753 		hi = strtonum(p, PORT_MIN, PORT_MAX, &errstr);
754 		if (errstr)
755 			errx(1, "port number %s: %s", errstr, p);
756 		portlist[0] = calloc(1, PORT_MAX_LEN);
757 		if (portlist[0] == NULL)
758 			err(1, NULL);
759 		portlist[0] = p;
760 	}
761 }
762 
763 /*
764  * udptest()
765  * Do a few writes to see if the UDP port is there.
766  * XXX - Better way of doing this? Doesn't work for IPv6.
767  * Also fails after around 100 ports checked.
768  */
769 int
770 udptest(int s)
771 {
772 	int i, ret;
773 
774 	for (i = 0; i <= 3; i++) {
775 		if (write(s, "X", 1) == 1)
776 			ret = 1;
777 		else
778 			ret = -1;
779 	}
780 	return (ret);
781 }
782 
783 void
784 set_common_sockopts(int s)
785 {
786 	int x = 1;
787 
788 	if (Dflag) {
789 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG, &x, sizeof (x)) == -1)
790 			err(1, NULL);
791 	}
792 	if (Tflag != -1) {
793 		if (setsockopt(s, IPPROTO_IP, IP_TOS, &Tflag,
794 		    sizeof (Tflag)) == -1)
795 			err(1, "set IP ToS");
796 	}
797 }
798 
799 int
800 parse_iptos(char *s)
801 {
802 	int tos = -1;
803 
804 	if (strcmp(s, "lowdelay") == 0)
805 		return (IPTOS_LOWDELAY);
806 	if (strcmp(s, "throughput") == 0)
807 		return (IPTOS_THROUGHPUT);
808 	if (strcmp(s, "reliability") == 0)
809 		return (IPTOS_RELIABILITY);
810 
811 	if (sscanf(s, "0x%x", (unsigned int *) &tos) != 1 ||
812 	    tos < 0 || tos > 0xff)
813 		errx(1, "invalid IP Type of Service");
814 	return (tos);
815 }
816 
817 void
818 help(void)
819 {
820 	usage(0);
821 	(void) fprintf(stderr, "\tCommand Summary:\n\
822 	\t-4		Use IPv4\n\
823 	\t-6		Use IPv6\n\
824 	\t-D		Enable the debug socket option\n\
825 	\t-d		Detach from stdin\n\
826 	\t-h		This help text\n\
827 	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
828 	\t-k		Keep inbound sockets open for multiple connects\n\
829 	\t-l		Listen mode, for inbound connects\n\
830 	\t-n		Suppress name/port resolutions\n\
831 	\t-P proxyuser\tUsername for proxy authentication\n\
832 	\t-p port\t	Specify local port or listen port\n\
833 	\t-r		Randomize remote ports\n\
834 	\t-s addr\t	Local source address\n\
835 	\t-T ToS\t	Set IP Type of Service\n\
836 	\t-t		Answer TELNET negotiation\n\
837 	\t-U		Use UNIX domain socket\n\
838 	\t-u		UDP mode\n\
839 	\t-v		Verbose\n\
840 	\t-w secs\t	Timeout for connects and final net reads\n\
841 	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
842 	\t-x addr[:port]\tSpecify proxy address and port\n\
843 	\t-z		Zero-I/O mode [used for scanning]\n\
844 	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
845 	exit(1);
846 }
847 
848 void
849 usage(int ret)
850 {
851 	(void) fprintf(stderr,
852 	    "usage: nc [-46DdhklnrtUuvz] [-i interval] [-P proxy_username]"
853 	    " [-p port]\n");
854 	(void) fprintf(stderr,
855 	    "\t  [-s source_ip_address] [-T ToS] [-w timeout]"
856 	    " [-X proxy_protocol]\n");
857 	(void) fprintf(stderr,
858 	    "\t  [-x proxy_address[:port]] [hostname]"
859 	    " [port[s]]\n");
860 	if (ret)
861 		exit(1);
862 }
863