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