1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 /* 6 * Copyright (c) 1983 Regents of the University of California. 7 * All rights reserved. The Berkeley software License Agreement 8 * specifies the terms and conditions for redistribution. 9 */ 10 11 #pragma ident "%Z%%M% %I% %E% SMI" 12 13 #include "defs.h" 14 #include "strings.h" 15 #include "ifconfig.h" 16 #include <compat.h> 17 18 #include <sys/dlpi.h> 19 #include <libdlpi.h> 20 21 #define LOOPBACK_IF "lo0" 22 23 #define NONE_STR "none" 24 25 #ifndef ARP_MOD_NAME 26 #define ARP_MOD_NAME "arp" 27 #endif 28 29 #ifndef IP_DEV_NAME 30 #define IP_DEV_NAME "/dev/ip" 31 #endif 32 33 #ifndef IP_MOD_NAME 34 #define IP_MOD_NAME "ip" 35 #endif 36 37 #ifndef IP6_DEV_NAME 38 #define IP6_DEV_NAME "/dev/ip6" 39 #endif 40 41 #ifndef UDP_DEV_NAME 42 #define UDP_DEV_NAME "/dev/udp" 43 #endif 44 45 #ifndef UDP6_DEV_NAME 46 #define UDP6_DEV_NAME "/dev/udp6" 47 #endif 48 49 #define ADDRBITS_V4 32 /* number of bits in IPv4 address */ 50 #define ADDRBITS_V6 128 /* number of bits in IPv6 address */ 51 52 #define AF_FUNC_STATUS 1 /* af_status func reports status */ 53 #define AF_FUNC_CONFIGINFO 2 /* af_status func reports configinfo */ 54 55 typedef struct if_flags { 56 uint64_t iff_value; 57 char *iff_name; 58 } if_flags_t; 59 60 static if_flags_t if_flags_tbl[] = { 61 { IFF_UP, "UP" }, 62 { IFF_BROADCAST, "BROADCAST" }, 63 { IFF_DEBUG, "DEBUG" }, 64 { IFF_LOOPBACK, "LOOPBACK" }, 65 { IFF_POINTOPOINT, "POINTOPOINT" }, 66 { IFF_NOTRAILERS, "NOTRAILERS" }, 67 { IFF_RUNNING, "RUNNING" }, 68 { IFF_NOARP, "NOARP" }, 69 { IFF_PROMISC, "PROMISC" }, 70 { IFF_ALLMULTI, "ALLMULTI" }, 71 { IFF_INTELLIGENT, "INTELLIGENT" }, 72 { IFF_MULTICAST, "MULTICAST" }, 73 { IFF_MULTI_BCAST, "MULTI_BCAST" }, 74 { IFF_UNNUMBERED, "UNNUMBERED" }, 75 { IFF_DHCPRUNNING, "DHCP" }, 76 { IFF_PRIVATE, "PRIVATE" }, 77 { IFF_NOXMIT, "NOXMIT" }, 78 { IFF_NOLOCAL, "NOLOCAL" }, 79 { IFF_DEPRECATED, "DEPRECATED" }, 80 { IFF_ADDRCONF, "ADDRCONF" }, 81 { IFF_ROUTER, "ROUTER" }, 82 { IFF_NONUD, "NONUD" }, 83 { IFF_ANYCAST, "ANYCAST" }, 84 { IFF_NORTEXCH, "NORTEXCH" }, 85 { IFF_IPV4, "IPv4" }, 86 { IFF_IPV6, "IPv6" }, 87 { IFF_MIPRUNNING, "MIP" }, 88 { IFF_NOFAILOVER, "NOFAILOVER" }, 89 { IFF_FAILED, "FAILED" }, 90 { IFF_STANDBY, "STANDBY" }, 91 { IFF_INACTIVE, "INACTIVE" }, 92 { IFF_OFFLINE, "OFFLINE" }, 93 { IFF_XRESOLV, "XRESOLV" }, 94 { IFF_COS_ENABLED, "CoS" }, 95 { IFF_PREFERRED, "PREFERRED" }, 96 { IFF_TEMPORARY, "TEMPORARY" }, 97 { IFF_FIXEDMTU, "FIXEDMTU" }, 98 { IFF_VIRTUAL, "VIRTUAL"} 99 }; 100 101 static struct lifreq lifr; 102 /* current interface name a praticular function is accessing */ 103 static char name[LIFNAMSIZ]; 104 /* foreach interface saved name */ 105 static char origname[LIFNAMSIZ]; 106 static char savedname[LIFNAMSIZ]; /* For addif */ 107 static int setaddr; 108 static char partname[LIFNAMSIZ]; 109 110 uid_t euid; 111 112 /* 113 * Make sure the algorithm variables hold more than the sizeof an algorithm 114 * in PF_KEY. (For now, more than a uint8_t.) The NO_***_?ALG indicates that 115 * there was no algorithm requested, and in the ipsec_req that service should 116 * be disabled. (E.g. if ah_aalg remains NO_AH_AALG, then AH will be 117 * disabled on that tunnel.) 118 */ 119 #define NO_AH_AALG 256 120 #define NO_ESP_AALG 256 121 #define NO_ESP_EALG 256 122 123 /* 124 * iface_t 125 * used by setifether to create a list of interfaces to mark 126 * down-up when changing the ethernet address of an interface 127 */ 128 typedef struct iface { 129 struct lifreq lifr; 130 struct iface *next; /* pointer to the next list element */ 131 } iface_t; 132 133 static iface_t *logifs = NULL; /* list of logical interfaces */ 134 static iface_t *phyif = NULL; /* physical interface */ 135 136 int s; 137 int af = AF_INET; /* default address family */ 138 int debug = 0; 139 int all = 0; /* setifdhcp() needs to know this */ 140 int verbose = 0; 141 int v4compat = 0; /* Compatible printing format */ 142 boolean_t partial = _B_FALSE; 143 144 /* 145 * Function prototypes for command functions. 146 */ 147 static int addif(char *arg, int64_t param); 148 static int inetplumb(char *arg, int64_t param); 149 static int inetunplumb(char *arg, int64_t param); 150 static int removeif(char *arg, int64_t param); 151 static int setdebugflag(char *arg, int64_t param); 152 static int setifaddr(char *arg, int64_t param); 153 static int setifbroadaddr(char *arg, int64_t param); 154 static int setifdstaddr(char *arg, int64_t param); 155 static int setifether(char *arg, int64_t param); 156 static int setifflags(char *arg, int64_t param); 157 static int setifindex(char *arg, int64_t param); 158 static int setifmetric(char *arg, int64_t param); 159 static int setifmtu(char *arg, int64_t param); 160 static int setifnetmask(char *arg, int64_t param); 161 static int setifprefixlen(char *arg, int64_t param); 162 static int setifrevarp(char *arg, int64_t param); 163 static int setifsubnet(char *arg, int64_t param); 164 static int setiftdst(char *arg, int64_t param); 165 static int setiftoken(char *arg, int64_t param); 166 static int setiftsrc(char *arg, int64_t param); 167 static int setverboseflag(char *arg, int64_t param); 168 static int set_tun_ah_alg(char *arg, int64_t param); 169 static int set_tun_esp_auth_alg(char *arg, int64_t param); 170 static int set_tun_esp_encr_alg(char *arg, int64_t param); 171 static int modlist(char *arg, int64_t param); 172 static int modinsert(char *arg, int64_t param); 173 static int modremove(char *arg, int64_t param); 174 static int setifgroupname(char *arg, int64_t param); 175 static int configinfo(char *arg, int64_t param); 176 static void print_config_flags(uint64_t flags); 177 static void print_flags(uint64_t flags); 178 static void print_ifether(char *ifname); 179 static int set_tun_encap_limit(char *arg, int64_t param); 180 static int clr_tun_encap_limit(char *arg, int64_t param); 181 static int set_tun_hop_limit(char *arg, int64_t param); 182 static int setzone(char *arg, int64_t param); 183 static int setifsrc(char *arg, int64_t param); 184 185 #ifdef DEBUG 186 static int setnd(char *arg, int64_t param); 187 static int delnd(char *arg, int64_t param); 188 static int getnd(char *arg, int64_t param); 189 #endif /* DEBUG */ 190 191 /* 192 * Address family specific function prototypes. 193 */ 194 static void in_getaddr(char *s, struct sockaddr *saddr, int *plenp); 195 static void in_status(int force, uint64_t flags); 196 static void in_configinfo(int force, uint64_t flags); 197 static void in6_getaddr(char *s, struct sockaddr *saddr, int *plenp); 198 static void in6_status(int force, uint64_t flags); 199 static void in6_configinfo(int force, uint64_t flags); 200 201 /* 202 * Misc support functions 203 */ 204 static int devfs_entry(di_node_t node, di_minor_t minor, void *arg); 205 static void foreachinterface(void (*func)(), int argc, char *argv[], 206 int af, int64_t onflags, int64_t offflags, 207 int64_t lifc_flags); 208 static void ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp); 209 static int ifdad(char *ifname, struct sockaddr_in6 *laddr); 210 static boolean_t in_getmask(struct sockaddr_in *saddr, 211 boolean_t addr_set); 212 static int in_getprefixlen(char *addr, boolean_t slash, int plen); 213 static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 214 uchar_t *mask); 215 static int settaddr(char *, int (*)(icfg_handle_t, 216 const struct sockaddr *, socklen_t)); 217 static void status(void); 218 static void ifstatus(const char *); 219 static void usage(void); 220 static int strioctl(int s, int cmd, char *buf, int buflen); 221 static int setifdhcp(const char *caller, const char *ifname, 222 int argc, char *argv[]); 223 static int ip_domux2fd(int *, int *, int *, int *); 224 static int ip_plink(int, int, int, int); 225 static int modop(char *arg, char op); 226 static int get_lun(char *); 227 static void selectifs(int argc, char *argv[], int af, 228 struct lifreq *lifrp); 229 static int updownifs(iface_t *ifs, int up); 230 231 #define max(a, b) ((a) < (b) ? (b) : (a)) 232 233 /* 234 * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there 235 * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep 236 * on going rather than exit with an error. 237 */ 238 239 #define DHCP_EXIT_IF_FAILURE -1 240 #define DHCP_IPC_MAX_WAIT 15 /* max seconds to wait to start agent */ 241 242 #define NEXTARG 0xffffff /* command takes an argument */ 243 #define OPTARG 0xfffffe /* command takes an optional argument */ 244 #define AF_ANY (-1) 245 246 /* Refer to the comments in ifconfig() on the netmask "hack" */ 247 #define NETMASK_CMD "netmask" 248 struct sockaddr_storage g_netmask; 249 enum { G_NETMASK_NIL, G_NETMASK_PENDING, G_NETMASK_SET } 250 g_netmask_set = G_NETMASK_NIL; 251 252 struct cmd { 253 char *c_name; 254 int64_t c_parameter; /* NEXTARG means next argv */ 255 int (*c_func)(char *, int64_t); 256 int c_abortonfail; /* don't continue parsing args */ 257 /* for the current interface */ 258 int c_af; /* address family restrictions */ 259 } cmds[] = { 260 { "up", IFF_UP, setifflags, 0, AF_ANY }, 261 { "down", -IFF_UP, setifflags, 0, AF_ANY }, 262 { "trailers", -IFF_NOTRAILERS, setifflags, 0, AF_ANY }, 263 { "-trailers", IFF_NOTRAILERS, setifflags, 0, AF_ANY }, 264 { "arp", -IFF_NOARP, setifflags, 0, AF_INET }, 265 { "-arp", IFF_NOARP, setifflags, 0, AF_INET }, 266 { "router", IFF_ROUTER, setifflags, 0, AF_ANY }, 267 { "-router", -IFF_ROUTER, setifflags, 0, AF_ANY }, 268 { "private", IFF_PRIVATE, setifflags, 0, AF_ANY }, 269 { "-private", -IFF_PRIVATE, setifflags, 0, AF_ANY }, 270 { "xmit", -IFF_NOXMIT, setifflags, 0, AF_ANY }, 271 { "-xmit", IFF_NOXMIT, setifflags, 0, AF_ANY }, 272 { "-nud", IFF_NONUD, setifflags, 0, AF_INET6 }, 273 { "nud", -IFF_NONUD, setifflags, 0, AF_INET6 }, 274 { "anycast", IFF_ANYCAST, setifflags, 0, AF_ANY }, 275 { "-anycast", -IFF_ANYCAST, setifflags, 0, AF_ANY }, 276 { "local", -IFF_NOLOCAL, setifflags, 0, AF_ANY }, 277 { "-local", IFF_NOLOCAL, setifflags, 0, AF_ANY }, 278 { "deprecated", IFF_DEPRECATED, setifflags, 0, AF_ANY }, 279 { "-deprecated", -IFF_DEPRECATED, setifflags, 0, AF_ANY }, 280 { "preferred", IFF_PREFERRED, setifflags, 0, AF_INET6 }, 281 { "-preferred", -IFF_PREFERRED, setifflags, 0, AF_INET6 }, 282 { "debug", 0, setdebugflag, 0, AF_ANY }, 283 { "verbose", 0, setverboseflag, 0, AF_ANY }, 284 { NETMASK_CMD, NEXTARG, setifnetmask, 0, AF_INET }, 285 { "metric", NEXTARG, setifmetric, 0, AF_ANY }, 286 { "mtu", NEXTARG, setifmtu, 0, AF_ANY }, 287 { "index", NEXTARG, setifindex, 0, AF_ANY }, 288 { "broadcast", NEXTARG, setifbroadaddr, 0, AF_INET }, 289 { "auto-revarp", 0, setifrevarp, 1, AF_INET }, 290 { "plumb", 0, inetplumb, 1, AF_ANY }, 291 { "unplumb", 0, inetunplumb, 0, AF_ANY }, 292 { "subnet", NEXTARG, setifsubnet, 0, AF_ANY }, 293 { "token", NEXTARG, setiftoken, 0, AF_INET6 }, 294 { "tsrc", NEXTARG, setiftsrc, 0, AF_ANY }, 295 { "tdst", NEXTARG, setiftdst, 0, AF_ANY }, 296 { "encr_auth_algs", NEXTARG, set_tun_esp_auth_alg, 0, AF_ANY }, 297 { "encr_algs", NEXTARG, set_tun_esp_encr_alg, 0, AF_ANY }, 298 { "auth_algs", NEXTARG, set_tun_ah_alg, 0, AF_ANY }, 299 { "addif", NEXTARG, addif, 1, AF_ANY }, 300 { "removeif", NEXTARG, removeif, 1, AF_ANY }, 301 { "modlist", 0, modlist, 1, AF_ANY }, 302 { "modinsert", NEXTARG, modinsert, 1, AF_ANY }, 303 { "modremove", NEXTARG, modremove, 1, AF_ANY }, 304 { "failover", -IFF_NOFAILOVER, setifflags, 1, AF_ANY }, 305 { "-failover", IFF_NOFAILOVER, setifflags, 1, AF_ANY }, 306 { "standby", IFF_STANDBY, setifflags, 1, AF_ANY }, 307 { "-standby", -IFF_STANDBY, setifflags, 1, AF_ANY }, 308 { "failed", IFF_FAILED, setifflags, 1, AF_ANY }, 309 { "-failed", -IFF_FAILED, setifflags, 1, AF_ANY }, 310 { "group", NEXTARG, setifgroupname, 1, AF_ANY }, 311 { "configinfo", 0, configinfo, 1, AF_ANY }, 312 { "encaplimit", NEXTARG, set_tun_encap_limit, 0, 313 AF_ANY }, 314 { "-encaplimit", 0, clr_tun_encap_limit, 0, 315 AF_ANY }, 316 { "thoplimit", NEXTARG, set_tun_hop_limit, 0, 317 AF_ANY }, 318 #ifdef DEBUG 319 { "getnd", NEXTARG, getnd, 0, AF_INET6 }, 320 { "setnd", NEXTARG, setnd, 0, AF_INET6 }, 321 { "delnd", NEXTARG, delnd, 0, AF_INET6 }, 322 #endif 323 /* XXX for testing SIOCT* ioctls. Remove */ 324 { "set", NEXTARG, setifaddr, 0, AF_ANY }, 325 { "destination", NEXTARG, setifdstaddr, 0, AF_ANY }, 326 { "zone", NEXTARG, setzone, 0, AF_ANY }, 327 { "-zone", 0, setzone, 0, AF_ANY }, 328 { "ether", OPTARG, setifether, 0, AF_ANY }, 329 { "usesrc", NEXTARG, setifsrc, 0, AF_ANY }, 330 { 0, 0, setifaddr, 0, AF_ANY }, 331 { 0, 0, setifdstaddr, 0, AF_ANY }, 332 { 0, 0, 0, 0, 0 }, 333 }; 334 335 336 typedef struct if_config_cmd { 337 uint64_t iff_flag; 338 char *iff_name; 339 } if_config_cmd_t; 340 341 static if_config_cmd_t if_config_cmd_tbl[] = { 342 { IFF_UP, "up" }, 343 { IFF_NOTRAILERS, "-trailers" }, 344 { IFF_PRIVATE, "private" }, 345 { IFF_NOXMIT, "-xmit" }, 346 { IFF_ANYCAST, "anycast" }, 347 { IFF_NOLOCAL, "-local" }, 348 { IFF_DEPRECATED, "deprecated" }, 349 { IFF_NOFAILOVER, "-failover" }, 350 { IFF_STANDBY, "standby" }, 351 { IFF_FAILED, "failed" }, 352 { IFF_PREFERRED, "preferred" }, 353 { 0, 0 }, 354 }; 355 356 typedef struct ni { 357 char ni_name[LIFNAMSIZ]; 358 struct ni *ni_next; 359 } ni_t; 360 361 static ni_t *ni_list = NULL; 362 static int num_ni = 0; 363 364 /* End defines and structure definitions for ifconfig -a plumb */ 365 366 /* Known address families */ 367 struct afswtch { 368 char *af_name; 369 short af_af; 370 void (*af_status)(); 371 void (*af_getaddr)(); 372 void (*af_configinfo)(); 373 } afs[] = { 374 { "inet", AF_INET, in_status, in_getaddr, in_configinfo }, 375 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo }, 376 { 0, 0, 0, 0, 0 } 377 }; 378 379 #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af)) 380 381 struct afswtch *afp; /* the address family being set or asked about */ 382 383 int 384 main(int argc, char *argv[]) 385 { 386 /* Include IFF_NOXMIT, IFF_TEMPORARY and all zone interfaces */ 387 int64_t lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 388 char *default_ip_str; 389 390 if (argc < 2) { 391 usage(); 392 exit(1); 393 } 394 argc--, argv++; 395 if (strlen(*argv) > sizeof (name) - 1) { 396 (void) fprintf(stderr, "%s: interface name too long\n", *argv); 397 exit(1); 398 } 399 (void) strncpy(name, *argv, sizeof (name)); 400 name[sizeof (name) - 1] = '\0'; 401 (void) strncpy(origname, name, sizeof (origname)); /* For addif */ 402 euid = geteuid(); 403 default_ip_str = NULL; 404 v4compat = get_compat_flag(&default_ip_str); 405 if (v4compat == DEFAULT_PROT_BAD_VALUE) { 406 (void) fprintf(stderr, 407 "ifconfig: %s: Bad value for %s in %s\n", default_ip_str, 408 DEFAULT_IP, INET_DEFAULT_FILE); 409 free(default_ip_str); 410 exit(2); 411 } 412 free(default_ip_str); 413 argc--, argv++; 414 if (argc > 0) { 415 struct afswtch *myafp; 416 417 for (myafp = afp = afs; myafp->af_name; myafp++) { 418 if (strcmp(myafp->af_name, *argv) == 0) { 419 afp = myafp; argc--; argv++; 420 break; 421 } 422 } 423 af = lifr.lifr_addr.ss_family = afp->af_af; 424 if (af == AF_INET6) { 425 v4compat = 0; 426 } 427 } 428 429 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); 430 if (s < 0) { 431 Perror0_exit("socket"); 432 } 433 434 /* 435 * Special interface names is any combination of these flags. 436 * Note that due to the ifconfig syntax they have to be combined 437 * as a single '-' option. 438 * -a All interfaces 439 * -u "up" interfaces 440 * -d "down" interfaces 441 * -D Interfaces not controlled by DHCP 442 * -4 IPv4 interfaces 443 * -6 IPv6 interfaces 444 * -X Turn on debug (not documented) 445 * -v Turn on verbose 446 * -Z Only interfaces in caller's zone 447 */ 448 449 if (name[0] == '-') { 450 /* One or more options */ 451 int64_t onflags = 0; 452 int64_t offflags = 0; 453 int c; 454 char *av[2] = { "ifconfig", name }; 455 456 while ((c = getopt(2, av, "audDXZ46v")) != -1) { 457 switch ((char)c) { 458 case 'a': 459 all = 1; 460 break; 461 case 'u': 462 onflags |= IFF_UP; 463 break; 464 case 'd': 465 offflags |= IFF_UP; 466 break; 467 case 'D': 468 offflags |= IFF_DHCPRUNNING; 469 break; 470 case 'X': 471 debug += 3; 472 break; 473 case 'Z': 474 lifc_flags &= ~LIFC_ALLZONES; 475 break; 476 case '4': 477 /* 478 * -4 is not a compatable flag, therefore 479 * we assume they want v4compat turned off 480 */ 481 v4compat = 0; 482 onflags |= IFF_IPV4; 483 break; 484 case '6': 485 /* 486 * If they want IPv6, well then we'll assume 487 * they don't want IPv4 compat 488 */ 489 v4compat = 0; 490 onflags |= IFF_IPV6; 491 break; 492 case 'v': 493 verbose = 1; 494 break; 495 case '?': 496 usage(); 497 exit(1); 498 } 499 } 500 if (!all) { 501 (void) fprintf(stderr, 502 "ifconfig: %s: no such interface\n", 503 name); 504 exit(1); 505 } 506 foreachinterface(ifconfig, argc, argv, af, onflags, offflags, 507 lifc_flags); 508 } else { 509 ifconfig(argc, argv, af, (struct lifreq *)NULL); 510 } 511 return (0); 512 } 513 514 /* 515 * For each interface, call (*func)(argc, argv, af, lifrp). 516 * Only call function if onflags and offflags are set or clear, respectively, 517 * in the interfaces flags field. 518 */ 519 static void 520 foreachinterface(void (*func)(), int argc, char *argv[], int af, 521 int64_t onflags, int64_t offflags, int64_t lifc_flags) 522 { 523 int n; 524 char *buf; 525 struct lifnum lifn; 526 struct lifconf lifc; 527 struct lifreq *lifrp; 528 struct lifreq lifrl; /* Local lifreq struct */ 529 int numifs; 530 unsigned bufsize; 531 ni_t *nip; 532 int plumball = 0; 533 int save_af = af; 534 535 /* 536 * Special case: 537 * ifconfig -a plumb should find all network interfaces 538 * in the machine by traversing the devinfo tree. 539 * Also, there is no need to SIOCGLIF* ioctls, since 540 * those interfaces have already been plumbed 541 */ 542 if (argc > 0 && (strcmp(*argv, "plumb") == 0)) { 543 /* 544 * Look through the kernel's devinfo tree for 545 * network devices 546 */ 547 di_node_t root; 548 549 /* 550 * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR | 551 * DINFOPROP | DINFOFORCE. 552 */ 553 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 554 (void) fprintf(stderr, "ifconfig: di_init failed;" 555 " check the devinfo driver.\n"); 556 exit(1); 557 } 558 559 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL, 560 devfs_entry); 561 di_fini(root); 562 563 /* 564 * Now, translate the linked list into 565 * a struct lifreq buffer 566 */ 567 bufsize = num_ni * sizeof (struct lifreq); 568 if ((buf = malloc(bufsize)) == NULL) 569 Perror0_exit("foreachinterface: malloc failed"); 570 571 lifc.lifc_family = AF_UNSPEC; 572 lifc.lifc_flags = lifc_flags; 573 lifc.lifc_len = bufsize; 574 lifc.lifc_buf = buf; 575 576 for (n = 0, lifrp = lifc.lifc_req; n < num_ni; n++, lifrp++) { 577 nip = ni_list; 578 (void) strncpy(lifrp->lifr_name, nip->ni_name, 579 sizeof (lifr.lifr_name)); 580 ni_list = nip->ni_next; 581 free(nip); 582 } 583 584 plumball = 1; 585 } else { 586 lifn.lifn_family = AF_UNSPEC; 587 lifn.lifn_flags = lifc_flags; 588 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { 589 Perror0_exit("Could not determine number" 590 " of interfaces"); 591 } 592 numifs = lifn.lifn_count; 593 if (debug) 594 (void) printf("ifconfig: %d interfaces\n", numifs); 595 596 bufsize = numifs * sizeof (struct lifreq); 597 if ((buf = malloc(bufsize)) == NULL) { 598 Perror0("out of memory\n"); 599 (void) close(s); 600 return; 601 } 602 603 lifc.lifc_family = AF_UNSPEC; 604 lifc.lifc_flags = lifc_flags; 605 lifc.lifc_len = bufsize; 606 lifc.lifc_buf = buf; 607 608 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { 609 Perror0("SIOCGLIFCONF"); 610 (void) close(s); 611 free(buf); 612 return; 613 } 614 } 615 616 lifrp = lifc.lifc_req; 617 for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { 618 619 if (!plumball) { 620 /* 621 * We must close and recreate the socket each time 622 * since we don't know what type of socket it is now 623 * (each status function may change it). 624 */ 625 626 (void) close(s); 627 628 af = lifrp->lifr_addr.ss_family; 629 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); 630 if (s == -1) { 631 /* 632 * Perror0() assumes the name to be in the 633 * globally defined lifreq structure. 634 */ 635 (void) strncpy(lifr.lifr_name, 636 lifrp->lifr_name, sizeof (lifr.lifr_name)); 637 Perror0_exit("socket"); 638 } 639 } 640 641 /* 642 * Only service interfaces that match the on and off 643 * flags masks. 644 */ 645 if (onflags || offflags) { 646 (void) memset(&lifrl, 0, sizeof (lifrl)); 647 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, 648 sizeof (lifrl.lifr_name)); 649 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { 650 /* 651 * Perror0() assumes the name to be in the 652 * globally defined lifreq structure. 653 */ 654 (void) strncpy(lifr.lifr_name, 655 lifrp->lifr_name, sizeof (lifr.lifr_name)); 656 Perror0_exit("foreachinterface: SIOCGLIFFLAGS"); 657 } 658 if ((lifrl.lifr_flags & onflags) != onflags) 659 continue; 660 if ((~lifrl.lifr_flags & offflags) != offflags) 661 continue; 662 } 663 664 if (!plumball) { 665 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, 666 sizeof (lifrl.lifr_name)); 667 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) { 668 /* 669 * Perror0() assumes the name to be in the 670 * globally defined lifreq structure. 671 */ 672 (void) strncpy(lifr.lifr_name, 673 lifrp->lifr_name, sizeof (lifr.lifr_name)); 674 Perror0("foreachinterface: SIOCGLIFADDR"); 675 continue; 676 } 677 if (lifrl.lifr_addr.ss_family != af) { 678 /* Switch address family */ 679 af = lifrl.lifr_addr.ss_family; 680 (void) close(s); 681 682 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); 683 if (s == -1) { 684 /* 685 * Perror0() assumes the name to be in 686 * the globally defined lifreq 687 * structure. 688 */ 689 (void) strncpy(lifr.lifr_name, 690 lifrp->lifr_name, 691 sizeof (lifr.lifr_name)); 692 Perror0_exit("socket"); 693 } 694 } 695 } 696 697 /* 698 * Reset global state 699 * setaddr: Used by parser to tear apart source and dest 700 * name and origname contain the name of the 'current' 701 * interface. 702 */ 703 setaddr = 0; 704 (void) strncpy(name, lifrp->lifr_name, sizeof (name)); 705 (void) strncpy(origname, name, sizeof (origname)); 706 707 if (partial) { 708 if (debug) 709 (void) fprintf(stderr, 710 "checking partial %s against %s\n", 711 partname, name); 712 if (strncmp(name, partname, strlen(partname))) 713 continue; 714 } 715 (*func)(argc, argv, save_af, lifrp); 716 /* the func could have overwritten origname, so restore */ 717 (void) strncpy(name, origname, sizeof (name)); 718 } 719 free(buf); 720 } 721 722 static void 723 tun_reality_check(void) 724 { 725 struct iftun_req treq; 726 ipsec_req_t *ipsr; 727 728 (void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name)); 729 if (strchr(name, ':') != NULL) { 730 /* Return, we don't need to check. */ 731 return; 732 } 733 if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0 || 734 (treq.ifta_flags & IFTUN_SECURITY) == 0) { 735 /* 736 * Either not a tunnel (the SIOCGTUNPARAM fails on 737 * non-tunnels), or the security flag is not set. Either 738 * way, return. 739 */ 740 return; 741 } 742 743 ipsr = (ipsec_req_t *)&treq.ifta_secinfo; 744 745 if (ipsr->ipsr_esp_req != 0 && 746 ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE && 747 ipsr->ipsr_ah_req == 0) 748 (void) fprintf(stderr, "ifconfig: WARNING - tunnel with " 749 "only ESP and potentially no authentication.\n"); 750 } 751 752 /* 753 * for the specified interface call (*func)(argc, argv, af, lifrp). 754 */ 755 756 static void 757 ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp) 758 { 759 static boolean_t scan_netmask = _B_FALSE; 760 int ret; 761 762 if (argc == 0) { 763 status(); 764 return; 765 } 766 767 if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) { 768 if (af == AF_INET) { 769 770 /* 771 * some errors are ignored in the case where 772 * more than one interface is being operated on. 773 */ 774 ret = setifdhcp("ifconfig", name, argc, argv); 775 if (ret == DHCP_EXIT_IF_FAILURE) { 776 if (!all) 777 exit(DHCP_EXIT_FAILURE); 778 } else if (ret != DHCP_EXIT_SUCCESS) 779 exit(ret); 780 } else 781 (void) fprintf(stderr, "ifconfig: dhcp not supported " 782 "for inet6\n"); 783 return; 784 } 785 786 /* 787 * The following is a "hack" to get around the existing interface 788 * setting mechanism. Currently, each interface attribute, 789 * such as address, netmask, broadcast, ... is set separately. But 790 * sometimes two or more attributes must be set together. For 791 * example, setting an address without a netmask does not make sense. 792 * Yet they can be set separately for IPv4 address using the current 793 * ifconfig(1M) syntax. The kernel then "infers" the correct netmask 794 * using the deprecated "IP address classes." This is simply not 795 * correct. 796 * 797 * The "hack" below is to go thru the whole command list looking for 798 * the netmask command first. Then use this netmask to set the 799 * address. This does not provide an extensible way to accommodate 800 * future need for setting more than one attributes together. 801 * 802 * Note that if the "netmask" command argument is a "+", we need 803 * to save this info and do the query after we know the address to 804 * be set. The reason is that if "addif" is used, the working 805 * interface name will be changed later when the logical interface 806 * is created. In in_getmask(), if an address is not provided, 807 * it will use the working interface's address to do the query. 808 * It will be wrong now as we don't know the logical interface's name. 809 * 810 * ifconfig(1M) is too overloaded and the code is so convoluted 811 * that it is "safer" not to re-architect the code to fix the above 812 * issue, hence this "hack." We may be better off to have a new 813 * command with better syntax for configuring network interface 814 * parameters... 815 */ 816 if (!scan_netmask && afp->af_af == AF_INET) { 817 int largc; 818 char **largv; 819 820 /* Only go thru the command list once to find the netmask. */ 821 scan_netmask = _B_TRUE; 822 823 /* 824 * Currently, if multiple netmask commands are specified, the 825 * last one will be used as the final netmask. So we need 826 * to scan the whole list to preserve this behavior. 827 */ 828 for (largc = argc, largv = argv; largc > 0; largc--, largv++) { 829 if (strcmp(*largv, NETMASK_CMD) == 0) { 830 if (--largc == 0) 831 break; 832 largv++; 833 if (strcmp(*largv, "+") == 0) { 834 g_netmask_set = G_NETMASK_PENDING; 835 } else { 836 in_getaddr(*largv, (struct sockaddr *) 837 &g_netmask, NULL); 838 g_netmask_set = G_NETMASK_SET; 839 } 840 /* Continue the scan. */ 841 } 842 } 843 } 844 845 while (argc > 0) { 846 struct cmd *p; 847 boolean_t found_cmd; 848 849 if (debug) 850 (void) printf("ifconfig: argv %s\n", *argv); 851 852 found_cmd = _B_FALSE; 853 for (p = cmds; p->c_func; p++) { 854 if (p->c_name) { 855 if (strcmp(*argv, p->c_name) == 0) { 856 /* 857 * indicate that the command was 858 * found and check to see if 859 * the address family is valid 860 */ 861 found_cmd = _B_TRUE; 862 if (p->c_af == AF_ANY || 863 af == p->c_af) 864 break; 865 } 866 } else { 867 if (p->c_af == AF_ANY || 868 af == p->c_af) 869 break; 870 } 871 } 872 /* 873 * If we found the keyword, but the address family 874 * did not match spit out an error 875 */ 876 if (found_cmd && p->c_name == 0) { 877 (void) fprintf(stderr, "ifconfig: Operation %s not" 878 " supported for %s\n", *argv, afp->af_name); 879 exit(1); 880 } 881 /* 882 * else (no keyword found), we assume it's an address 883 * of some sort 884 */ 885 if (p->c_name == 0 && setaddr) 886 p++; /* got src, do dst */ 887 if (p->c_func) { 888 if (p->c_af == AF_INET6) { 889 v4compat = 0; 890 } 891 if (p->c_parameter == NEXTARG || 892 p->c_parameter == OPTARG) { 893 argc--, argv++; 894 if (argc == 0 && p->c_parameter == NEXTARG) { 895 (void) fprintf(stderr, 896 "ifconfig: no argument for %s\n", 897 p->c_name); 898 exit(1); 899 } 900 } 901 /* 902 * Call the function if: 903 * 904 * there's no address family 905 * restriction 906 * OR 907 * we don't know the address yet 908 * (because we were called from 909 * main) 910 * OR 911 * there is a restriction AND 912 * the address families match 913 */ 914 if ((p->c_af == AF_ANY) || 915 (lifrp == (struct lifreq *)NULL) || 916 (lifrp->lifr_addr.ss_family == p->c_af)) { 917 ret = (*p->c_func)(*argv, p->c_parameter); 918 /* 919 * If c_func failed and we should 920 * abort processing for this 921 * interface on failure, return 922 * now rather than going on to 923 * process other commands for 924 * the same interface. 925 */ 926 if (ret != 0 && p->c_abortonfail) 927 return; 928 } 929 } 930 argc--, argv++; 931 } 932 933 /* Check to see if there's a security hole in the tunnel setup. */ 934 tun_reality_check(); 935 } 936 937 /* ARGSUSED */ 938 static int 939 setdebugflag(char *val, int64_t arg) 940 { 941 debug++; 942 return (0); 943 } 944 945 /* ARGSUSED */ 946 static int 947 setverboseflag(char *val, int64_t arg) 948 { 949 verbose++; 950 return (0); 951 } 952 953 /* 954 * This function fills in the given lifreq's lifr_addr field based on 955 * g_netmask_set. 956 */ 957 static void 958 set_mask_lifreq(struct lifreq *lifr, struct sockaddr_storage *addr, 959 struct sockaddr_storage *mask) 960 { 961 assert(addr != NULL); 962 assert(mask != NULL); 963 964 switch (g_netmask_set) { 965 case G_NETMASK_SET: 966 lifr->lifr_addr = g_netmask; 967 break; 968 969 case G_NETMASK_PENDING: 970 /* 971 * "+" is used as the argument to "netmask" command. Query 972 * the database on the correct netmask based on the address to 973 * be set. 974 */ 975 assert(afp->af_af == AF_INET); 976 g_netmask = *addr; 977 if (!in_getmask((struct sockaddr_in *)&g_netmask, _B_TRUE)) { 978 lifr->lifr_addr = *mask; 979 g_netmask_set = G_NETMASK_NIL; 980 } else { 981 lifr->lifr_addr = g_netmask; 982 g_netmask_set = G_NETMASK_SET; 983 } 984 break; 985 986 case G_NETMASK_NIL: 987 default: 988 lifr->lifr_addr = *mask; 989 break; 990 } 991 } 992 993 /* 994 * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n> 995 * syntax for setting the address, the address plus netmask, and just 996 * the netmask respectively. 997 */ 998 /* ARGSUSED */ 999 static int 1000 setifaddr(char *addr, int64_t param) 1001 { 1002 int prefixlen = 0; 1003 struct sockaddr_storage laddr; 1004 struct sockaddr_storage netmask; 1005 struct sockaddr_in6 *sin6; 1006 struct sockaddr_in *sin; 1007 struct sockaddr_storage sav_netmask; 1008 1009 if (addr[0] == '/') 1010 return (setifprefixlen(addr, 0)); 1011 1012 (*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen); 1013 1014 (void) memset(&netmask, 0, sizeof (netmask)); 1015 netmask.ss_family = afp->af_af; 1016 switch (prefixlen) { 1017 case NO_PREFIX: 1018 /* Nothing there - ok */ 1019 break; 1020 case BAD_ADDR: 1021 (void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n", 1022 addr); 1023 exit(1); 1024 default: 1025 if (afp->af_af == AF_INET6) { 1026 sin6 = (struct sockaddr_in6 *)&netmask; 1027 if (!in_prefixlentomask(prefixlen, ADDRBITS_V6, 1028 (uchar_t *)&sin6->sin6_addr)) { 1029 (void) fprintf(stderr, "ifconfig: " 1030 "Bad prefix length: %d\n", 1031 prefixlen); 1032 exit(1); 1033 } 1034 } else { 1035 sin = (struct sockaddr_in *)&netmask; 1036 if (!in_prefixlentomask(prefixlen, ADDRBITS_V4, 1037 (uchar_t *)&sin->sin_addr)) { 1038 (void) fprintf(stderr, "ifconfig: " 1039 "Bad prefix length: %d\n", 1040 prefixlen); 1041 exit(1); 1042 } 1043 } 1044 /* 1045 * Just in case of funny setting of both prefix and netmask, 1046 * prefix should override the netmask command. 1047 */ 1048 g_netmask_set = G_NETMASK_NIL; 1049 break; 1050 } 1051 /* Tell parser that an address was set */ 1052 setaddr++; 1053 /* save copy of netmask to restore in case of error */ 1054 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1055 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) 1056 Perror0_exit("SIOCGLIFNETMASK"); 1057 sav_netmask = lifr.lifr_addr; 1058 1059 /* 1060 * Catch set of address for AF_INET6 to perform 1061 * duplicate address detection. Check that the interface is 1062 * up. 1063 */ 1064 if (afp->af_af == AF_INET6) { 1065 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 1066 Perror0_exit("ifsetaddr: SIOCGLIFFLAGS"); 1067 } 1068 if (lifr.lifr_flags & IFF_UP) { 1069 if (debug) 1070 (void) printf( 1071 "setifaddr: Calling ifdad flags %llx\n", 1072 lifr.lifr_flags); 1073 if (ifdad(name, (struct sockaddr_in6 *)&laddr) == -1) 1074 exit(3); 1075 } 1076 } 1077 1078 /* 1079 * If setting the address and not the mask, clear any existing mask 1080 * and the kernel will then assign the default (netmask has been set 1081 * to 0 in this case). If setting both (either by using a prefix or 1082 * using the netmask command), set the mask first, so the address will 1083 * be interpreted correctly. 1084 */ 1085 set_mask_lifreq(&lifr, &laddr, &netmask); 1086 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1087 Perror0_exit("SIOCSLIFNETMASK"); 1088 1089 if (debug) { 1090 char abuf[INET6_ADDRSTRLEN]; 1091 void *addr = (afp->af_af == AF_INET) ? 1092 (void *)&((struct sockaddr_in *)&laddr)->sin_addr : 1093 (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr; 1094 1095 (void) printf("Setting %s af %d addr %s\n", 1096 lifr.lifr_name, afp->af_af, 1097 inet_ntop(afp->af_af, addr, abuf, sizeof (abuf))); 1098 } 1099 lifr.lifr_addr = laddr; 1100 lifr.lifr_addr.ss_family = afp->af_af; 1101 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) { 1102 /* 1103 * Restore the netmask 1104 */ 1105 int saverr = errno; 1106 1107 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1108 lifr.lifr_addr = sav_netmask; 1109 (void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr); 1110 errno = saverr; 1111 Perror0_exit("SIOCSLIFADDR"); 1112 } 1113 1114 return (0); 1115 } 1116 1117 /* 1118 * The following functions are stolen from the ipseckey(1m) program. 1119 * Perhaps they should be somewhere common, but for now, we just maintain 1120 * two versions. We do this because of the different semantics for which 1121 * algorithms we select ("requested" for ifconfig vs. "actual" for key). 1122 */ 1123 1124 static ulong_t 1125 parsenum(char *num) 1126 { 1127 ulong_t rc; 1128 char *end = NULL; 1129 1130 errno = 0; 1131 rc = strtoul(num, &end, 0); 1132 if (errno != 0 || end == num || *end != '\0') { 1133 rc = (ulong_t)-1; 1134 } 1135 1136 return (rc); 1137 } 1138 1139 /* 1140 * Parse and reverse parse possible algorithm values, include numbers. 1141 * Mostly stolen from ipseckey.c. See the comments above parsenum() for why 1142 * this isn't common to ipseckey.c. 1143 * 1144 * NOTE: Static buffer in this function for the return value. Since ifconfig 1145 * isn't multithreaded, this isn't a huge problem. 1146 */ 1147 1148 #define NBUF_SIZE 20 /* Enough to print a large integer. */ 1149 1150 static char * 1151 rparsealg(uint8_t alg_value, int proto_num) 1152 { 1153 struct ipsecalgent *alg; 1154 static char numprint[128]; /* Enough to hold an algorithm name. */ 1155 1156 /* Special-case 0 to return "<any-none>" */ 1157 if (alg_value == 0) 1158 return ("<any-none>"); 1159 1160 alg = getipsecalgbynum(alg_value, proto_num, NULL); 1161 if (alg != NULL) { 1162 (void) strlcpy(numprint, alg->a_names[0], sizeof (numprint)); 1163 freeipsecalgent(alg); 1164 } else { 1165 (void) snprintf(numprint, sizeof (numprint), "%d", alg_value); 1166 } 1167 1168 return (numprint); 1169 } 1170 1171 static uint_t 1172 parsealg(char *algname, int proto_num) 1173 { 1174 struct ipsecalgent *alg; 1175 ulong_t invalue; 1176 1177 if (algname == NULL) { 1178 (void) fprintf(stderr, "ifconfig: Unexpected end of command " 1179 "line.\n"); 1180 exit(1); 1181 } 1182 1183 /* 1184 * Special-case "none". Use strcasecmp because its length is 1185 * bound. 1186 */ 1187 if (strcasecmp("none", algname) == 0) { 1188 return ((proto_num == IPSEC_PROTO_ESP) ? 1189 NO_ESP_EALG : NO_ESP_AALG); 1190 } 1191 1192 alg = getipsecalgbyname(algname, proto_num, NULL); 1193 if (alg != NULL) { 1194 invalue = alg->a_alg_num; 1195 freeipsecalgent(alg); 1196 return ((uint_t)invalue); 1197 } 1198 1199 /* 1200 * Since algorithms can be loaded during kernel run-time, check for 1201 * numeric algorithm values too. 1202 */ 1203 invalue = parsenum(algname); 1204 if ((invalue & (ulong_t)0xff) == invalue) 1205 return ((uint_t)invalue); 1206 1207 (void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n", 1208 (proto_num == IPSEC_PROTO_ESP) ? 1209 "Encryption" : "Authentication", algname); 1210 exit(1); 1211 /* NOTREACHED */ 1212 } 1213 1214 /* 1215 * Actual ifconfig functions to set tunnel security properties. 1216 */ 1217 1218 enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG }; 1219 1220 boolean_t first_set_tun = _B_TRUE; 1221 boolean_t encr_alg_set = _B_FALSE; 1222 1223 static int 1224 set_tun_algs(int which_alg, int alg) 1225 { 1226 struct iftun_req treq; 1227 ipsec_req_t *ipsr; 1228 1229 (void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name)); 1230 if (strchr(name, ':') != NULL) { 1231 errno = EPERM; 1232 Perror0_exit("Tunnel params on logical interfaces"); 1233 } 1234 if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0) { 1235 if (errno == EOPNOTSUPP || errno == EINVAL) 1236 Perror0_exit("Not a tunnel"); 1237 else Perror0_exit("SIOCGTUNPARAM"); 1238 } 1239 1240 ipsr = (ipsec_req_t *)&treq.ifta_secinfo; 1241 1242 if (treq.ifta_vers != IFTUN_VERSION) { 1243 (void) fprintf(stderr, 1244 "Kernel tunnel secinfo version mismatch.\n"); 1245 exit(1); 1246 } 1247 1248 /* 1249 * If I'm just starting off this ifconfig, I want a clean slate, 1250 * otherwise, I've captured the current tunnel security settings. 1251 * In the case of continuation, I merely add to the settings. 1252 */ 1253 if (first_set_tun) { 1254 first_set_tun = _B_FALSE; 1255 (void) memset(ipsr, 0, sizeof (*ipsr)); 1256 } 1257 1258 treq.ifta_flags = IFTUN_SECURITY; 1259 1260 switch (which_alg) { 1261 case ESP_ENCR_ALG: 1262 if (alg == NO_ESP_EALG) { 1263 if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE) 1264 ipsr->ipsr_esp_req = 0; 1265 ipsr->ipsr_esp_alg = SADB_EALG_NONE; 1266 } else { 1267 encr_alg_set = _B_TRUE; 1268 ipsr->ipsr_esp_req = 1269 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE; 1270 ipsr->ipsr_esp_alg = alg; 1271 } 1272 break; 1273 case ESP_AUTH_ALG: 1274 if (alg == NO_ESP_AALG) { 1275 if (ipsr->ipsr_esp_alg == SADB_EALG_NONE || 1276 ipsr->ipsr_esp_alg == SADB_EALG_NULL) 1277 ipsr->ipsr_esp_req = 0; 1278 ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE; 1279 } else { 1280 ipsr->ipsr_esp_req = 1281 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE; 1282 ipsr->ipsr_esp_auth_alg = alg; 1283 1284 /* Let the user specify NULL encryption implicitly. */ 1285 if (ipsr->ipsr_esp_alg == SADB_EALG_NONE && 1286 !encr_alg_set) 1287 ipsr->ipsr_esp_alg = SADB_EALG_NULL; 1288 } 1289 break; 1290 case AH_AUTH_ALG: 1291 if (alg == NO_AH_AALG) { 1292 ipsr->ipsr_ah_req = 0; 1293 ipsr->ipsr_auth_alg = SADB_AALG_NONE; 1294 } else { 1295 ipsr->ipsr_ah_req = 1296 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE; 1297 ipsr->ipsr_auth_alg = alg; 1298 } 1299 break; 1300 /* Will never hit DEFAULT */ 1301 } 1302 1303 if (ioctl(s, SIOCSTUNPARAM, (caddr_t)&treq) < 0) { 1304 Perror2_exit("set tunnel security properties", 1305 treq.ifta_lifr_name); 1306 } 1307 1308 return (0); 1309 } 1310 1311 /* ARGSUSED */ 1312 static int 1313 set_tun_esp_encr_alg(char *addr, int64_t param) 1314 { 1315 return (set_tun_algs(ESP_ENCR_ALG, 1316 parsealg(addr, IPSEC_PROTO_ESP))); 1317 } 1318 1319 /* ARGSUSED */ 1320 static int 1321 set_tun_esp_auth_alg(char *addr, int64_t param) 1322 { 1323 return (set_tun_algs(ESP_AUTH_ALG, 1324 parsealg(addr, IPSEC_PROTO_AH))); 1325 } 1326 1327 /* ARGSUSED */ 1328 static int 1329 set_tun_ah_alg(char *addr, int64_t param) 1330 { 1331 return (set_tun_algs(AH_AUTH_ALG, 1332 parsealg(addr, IPSEC_PROTO_AH))); 1333 } 1334 1335 /* ARGSUSED */ 1336 static int 1337 setifrevarp(char *arg, int64_t param) 1338 { 1339 struct sockaddr_in laddr; 1340 1341 if (afp->af_af == AF_INET6) { 1342 (void) fprintf(stderr, 1343 "ifconfig: revarp not possible on IPv6 interface %s\n", 1344 name); 1345 exit(1); 1346 } 1347 if (doifrevarp(name, &laddr)) { 1348 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1349 laddr.sin_family = AF_INET; 1350 (void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr)); 1351 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 1352 Perror0_exit("SIOCSLIFADDR"); 1353 } 1354 return (0); 1355 } 1356 1357 /* ARGSUSED */ 1358 static int 1359 setifsubnet(char *addr, int64_t param) 1360 { 1361 int prefixlen = 0; 1362 struct sockaddr_storage subnet; 1363 1364 (*afp->af_getaddr)(addr, &subnet, &prefixlen); 1365 1366 switch (prefixlen) { 1367 case NO_PREFIX: 1368 (void) fprintf(stderr, 1369 "ifconfig: Missing prefix length in subnet %s\n", addr); 1370 exit(1); 1371 /* NOTREACHED */ 1372 case BAD_ADDR: 1373 (void) fprintf(stderr, 1374 "ifconfig: Bad prefix length in %s\n", addr); 1375 exit(1); 1376 default: 1377 break; 1378 } 1379 1380 lifr.lifr_addr = subnet; 1381 lifr.lifr_addrlen = prefixlen; 1382 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1383 if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0) 1384 Perror0_exit("SIOCSLIFSUBNET"); 1385 1386 return (0); 1387 } 1388 1389 /* ARGSUSED */ 1390 static int 1391 setifnetmask(char *addr, int64_t param) 1392 { 1393 struct sockaddr_in netmask; 1394 1395 assert(afp->af_af != AF_INET6); 1396 1397 if (strcmp(addr, "+") == 0) { 1398 if (!in_getmask(&netmask, _B_FALSE)) 1399 return (0); 1400 (void) printf("Setting netmask of %s to %s\n", name, 1401 inet_ntoa(netmask.sin_addr)); 1402 } else { 1403 in_getaddr(addr, (struct sockaddr *)&netmask, NULL); 1404 } 1405 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1406 (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask)); 1407 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1408 Perror0_exit("SIOCSLIFNETMASK"); 1409 return (0); 1410 } 1411 1412 /* 1413 * Parse '/<n>' as a netmask. 1414 */ 1415 /* ARGSUSED */ 1416 static int 1417 setifprefixlen(char *addr, int64_t param) 1418 { 1419 int prefixlen; 1420 int af = afp->af_af; 1421 1422 prefixlen = in_getprefixlen(addr, _B_TRUE, 1423 (af == AF_INET) ? ADDRBITS_V4 : ADDRBITS_V6); 1424 if (prefixlen < 0) { 1425 (void) fprintf(stderr, 1426 "ifconfig: Bad prefix length in %s\n", addr); 1427 exit(1); 1428 } 1429 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 1430 lifr.lifr_addr.ss_family = af; 1431 if (af == AF_INET6) { 1432 struct sockaddr_in6 *sin6; 1433 1434 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1435 if (!in_prefixlentomask(prefixlen, ADDRBITS_V6, 1436 (uchar_t *)&sin6->sin6_addr)) { 1437 (void) fprintf(stderr, "ifconfig: " 1438 "Bad prefix length: %d\n", 1439 prefixlen); 1440 exit(1); 1441 } 1442 } else if (af == AF_INET) { 1443 struct sockaddr_in *sin; 1444 1445 sin = (struct sockaddr_in *)&lifr.lifr_addr; 1446 if (!in_prefixlentomask(prefixlen, ADDRBITS_V4, 1447 (uchar_t *)&sin->sin_addr)) { 1448 (void) fprintf(stderr, "ifconfig: " 1449 "Bad prefix length: %d\n", 1450 prefixlen); 1451 exit(1); 1452 } 1453 } else { 1454 (void) fprintf(stderr, "ifconfig: setting prefix only supported" 1455 " for address family inet or inet6\n"); 1456 exit(1); 1457 } 1458 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1459 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1460 Perror0_exit("SIOCSLIFNETMASK"); 1461 return (0); 1462 } 1463 1464 /* ARGSUSED */ 1465 static int 1466 setifbroadaddr(char *addr, int64_t param) 1467 { 1468 struct sockaddr_in broadaddr; 1469 1470 assert(afp->af_af != AF_INET6); 1471 1472 if (strcmp(addr, "+") == 0) { 1473 /* 1474 * This doesn't set the broadcast address at all. Rather, it 1475 * gets, then sets the interface's address, relying on the fact 1476 * that resetting the address will reset the broadcast address. 1477 */ 1478 (void) strncpy(lifr.lifr_name, name, 1479 sizeof (lifr.lifr_name)); 1480 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 1481 if (errno != EADDRNOTAVAIL) 1482 Perror0_exit("SIOCGLIFADDR"); 1483 return (0); 1484 } 1485 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 1486 Perror0_exit("SIOCGLIFADDR"); 1487 1488 return (0); 1489 } 1490 in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL); 1491 1492 (void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr)); 1493 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1494 if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0) 1495 Perror0_exit("SIOCSLIFBRDADDR"); 1496 return (0); 1497 } 1498 1499 /* 1500 * set interface destination address 1501 */ 1502 /* ARGSUSED */ 1503 static int 1504 setifdstaddr(char *addr, int64_t param) 1505 { 1506 (*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL); 1507 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1508 if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) 1509 Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR"); 1510 return (0); 1511 } 1512 1513 /* ARGSUSED */ 1514 static int 1515 setifflags(char *val, int64_t value) 1516 { 1517 int phyintlen, origphyintlen; 1518 1519 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1520 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) 1521 Perror0_exit("setifflags: SIOCGLIFFLAGS"); 1522 1523 if (value == IFF_NOFAILOVER) { 1524 /* 1525 * Fail if '-failover' is set after a prior addif created the 1526 * alias on a different interface. This can happen when the 1527 * interface is part of an IPMP group. 1528 */ 1529 phyintlen = strcspn(name, ":"); 1530 origphyintlen = strcspn(origname, ":"); 1531 if (phyintlen != origphyintlen || 1532 strncmp(name, origname, phyintlen) != 0) { 1533 (void) fprintf(stderr, "ifconfig: can't set -failover " 1534 "on failed/standby/offlined interface %s\n", 1535 origname); 1536 exit(1); 1537 } 1538 } 1539 1540 /* 1541 * Catch "up" transition for AF_INET6 to perform duplicate address 1542 * detection. ifdad checks if an address has been set. 1543 */ 1544 if (afp->af_af == AF_INET6 && !(lifr.lifr_flags & IFF_UP) && 1545 value == IFF_UP) { 1546 if (debug) 1547 (void) printf( 1548 "setifaddr:Calling ifdad flags %llx value 0x%llx\n", 1549 lifr.lifr_flags, value); 1550 if (ifdad(name, NULL) == -1) 1551 exit(1); 1552 } 1553 1554 if (value < 0) { 1555 value = -value; 1556 lifr.lifr_flags &= ~value; 1557 } else 1558 lifr.lifr_flags |= value; 1559 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1560 if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 1561 Perror0_exit("setifflags: SIOCSLIFFLAGS"); 1562 } 1563 return (0); 1564 } 1565 1566 /* ARGSUSED */ 1567 static int 1568 setifmetric(char *val, int64_t param) 1569 { 1570 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1571 lifr.lifr_metric = atoi(val); 1572 if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0) 1573 Perror0_exit("setifmetric: SIOCSLIFMETRIC"); 1574 return (0); 1575 } 1576 1577 /* ARGSUSED */ 1578 static int 1579 setifmtu(char *val, int64_t param) 1580 { 1581 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1582 lifr.lifr_mtu = atoi(val); 1583 if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0) 1584 Perror0_exit("setifmtu: SIOCSLIFMTU"); 1585 return (0); 1586 } 1587 1588 /* ARGSUSED */ 1589 static int 1590 setifindex(char *val, int64_t param) 1591 { 1592 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1593 lifr.lifr_index = atoi(val); 1594 if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0) 1595 Perror0_exit("setifindex: SIOCSLIFINDEX"); 1596 return (0); 1597 } 1598 1599 /* ARGSUSED */ 1600 static int 1601 setifether(char *addr, int64_t param) 1602 { 1603 uchar_t *ea; 1604 iface_t *current; 1605 int maclen; 1606 1607 if (addr == NULL) { 1608 ifstatus(name); 1609 print_ifether(name); 1610 return (0); 1611 } 1612 1613 phyif = NULL; 1614 logifs = NULL; 1615 1616 /* 1617 * if the IP interface in the arguments is a logical 1618 * interface, exit with an error now. 1619 */ 1620 if (strchr(name, ':') != NULL) { 1621 (void) fprintf(stderr, "ifconfig: cannot change" 1622 " ethernet address of a logical interface\n"); 1623 exit(1); 1624 } 1625 1626 ea = _link_aton(addr, &maclen); 1627 if (ea == NULL) { 1628 if (maclen == -1) 1629 (void) fprintf(stderr, 1630 "ifconfig: %s: bad address\n", addr); 1631 else 1632 (void) fprintf(stderr, "ifconfig: malloc() failed\n"); 1633 exit(1); 1634 } 1635 1636 (void) strncpy(savedname, name, sizeof (savedname)); 1637 1638 /* 1639 * Call selectifs only for the IP interfaces that are ipv4. 1640 * offflags == IFF_IPV6 because you should not change the 1641 * Ethernet address of an ipv6 interface 1642 */ 1643 foreachinterface(selectifs, 0, (char **)NULL, 0, 0, IFF_IPV6, 0); 1644 1645 /* If physical interface not found, exit now */ 1646 if (phyif == NULL) { 1647 (void) fprintf(stderr, 1648 "ifconfig: interface %s not found\n", savedname); 1649 exit(1); 1650 } 1651 1652 /* Restore */ 1653 (void) strncpy(name, savedname, sizeof (name)); 1654 (void) strncpy(origname, savedname, sizeof (origname)); 1655 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1656 1657 /* 1658 * close and reopen the socket 1659 * we don't know which type of socket we have now 1660 */ 1661 (void) close(s); 1662 s = socket(SOCKET_AF(AF_UNSPEC), SOCK_DGRAM, 0); 1663 if (s < 0) { 1664 Perror0_exit("socket"); 1665 } 1666 1667 /* 1668 * mark down the logical interfaces first, 1669 * and then the physical interface 1670 */ 1671 if (updownifs(logifs, 0) < 0 || updownifs(phyif, 0) < 0) { 1672 Perror0_exit("mark down interface failed"); 1673 } 1674 1675 /* 1676 * Change the physical address 1677 */ 1678 if (dlpi_set_address(savedname, ea, maclen) == -1) { 1679 (void) fprintf(stderr, 1680 "ifconfig: failed setting mac address on %s\n", 1681 savedname); 1682 } 1683 1684 /* 1685 * if any interfaces were marked down before changing the 1686 * ethernet address, put them up again. 1687 * First the physical interface, then the logical ones. 1688 */ 1689 if (updownifs(phyif, 1) < 0 || updownifs(logifs, 1) < 0) { 1690 Perror0_exit("mark down interface failed"); 1691 } 1692 1693 /* Free the memory allocated by selectifs */ 1694 free(phyif); 1695 for (current = logifs; current != NULL; current = logifs) { 1696 logifs = logifs->next; 1697 free(current); 1698 } 1699 1700 return (0); 1701 } 1702 1703 /* 1704 * Print an interface's Ethernet address, if it has one. 1705 */ 1706 static void 1707 print_ifether(char *ifname) 1708 { 1709 int protocol; 1710 icfg_if_t interface; 1711 icfg_handle_t handle; 1712 int fd; 1713 1714 /* 1715 * Loopback interfaces and tunnels can't have MAC addresses, 1716 * so filter them out first. 1717 */ 1718 if (strcmp(ifname, LOOPBACK_IF) == 0) 1719 return; 1720 1721 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1722 1723 fd = socket(AF_INET, SOCK_DGRAM, 0); 1724 if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1725 /* 1726 * It's possible the interface is only configured for 1727 * IPv6; check again with AF_INET6. 1728 */ 1729 (void) close(fd); 1730 fd = socket(AF_INET6, SOCK_DGRAM, 0); 1731 if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1732 (void) close(fd); 1733 return; 1734 } 1735 } 1736 (void) close(fd); 1737 1738 /* Virtual interfaces don't have MAC addresses */ 1739 if (lifr.lifr_flags & IFF_VIRTUAL) 1740 return; 1741 1742 /* 1743 * We must be careful to set if_protocol based on the current 1744 * properties of the interface. For instance, if "ip.tun0" is 1745 * configured only as an IPv6 tunnel, then if_protocol must be 1746 * set to AF_INET6 or icfg_get_tunnel_lower() will fail and 1747 * we will falsely conclude that it's not a tunnel. 1748 */ 1749 interface.if_protocol = AF_INET; 1750 if (lifr.lifr_flags & IFF_IPV6) 1751 interface.if_protocol = AF_INET6; 1752 1753 (void) strncpy(interface.if_name, ifname, sizeof (interface.if_name)); 1754 1755 if (icfg_open(&handle, &interface) == ICFG_SUCCESS) { 1756 if (icfg_get_tunnel_lower(handle, &protocol) == ICFG_SUCCESS) { 1757 /* Tunnel op succeeded -- it's a tunnel so skip */ 1758 icfg_close(handle); 1759 return; 1760 } 1761 icfg_close(handle); 1762 } 1763 1764 dlpi_print_address(ifname); 1765 } 1766 1767 /* 1768 * static void selectifs(int argc, char *argv[], int af, struct lifreq *rp) 1769 * 1770 * Called inside setifether() to create a list of interfaces to 1771 * mark down/up when changing the Ethernet address. 1772 * If the current interface is the physical interface passed 1773 * as an argument to ifconfig, update phyif. 1774 * If the current interface is a logical interface associated 1775 * to the physical interface, add it to the logifs list. 1776 */ 1777 /* ARGSUSED */ 1778 static void 1779 selectifs(int argc, char *argv[], int af, struct lifreq *rp) 1780 { 1781 char *colonp; 1782 int length; 1783 iface_t *current; 1784 1785 /* 1786 * savedname= name of the IP interface to which you want to 1787 * change ethernet address 1788 * name= name of the current IP interface 1789 */ 1790 colonp = strchr(name, ':'); 1791 if (colonp == NULL) 1792 length = max(strlen(savedname), strlen(name)); 1793 else 1794 length = max(strlen(savedname), colonp - name); 1795 if (strncmp(savedname, name, length) == 0) { 1796 (void) strcpy(lifr.lifr_name, name); 1797 if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) { 1798 Perror0("selectifs: SIOCGLIFFLAGS"); 1799 return; 1800 } 1801 1802 if ((current = malloc(sizeof (iface_t))) == NULL) { 1803 Perror0_exit("selectifs: malloc failed\n"); 1804 } 1805 1806 if (colonp == NULL) { 1807 /* this is the physical interface */ 1808 phyif = current; 1809 bcopy(&lifr, &phyif->lifr, sizeof (struct lifreq)); 1810 phyif->next = NULL; 1811 } else { 1812 /* this is a logical interface */ 1813 bcopy(&lifr, ¤t->lifr, sizeof (struct lifreq)); 1814 current->next = logifs; 1815 logifs = current; 1816 } 1817 } 1818 } 1819 1820 /* 1821 * static int updownifs(iface_t *ifs, int up) 1822 * 1823 * It takes in input a list of IP interfaces (ifs) 1824 * and a flag (up). 1825 * It marks each interface in the list down (up = 0) 1826 * or up (up > 0). This is done ONLY if the IP 1827 * interface was originally up. 1828 * 1829 * Return values: 1830 * 0 = everything OK 1831 * -1 = problem 1832 */ 1833 static int 1834 updownifs(iface_t *ifs, int up) 1835 { 1836 iface_t *current; 1837 int ret = 0; 1838 int save_errno; 1839 char savename[LIFNAMSIZ]; 1840 uint64_t orig_flags; 1841 1842 for (current = ifs; current != NULL; current = current->next) { 1843 if (current->lifr.lifr_flags & IFF_UP) { 1844 orig_flags = current->lifr.lifr_flags; 1845 if (!up) 1846 current->lifr.lifr_flags &= ~IFF_UP; 1847 if (ioctl(s, SIOCSLIFFLAGS, ¤t->lifr) < 0) { 1848 save_errno = errno; 1849 (void) strcpy(savename, 1850 current->lifr.lifr_name); 1851 ret = -1; 1852 } 1853 if (!up) /* restore the original flags */ 1854 current->lifr.lifr_flags = orig_flags; 1855 } 1856 } 1857 1858 if (ret == -1) { 1859 (void) strcpy(lifr.lifr_name, savename); 1860 errno = save_errno; 1861 } 1862 return (ret); 1863 } 1864 1865 /* 1866 * Create the next unused logical interface using the original name 1867 * and assign the address (and mask if '/<n>' is part of the address). 1868 * Use the new logical interface for subsequent subcommands by updating 1869 * the name variable. 1870 * 1871 * This allows syntax like: 1872 * ifconfig le0 addif 109.106.86.130 netmask + up \ 1873 * addif 109.106.86.131 netmask + up 1874 */ 1875 /* ARGSUSED */ 1876 static int 1877 addif(char *str, int64_t param) 1878 { 1879 int prefixlen = 0; 1880 struct sockaddr_storage laddr; 1881 struct sockaddr_storage mask; 1882 1883 (void) strncpy(name, origname, sizeof (name)); 1884 1885 if (strchr(name, ':') != NULL) { 1886 (void) fprintf(stderr, 1887 "ifconfig: addif: bad physical interface name %s\n", 1888 name); 1889 exit(1); 1890 } 1891 1892 /* 1893 * clear so parser will interpret next address as source followed 1894 * by possible dest 1895 */ 1896 setaddr = 0; 1897 (*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen); 1898 1899 switch (prefixlen) { 1900 case NO_PREFIX: 1901 /* Nothing there - ok */ 1902 break; 1903 case BAD_ADDR: 1904 (void) fprintf(stderr, 1905 "ifconfig: Bad prefix length in %s\n", str); 1906 exit(1); 1907 default: 1908 (void) memset(&mask, 0, sizeof (mask)); 1909 mask.ss_family = afp->af_af; 1910 if (afp->af_af == AF_INET6) { 1911 struct sockaddr_in6 *sin6; 1912 sin6 = (struct sockaddr_in6 *)&mask; 1913 if (!in_prefixlentomask(prefixlen, ADDRBITS_V6, 1914 (uchar_t *)&sin6->sin6_addr)) { 1915 (void) fprintf(stderr, "ifconfig: " 1916 "Bad prefix length: %d\n", 1917 prefixlen); 1918 exit(1); 1919 } 1920 } else { 1921 struct sockaddr_in *sin; 1922 1923 sin = (struct sockaddr_in *)&mask; 1924 if (!in_prefixlentomask(prefixlen, ADDRBITS_V4, 1925 (uchar_t *)&sin->sin_addr)) { 1926 (void) fprintf(stderr, "ifconfig: " 1927 "Bad prefix length: %d\n", 1928 prefixlen); 1929 exit(1); 1930 } 1931 } 1932 g_netmask_set = G_NETMASK_NIL; 1933 break; 1934 } 1935 1936 /* 1937 * This is a "hack" to get around the problem of SIOCLIFADDIF. The 1938 * problem is that this ioctl does not include the netmask when 1939 * adding a logical interface. This is the same problem described 1940 * in the ifconfig() comments. To get around this problem, we first 1941 * add the logical interface with a 0 address. After that, we set 1942 * the netmask if provided. Finally we set the interface address. 1943 */ 1944 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1945 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 1946 1947 /* Note: no need to do DAD here since the interface isn't up yet. */ 1948 1949 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 1950 Perror0_exit("addif: SIOCLIFADDIF"); 1951 1952 (void) printf("Created new logical interface %s\n", 1953 lifr.lifr_name); 1954 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 1955 1956 /* 1957 * Check and see if any "netmask" command is used and perform the 1958 * necessary operation. 1959 */ 1960 set_mask_lifreq(&lifr, &laddr, &mask); 1961 /* 1962 * Only set the netmask if "netmask" command is used or a prefix is 1963 * provided. 1964 */ 1965 if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) { 1966 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1967 Perror0_exit("addif: SIOCSLIFNETMASK"); 1968 } 1969 1970 /* Finally, we set the interface address. */ 1971 lifr.lifr_addr = laddr; 1972 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 1973 Perror0_exit("SIOCSLIFADDR"); 1974 1975 /* 1976 * let parser know we got a source. 1977 * Next address, if given, should be dest 1978 */ 1979 setaddr++; 1980 return (0); 1981 } 1982 1983 /* 1984 * Remove a logical interface based on its IP address. Unlike addif 1985 * there is no '/<n>' here. 1986 * Verifies that the interface is down before it is removed. 1987 */ 1988 /* ARGSUSED */ 1989 static int 1990 removeif(char *str, int64_t param) 1991 { 1992 struct sockaddr_storage laddr; 1993 1994 if (strchr(name, ':') != NULL) { 1995 (void) fprintf(stderr, 1996 "ifconfig: removeif: bad physical interface name %s\n", 1997 name); 1998 exit(1); 1999 } 2000 2001 (*afp->af_getaddr)(str, &laddr, NULL); 2002 lifr.lifr_addr = laddr; 2003 2004 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2005 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 2006 if (errno == EBUSY) { 2007 /* This can only happen if ipif_id = 0 */ 2008 (void) fprintf(stderr, 2009 "ifconfig: removeif: can't remove interface: %s\n", 2010 name); 2011 exit(1); 2012 } 2013 Perror0_exit("removeif: SIOCLIFREMOVEIF"); 2014 } 2015 return (0); 2016 } 2017 2018 /* 2019 * If laddr is non-NULL it is used - otherwise we use the address on 2020 * the interface. 2021 */ 2022 /* ARGSUSED */ 2023 static int 2024 ifdad(char *ifname, struct sockaddr_in6 *laddr) 2025 { 2026 struct sockaddr_in6 testaddr; 2027 struct lifreq lifr2; /* Avoid overriting lifr */ 2028 2029 if (debug) 2030 (void) printf("ifdad(%s)\n", ifname); 2031 2032 assert(afp->af_af == AF_INET6); 2033 2034 /* 2035 * Check the address assigned to the interface. 2036 * Skip the check if IFF_NOLOCAL, IFF_NONUD, IFF_ANYCAST, or 2037 * IFF_LOOPBACK. 2038 * Note that IFF_NONUD turns of both NUD and DAD. 2039 */ 2040 (void) strncpy(lifr2.lifr_name, ifname, 2041 sizeof (lifr2.lifr_name)); 2042 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr2) < 0) { 2043 Perror0_exit("ifdad: SIOCGLIFFLAGS"); 2044 } 2045 if (lifr2.lifr_flags & (IFF_NOLOCAL|IFF_LOOPBACK|IFF_NONUD|IFF_ANYCAST)) 2046 return (0); 2047 2048 if (laddr != NULL) { 2049 testaddr = *laddr; 2050 } else { 2051 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr2) < 0) { 2052 Perror0_exit("ifdad: SIOCGLIFADDR"); 2053 } 2054 testaddr = *(struct sockaddr_in6 *)&lifr2.lifr_addr; 2055 } 2056 2057 if (IN6_IS_ADDR_UNSPECIFIED(&testaddr.sin6_addr)) 2058 return (0); 2059 2060 if (do_dad(name, &testaddr) != 0) 2061 return (-1); 2062 else 2063 return (0); 2064 } 2065 2066 /* 2067 * Set the address token for IPv6. 2068 */ 2069 /* ARGSUSED */ 2070 static int 2071 setiftoken(char *addr, int64_t param) 2072 { 2073 int prefixlen = 0; 2074 struct sockaddr_in6 token; 2075 2076 in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen); 2077 switch (prefixlen) { 2078 case NO_PREFIX: 2079 (void) fprintf(stderr, 2080 "ifconfig: Missing prefix length in subnet %s\n", addr); 2081 exit(1); 2082 /* NOTREACHED */ 2083 case BAD_ADDR: 2084 (void) fprintf(stderr, 2085 "ifconfig: Bad prefix length in %s\n", addr); 2086 exit(1); 2087 default: 2088 break; 2089 } 2090 (void) memcpy(&lifr.lifr_addr, &token, sizeof (token)); 2091 lifr.lifr_addrlen = prefixlen; 2092 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2093 if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0) { 2094 Perror0_exit("setiftoken: SIOCSLIFTOKEN"); 2095 } 2096 return (0); 2097 } 2098 2099 /* 2100 * Return value: 0 on success, -1 on failure. 2101 */ 2102 static int 2103 connect_to_mpathd(int family) 2104 { 2105 int s; 2106 struct sockaddr_storage ss; 2107 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 2108 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 2109 struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 2110 int addrlen; 2111 int ret; 2112 int on; 2113 2114 s = socket(family, SOCK_STREAM, 0); 2115 if (s < 0) { 2116 Perror0_exit("connect_to_mpathd: socket"); 2117 } 2118 (void) bzero((char *)&ss, sizeof (ss)); 2119 ss.ss_family = family; 2120 /* 2121 * Need to bind to a privileged port. For non-root, this 2122 * will fail. in.mpathd verifies that only commands coming 2123 * from privileged ports succeed so that ordinary users 2124 * can't connect and start talking to in.mpathd 2125 */ 2126 on = 1; 2127 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2128 sizeof (on)) < 0) { 2129 Perror0_exit("connect_to_mpathd: setsockopt"); 2130 } 2131 switch (family) { 2132 case AF_INET: 2133 sin->sin_port = 0; 2134 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2135 addrlen = sizeof (struct sockaddr_in); 2136 break; 2137 case AF_INET6: 2138 sin6->sin6_port = 0; 2139 sin6->sin6_addr = loopback_addr; 2140 addrlen = sizeof (struct sockaddr_in6); 2141 break; 2142 } 2143 ret = bind(s, (struct sockaddr *)&ss, addrlen); 2144 if (ret != 0) { 2145 (void) close(s); 2146 return (-1); 2147 } 2148 2149 switch (family) { 2150 case AF_INET: 2151 sin->sin_port = htons(MPATHD_PORT); 2152 break; 2153 case AF_INET6: 2154 sin6->sin6_port = htons(MPATHD_PORT); 2155 break; 2156 } 2157 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2158 (void) close(s); 2159 return (ret); 2160 } 2161 2162 /* ARGSUSED */ 2163 static int 2164 setifgroupname(char *grpname, int64_t param) 2165 { 2166 if (debug) { 2167 (void) printf("Setting groupname %s on interface %s\n", 2168 grpname, name); 2169 } 2170 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2171 (void) strncpy(lifr.lifr_groupname, grpname, 2172 sizeof (lifr.lifr_groupname)); 2173 if (ioctl(s, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) { 2174 Perror0_exit("setifgroupname: SIOCSLIFGROUPNAME"); 2175 } 2176 2177 /* 2178 * If the SUNW_NO_MPATHD environment variable is set then don't 2179 * bother starting up in.mpathd. See PSARC/2002/249 for the 2180 * depressing details on this bit of stupidity. 2181 */ 2182 if (getenv("SUNW_NO_MPATHD") != NULL) { 2183 return (0); 2184 } 2185 2186 /* 2187 * Try to connect to in.mpathd using IPv4. If we succeed, 2188 * we conclude that in.mpathd is running, and quit. 2189 */ 2190 if (connect_to_mpathd(AF_INET) == 0) { 2191 /* connect succeeded, mpathd is already running */ 2192 return (0); 2193 } 2194 /* 2195 * Try to connect to in.mpathd using IPv6. If we succeed, 2196 * we conclude that in.mpathd is running, and quit. 2197 */ 2198 if (connect_to_mpathd(AF_INET6) == 0) { 2199 /* connect succeeded, mpathd is already running */ 2200 return (0); 2201 } 2202 2203 /* 2204 * in.mpathd may not be running. Start it now. If it is already 2205 * running, in.mpathd will take care of handling multiple incarnations 2206 * of itself. ifconfig only tries to optimize performance by not 2207 * starting another incarnation of in.mpathd. 2208 */ 2209 switch (fork()) { 2210 2211 case -1: 2212 Perror0_exit("setifgroupname: fork"); 2213 /* NOTREACHED */ 2214 case 0: 2215 (void) execl(MPATHD_PATH, MPATHD_PATH, NULL); 2216 _exit(1); 2217 /* NOTREACHED */ 2218 default: 2219 return (0); 2220 } 2221 } 2222 2223 2224 /* 2225 * To list all the modules above a given network interface. 2226 */ 2227 /* ARGSUSED */ 2228 static int 2229 modlist(char *null, int64_t param) 2230 { 2231 int muxfd; 2232 int ipfd_lowstr; 2233 int arpfd_lowstr; 2234 int num_mods; 2235 int i; 2236 struct str_list strlist; 2237 int orig_arpid; 2238 2239 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2240 if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr, 2241 &orig_arpid) < 0) { 2242 return (-1); 2243 } 2244 if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) { 2245 Perror0("cannot I_LIST to get the number of modules"); 2246 } else { 2247 if (debug > 0) { 2248 (void) printf("Listing (%d) modules above %s\n", 2249 num_mods, name); 2250 } 2251 2252 strlist.sl_nmods = num_mods; 2253 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * 2254 num_mods); 2255 if (strlist.sl_modlist == NULL) { 2256 Perror0("cannot malloc"); 2257 } else { 2258 if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) { 2259 Perror0("cannot I_LIST for module names"); 2260 } else { 2261 for (i = 0; i < strlist.sl_nmods; i++) { 2262 (void) printf("%d %s\n", i, 2263 strlist.sl_modlist[i].l_name); 2264 } 2265 } 2266 free(strlist.sl_modlist); 2267 } 2268 } 2269 return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid)); 2270 } 2271 2272 #define MODINSERT_OP 'i' 2273 #define MODREMOVE_OP 'r' 2274 2275 /* 2276 * To insert a module to the stream of the interface. It is just a 2277 * wrapper. The real function is modop(). 2278 */ 2279 /* ARGSUSED */ 2280 static int 2281 modinsert(char *arg, int64_t param) 2282 { 2283 return (modop(arg, MODINSERT_OP)); 2284 } 2285 2286 /* 2287 * To remove a module from the stream of the interface. It is just a 2288 * wrapper. The real function is modop(). 2289 */ 2290 /* ARGSUSED */ 2291 static int 2292 modremove(char *arg, int64_t param) 2293 { 2294 return (modop(arg, MODREMOVE_OP)); 2295 } 2296 2297 /* 2298 * Open a stream on /dev/udp, pop off all undesired modules (note that 2299 * the user may have configured autopush to add modules above or below 2300 * udp), and push the arp module onto raw IP. 2301 */ 2302 static int 2303 open_arp_on_udp(char *udp_dev_name) 2304 { 2305 int fd; 2306 boolean_t popped; 2307 2308 if ((fd = open(udp_dev_name, O_RDWR)) == -1) { 2309 Perror2("open", udp_dev_name); 2310 return (-1); 2311 } 2312 errno = 0; 2313 popped = _B_FALSE; 2314 while (ioctl(fd, I_POP, 0) != -1) 2315 popped = _B_TRUE; 2316 if (!popped) { 2317 Perror2("cannot pop", udp_dev_name); 2318 } else if (errno != EINVAL) { 2319 Perror2("pop", udp_dev_name); 2320 } else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) { 2321 Perror2("arp PUSH", udp_dev_name); 2322 } else { 2323 return (fd); 2324 } 2325 (void) close(fd); 2326 return (-1); 2327 } 2328 2329 /* 2330 * Helper function for mod*() functions. It gets a fd to the lower IP 2331 * stream and I_PUNLINK's the lower stream. It also initializes the 2332 * global variable lifr. 2333 * 2334 * Param: 2335 * int *udp_fd: (referenced) fd to /dev/udp (upper IP stream). 2336 * int *fd: (referenced) fd to the lower IP stream. 2337 * 2338 * Return: 2339 * -1 if operation fails, 0 otherwise. 2340 * 2341 * Please see the big block comment above plumb_one_device() 2342 * for the logic of the PLINK/PUNLINK 2343 */ 2344 static int 2345 ip_domux2fd(int *muxfd, int *ipfd_lowstr, int *arpfd_lowstr, int *orig_arpid) 2346 { 2347 int ip_fd; 2348 uint64_t flags; 2349 char *udp_dev_name; 2350 char *ip_dev_name; 2351 2352 *orig_arpid = 0; 2353 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2354 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2355 Perror0_exit("status: SIOCGLIFFLAGS"); 2356 } 2357 flags = lifr.lifr_flags; 2358 if (flags & IFF_IPV4) { 2359 udp_dev_name = UDP_DEV_NAME; 2360 ip_dev_name = IP_DEV_NAME; 2361 } else if (flags & IFF_IPV6) { 2362 udp_dev_name = UDP6_DEV_NAME; 2363 ip_dev_name = IP6_DEV_NAME; 2364 } else { 2365 return (-1); 2366 } 2367 2368 if ((ip_fd = open(ip_dev_name, O_RDWR)) < 0) { 2369 Perror2("open", ip_dev_name); 2370 return (-1); 2371 } 2372 if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 2373 Perror2("SIOCGLIFMUXID", ip_dev_name); 2374 return (-1); 2375 } 2376 if (debug > 0) { 2377 (void) printf("ARP_muxid %d IP_muxid %d\n", 2378 lifr.lifr_arp_muxid, lifr.lifr_ip_muxid); 2379 } 2380 2381 if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1) 2382 return (-1); 2383 2384 if (lifr.lifr_arp_muxid != 0) { 2385 if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2386 lifr.lifr_arp_muxid)) < 0) { 2387 if ((errno == EINVAL) && 2388 (flags & (IFF_NOARP | IFF_IPV6))) { 2389 /* 2390 * Some plumbing utilities set the muxid to 2391 * -1 or some invalid value to signify that 2392 * there is no arp stream. Set the muxid to 0 2393 * before trying to unplumb the IP stream. 2394 * IP does not allow the IP stream to be 2395 * unplumbed if it sees a non-null arp muxid, 2396 * for consistency of IP-ARP streams. 2397 */ 2398 *orig_arpid = lifr.lifr_arp_muxid; 2399 lifr.lifr_arp_muxid = 0; 2400 (void) ioctl(*muxfd, SIOCSLIFMUXID, 2401 (caddr_t)&lifr); 2402 *arpfd_lowstr = -1; 2403 } else { 2404 Perror0("_I_MUXID2FD"); 2405 return (-1); 2406 } 2407 } else if (ioctl(*muxfd, I_PUNLINK, 2408 lifr.lifr_arp_muxid) < 0) { 2409 Perror2("I_PUNLINK", udp_dev_name); 2410 return (-1); 2411 } 2412 } else { 2413 *arpfd_lowstr = -1; 2414 } 2415 2416 if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2417 lifr.lifr_ip_muxid)) < 0) { 2418 Perror0("_I_MUXID2FD"); 2419 /* Undo any changes we made */ 2420 if (*orig_arpid != 0) { 2421 lifr.lifr_arp_muxid = *orig_arpid; 2422 (void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr); 2423 } 2424 return (-1); 2425 } 2426 if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) { 2427 Perror2("I_PUNLINK", udp_dev_name); 2428 /* Undo any changes we made */ 2429 if (*orig_arpid != 0) { 2430 lifr.lifr_arp_muxid = *orig_arpid; 2431 (void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr); 2432 } 2433 return (-1); 2434 } 2435 return (0); 2436 } 2437 2438 /* 2439 * Helper function for mod*() functions. It I_PLINK's back the upper and 2440 * lower IP streams. Note that this function must be called after 2441 * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized 2442 * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink() 2443 * must be called in pairs. 2444 * 2445 * Param: 2446 * int udp_fd: fd to /dev/udp (upper IP stream). 2447 * int fd: fd to the lower IP stream. 2448 * 2449 * Return: 2450 * -1 if operation fails, 0 otherwise. 2451 * 2452 * Please see the big block comment above plumb_one_device() 2453 * for the logic of the PLINK/PUNLINK 2454 */ 2455 static int 2456 ip_plink(int muxfd, int ipfd_lowstr, int arpfd_lowstr, int orig_arpid) 2457 { 2458 int ip_muxid; 2459 2460 ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr); 2461 if (ip_muxid < 0) { 2462 Perror2("I_PLINK", UDP_DEV_NAME); 2463 return (-1); 2464 } 2465 2466 /* 2467 * If there is an arp stream, plink it. If there is no 2468 * arp stream, then it is possible that the plumbing 2469 * utility could have stored any value in the arp_muxid. 2470 * If so, restore it from orig_arpid. 2471 */ 2472 if (arpfd_lowstr != -1) { 2473 if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) { 2474 Perror2("I_PLINK", UDP_DEV_NAME); 2475 return (-1); 2476 } 2477 } else if (orig_arpid != 0) { 2478 /* Undo the changes we did in ip_domux2fd */ 2479 lifr.lifr_arp_muxid = orig_arpid; 2480 lifr.lifr_ip_muxid = ip_muxid; 2481 (void) ioctl(muxfd, SIOCSLIFMUXID, (caddr_t)&lifr); 2482 } 2483 2484 return (0); 2485 } 2486 2487 2488 /* 2489 * The names of other core TCP/IP stack modules which cannot be removed. 2490 */ 2491 #ifndef TUN_NAME 2492 #define TUN_NAME "tun" 2493 #endif 2494 2495 #ifndef ATUN_NAME 2496 #define ATUN_NAME "atun" 2497 #endif 2498 2499 #ifndef TUN6TO4_NAME 2500 #define TUN6TO4_NAME "6to4tun" 2501 #endif 2502 2503 /* 2504 * The real function to perform module insertion/removal. 2505 * 2506 * Param: 2507 * char *arg: the argument string module_name@position 2508 * char op: operation, either MODINSERT_OP or MODREMOVE_OP. 2509 * 2510 * Return: 2511 * Before doing ip_domux2fd(), this function calls exit(1) in case of 2512 * error. After ip_domux2fd() is done, it returns -1 for error, 0 2513 * otherwise. 2514 */ 2515 static int 2516 modop(char *arg, char op) 2517 { 2518 char *pos_p; 2519 int muxfd; 2520 int ipfd_lowstr; /* IP stream (lower stream of mux) to be plinked */ 2521 int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */ 2522 struct strmodconf mod; 2523 char *at_char = "@"; 2524 char *arg_str; 2525 int orig_arpid; 2526 2527 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2528 2529 /* Need to save the original string for -a option. */ 2530 if ((arg_str = malloc(strlen(arg) + 1)) == NULL) { 2531 Perror0("cannot malloc"); 2532 return (-1); 2533 } 2534 (void) strcpy(arg_str, arg); 2535 2536 if (*arg_str == *at_char) { 2537 (void) fprintf(stderr, 2538 "ifconfig: must supply a module name\n"); 2539 exit(1); 2540 } 2541 mod.mod_name = strtok(arg_str, at_char); 2542 if (strlen(mod.mod_name) > FMNAMESZ) { 2543 (void) fprintf(stderr, "ifconfig: module name too long: %s\n", 2544 mod.mod_name); 2545 exit(1); 2546 } 2547 2548 /* 2549 * Need to make sure that the core TCP/IP stack modules are not 2550 * removed. Otherwise, "bad" things can happen. If a module 2551 * is removed and inserted back, it loses its old state. But 2552 * the modules above it still have the old state. E.g. IP assumes 2553 * fast data path while tunnel after re-inserted assumes that it can 2554 * receive M_DATA only in fast data path for which it does not have 2555 * any state. This is a general caveat of _I_REMOVE/_I_INSERT. 2556 */ 2557 if (op == MODREMOVE_OP && 2558 (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 || 2559 strcmp(mod.mod_name, IP_MOD_NAME) == 0 || 2560 strcmp(mod.mod_name, TUN_NAME) == 0 || 2561 strcmp(mod.mod_name, ATUN_NAME) == 0 || 2562 strcmp(mod.mod_name, TUN6TO4_NAME) == 0)) { 2563 (void) fprintf(stderr, "ifconfig: cannot remove %s\n", 2564 mod.mod_name); 2565 exit(1); 2566 } 2567 2568 if ((pos_p = strtok(NULL, at_char)) == NULL) { 2569 (void) fprintf(stderr, "ifconfig: must supply a position\n"); 2570 exit(1); 2571 } 2572 mod.pos = atoi(pos_p); 2573 2574 if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr, 2575 &orig_arpid) < 0) { 2576 free(arg_str); 2577 return (-1); 2578 } 2579 switch (op) { 2580 case MODINSERT_OP: 2581 if (debug > 0) { 2582 (void) printf("Inserting module %s at %d\n", 2583 mod.mod_name, mod.pos); 2584 } 2585 if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) { 2586 Perror2("fail to insert module", mod.mod_name); 2587 } 2588 break; 2589 case MODREMOVE_OP: 2590 if (debug > 0) { 2591 (void) printf("Removing module %s at %d\n", 2592 mod.mod_name, mod.pos); 2593 } 2594 if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) { 2595 Perror2("fail to remove module", mod.mod_name); 2596 } 2597 break; 2598 default: 2599 /* Should never get to here. */ 2600 (void) fprintf(stderr, "Unknown operation\n"); 2601 break; 2602 } 2603 free(arg_str); 2604 return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid)); 2605 } 2606 2607 #ifdef DEBUG 2608 2609 /* ARGSUSED */ 2610 static int 2611 getnd(char *addr, int64_t param) 2612 { 2613 struct sockaddr_in6 v6addr; 2614 char *str = NULL; 2615 2616 in6_getaddr(addr, &v6addr, NULL); 2617 (void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr)); 2618 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2619 if (ioctl(s, SIOCLIFGETND, (caddr_t)&lifr) < 0) { 2620 Perror0_exit("SIOCLIFGETND"); 2621 } 2622 str = _link_ntoa((const unsigned char *)lifr.lifr_nd.lnr_hdw_addr, 2623 str, lifr.lifr_nd.lnr_hdw_len, IFT_OTHER); 2624 if (str != NULL) { 2625 (void) printf("address %s", str); 2626 free(str); 2627 } 2628 (void) printf(" state %d/%d/%d flags %x\n", 2629 lifr.lifr_nd.lnr_state_create, 2630 lifr.lifr_nd.lnr_state_same_lla, 2631 lifr.lifr_nd.lnr_state_diff_lla, 2632 lifr.lifr_nd.lnr_flags); 2633 return (0); 2634 } 2635 2636 /* ARGSUSED */ 2637 static int 2638 delnd(char *addr, int64_t param) 2639 { 2640 struct sockaddr_in6 v6addr; 2641 2642 in6_getaddr(addr, &v6addr, NULL); 2643 (void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr)); 2644 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2645 2646 lifr.lifr_nd.lnr_state_create = ND_UNCHANGED; 2647 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 2648 lifr.lifr_nd.lnr_state_diff_lla = ND_UNCHANGED; 2649 lifr.lifr_nd.lnr_flags = 0; 2650 if (ioctl(s, SIOCLIFDELND, (caddr_t)&lifr) < 0) { 2651 Perror0_exit("SIOCLIFDELND"); 2652 } 2653 return (0); 2654 } 2655 2656 /* ARGSUSED */ 2657 static int 2658 setnd(char *addr, int64_t param) 2659 { 2660 struct sockaddr_in6 v6addr; 2661 2662 /* 2663 * XXX parse phyaddr? Need syntax to fit in one argv. 2664 * XXX <proto addr>/<phyaddr> ?? 2665 */ 2666 in6_getaddr(addr, &v6addr, NULL); 2667 (void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr)); 2668 (void) memset(lifr.lifr_nd.lnr_hdw_addr, 0x55, 2669 sizeof (lifr.lifr_nd.lnr_hdw_addr)); 2670 lifr.lifr_nd.lnr_hdw_len = 6; 2671 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2672 2673 lifr.lifr_nd.lnr_state_create = ND_STALE; 2674 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 2675 lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 2676 lifr.lifr_nd.lnr_flags = 0; 2677 2678 if (ioctl(s, SIOCLIFSETND, (caddr_t)&lifr) < 0) { 2679 Perror0_exit("SIOCLIFSETND"); 2680 } 2681 return (0); 2682 } 2683 #endif /* DEBUG */ 2684 2685 /* 2686 * Set tunnel source address 2687 */ 2688 /* ARGSUSED */ 2689 static int 2690 setiftsrc(char *addr, int64_t param) 2691 { 2692 return (settaddr(addr, icfg_set_tunnel_src)); 2693 } 2694 2695 /* 2696 * Set tunnel destination address 2697 */ 2698 /* ARGSUSED */ 2699 static int 2700 setiftdst(char *addr, int64_t param) 2701 { 2702 return (settaddr(addr, icfg_set_tunnel_dest)); 2703 } 2704 2705 /* 2706 * sets tunnels src|dst address. settaddr() expects the following: 2707 * addr: Points to a printable string containing the address to be 2708 * set, e.g. 129.153.128.110. 2709 * fn: Pointer to a libinetcfg routine that will do the actual work. 2710 * The only valid functions are icfg_set_tunnel_src and 2711 * icfg_set_tunnel_dest. 2712 */ 2713 static int 2714 settaddr(char *addr, 2715 int (*fn)(icfg_handle_t, const struct sockaddr *, socklen_t)) 2716 { 2717 icfg_handle_t handle; 2718 icfg_if_t interface; 2719 struct sockaddr_storage laddr; 2720 int lower; 2721 int rc; 2722 2723 if (strchr(name, ':') != NULL) { 2724 errno = EPERM; 2725 Perror0_exit("Tunnel params on logical interfaces"); 2726 } 2727 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2728 interface.if_protocol = SOCKET_AF(af); 2729 2730 /* Open interface. */ 2731 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 2732 Perror0_exit((char *)icfg_errmsg(rc)); 2733 2734 rc = icfg_get_tunnel_lower(handle, &lower); 2735 if (rc != ICFG_SUCCESS) 2736 Perror0_exit((char *)icfg_errmsg(rc)); 2737 2738 if (lower == AF_INET) { 2739 in_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2740 } else { 2741 in6_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2742 } 2743 2744 /* Call fn to do the real work, and close the interface. */ 2745 rc = (*fn)(handle, (struct sockaddr *)&laddr, 2746 sizeof (struct sockaddr_storage)); 2747 icfg_close(handle); 2748 2749 if (rc != ICFG_SUCCESS) 2750 Perror0_exit((char *)icfg_errmsg(rc)); 2751 2752 return (0); 2753 } 2754 2755 /* Set tunnel encapsulation limit. */ 2756 /* ARGSUSED */ 2757 static int 2758 set_tun_encap_limit(char *arg, int64_t param) 2759 { 2760 short limit; 2761 icfg_if_t interface; 2762 icfg_handle_t handle; 2763 int rc; 2764 2765 if (strchr(name, ':') != NULL) { 2766 errno = EPERM; 2767 Perror0_exit("Tunnel params on logical interfaces"); 2768 } 2769 2770 if ((sscanf(arg, "%hd", &limit) != 1) || (limit < 0) || 2771 (limit > 255)) { 2772 errno = EINVAL; 2773 Perror0_exit("Invalid encapsulation limit"); 2774 } 2775 2776 /* Open interface for configuration. */ 2777 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2778 interface.if_protocol = SOCKET_AF(af); 2779 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2780 Perror0_exit("couldn't open interface"); 2781 2782 rc = icfg_set_tunnel_encaplimit(handle, (int)limit); 2783 icfg_close(handle); 2784 2785 if (rc != ICFG_SUCCESS) 2786 Perror0_exit("Could not configure tunnel encapsulation limit"); 2787 2788 return (0); 2789 } 2790 2791 /* Disable encapsulation limit. */ 2792 /* ARGSUSED */ 2793 static int 2794 clr_tun_encap_limit(char *arg, int64_t param) 2795 { 2796 icfg_if_t interface; 2797 icfg_handle_t handle; 2798 int rc; 2799 2800 if (strchr(name, ':') != NULL) { 2801 errno = EPERM; 2802 Perror0_exit("Tunnel params on logical interfaces"); 2803 } 2804 2805 /* Open interface for configuration. */ 2806 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2807 interface.if_protocol = SOCKET_AF(af); 2808 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2809 Perror0_exit("couldn't open interface"); 2810 2811 rc = icfg_set_tunnel_encaplimit(handle, -1); 2812 icfg_close(handle); 2813 2814 if (rc != ICFG_SUCCESS) 2815 Perror0_exit((char *)icfg_errmsg(rc)); 2816 2817 return (0); 2818 } 2819 2820 /* Set tunnel hop limit. */ 2821 /* ARGSUSED */ 2822 static int 2823 set_tun_hop_limit(char *arg, int64_t param) 2824 { 2825 unsigned short limit; 2826 icfg_if_t interface; 2827 icfg_handle_t handle; 2828 int rc; 2829 2830 if (strchr(name, ':') != NULL) { 2831 errno = EPERM; 2832 Perror0_exit("Tunnel params on logical interfaces"); 2833 } 2834 2835 /* 2836 * Check limit here since it's really only an 8-bit unsigned quantity. 2837 */ 2838 if ((sscanf(arg, "%hu", &limit) != 1) || (limit > 255)) { 2839 errno = EINVAL; 2840 Perror0_exit("Invalid hop limit"); 2841 } 2842 2843 /* Open interface for configuration. */ 2844 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2845 interface.if_protocol = SOCKET_AF(af); 2846 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2847 Perror0_exit("couldn't open interface"); 2848 2849 rc = icfg_set_tunnel_hoplimit(handle, (uint8_t)limit); 2850 icfg_close(handle); 2851 2852 if (rc != ICFG_SUCCESS) 2853 Perror0_exit("Could not configure tunnel hop limit"); 2854 2855 return (0); 2856 } 2857 2858 /* Set zone ID */ 2859 static int 2860 setzone(char *arg, int64_t param) 2861 { 2862 zoneid_t zoneid = GLOBAL_ZONEID; 2863 2864 if (param == NEXTARG) { 2865 /* zone must be active */ 2866 if ((zoneid = getzoneidbyname(arg)) == -1) { 2867 (void) fprintf(stderr, 2868 "ifconfig: unknown zone '%s'\n", arg); 2869 exit(1); 2870 } 2871 } 2872 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2873 lifr.lifr_zoneid = zoneid; 2874 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1) 2875 Perror0_exit("SIOCSLIFZONE"); 2876 return (0); 2877 } 2878 2879 /* Set source address to use */ 2880 /* ARGSUSED */ 2881 static int 2882 setifsrc(char *arg, int64_t param) 2883 { 2884 uint_t ifindex = 0; 2885 int rval; 2886 2887 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2888 2889 /* 2890 * Argument can be either an interface name or "none". The latter means 2891 * that any previous selection is cleared. 2892 */ 2893 2894 rval = strcmp(arg, name); 2895 if (rval == 0) { 2896 (void) fprintf(stderr, 2897 "ifconfig: Cannot specify same interface for usesrc" 2898 " group\n"); 2899 exit(1); 2900 } 2901 2902 rval = strcmp(arg, NONE_STR); 2903 if (rval != 0) { 2904 if ((ifindex = if_nametoindex(arg)) == 0) { 2905 (void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ); 2906 Perror0_exit("Could not get interface index"); 2907 } 2908 lifr.lifr_index = ifindex; 2909 } else { 2910 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0) 2911 Perror0_exit("Not a valid usesrc consumer"); 2912 lifr.lifr_index = 0; 2913 } 2914 2915 if (debug) 2916 (void) printf("setifsrc: lifr_name %s, lifr_index %d\n", 2917 lifr.lifr_name, lifr.lifr_index); 2918 2919 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) { 2920 if (rval == 0) 2921 Perror0_exit("Cannot reset usesrc group"); 2922 else 2923 Perror0_exit("Could not set source interface"); 2924 } 2925 2926 return (0); 2927 } 2928 2929 /* 2930 * Print the interface status line associated with `ifname' 2931 */ 2932 static void 2933 ifstatus(const char *ifname) 2934 { 2935 uint64_t flags; 2936 char if_usesrc_name[LIFNAMSIZ]; 2937 char *newbuf; 2938 int n, numifs, rval = 0; 2939 struct lifreq *lifrp; 2940 struct lifsrcof lifs; 2941 2942 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2943 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2944 Perror0_exit("status: SIOCGLIFFLAGS"); 2945 } 2946 flags = lifr.lifr_flags; 2947 2948 /* 2949 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or 2950 * interfaces with IFF_IPV6 set. 2951 */ 2952 if (v4compat) { 2953 flags &= ~IFF_IPV4; 2954 if (flags & IFF_IPV6) 2955 return; 2956 } 2957 2958 (void) printf("%s: ", ifname); 2959 print_flags(flags); 2960 2961 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2962 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 2963 Perror0_exit("status: SIOCGLIFMETRIC"); 2964 } else { 2965 if (lifr.lifr_metric) 2966 (void) printf(" metric %d", lifr.lifr_metric); 2967 } 2968 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 2969 (void) printf(" mtu %d", lifr.lifr_metric); 2970 2971 /* don't print index or zone when in compatibility mode */ 2972 if (!v4compat) { 2973 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 2974 (void) printf(" index %d", lifr.lifr_index); 2975 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 && 2976 lifr.lifr_zoneid != getzoneid()) { 2977 char zone_name[ZONENAME_MAX]; 2978 2979 if (getzonenamebyid(lifr.lifr_zoneid, zone_name, 2980 sizeof (zone_name)) < 0) { 2981 (void) printf("\n\tzone %d", lifr.lifr_zoneid); 2982 } else { 2983 (void) printf("\n\tzone %s", zone_name); 2984 } 2985 } 2986 } 2987 2988 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) { 2989 lifs.lifs_ifindex = lifr.lifr_index; 2990 2991 /* 2992 * Find the number of interfaces that use this interfaces' 2993 * address as a source address 2994 */ 2995 lifs.lifs_buf = NULL; 2996 lifs.lifs_maxlen = 0; 2997 for (;;) { 2998 /* The first pass will give the bufsize we need */ 2999 rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs); 3000 if (rval < 0) { 3001 if (lifs.lifs_buf != NULL) { 3002 free(lifs.lifs_buf); 3003 lifs.lifs_buf = NULL; 3004 } 3005 lifs.lifs_len = 0; 3006 break; 3007 } 3008 if (lifs.lifs_len <= lifs.lifs_maxlen) 3009 break; 3010 /* Use kernel's size + a small margin to avoid loops */ 3011 lifs.lifs_maxlen = lifs.lifs_len + 3012 5 * sizeof (struct lifreq); 3013 /* For the first pass, realloc acts like malloc */ 3014 newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen); 3015 if (newbuf == NULL) { 3016 if (lifs.lifs_buf != NULL) { 3017 free(lifs.lifs_buf); 3018 lifs.lifs_buf = NULL; 3019 } 3020 lifs.lifs_len = 0; 3021 break; 3022 } 3023 lifs.lifs_buf = newbuf; 3024 } 3025 3026 3027 numifs = lifs.lifs_len / sizeof (struct lifreq); 3028 if (numifs > 0) { 3029 lifrp = lifs.lifs_req; 3030 (void) printf("\n\tsrcof"); 3031 for (n = numifs; n > 0; n--, lifrp++) { 3032 (void) printf(" %s", lifrp->lifr_name); 3033 } 3034 } 3035 3036 if (lifs.lifs_buf != NULL) 3037 free(lifs.lifs_buf); 3038 } 3039 3040 /* Find the interface whose source address this interface uses */ 3041 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 3042 if (lifr.lifr_index != 0) { 3043 if (if_indextoname(lifr.lifr_index, 3044 if_usesrc_name) == NULL) { 3045 (void) printf("\n\tusesrc ifIndex %d", 3046 lifr.lifr_index); 3047 } else { 3048 (void) printf("\n\tusesrc %s", if_usesrc_name); 3049 } 3050 } 3051 } 3052 3053 (void) putchar('\n'); 3054 } 3055 3056 3057 /* 3058 * Print the status of the interface. If an address family was 3059 * specified, show it and it only; otherwise, show them all. 3060 */ 3061 static void 3062 status(void) 3063 { 3064 struct afswtch *p = afp; 3065 uint64_t flags; 3066 3067 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3068 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3069 Perror0_exit("status: SIOCGLIFFLAGS"); 3070 } 3071 3072 flags = lifr.lifr_flags; 3073 3074 /* 3075 * Only print the interface status if the address family matches 3076 * the interface family flag. 3077 */ 3078 if (p != NULL) { 3079 if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) || 3080 ((p->af_af == AF_INET) && (flags & IFF_IPV6))) 3081 return; 3082 } 3083 3084 /* 3085 * In V4 compatibility mode, don't print IFF_IPV6 interfaces. 3086 */ 3087 if (v4compat && (flags & IFF_IPV6)) 3088 return; 3089 3090 ifstatus(name); 3091 3092 if (p != NULL) { 3093 (*p->af_status)(1, flags); 3094 } else { 3095 for (p = afs; p->af_name; p++) { 3096 (void) close(s); 3097 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3098 /* set global af for use in p->af_status */ 3099 af = p->af_af; 3100 if (s == -1) { 3101 Perror0_exit("socket"); 3102 } 3103 (*p->af_status)(0, flags); 3104 } 3105 3106 /* 3107 * Historically, 'ether' has been an address family, 3108 * so print it here. 3109 */ 3110 print_ifether(name); 3111 } 3112 } 3113 3114 /* 3115 * Print the status of the interface in a format that can be used to 3116 * reconfigure the interface later. Code stolen from status() above. 3117 */ 3118 /* ARGSUSED */ 3119 static int 3120 configinfo(char *null, int64_t param) 3121 { 3122 struct afswtch *p = afp; 3123 uint64_t flags; 3124 char phydevname[LIFNAMSIZ]; 3125 char if_usesrc_name[LIFNAMSIZ]; 3126 char *cp; 3127 3128 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3129 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3130 Perror0_exit("status: SIOCGLIFFLAGS"); 3131 } 3132 flags = lifr.lifr_flags; 3133 3134 if (debug) { 3135 (void) printf("configinfo: name %s flags 0x%llx af_af %d\n", 3136 name, flags, p != NULL ? p->af_af : -1); 3137 } 3138 3139 /* remove LIF component */ 3140 (void) strncpy(phydevname, name, sizeof (phydevname)); 3141 cp = strchr(phydevname, ':'); 3142 if (cp) { 3143 *cp = 0; 3144 } 3145 phydevname[sizeof (phydevname) - 1] = '\0'; 3146 3147 /* 3148 * if the interface is IPv4 3149 * if we have a IPv6 address family restriction return 3150 * so it won't print 3151 * if we are in IPv4 compatibility mode, clear out IFF_IPV4 3152 * so we don't print it. 3153 */ 3154 if (flags & IFF_IPV4) { 3155 if (p && p->af_af == AF_INET6) 3156 return (-1); 3157 if (v4compat) 3158 flags &= ~IFF_IPV4; 3159 3160 (void) printf("%s inet plumb", phydevname); 3161 } else if (flags & IFF_IPV6) { 3162 /* 3163 * else if the interface is IPv6 3164 * if we have a IPv4 address family restriction return 3165 * or we are in IPv4 compatibiltiy mode, return. 3166 */ 3167 if (p && p->af_af == AF_INET) 3168 return (-1); 3169 if (v4compat) 3170 return (-1); 3171 3172 (void) printf("%s inet6 plumb", phydevname); 3173 } 3174 3175 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3176 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 3177 Perror0_exit("configinfo: SIOCGLIFMETRIC"); 3178 } else { 3179 if (lifr.lifr_metric) 3180 (void) printf(" metric %d ", lifr.lifr_metric); 3181 } 3182 if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) && 3183 ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 3184 (void) printf(" mtu %d", lifr.lifr_metric); 3185 3186 /* don't print index when in compatibility mode */ 3187 if (!v4compat) { 3188 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 3189 (void) printf(" index %d", lifr.lifr_index); 3190 } 3191 3192 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 3193 if (lifr.lifr_index != 0) { 3194 if (if_indextoname(lifr.lifr_index, 3195 if_usesrc_name) != NULL) { 3196 (void) printf(" usesrc %s", if_usesrc_name); 3197 } 3198 } 3199 } 3200 3201 if (p != NULL) { 3202 (*p->af_configinfo)(1, flags); 3203 } else { 3204 for (p = afs; p->af_name; p++) { 3205 (void) close(s); 3206 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3207 /* set global af for use in p->af_configinfo */ 3208 af = p->af_af; 3209 if (s == -1) { 3210 Perror0_exit("socket"); 3211 } 3212 (*p->af_configinfo)(0, flags); 3213 } 3214 } 3215 3216 (void) printf("\n"); 3217 3218 return (0); 3219 } 3220 3221 static void 3222 print_tsec(struct iftun_req *tparams) 3223 { 3224 ipsec_req_t *ipsr; 3225 3226 (void) printf("\ttunnel security settings "); 3227 /* 3228 * Deal with versioning, for now just point 3229 * an ipsec_req_t at ifta_secinfo. If versions 3230 * change, something else will overlay ifta_secinfo. 3231 */ 3232 assert(tparams->ifta_vers == IFTUN_VERSION); 3233 3234 ipsr = (ipsec_req_t *)(&tparams->ifta_secinfo); 3235 if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) { 3236 (void) printf("ah (%s) ", 3237 rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH)); 3238 } 3239 if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) { 3240 (void) printf("esp (%s", 3241 rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP)); 3242 (void) printf("/%s)", 3243 rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH)); 3244 } 3245 (void) printf("\n"); 3246 } 3247 3248 static void 3249 tun_status(void) 3250 { 3251 icfg_if_t interface; 3252 int rc; 3253 icfg_handle_t handle; 3254 int protocol; 3255 char srcbuf[INET6_ADDRSTRLEN]; 3256 char dstbuf[INET6_ADDRSTRLEN]; 3257 boolean_t tabbed; 3258 uint8_t hoplimit; 3259 int16_t encaplimit; 3260 struct sockaddr_storage taddr; 3261 socklen_t socklen = sizeof (taddr); 3262 3263 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 3264 interface.if_protocol = SOCKET_AF(af); 3265 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 3266 Perror0_exit((char *)icfg_errmsg(rc)); 3267 3268 /* 3269 * only print tunnel info for lun 0. If ioctl fails, assume 3270 * we are not a tunnel 3271 */ 3272 if (strchr(name, ':') != NULL || 3273 icfg_get_tunnel_lower(handle, &protocol) != ICFG_SUCCESS) { 3274 icfg_close(handle); 3275 return; 3276 } 3277 3278 switch (protocol) { 3279 case AF_INET: 3280 (void) printf("\tinet"); 3281 break; 3282 case AF_INET6: 3283 (void) printf("\tinet6"); 3284 break; 3285 default: 3286 Perror0_exit("\ttunnel: Illegal lower stream\n\t"); 3287 break; 3288 } 3289 3290 rc = icfg_get_tunnel_src(handle, (struct sockaddr *)&taddr, &socklen); 3291 if (rc == ICFG_NOT_SET) { 3292 (void) strlcpy(srcbuf, (protocol == AF_INET) ? "0.0.0.0" : 3293 "::", sizeof (srcbuf)); 3294 } else if (rc != ICFG_SUCCESS) { 3295 Perror0_exit((char *)icfg_errmsg(rc)); 3296 } else { 3297 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3298 srcbuf, sizeof (srcbuf)); 3299 if (rc != ICFG_SUCCESS) { 3300 Perror0_exit((char *)icfg_errmsg(rc)); 3301 } 3302 } 3303 3304 (void) printf(" tunnel src %s ", srcbuf); 3305 3306 rc = icfg_get_tunnel_dest(handle, (struct sockaddr *)&taddr, &socklen); 3307 if (rc == ICFG_NOT_SET) { 3308 (void) printf("\n"); 3309 } else { 3310 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3311 dstbuf, sizeof (dstbuf)); 3312 if (rc != ICFG_SUCCESS) { 3313 Perror0_exit((char *)icfg_errmsg(rc)); 3314 } 3315 (void) printf("tunnel dst %s\n", dstbuf); 3316 } 3317 3318 if (handle->ifh_tunnel_params != NULL && 3319 (handle->ifh_tunnel_params->ifta_flags & IFTUN_SECURITY)) 3320 print_tsec(handle->ifh_tunnel_params); 3321 3322 /* 3323 * tabbed indicates tabbed and printed. Use it tell us whether 3324 * to tab and that we've printed something here, so we need a 3325 * newline 3326 */ 3327 tabbed = _B_FALSE; 3328 3329 if (icfg_get_tunnel_hoplimit(handle, &hoplimit) == ICFG_SUCCESS) { 3330 (void) printf("\ttunnel hop limit %d ", hoplimit); 3331 tabbed = _B_TRUE; 3332 } 3333 3334 if ((protocol == AF_INET6) && 3335 (icfg_get_tunnel_encaplimit(handle, &encaplimit) == 3336 ICFG_SUCCESS)) { 3337 if (!tabbed) { 3338 (void) printf("\t"); 3339 tabbed = _B_TRUE; 3340 } 3341 if (encaplimit >= 0) { 3342 (void) printf("tunnel encapsulation limit %d", 3343 encaplimit); 3344 } else { 3345 (void) printf("tunnel encapsulation limit disabled"); 3346 } 3347 } 3348 3349 if (tabbed) 3350 (void) printf("\n"); 3351 3352 icfg_close(handle); 3353 } 3354 3355 static void 3356 in_status(int force, uint64_t flags) 3357 { 3358 struct sockaddr_in *sin, *laddr; 3359 struct sockaddr_in netmask = { AF_INET }; 3360 3361 if (debug) 3362 (void) printf("in_status(%s) flags 0x%llx\n", name, flags); 3363 3364 /* only print status for IPv4 interfaces */ 3365 if (!(flags & IFF_IPV4)) 3366 return; 3367 3368 /* if the interface is a tunnel, print the tunnel status */ 3369 tun_status(); 3370 3371 if (!(flags & IFF_NOLOCAL)) { 3372 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3373 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3374 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3375 errno == ENXIO) { 3376 if (!force) 3377 return; 3378 (void) memset(&lifr.lifr_addr, 0, 3379 sizeof (lifr.lifr_addr)); 3380 } else 3381 Perror0_exit("in_status: SIOCGLIFADDR"); 3382 } 3383 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3384 (void) printf("\tinet %s ", inet_ntoa(sin->sin_addr)); 3385 laddr = sin; 3386 } else { 3387 (void) printf("\tinet "); 3388 } 3389 3390 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3391 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3392 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3393 errno == ENXIO) { 3394 if (!force) 3395 return; 3396 (void) memset(&lifr.lifr_addr, 0, 3397 sizeof (lifr.lifr_addr)); 3398 } else { 3399 Perror0_exit("in_status: SIOCGLIFSUBNET"); 3400 } 3401 } 3402 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3403 if ((flags & IFF_NOLOCAL) || 3404 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3405 (void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr), 3406 lifr.lifr_addrlen); 3407 } 3408 if (sin->sin_family != AF_INET) { 3409 (void) printf("Wrong family: %d\n", sin->sin_family); 3410 } 3411 3412 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3413 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3414 if (errno != EADDRNOTAVAIL) 3415 Perror0_exit("in_status: SIOCGLIFNETMASK"); 3416 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3417 } else 3418 netmask.sin_addr = 3419 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3420 if (flags & IFF_POINTOPOINT) { 3421 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3422 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3423 if (errno == EADDRNOTAVAIL) 3424 (void) memset(&lifr.lifr_addr, 0, 3425 sizeof (lifr.lifr_addr)); 3426 else 3427 Perror0_exit("in_status: SIOCGLIFDSTADDR"); 3428 } 3429 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3430 (void) printf("--> %s ", inet_ntoa(sin->sin_addr)); 3431 } 3432 (void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr)); 3433 if (flags & IFF_BROADCAST) { 3434 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3435 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3436 if (errno == EADDRNOTAVAIL) 3437 (void) memset(&lifr.lifr_addr, 0, 3438 sizeof (lifr.lifr_addr)); 3439 else 3440 Perror0_exit("in_status: SIOCGLIFBRDADDR"); 3441 } 3442 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3443 if (sin->sin_addr.s_addr != 0) { 3444 (void) printf("broadcast %s", 3445 inet_ntoa(sin->sin_addr)); 3446 } 3447 } 3448 /* If there is a groupname, print it for lun 0 alone */ 3449 if (strchr(name, ':') == NULL) { 3450 (void) memset(lifr.lifr_groupname, 0, 3451 sizeof (lifr.lifr_groupname)); 3452 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3453 if (strlen(lifr.lifr_groupname) > 0) { 3454 (void) printf("\n\tgroupname %s", 3455 lifr.lifr_groupname); 3456 } 3457 } 3458 } 3459 (void) putchar('\n'); 3460 } 3461 3462 static void 3463 in6_status(int force, uint64_t flags) 3464 { 3465 char abuf[INET6_ADDRSTRLEN]; 3466 struct sockaddr_in6 *sin6, *laddr6; 3467 3468 if (debug) 3469 (void) printf("in6_status(%s) flags 0x%llx\n", name, flags); 3470 3471 if (!(flags & IFF_IPV6)) 3472 return; 3473 3474 /* if the interface is a tunnel, print the tunnel status */ 3475 tun_status(); 3476 3477 if (!(flags & IFF_NOLOCAL)) { 3478 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3479 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3480 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3481 errno == ENXIO) { 3482 if (!force) 3483 return; 3484 (void) memset(&lifr.lifr_addr, 0, 3485 sizeof (lifr.lifr_addr)); 3486 } else 3487 Perror0_exit("in_status6: SIOCGLIFADDR"); 3488 } 3489 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3490 (void) printf("\tinet6 %s/%d ", 3491 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3492 abuf, sizeof (abuf)), 3493 lifr.lifr_addrlen); 3494 laddr6 = sin6; 3495 } else { 3496 (void) printf("\tinet6 "); 3497 } 3498 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3499 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3500 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3501 errno == ENXIO) { 3502 if (!force) 3503 return; 3504 (void) memset(&lifr.lifr_addr, 0, 3505 sizeof (lifr.lifr_addr)); 3506 } else 3507 Perror0_exit("in_status6: SIOCGLIFSUBNET"); 3508 } 3509 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3510 if ((flags & IFF_NOLOCAL) || 3511 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3512 (void) printf("subnet %s/%d ", 3513 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3514 abuf, sizeof (abuf)), 3515 lifr.lifr_addrlen); 3516 } 3517 if (sin6->sin6_family != AF_INET6) { 3518 (void) printf("Wrong family: %d\n", sin6->sin6_family); 3519 } 3520 if (flags & IFF_POINTOPOINT) { 3521 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3522 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3523 if (errno == EADDRNOTAVAIL) 3524 (void) memset(&lifr.lifr_addr, 0, 3525 sizeof (lifr.lifr_addr)); 3526 else 3527 Perror0_exit("in_status6: SIOCGLIFDSTADDR"); 3528 } 3529 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3530 (void) printf("--> %s ", 3531 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3532 abuf, sizeof (abuf))); 3533 } 3534 if (verbose) { 3535 (void) putchar('\n'); 3536 (void) putchar('\t'); 3537 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3538 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3539 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3540 (void) memset(&lifr.lifr_addr, 0, 3541 sizeof (lifr.lifr_addr)); 3542 else 3543 Perror0_exit("in_status6: SIOCGLIFTOKEN"); 3544 } else { 3545 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3546 (void) printf("token %s/%d ", 3547 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3548 abuf, sizeof (abuf)), 3549 lifr.lifr_addrlen); 3550 } 3551 if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) { 3552 if (errno != EINVAL) { 3553 Perror0_exit("in_status6: SIOCGLIFLNKINFO"); 3554 } 3555 } else { 3556 (void) printf("maxhops %u, reachtime %u ms, " 3557 "reachretrans %u ms, maxmtu %u ", 3558 lifr.lifr_ifinfo.lir_maxhops, 3559 lifr.lifr_ifinfo.lir_reachtime, 3560 lifr.lifr_ifinfo.lir_reachretrans, 3561 lifr.lifr_ifinfo.lir_maxmtu); 3562 } 3563 } 3564 /* If there is a groupname, print it for lun 0 alone */ 3565 if (strchr(name, ':') == NULL) { 3566 (void) memset(lifr.lifr_groupname, 0, 3567 sizeof (lifr.lifr_groupname)); 3568 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3569 if (strlen(lifr.lifr_groupname) > 0) { 3570 (void) printf("\n\tgroupname %s", 3571 lifr.lifr_groupname); 3572 } 3573 } 3574 } 3575 (void) putchar('\n'); 3576 } 3577 3578 static void 3579 in_configinfo(int force, uint64_t flags) 3580 { 3581 struct sockaddr_in *sin, *laddr; 3582 struct sockaddr_in netmask = { AF_INET }; 3583 3584 if (debug) 3585 (void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags); 3586 3587 /* only configinfo info for IPv4 interfaces */ 3588 if (!(flags & IFF_IPV4)) 3589 return; 3590 3591 if (!(flags & IFF_NOLOCAL)) { 3592 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3593 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3594 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3595 errno == ENXIO) { 3596 if (!force) 3597 return; 3598 (void) memset(&lifr.lifr_addr, 0, 3599 sizeof (lifr.lifr_addr)); 3600 } else 3601 Perror0_exit("in_configinfo: SIOCGLIFADDR"); 3602 } 3603 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3604 if (get_lun(name) != 0) { 3605 (void) printf(" addif %s ", inet_ntoa(sin->sin_addr)); 3606 } else { 3607 (void) printf(" set %s ", inet_ntoa(sin->sin_addr)); 3608 } 3609 laddr = sin; 3610 } 3611 3612 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3613 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3614 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3615 errno == ENXIO) { 3616 if (!force) 3617 return; 3618 (void) memset(&lifr.lifr_addr, 0, 3619 sizeof (lifr.lifr_addr)); 3620 } else { 3621 Perror0_exit("in_configinfo: SIOCGLIFSUBNET"); 3622 } 3623 } 3624 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3625 3626 if ((flags & IFF_NOLOCAL) || 3627 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3628 (void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr), 3629 lifr.lifr_addrlen); 3630 } 3631 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3632 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3633 if (errno != EADDRNOTAVAIL) 3634 Perror0_exit("in_configinfo: SIOCGLIFNETMASK"); 3635 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3636 } else 3637 netmask.sin_addr = 3638 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3639 if (flags & IFF_POINTOPOINT) { 3640 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3641 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3642 if (errno == EADDRNOTAVAIL) 3643 (void) memset(&lifr.lifr_addr, 0, 3644 sizeof (lifr.lifr_addr)); 3645 else 3646 Perror0_exit("in_configinfo: SIOCGLIFDSTADDR"); 3647 } 3648 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3649 (void) printf(" destination %s ", inet_ntoa(sin->sin_addr)); 3650 } 3651 (void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr)); 3652 if (flags & IFF_BROADCAST) { 3653 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3654 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3655 if (errno == EADDRNOTAVAIL) 3656 (void) memset(&lifr.lifr_addr, 0, 3657 sizeof (lifr.lifr_addr)); 3658 else 3659 Perror0_exit("in_configinfo: SIOCGLIFBRDADDR"); 3660 } 3661 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3662 if (sin->sin_addr.s_addr != 0) { 3663 (void) printf(" broadcast %s ", 3664 inet_ntoa(sin->sin_addr)); 3665 } 3666 } 3667 3668 /* If there is a groupname, print it for lun 0 alone */ 3669 if (get_lun(name) == 0) { 3670 (void) memset(lifr.lifr_groupname, 0, 3671 sizeof (lifr.lifr_groupname)); 3672 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3673 if (strlen(lifr.lifr_groupname) > 0) { 3674 (void) printf(" group %s ", 3675 lifr.lifr_groupname); 3676 } 3677 } 3678 } 3679 3680 /* Print flags to configure */ 3681 print_config_flags(flags); 3682 3683 /* IFF_NOARP applies to AF_INET only */ 3684 if (flags & IFF_NOARP) { 3685 (void) printf("-arp "); 3686 } 3687 } 3688 3689 static void 3690 in6_configinfo(int force, uint64_t flags) 3691 { 3692 char abuf[INET6_ADDRSTRLEN]; 3693 struct sockaddr_in6 *sin6, *laddr6; 3694 3695 if (debug) 3696 (void) printf("in6_configinfo(%s) flags 0x%llx\n", name, 3697 flags); 3698 3699 if (!(flags & IFF_IPV6)) 3700 return; 3701 3702 if (!(flags & IFF_NOLOCAL)) { 3703 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3704 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3705 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3706 errno == ENXIO) { 3707 if (!force) 3708 return; 3709 (void) memset(&lifr.lifr_addr, 0, 3710 sizeof (lifr.lifr_addr)); 3711 } else 3712 Perror0_exit("in6_configinfo: SIOCGLIFADDR"); 3713 } 3714 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3715 if (get_lun(name) != 0) { 3716 (void) printf(" addif %s/%d ", 3717 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3718 abuf, sizeof (abuf)), 3719 lifr.lifr_addrlen); 3720 } else { 3721 (void) printf(" set %s/%d ", 3722 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3723 abuf, sizeof (abuf)), 3724 lifr.lifr_addrlen); 3725 } 3726 laddr6 = sin6; 3727 } 3728 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3729 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3730 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3731 errno == ENXIO) { 3732 if (!force) 3733 return; 3734 (void) memset(&lifr.lifr_addr, 0, 3735 sizeof (lifr.lifr_addr)); 3736 } else 3737 Perror0_exit("in6_configinfo: SIOCGLIFSUBNET"); 3738 } 3739 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3740 if ((flags & IFF_NOLOCAL) || 3741 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3742 (void) printf(" subnet %s/%d ", 3743 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3744 abuf, sizeof (abuf)), 3745 lifr.lifr_addrlen); 3746 } 3747 3748 if (flags & IFF_POINTOPOINT) { 3749 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3750 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3751 if (errno == EADDRNOTAVAIL) 3752 (void) memset(&lifr.lifr_addr, 0, 3753 sizeof (lifr.lifr_addr)); 3754 else 3755 Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR"); 3756 } 3757 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3758 (void) printf(" destination %s ", 3759 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3760 abuf, sizeof (abuf))); 3761 } 3762 3763 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3764 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3765 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3766 (void) memset(&lifr.lifr_addr, 0, 3767 sizeof (lifr.lifr_addr)); 3768 else 3769 Perror0_exit("in6_configinfo: SIOCGLIFTOKEN"); 3770 } else { 3771 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3772 (void) printf(" token %s/%d ", 3773 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3774 abuf, sizeof (abuf)), 3775 lifr.lifr_addrlen); 3776 } 3777 3778 /* If there is a groupname, print it for lun 0 alone */ 3779 if (get_lun(name) == 0) { 3780 (void) memset(lifr.lifr_groupname, 0, 3781 sizeof (lifr.lifr_groupname)); 3782 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3783 if (strlen(lifr.lifr_groupname) > 0) { 3784 (void) printf(" group %s ", 3785 lifr.lifr_groupname); 3786 } 3787 } 3788 } 3789 3790 /* Print flags to configure */ 3791 print_config_flags(flags); 3792 3793 /* IFF_NONUD applies to AF_INET6 only */ 3794 if (flags & IFF_NONUD) { 3795 (void) printf("-nud "); 3796 } 3797 } 3798 3799 /* ARGSUSED */ 3800 static int 3801 get_lun(char *rsrc) 3802 { 3803 char resource[LIFNAMSIZ]; 3804 char *cp; 3805 3806 (void) strcpy(resource, rsrc); 3807 3808 /* remove LIF component */ 3809 cp = strchr(resource, ':'); 3810 if (cp) { 3811 cp++; 3812 return (atoi(cp)); 3813 } 3814 3815 return (0); 3816 } 3817 3818 /* 3819 * We need to plink both the arp-device stream and the arp-ip-device stream. 3820 * However the muxid is stored only in IP. Plumbing 2 streams individually 3821 * is not atomic, and if ifconfig is killed, the resulting plumbing can 3822 * be inconsistent. For eg. if only the arp stream is plumbed, we have lost 3823 * the muxid, and the half-baked plumbing can neither be unplumbed nor 3824 * replumbed, thus requiring a reboot. To avoid the above the following 3825 * scheme is used. 3826 * 3827 * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams. 3828 * This is done by pushing arp on to the mux (/dev/udp). ARP adds some 3829 * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know 3830 * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs 3831 * the IP stream first, and unplumbs it last. The kernel (IP) does not 3832 * allow IP stream to be unplumbed without unplumbing arp stream. Similarly 3833 * it does not allow arp stream to be plumbed before IP stream is plumbed. 3834 * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic, 3835 * and IP uses the info in the I_PLINK message to get the muxid. 3836 * 3837 * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use 3838 * /dev/udp[6]. 3839 * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream 3840 * depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp 3841 * or /dev/udp6. 3842 * c. We need to push ARP in order to get the required kernel support for 3843 * atomic plumbings. The actual work done by ARP is explained in arp.c 3844 * Without pushing ARP, we will still be able to plumb/unplumb. But 3845 * it is not atomic, and is supported by the kernel for backward 3846 * compatibility for other utilities like atmifconfig etc. In this case 3847 * the utility must use SIOCSLIFMUXID. 3848 */ 3849 static void 3850 plumb_one_device(dlpi_if_attr_t *diap, int ip_fd, int af) 3851 { 3852 int arp_fd = -1; 3853 int arp_muxid = -1, ip_muxid; 3854 int mux_fd; 3855 char *udp_dev_name; 3856 dlpi_if_attr_t dia; 3857 3858 if (debug) 3859 (void) printf("plumb_one_device: ifname %s, ppa %d\n", 3860 diap->ifname, diap->ppa); 3861 3862 if (diap->style == DL_STYLE2 && dlpi_detach(ip_fd, -1) < 0) 3863 Perror0_exit("dlpi_detach"); 3864 3865 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) 3866 Perror2_exit("I_PUSH", IP_MOD_NAME); 3867 3868 /* 3869 * Push the ARP module onto the interface stream. IP uses 3870 * this to send resolution requests up to ARP. We need to 3871 * do this before the SLIFNAME ioctl is sent down because 3872 * the interface becomes publicly known as soon as the SLIFNAME 3873 * ioctl completes. Thus some other process trying to bring up 3874 * the interface after SLIFNAME but before we have pushed ARP 3875 * could hang. We pop the module again later if it is not needed. 3876 */ 3877 if (ioctl(ip_fd, I_PUSH, ARP_MOD_NAME) == -1) 3878 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3879 3880 /* 3881 * Set IFF_IPV4/IFF_IPV6 flags. 3882 * At this point in time the kernel also allows an 3883 * override of the CANTCHANGE flags. 3884 */ 3885 3886 lifr.lifr_name[0] = '\0'; 3887 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3888 Perror0_exit("plumb_one_device: SIOCGLIFFLAGS"); 3889 3890 /* Set the name string and the IFF_IPV* flag */ 3891 if (af == AF_INET6) { 3892 lifr.lifr_flags |= IFF_IPV6; 3893 lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4); 3894 } else { 3895 lifr.lifr_flags |= IFF_IPV4; 3896 lifr.lifr_flags &= ~IFF_IPV6; 3897 } 3898 3899 /* record the device and module names as interface name */ 3900 lifr.lifr_ppa = diap->ppa; 3901 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3902 3903 /* set the interface name */ 3904 if (ioctl(ip_fd, SIOCSLIFNAME, (char *)&lifr) == -1) { 3905 if (errno != EEXIST) 3906 Perror0_exit("SIOCSLIFNAME for ip"); 3907 /* 3908 * This difference between the way we behave for EEXIST 3909 * and that with other errors exists to preserve legacy 3910 * behaviour. Earlier when foreachinterface() and matcif() 3911 * were doing the duplicate interface name checks, for 3912 * already existing interfaces, inetplumb() returned "0". 3913 * To preserve this behaviour, Perror0() and return are 3914 * called for EEXIST. 3915 */ 3916 Perror0("SIOCSLIFNAME for ip"); 3917 return; 3918 } 3919 3920 /* Get the full set of existing flags for this stream */ 3921 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3922 Perror0_exit("plumb_one_device: SIOCFLIFFLAGS"); 3923 3924 if (debug) { 3925 (void) printf("plumb_one_device: %s got flags: \n", 3926 lifr.lifr_name); 3927 print_flags(lifr.lifr_flags); 3928 (void) putchar('\n'); 3929 } 3930 3931 /* Check if arp is not actually needed */ 3932 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3933 if (ioctl(ip_fd, I_POP, 0) == -1) 3934 Perror2_exit("I_POP", ARP_MOD_NAME); 3935 } 3936 3937 /* 3938 * Open "/dev/udp" for use as a multiplexor to PLINK the 3939 * interface stream under. We use "/dev/udp" instead of "/dev/ip" 3940 * since STREAMS will not let you PLINK a driver under itself, 3941 * and "/dev/ip" is typically the driver at the bottom of 3942 * the stream for tunneling interfaces. 3943 */ 3944 if (af == AF_INET6) 3945 udp_dev_name = UDP6_DEV_NAME; 3946 else 3947 udp_dev_name = UDP_DEV_NAME; 3948 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 3949 exit(EXIT_FAILURE); 3950 3951 /* Check if arp is not needed */ 3952 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3953 /* 3954 * PLINK the interface stream so that ifconfig can exit 3955 * without tearing down the stream. 3956 */ 3957 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 3958 Perror0_exit("I_PLINK for ip"); 3959 } 3960 (void) close(mux_fd); 3961 return; 3962 } 3963 3964 /* 3965 * This interface does use ARP, so set up a separate stream 3966 * from the interface to ARP. 3967 * 3968 * Note: modules specified by the user are pushed 3969 * only on the interface stream, not on the ARP stream. 3970 */ 3971 3972 if (debug) 3973 (void) printf("plumb_one_device: ifname: %s\n", 3974 diap->ifname); 3975 arp_fd = dlpi_if_open(diap->ifname, &dia, _B_FALSE); 3976 3977 if (dia.style == DL_STYLE2 && dlpi_detach(arp_fd, -1) < 0) 3978 Perror0_exit("dlpi_detach"); 3979 3980 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) 3981 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3982 3983 /* 3984 * Tell ARP the name and unit number for this interface. 3985 * Note that arp has no support for transparent ioctls. 3986 */ 3987 if (strioctl(arp_fd, SIOCSLIFNAME, (char *)&lifr, 3988 sizeof (lifr)) == -1) { 3989 if (errno != EEXIST) 3990 Perror0_exit("SIOCSLIFNAME for arp"); 3991 Perror0("SIOCSLIFNAME for arp"); 3992 (void) close(arp_fd); 3993 (void) close(mux_fd); 3994 return; 3995 } 3996 /* 3997 * PLINK the IP and ARP streams so that ifconfig can exit 3998 * without tearing down the stream. 3999 */ 4000 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 4001 Perror0_exit("I_PLINK for ip"); 4002 } 4003 if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) { 4004 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 4005 Perror0_exit("I_PLINK for arp"); 4006 } 4007 4008 if (debug) 4009 (void) printf("arp muxid = %d\n", arp_muxid); 4010 (void) close(arp_fd); 4011 (void) close(mux_fd); 4012 } 4013 4014 4015 /* 4016 * If this is a physical interface then remove it. 4017 * If it is a logical interface name use SIOCLIFREMOVEIF to 4018 * remove it. In both cases fail if it doesn't exist. 4019 */ 4020 /* ARGSUSED */ 4021 static int 4022 inetunplumb(char *arg, int64_t param) 4023 { 4024 int ip_muxid, arp_muxid; 4025 int mux_fd; 4026 char *udp_dev_name; 4027 char *strptr; 4028 uint64_t flags; 4029 boolean_t changed_arp_muxid = _B_FALSE; 4030 int save_errno; 4031 4032 strptr = strchr(name, ':'); 4033 if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) { 4034 /* Can't unplumb logical interface zero */ 4035 if (strptr != NULL && strcmp(strptr, ":0") == 0) { 4036 (void) fprintf(stderr, "ifconfig: unplumb:" 4037 " Cannot unplumb %s: Invalid interface\n", name); 4038 exit(1); 4039 } 4040 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4041 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 4042 4043 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) 4044 Perror0_exit("unplumb: SIOCLIFREMOVEIF"); 4045 return (0); 4046 } 4047 4048 /* 4049 * We used /dev/udp or udp6 to set up the mux. So we have to use 4050 * the same now for PUNLINK also. 4051 */ 4052 if (afp->af_af == AF_INET6) 4053 udp_dev_name = UDP6_DEV_NAME; 4054 else 4055 udp_dev_name = UDP_DEV_NAME; 4056 4057 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 4058 exit(EXIT_FAILURE); 4059 4060 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4061 if (ioctl(mux_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 4062 Perror0_exit("unplumb: SIOCGLIFFLAGS"); 4063 } 4064 flags = lifr.lifr_flags; 4065 if (ioctl(mux_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 4066 Perror0_exit("unplumb: SIOCGLIFMUXID"); 4067 } 4068 arp_muxid = lifr.lifr_arp_muxid; 4069 ip_muxid = lifr.lifr_ip_muxid; 4070 /* 4071 * We don't have a good way of knowing whether the arp stream is 4072 * plumbed. We can't rely on IFF_NOARP because someone could 4073 * have turned it off later using "ifconfig xxx -arp". 4074 */ 4075 if (arp_muxid != 0) { 4076 if (debug) 4077 (void) printf("arp_muxid %d\n", arp_muxid); 4078 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 4079 if ((errno == EINVAL) && 4080 (flags & (IFF_NOARP | IFF_IPV6))) { 4081 /* 4082 * Some plumbing utilities set the muxid to 4083 * -1 or some invalid value to signify that 4084 * there is no arp stream. Set the muxid to 0 4085 * before trying to unplumb the IP stream. 4086 * IP does not allow the IP stream to be 4087 * unplumbed if it sees a non-null arp muxid, 4088 * for consistency of IP-ARP streams. 4089 */ 4090 lifr.lifr_arp_muxid = 0; 4091 (void) ioctl(mux_fd, SIOCSLIFMUXID, 4092 (caddr_t)&lifr); 4093 changed_arp_muxid = _B_TRUE; 4094 } else { 4095 Perror0("I_PUNLINK for arp"); 4096 } 4097 } 4098 } 4099 if (debug) 4100 (void) printf("ip_muxid %d\n", ip_muxid); 4101 4102 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 4103 if (changed_arp_muxid) { 4104 /* 4105 * Some error occurred, and we need to restore 4106 * everything back to what it was. 4107 */ 4108 save_errno = errno; 4109 lifr.lifr_arp_muxid = arp_muxid; 4110 lifr.lifr_ip_muxid = ip_muxid; 4111 (void) ioctl(mux_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 4112 errno = save_errno; 4113 } 4114 Perror0_exit("I_PUNLINK for ip"); 4115 } 4116 (void) close(mux_fd); 4117 return (0); 4118 } 4119 4120 /* 4121 * If this is a physical interface then create it unless it is already 4122 * present. If it is a logical interface name use SIOCLIFADDIF to 4123 * create and (and fail it if already exists.) 4124 * As a special case send SIOCLIFADDIF for the loopback interface. This 4125 * is needed since there is no other notion of plumbing the loopback 4126 * interface. 4127 */ 4128 /* ARGSUSED */ 4129 static int 4130 inetplumb(char *arg, int64_t param) 4131 { 4132 char *strptr; 4133 int dev_fd; 4134 dlpi_if_attr_t dia; 4135 boolean_t islo; 4136 4137 strptr = strchr(name, ':'); 4138 islo = (strcmp(name, LOOPBACK_IF) == 0); 4139 4140 if (strptr != NULL || islo) { 4141 (void) memset(&lifr, 0, sizeof (lifr)); 4142 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4143 if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) { 4144 if (debug) { 4145 (void) fprintf(stderr, 4146 "ifconfig: %s already exists\n", name); 4147 } 4148 return (0); 4149 } 4150 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) { 4151 if (errno == EEXIST) { 4152 if (debug) { 4153 (void) fprintf(stderr, 4154 "ifconfig: %s already exists\n", 4155 name); 4156 } 4157 } else { 4158 Perror2_exit("plumb: SIOCLIFADDIF", name); 4159 } 4160 } 4161 /* 4162 * IP can create the new logical interface on a different 4163 * physical interface in the same IPMP group. Take the new 4164 * interface into account for further operations. 4165 */ 4166 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 4167 return (0); 4168 } 4169 4170 if (debug) 4171 (void) printf("inetplumb: %s af %d\n", name, afp->af_af); 4172 4173 if ((dev_fd = dlpi_if_open(name, &dia, _B_FALSE)) < 0) { 4174 Perror2_exit("plumb", name); 4175 /* NOTREACHED */ 4176 } 4177 4178 plumb_one_device(&dia, dev_fd, afp->af_af); 4179 (void) close(dev_fd); 4180 return (0); 4181 } 4182 4183 void 4184 Perror0(char *cmd) 4185 { 4186 int save_errno; 4187 4188 save_errno = errno; 4189 (void) fprintf(stderr, "ifconfig: "); 4190 errno = save_errno; 4191 switch (errno) { 4192 4193 case ENXIO: 4194 (void) fprintf(stderr, "%s: %s: no such interface\n", 4195 cmd, lifr.lifr_name); 4196 break; 4197 4198 case EPERM: 4199 (void) fprintf(stderr, "%s: %s: permission denied\n", 4200 cmd, lifr.lifr_name); 4201 break; 4202 4203 case EEXIST: 4204 (void) fprintf(stderr, "%s: %s: already exists\n", 4205 cmd, lifr.lifr_name); 4206 break; 4207 4208 default: { 4209 char buf[BUFSIZ]; 4210 4211 (void) snprintf(buf, sizeof (buf), "%s: %s", 4212 cmd, lifr.lifr_name); 4213 perror(buf); 4214 } 4215 } 4216 } 4217 4218 void 4219 Perror0_exit(char *cmd) 4220 { 4221 Perror0(cmd); 4222 exit(1); 4223 /* NOTREACHED */ 4224 } 4225 4226 void 4227 Perror2(char *cmd, char *str) 4228 { 4229 int save_errno; 4230 4231 save_errno = errno; 4232 (void) fprintf(stderr, "ifconfig: "); 4233 errno = save_errno; 4234 switch (errno) { 4235 4236 case ENXIO: 4237 (void) fprintf(stderr, "%s: %s: no such interface\n", 4238 cmd, str); 4239 break; 4240 4241 case EPERM: 4242 (void) fprintf(stderr, "%s: %s: permission denied\n", 4243 cmd, str); 4244 break; 4245 4246 default: { 4247 char buf[BUFSIZ]; 4248 4249 (void) snprintf(buf, sizeof (buf), "%s: %s", cmd, str); 4250 perror(buf); 4251 } 4252 } 4253 } 4254 4255 /* 4256 * Print out error message (Perror2()) and exit 4257 */ 4258 void 4259 Perror2_exit(char *cmd, char *str) 4260 { 4261 Perror2(cmd, str); 4262 exit(1); 4263 /* NOTREACHED */ 4264 } 4265 4266 /* 4267 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4268 * pass out <n> in *plenp. 4269 * If <n> doesn't parse return BAD_ADDR as *plenp. 4270 * If no /<n> is present return NO_PREFIX as *plenp. 4271 */ 4272 static void 4273 in_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4274 { 4275 struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 4276 struct hostent *hp; 4277 struct netent *np; 4278 char str[BUFSIZ]; 4279 int error_num; 4280 4281 (void) strncpy(str, s, sizeof (str)); 4282 4283 /* 4284 * Look for '/'<n> is plenp 4285 */ 4286 if (plenp != NULL) { 4287 char *cp; 4288 4289 *plenp = in_getprefixlen(str, _B_TRUE, ADDRBITS_V4); 4290 if (*plenp == BAD_ADDR) 4291 return; 4292 cp = strchr(str, '/'); 4293 if (cp != NULL) 4294 *cp = '\0'; 4295 } else if (strchr(str, '/') != NULL) { 4296 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4297 exit(1); 4298 } 4299 4300 (void) memset(sin, 0, sizeof (*sin)); 4301 4302 /* 4303 * Try to catch attempts to set the broadcast address to all 1's. 4304 */ 4305 if (strcmp(str, "255.255.255.255") == 0 || 4306 (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) { 4307 sin->sin_family = AF_INET; 4308 sin->sin_addr.s_addr = 0xffffffff; 4309 return; 4310 } 4311 4312 hp = getipnodebyname(str, AF_INET, 0, &error_num); 4313 if (hp) { 4314 sin->sin_family = hp->h_addrtype; 4315 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); 4316 freehostent(hp); 4317 return; 4318 } 4319 np = getnetbyname(str); 4320 if (np) { 4321 sin->sin_family = np->n_addrtype; 4322 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 4323 return; 4324 } 4325 if (error_num == TRY_AGAIN) { 4326 (void) fprintf(stderr, "ifconfig: %s: bad address " 4327 "(try again later)\n", s); 4328 } else { 4329 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4330 } 4331 exit(1); 4332 } 4333 4334 /* 4335 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4336 * pass out <n> in *plenp. 4337 * If <n> doesn't parse return BAD_ADDR as *plenp. 4338 * If no /<n> is present return NO_PREFIX as *plenp. 4339 */ 4340 static void 4341 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4342 { 4343 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr; 4344 struct hostent *hp; 4345 char str[BUFSIZ]; 4346 int error_num; 4347 4348 (void) strncpy(str, s, sizeof (str)); 4349 4350 /* 4351 * Look for '/'<n> is plenp 4352 */ 4353 if (plenp != NULL) { 4354 char *cp; 4355 4356 *plenp = in_getprefixlen(str, _B_TRUE, ADDRBITS_V6); 4357 if (*plenp == BAD_ADDR) 4358 return; 4359 cp = strchr(str, '/'); 4360 if (cp != NULL) 4361 *cp = '\0'; 4362 } else if (strchr(str, '/') != NULL) { 4363 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4364 exit(1); 4365 } 4366 4367 (void) memset(sin6, 0, sizeof (*sin6)); 4368 4369 hp = getipnodebyname(str, AF_INET6, 0, &error_num); 4370 if (hp) { 4371 sin6->sin6_family = hp->h_addrtype; 4372 (void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length); 4373 freehostent(hp); 4374 return; 4375 } 4376 if (error_num == TRY_AGAIN) { 4377 (void) fprintf(stderr, "ifconfig: %s: bad address " 4378 "(try again later)\n", s); 4379 } else { 4380 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4381 } 4382 exit(1); 4383 } 4384 4385 /* 4386 * If "slash" is zero this parses the whole string as 4387 * an integer. With "slash" non zero it parses the tail part as an integer. 4388 * 4389 * If it is not a valid integer this returns BAD_ADDR. 4390 * If there is /<n> present this returns NO_PREFIX. 4391 */ 4392 static int 4393 in_getprefixlen(char *addr, boolean_t slash, int max_plen) 4394 { 4395 int prefixlen; 4396 char *str, *end; 4397 4398 if (slash) { 4399 str = strchr(addr, '/'); 4400 if (str == NULL) 4401 return (NO_PREFIX); 4402 str++; 4403 } else 4404 str = addr; 4405 4406 prefixlen = strtol(str, &end, 10); 4407 if (prefixlen < 0) 4408 return (BAD_ADDR); 4409 if (str == end) 4410 return (BAD_ADDR); 4411 if (max_plen != 0 && max_plen < prefixlen) 4412 return (BAD_ADDR); 4413 return (prefixlen); 4414 } 4415 4416 /* 4417 * Convert a prefix length to a mask. 4418 * Returns 1 if ok. 0 otherwise. 4419 * Assumes the mask array is zero'ed by the caller. 4420 */ 4421 static boolean_t 4422 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 4423 { 4424 if (prefixlen < 0 || prefixlen > maxlen) 4425 return (0); 4426 4427 while (prefixlen > 0) { 4428 if (prefixlen >= 8) { 4429 *mask++ = 0xFF; 4430 prefixlen -= 8; 4431 continue; 4432 } 4433 *mask |= 1 << (8 - prefixlen); 4434 prefixlen--; 4435 } 4436 return (1); 4437 } 4438 4439 static void 4440 print_flags(uint64_t flags) 4441 { 4442 boolean_t first = _B_TRUE; 4443 int cnt, i; 4444 4445 (void) printf("flags=%llx", flags); 4446 cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t); 4447 for (i = 0; i < cnt; i++) { 4448 if (flags & if_flags_tbl[i].iff_value) { 4449 if (first) { 4450 (void) printf("<"); 4451 first = _B_FALSE; 4452 } else { 4453 /* 4454 * It has to be here and not with the 4455 * printf below because for the last one, 4456 * we don't want a comma before the ">". 4457 */ 4458 (void) printf(","); 4459 } 4460 (void) printf("%s", if_flags_tbl[i].iff_name); 4461 } 4462 } 4463 if (!first) 4464 (void) printf(">"); 4465 } 4466 4467 static void 4468 print_config_flags(uint64_t flags) 4469 { 4470 int cnt, i; 4471 4472 cnt = sizeof (if_config_cmd_tbl) / sizeof (if_config_cmd_t); 4473 for (i = 0; i < cnt; i++) { 4474 if (flags & if_config_cmd_tbl[i].iff_flag) { 4475 (void) printf("%s ", if_config_cmd_tbl[i].iff_name); 4476 } 4477 } 4478 } 4479 4480 /* 4481 * Use the configured directory lookup mechanism (e.g. files/NIS/NIS+/...) 4482 * to find the network mask. Returns true if we found one to set. 4483 * 4484 * The parameter addr_set controls whether we should get the address of 4485 * the working interface for the netmask query. If addr_set is true, 4486 * we will use the address provided. Otherwise, we will find the working 4487 * interface's address and use it instead. 4488 */ 4489 static boolean_t 4490 in_getmask(struct sockaddr_in *saddr, boolean_t addr_set) 4491 { 4492 struct sockaddr_in ifaddr; 4493 4494 /* 4495 * Read the address from the interface if it is not passed in. 4496 */ 4497 if (!addr_set) { 4498 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4499 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 4500 if (errno != EADDRNOTAVAIL) { 4501 (void) fprintf(stderr, "Need net number for " 4502 "mask\n"); 4503 } 4504 return (_B_FALSE); 4505 } 4506 ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr); 4507 } else { 4508 ifaddr.sin_addr = saddr->sin_addr; 4509 } 4510 if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) { 4511 saddr->sin_family = AF_INET; 4512 return (_B_TRUE); 4513 } 4514 return (_B_FALSE); 4515 } 4516 4517 static int 4518 strioctl(int s, int cmd, char *buf, int buflen) 4519 { 4520 struct strioctl ioc; 4521 4522 (void) memset(&ioc, 0, sizeof (ioc)); 4523 ioc.ic_cmd = cmd; 4524 ioc.ic_timout = 0; 4525 ioc.ic_len = buflen; 4526 ioc.ic_dp = buf; 4527 return (ioctl(s, I_STR, (char *)&ioc)); 4528 } 4529 4530 static void 4531 add_ni(char *name) 4532 { 4533 ni_t **pp; 4534 ni_t *p; 4535 4536 for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) { 4537 if (strcmp(p->ni_name, name) == 0) { 4538 if (debug > 2) 4539 (void) fprintf(stderr, "'%s' is a duplicate\n", 4540 name); 4541 return; 4542 } 4543 } 4544 4545 if (debug > 2) 4546 (void) fprintf(stderr, "adding '%s'\n", 4547 name); 4548 4549 if ((p = malloc(sizeof (ni_t))) == NULL) 4550 return; 4551 4552 (void) strlcpy(p->ni_name, name, sizeof (p->ni_name)); 4553 p->ni_next = NULL; 4554 4555 *pp = p; 4556 num_ni++; 4557 } 4558 4559 /* ARGSUSED2 */ 4560 static int 4561 devfs_entry(di_node_t node, di_minor_t minor, void *arg) 4562 { 4563 char *provider; 4564 int fd; 4565 uint_t ppa; 4566 dl_info_ack_t dlia; 4567 char ifname[LIFNAMSIZ]; 4568 4569 provider = di_minor_name(minor); 4570 4571 if (strlen(provider) > LIFNAMSIZ) 4572 return (DI_WALK_CONTINUE); 4573 4574 if (debug > 2) 4575 fprintf(stderr, "provider = %s\n", provider); 4576 4577 if ((fd = dlpi_open(provider)) < 0) 4578 return (DI_WALK_CONTINUE); 4579 4580 if (debug > 2) 4581 fprintf(stderr, "getting DL_INFO_ACK\n"); 4582 4583 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) 4584 goto done; 4585 4586 if (dlia.dl_provider_style == DL_STYLE1) { 4587 if (debug > 2) 4588 fprintf(stderr, "provider is DL_STYLE1\n"); 4589 add_ni(provider); 4590 goto done; 4591 } 4592 4593 if (debug > 2) 4594 fprintf(stderr, "provider is DL_STYLE2\n"); 4595 4596 if (di_minor_type(minor) != DDM_ALIAS) { 4597 if (debug > 2) 4598 (void) fprintf(stderr, 4599 "non-alias node, ignoring\n"); 4600 goto done; 4601 } 4602 4603 if (debug > 2) 4604 (void) fprintf(stderr, 4605 "alias node, using instance\n"); 4606 ppa = di_instance(node); 4607 4608 if (dlpi_attach(fd, -1, ppa) < 0) { 4609 if (debug > 2) 4610 (void) fprintf(stderr, 4611 "non-existent PPA, ignoring\n"); 4612 goto done; 4613 } 4614 4615 (void) snprintf(ifname, LIFNAMSIZ, "%s%d", provider, ppa); 4616 add_ni(ifname); 4617 4618 done: 4619 (void) dlpi_close(fd); 4620 return (DI_WALK_CONTINUE); 4621 } 4622 4623 /* 4624 * dhcp-related routines 4625 */ 4626 4627 static int 4628 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[]) 4629 { 4630 dhcp_ipc_request_t *request; 4631 dhcp_ipc_reply_t *reply = NULL; 4632 int timeout = DHCP_IPC_WAIT_DEFAULT; 4633 dhcp_ipc_type_t type = DHCP_START; 4634 int error; 4635 boolean_t is_primary = _B_FALSE; 4636 boolean_t started = _B_FALSE; 4637 4638 for (argv++; --argc > 0; argv++) { 4639 4640 if (strcmp(*argv, "primary") == 0) { 4641 is_primary = _B_TRUE; 4642 continue; 4643 } 4644 4645 if (strcmp(*argv, "wait") == 0) { 4646 if (--argc <= 0) { 4647 usage(); 4648 return (DHCP_EXIT_BADARGS); 4649 } 4650 argv++; 4651 4652 if (strcmp(*argv, "forever") == 0) { 4653 timeout = DHCP_IPC_WAIT_FOREVER; 4654 continue; 4655 } 4656 4657 if (sscanf(*argv, "%d", &timeout) != 1) { 4658 usage(); 4659 return (DHCP_EXIT_BADARGS); 4660 } 4661 4662 if (timeout < 0) { 4663 usage(); 4664 return (DHCP_EXIT_BADARGS); 4665 } 4666 continue; 4667 } 4668 4669 type = dhcp_string_to_request(*argv); 4670 if (type == -1) { 4671 usage(); 4672 return (DHCP_EXIT_BADARGS); 4673 } 4674 } 4675 4676 /* 4677 * Only try to start agent on start or inform; in all other cases it 4678 * has to already be running for anything to make sense. 4679 */ 4680 if (type == DHCP_START || type == DHCP_INFORM) { 4681 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) { 4682 (void) fprintf(stderr, "%s: unable to start %s\n", 4683 caller, DHCP_AGENT_PATH); 4684 return (DHCP_EXIT_FAILURE); 4685 } 4686 started = _B_TRUE; 4687 } 4688 4689 if (is_primary) 4690 type = type | DHCP_PRIMARY; 4691 4692 request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE); 4693 if (request == NULL) { 4694 (void) fprintf(stderr, "%s: out of memory\n", caller); 4695 return (DHCP_EXIT_SYSTEM); 4696 } 4697 4698 error = dhcp_ipc_make_request(request, &reply, timeout); 4699 if (error != 0) { 4700 free(request); 4701 /* 4702 * Re-map connect error to not under control if we didn't try a 4703 * start operation, as this has to be true and results in a 4704 * clearer message, not to mention preserving compatibility 4705 * with the days when we always started dhcpagent for every 4706 * request. 4707 */ 4708 if (error == DHCP_IPC_E_CONNECT && !started) 4709 error = DHCP_IPC_E_UNKIF; 4710 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4711 dhcp_ipc_strerror(error)); 4712 return (DHCP_EXIT_FAILURE); 4713 } 4714 4715 error = reply->return_code; 4716 if (error != 0) { 4717 free(request); 4718 free(reply); 4719 4720 if (error == DHCP_IPC_E_TIMEOUT && timeout == 0) 4721 return (DHCP_EXIT_SUCCESS); 4722 4723 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4724 dhcp_ipc_strerror(error)); 4725 4726 if (error == DHCP_IPC_E_TIMEOUT) 4727 return (DHCP_EXIT_TIMEOUT); 4728 else 4729 return (DHCP_EXIT_IF_FAILURE); 4730 } 4731 4732 if (DHCP_IPC_CMD(type) == DHCP_STATUS) { 4733 (void) printf("%s", dhcp_status_hdr_string()); 4734 (void) printf("%s", dhcp_status_reply_to_string(reply)); 4735 } 4736 4737 free(request); 4738 free(reply); 4739 return (DHCP_EXIT_SUCCESS); 4740 } 4741 4742 static void 4743 usage(void) 4744 { 4745 (void) fprintf(stderr, 4746 "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n"); 4747 4748 (void) fprintf(stderr, "%s", 4749 "\t[ <addr_family> ]\n" 4750 "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n" 4751 "\t[ set [ <address>][/<prefix_length>] ]" 4752 " [ <address>/<prefix_length>] ]\n" 4753 "\t[ destination <dest_address> ]\n" 4754 "\t[ addif <address>[/<prefix_length>]" 4755 " [ <dest_address> ] ]\n" 4756 "\t[ removeif <address>[/<prefix_length>] ]\n" 4757 "\t[ arp | -arp ]\n" 4758 "\t[ auto-revarp ]\n" 4759 "\t[ broadcast <broad_addr> ]\n" 4760 "\t[ index <if_index> ]\n" 4761 "\t[ metric <n> ] [ mtu <n> ]\n" 4762 "\t[ netmask <mask> ]\n" 4763 "\t[ plumb ] [ unplumb ]\n" 4764 "\t[ preferred | -preferred ]\n" 4765 "\t[ private | -private ]\n" 4766 "\t[ local | -local ]\n" 4767 "\t[ router | -router ]\n" 4768 "\t[ subnet <subnet_address>]\n" 4769 "\t[ trailers | -trailers ]\n" 4770 "\t[ token <address>/<prefix_length> ]\n" 4771 "\t[ tsrc <tunnel_src_address> ]\n" 4772 "\t[ tdst <tunnel_dest_address> ]\n" 4773 "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n" 4774 "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n" 4775 "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n" 4776 "\t[ up ] [ down ]\n" 4777 "\t[ xmit | -xmit ]\n" 4778 "\t[ modlist ]\n" 4779 "\t[ modinsert <module_name@position> ]\n" 4780 "\t[ modremove <module_name@position> ]\n" 4781 "\t[ group <groupname>] | [ group \"\"]\n" 4782 "\t[ deprecated | -deprecated ]\n" 4783 "\t[ standby | -standby ]\n" 4784 "\t[ failover | -failover ]\n" 4785 "\t[ zone <zonename> | -zone ]\n" 4786 "\t[ usesrc <interface> ]\n"); 4787 4788 (void) fprintf(stderr, "or\n"); 4789 (void) fprintf(stderr, 4790 "\tifconfig <interface> | -a[ 4 | 6 | D ] [ u | d ]\n"); 4791 4792 (void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n" 4793 "\t[ wait <time> | forever ]\n\t[ primary ]\n" 4794 "\tstart | drop | ping | release | status | inform\n"); 4795 } 4796