xref: /openbsd-src/usr.bin/nc/netcat.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /* $OpenBSD: netcat.c,v 1.62 2003/07/25 21:35:16 millert 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 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <sys/un.h>
38 
39 #include <netinet/in.h>
40 #include <arpa/telnet.h>
41 
42 #include <err.h>
43 #include <errno.h>
44 #include <netdb.h>
45 #include <poll.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 
53 #ifndef SUN_LEN
54 #define SUN_LEN(su) \
55 	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
56 #endif
57 
58 #define PORT_MAX	65535
59 #define PORT_MAX_LEN	6
60 
61 /* Command Line Options */
62 int	iflag;					/* Interval Flag */
63 int	kflag;					/* More than one connect */
64 int	lflag;					/* Bind to local port */
65 int	nflag;					/* Dont do name lookup */
66 char   *pflag;					/* Localport flag */
67 int	rflag;					/* Random ports flag */
68 char   *sflag;					/* Source Address */
69 int	tflag;					/* Telnet Emulation */
70 int	uflag;					/* UDP - Default to TCP */
71 int	vflag;					/* Verbosity */
72 int	xflag;					/* Socks proxy */
73 int	zflag;					/* Port Scan Flag */
74 
75 int timeout = -1;
76 int family = AF_UNSPEC;
77 char *portlist[PORT_MAX];
78 
79 ssize_t	atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
80 void	atelnet(int, unsigned char *, unsigned int);
81 void	build_ports(char *);
82 void	help(void);
83 int	local_listen(char *, char *, struct addrinfo);
84 void	readwrite(int);
85 int	remote_connect(char *, char *, struct addrinfo);
86 int	socks_connect(char *, char *, struct addrinfo, char *, char *,
87 	struct addrinfo, int);
88 int	udptest(int);
89 int	unix_connect(char *);
90 int	unix_listen(char *);
91 void	usage(int);
92 
93 int
94 main(int argc, char *argv[])
95 {
96 	int ch, s, ret, socksv;
97 	char *host, *uport, *endp;
98 	struct addrinfo hints;
99 	struct servent *sv;
100 	socklen_t len;
101 	struct sockaddr *cliaddr;
102 	char *proxy;
103 	char *proxyhost = "", *proxyport = NULL;
104 	struct addrinfo proxyhints;
105 
106 	ret = 1;
107 	s = 0;
108 	socksv = 5;
109 	host = NULL;
110 	uport = NULL;
111 	endp = NULL;
112 	sv = NULL;
113 
114 	while ((ch = getopt(argc, argv, "46UX:hi:klnp:rs:tuvw:x:z")) != -1) {
115 		switch (ch) {
116 		case '4':
117 			family = AF_INET;
118 			break;
119 		case '6':
120 			family = AF_INET6;
121 			break;
122 		case 'U':
123 			family = AF_UNIX;
124 			break;
125 		case 'X':
126 			socksv = (int)strtoul(optarg, &endp, 10);
127 			if ((socksv != 4 && socksv != 5) || *endp != '\0')
128 				errx(1, "only SOCKS version 4 and 5 supported");
129 			break;
130 		case 'h':
131 			help();
132 			break;
133 		case 'i':
134 			iflag = (int)strtoul(optarg, &endp, 10);
135 			if (iflag < 0 || *endp != '\0')
136 				errx(1, "interval cannot be negative");
137 			break;
138 		case 'k':
139 			kflag = 1;
140 			break;
141 		case 'l':
142 			lflag = 1;
143 			break;
144 		case 'n':
145 			nflag = 1;
146 			break;
147 		case 'p':
148 			pflag = optarg;
149 			break;
150 		case 'r':
151 			rflag = 1;
152 			break;
153 		case 's':
154 			sflag = optarg;
155 			break;
156 		case 't':
157 			tflag = 1;
158 			break;
159 		case 'u':
160 			uflag = 1;
161 			break;
162 		case 'v':
163 			vflag = 1;
164 			break;
165 		case 'w':
166 			timeout = (int)strtoul(optarg, &endp, 10);
167 			if (timeout < 0 || *endp != '\0')
168 				errx(1, "timeout cannot be negative");
169 			if (timeout >= (INT_MAX / 1000))
170 				errx(1, "timeout too large");
171 			timeout *= 1000;
172 			break;
173 		case 'x':
174 			xflag = 1;
175 			proxy = strdup(optarg);
176 			break;
177 		case 'z':
178 			zflag = 1;
179 			break;
180 		default:
181 			usage(1);
182 		}
183 	}
184 	argc -= optind;
185 	argv += optind;
186 
187 	/* Cruft to make sure options are clean, and used properly. */
188 	if (argv[0] && !argv[1] && family == AF_UNIX) {
189 		if (uflag)
190 			errx(1, "cannot use -u and -U");
191 		host = argv[0];
192 		uport = NULL;
193 	} else if (argv[0] && !argv[1]) {
194 		if  (!lflag)
195 			usage(1);
196 		uport = argv[0];
197 		host = NULL;
198 	} else if (argv[0] && argv[1]) {
199 		host = argv[0];
200 		uport = argv[1];
201 	} else
202 		usage(1);
203 
204 	if (lflag && sflag)
205 		errx(1, "cannot use -s and -l");
206 	if (lflag && pflag)
207 		errx(1, "cannot use -p and -l");
208 	if (lflag && zflag)
209 		errx(1, "cannot use -z and -l");
210 	if (!lflag && kflag)
211 		errx(1, "must use -l with -k");
212 
213 	/* Initialize addrinfo structure */
214 	if (family != AF_UNIX) {
215 		memset(&hints, 0, sizeof(struct addrinfo));
216 		hints.ai_family = family;
217 		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
218 		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
219 		if (nflag)
220 			hints.ai_flags |= AI_NUMERICHOST;
221 	}
222 
223 	if (xflag) {
224 		if (uflag)
225 			errx(1, "no proxy support for UDP mode");
226 
227 		if (lflag)
228 			errx(1, "no proxy support for listen");
229 
230 		if (family == AF_UNIX)
231 			errx(1, "no proxy support for unix sockets");
232 
233 		/* XXX IPv6 transport to proxy would probably work */
234 		if (family == AF_INET6)
235 			errx(1, "no proxy support for IPv6");
236 
237 		if (sflag)
238 			errx(1, "no proxy support for local source address");
239 
240 		proxyhost = strsep(&proxy, ":");
241 		proxyport = proxy;
242 
243 		memset(&proxyhints, 0, sizeof(struct addrinfo));
244 		proxyhints.ai_family = family;
245 		proxyhints.ai_socktype = SOCK_STREAM;
246 		proxyhints.ai_protocol = IPPROTO_TCP;
247 		if (nflag)
248 			proxyhints.ai_flags |= AI_NUMERICHOST;
249 	}
250 
251 	if (lflag) {
252 		int connfd;
253 		ret = 0;
254 
255 		if (family == AF_UNIX)
256 			s = unix_listen(host);
257 
258 		/* Allow only one connection at a time, but stay alive */
259 		for (;;) {
260 			if (family != AF_UNIX)
261 				s = local_listen(host, uport, hints);
262 			if (s < 0)
263 				err(1, NULL);
264 			/*
265 			 * For UDP, we will use recvfrom() initially
266 			 * to wait for a caller, then use the regular
267 			 * functions to talk to the caller.
268 			 */
269 			if (uflag) {
270 				int rv;
271 				char buf[1024];
272 				struct sockaddr_storage z;
273 
274 				len = sizeof(z);
275 				rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
276 				    (struct sockaddr *)&z, &len);
277 				if (rv < 0)
278 					err(1, "recvfrom");
279 
280 				rv = connect(s, (struct sockaddr *)&z, len);
281 				if (rv < 0)
282 					err(1, "connect");
283 
284 				connfd = s;
285 			} else {
286 				connfd = accept(s, (struct sockaddr *)&cliaddr,
287 				    &len);
288 			}
289 
290 			readwrite(connfd);
291 			close(connfd);
292 			if (family != AF_UNIX)
293 				close(s);
294 
295 			if (!kflag)
296 				break;
297 		}
298 	} else if (family == AF_UNIX) {
299 		ret = 0;
300 
301 		if ((s = unix_connect(host)) > 0 && !zflag) {
302 			readwrite(s);
303 			close(s);
304 		} else
305 			ret = 1;
306 
307 		exit(ret);
308 
309 	} else {
310 		int i = 0;
311 
312 		/* construct the portlist[] array */
313 		build_ports(uport);
314 
315 		/* Cycle through portlist, connecting to each port */
316 		for (i = 0; portlist[i] != NULL; i++) {
317 			if (s)
318 				close(s);
319 
320 			if (xflag)
321 				s = socks_connect(host, portlist[i], hints,
322 				    proxyhost, proxyport, proxyhints, socksv);
323 			else
324 				s = remote_connect(host, portlist[i], hints);
325 
326 			if (s < 0)
327 				continue;
328 
329 			ret = 0;
330 			if (vflag || zflag) {
331 				/* For UDP, make sure we are connected */
332 				if (uflag) {
333 					if (udptest(s) == -1) {
334 						ret = 1;
335 						continue;
336 					}
337 				}
338 
339 				/* Don't lookup port if -n */
340 				if (nflag)
341 					sv = NULL;
342 				else {
343 					sv = getservbyport(
344 					    ntohs(atoi(portlist[i])),
345 					    uflag ? "udp" : "tcp");
346 				}
347 
348 				printf("Connection to %s %s port [%s/%s] succeeded!\n",
349 				    host, portlist[i], uflag ? "udp" : "tcp",
350 				    sv ? sv->s_name : "*");
351 			}
352 			if (!zflag)
353 				readwrite(s);
354 		}
355 	}
356 
357 	if (s)
358 		close(s);
359 
360 	exit(ret);
361 }
362 
363 /*
364  * unix_connect()
365  * Return's a socket connected to a local unix socket. Return's -1 on failure.
366  */
367 int
368 unix_connect(char *path)
369 {
370 	struct sockaddr_un sun;
371 	int s;
372 
373 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
374 		return (-1);
375 	(void)fcntl(s, F_SETFD, 1);
376 
377 	memset(&sun, 0, sizeof(struct sockaddr_un));
378 	sun.sun_family = AF_UNIX;
379 
380 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
381 	    sizeof(sun.sun_path)) {
382 		close(s);
383 		errno = ENAMETOOLONG;
384 		return (-1);
385 	}
386 	if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
387 		close(s);
388 		return (-1);
389 	}
390 	return (s);
391 
392 }
393 
394 /*
395  * unix_listen()
396  * create a unix domain socket, and listen on it.
397  */
398 int
399 unix_listen(char *path)
400 {
401 	struct sockaddr_un sun;
402 	int s;
403 
404 	/* create unix domain socket */
405 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
406 		return (-1);
407 
408 	memset(&sun, 0, sizeof(struct sockaddr_un));
409 	sun.sun_family = AF_UNIX;
410 
411 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
412 	    sizeof(sun.sun_path)) {
413 		close(s);
414 		errno = ENAMETOOLONG;
415 		return (-1);
416 	}
417 
418 	if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
419 		close(s);
420 		return (-1);
421 	}
422 
423 	if (listen(s, 5) < 0) {
424 		close(s);
425 		return (-1);
426 	}
427 	return (s);
428 }
429 
430 /*
431  * remote_connect()
432  * Return's a socket connected to a remote host. Properly bind's to a local
433  * port or source address if needed. Return's -1 on failure.
434  */
435 int
436 remote_connect(char *host, char *port, struct addrinfo hints)
437 {
438 	struct addrinfo *res, *res0;
439 	int s, error;
440 
441 	if ((error = getaddrinfo(host, port, &hints, &res)))
442 		errx(1, "getaddrinfo: %s", gai_strerror(error));
443 
444 	res0 = res;
445 	do {
446 		if ((s = socket(res0->ai_family, res0->ai_socktype,
447 		    res0->ai_protocol)) < 0)
448 			continue;
449 
450 		/* Bind to a local port or source address if specified */
451 		if (sflag || pflag) {
452 			struct addrinfo ahints, *ares;
453 
454 			if (!(sflag && pflag)) {
455 				if (!sflag)
456 					sflag = NULL;
457 				else
458 					pflag = NULL;
459 			}
460 
461 			memset(&ahints, 0, sizeof(struct addrinfo));
462 			ahints.ai_family = res0->ai_family;
463 			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
464 			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
465 			ahints.ai_flags = AI_PASSIVE;
466 			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
467 				errx(1, "getaddrinfo: %s", gai_strerror(error));
468 
469 			if (bind(s, (struct sockaddr *)ares->ai_addr,
470 			    ares->ai_addrlen) < 0)
471 				errx(1, "bind failed: %s", strerror(errno));
472 			freeaddrinfo(ares);
473 		}
474 
475 		if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
476 			break;
477 
478 		close(s);
479 		s = -1;
480 	} while ((res0 = res0->ai_next) != NULL);
481 
482 	freeaddrinfo(res);
483 
484 	return (s);
485 }
486 
487 /*
488  * local_listen()
489  * Return's a socket listening on a local port, binds to specified source
490  * address. Return's -1 on failure.
491  */
492 int
493 local_listen(char *host, char *port, struct addrinfo hints)
494 {
495 	struct addrinfo *res, *res0;
496 	int s, ret, x = 1;
497 	int error;
498 
499 	/* Allow nodename to be null */
500 	hints.ai_flags |= AI_PASSIVE;
501 
502 	/*
503 	 * In the case of binding to a wildcard address
504 	 * default to binding to an ipv4 address.
505 	 */
506 	if (host == NULL && hints.ai_family == AF_UNSPEC)
507 		hints.ai_family = AF_INET;
508 
509 	if ((error = getaddrinfo(host, port, &hints, &res)))
510                 errx(1, "getaddrinfo: %s", gai_strerror(error));
511 
512 	res0 = res;
513 	do {
514 		if ((s = socket(res0->ai_family, res0->ai_socktype,
515 		    res0->ai_protocol)) == 0)
516 			continue;
517 
518 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
519 		if (ret == -1)
520 			err(1, NULL);
521 
522 		if (bind(s, (struct sockaddr *)res0->ai_addr,
523 		    res0->ai_addrlen) == 0)
524 			break;
525 
526 		close(s);
527 		s = -1;
528 	} while ((res0 = res0->ai_next) != NULL);
529 
530 	if (!uflag && s != -1) {
531 		if (listen(s, 1) < 0)
532 			err(1, "listen");
533 	}
534 
535 	freeaddrinfo(res);
536 
537 	return (s);
538 }
539 
540 /*
541  * readwrite()
542  * Loop that polls on the network file descriptor and stdin.
543  */
544 void
545 readwrite(int nfd)
546 {
547 	struct pollfd pfd[2];
548 	char buf[BUFSIZ];
549 	int wfd = fileno(stdin), n, ret;
550 	int lfd = fileno(stdout);
551 
552 	/* Setup Network FD */
553 	pfd[0].fd = nfd;
554 	pfd[0].events = POLLIN;
555 
556 	/* Setup STDIN FD */
557 	pfd[1].fd = wfd;
558 	pfd[1].events = POLLIN;
559 
560 	while (pfd[0].fd != -1) {
561 		if (iflag)
562 			sleep(iflag);
563 
564 		if ((n = poll(pfd, 2, timeout)) < 0) {
565 			close(nfd);
566 			err(1, "Polling Error");
567 		}
568 
569 		if (n == 0)
570 			return;
571 
572 		if (pfd[0].revents & POLLIN) {
573 			if ((n = read(nfd, buf, sizeof(buf))) < 0)
574 				return;
575 			else if (n == 0) {
576 				shutdown(nfd, SHUT_RD);
577 				pfd[0].fd = -1;
578 				pfd[0].events = 0;
579 			} else {
580 				if (tflag)
581 					atelnet(nfd, buf, n);
582 				if ((ret = atomicio(
583 				    (ssize_t (*)(int, void *, size_t))write,
584 				    lfd, buf, n)) != n)
585 					return;
586 			}
587 		}
588 
589 		if (pfd[1].revents & POLLIN) {
590 			if ((n = read(wfd, buf, sizeof(buf))) < 0)
591 				return;
592 			else if (n == 0) {
593 				shutdown(nfd, SHUT_WR);
594 				pfd[1].fd = -1;
595 				pfd[1].events = 0;
596 			} else {
597 				if((ret = atomicio(
598 				    (ssize_t (*)(int, void *, size_t))write,
599 				    nfd, buf, n)) != n)
600 					return;
601 			}
602 		}
603 	}
604 }
605 
606 /* Deal with RFC854 WILL/WONT DO/DONT negotiation */
607 void
608 atelnet(int nfd, unsigned char *buf, unsigned int size)
609 {
610 	int ret;
611 	unsigned char *p, *end;
612 	unsigned char obuf[4];
613 
614 	end = buf + size;
615 	obuf[0] = '\0';
616 
617 	for (p = buf; p < end; p++) {
618 		if (*p != IAC)
619 			break;
620 
621 		obuf[0] = IAC;
622 		p++;
623 		if ((*p == WILL) || (*p == WONT))
624 			obuf[1] = DONT;
625 		if ((*p == DO) || (*p == DONT))
626 			obuf[1] = WONT;
627 		if (obuf) {
628 			p++;
629 			obuf[2] = *p;
630 			obuf[3] = '\0';
631 			if ((ret = atomicio(
632 			    (ssize_t (*)(int, void *, size_t))write,
633 			    nfd, obuf, 3)) != 3)
634 				warnx("Write Error!");
635 			obuf[0] = '\0';
636 		}
637 	}
638 }
639 
640 /*
641  * build_ports()
642  * Build an array or ports in portlist[], listing each port
643  * that we should try to connect too.
644  */
645 void
646 build_ports(char *p)
647 {
648 	char *n, *endp;
649 	int hi, lo, cp;
650 	int x = 0;
651 
652 	if ((n = strchr(p, '-')) != NULL) {
653 		if (lflag)
654 			errx(1, "Cannot use -l with multiple ports!");
655 
656 		*n = '\0';
657 		n++;
658 
659 		/* Make sure the ports are in order: lowest->highest */
660 		hi = (int)strtoul(n, &endp, 10);
661 		if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
662 			errx(1, "port range not valid");
663 		lo = (int)strtoul(p, &endp, 10);
664 		if (lo <= 0 || lo > PORT_MAX || *endp != '\0')
665 			errx(1, "port range not valid");
666 
667 		if (lo > hi) {
668 			cp = hi;
669 			hi = lo;
670 			lo = cp;
671 		}
672 
673 		/* Load ports sequentially */
674 		for (cp = lo; cp <= hi; cp++) {
675 			portlist[x] = calloc(1, PORT_MAX_LEN);
676 			if (portlist[x] == NULL)
677 				err(1, NULL);
678 			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
679 			x++;
680 		}
681 
682 		/* Randomly swap ports */
683 		if (rflag) {
684 			int y;
685 			char *c;
686 
687 			for (x = 0; x <= (hi - lo); x++) {
688 				y = (arc4random() & 0xFFFF) % (hi - lo);
689 				c = portlist[x];
690 				portlist[x] = portlist[y];
691 				portlist[y] = c;
692 			}
693 		}
694 	} else {
695 		hi = (int)strtoul(p, &endp, 10);
696 		if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
697 			errx(1, "port range not valid");
698 		portlist[0] = calloc(1, PORT_MAX_LEN);
699 		if (portlist[0] == NULL)
700 			err(1, NULL);
701 		portlist[0] = p;
702 	}
703 }
704 
705 /*
706  * udptest()
707  * Do a few writes to see if the UDP port is there.
708  * XXX - Better way of doing this? Doesn't work for IPv6
709  * Also fails after around 100 ports checked.
710  */
711 int
712 udptest(int s)
713 {
714 	int i, rv, ret;
715 
716 	for (i = 0; i <= 3; i++) {
717 		if ((rv = write(s, "X", 1)) == 1)
718 			ret = 1;
719 		else
720 			ret = -1;
721 	}
722 	return (ret);
723 }
724 
725 void
726 help(void)
727 {
728 	usage(0);
729 	fprintf(stderr, "\tCommand Summary:\n\
730 	\t-4		Use IPv4\n\
731 	\t-6		Use IPv6\n\
732 	\t-U		Use UNIX domain socket\n\
733 	\t-X vers\t	SOCKS version (4 or 5)\n\
734 	\t-h		This help text\n\
735 	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
736 	\t-k		Keep inbound sockets open for multiple connects\n\
737 	\t-l		Listen mode, for inbound connects\n\
738 	\t-n		Suppress name/port resolutions\n\
739 	\t-p port\t	Specify local port for remote connects\n\
740 	\t-r		Randomize remote ports\n\
741 	\t-s addr\t	Local source address\n\
742 	\t-t		Answer TELNET negotiation\n\
743 	\t-u		UDP mode\n\
744 	\t-v		Verbose\n\
745 	\t-w secs\t	Timeout for connects and final net reads\n\
746 	\t-x addr[:port]\tSpecify socks proxy address and port\n\
747 	\t-z		Zero-I/O mode [used for scanning]\n\
748 	Port numbers can be individual or ranges: lo-hi [inclusive]\n");
749 	exit(1);
750 }
751 
752 void
753 usage(int ret)
754 {
755 	fprintf(stderr, "usage: nc [-46Uhklnrtuvz] [-i interval] [-p source port]\n");
756 	fprintf(stderr, "\t  [-s ip address] [-w timeout] [-X vers] [-x proxy address [:port]]\n");
757 	fprintf(stderr, "\t  [hostname] [port[s...]]\n");
758 	if (ret)
759 		exit(1);
760 }
761