1/* $OpenBSD: netcat.c,v 1.82 2005/07/24 09:33:56 marius 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#include <sys/event.h>
39#include <sys/ioctl.h>
40
41#include <net/if.h>
42#include <netinet/in.h>
43#include <netinet/ip.h>
44#include <netinet/tcp.h>
45#include <arpa/telnet.h>
46#include <arpa/inet.h>
47
48#include <err.h>
49#include <errno.h>
50#ifdef __APPLE__
51#include <limits.h>
52#endif /* __APPLE__ */
53#include <netdb.h>
54#include <poll.h>
55#include <stdarg.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <inttypes.h>
59#include <string.h>
60#include <unistd.h>
61#include <fcntl.h>
62#include "atomicio.h"
63
64#include <network/conninfo.h>
65
66#ifndef SUN_LEN
67#define SUN_LEN(su) \
68	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
69#endif
70
71#define PORT_MAX	65535
72#define PORT_MAX_LEN	6
73
74/* Command Line Options */
75int	cflag;					/* CRLF line-ending */
76int	dflag;					/* detached, no stdin */
77int	iflag;					/* Interval Flag */
78#ifndef __APPLE__
79int	jflag;					/* use jumbo frames if we can */
80#endif /* !__APPLE__ */
81int	kflag;					/* More than one connect */
82int	lflag;					/* Bind to local port */
83int	nflag;					/* Don't do name look up */
84char   *pflag;					/* Localport flag */
85int	rflag;					/* Random ports flag */
86char   *sflag;					/* Source Address */
87int	tflag;					/* Telnet Emulation */
88int	uflag;					/* UDP - Default to TCP */
89int	vflag;					/* Verbosity */
90int	xflag;					/* Socks proxy */
91int	Oflag;					/* use connect vs. connectx */
92int	zflag;					/* Port Scan Flag */
93int	Dflag;					/* sodebug */
94#ifndef __APPLE__
95int	Sflag;					/* TCP MD5 signature option */
96#endif /* !__APPLE__ */
97
98#ifdef __APPLE__
99int	Aflag;					/* Set SO_RECV_ANYIF on socket */
100char	*boundif;				/* interface to bind to */
101int	ifscope;				/* idx of bound to interface */
102int	Cflag;					/* cellular connection OFF option */
103int	tclass = SO_TC_BE;			/* traffic class value */
104int	Kflag;					/* traffic class option */
105int	Fflag;					/* disable flow advisory for UDP if set */
106int	Gflag;					/* TCP connection timeout */
107int	tcp_conn_timeout;			/* Value of TCP connection timeout */
108int	Hflag;					/* TCP keep idle option */
109int	tcp_conn_keepidle;			/* Value of TCP keep idle interval in seconds */
110int	Iflag;					/* TCP keep intvl option */
111int	tcp_conn_keepintvl;			/* Value of TCP keep interval in seconds */
112int	Jflag;					/* TCP keep count option */
113int	tcp_conn_keepcnt;			/* Value of TCP keep count */
114int	Lflag;					/* TCP adaptive read timeout */
115int	Mflag;					/* MULTIPATH domain */
116int	Nflag;					/* TCP adaptive write timeout */
117int	oflag;					/* set options after connect/bind */
118int	tcp_conn_adaptive_rtimo;			/* Value of TCP adaptive timeout */
119int	tcp_conn_adaptive_wtimo;			/* Value of TCP adaptive timeout */
120#endif /* __APPLE__ */
121
122int srcroute = 0;				/* Source routing IPv4/IPv6 options */
123char *srcroute_hosts = NULL;
124
125int use_flowadv = 1;
126int timeout = -1;
127int family = AF_UNSPEC;
128char *portlist[PORT_MAX+1];
129
130void	atelnet(int, unsigned char *, unsigned int);
131void	build_ports(char *);
132void	help(void);
133int	local_listen(char *, char *, struct addrinfo);
134void	readwrite(int);
135int	remote_connect(const char *, const char *, struct addrinfo);
136int	remote_connectx(const char *, const char *, struct addrinfo);
137int	socks_connect(const char *, const char *, struct addrinfo, const char *, const char *,
138	struct addrinfo, int);
139int	udptest(int);
140int	unix_connect(char *);
141int	unix_listen(char *);
142void    set_common_sockopts(int);
143void	usage(int);
144int	showconninfo(int, connid_t);
145void	showmpinfo(int);
146
147extern int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *);
148
149int
150main(int argc, char *argv[])
151{
152	int ch, s, ret, socksv;
153	char *host, *uport, *endp;
154	struct addrinfo hints;
155	struct servent *sv;
156	socklen_t len;
157	struct sockaddr_storage cliaddr;
158	char *proxy;
159	const char *proxyhost = "", *proxyport = NULL;
160	struct addrinfo proxyhints;
161
162	ret = 1;
163	s = 0;
164	socksv = 5;
165	host = NULL;
166	uport = NULL;
167	endp = NULL;
168	sv = NULL;
169
170	while ((ch = getopt(argc, argv,
171	    "46AcDCb:dhi:jFG:H:I:J:K:L:klMnN:Oop:rSs:tUuvw:X:x:z")) != -1) {
172		switch (ch) {
173		case '4':
174			family = AF_INET;
175			break;
176		case '6':
177			family = AF_INET6;
178			break;
179		case 'A':
180			Aflag = 1;
181			break;
182		case 'U':
183			family = AF_UNIX;
184			break;
185		case 'M':
186			Mflag = 1;
187			break;
188		case 'X':
189			if (strcasecmp(optarg, "connect") == 0)
190				socksv = -1; /* HTTP proxy CONNECT */
191			else if (strcmp(optarg, "4") == 0)
192				socksv = 4; /* SOCKS v.4 */
193			else if (strcmp(optarg, "5") == 0)
194				socksv = 5; /* SOCKS v.5 */
195			else
196				errx(1, "unsupported proxy protocol");
197			break;
198		case 'c':
199			cflag = 1;
200			break;
201#ifdef __APPLE__
202		case 'C':
203			Cflag = 1;
204			break;
205		case 'b':
206			boundif = optarg;
207			if ((ifscope = if_nametoindex(boundif)) == 0)
208				errx(1, "bad interface name");
209			break;
210#endif /* __APPLE__ */
211		case 'd':
212			dflag = 1;
213			break;
214		case 'h':
215			help();
216			break;
217		case 'i':
218			iflag = (int)strtoul(optarg, &endp, 10);
219			if (iflag < 0 || *endp != '\0')
220				errx(1, "interval cannot be negative");
221			break;
222#ifndef __APPLE__
223		case 'j':
224			jflag = 1;
225			break;
226#endif /* !__APPLE__ */
227		case 'k':
228			kflag = 1;
229			break;
230#ifdef __APPLE__
231		case 'K':
232			Kflag = 1;
233			tclass = (int)strtoul(optarg, &endp, 10);
234			if (tclass < 0 || *endp != '\0')
235				errx(1, "invalid traffic class");
236			break;
237		case 'F':
238			Fflag = 1;
239			use_flowadv = 0;
240			break;
241		case 'G':
242			Gflag = 1;
243			tcp_conn_timeout = strtoumax(optarg, &endp, 10);
244			if (tcp_conn_timeout < 0 || *endp != '\0')
245				errx(1, "invalid tcp connection timeout");
246			break;
247		case 'H':
248			Hflag = 1;
249			tcp_conn_keepidle = strtoumax(optarg, &endp, 10);
250			if (tcp_conn_keepidle < 0 || *endp != '\0')
251				errx(1, "invalid tcp keep idle interval");
252			break;
253		case 'I':
254			Iflag = 1;
255			tcp_conn_keepintvl = strtoumax(optarg, &endp, 10);
256			if (tcp_conn_keepintvl < 0 || *endp != '\0')
257				errx(1, "invalid tcp keep interval");
258			break;
259		case 'J':
260			Jflag = 1;
261			tcp_conn_keepcnt = strtoumax(optarg, &endp, 10);
262			if (tcp_conn_keepcnt < 0 || *endp != '\0')
263				errx(1, "invalid tcp keep count");
264			break;
265		case 'L':
266			Lflag = 1;
267			tcp_conn_adaptive_rtimo = strtoumax(optarg, &endp, 10);
268			if (tcp_conn_adaptive_rtimo < 0 || *endp != '\0')
269				errx(1, "invalid tcp adaptive read timeout value");
270			break;
271		case 'N':
272			Nflag = 1;
273			tcp_conn_adaptive_wtimo = strtoumax(optarg, &endp, 10);
274			if (tcp_conn_adaptive_wtimo < 0 || *endp != '\0')
275				errx(1, "invalid tcp adaptive write timeout value");
276			break;
277
278#endif /* __APPLE__ */
279		case 'l':
280			lflag = 1;
281			break;
282		case 'n':
283			nflag = 1;
284			break;
285		case 'o':
286			oflag = 1;
287			break;
288		case 'O':
289			Oflag = 1;
290			break;
291		case 'p':
292			pflag = optarg;
293			break;
294		case 'r':
295			rflag = 1;
296			break;
297		case 's':
298			sflag = optarg;
299			break;
300		case 't':
301			tflag = 1;
302			break;
303		case 'u':
304			uflag = 1;
305			break;
306		case 'v':
307			vflag = 1;
308			break;
309		case 'w':
310			timeout = (int)strtoul(optarg, &endp, 10);
311			if (timeout < 0 || *endp != '\0')
312				errx(1, "timeout cannot be negative");
313			if (timeout >= (INT_MAX / 1000))
314				errx(1, "timeout too large");
315#ifndef USE_SELECT
316			timeout *= 1000;
317#endif
318			break;
319		case 'x':
320			xflag = 1;
321			if ((proxy = strdup(optarg)) == NULL)
322				err(1, NULL);
323			break;
324		case 'z':
325			zflag = 1;
326			break;
327		case 'D':
328			Dflag = 1;
329			break;
330#ifndef __APPLE__
331		case 'S':
332			Sflag = 1;
333			break;
334#endif /* !__APPLE__ */
335		default:
336			usage(1);
337		}
338	}
339	argc -= optind;
340	argv += optind;
341
342	/* Cruft to make sure options are clean, and used properly. */
343	if (argv[0] && !argv[1] && family == AF_UNIX) {
344		if (uflag)
345			errx(1, "cannot use -u and -U");
346		if (Mflag)
347			errx(1, "cannot use -M and -U");
348		host = argv[0];
349		uport = NULL;
350	} else if (argv[0] && !argv[1]) {
351		if  (!lflag)
352			usage(1);
353		uport = argv[0];
354		host = NULL;
355	} else if (argv[0] && argv[1]) {
356		host = argv[0];
357		uport = argv[1];
358	} else
359		usage(1);
360
361	/* Detect if hostname has the telnet source-routing syntax (see sourceroute()) */
362	srcroute_hosts = host;
363	if (srcroute_hosts && (srcroute_hosts[0] == '@' || srcroute_hosts[0] == '!')) {
364		if (
365#ifdef INET6
366			family == AF_INET6 ||
367#endif
368			(host = strrchr(srcroute_hosts, ':')) == NULL)
369		{
370			host = strrchr(srcroute_hosts, '@');
371		}
372		if (host == NULL) {
373			host = srcroute_hosts;
374		} else {
375			host++;
376			srcroute = 1;
377		}
378	}
379
380	if (Mflag && Oflag)
381		errx(1, "cannot use -M and -O");
382	if (srcroute && Mflag)
383		errx(1, "source routing isn't compatible with -M");
384	if (srcroute && !Oflag)
385		errx(1, "must use -O for source routing");
386	if (lflag && sflag)
387		errx(1, "cannot use -s and -l");
388	if (lflag && pflag)
389		errx(1, "cannot use -p and -l");
390	if (lflag && zflag)
391		errx(1, "cannot use -z and -l");
392	if (!lflag && kflag)
393		errx(1, "must use -l with -k");
394
395	/* Initialize addrinfo structure. */
396	if (family != AF_UNIX) {
397		memset(&hints, 0, sizeof(struct addrinfo));
398		hints.ai_family = family;
399		hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
400		hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
401		if (nflag)
402			hints.ai_flags |= AI_NUMERICHOST;
403	}
404
405	if (xflag) {
406		if (uflag)
407			errx(1, "no proxy support for UDP mode");
408
409		if (lflag)
410			errx(1, "no proxy support for listen");
411
412		if (family == AF_UNIX)
413			errx(1, "no proxy support for unix sockets");
414
415		/* XXX IPv6 transport to proxy would probably work */
416		if (family == AF_INET6)
417			errx(1, "no proxy support for IPv6");
418
419		if (sflag)
420			errx(1, "no proxy support for local source address");
421
422		proxyhost = strsep(&proxy, ":");
423		proxyport = proxy;
424
425		memset(&proxyhints, 0, sizeof(struct addrinfo));
426		proxyhints.ai_family = family;
427		proxyhints.ai_socktype = SOCK_STREAM;
428		proxyhints.ai_protocol = IPPROTO_TCP;
429		if (nflag)
430			proxyhints.ai_flags |= AI_NUMERICHOST;
431	}
432
433	if (lflag) {
434		int connfd;
435		ret = 0;
436
437		if (family == AF_UNIX)
438			s = unix_listen(host);
439
440		/* Allow only one connection at a time, but stay alive. */
441		for (;;) {
442			if (family != AF_UNIX)
443				s = local_listen(host, uport, hints);
444			if (s < 0)
445				err(1, NULL);
446			/*
447			 * For UDP, we will use recvfrom() initially
448			 * to wait for a caller, then use the regular
449			 * functions to talk to the caller.
450			 */
451			if (uflag) {
452				int rv, plen;
453				char buf[8192];
454				struct sockaddr_storage z;
455
456				len = sizeof(z);
457#ifndef __APPLE__
458				plen = jflag ? 8192 : 1024;
459#else /* __APPLE__ */
460				plen = 1024;
461#endif /* !__APPLE__ */
462				rv = recvfrom(s, buf, plen, MSG_PEEK,
463				    (struct sockaddr *)&z, &len);
464				if (rv < 0)
465					err(1, "recvfrom");
466
467				rv = connect(s, (struct sockaddr *)&z, len);
468				if (rv < 0)
469					err(1, "connect");
470
471				connfd = s;
472			} else {
473				len = sizeof(cliaddr);
474				connfd = accept(s, (struct sockaddr *)&cliaddr,
475				    &len);
476			}
477
478			readwrite(connfd);
479			close(connfd);
480			if (family != AF_UNIX)
481				close(s);
482
483			if (!kflag)
484				break;
485		}
486	} else if (family == AF_UNIX) {
487		ret = 0;
488
489		if ((s = unix_connect(host)) > 0 && !zflag) {
490			readwrite(s);
491			close(s);
492		} else
493			ret = 1;
494
495		exit(ret);
496
497	} else {
498		int i = 0;
499
500		/* Construct the portlist[] array. */
501		build_ports(uport);
502
503		/* Cycle through portlist, connecting to each port. */
504		for (i = 0; portlist[i] != NULL; i++) {
505			if (s)
506				close(s);
507
508			if (xflag)
509				s = socks_connect(host, portlist[i], hints,
510				    proxyhost, proxyport, proxyhints, socksv);
511			else if (!Oflag)
512				s = remote_connectx(host, portlist[i], hints);
513			else
514				s = remote_connect(host, portlist[i], hints);
515
516			if (s < 0)
517				continue;
518
519			ret = 0;
520			if (vflag || zflag) {
521				/* For UDP, make sure we are connected. */
522				if (uflag) {
523					if (udptest(s) == -1) {
524						ret = 1;
525						continue;
526					}
527				}
528
529				/* Don't look up port if -n. */
530				if (nflag)
531					sv = NULL;
532				else {
533					sv = getservbyport(
534					    ntohs(atoi(portlist[i])),
535					    uflag ? "udp" : "tcp");
536				}
537
538				printf("Connection to %s port %s [%s/%s] succeeded!\n",
539				    host, portlist[i], uflag ? "udp" : "tcp",
540				    sv ? sv->s_name : "*");
541			}
542			if (!zflag)
543				readwrite(s);
544		}
545	}
546
547	if (s)
548		close(s);
549
550	exit(ret);
551}
552
553/*
554 * unix_connect()
555 * Returns a socket connected to a local unix socket. Returns -1 on failure.
556 */
557int
558unix_connect(char *path)
559{
560	struct sockaddr_un sun;
561	int s;
562
563	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
564		return (-1);
565	(void)fcntl(s, F_SETFD, 1);
566
567	memset(&sun, 0, sizeof(struct sockaddr_un));
568	sun.sun_family = AF_UNIX;
569
570	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
571	    sizeof(sun.sun_path)) {
572		close(s);
573		errno = ENAMETOOLONG;
574		return (-1);
575	}
576	if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
577		close(s);
578		return (-1);
579	}
580	return (s);
581
582}
583
584/*
585 * unix_listen()
586 * Create a unix domain socket, and listen on it.
587 */
588int
589unix_listen(char *path)
590{
591	struct sockaddr_un sun;
592	int s;
593
594	/* Create unix domain socket. */
595	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
596		return (-1);
597
598	memset(&sun, 0, sizeof(struct sockaddr_un));
599	sun.sun_family = AF_UNIX;
600
601	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
602	    sizeof(sun.sun_path)) {
603		close(s);
604		errno = ENAMETOOLONG;
605		return (-1);
606	}
607
608	if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
609		close(s);
610		return (-1);
611	}
612
613	if (listen(s, 5) < 0) {
614		close(s);
615		return (-1);
616	}
617	return (s);
618}
619
620/*
621 * remote_connect()
622 * Returns a socket connected to a remote host. Properly binds to a local
623 * port or source address if needed. Returns -1 on failure.
624 */
625int
626remote_connect(const char *host, const char *port, struct addrinfo hints)
627{
628	struct addrinfo *res, *res0;
629	int s, error;
630
631	if ((error = getaddrinfo(host, port, &hints, &res)))
632		errx(1, "getaddrinfo: %s", gai_strerror(error));
633
634	res0 = res;
635	do {
636		if ((s = socket(res0->ai_family, res0->ai_socktype,
637		    res0->ai_protocol)) < 0)
638			continue;
639
640		/* Bind to a local port or source address if specified. */
641		if (sflag || pflag) {
642			struct addrinfo ahints, *ares;
643
644			if (!(sflag && pflag)) {
645				if (!sflag)
646					sflag = NULL;
647				else
648					pflag = NULL;
649			}
650
651			memset(&ahints, 0, sizeof(struct addrinfo));
652			ahints.ai_family = res0->ai_family;
653			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
654			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
655			ahints.ai_flags = AI_PASSIVE;
656			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
657				errx(1, "getaddrinfo: %s", gai_strerror(error));
658
659			if (bind(s, (struct sockaddr *)ares->ai_addr,
660			    ares->ai_addrlen) < 0)
661				errx(1, "bind failed: %s", strerror(errno));
662			freeaddrinfo(ares);
663		}
664
665		/* Set source-routing option */
666		if (srcroute != 0) {
667			int result, proto, opt, srlen = 0;
668			char *srp = NULL;
669
670			result = sourceroute(res, srcroute_hosts, &srp, &srlen, &proto, &opt);
671			if (result == 1 && srp != NULL) {
672				if (setsockopt(s, proto, opt, srp, srlen) < 0)
673					perror("setsockopt (source route)");
674			} else {
675				warn("bad source route option: %s\n", srcroute_hosts);
676			}
677		}
678
679		if (!oflag)
680			set_common_sockopts(s);
681
682		if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0) {
683			if (oflag)
684				set_common_sockopts(s);
685			break;
686		} else if (vflag) {
687			warn("connect to %s port %s (%s) failed", host, port,
688			    uflag ? "udp" : "tcp");
689		}
690		close(s);
691		s = -1;
692	} while ((res0 = res0->ai_next) != NULL);
693
694	freeaddrinfo(res);
695
696	return (s);
697}
698
699/*
700 * remote_connectx()
701 * Returns a socket connected to a remote host. Properly binds to a local
702 * port or source address if needed, using connectx(2). Returns -1 on failure.
703 */
704int
705remote_connectx(const char *host, const char *port, struct addrinfo hints)
706{
707	struct addrinfo *res, *res0, *ares = NULL;
708	connid_t cid;
709	int s, error;
710
711	if ((error = getaddrinfo(host, port, &hints, &res)))
712		errx(1, "getaddrinfo: %s", gai_strerror(error));
713
714	res0 = res;
715	do {
716		if ((s = socket(Mflag ? PF_MULTIPATH : res0->ai_family,
717		     res0->ai_socktype, res0->ai_protocol)) < 0) {
718			warn("socket(%d,%d,%d) failed",
719			    (Mflag ? PF_MULTIPATH : res0->ai_family),
720			    res0->ai_socktype, res0->ai_protocol);
721			continue;
722		}
723
724		/* Bind to a local port or source address if specified. */
725		if (sflag || pflag) {
726			struct addrinfo ahints;
727
728			if (!(sflag && pflag)) {
729				if (!sflag)
730					sflag = NULL;
731				else
732					pflag = NULL;
733			}
734			if (ares != NULL) {
735				freeaddrinfo(ares);
736				ares = NULL;
737			}
738
739			memset(&ahints, 0, sizeof(struct addrinfo));
740			ahints.ai_family = res0->ai_family;
741			ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
742			ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
743			ahints.ai_flags = AI_PASSIVE;
744			if ((error = getaddrinfo(sflag, pflag, &ahints, &ares)))
745				errx(1, "getaddrinfo: %s", gai_strerror(error));
746		}
747
748		if (!oflag)
749			set_common_sockopts(s);
750
751		cid = CONNID_ANY;
752		if (ares == NULL) {
753			error = connectx(s, NULL, 0, res0->ai_addr,
754			     res0->ai_addrlen, ifscope, ASSOCID_ANY, &cid);
755		} else {
756			error = connectx(s, ares->ai_addr, ares->ai_addrlen,
757			    res0->ai_addr, res0->ai_addrlen, ifscope,
758			    ASSOCID_ANY, &cid);
759		}
760
761		if (error == 0) {
762			if (oflag)
763				set_common_sockopts(s);
764			if (vflag)
765				showmpinfo(s);
766			break;
767		} else if (errno == EPROTO) {	/* PF_MULTIPATH specific */
768			int ps;
769			warn("connectx to %s port %s (%s) succeded without "
770			    "multipath association (connid %d)",
771			    host, port, uflag ? "udp" : "tcp", cid);
772			if (vflag)
773				showmpinfo(s);
774			ps = peeloff(s, ASSOCID_ANY);
775			if (ps != -1) {
776				close(s);
777				s = ps;
778				if (oflag)
779					set_common_sockopts(s);
780				break;
781			}
782			warn("peeloff failed for connid %d", cid);
783		} else if (vflag) {
784			warn("connectx to %s port %s (%s) failed", host, port,
785			    (uflag ? "udp" : (Mflag ? "mptcp" : "tcp")));
786		}
787		close(s);
788		s = -1;
789	} while ((res0 = res0->ai_next) != NULL);
790
791	freeaddrinfo(res);
792	if (ares != NULL)
793		freeaddrinfo(ares);
794
795	return (s);
796}
797
798/*
799 * local_listen()
800 * Returns a socket listening on a local port, binds to specified source
801 * address. Returns -1 on failure.
802 */
803int
804local_listen(char *host, char *port, struct addrinfo hints)
805{
806	struct addrinfo *res, *res0;
807	int s, ret, x = 1;
808	int error;
809
810	/* Allow nodename to be null. */
811	hints.ai_flags |= AI_PASSIVE;
812
813	/*
814	 * In the case of binding to a wildcard address
815	 * default to binding to an ipv4 address.
816	 */
817	if (host == NULL && hints.ai_family == AF_UNSPEC)
818		hints.ai_family = AF_INET;
819
820	if ((error = getaddrinfo(host, port, &hints, &res)))
821		errx(1, "getaddrinfo: %s", gai_strerror(error));
822
823	res0 = res;
824	do {
825		if ((s = socket(res0->ai_family, res0->ai_socktype,
826		    res0->ai_protocol)) < 0)
827			continue;
828
829		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
830		if (ret == -1)
831			err(1, NULL);
832
833		if (!oflag)
834			set_common_sockopts(s);
835
836		if (bind(s, (struct sockaddr *)res0->ai_addr,
837		    res0->ai_addrlen) == 0) {
838			if (oflag)
839				set_common_sockopts(s);
840			break;
841		}
842
843		close(s);
844		s = -1;
845	} while ((res0 = res0->ai_next) != NULL);
846
847	if (!uflag && s != -1) {
848		if (listen(s, 1) < 0)
849			err(1, "listen");
850	}
851
852	freeaddrinfo(res);
853
854	return (s);
855}
856
857/*
858 * readwrite()
859 * Loop that polls on the network file descriptor and stdin.
860 */
861void
862readwrite(int nfd)
863{
864#ifdef USE_SELECT
865	fd_set readfds;
866	struct timeval tv;
867	int nfd_open = 1, wfd_open = 1;
868#else
869	struct pollfd pfd[2];
870#endif
871	unsigned char buf[8192];
872	int n, wfd = fileno(stdin);
873	int lfd = fileno(stdout);
874	int plen;
875
876#ifndef __APPLE__
877	plen = jflag ? 8192 : 1024;
878#else /* __APPLE__ */
879	plen = 1024;
880#endif /* !__APPLE__ */
881
882#ifndef USE_SELECT
883	/* Setup Network FD */
884	pfd[0].fd = nfd;
885	pfd[0].events = POLLIN;
886
887	/* Set up STDIN FD. */
888	pfd[1].fd = wfd;
889	pfd[1].events = POLLIN;
890#endif
891
892#ifdef USE_SELECT
893	while (nfd_open) {
894#else
895	while (pfd[0].fd != -1) {
896#endif
897		if (iflag)
898			sleep(iflag);
899
900#ifdef USE_SELECT
901		FD_ZERO(&readfds);
902		if (nfd_open)
903			FD_SET(nfd, &readfds);
904		if (wfd_open)
905			FD_SET(wfd, &readfds);
906
907		tv.tv_sec = timeout;
908		tv.tv_usec = 0;
909
910		if ((n = select(nfd + 1, &readfds, NULL, NULL, (timeout == -1) ? NULL : &tv)) < 0) {
911#else
912		if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
913#endif
914			close(nfd);
915			err(1, "Polling Error");
916		}
917
918		if (n == 0)
919			return;
920
921#ifdef USE_SELECT
922		if (FD_ISSET(nfd, &readfds)) {
923#else
924		if (pfd[0].revents & POLLIN) {
925#endif
926			if ((n = read(nfd, buf, plen)) < 0)
927				return;
928			else if (n == 0) {
929				shutdown(nfd, SHUT_RD);
930#ifdef USE_SELECT
931				nfd_open = 0;
932#else
933				pfd[0].fd = -1;
934				pfd[0].events = 0;
935#endif
936			} else {
937				if (tflag)
938					atelnet(nfd, buf, n);
939				if (atomicio(vwrite, lfd, buf, n) != n)
940					return;
941			}
942		}
943
944#ifdef USE_SELECT
945		if (!dflag && FD_ISSET(wfd, &readfds)) {
946#else
947		if (!dflag && pfd[1].revents & POLLIN) {
948#endif
949			if ((n = read(wfd, buf, plen)) < 0)
950				return;
951			else if (n == 0) {
952				shutdown(nfd, SHUT_WR);
953#ifdef USE_SELECT
954				wfd_open = 0;
955#else
956				pfd[1].fd = -1;
957				pfd[1].events = 0;
958#endif
959			} else {
960				if ((cflag) && (buf[n - 1] == '\n')) {
961					if (atomicio(vwrite, nfd, buf, n - 1) != (n - 1))
962						return;
963					if (atomicio(vwrite, nfd, "\r\n", 2) != 2)
964						return;
965				} else {
966					if (atomicio(vwrite, nfd, buf, n) != n)
967						return;
968				}
969			}
970		}
971	}
972}
973
974/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
975void
976atelnet(int nfd, unsigned char *buf, unsigned int size)
977{
978	unsigned char *p, *end;
979	unsigned char obuf[4];
980
981	end = buf + size;
982	obuf[0] = '\0';
983
984	for (p = buf; p < end; p++) {
985		if (*p != IAC)
986			break;
987
988		obuf[0] = IAC;
989		p++;
990		if ((*p == WILL) || (*p == WONT))
991			obuf[1] = DONT;
992		if ((*p == DO) || (*p == DONT))
993			obuf[1] = WONT;
994		if (obuf) {
995			p++;
996			obuf[2] = *p;
997			obuf[3] = '\0';
998			if (atomicio(vwrite, nfd, obuf, 3) != 3)
999				warn("Write Error!");
1000			obuf[0] = '\0';
1001		}
1002	}
1003}
1004
1005/*
1006 * build_ports()
1007 * Build an array or ports in portlist[], listing each port
1008 * that we should try to connect to.
1009 */
1010void
1011build_ports(char *p)
1012{
1013	char *n, *endp;
1014	int hi, lo, cp;
1015	int x = 0;
1016
1017	if ((n = strchr(p, '-')) != NULL) {
1018		if (lflag)
1019			errx(1, "Cannot use -l with multiple ports!");
1020
1021		*n = '\0';
1022		n++;
1023
1024		/* Make sure the ports are in order: lowest->highest. */
1025		hi = (int)strtoul(n, &endp, 10);
1026		if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
1027			errx(1, "port range not valid");
1028		lo = (int)strtoul(p, &endp, 10);
1029		if (lo <= 0 || lo > PORT_MAX || *endp != '\0')
1030			errx(1, "port range not valid");
1031
1032		if (lo > hi) {
1033			cp = hi;
1034			hi = lo;
1035			lo = cp;
1036		}
1037
1038		/* Load ports sequentially. */
1039		for (cp = lo; cp <= hi; cp++) {
1040			portlist[x] = calloc(1, PORT_MAX_LEN);
1041			if (portlist[x] == NULL)
1042				err(1, NULL);
1043			snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
1044			x++;
1045		}
1046
1047		/* Randomly swap ports. */
1048		if (rflag) {
1049			int y;
1050			char *c;
1051
1052			for (x = 0; x <= (hi - lo); x++) {
1053				y = (arc4random() & 0xFFFF) % (hi - lo);
1054				c = portlist[x];
1055				portlist[x] = portlist[y];
1056				portlist[y] = c;
1057			}
1058		}
1059	} else {
1060		hi = (int)strtoul(p, &endp, 10);
1061		if (hi <= 0 || hi > PORT_MAX || *endp != '\0')
1062			errx(1, "port range not valid");
1063		portlist[0] = calloc(1, PORT_MAX_LEN);
1064		if (portlist[0] == NULL)
1065			err(1, NULL);
1066		strlcpy(portlist[0], p, PORT_MAX_LEN);
1067	}
1068}
1069
1070/*
1071 * udptest()
1072 * Do a few writes to see if the UDP port is there.
1073 * XXX - Better way of doing this? Doesn't work for IPv6.
1074 * Also fails after around 100 ports checked.
1075 */
1076int
1077udptest(int s)
1078{
1079	int i, ret;
1080
1081	for (i = 0; i <= 3; i++) {
1082		if (write(s, "X", 1) == 1)
1083			ret = 1;
1084		else
1085			ret = -1;
1086	}
1087	return (ret);
1088}
1089
1090void
1091set_common_sockopts(int s)
1092{
1093	int x = 1;
1094
1095#ifndef __APPLE__
1096	if (Sflag) {
1097		if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
1098			&x, sizeof(x)) == -1)
1099			err(1, NULL);
1100	}
1101#endif /* !__APPLE__ */
1102	if (Dflag) {
1103		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
1104			&x, sizeof(x)) == -1)
1105			err(1, "SO_DEBUG");
1106	}
1107#ifndef __APPLE__
1108	if (jflag) {
1109		if (setsockopt(s, SOL_SOCKET, SO_JUMBO,
1110			&x, sizeof(x)) == -1)
1111			err(1, NULL);
1112	}
1113#endif /* !__APPLE__ */
1114#ifdef __APPLE__
1115	if (Aflag) {
1116		if (setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF,
1117			&x, sizeof(x)) == -1)
1118			err(1, "SO_RECV_ANYIF");
1119	}
1120
1121	if (boundif && (lflag || Oflag)) {
1122		/* Socket family could be AF_UNSPEC, so try both */
1123		if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifscope,
1124		    sizeof (ifscope)) == -1 &&
1125		    setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &ifscope,
1126		    sizeof (ifscope)) == -1)
1127			err(1, "{IP,IPV6}_BOUND_IF");
1128	}
1129
1130	if (Cflag) {
1131		uint32_t restrictions = SO_RESTRICT_DENY_CELLULAR;
1132		if (setsockopt(s, SOL_SOCKET, SO_RESTRICTIONS, &restrictions,
1133		     sizeof (restrictions)) == -1)
1134			err(1, "SO_RESTRICTIONS: SO_RESTRICT_DENY_CELLULAR");
1135	}
1136
1137	if (Kflag) {
1138		if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
1139		    &tclass, sizeof (tclass)) == -1)
1140			err(1, "SO_TRAFFIC_CLASS");
1141	}
1142
1143	if (Gflag) {
1144		if (setsockopt(s, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &tcp_conn_timeout,
1145			sizeof(tcp_conn_timeout)) == -1)
1146			err(1, "TCP_CONNECTIONTIMEOUT");
1147	}
1148
1149	if (Hflag || Iflag || Jflag) {
1150		/* enable keep alives on this socket */
1151		int on = 1;
1152		if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1153			&on, sizeof(on)) == -1)
1154			err(1, "SO_KEEPALIVE");
1155	}
1156
1157	if (Hflag) {
1158		if (setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,
1159			&tcp_conn_keepidle, sizeof(tcp_conn_keepidle)) == -1)
1160			err(1, "TCP_KEEPALIVE");
1161	}
1162
1163	if (Iflag) {
1164		if (setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL,
1165			&tcp_conn_keepintvl, sizeof(tcp_conn_keepintvl)) == -1)
1166			err(1, "TCP_KEEPINTVL");
1167	}
1168
1169	if (Jflag) {
1170		if (setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT,
1171			&tcp_conn_keepcnt, sizeof(tcp_conn_keepcnt)) == -1)
1172			err(1, "TCP_KEEPCNT");
1173	}
1174
1175	if (Lflag) {
1176		if (setsockopt(s, IPPROTO_TCP, TCP_ADAPTIVE_READ_TIMEOUT,
1177			&tcp_conn_adaptive_rtimo,
1178			sizeof(tcp_conn_adaptive_rtimo)) == -1)
1179			err(1, "TCP_ADAPTIVE_READ_TIMEOUT");
1180	}
1181
1182	if (Nflag) {
1183		if (setsockopt(s, IPPROTO_TCP,TCP_ADAPTIVE_WRITE_TIMEOUT,
1184			&tcp_conn_adaptive_wtimo,
1185			sizeof(tcp_conn_adaptive_wtimo)) == -1)
1186			err(1, "TCP_ADAPTIVE_WRITE_TIMEOUT");
1187	}
1188#endif /* __APPLE__ */
1189}
1190
1191void
1192help(void)
1193{
1194	usage(0);
1195	fprintf(stderr, "\tCommand Summary:\n\
1196	\t-4		Use IPv4\n\
1197	\t-6		Use IPv6\n\
1198%s\
1199%s\
1200%s\
1201	\t-c		Send CRLF as line-ending\n\
1202	\t-D		Enable the debug socket option\n\
1203	\t-d		Detach from stdin\n\
1204	\t-h		This help text\n\
1205	\t-i secs\t	Delay interval for lines sent, ports scanned\n\
1206	\t-k		Keep inbound sockets open for multiple connects\n\
1207	\t-l		Listen mode, for inbound connects\n\
1208	\t-n		Suppress name/port resolutions\n\
1209	\t-p port\t	Specify local port for remote connects\n\
1210	\t-r		Randomize remote ports\n\
1211%s\
1212%s\
1213%s\
1214%s\
1215%s\
1216%s\
1217%s\
1218	\t-s addr\t	Local source address\n\
1219	\t-t		Answer TELNET negotiation\n\
1220	\t-U		Use UNIX domain socket\n\
1221	\t-u		UDP mode\n\
1222	\t-v		Verbose\n\
1223	\t-w secs\t	Timeout for connects and final net reads\n\
1224	\t-X proto	Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
1225	\t-x addr[:port]\tSpecify proxy address and port\n\
1226	\t-z		Zero-I/O mode [used for scanning]\n\
1227	Port numbers can be individual or ranges: lo-hi [inclusive]\n",
1228#ifndef __APPLE__
1229	"",
1230	"",
1231	"",
1232	"	\t-S		Enable the TCP MD5 signature option\n",
1233	"",
1234	"",
1235	"",
1236	"",
1237	""
1238#else /* __APPLE__ */
1239	"	\t-A		Set SO_RECV_ANYIF on socket\n",
1240	"	\t-C		Don't use cellular connection\n",
1241	"	\t-b ifbound	Bind socket to interface\n",
1242	"	\t-O		Use old-style connect instead of connectx\n",
1243	"	\t-o		Issue socket options after connect/bind\n",
1244	"	\t-K tclass	Specify traffic class\n",
1245	"	\t-F		Do not use flow advisory (flow adv enabled by default)\n",
1246	"	\t-G conntimo	Connection timeout in seconds\n",
1247	"	\t-H keepidle	Initial idle timeout in seconds\n",
1248	"	\t-I keepintvl	Interval for repeating idle timeouts in seconds\n",
1249	"	\t-J keepcnt	Number of times to repeat idle timeout\n",
1250	"	\t-L num_probes Number of probes to send before generating a read timeout event\n",
1251	"	\t-M		Use MULTIPATH domain socket\n",
1252	"	\t-N num_probes Number of probes to send before generating a write timeout event\n"
1253#endif /* !__APPLE__ */
1254	);
1255	exit(1);
1256}
1257
1258void
1259usage(int ret)
1260{
1261#ifndef __APPLE__
1262	fprintf(stderr, "usage: nc [-46cDdhklnrStUuvz] [-i interval] [-p source_port]\n");
1263#else /* __APPLE__ */
1264	fprintf(stderr, "usage: nc [-46AcCDdFhklMnOortUuvz] [-K tc] [-b boundif] [-i interval] [-p source_port]\n");
1265#endif /* !__APPLE__ */
1266	fprintf(stderr, "\t  [-s source_ip_address] [-w timeout] [-X proxy_version]\n");
1267	fprintf(stderr, "\t  [-x proxy_address[:port]] [hostname] [port[s]]\n");
1268	if (ret)
1269		exit(1);
1270}
1271
1272int
1273wait_for_flowadv(int fd)
1274{
1275	static int kq = -1;
1276	int rc;
1277	struct kevent kev[2];
1278	bzero(kev, sizeof(kev));
1279
1280	/* Got ENOBUFS.
1281	 * Now wait for flow advisory only if UDP is set and flow adv is enabled. */
1282	if (!uflag || !use_flowadv) {
1283		return (1);
1284	}
1285
1286	if (kq < 0) {
1287		kq = kqueue();
1288		if (kq < 0) {
1289			errx(1, "failed to create kqueue for flow advisory");
1290			return (1);
1291		}
1292	}
1293
1294	EV_SET(&kev[0], fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0);
1295	rc = kevent(kq, &kev[0], 1, NULL, 0, NULL);
1296	if (rc < 0) {
1297		return (1);
1298	}
1299
1300	rc = kevent(kq, NULL, 0, &kev[1], 1, NULL);
1301	if (rc < 0) {
1302		return (1);
1303	}
1304
1305	if (kev[1].flags & EV_EOF) {
1306		return (2);
1307	}
1308
1309	return (0);
1310}
1311
1312/*
1313 * Print a value a la the %b format of the kernel's printf
1314 */
1315void
1316printb(const char *s, unsigned v, const char *bits)
1317{
1318	int i, any = 0;
1319	char c;
1320
1321	if (bits && *bits == 8)
1322		printf("%s=%o", s, v);
1323	else
1324		printf("%s=%x", s, v);
1325	bits++;
1326	if (bits) {
1327		putchar('<');
1328		while ((i = *bits++) != '\0') {
1329			if (v & (1 << (i-1))) {
1330				if (any)
1331					putchar(',');
1332				any = 1;
1333				for (; (c = *bits) > 32; bits++)
1334					putchar(c);
1335			} else
1336				for (; *bits > 32; bits++)
1337					;
1338		}
1339		putchar('>');
1340	}
1341}
1342
1343#define	CIF_BITS	\
1344	"\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF" \
1345	"\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \
1346	"\13MP_DEGRADED"
1347
1348int
1349showconninfo(int s, connid_t cid)
1350{
1351	struct so_cordreq scor;
1352	char buf[INET6_ADDRSTRLEN];
1353	conninfo_t *cfo = NULL;
1354	int err;
1355
1356	err = copyconninfo(s, cid, &cfo);
1357	if (err != 0) {
1358		warn("copyconninfo failed for cid %d\n", cid);
1359		goto out;
1360	}
1361
1362	printf("%6d:\t", cid);
1363	printb("flags", cfo->ci_flags, CIF_BITS);
1364	printf("\n");
1365	printf("\toutif %s\n", if_indextoname(cfo->ci_ifindex, buf));
1366	if (cfo->ci_src != NULL) {
1367		printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family,
1368		    (cfo->ci_src->sa_family == AF_INET) ?
1369		    (void *)&((struct sockaddr_in *)cfo->ci_src)->
1370		    sin_addr.s_addr :
1371		    (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr,
1372		    buf, sizeof (buf)),
1373		    (cfo->ci_src->sa_family == AF_INET) ?
1374		    ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) :
1375		    ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port));
1376	}
1377	if (cfo->ci_dst != NULL) {
1378		printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family,
1379		    (cfo->ci_dst->sa_family == AF_INET) ?
1380		    (void *)&((struct sockaddr_in *)cfo->ci_dst)->
1381		    sin_addr.s_addr :
1382		    (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr,
1383		    buf, sizeof (buf)),
1384		    (cfo->ci_dst->sa_family == AF_INET) ?
1385		    ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) :
1386		    ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port));
1387	}
1388
1389	bzero(&scor, sizeof (scor));
1390	scor.sco_cid = cid;
1391	err = ioctl(s, SIOCGCONNORDER, &scor);
1392	if (err == 0) {
1393		printf("\trank %d\n", scor.sco_rank);
1394	} else {
1395		printf("\trank info not available\n");
1396	}
1397
1398	if (cfo->ci_aux_data != NULL) {
1399		switch (cfo->ci_aux_type) {
1400		case CIAUX_TCP:
1401			printf("\tTCP aux info available\n");
1402			break;
1403		default:
1404			printf("\tUnknown aux type %d\n", cfo->ci_aux_type);
1405			break;
1406		}
1407	}
1408out:
1409	if (cfo != NULL)
1410		freeconninfo(cfo);
1411
1412	return (err);
1413}
1414
1415void
1416showmpinfo(int s)
1417{
1418	uint32_t aid_cnt, cid_cnt;
1419	associd_t *aid = NULL;
1420	connid_t *cid = NULL;
1421	int i, err;
1422
1423	err = copyassocids(s, &aid, &aid_cnt);
1424	if (err != 0) {
1425		warn("copyassocids failed\n");
1426		goto done;
1427	} else {
1428		printf("found %d associations", aid_cnt);
1429		if (aid_cnt > 0) {
1430			printf(" with IDs:");
1431			for (i = 0; i < aid_cnt; i++)
1432				printf(" %d\n", aid[i]);
1433		}
1434		printf("\n");
1435	}
1436
1437	/* just do an association for now */
1438	err = copyconnids(s, ASSOCID_ANY, &cid, &cid_cnt);
1439	if (err != 0) {
1440		warn("copyconnids failed\n");
1441		goto done;
1442	} else {
1443		printf("found %d connections", cid_cnt);
1444		if (cid_cnt > 0) {
1445			printf(":\n");
1446			for (i = 0; i < cid_cnt; i++) {
1447				if (showconninfo(s, cid[i]) != 0)
1448					break;
1449			}
1450		}
1451		printf("\n");
1452	}
1453
1454done:
1455	if (aid != NULL)
1456		freeassocids(aid);
1457	if (cid != NULL)
1458		freeconnids(cid);
1459}
1460