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