1/* $OpenBSD: ifaddr.c,v 1.8 2023/03/08 04:43:06 guenther Exp $ */ 2 3/* 4 * This file has been copied from ifconfig and adapted to test 5 * SIOCSIFADDR, SIOCSIFNETMASK, SIOCSIFDSTADDR, SIOCSIFBRDADDR 6 * ioctls. Usually ifconfig uses SIOCAIFADDR and SIOCDIFADDR, but 7 * the old kernel interface has to be tested, too. 8 */ 9 10/* 11 * Copyright (c) 1983, 1993 12 * The Regents of the University of California. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39/*- 40 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to The NetBSD Foundation 44 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 45 * NASA Ames Research Center. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 57 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 58 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 59 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 60 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 61 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 62 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 63 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 64 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 65 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 66 * POSSIBILITY OF SUCH DAMAGE. 67 */ 68 69/* 70 * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org> 71 * 72 * Permission to use, copy, modify, and distribute this software for any 73 * purpose with or without fee is hereby granted, provided that the above 74 * copyright notice and this permission notice appear in all copies. 75 * 76 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 77 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 78 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 79 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 80 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 81 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 82 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 83 */ 84 85#include <sys/socket.h> 86#include <sys/ioctl.h> 87#include <sys/time.h> 88 89#include <net/if.h> 90#include <net/if_dl.h> 91#include <net/if_media.h> 92#include <net/if_types.h> 93#include <netinet/in.h> 94#include <netinet/in_var.h> 95#include <netinet6/in6_var.h> 96#include <netinet6/nd6.h> 97#include <arpa/inet.h> 98#include <netinet/ip_ipsp.h> 99#include <netinet/if_ether.h> 100 101#include <netdb.h> 102 103#include <net/if_vlan_var.h> 104 105#include <ctype.h> 106#include <err.h> 107#include <errno.h> 108#include <stdio.h> 109#include <stdint.h> 110#include <stdlib.h> 111#include <string.h> 112#include <unistd.h> 113#include <limits.h> 114#include <resolv.h> 115#include <util.h> 116#include <ifaddrs.h> 117 118#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 119#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 120 121#define HWFEATURESBITS \ 122 "\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4" \ 123 "\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6" \ 124 "\11CSUM_UDPv6\20WOL" 125 126struct ifreq ifr, ridreq; 127struct in_aliasreq in_addreq; 128struct in6_ifreq ifr6; 129struct in6_ifreq in6_ridreq; 130struct in6_aliasreq in6_addreq; 131struct sockaddr_in netmask; 132 133char ifname[IFNAMSIZ]; 134int flags, xflags, setaddr, setmask, setipdst, setbroad, doalias; 135u_long metric, mtu; 136int rdomainid; 137int llprio; 138int clearaddr, sock; 139int newaddr = 0; 140int af = AF_INET; 141int explicit_prefix = 0; 142int Lflag = 1; 143 144int showcapsflag; 145 146void notealias(const char *, int); 147void setifaddr(const char *, int); 148void setifrtlabel(const char *, int); 149void setifdstaddr(const char *, int); 150void addaf(const char *, int); 151void removeaf(const char *, int); 152void setifbroadaddr(const char *, int); 153void setifnetmask(const char *, int); 154void setifprefixlen(const char *, int); 155void settunnel(const char *, const char *); 156void settunneladdr(const char *, int); 157void deletetunnel(const char *, int); 158void settunnelinst(const char *, int); 159void unsettunnelinst(const char *, int); 160void settunnelttl(const char *, int); 161void setia6flags(const char *, int); 162void setia6pltime(const char *, int); 163void setia6vltime(const char *, int); 164void setia6lifetime(const char *, const char *); 165void setia6eui64(const char *, int); 166void setrdomain(const char *, int); 167void unsetrdomain(const char *, int); 168int prefix(void *val, int); 169int printgroup(char *, int); 170void setifipdst(const char *, int); 171void setignore(const char *, int); 172 173int actions; /* Actions performed */ 174 175#define A_SILENT 0x8000000 /* doing operation, do not print */ 176 177#define NEXTARG0 0xffffff 178#define NEXTARG 0xfffffe 179#define NEXTARG2 0xfffffd 180 181const struct cmd { 182 char *c_name; 183 int c_parameter; /* NEXTARG means next argv */ 184 int c_action; /* defered action */ 185 void (*c_func)(const char *, int); 186 void (*c_func2)(const char *, const char *); 187} cmds[] = { 188 { "alias", IFF_UP, 0, notealias }, 189 { "-alias", -IFF_UP, 0, notealias }, 190 { "delete", -IFF_UP, 0, notealias }, 191 { "netmask", NEXTARG, 0, setifnetmask }, 192 { "broadcast", NEXTARG, 0, setifbroadaddr }, 193 { "prefixlen", NEXTARG, 0, setifprefixlen}, 194 { "anycast", IN6_IFF_ANYCAST, 0, setia6flags }, 195 { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags }, 196 { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags }, 197 { "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags }, 198 { "pltime", NEXTARG, 0, setia6pltime }, 199 { "vltime", NEXTARG, 0, setia6vltime }, 200 { "eui64", 0, 0, setia6eui64 }, 201#ifndef SMALL 202 { "rtlabel", NEXTARG, 0, setifrtlabel }, 203 { "-rtlabel", -1, 0, setifrtlabel }, 204 { "rdomain", NEXTARG, 0, setrdomain }, 205 { "-rdomain", 0, 0, unsetrdomain }, 206 { "tunnel", NEXTARG2, 0, NULL, settunnel }, 207 { "tunneladdr", NEXTARG, 0, settunneladdr }, 208 { "-tunnel", 0, 0, deletetunnel }, 209 { "tunneldomain", NEXTARG, 0, settunnelinst }, 210 { "-tunneldomain", 0, 0, unsettunnelinst }, 211 { "tunnelttl", NEXTARG, 0, settunnelttl }, 212 { "-inet", AF_INET, 0, removeaf }, 213 { "-inet6", AF_INET6, 0, removeaf }, 214 { "ipdst", NEXTARG, 0, setifipdst }, 215#endif /* SMALL */ 216 { NULL, /*src*/ 0, 0, setifaddr }, 217 { NULL, /*dst*/ 0, 0, setifdstaddr }, 218 { NULL, /*illegal*/0, 0, NULL }, 219}; 220 221#define IFFBITS \ 222 "\024\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6STATICARP" \ 223 "\7RUNNING\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX" \ 224 "\15LINK0\16LINK1\17LINK2\20MULTICAST" \ 225 "\23AUTOCONF6TEMP\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII" \ 226 "\30AUTOCONF4" 227 228int getinfo(struct ifreq *, int); 229void getsock(int); 230void printif(char *, int); 231void printb(char *, unsigned int, unsigned char *); 232void printb_status(unsigned short, unsigned char *); 233const char *get_linkstate(int, int); 234void status(int, struct sockaddr_dl *, int); 235__dead void usage(void); 236const char *get_string(const char *, const char *, u_int8_t *, int *); 237int len_string(const u_int8_t *, int); 238int print_string(const u_int8_t *, int); 239char *sec2str(time_t); 240 241unsigned long get_ts_map(int, int, int); 242 243void in_status(int); 244void in_getaddr(const char *, int); 245void in_getprefix(const char *, int); 246void in6_fillscopeid(struct sockaddr_in6 *); 247void in6_alias(struct in6_ifreq *); 248void in6_status(int); 249void in6_getaddr(const char *, int); 250void in6_getprefix(const char *, int); 251 252/* Known address families */ 253const struct afswtch { 254 char *af_name; 255 short af_af; 256 void (*af_status)(int); 257 void (*af_getaddr)(const char *, int); 258 void (*af_getprefix)(const char *, int); 259 u_long af_difaddr; 260 u_long af_aifaddr; 261 caddr_t af_ridreq; 262 caddr_t af_addreq; 263} afs[] = { 264#define C(x) ((caddr_t) &x) 265 { "inet", AF_INET, in_status, in_getaddr, in_getprefix, 266 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(in_addreq) }, 267 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix, 268 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) }, 269 { 0, 0, 0, 0 } 270}; 271 272const struct afswtch *afp; /*the address family being set or asked about*/ 273 274int ifaliases = 0; 275int aflag = 0; 276 277int 278main(int argc, char *argv[]) 279{ 280 const struct afswtch *rafp = NULL; 281 int create = 0; 282 int i; 283 284 /* If no args at all, print all interfaces. */ 285 if (argc < 2) { 286 /* no filesystem visibility */ 287 if (unveil("/", "") == -1) 288 err(1, "unveil /"); 289 if (unveil(NULL, NULL) == -1) 290 err(1, "unveil"); 291 aflag = 1; 292 printif(NULL, 0); 293 return (0); 294 } 295 argc--, argv++; 296 if (*argv[0] == '-') { 297 int nomore = 0; 298 299 for (i = 1; argv[0][i]; i++) { 300 switch (argv[0][i]) { 301 case 'a': 302 aflag = 1; 303 nomore = 1; 304 break; 305 case 'A': 306 aflag = 1; 307 ifaliases = 1; 308 nomore = 1; 309 break; 310 default: 311 usage(); 312 break; 313 } 314 } 315 if (nomore == 0) { 316 argc--, argv++; 317 if (argc < 1) 318 usage(); 319 if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ) 320 errx(1, "interface name '%s' too long", *argv); 321 } 322 } else if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ) 323 errx(1, "interface name '%s' too long", *argv); 324 argc--, argv++; 325 326 if (unveil(_PATH_RESCONF, "r") == -1) 327 err(1, "unveil %s", _PATH_RESCONF); 328 if (unveil(_PATH_HOSTS, "r") == -1) 329 err(1, "unveil %s", _PATH_HOSTS); 330 if (unveil(_PATH_SERVICES, "r") == -1) 331 err(1, "unveil %s", _PATH_SERVICES); 332 if (unveil(NULL, NULL) == -1) 333 err(1, "unveil"); 334 335 if (argc > 0) { 336 for (afp = rafp = afs; rafp->af_name; rafp++) 337 if (strcmp(rafp->af_name, *argv) == 0) { 338 afp = rafp; 339 argc--; 340 argv++; 341 break; 342 } 343 rafp = afp; 344 af = ifr.ifr_addr.sa_family = rafp->af_af; 345 } 346 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 347 348 /* initialization */ 349 in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 350 in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 351 352 if (aflag == 0) { 353 create = (argc > 0) && strcmp(argv[0], "destroy") != 0; 354 (void)getinfo(&ifr, create); 355 } 356 357 if (argc != 0 && af == AF_INET6) 358 addaf(ifname, AF_INET6); 359 360 while (argc > 0) { 361 const struct cmd *p; 362 363 for (p = cmds; p->c_name; p++) 364 if (strcmp(*argv, p->c_name) == 0) 365 break; 366 if (p->c_name == 0 && setaddr) 367 for (i = setaddr; i > 0; i--) { 368 p++; 369 if (p->c_func == NULL) 370 errx(1, "%s: bad value", *argv); 371 } 372 if (p->c_func || p->c_func2) { 373 if (p->c_parameter == NEXTARG0) { 374 const struct cmd *p0; 375 int noarg = 1; 376 377 if (argv[1]) { 378 for (p0 = cmds; p0->c_name; p0++) 379 if (strcmp(argv[1], 380 p0->c_name) == 0) { 381 noarg = 0; 382 break; 383 } 384 } else 385 noarg = 0; 386 387 if (noarg == 0) 388 (*p->c_func)(NULL, 0); 389 else 390 goto nextarg; 391 } else if (p->c_parameter == NEXTARG) { 392nextarg: 393 if (argv[1] == NULL) 394 errx(1, "'%s' requires argument", 395 p->c_name); 396 (*p->c_func)(argv[1], 0); 397 argc--, argv++; 398 actions = actions | A_SILENT | p->c_action; 399 } else if (p->c_parameter == NEXTARG2) { 400 if ((argv[1] == NULL) || 401 (argv[2] == NULL)) 402 errx(1, "'%s' requires 2 arguments", 403 p->c_name); 404 (*p->c_func2)(argv[1], argv[2]); 405 argc -= 2; 406 argv += 2; 407 actions = actions | A_SILENT | p->c_action; 408 } else { 409 (*p->c_func)(*argv, p->c_parameter); 410 actions = actions | A_SILENT | p->c_action; 411 } 412 } 413 argc--, argv++; 414 } 415 416 if (argc == 0 && actions == 0) { 417 printif(ifr.ifr_name, aflag ? ifaliases : 1); 418 return (0); 419 } 420 421 if (af == AF_INET6 && explicit_prefix == 0) { 422 /* 423 * Aggregatable address architecture defines all prefixes 424 * are 64. So, it is convenient to set prefixlen to 64 if 425 * it is not specified. If we are setting a destination 426 * address on a point-to-point interface, 128 is required. 427 */ 428 if (setipdst && (flags & IFF_POINTOPOINT)) 429 setifprefixlen("128", 0); 430 else 431 setifprefixlen("64", 0); 432 /* in6_getprefix("64", MASK) if MASK is available here... */ 433 } 434 435 if (doalias == 0 || (newaddr && clearaddr)) { 436 (void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name)); 437 /* IPv4 only, inet6 does not have such ioctls */ 438 if (setaddr) { 439 memcpy(&ridreq.ifr_addr, &in_addreq.ifra_addr, 440 in_addreq.ifra_addr.sin_len); 441 if (ioctl(sock, SIOCSIFADDR, rafp->af_ridreq) == -1) 442 err(1, "SIOCSIFADDR"); 443 } 444 if (setmask) { 445 memcpy(&ridreq.ifr_addr, &in_addreq.ifra_mask, 446 in_addreq.ifra_mask.sin_len); 447 if (ioctl(sock, SIOCSIFNETMASK, rafp->af_ridreq) == -1) 448 err(1, "SIOCSIFNETMASK"); 449 } 450 if (setipdst) { 451 memcpy(&ridreq.ifr_addr, &in_addreq.ifra_dstaddr, 452 in_addreq.ifra_dstaddr.sin_len); 453 if (ioctl(sock, SIOCSIFDSTADDR, rafp->af_ridreq) == -1) 454 err(1, "SIOCSIFDSTADDR"); 455 } 456 if (setbroad) { 457 memcpy(&ridreq.ifr_addr, &in_addreq.ifra_broadaddr, 458 in_addreq.ifra_broadaddr.sin_len); 459 if (ioctl(sock, SIOCSIFBRDADDR, rafp->af_ridreq) == -1) 460 err(1, "SIOCSIFBRDADDR"); 461 } 462 return (0); 463 } 464 if (clearaddr) { 465 (void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name)); 466 if (ioctl(sock, rafp->af_difaddr, rafp->af_ridreq) == -1) { 467 if (errno == EADDRNOTAVAIL && (doalias >= 0)) { 468 /* means no previous address for interface */ 469 } else 470 err(1, "SIOCDIFADDR"); 471 } 472 } 473 if (newaddr) { 474 (void) strlcpy(rafp->af_addreq, ifname, sizeof(ifr.ifr_name)); 475 if (ioctl(sock, rafp->af_aifaddr, rafp->af_addreq) == -1) 476 err(1, "SIOCAIFADDR"); 477 } 478 return (0); 479} 480 481void 482getsock(int naf) 483{ 484 static int oaf = -1; 485 486 if (oaf == naf) 487 return; 488 if (oaf != -1) 489 close(sock); 490 sock = socket(naf, SOCK_DGRAM, 0); 491 if (sock == -1) 492 oaf = -1; 493 else 494 oaf = naf; 495} 496 497int 498getinfo(struct ifreq *ifr, int create) 499{ 500 501 getsock(af); 502 if (sock == -1) 503 err(1, "socket"); 504 if (!isdigit((unsigned char)ifname[strlen(ifname) - 1])) 505 return (-1); /* ignore groups here */ 506 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1) { 507 int oerrno = errno; 508 509 if (!create) 510 return (-1); 511 if (ioctl(sock, SIOCIFCREATE, (caddr_t)ifr) == -1) { 512 errno = oerrno; 513 return (-1); 514 } 515 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1) 516 return (-1); 517 } 518 flags = ifr->ifr_flags & 0xffff; 519 if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)ifr) == -1) 520 ifr->ifr_flags = 0; 521 xflags = ifr->ifr_flags; 522 if (ioctl(sock, SIOCGIFMETRIC, (caddr_t)ifr) == -1) 523 metric = 0; 524 else 525 metric = ifr->ifr_metric; 526 if (ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) == -1) 527 mtu = 0; 528 else 529 mtu = ifr->ifr_mtu; 530#ifndef SMALL 531 if (ioctl(sock, SIOCGIFRDOMAIN, (caddr_t)ifr) == -1) 532 rdomainid = 0; 533 else 534 rdomainid = ifr->ifr_rdomainid; 535#endif 536 if (ioctl(sock, SIOCGIFLLPRIO, (caddr_t)ifr) == -1) 537 llprio = 0; 538 else 539 llprio = ifr->ifr_llprio; 540 541 return (0); 542} 543 544int 545printgroup(char *groupname, int ifaliases) 546{ 547 struct ifgroupreq ifgr; 548 struct ifg_req *ifg; 549 int len, cnt = 0; 550 551 getsock(AF_INET); 552 bzero(&ifgr, sizeof(ifgr)); 553 strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name)); 554 if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { 555 if (errno == EINVAL || errno == ENOTTY || 556 errno == ENOENT) 557 return (-1); 558 else 559 err(1, "SIOCGIFGMEMB"); 560 } 561 562 len = ifgr.ifgr_len; 563 if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) 564 err(1, "printgroup"); 565 if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) 566 err(1, "SIOCGIFGMEMB"); 567 568 for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); 569 ifg++) { 570 len -= sizeof(struct ifg_req); 571 printif(ifg->ifgrq_member, ifaliases); 572 cnt++; 573 } 574 free(ifgr.ifgr_groups); 575 576 return (cnt); 577} 578 579void 580printif(char *name, int ifaliases) 581{ 582 struct ifaddrs *ifap, *ifa; 583 struct if_data *ifdata; 584 const char *namep; 585 char *oname = NULL; 586 struct ifreq *ifrp; 587 int count = 0, noinet = 1; 588 size_t nlen = 0; 589 590 if (aflag) 591 name = NULL; 592 if (name) { 593 if ((oname = strdup(name)) == NULL) 594 err(1, "strdup"); 595 nlen = strlen(oname); 596 /* is it a group? */ 597 if (nlen && !isdigit((unsigned char)oname[nlen - 1])) 598 if (printgroup(oname, ifaliases) != -1) { 599 free(oname); 600 return; 601 } 602 } 603 604 if (getifaddrs(&ifap) != 0) 605 err(1, "getifaddrs"); 606 607 namep = NULL; 608 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 609 if (oname) { 610 if (nlen && isdigit((unsigned char)oname[nlen - 1])) { 611 /* must have exact match */ 612 if (strcmp(oname, ifa->ifa_name) != 0) 613 continue; 614 } else { 615 /* partial match OK if it ends w/ digit */ 616 if (strncmp(oname, ifa->ifa_name, nlen) != 0 || 617 !isdigit((unsigned char)ifa->ifa_name[nlen])) 618 continue; 619 } 620 } 621 /* quickhack: sizeof(ifr) < sizeof(ifr6) */ 622 if (ifa->ifa_addr->sa_family == AF_INET6) { 623 memset(&ifr6, 0, sizeof(ifr6)); 624 memcpy(&ifr6.ifr_addr, ifa->ifa_addr, 625 MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len)); 626 ifrp = (struct ifreq *)&ifr6; 627 } else { 628 memset(&ifr, 0, sizeof(ifr)); 629 memcpy(&ifr.ifr_addr, ifa->ifa_addr, 630 MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len)); 631 ifrp = 𝔦 632 } 633 strlcpy(ifname, ifa->ifa_name, sizeof(ifname)); 634 strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name)); 635 636 if (ifa->ifa_addr->sa_family == AF_LINK) { 637 namep = ifa->ifa_name; 638 if (getinfo(ifrp, 0) < 0) 639 continue; 640 ifdata = ifa->ifa_data; 641 status(1, (struct sockaddr_dl *)ifa->ifa_addr, 642 ifdata->ifi_link_state); 643 count++; 644 noinet = 1; 645 continue; 646 } 647 648 if (!namep || !strcmp(namep, ifa->ifa_name)) { 649 const struct afswtch *p; 650 651 if (ifa->ifa_addr->sa_family == AF_INET && 652 ifaliases == 0 && noinet == 0) 653 continue; 654 if ((p = afp) != NULL) { 655 if (ifa->ifa_addr->sa_family == p->af_af) 656 p->af_status(1); 657 } else { 658 for (p = afs; p->af_name; p++) { 659 if (ifa->ifa_addr->sa_family == 660 p->af_af) 661 p->af_status(0); 662 } 663 } 664 count++; 665 if (ifa->ifa_addr->sa_family == AF_INET) 666 noinet = 0; 667 continue; 668 } 669 } 670 freeifaddrs(ifap); 671 free(oname); 672 if (count == 0) { 673 fprintf(stderr, "%s: no such interface\n", ifname); 674 exit(1); 675 } 676} 677 678#define RIDADDR 0 679#define ADDR 1 680#define MASK 2 681#define DSTADDR 3 682 683void 684setifaddr(const char *addr, int param) 685{ 686 /* 687 * Delay the ioctl to set the interface addr until flags are all set. 688 * The address interpretation may depend on the flags, 689 * and the flags may change when the address is set. 690 */ 691 setaddr++; 692 if (doalias >= 0) 693 newaddr = 1; 694 if (doalias == 0) 695 clearaddr = 1; 696 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); 697} 698 699#ifndef SMALL 700void 701setifrtlabel(const char *label, int d) 702{ 703 if (d != 0) 704 ifr.ifr_data = (caddr_t)(const char *)""; 705 else 706 ifr.ifr_data = (caddr_t)label; 707 if (ioctl(sock, SIOCSIFRTLABEL, &ifr) == -1) 708 warn("SIOCSIFRTLABEL"); 709} 710#endif 711 712void 713setifnetmask(const char *addr, int ignored) 714{ 715 setmask++; 716 afp->af_getaddr(addr, MASK); 717 explicit_prefix = 1; 718} 719 720void 721setifbroadaddr(const char *addr, int ignored) 722{ 723 setbroad++; 724 afp->af_getaddr(addr, DSTADDR); 725} 726 727void 728setifipdst(const char *addr, int ignored) 729{ 730 in_getaddr(addr, DSTADDR); 731 setipdst++; 732 clearaddr = 0; 733 newaddr = 0; 734} 735 736#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) 737void 738notealias(const char *addr, int param) 739{ 740 if (setaddr && doalias == 0 && param < 0) 741 memcpy(rqtosa(af_ridreq), rqtosa(af_addreq), 742 rqtosa(af_addreq)->sa_len); 743 doalias = param; 744 if (param < 0) { 745 clearaddr = 1; 746 newaddr = 0; 747 } else 748 clearaddr = 0; 749} 750 751void 752setifdstaddr(const char *addr, int param) 753{ 754 setaddr++; 755 setipdst++; 756 afp->af_getaddr(addr, DSTADDR); 757} 758 759void 760addaf(const char *vname, int value) 761{ 762 struct if_afreq ifar; 763 764 strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name)); 765 ifar.ifar_af = value; 766 if (ioctl(sock, SIOCIFAFATTACH, (caddr_t)&ifar) == -1) 767 warn("SIOCIFAFATTACH"); 768} 769 770void 771removeaf(const char *vname, int value) 772{ 773 struct if_afreq ifar; 774 775 strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name)); 776 ifar.ifar_af = value; 777 if (ioctl(sock, SIOCIFAFDETACH, (caddr_t)&ifar) == -1) 778 warn("SIOCIFAFDETACH"); 779} 780 781void 782setia6flags(const char *vname, int value) 783{ 784 785 if (value < 0) { 786 value = -value; 787 in6_addreq.ifra_flags &= ~value; 788 } else 789 in6_addreq.ifra_flags |= value; 790} 791 792void 793setia6pltime(const char *val, int d) 794{ 795 796 setia6lifetime("pltime", val); 797} 798 799void 800setia6vltime(const char *val, int d) 801{ 802 803 setia6lifetime("vltime", val); 804} 805 806void 807setia6lifetime(const char *cmd, const char *val) 808{ 809 const char *errmsg = NULL; 810 time_t newval, t; 811 812 newval = strtonum(val, 0, 1000000, &errmsg); 813 if (errmsg) 814 errx(1, "invalid %s %s: %s", cmd, val, errmsg); 815 816 t = time(NULL); 817 818 if (afp->af_af != AF_INET6) 819 errx(1, "%s not allowed for this address family", cmd); 820 if (strcmp(cmd, "vltime") == 0) { 821 in6_addreq.ifra_lifetime.ia6t_expire = t + newval; 822 in6_addreq.ifra_lifetime.ia6t_vltime = newval; 823 } else if (strcmp(cmd, "pltime") == 0) { 824 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; 825 in6_addreq.ifra_lifetime.ia6t_pltime = newval; 826 } 827} 828 829void 830setia6eui64(const char *cmd, int val) 831{ 832 struct ifaddrs *ifap, *ifa; 833 const struct sockaddr_in6 *sin6 = NULL; 834 const struct in6_addr *lladdr = NULL; 835 struct in6_addr *in6; 836 837 if (afp->af_af != AF_INET6) 838 errx(1, "%s not allowed for this address family", cmd); 839 840 addaf(ifname, AF_INET6); 841 842 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; 843 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) 844 errx(1, "interface index is already filled"); 845 if (getifaddrs(&ifap) != 0) 846 err(1, "getifaddrs"); 847 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 848 if (ifa->ifa_addr->sa_family == AF_INET6 && 849 strcmp(ifa->ifa_name, ifname) == 0) { 850 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr; 851 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 852 lladdr = &sin6->sin6_addr; 853 break; 854 } 855 } 856 } 857 if (!lladdr) 858 errx(1, "could not determine link local address"); 859 860 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); 861 862 freeifaddrs(ifap); 863} 864 865const char * 866get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 867{ 868 int len = *lenp, hexstr; 869 u_int8_t *p = buf; 870 871 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 872 if (hexstr) 873 val += 2; 874 for (;;) { 875 if (*val == '\0') 876 break; 877 if (sep != NULL && strchr(sep, *val) != NULL) { 878 val++; 879 break; 880 } 881 if (hexstr) { 882 if (!isxdigit((u_char)val[0]) || 883 !isxdigit((u_char)val[1])) { 884 warnx("bad hexadecimal digits"); 885 return NULL; 886 } 887 } 888 if (p > buf + len) { 889 if (hexstr) 890 warnx("hexadecimal digits too long"); 891 else 892 warnx("strings too long"); 893 return NULL; 894 } 895 if (hexstr) { 896#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 897 *p++ = (tohex((u_char)val[0]) << 4) | 898 tohex((u_char)val[1]); 899#undef tohex 900 val += 2; 901 } else { 902 if (*val == '\\' && 903 sep != NULL && strchr(sep, *(val + 1)) != NULL) 904 val++; 905 *p++ = *val++; 906 } 907 } 908 len = p - buf; 909 if (len < *lenp) 910 memset(p, 0, *lenp - len); 911 *lenp = len; 912 return val; 913} 914 915int 916len_string(const u_int8_t *buf, int len) 917{ 918 int i = 0, hasspc = 0; 919 920 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') { 921 for (; i < len; i++) { 922 /* Only print 7-bit ASCII keys */ 923 if (buf[i] & 0x80 || !isprint(buf[i])) 924 break; 925 if (isspace(buf[i])) 926 hasspc++; 927 } 928 } 929 if (i == len) { 930 if (hasspc || len == 0) 931 return len + 2; 932 else 933 return len; 934 } else 935 return (len * 2) + 2; 936} 937 938int 939print_string(const u_int8_t *buf, int len) 940{ 941 int i = 0, hasspc = 0; 942 943 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') { 944 for (; i < len; i++) { 945 /* Only print 7-bit ASCII keys */ 946 if (buf[i] & 0x80 || !isprint(buf[i])) 947 break; 948 if (isspace(buf[i])) 949 hasspc++; 950 } 951 } 952 if (i == len) { 953 if (hasspc || len == 0) { 954 printf("\"%.*s\"", len, buf); 955 return len + 2; 956 } else { 957 printf("%.*s", len, buf); 958 return len; 959 } 960 } else { 961 printf("0x"); 962 for (i = 0; i < len; i++) 963 printf("%02x", buf[i]); 964 return (len * 2) + 2; 965 } 966} 967 968static void 969print_tunnel(const struct if_laddrreq *req) 970{ 971 char psrcaddr[NI_MAXHOST]; 972 char pdstaddr[NI_MAXHOST]; 973 const char *ver = ""; 974 const int niflag = NI_NUMERICHOST; 975 976 if (req == NULL) { 977 printf("(unset)"); 978 return; 979 } 980 981 psrcaddr[0] = pdstaddr[0] = '\0'; 982 983 if (getnameinfo((struct sockaddr *)&req->addr, req->addr.ss_len, 984 psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0) 985 strlcpy(psrcaddr, "<error>", sizeof(psrcaddr)); 986 if (req->addr.ss_family == AF_INET6) 987 ver = "6"; 988 989 printf("inet%s %s", ver, psrcaddr); 990 991 if (req->dstaddr.ss_family != AF_UNSPEC) { 992 in_port_t dstport = 0; 993 const struct sockaddr_in *sin; 994 const struct sockaddr_in6 *sin6; 995 996 if (getnameinfo((struct sockaddr *)&req->dstaddr, 997 req->dstaddr.ss_len, pdstaddr, sizeof(pdstaddr), 998 0, 0, niflag) != 0) 999 strlcpy(pdstaddr, "<error>", sizeof(pdstaddr)); 1000 1001 printf(" -> %s", pdstaddr); 1002 1003 switch (req->dstaddr.ss_family) { 1004 case AF_INET: 1005 sin = (const struct sockaddr_in *)&req->dstaddr; 1006 dstport = sin->sin_port; 1007 break; 1008 case AF_INET6: 1009 sin6 = (const struct sockaddr_in6 *)&req->dstaddr; 1010 dstport = sin6->sin6_port; 1011 break; 1012 } 1013 1014 if (dstport) 1015 printf(":%u", ntohs(dstport)); 1016 } 1017} 1018 1019static void 1020phys_status(int force) 1021{ 1022 struct if_laddrreq req; 1023 struct if_laddrreq *r = &req; 1024 1025 memset(&req, 0, sizeof(req)); 1026 (void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)); 1027 if (ioctl(sock, SIOCGLIFPHYADDR, (caddr_t)&req) == -1) { 1028 if (errno != EADDRNOTAVAIL) 1029 return; 1030 1031 r = NULL; 1032 } 1033 1034 printf("\ttunnel: "); 1035 print_tunnel(r); 1036 1037 if (ioctl(sock, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0) { 1038 if (ifr.ifr_ttl == -1) 1039 printf(" ttl copy"); 1040 else if (ifr.ifr_ttl > 0) 1041 printf(" ttl %d", ifr.ifr_ttl); 1042 } 1043 1044 if (ioctl(sock, SIOCGLIFPHYDF, (caddr_t)&ifr) == 0) 1045 printf(" %s", ifr.ifr_df ? "df" : "nodf"); 1046 1047#ifndef SMALL 1048 if (ioctl(sock, SIOCGLIFPHYECN, (caddr_t)&ifr) == 0) 1049 printf(" %s", ifr.ifr_metric ? "ecn" : "noecn"); 1050 1051 if (ioctl(sock, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 && 1052 (rdomainid != 0 || ifr.ifr_rdomainid != 0)) 1053 printf(" rdomain %d", ifr.ifr_rdomainid); 1054#endif 1055 printf("\n"); 1056} 1057 1058#ifndef SMALL 1059const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST; 1060 1061const struct ifmedia_status_description ifm_status_descriptions[] = 1062 IFM_STATUS_DESCRIPTIONS; 1063#endif 1064 1065const struct if_status_description if_status_descriptions[] = 1066 LINK_STATE_DESCRIPTIONS; 1067 1068const char * 1069get_linkstate(int mt, int link_state) 1070{ 1071 const struct if_status_description *p; 1072 static char buf[8]; 1073 1074 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 1075 if (LINK_STATE_DESC_MATCH(p, mt, link_state)) 1076 return (p->ifs_string); 1077 } 1078 snprintf(buf, sizeof(buf), "[#%d]", link_state); 1079 return buf; 1080} 1081 1082/* 1083 * Print the status of the interface. If an address family was 1084 * specified, show it and it only; otherwise, show them all. 1085 */ 1086void 1087status(int link, struct sockaddr_dl *sdl, int ls) 1088{ 1089 const struct afswtch *p = afp; 1090 struct ifmediareq ifmr; 1091#ifndef SMALL 1092 struct ifreq ifrdesc; 1093 char ifdescr[IFDESCRSIZE]; 1094#endif 1095 uint64_t *media_list; 1096 char sep; 1097 1098 1099 printf("%s: ", ifname); 1100 printb("flags", flags | (xflags << 16), IFFBITS); 1101 if (rdomainid) 1102 printf(" rdomain %d", rdomainid); 1103 if (metric) 1104 printf(" metric %lu", metric); 1105 if (mtu) 1106 printf(" mtu %lu", mtu); 1107 putchar('\n'); 1108 if (sdl != NULL && sdl->sdl_alen && 1109 (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP)) 1110 (void)printf("\tlladdr %s\n", ether_ntoa( 1111 (struct ether_addr *)LLADDR(sdl))); 1112 1113 sep = '\t'; 1114#ifndef SMALL 1115 (void) memset(&ifrdesc, 0, sizeof(ifrdesc)); 1116 (void) strlcpy(ifrdesc.ifr_name, ifname, sizeof(ifrdesc.ifr_name)); 1117 ifrdesc.ifr_data = (caddr_t)&ifdescr; 1118 if (ioctl(sock, SIOCGIFDESCR, &ifrdesc) == 0 && 1119 strlen(ifrdesc.ifr_data)) 1120 printf("\tdescription: %s\n", ifrdesc.ifr_data); 1121 1122 if (sdl != NULL) { 1123 printf("%cindex %u", sep, sdl->sdl_index); 1124 sep = ' '; 1125 } 1126 if (ioctl(sock, SIOCGIFPRIORITY, &ifrdesc) == 0) { 1127 printf("%cpriority %d", sep, ifrdesc.ifr_metric); 1128 sep = ' '; 1129 } 1130#endif 1131 printf("%cllprio %d\n", sep, llprio); 1132 1133 (void) memset(&ifmr, 0, sizeof(ifmr)); 1134 (void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 1135 1136 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 1137 /* 1138 * Interface doesn't support SIOC{G,S}IFMEDIA. 1139 */ 1140 if (ls != LINK_STATE_UNKNOWN) 1141 printf("\tstatus: %s\n", 1142 get_linkstate(sdl->sdl_type, ls)); 1143 goto proto_status; 1144 } 1145 1146 if (ifmr.ifm_count == 0) { 1147 warnx("%s: no media types?", ifname); 1148 goto proto_status; 1149 } 1150 1151 media_list = calloc(ifmr.ifm_count, sizeof(*media_list)); 1152 if (media_list == NULL) 1153 err(1, "calloc"); 1154 ifmr.ifm_ulist = media_list; 1155 1156 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) 1157 err(1, "SIOCGIFMEDIA"); 1158 1159#ifdef SMALL 1160 printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls)); 1161#else 1162 if (ifmr.ifm_status & IFM_AVALID) { 1163 const struct ifmedia_status_description *ifms; 1164 int bitno, found = 0; 1165 1166 printf("\tstatus: "); 1167 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) { 1168 for (ifms = ifm_status_descriptions; 1169 ifms->ifms_valid != 0; ifms++) { 1170 if (ifms->ifms_type != 1171 IFM_TYPE(ifmr.ifm_current) || 1172 ifms->ifms_valid != 1173 ifm_status_valid_list[bitno]) 1174 continue; 1175 printf("%s%s", found ? ", " : "", 1176 IFM_STATUS_DESC(ifms, ifmr.ifm_status)); 1177 found = 1; 1178 1179 /* 1180 * For each valid indicator bit, there's 1181 * only one entry for each media type, so 1182 * terminate the inner loop now. 1183 */ 1184 break; 1185 } 1186 } 1187 1188 if (found == 0) 1189 printf("unknown"); 1190 putchar('\n'); 1191 } 1192 1193#endif 1194 free(media_list); 1195 1196 proto_status: 1197 if (link == 0) { 1198 if ((p = afp) != NULL) { 1199 p->af_status(1); 1200 } else for (p = afs; p->af_name; p++) { 1201 ifr.ifr_addr.sa_family = p->af_af; 1202 p->af_status(0); 1203 } 1204 } 1205 1206 phys_status(0); 1207} 1208 1209void 1210in_status(int force) 1211{ 1212 struct sockaddr_in *sin, sin2; 1213 1214 getsock(AF_INET); 1215 if (sock == -1) { 1216 if (errno == EPROTONOSUPPORT) 1217 return; 1218 err(1, "socket"); 1219 } 1220 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1221 sin = (struct sockaddr_in *)&ifr.ifr_addr; 1222 1223 /* 1224 * We keep the interface address and reset it before each 1225 * ioctl() so we can get ifaliases information (as opposed 1226 * to the primary interface netmask/dstaddr/broadaddr, if 1227 * the ifr_addr field is zero). 1228 */ 1229 memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2)); 1230 1231 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1232 if (ioctl(sock, SIOCGIFADDR, (caddr_t)&ifr) == -1) { 1233 warn("SIOCGIFADDR"); 1234 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 1235 } 1236 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1237 sin = (struct sockaddr_in *)&ifr.ifr_addr; 1238 printf("\tinet %s", inet_ntoa(sin->sin_addr)); 1239 memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2)); 1240 if (ioctl(sock, SIOCGIFNETMASK, (caddr_t)&ifr) == -1) { 1241 if (errno != EADDRNOTAVAIL) 1242 warn("SIOCGIFNETMASK"); 1243 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 1244 } else 1245 netmask.sin_addr = 1246 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; 1247 if (flags & IFF_POINTOPOINT) { 1248 memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2)); 1249 if (ioctl(sock, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) { 1250 if (errno == EADDRNOTAVAIL) 1251 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 1252 else 1253 warn("SIOCGIFDSTADDR"); 1254 } 1255 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1256 sin = (struct sockaddr_in *)&ifr.ifr_dstaddr; 1257 printf(" --> %s", inet_ntoa(sin->sin_addr)); 1258 } 1259 printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr)); 1260 if (flags & IFF_BROADCAST) { 1261 memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2)); 1262 if (ioctl(sock, SIOCGIFBRDADDR, (caddr_t)&ifr) == -1) { 1263 if (errno == EADDRNOTAVAIL) 1264 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 1265 else 1266 warn("SIOCGIFBRDADDR"); 1267 } 1268 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1269 sin = (struct sockaddr_in *)&ifr.ifr_addr; 1270 if (sin->sin_addr.s_addr != 0) 1271 printf(" broadcast %s", inet_ntoa(sin->sin_addr)); 1272 } 1273 putchar('\n'); 1274} 1275 1276void 1277setifprefixlen(const char *addr, int d) 1278{ 1279 setmask++; 1280 if (afp->af_getprefix) 1281 afp->af_getprefix(addr, MASK); 1282 explicit_prefix = 1; 1283} 1284 1285void 1286in6_fillscopeid(struct sockaddr_in6 *sin6) 1287{ 1288#ifdef __KAME__ 1289 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1290 sin6->sin6_scope_id = 1291 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 1292 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; 1293 } 1294#endif /* __KAME__ */ 1295} 1296 1297/* XXX not really an alias */ 1298void 1299in6_alias(struct in6_ifreq *creq) 1300{ 1301 struct sockaddr_in6 *sin6; 1302 struct in6_ifreq ifr6; /* shadows file static variable */ 1303 u_int32_t scopeid; 1304 char hbuf[NI_MAXHOST]; 1305 const int niflag = NI_NUMERICHOST; 1306 1307 /* Get the non-alias address for this interface. */ 1308 getsock(AF_INET6); 1309 if (sock == -1) { 1310 if (errno == EPROTONOSUPPORT) 1311 return; 1312 err(1, "socket"); 1313 } 1314 1315 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr; 1316 1317 in6_fillscopeid(sin6); 1318 scopeid = sin6->sin6_scope_id; 1319 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, 1320 hbuf, sizeof(hbuf), NULL, 0, niflag) != 0) 1321 strlcpy(hbuf, "", sizeof hbuf); 1322 printf("\tinet6 %s", hbuf); 1323 1324 if (flags & IFF_POINTOPOINT) { 1325 (void) memset(&ifr6, 0, sizeof(ifr6)); 1326 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 1327 ifr6.ifr_addr = creq->ifr_addr; 1328 if (ioctl(sock, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) == -1) { 1329 if (errno != EADDRNOTAVAIL) 1330 warn("SIOCGIFDSTADDR_IN6"); 1331 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr)); 1332 ifr6.ifr_addr.sin6_family = AF_INET6; 1333 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); 1334 } 1335 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr; 1336 in6_fillscopeid(sin6); 1337 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, 1338 hbuf, sizeof(hbuf), NULL, 0, niflag) != 0) 1339 strlcpy(hbuf, "", sizeof hbuf); 1340 printf(" -> %s", hbuf); 1341 } 1342 1343 (void) memset(&ifr6, 0, sizeof(ifr6)); 1344 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 1345 ifr6.ifr_addr = creq->ifr_addr; 1346 if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) { 1347 if (errno != EADDRNOTAVAIL) 1348 warn("SIOCGIFNETMASK_IN6"); 1349 } else { 1350 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr; 1351 printf(" prefixlen %d", prefix(&sin6->sin6_addr, 1352 sizeof(struct in6_addr))); 1353 } 1354 1355 (void) memset(&ifr6, 0, sizeof(ifr6)); 1356 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 1357 ifr6.ifr_addr = creq->ifr_addr; 1358 if (ioctl(sock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) { 1359 if (errno != EADDRNOTAVAIL) 1360 warn("SIOCGIFAFLAG_IN6"); 1361 } else { 1362 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST) 1363 printf(" anycast"); 1364 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE) 1365 printf(" tentative"); 1366 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) 1367 printf(" duplicated"); 1368 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED) 1369 printf(" detached"); 1370 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) 1371 printf(" deprecated"); 1372 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF) 1373 printf(" autoconf"); 1374 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TEMPORARY) 1375 printf(" autoconfprivacy"); 1376 } 1377 1378 if (scopeid) 1379 printf(" scopeid 0x%x", scopeid); 1380 1381 if (Lflag) { 1382 struct in6_addrlifetime *lifetime; 1383 1384 (void) memset(&ifr6, 0, sizeof(ifr6)); 1385 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 1386 ifr6.ifr_addr = creq->ifr_addr; 1387 lifetime = &ifr6.ifr_ifru.ifru_lifetime; 1388 if (ioctl(sock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) { 1389 if (errno != EADDRNOTAVAIL) 1390 warn("SIOCGIFALIFETIME_IN6"); 1391 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) { 1392 time_t t = time(NULL); 1393 1394 printf(" pltime "); 1395 if (lifetime->ia6t_preferred) { 1396 printf("%s", lifetime->ia6t_preferred < t 1397 ? "0" : 1398 sec2str(lifetime->ia6t_preferred - t)); 1399 } else 1400 printf("infty"); 1401 1402 printf(" vltime "); 1403 if (lifetime->ia6t_expire) { 1404 printf("%s", lifetime->ia6t_expire < t 1405 ? "0" 1406 : sec2str(lifetime->ia6t_expire - t)); 1407 } else 1408 printf("infty"); 1409 } 1410 } 1411 1412 printf("\n"); 1413} 1414 1415void 1416in6_status(int force) 1417{ 1418 in6_alias((struct in6_ifreq *)&ifr6); 1419} 1420 1421#ifndef SMALL 1422void 1423settunnel(const char *src, const char *dst) 1424{ 1425 char buf[HOST_NAME_MAX+1 + sizeof (":65535")], *dstport; 1426 const char *dstip; 1427 struct addrinfo *srcres, *dstres; 1428 int ecode; 1429 struct if_laddrreq req; 1430 1431 if (strchr(dst, ':') == NULL || strchr(dst, ':') != strrchr(dst, ':')) { 1432 /* no port or IPv6 */ 1433 dstip = dst; 1434 dstport = NULL; 1435 } else { 1436 if (strlcpy(buf, dst, sizeof(buf)) >= sizeof(buf)) 1437 errx(1, "%s bad value", dst); 1438 dstport = strchr(buf, ':'); 1439 *dstport++ = '\0'; 1440 dstip = buf; 1441 } 1442 1443 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) 1444 errx(1, "error in parsing address string: %s", 1445 gai_strerror(ecode)); 1446 1447 if ((ecode = getaddrinfo(dstip, dstport, NULL, &dstres)) != 0) 1448 errx(1, "error in parsing address string: %s", 1449 gai_strerror(ecode)); 1450 1451 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 1452 errx(1, 1453 "source and destination address families do not match"); 1454 1455 memset(&req, 0, sizeof(req)); 1456 (void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)); 1457 memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen); 1458 memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen); 1459 if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1) 1460 warn("SIOCSLIFPHYADDR"); 1461 1462 freeaddrinfo(srcres); 1463 freeaddrinfo(dstres); 1464} 1465 1466void 1467settunneladdr(const char *addr, int ignored) 1468{ 1469 struct addrinfo hints, *res; 1470 struct if_laddrreq req; 1471 ssize_t len; 1472 int rv; 1473 1474 memset(&hints, 0, sizeof(hints)); 1475 hints.ai_family = AF_UNSPEC; 1476 hints.ai_socktype = SOCK_DGRAM; 1477 hints.ai_protocol = 0; 1478 hints.ai_flags = AI_PASSIVE; 1479 1480 rv = getaddrinfo(addr, NULL, &hints, &res); 1481 if (rv != 0) 1482 errx(1, "tunneladdr %s: %s", addr, gai_strerror(rv)); 1483 1484 memset(&req, 0, sizeof(req)); 1485 len = strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)); 1486 if (len >= sizeof(req.iflr_name)) 1487 errx(1, "%s: Interface name too long", ifname); 1488 1489 memcpy(&req.addr, res->ai_addr, res->ai_addrlen); 1490 1491 req.dstaddr.ss_len = 2; 1492 req.dstaddr.ss_family = AF_UNSPEC; 1493 1494 if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1) 1495 warn("tunneladdr %s", addr); 1496 1497 freeaddrinfo(res); 1498} 1499 1500void 1501deletetunnel(const char *ignored, int alsoignored) 1502{ 1503 if (ioctl(sock, SIOCDIFPHYADDR, &ifr) == -1) 1504 warn("SIOCDIFPHYADDR"); 1505} 1506 1507void 1508settunnelinst(const char *id, int param) 1509{ 1510 const char *errmsg = NULL; 1511 int rdomainid; 1512 1513 rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg); 1514 if (errmsg) 1515 errx(1, "rdomain %s: %s", id, errmsg); 1516 1517 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1518 ifr.ifr_rdomainid = rdomainid; 1519 if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1) 1520 warn("SIOCSLIFPHYRTABLE"); 1521} 1522 1523void 1524unsettunnelinst(const char *ignored, int alsoignored) 1525{ 1526 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1527 ifr.ifr_rdomainid = 0; 1528 if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1) 1529 warn("SIOCSLIFPHYRTABLE"); 1530} 1531 1532void 1533settunnelttl(const char *id, int param) 1534{ 1535 const char *errmsg = NULL; 1536 int ttl; 1537 1538 if (strcmp(id, "copy") == 0) 1539 ttl = -1; 1540 else { 1541 ttl = strtonum(id, 0, 0xff, &errmsg); 1542 if (errmsg) 1543 errx(1, "tunnelttl %s: %s", id, errmsg); 1544 } 1545 1546 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1547 ifr.ifr_ttl = ttl; 1548 if (ioctl(sock, SIOCSLIFPHYTTL, (caddr_t)&ifr) == -1) 1549 warn("SIOCSLIFPHYTTL"); 1550} 1551 1552void 1553utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen) 1554{ 1555 uint16_t c; 1556 1557 while (outlen > 0) { 1558 c = inlen > 0 ? letoh16(*in) : 0; 1559 if (c == 0 || --outlen == 0) { 1560 /* always NUL terminate result */ 1561 *out = '\0'; 1562 break; 1563 } 1564 *out++ = isascii(c) ? (char)c : '?'; 1565 in++; 1566 inlen--; 1567 } 1568} 1569 1570int 1571char_to_utf16(const char *in, uint16_t *out, size_t outlen) 1572{ 1573 int n = 0; 1574 uint16_t c; 1575 1576 for (;;) { 1577 c = *in++; 1578 1579 if (c == '\0') { 1580 /* 1581 * NUL termination is not required, but zero out the 1582 * residual buffer 1583 */ 1584 memset(out, 0, outlen); 1585 return n; 1586 } 1587 if (outlen < sizeof (*out)) 1588 return -1; 1589 1590 *out++ = htole16(c); 1591 n += sizeof (*out); 1592 outlen -= sizeof (*out); 1593 } 1594} 1595 1596#endif 1597 1598#define SIN(x) ((struct sockaddr_in *) &(x)) 1599struct sockaddr_in *sintab[] = { 1600SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr), 1601SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)}; 1602 1603void 1604in_getaddr(const char *s, int which) 1605{ 1606 struct sockaddr_in *sin = sintab[which], tsin; 1607 struct hostent *hp; 1608 int bits, l; 1609 char p[3]; 1610 1611 bzero(&tsin, sizeof(tsin)); 1612 sin->sin_len = sizeof(*sin); 1613 if (which != MASK) 1614 sin->sin_family = AF_INET; 1615 1616 if (which == ADDR && strrchr(s, '/') != NULL && 1617 (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr, 1618 sizeof(tsin.sin_addr))) != -1) { 1619 l = snprintf(p, sizeof(p), "%d", bits); 1620 if (l < 0 || l >= sizeof(p)) 1621 errx(1, "%d: bad prefixlen", bits); 1622 setmask++; 1623 in_getprefix(p, MASK); 1624 memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr)); 1625 } else if (inet_aton(s, &sin->sin_addr) == 0) { 1626 if ((hp = gethostbyname(s))) 1627 memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); 1628 else 1629 errx(1, "%s: bad value", s); 1630 } 1631} 1632 1633void 1634in_getprefix(const char *plen, int which) 1635{ 1636 struct sockaddr_in *sin = sintab[which]; 1637 const char *errmsg = NULL; 1638 u_char *cp; 1639 int len; 1640 1641 len = strtonum(plen, 0, 32, &errmsg); 1642 if (errmsg) 1643 errx(1, "prefix %s: %s", plen, errmsg); 1644 1645 sin->sin_len = sizeof(*sin); 1646 if (which != MASK) 1647 sin->sin_family = AF_INET; 1648 if ((len == 0) || (len == 32)) { 1649 memset(&sin->sin_addr, 0xff, sizeof(struct in_addr)); 1650 return; 1651 } 1652 memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr)); 1653 for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8) 1654 *cp++ = 0xff; 1655 if (len) 1656 *cp = 0xff << (8 - len); 1657} 1658 1659/* 1660 * Print a value a la the %b format of the kernel's printf 1661 */ 1662void 1663printb(char *s, unsigned int v, unsigned char *bits) 1664{ 1665 int i, any = 0; 1666 unsigned char c; 1667 1668 if (bits && *bits == 8) 1669 printf("%s=%o", s, v); 1670 else 1671 printf("%s=%x", s, v); 1672 1673 if (bits) { 1674 bits++; 1675 putchar('<'); 1676 while ((i = *bits++)) { 1677 if (v & (1 << (i-1))) { 1678 if (any) 1679 putchar(','); 1680 any = 1; 1681 for (; (c = *bits) > 32; bits++) 1682 putchar(c); 1683 } else 1684 for (; *bits > 32; bits++) 1685 ; 1686 } 1687 putchar('>'); 1688 } 1689} 1690 1691/* 1692 * A simple version of printb for status output 1693 */ 1694void 1695printb_status(unsigned short v, unsigned char *bits) 1696{ 1697 int i, any = 0; 1698 unsigned char c; 1699 1700 if (bits) { 1701 bits++; 1702 while ((i = *bits++)) { 1703 if (v & (1 << (i-1))) { 1704 if (any) 1705 putchar(','); 1706 any = 1; 1707 for (; (c = *bits) > 32; bits++) 1708 putchar(tolower(c)); 1709 } else 1710 for (; *bits > 32; bits++) 1711 ; 1712 } 1713 } 1714} 1715 1716#define SIN6(x) ((struct sockaddr_in6 *) &(x)) 1717struct sockaddr_in6 *sin6tab[] = { 1718SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), 1719SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)}; 1720 1721void 1722in6_getaddr(const char *s, int which) 1723{ 1724 struct sockaddr_in6 *sin6 = sin6tab[which]; 1725 struct addrinfo hints, *res; 1726 char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen; 1727 int error; 1728 1729 memset(&hints, 0, sizeof(hints)); 1730 hints.ai_family = AF_INET6; 1731 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 1732 1733 if (which == ADDR && strchr(s, '/') != NULL) { 1734 if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf)) 1735 errx(1, "%s: bad value", s); 1736 pfxlen = strchr(buf, '/'); 1737 *pfxlen++ = '\0'; 1738 s = buf; 1739 setmask++; 1740 in6_getprefix(pfxlen, MASK); 1741 explicit_prefix = 1; 1742 } 1743 1744 error = getaddrinfo(s, "0", &hints, &res); 1745 if (error) 1746 errx(1, "%s: %s", s, gai_strerror(error)); 1747 memcpy(sin6, res->ai_addr, res->ai_addrlen); 1748#ifdef __KAME__ 1749 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 1750 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 && 1751 sin6->sin6_scope_id) { 1752 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] = 1753 htons(sin6->sin6_scope_id & 0xffff); 1754 sin6->sin6_scope_id = 0; 1755 } 1756#endif /* __KAME__ */ 1757 freeaddrinfo(res); 1758} 1759 1760void 1761in6_getprefix(const char *plen, int which) 1762{ 1763 struct sockaddr_in6 *sin6 = sin6tab[which]; 1764 const char *errmsg = NULL; 1765 u_char *cp; 1766 int len; 1767 1768 len = strtonum(plen, 0, 128, &errmsg); 1769 if (errmsg) 1770 errx(1, "prefix %s: %s", plen, errmsg); 1771 1772 sin6->sin6_len = sizeof(*sin6); 1773 if (which != MASK) 1774 sin6->sin6_family = AF_INET6; 1775 if ((len == 0) || (len == 128)) { 1776 memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr)); 1777 return; 1778 } 1779 memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr)); 1780 for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8) 1781 *cp++ = 0xff; 1782 if (len) 1783 *cp = 0xff << (8 - len); 1784} 1785 1786int 1787prefix(void *val, int size) 1788{ 1789 u_char *nam = (u_char *)val; 1790 int byte, bit, plen = 0; 1791 1792 for (byte = 0; byte < size; byte++, plen += 8) 1793 if (nam[byte] != 0xff) 1794 break; 1795 if (byte == size) 1796 return (plen); 1797 for (bit = 7; bit != 0; bit--, plen++) 1798 if (!(nam[byte] & (1 << bit))) 1799 break; 1800 for (; bit != 0; bit--) 1801 if (nam[byte] & (1 << bit)) 1802 return (0); 1803 byte++; 1804 for (; byte < size; byte++) 1805 if (nam[byte]) 1806 return (0); 1807 return (plen); 1808} 1809 1810/* Print usage and exit */ 1811__dead void 1812usage(void) 1813{ 1814 fprintf(stderr, 1815 "usage: ifaddr interface [address_family] " 1816 "[address [dest_address]]\n" 1817 "\t\t[parameters]\n"); 1818 exit(1); 1819} 1820 1821#ifndef SMALL 1822void 1823printifhwfeatures(const char *unused, int show) 1824{ 1825 struct if_data ifrdat; 1826 1827 if (!show) { 1828 if (showcapsflag) 1829 usage(); 1830 showcapsflag = 1; 1831 return; 1832 } 1833 bzero(&ifrdat, sizeof(ifrdat)); 1834 ifr.ifr_data = (caddr_t)&ifrdat; 1835 if (ioctl(sock, SIOCGIFDATA, (caddr_t)&ifr) == -1) 1836 err(1, "SIOCGIFDATA"); 1837 printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS); 1838 1839 if (ioctl(sock, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) { 1840 if (ifr.ifr_hardmtu) 1841 printf(" hardmtu %u", ifr.ifr_hardmtu); 1842 } 1843 putchar('\n'); 1844} 1845#endif 1846 1847char * 1848sec2str(time_t total) 1849{ 1850 static char result[256]; 1851 char *p = result; 1852 char *end = &result[sizeof(result)]; 1853 1854 snprintf(p, end - p, "%lld", (long long)total); 1855 return (result); 1856} 1857 1858#ifndef SMALL 1859void 1860setrdomain(const char *id, int param) 1861{ 1862 const char *errmsg = NULL; 1863 int rdomainid; 1864 1865 rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg); 1866 if (errmsg) 1867 errx(1, "rdomain %s: %s", id, errmsg); 1868 1869 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1870 ifr.ifr_rdomainid = rdomainid; 1871 if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1) 1872 warn("SIOCSIFRDOMAIN"); 1873} 1874 1875void 1876unsetrdomain(const char *ignored, int alsoignored) 1877{ 1878 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1879 ifr.ifr_rdomainid = 0; 1880 if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1) 1881 warn("SIOCSIFRDOMAIN"); 1882} 1883#endif 1884 1885#ifdef SMALL 1886void 1887setignore(const char *id, int param) 1888{ 1889 /* just digest the command */ 1890} 1891#endif 1892