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