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