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