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 *, int *); 186 static int ip_plink(int, 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 muxid_fd; 2228 int muxfd; 2229 int ipfd_lowstr; 2230 int arpfd_lowstr; 2231 int num_mods; 2232 int i; 2233 struct str_list strlist; 2234 int orig_arpid; 2235 2236 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2237 if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr, 2238 &orig_arpid) < 0) { 2239 return (-1); 2240 } 2241 if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) { 2242 Perror0("cannot I_LIST to get the number of modules"); 2243 } else { 2244 if (debug > 0) { 2245 (void) printf("Listing (%d) modules above %s\n", 2246 num_mods, name); 2247 } 2248 2249 strlist.sl_nmods = num_mods; 2250 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * 2251 num_mods); 2252 if (strlist.sl_modlist == NULL) { 2253 Perror0("cannot malloc"); 2254 } else { 2255 if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) { 2256 Perror0("cannot I_LIST for module names"); 2257 } else { 2258 for (i = 0; i < strlist.sl_nmods; i++) { 2259 (void) printf("%d %s\n", i, 2260 strlist.sl_modlist[i].l_name); 2261 } 2262 } 2263 free(strlist.sl_modlist); 2264 } 2265 } 2266 return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr, 2267 orig_arpid)); 2268 } 2269 2270 #define MODINSERT_OP 'i' 2271 #define MODREMOVE_OP 'r' 2272 2273 /* 2274 * To insert a module to the stream of the interface. It is just a 2275 * wrapper. The real function is modop(). 2276 */ 2277 /* ARGSUSED */ 2278 static int 2279 modinsert(char *arg, int64_t param) 2280 { 2281 return (modop(arg, MODINSERT_OP)); 2282 } 2283 2284 /* 2285 * To remove a module from the stream of the interface. It is just a 2286 * wrapper. The real function is modop(). 2287 */ 2288 /* ARGSUSED */ 2289 static int 2290 modremove(char *arg, int64_t param) 2291 { 2292 return (modop(arg, MODREMOVE_OP)); 2293 } 2294 2295 /* 2296 * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that 2297 * the user may have configured autopush to add modules above 2298 * udp), and push the arp module onto the resulting stream. 2299 * This is used to make IP+ARP be able to atomically track the muxid 2300 * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP 2301 * protocol. 2302 */ 2303 static int 2304 open_arp_on_udp(char *udp_dev_name) 2305 { 2306 int fd; 2307 2308 if ((fd = open(udp_dev_name, O_RDWR)) == -1) { 2309 Perror2("open", udp_dev_name); 2310 return (-1); 2311 } 2312 errno = 0; 2313 while (ioctl(fd, I_POP, 0) != -1) 2314 ; 2315 if (errno != EINVAL) { 2316 Perror2("pop", udp_dev_name); 2317 } else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) { 2318 Perror2("arp PUSH", udp_dev_name); 2319 } else { 2320 return (fd); 2321 } 2322 (void) close(fd); 2323 return (-1); 2324 } 2325 2326 /* 2327 * Helper function for mod*() functions. It gets a fd to the lower IP 2328 * stream and I_PUNLINK's the lower stream. It also initializes the 2329 * global variable lifr. 2330 * 2331 * Param: 2332 * int *muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK 2333 * int *muxid_fd: fd to /dev/udp{,6} for LIFMUXID 2334 * int *ipfd_lowstr: fd to the lower IP stream. 2335 * int *arpfd_lowstr: fd to the lower ARP stream. 2336 * 2337 * Return: 2338 * -1 if operation fails, 0 otherwise. 2339 * 2340 * Please see the big block comment above plumb_one_device() 2341 * for the logic of the PLINK/PUNLINK 2342 */ 2343 static int 2344 ip_domux2fd(int *muxfd, int *muxid_fd, int *ipfd_lowstr, int *arpfd_lowstr, 2345 int *orig_arpid) 2346 { 2347 uint64_t flags; 2348 char *udp_dev_name; 2349 2350 *orig_arpid = 0; 2351 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2352 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2353 Perror0_exit("status: SIOCGLIFFLAGS"); 2354 } 2355 flags = lifr.lifr_flags; 2356 if (flags & IFF_IPV4) { 2357 udp_dev_name = UDP_DEV_NAME; 2358 } else if (flags & IFF_IPV6) { 2359 udp_dev_name = UDP6_DEV_NAME; 2360 } else { 2361 return (-1); 2362 } 2363 2364 if ((*muxid_fd = open(udp_dev_name, O_RDWR)) < 0) { 2365 Perror2("open", udp_dev_name); 2366 return (-1); 2367 } 2368 if (ioctl(*muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 2369 Perror2("SIOCGLIFMUXID", udp_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 /* 2378 * Use /dev/udp{,6} as the mux to avoid linkcycles. 2379 */ 2380 if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1) 2381 return (-1); 2382 2383 if (lifr.lifr_arp_muxid != 0) { 2384 if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2385 lifr.lifr_arp_muxid)) < 0) { 2386 if ((errno == EINVAL) && 2387 (flags & (IFF_NOARP | IFF_IPV6))) { 2388 /* 2389 * Some plumbing utilities set the muxid to 2390 * -1 or some invalid value to signify that 2391 * there is no arp stream. Set the muxid to 0 2392 * before trying to unplumb the IP stream. 2393 * IP does not allow the IP stream to be 2394 * unplumbed if it sees a non-null arp muxid, 2395 * for consistency of IP-ARP streams. 2396 */ 2397 *orig_arpid = lifr.lifr_arp_muxid; 2398 lifr.lifr_arp_muxid = 0; 2399 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, 2400 (caddr_t)&lifr); 2401 *arpfd_lowstr = -1; 2402 } else { 2403 Perror0("_I_MUXID2FD"); 2404 return (-1); 2405 } 2406 } else if (ioctl(*muxfd, I_PUNLINK, 2407 lifr.lifr_arp_muxid) < 0) { 2408 Perror2("I_PUNLINK", udp_dev_name); 2409 return (-1); 2410 } 2411 } else { 2412 *arpfd_lowstr = -1; 2413 } 2414 2415 if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2416 lifr.lifr_ip_muxid)) < 0) { 2417 Perror0("_I_MUXID2FD"); 2418 /* Undo any changes we made */ 2419 if (*orig_arpid != 0) { 2420 lifr.lifr_arp_muxid = *orig_arpid; 2421 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 2422 } 2423 return (-1); 2424 } 2425 if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) { 2426 Perror2("I_PUNLINK", udp_dev_name); 2427 /* Undo any changes we made */ 2428 if (*orig_arpid != 0) { 2429 lifr.lifr_arp_muxid = *orig_arpid; 2430 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 2431 } 2432 return (-1); 2433 } 2434 return (0); 2435 } 2436 2437 /* 2438 * Helper function for mod*() functions. It I_PLINK's back the upper and 2439 * lower IP streams. Note that this function must be called after 2440 * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized 2441 * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink() 2442 * must be called in pairs. 2443 * 2444 * Param: 2445 * int muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK 2446 * int muxid_fd: fd to /dev/udp{,6} for LIFMUXID 2447 * int ipfd_lowstr: fd to the lower IP stream. 2448 * int arpfd_lowstr: fd to the lower ARP stream. 2449 * 2450 * Return: 2451 * -1 if operation fails, 0 otherwise. 2452 * 2453 * Please see the big block comment above plumb_one_device() 2454 * for the logic of the PLINK/PUNLINK 2455 */ 2456 static int 2457 ip_plink(int muxfd, int muxid_fd, int ipfd_lowstr, int arpfd_lowstr, 2458 int orig_arpid) 2459 { 2460 int ip_muxid; 2461 2462 ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr); 2463 if (ip_muxid < 0) { 2464 Perror2("I_PLINK", UDP_DEV_NAME); 2465 return (-1); 2466 } 2467 2468 /* 2469 * If there is an arp stream, plink it. If there is no 2470 * arp stream, then it is possible that the plumbing 2471 * utility could have stored any value in the arp_muxid. 2472 * If so, restore it from orig_arpid. 2473 */ 2474 if (arpfd_lowstr != -1) { 2475 if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) { 2476 Perror2("I_PLINK", UDP_DEV_NAME); 2477 return (-1); 2478 } 2479 } else if (orig_arpid != 0) { 2480 /* Undo the changes we did in ip_domux2fd */ 2481 lifr.lifr_arp_muxid = orig_arpid; 2482 lifr.lifr_ip_muxid = ip_muxid; 2483 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 2484 } 2485 2486 (void) close(muxfd); 2487 (void) close(muxid_fd); 2488 return (0); 2489 } 2490 2491 /* 2492 * The real function to perform module insertion/removal. 2493 * 2494 * Param: 2495 * char *arg: the argument string module_name@position 2496 * char op: operation, either MODINSERT_OP or MODREMOVE_OP. 2497 * 2498 * Return: 2499 * Before doing ip_domux2fd(), this function calls exit(1) in case of 2500 * error. After ip_domux2fd() is done, it returns -1 for error, 0 2501 * otherwise. 2502 */ 2503 static int 2504 modop(char *arg, char op) 2505 { 2506 char *pos_p; 2507 int muxfd; 2508 int muxid_fd; 2509 int ipfd_lowstr; /* IP stream (lower stream of mux) to be plinked */ 2510 int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */ 2511 struct strmodconf mod; 2512 char *at_char = "@"; 2513 char *arg_str; 2514 int orig_arpid; 2515 2516 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2517 2518 /* Need to save the original string for -a option. */ 2519 if ((arg_str = malloc(strlen(arg) + 1)) == NULL) { 2520 Perror0("cannot malloc"); 2521 return (-1); 2522 } 2523 (void) strcpy(arg_str, arg); 2524 2525 if (*arg_str == *at_char) { 2526 (void) fprintf(stderr, 2527 "ifconfig: must supply a module name\n"); 2528 exit(1); 2529 } 2530 mod.mod_name = strtok(arg_str, at_char); 2531 if (strlen(mod.mod_name) > FMNAMESZ) { 2532 (void) fprintf(stderr, "ifconfig: module name too long: %s\n", 2533 mod.mod_name); 2534 exit(1); 2535 } 2536 2537 /* 2538 * Need to make sure that the core TCP/IP stack modules are not 2539 * removed. Otherwise, "bad" things can happen. If a module 2540 * is removed and inserted back, it loses its old state. But 2541 * the modules above it still have the old state. E.g. IP assumes 2542 * fast data path while tunnel after re-inserted assumes that it can 2543 * receive M_DATA only in fast data path for which it does not have 2544 * any state. This is a general caveat of _I_REMOVE/_I_INSERT. 2545 */ 2546 if (op == MODREMOVE_OP && 2547 (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 || 2548 strcmp(mod.mod_name, IP_MOD_NAME) == 0 || 2549 strcmp(mod.mod_name, TUN_NAME) == 0 || 2550 strcmp(mod.mod_name, ATUN_NAME) == 0 || 2551 strcmp(mod.mod_name, TUN6TO4_NAME) == 0)) { 2552 (void) fprintf(stderr, "ifconfig: cannot remove %s\n", 2553 mod.mod_name); 2554 exit(1); 2555 } 2556 2557 if ((pos_p = strtok(NULL, at_char)) == NULL) { 2558 (void) fprintf(stderr, "ifconfig: must supply a position\n"); 2559 exit(1); 2560 } 2561 mod.pos = atoi(pos_p); 2562 2563 if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr, 2564 &orig_arpid) < 0) { 2565 free(arg_str); 2566 return (-1); 2567 } 2568 switch (op) { 2569 case MODINSERT_OP: 2570 if (debug > 0) { 2571 (void) printf("Inserting module %s at %d\n", 2572 mod.mod_name, mod.pos); 2573 } 2574 if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) { 2575 Perror2("fail to insert module", mod.mod_name); 2576 } 2577 break; 2578 case MODREMOVE_OP: 2579 if (debug > 0) { 2580 (void) printf("Removing module %s at %d\n", 2581 mod.mod_name, mod.pos); 2582 } 2583 if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) { 2584 Perror2("fail to remove module", mod.mod_name); 2585 } 2586 break; 2587 default: 2588 /* Should never get to here. */ 2589 (void) fprintf(stderr, "Unknown operation\n"); 2590 break; 2591 } 2592 free(arg_str); 2593 return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr, 2594 orig_arpid)); 2595 } 2596 2597 /* 2598 * Set tunnel source address 2599 */ 2600 /* ARGSUSED */ 2601 static int 2602 setiftsrc(char *addr, int64_t param) 2603 { 2604 return (settaddr(addr, icfg_set_tunnel_src)); 2605 } 2606 2607 /* 2608 * Set tunnel destination address 2609 */ 2610 /* ARGSUSED */ 2611 static int 2612 setiftdst(char *addr, int64_t param) 2613 { 2614 return (settaddr(addr, icfg_set_tunnel_dest)); 2615 } 2616 2617 /* 2618 * sets tunnels src|dst address. settaddr() expects the following: 2619 * addr: Points to a printable string containing the address to be 2620 * set, e.g. 129.153.128.110. 2621 * fn: Pointer to a libinetcfg routine that will do the actual work. 2622 * The only valid functions are icfg_set_tunnel_src and 2623 * icfg_set_tunnel_dest. 2624 */ 2625 static int 2626 settaddr(char *addr, 2627 int (*fn)(icfg_handle_t, const struct sockaddr *, socklen_t)) 2628 { 2629 icfg_handle_t handle; 2630 icfg_if_t interface; 2631 struct sockaddr_storage laddr; 2632 int lower; 2633 int rc; 2634 2635 if (strchr(name, ':') != NULL) { 2636 errno = EPERM; 2637 Perror0_exit("Tunnel params on logical interfaces"); 2638 } 2639 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2640 interface.if_protocol = SOCKET_AF(af); 2641 2642 /* Open interface. */ 2643 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 2644 Perror0_exit((char *)icfg_errmsg(rc)); 2645 2646 rc = icfg_get_tunnel_lower(handle, &lower); 2647 if (rc != ICFG_SUCCESS) 2648 Perror0_exit((char *)icfg_errmsg(rc)); 2649 2650 if (lower == AF_INET) { 2651 in_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2652 } else { 2653 in6_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2654 } 2655 2656 /* Call fn to do the real work, and close the interface. */ 2657 rc = (*fn)(handle, (struct sockaddr *)&laddr, 2658 sizeof (struct sockaddr_storage)); 2659 icfg_close(handle); 2660 2661 if (rc != ICFG_SUCCESS) 2662 Perror0_exit((char *)icfg_errmsg(rc)); 2663 2664 return (0); 2665 } 2666 2667 /* Set tunnel encapsulation limit. */ 2668 /* ARGSUSED */ 2669 static int 2670 set_tun_encap_limit(char *arg, int64_t param) 2671 { 2672 short limit; 2673 icfg_if_t interface; 2674 icfg_handle_t handle; 2675 int rc; 2676 2677 if (strchr(name, ':') != NULL) { 2678 errno = EPERM; 2679 Perror0_exit("Tunnel params on logical interfaces"); 2680 } 2681 2682 if ((sscanf(arg, "%hd", &limit) != 1) || (limit < 0) || 2683 (limit > 255)) { 2684 errno = EINVAL; 2685 Perror0_exit("Invalid encapsulation limit"); 2686 } 2687 2688 /* Open interface for configuration. */ 2689 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2690 interface.if_protocol = SOCKET_AF(af); 2691 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2692 Perror0_exit("couldn't open interface"); 2693 2694 rc = icfg_set_tunnel_encaplimit(handle, (int)limit); 2695 icfg_close(handle); 2696 2697 if (rc != ICFG_SUCCESS) 2698 Perror0_exit("Could not configure tunnel encapsulation limit"); 2699 2700 return (0); 2701 } 2702 2703 /* Disable encapsulation limit. */ 2704 /* ARGSUSED */ 2705 static int 2706 clr_tun_encap_limit(char *arg, int64_t param) 2707 { 2708 icfg_if_t interface; 2709 icfg_handle_t handle; 2710 int rc; 2711 2712 if (strchr(name, ':') != NULL) { 2713 errno = EPERM; 2714 Perror0_exit("Tunnel params on logical interfaces"); 2715 } 2716 2717 /* Open interface for configuration. */ 2718 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2719 interface.if_protocol = SOCKET_AF(af); 2720 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2721 Perror0_exit("couldn't open interface"); 2722 2723 rc = icfg_set_tunnel_encaplimit(handle, -1); 2724 icfg_close(handle); 2725 2726 if (rc != ICFG_SUCCESS) 2727 Perror0_exit((char *)icfg_errmsg(rc)); 2728 2729 return (0); 2730 } 2731 2732 /* Set tunnel hop limit. */ 2733 /* ARGSUSED */ 2734 static int 2735 set_tun_hop_limit(char *arg, int64_t param) 2736 { 2737 unsigned short limit; 2738 icfg_if_t interface; 2739 icfg_handle_t handle; 2740 int rc; 2741 2742 if (strchr(name, ':') != NULL) { 2743 errno = EPERM; 2744 Perror0_exit("Tunnel params on logical interfaces"); 2745 } 2746 2747 /* 2748 * Check limit here since it's really only an 8-bit unsigned quantity. 2749 */ 2750 if ((sscanf(arg, "%hu", &limit) != 1) || (limit > 255)) { 2751 errno = EINVAL; 2752 Perror0_exit("Invalid hop limit"); 2753 } 2754 2755 /* Open interface for configuration. */ 2756 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2757 interface.if_protocol = SOCKET_AF(af); 2758 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2759 Perror0_exit("couldn't open interface"); 2760 2761 rc = icfg_set_tunnel_hoplimit(handle, (uint8_t)limit); 2762 icfg_close(handle); 2763 2764 if (rc != ICFG_SUCCESS) 2765 Perror0_exit("Could not configure tunnel hop limit"); 2766 2767 return (0); 2768 } 2769 2770 /* Set zone ID */ 2771 static int 2772 setzone(char *arg, int64_t param) 2773 { 2774 zoneid_t zoneid = GLOBAL_ZONEID; 2775 2776 if (param == NEXTARG) { 2777 /* zone must be active */ 2778 if ((zoneid = getzoneidbyname(arg)) == -1) { 2779 (void) fprintf(stderr, 2780 "ifconfig: unknown zone '%s'\n", arg); 2781 exit(1); 2782 } 2783 } 2784 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2785 lifr.lifr_zoneid = zoneid; 2786 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1) 2787 Perror0_exit("SIOCSLIFZONE"); 2788 return (0); 2789 } 2790 2791 /* Put interface into all zones */ 2792 /* ARGSUSED */ 2793 static int 2794 setallzones(char *arg, int64_t param) 2795 { 2796 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2797 lifr.lifr_zoneid = ALL_ZONES; 2798 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1) 2799 Perror0_exit("SIOCSLIFZONE"); 2800 return (0); 2801 } 2802 2803 /* Set source address to use */ 2804 /* ARGSUSED */ 2805 static int 2806 setifsrc(char *arg, int64_t param) 2807 { 2808 uint_t ifindex = 0; 2809 int rval; 2810 2811 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2812 2813 /* 2814 * Argument can be either an interface name or "none". The latter means 2815 * that any previous selection is cleared. 2816 */ 2817 2818 rval = strcmp(arg, name); 2819 if (rval == 0) { 2820 (void) fprintf(stderr, 2821 "ifconfig: Cannot specify same interface for usesrc" 2822 " group\n"); 2823 exit(1); 2824 } 2825 2826 rval = strcmp(arg, NONE_STR); 2827 if (rval != 0) { 2828 if ((ifindex = if_nametoindex(arg)) == 0) { 2829 (void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ); 2830 Perror0_exit("Could not get interface index"); 2831 } 2832 lifr.lifr_index = ifindex; 2833 } else { 2834 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0) 2835 Perror0_exit("Not a valid usesrc consumer"); 2836 lifr.lifr_index = 0; 2837 } 2838 2839 if (debug) 2840 (void) printf("setifsrc: lifr_name %s, lifr_index %d\n", 2841 lifr.lifr_name, lifr.lifr_index); 2842 2843 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) { 2844 if (rval == 0) 2845 Perror0_exit("Cannot reset usesrc group"); 2846 else 2847 Perror0_exit("Could not set source interface"); 2848 } 2849 2850 return (0); 2851 } 2852 2853 /* 2854 * Print the interface status line associated with `ifname' 2855 */ 2856 static void 2857 ifstatus(const char *ifname) 2858 { 2859 uint64_t flags; 2860 char if_usesrc_name[LIFNAMSIZ]; 2861 char *newbuf; 2862 int n, numifs, rval = 0; 2863 struct lifreq *lifrp; 2864 struct lifsrcof lifs; 2865 2866 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2867 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2868 Perror0_exit("status: SIOCGLIFFLAGS"); 2869 } 2870 flags = lifr.lifr_flags; 2871 2872 /* 2873 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or 2874 * interfaces with IFF_IPV6 set. 2875 */ 2876 if (v4compat) { 2877 flags &= ~IFF_IPV4; 2878 if (flags & IFF_IPV6) 2879 return; 2880 } 2881 2882 (void) printf("%s: ", ifname); 2883 print_flags(flags); 2884 2885 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2886 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 2887 Perror0_exit("status: SIOCGLIFMETRIC"); 2888 } else { 2889 if (lifr.lifr_metric) 2890 (void) printf(" metric %d", lifr.lifr_metric); 2891 } 2892 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 2893 (void) printf(" mtu %d", lifr.lifr_metric); 2894 2895 /* don't print index or zone when in compatibility mode */ 2896 if (!v4compat) { 2897 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 2898 (void) printf(" index %d", lifr.lifr_index); 2899 /* 2900 * Stack instances use GLOBAL_ZONEID for IP data structures 2901 * even in the non-global zone. 2902 */ 2903 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 && 2904 lifr.lifr_zoneid != getzoneid() && 2905 lifr.lifr_zoneid != GLOBAL_ZONEID) { 2906 char zone_name[ZONENAME_MAX]; 2907 2908 if (lifr.lifr_zoneid == ALL_ZONES) { 2909 (void) printf("\n\tall-zones"); 2910 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name, 2911 sizeof (zone_name)) < 0) { 2912 (void) printf("\n\tzone %d", lifr.lifr_zoneid); 2913 } else { 2914 (void) printf("\n\tzone %s", zone_name); 2915 } 2916 } 2917 } 2918 2919 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) { 2920 lifs.lifs_ifindex = lifr.lifr_index; 2921 2922 /* 2923 * Find the number of interfaces that use this interfaces' 2924 * address as a source address 2925 */ 2926 lifs.lifs_buf = NULL; 2927 lifs.lifs_maxlen = 0; 2928 for (;;) { 2929 /* The first pass will give the bufsize we need */ 2930 rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs); 2931 if (rval < 0) { 2932 if (lifs.lifs_buf != NULL) { 2933 free(lifs.lifs_buf); 2934 lifs.lifs_buf = NULL; 2935 } 2936 lifs.lifs_len = 0; 2937 break; 2938 } 2939 if (lifs.lifs_len <= lifs.lifs_maxlen) 2940 break; 2941 /* Use kernel's size + a small margin to avoid loops */ 2942 lifs.lifs_maxlen = lifs.lifs_len + 2943 5 * sizeof (struct lifreq); 2944 /* For the first pass, realloc acts like malloc */ 2945 newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen); 2946 if (newbuf == NULL) { 2947 if (lifs.lifs_buf != NULL) { 2948 free(lifs.lifs_buf); 2949 lifs.lifs_buf = NULL; 2950 } 2951 lifs.lifs_len = 0; 2952 break; 2953 } 2954 lifs.lifs_buf = newbuf; 2955 } 2956 2957 2958 numifs = lifs.lifs_len / sizeof (struct lifreq); 2959 if (numifs > 0) { 2960 lifrp = lifs.lifs_req; 2961 (void) printf("\n\tsrcof"); 2962 for (n = numifs; n > 0; n--, lifrp++) { 2963 (void) printf(" %s", lifrp->lifr_name); 2964 } 2965 } 2966 2967 if (lifs.lifs_buf != NULL) 2968 free(lifs.lifs_buf); 2969 } 2970 2971 /* Find the interface whose source address this interface uses */ 2972 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 2973 if (lifr.lifr_index != 0) { 2974 if (if_indextoname(lifr.lifr_index, 2975 if_usesrc_name) == NULL) { 2976 (void) printf("\n\tusesrc ifIndex %d", 2977 lifr.lifr_index); 2978 } else { 2979 (void) printf("\n\tusesrc %s", if_usesrc_name); 2980 } 2981 } 2982 } 2983 2984 (void) putchar('\n'); 2985 } 2986 2987 2988 /* 2989 * Print the status of the interface. If an address family was 2990 * specified, show it and it only; otherwise, show them all. 2991 */ 2992 static void 2993 status(void) 2994 { 2995 struct afswtch *p = afp; 2996 uint64_t flags; 2997 2998 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2999 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3000 Perror0_exit("status: SIOCGLIFFLAGS"); 3001 } 3002 3003 flags = lifr.lifr_flags; 3004 3005 /* 3006 * Only print the interface status if the address family matches 3007 * the interface family flag. 3008 */ 3009 if (p != NULL) { 3010 if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) || 3011 ((p->af_af == AF_INET) && (flags & IFF_IPV6))) 3012 return; 3013 } 3014 3015 /* 3016 * In V4 compatibility mode, don't print IFF_IPV6 interfaces. 3017 */ 3018 if (v4compat && (flags & IFF_IPV6)) 3019 return; 3020 3021 ifstatus(name); 3022 3023 if (p != NULL) { 3024 (*p->af_status)(1, flags); 3025 } else { 3026 for (p = afs; p->af_name; p++) { 3027 (void) close(s); 3028 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3029 /* set global af for use in p->af_status */ 3030 af = p->af_af; 3031 if (s == -1) { 3032 Perror0_exit("socket"); 3033 } 3034 (*p->af_status)(0, flags); 3035 } 3036 3037 /* 3038 * Historically, 'ether' has been an address family, 3039 * so print it here. 3040 */ 3041 print_ifether(name); 3042 } 3043 } 3044 3045 /* 3046 * Print the status of the interface in a format that can be used to 3047 * reconfigure the interface later. Code stolen from status() above. 3048 */ 3049 /* ARGSUSED */ 3050 static int 3051 configinfo(char *null, int64_t param) 3052 { 3053 struct afswtch *p = afp; 3054 uint64_t flags; 3055 char phydevname[LIFNAMSIZ]; 3056 char if_usesrc_name[LIFNAMSIZ]; 3057 char *cp; 3058 3059 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3060 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3061 Perror0_exit("status: SIOCGLIFFLAGS"); 3062 } 3063 flags = lifr.lifr_flags; 3064 3065 if (debug) { 3066 (void) printf("configinfo: name %s flags 0x%llx af_af %d\n", 3067 name, flags, p != NULL ? p->af_af : -1); 3068 } 3069 3070 /* remove LIF component */ 3071 (void) strncpy(phydevname, name, sizeof (phydevname)); 3072 cp = strchr(phydevname, ':'); 3073 if (cp) { 3074 *cp = 0; 3075 } 3076 phydevname[sizeof (phydevname) - 1] = '\0'; 3077 3078 /* 3079 * if the interface is IPv4 3080 * if we have a IPv6 address family restriction return 3081 * so it won't print 3082 * if we are in IPv4 compatibility mode, clear out IFF_IPV4 3083 * so we don't print it. 3084 */ 3085 if (flags & IFF_IPV4) { 3086 if (p && p->af_af == AF_INET6) 3087 return (-1); 3088 if (v4compat) 3089 flags &= ~IFF_IPV4; 3090 3091 (void) printf("%s inet plumb", phydevname); 3092 } else if (flags & IFF_IPV6) { 3093 /* 3094 * else if the interface is IPv6 3095 * if we have a IPv4 address family restriction return 3096 * or we are in IPv4 compatibiltiy mode, return. 3097 */ 3098 if (p && p->af_af == AF_INET) 3099 return (-1); 3100 if (v4compat) 3101 return (-1); 3102 3103 (void) printf("%s inet6 plumb", phydevname); 3104 } 3105 3106 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3107 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 3108 Perror0_exit("configinfo: SIOCGLIFMETRIC"); 3109 } else { 3110 if (lifr.lifr_metric) 3111 (void) printf(" metric %d ", lifr.lifr_metric); 3112 } 3113 if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) && 3114 ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 3115 (void) printf(" mtu %d", lifr.lifr_metric); 3116 3117 /* don't print index when in compatibility mode */ 3118 if (!v4compat) { 3119 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 3120 (void) printf(" index %d", lifr.lifr_index); 3121 } 3122 3123 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 3124 if (lifr.lifr_index != 0) { 3125 if (if_indextoname(lifr.lifr_index, 3126 if_usesrc_name) != NULL) { 3127 (void) printf(" usesrc %s", if_usesrc_name); 3128 } 3129 } 3130 } 3131 3132 if (p != NULL) { 3133 (*p->af_configinfo)(1, flags); 3134 } else { 3135 for (p = afs; p->af_name; p++) { 3136 (void) close(s); 3137 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3138 /* set global af for use in p->af_configinfo */ 3139 af = p->af_af; 3140 if (s == -1) { 3141 Perror0_exit("socket"); 3142 } 3143 (*p->af_configinfo)(0, flags); 3144 } 3145 } 3146 3147 (void) printf("\n"); 3148 3149 return (0); 3150 } 3151 3152 static void 3153 print_tsec(struct iftun_req *tparams) 3154 { 3155 ipsec_req_t *ipsr; 3156 3157 (void) printf("\ttunnel security settings "); 3158 /* 3159 * Deal with versioning, for now just point 3160 * an ipsec_req_t at ifta_secinfo. If versions 3161 * change, something else will overlay ifta_secinfo. 3162 */ 3163 assert(tparams->ifta_vers == IFTUN_VERSION); 3164 3165 if (tparams->ifta_flags & IFTUN_COMPLEX_SECURITY) { 3166 (void) printf("--> use 'ipsecconf -ln -i %s'", 3167 tparams->ifta_lifr_name); 3168 } else { 3169 ipsr = (ipsec_req_t *)(&tparams->ifta_secinfo); 3170 if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) { 3171 (void) printf("ah (%s) ", 3172 rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH)); 3173 } 3174 if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) { 3175 (void) printf("esp (%s", 3176 rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP)); 3177 (void) printf("/%s)", 3178 rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH)); 3179 } 3180 } 3181 (void) printf("\n"); 3182 } 3183 3184 static void 3185 tun_status(void) 3186 { 3187 icfg_if_t interface; 3188 int rc; 3189 icfg_handle_t handle; 3190 int protocol; 3191 char srcbuf[INET6_ADDRSTRLEN]; 3192 char dstbuf[INET6_ADDRSTRLEN]; 3193 boolean_t tabbed; 3194 uint8_t hoplimit; 3195 int16_t encaplimit; 3196 struct sockaddr_storage taddr; 3197 socklen_t socklen = sizeof (taddr); 3198 3199 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 3200 interface.if_protocol = SOCKET_AF(af); 3201 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 3202 Perror0_exit((char *)icfg_errmsg(rc)); 3203 3204 /* 3205 * only print tunnel info for lun 0. If ioctl fails, assume 3206 * we are not a tunnel 3207 */ 3208 if (strchr(name, ':') != NULL || 3209 icfg_get_tunnel_lower(handle, &protocol) != ICFG_SUCCESS) { 3210 icfg_close(handle); 3211 return; 3212 } 3213 3214 switch (protocol) { 3215 case AF_INET: 3216 (void) printf("\tinet"); 3217 break; 3218 case AF_INET6: 3219 (void) printf("\tinet6"); 3220 break; 3221 default: 3222 Perror0_exit("\ttunnel: Illegal lower stream\n\t"); 3223 break; 3224 } 3225 3226 rc = icfg_get_tunnel_src(handle, (struct sockaddr *)&taddr, &socklen); 3227 if (rc == ICFG_NOT_SET) { 3228 (void) strlcpy(srcbuf, (protocol == AF_INET) ? "0.0.0.0" : 3229 "::", sizeof (srcbuf)); 3230 } else if (rc != ICFG_SUCCESS) { 3231 Perror0_exit((char *)icfg_errmsg(rc)); 3232 } else { 3233 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3234 srcbuf, sizeof (srcbuf)); 3235 if (rc != ICFG_SUCCESS) { 3236 Perror0_exit((char *)icfg_errmsg(rc)); 3237 } 3238 } 3239 3240 (void) printf(" tunnel src %s ", srcbuf); 3241 3242 rc = icfg_get_tunnel_dest(handle, (struct sockaddr *)&taddr, &socklen); 3243 if (rc == ICFG_NOT_SET) { 3244 (void) printf("\n"); 3245 } else { 3246 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3247 dstbuf, sizeof (dstbuf)); 3248 if (rc != ICFG_SUCCESS) { 3249 Perror0_exit((char *)icfg_errmsg(rc)); 3250 } 3251 (void) printf("tunnel dst %s\n", dstbuf); 3252 } 3253 3254 if (handle->ifh_tunnel_params != NULL && 3255 (handle->ifh_tunnel_params->ifta_flags & IFTUN_SECURITY)) 3256 print_tsec(handle->ifh_tunnel_params); 3257 3258 /* 3259 * tabbed indicates tabbed and printed. Use it tell us whether 3260 * to tab and that we've printed something here, so we need a 3261 * newline 3262 */ 3263 tabbed = _B_FALSE; 3264 3265 if (icfg_get_tunnel_hoplimit(handle, &hoplimit) == ICFG_SUCCESS) { 3266 (void) printf("\ttunnel hop limit %d ", hoplimit); 3267 tabbed = _B_TRUE; 3268 } 3269 3270 if ((protocol == AF_INET6) && 3271 (icfg_get_tunnel_encaplimit(handle, &encaplimit) == 3272 ICFG_SUCCESS)) { 3273 if (!tabbed) { 3274 (void) printf("\t"); 3275 tabbed = _B_TRUE; 3276 } 3277 if (encaplimit >= 0) { 3278 (void) printf("tunnel encapsulation limit %d", 3279 encaplimit); 3280 } else { 3281 (void) printf("tunnel encapsulation limit disabled"); 3282 } 3283 } 3284 3285 if (tabbed) 3286 (void) printf("\n"); 3287 3288 icfg_close(handle); 3289 } 3290 3291 static void 3292 in_status(int force, uint64_t flags) 3293 { 3294 struct sockaddr_in *sin, *laddr; 3295 struct sockaddr_in netmask = { AF_INET }; 3296 3297 if (debug) 3298 (void) printf("in_status(%s) flags 0x%llx\n", name, flags); 3299 3300 /* only print status for IPv4 interfaces */ 3301 if (!(flags & IFF_IPV4)) 3302 return; 3303 3304 /* if the interface is a tunnel, print the tunnel status */ 3305 tun_status(); 3306 3307 if (!(flags & IFF_NOLOCAL)) { 3308 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3309 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3310 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3311 errno == ENXIO) { 3312 if (!force) 3313 return; 3314 (void) memset(&lifr.lifr_addr, 0, 3315 sizeof (lifr.lifr_addr)); 3316 } else 3317 Perror0_exit("in_status: SIOCGLIFADDR"); 3318 } 3319 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3320 (void) printf("\tinet %s ", inet_ntoa(sin->sin_addr)); 3321 laddr = sin; 3322 } else { 3323 (void) printf("\tinet "); 3324 } 3325 3326 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3327 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3328 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3329 errno == ENXIO) { 3330 if (!force) 3331 return; 3332 (void) memset(&lifr.lifr_addr, 0, 3333 sizeof (lifr.lifr_addr)); 3334 } else { 3335 Perror0_exit("in_status: SIOCGLIFSUBNET"); 3336 } 3337 } 3338 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3339 if ((flags & IFF_NOLOCAL) || 3340 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3341 (void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr), 3342 lifr.lifr_addrlen); 3343 } 3344 if (sin->sin_family != AF_INET) { 3345 (void) printf("Wrong family: %d\n", sin->sin_family); 3346 } 3347 3348 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3349 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3350 if (errno != EADDRNOTAVAIL) 3351 Perror0_exit("in_status: SIOCGLIFNETMASK"); 3352 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3353 } else 3354 netmask.sin_addr = 3355 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3356 if (flags & IFF_POINTOPOINT) { 3357 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3358 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3359 if (errno == EADDRNOTAVAIL) 3360 (void) memset(&lifr.lifr_addr, 0, 3361 sizeof (lifr.lifr_addr)); 3362 else 3363 Perror0_exit("in_status: SIOCGLIFDSTADDR"); 3364 } 3365 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3366 (void) printf("--> %s ", inet_ntoa(sin->sin_addr)); 3367 } 3368 (void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr)); 3369 if (flags & IFF_BROADCAST) { 3370 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3371 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3372 if (errno == EADDRNOTAVAIL) 3373 (void) memset(&lifr.lifr_addr, 0, 3374 sizeof (lifr.lifr_addr)); 3375 else 3376 Perror0_exit("in_status: SIOCGLIFBRDADDR"); 3377 } 3378 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3379 if (sin->sin_addr.s_addr != 0) { 3380 (void) printf("broadcast %s", 3381 inet_ntoa(sin->sin_addr)); 3382 } 3383 } 3384 /* If there is a groupname, print it for lun 0 alone */ 3385 if (strchr(name, ':') == NULL) { 3386 (void) memset(lifr.lifr_groupname, 0, 3387 sizeof (lifr.lifr_groupname)); 3388 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3389 if (strlen(lifr.lifr_groupname) > 0) { 3390 (void) printf("\n\tgroupname %s", 3391 lifr.lifr_groupname); 3392 } 3393 } 3394 } 3395 (void) putchar('\n'); 3396 } 3397 3398 static void 3399 in6_status(int force, uint64_t flags) 3400 { 3401 char abuf[INET6_ADDRSTRLEN]; 3402 struct sockaddr_in6 *sin6, *laddr6; 3403 3404 if (debug) 3405 (void) printf("in6_status(%s) flags 0x%llx\n", name, flags); 3406 3407 if (!(flags & IFF_IPV6)) 3408 return; 3409 3410 /* if the interface is a tunnel, print the tunnel status */ 3411 tun_status(); 3412 3413 if (!(flags & IFF_NOLOCAL)) { 3414 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3415 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3416 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3417 errno == ENXIO) { 3418 if (!force) 3419 return; 3420 (void) memset(&lifr.lifr_addr, 0, 3421 sizeof (lifr.lifr_addr)); 3422 } else 3423 Perror0_exit("in_status6: SIOCGLIFADDR"); 3424 } 3425 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3426 (void) printf("\tinet6 %s/%d ", 3427 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3428 abuf, sizeof (abuf)), 3429 lifr.lifr_addrlen); 3430 laddr6 = sin6; 3431 } else { 3432 (void) printf("\tinet6 "); 3433 } 3434 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3435 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3436 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3437 errno == ENXIO) { 3438 if (!force) 3439 return; 3440 (void) memset(&lifr.lifr_addr, 0, 3441 sizeof (lifr.lifr_addr)); 3442 } else 3443 Perror0_exit("in_status6: SIOCGLIFSUBNET"); 3444 } 3445 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3446 if ((flags & IFF_NOLOCAL) || 3447 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3448 (void) printf("subnet %s/%d ", 3449 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3450 abuf, sizeof (abuf)), 3451 lifr.lifr_addrlen); 3452 } 3453 if (sin6->sin6_family != AF_INET6) { 3454 (void) printf("Wrong family: %d\n", sin6->sin6_family); 3455 } 3456 if (flags & IFF_POINTOPOINT) { 3457 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3458 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3459 if (errno == EADDRNOTAVAIL) 3460 (void) memset(&lifr.lifr_addr, 0, 3461 sizeof (lifr.lifr_addr)); 3462 else 3463 Perror0_exit("in_status6: SIOCGLIFDSTADDR"); 3464 } 3465 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3466 (void) printf("--> %s ", 3467 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3468 abuf, sizeof (abuf))); 3469 } 3470 if (verbose) { 3471 (void) putchar('\n'); 3472 (void) putchar('\t'); 3473 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3474 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3475 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3476 (void) memset(&lifr.lifr_addr, 0, 3477 sizeof (lifr.lifr_addr)); 3478 else 3479 Perror0_exit("in_status6: SIOCGLIFTOKEN"); 3480 } else { 3481 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3482 (void) printf("token %s/%d ", 3483 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3484 abuf, sizeof (abuf)), 3485 lifr.lifr_addrlen); 3486 } 3487 if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) { 3488 if (errno != EINVAL) { 3489 Perror0_exit("in_status6: SIOCGLIFLNKINFO"); 3490 } 3491 } else { 3492 (void) printf("maxhops %u, reachtime %u ms, " 3493 "reachretrans %u ms, maxmtu %u ", 3494 lifr.lifr_ifinfo.lir_maxhops, 3495 lifr.lifr_ifinfo.lir_reachtime, 3496 lifr.lifr_ifinfo.lir_reachretrans, 3497 lifr.lifr_ifinfo.lir_maxmtu); 3498 } 3499 } 3500 /* If there is a groupname, print it for lun 0 alone */ 3501 if (strchr(name, ':') == NULL) { 3502 (void) memset(lifr.lifr_groupname, 0, 3503 sizeof (lifr.lifr_groupname)); 3504 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3505 if (strlen(lifr.lifr_groupname) > 0) { 3506 (void) printf("\n\tgroupname %s", 3507 lifr.lifr_groupname); 3508 } 3509 } 3510 } 3511 (void) putchar('\n'); 3512 } 3513 3514 static void 3515 in_configinfo(int force, uint64_t flags) 3516 { 3517 struct sockaddr_in *sin, *laddr; 3518 struct sockaddr_in netmask = { AF_INET }; 3519 3520 if (debug) 3521 (void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags); 3522 3523 /* only configinfo info for IPv4 interfaces */ 3524 if (!(flags & IFF_IPV4)) 3525 return; 3526 3527 if (!(flags & IFF_NOLOCAL)) { 3528 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3529 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3530 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3531 errno == ENXIO) { 3532 if (!force) 3533 return; 3534 (void) memset(&lifr.lifr_addr, 0, 3535 sizeof (lifr.lifr_addr)); 3536 } else 3537 Perror0_exit("in_configinfo: SIOCGLIFADDR"); 3538 } 3539 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3540 if (get_lun(name) != 0) { 3541 (void) printf(" addif %s ", inet_ntoa(sin->sin_addr)); 3542 } else { 3543 (void) printf(" set %s ", inet_ntoa(sin->sin_addr)); 3544 } 3545 laddr = sin; 3546 } 3547 3548 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3549 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3550 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3551 errno == ENXIO) { 3552 if (!force) 3553 return; 3554 (void) memset(&lifr.lifr_addr, 0, 3555 sizeof (lifr.lifr_addr)); 3556 } else { 3557 Perror0_exit("in_configinfo: SIOCGLIFSUBNET"); 3558 } 3559 } 3560 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3561 3562 if ((flags & IFF_NOLOCAL) || 3563 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3564 (void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr), 3565 lifr.lifr_addrlen); 3566 } 3567 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3568 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3569 if (errno != EADDRNOTAVAIL) 3570 Perror0_exit("in_configinfo: SIOCGLIFNETMASK"); 3571 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3572 } else 3573 netmask.sin_addr = 3574 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3575 if (flags & IFF_POINTOPOINT) { 3576 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3577 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3578 if (errno == EADDRNOTAVAIL) 3579 (void) memset(&lifr.lifr_addr, 0, 3580 sizeof (lifr.lifr_addr)); 3581 else 3582 Perror0_exit("in_configinfo: SIOCGLIFDSTADDR"); 3583 } 3584 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3585 (void) printf(" destination %s ", inet_ntoa(sin->sin_addr)); 3586 } 3587 (void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr)); 3588 if (flags & IFF_BROADCAST) { 3589 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3590 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3591 if (errno == EADDRNOTAVAIL) 3592 (void) memset(&lifr.lifr_addr, 0, 3593 sizeof (lifr.lifr_addr)); 3594 else 3595 Perror0_exit("in_configinfo: SIOCGLIFBRDADDR"); 3596 } 3597 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3598 if (sin->sin_addr.s_addr != 0) { 3599 (void) printf(" broadcast %s ", 3600 inet_ntoa(sin->sin_addr)); 3601 } 3602 } 3603 3604 /* If there is a groupname, print it for lun 0 alone */ 3605 if (get_lun(name) == 0) { 3606 (void) memset(lifr.lifr_groupname, 0, 3607 sizeof (lifr.lifr_groupname)); 3608 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3609 if (strlen(lifr.lifr_groupname) > 0) { 3610 (void) printf(" group %s ", 3611 lifr.lifr_groupname); 3612 } 3613 } 3614 } 3615 3616 /* Print flags to configure */ 3617 print_config_flags(flags); 3618 3619 /* IFF_NOARP applies to AF_INET only */ 3620 if (flags & IFF_NOARP) { 3621 (void) printf("-arp "); 3622 } 3623 } 3624 3625 static void 3626 in6_configinfo(int force, uint64_t flags) 3627 { 3628 char abuf[INET6_ADDRSTRLEN]; 3629 struct sockaddr_in6 *sin6, *laddr6; 3630 3631 if (debug) 3632 (void) printf("in6_configinfo(%s) flags 0x%llx\n", name, 3633 flags); 3634 3635 if (!(flags & IFF_IPV6)) 3636 return; 3637 3638 if (!(flags & IFF_NOLOCAL)) { 3639 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3640 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3641 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3642 errno == ENXIO) { 3643 if (!force) 3644 return; 3645 (void) memset(&lifr.lifr_addr, 0, 3646 sizeof (lifr.lifr_addr)); 3647 } else 3648 Perror0_exit("in6_configinfo: SIOCGLIFADDR"); 3649 } 3650 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3651 if (get_lun(name) != 0) { 3652 (void) printf(" addif %s/%d ", 3653 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3654 abuf, sizeof (abuf)), 3655 lifr.lifr_addrlen); 3656 } else { 3657 (void) printf(" set %s/%d ", 3658 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3659 abuf, sizeof (abuf)), 3660 lifr.lifr_addrlen); 3661 } 3662 laddr6 = sin6; 3663 } 3664 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3665 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3666 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3667 errno == ENXIO) { 3668 if (!force) 3669 return; 3670 (void) memset(&lifr.lifr_addr, 0, 3671 sizeof (lifr.lifr_addr)); 3672 } else 3673 Perror0_exit("in6_configinfo: SIOCGLIFSUBNET"); 3674 } 3675 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3676 if ((flags & IFF_NOLOCAL) || 3677 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3678 (void) printf(" subnet %s/%d ", 3679 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3680 abuf, sizeof (abuf)), 3681 lifr.lifr_addrlen); 3682 } 3683 3684 if (flags & IFF_POINTOPOINT) { 3685 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3686 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3687 if (errno == EADDRNOTAVAIL) 3688 (void) memset(&lifr.lifr_addr, 0, 3689 sizeof (lifr.lifr_addr)); 3690 else 3691 Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR"); 3692 } 3693 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3694 (void) printf(" destination %s ", 3695 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3696 abuf, sizeof (abuf))); 3697 } 3698 3699 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3700 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3701 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3702 (void) memset(&lifr.lifr_addr, 0, 3703 sizeof (lifr.lifr_addr)); 3704 else 3705 Perror0_exit("in6_configinfo: SIOCGLIFTOKEN"); 3706 } else { 3707 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3708 (void) printf(" token %s/%d ", 3709 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3710 abuf, sizeof (abuf)), 3711 lifr.lifr_addrlen); 3712 } 3713 3714 /* If there is a groupname, print it for lun 0 alone */ 3715 if (get_lun(name) == 0) { 3716 (void) memset(lifr.lifr_groupname, 0, 3717 sizeof (lifr.lifr_groupname)); 3718 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3719 if (strlen(lifr.lifr_groupname) > 0) { 3720 (void) printf(" group %s ", 3721 lifr.lifr_groupname); 3722 } 3723 } 3724 } 3725 3726 /* Print flags to configure */ 3727 print_config_flags(flags); 3728 3729 /* IFF_NONUD applies to AF_INET6 only */ 3730 if (flags & IFF_NONUD) { 3731 (void) printf("-nud "); 3732 } 3733 } 3734 3735 /* ARGSUSED */ 3736 static int 3737 get_lun(char *rsrc) 3738 { 3739 char resource[LIFNAMSIZ]; 3740 char *cp; 3741 3742 (void) strcpy(resource, rsrc); 3743 3744 /* remove LIF component */ 3745 cp = strchr(resource, ':'); 3746 if (cp) { 3747 cp++; 3748 return (atoi(cp)); 3749 } 3750 3751 return (0); 3752 } 3753 3754 /* 3755 * We need to plink both the arp-device stream and the arp-ip-device stream. 3756 * However the muxid is stored only in IP. Plumbing 2 streams individually 3757 * is not atomic, and if ifconfig is killed, the resulting plumbing can 3758 * be inconsistent. For eg. if only the arp stream is plumbed, we have lost 3759 * the muxid, and the half-baked plumbing can neither be unplumbed nor 3760 * replumbed, thus requiring a reboot. To avoid the above the following 3761 * scheme is used. 3762 * 3763 * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams. 3764 * This is done by pushing arp on to the mux (/dev/udp). ARP adds some 3765 * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know 3766 * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs 3767 * the IP stream first, and unplumbs it last. The kernel (IP) does not 3768 * allow IP stream to be unplumbed without unplumbing arp stream. Similarly 3769 * it does not allow arp stream to be plumbed before IP stream is plumbed. 3770 * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic, 3771 * and IP uses the info in the I_PLINK message to get the muxid. 3772 * 3773 * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use 3774 * /dev/udp{,6}. 3775 * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream 3776 * depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp 3777 * or /dev/udp6 for SIOCGLIFMUXID and SIOCSLIFMUXID. 3778 * c. We need to push ARP in order to get the required kernel support for 3779 * atomic plumbings. The actual work done by ARP is explained in arp.c 3780 * Without pushing ARP, we will still be able to plumb/unplumb. But 3781 * it is not atomic, and is supported by the kernel for backward 3782 * compatibility for other utilities like atmifconfig etc. In this case 3783 * the utility must use SIOCSLIFMUXID. 3784 */ 3785 static void 3786 plumb_one_device(int af) 3787 { 3788 int arp_muxid = -1, ip_muxid; 3789 int mux_fd, ip_fd, arp_fd; 3790 int retval; 3791 uint_t ppa; 3792 char *udp_dev_name; 3793 char provider[DLPI_LINKNAME_MAX]; 3794 dlpi_handle_t dh_arp, dh_ip; 3795 3796 /* 3797 * We use DLPI_NOATTACH because the ip module will do the attach 3798 * itself for DLPI style-2 devices. 3799 */ 3800 retval = dlpi_open(name, &dh_ip, DLPI_NOATTACH); 3801 if (retval != DLPI_SUCCESS) 3802 Perrdlpi_exit("cannot open link", name, retval); 3803 3804 if ((retval = dlpi_parselink(name, provider, &ppa)) != DLPI_SUCCESS) 3805 Perrdlpi_exit("dlpi_parselink", name, retval); 3806 3807 if (debug) { 3808 (void) printf("ifconfig: plumb_one_device: provider %s," 3809 " ppa %u\n", provider, ppa); 3810 } 3811 3812 ip_fd = dlpi_fd(dh_ip); 3813 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) 3814 Perror2_exit("I_PUSH", IP_MOD_NAME); 3815 3816 /* 3817 * Push the ARP module onto the interface stream. IP uses 3818 * this to send resolution requests up to ARP. We need to 3819 * do this before the SLIFNAME ioctl is sent down because 3820 * the interface becomes publicly known as soon as the SLIFNAME 3821 * ioctl completes. Thus some other process trying to bring up 3822 * the interface after SLIFNAME but before we have pushed ARP 3823 * could hang. We pop the module again later if it is not needed. 3824 */ 3825 if (ioctl(ip_fd, I_PUSH, ARP_MOD_NAME) == -1) 3826 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3827 3828 /* 3829 * Set IFF_IPV4/IFF_IPV6 flags. 3830 * At this point in time the kernel also allows an 3831 * override of the CANTCHANGE flags. 3832 */ 3833 lifr.lifr_name[0] = '\0'; 3834 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3835 Perror0_exit("plumb_one_device: SIOCGLIFFLAGS"); 3836 3837 /* Set the name string and the IFF_IPV* flag */ 3838 if (af == AF_INET6) { 3839 lifr.lifr_flags |= IFF_IPV6; 3840 lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4); 3841 } else { 3842 lifr.lifr_flags |= IFF_IPV4; 3843 lifr.lifr_flags &= ~IFF_IPV6; 3844 } 3845 3846 /* record the device and module names as interface name */ 3847 lifr.lifr_ppa = ppa; 3848 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3849 3850 /* set the interface name */ 3851 if (ioctl(ip_fd, SIOCSLIFNAME, (char *)&lifr) == -1) { 3852 if (errno != EEXIST) 3853 Perror0_exit("SIOCSLIFNAME for ip"); 3854 /* 3855 * This difference between the way we behave for EEXIST 3856 * and that with other errors exists to preserve legacy 3857 * behaviour. Earlier when foreachinterface() and matcif() 3858 * were doing the duplicate interface name checks, for 3859 * already existing interfaces, inetplumb() returned "0". 3860 * To preserve this behaviour, Perror0() and return are 3861 * called for EEXIST. 3862 */ 3863 Perror0("SIOCSLIFNAME for ip"); 3864 return; 3865 } 3866 3867 /* Get the full set of existing flags for this stream */ 3868 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3869 Perror0_exit("plumb_one_device: SIOCFLIFFLAGS"); 3870 3871 if (debug) { 3872 (void) printf("ifconfig: plumb_one_device: %s got flags:\n", 3873 lifr.lifr_name); 3874 print_flags(lifr.lifr_flags); 3875 (void) putchar('\n'); 3876 } 3877 3878 /* Check if arp is not actually needed */ 3879 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3880 if (ioctl(ip_fd, I_POP, 0) == -1) 3881 Perror2_exit("I_POP", ARP_MOD_NAME); 3882 } 3883 3884 /* 3885 * Open "/dev/udp" for use as a multiplexor to PLINK the 3886 * interface stream under. We use "/dev/udp" instead of "/dev/ip" 3887 * since STREAMS will not let you PLINK a driver under itself, 3888 * and "/dev/ip" is typically the driver at the bottom of 3889 * the stream for tunneling interfaces. 3890 */ 3891 if (af == AF_INET6) 3892 udp_dev_name = UDP6_DEV_NAME; 3893 else 3894 udp_dev_name = UDP_DEV_NAME; 3895 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 3896 exit(EXIT_FAILURE); 3897 3898 /* Check if arp is not needed */ 3899 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3900 /* 3901 * PLINK the interface stream so that ifconfig can exit 3902 * without tearing down the stream. 3903 */ 3904 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 3905 Perror0_exit("I_PLINK for ip"); 3906 (void) close(mux_fd); 3907 return; 3908 } 3909 3910 /* 3911 * This interface does use ARP, so set up a separate stream 3912 * from the interface to ARP. 3913 * 3914 * Note: modules specified by the user are pushed 3915 * only on the interface stream, not on the ARP stream. 3916 */ 3917 if (debug) 3918 (void) printf("ifconfig: plumb_one_device: ifname: %s\n", name); 3919 3920 /* 3921 * We use DLPI_NOATTACH because the arp module will do the attach 3922 * itself for DLPI style-2 devices. 3923 */ 3924 retval = dlpi_open(name, &dh_arp, DLPI_NOATTACH); 3925 if (retval != DLPI_SUCCESS) 3926 Perrdlpi_exit("cannot open link", name, retval); 3927 3928 arp_fd = dlpi_fd(dh_arp); 3929 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) 3930 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3931 3932 /* 3933 * Tell ARP the name and unit number for this interface. 3934 * Note that arp has no support for transparent ioctls. 3935 */ 3936 if (strioctl(arp_fd, SIOCSLIFNAME, (char *)&lifr, 3937 sizeof (lifr)) == -1) { 3938 if (errno != EEXIST) 3939 Perror0_exit("SIOCSLIFNAME for arp"); 3940 Perror0("SIOCSLIFNAME for arp"); 3941 dlpi_close(dh_arp); 3942 dlpi_close(dh_ip); 3943 (void) close(mux_fd); 3944 return; 3945 } 3946 /* 3947 * PLINK the IP and ARP streams so that ifconfig can exit 3948 * without tearing down the stream. 3949 */ 3950 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 3951 Perror0_exit("I_PLINK for ip"); 3952 if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) { 3953 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 3954 Perror0_exit("I_PLINK for arp"); 3955 } 3956 3957 if (debug) 3958 (void) printf("arp muxid = %d\n", arp_muxid); 3959 dlpi_close(dh_ip); 3960 dlpi_close(dh_arp); 3961 (void) close(mux_fd); 3962 } 3963 3964 3965 /* 3966 * If this is a physical interface then remove it. 3967 * If it is a logical interface name use SIOCLIFREMOVEIF to 3968 * remove it. In both cases fail if it doesn't exist. 3969 */ 3970 /* ARGSUSED */ 3971 static int 3972 inetunplumb(char *arg, int64_t param) 3973 { 3974 int ip_muxid, arp_muxid; 3975 int mux_fd; 3976 int muxid_fd; 3977 char *udp_dev_name; 3978 char *strptr; 3979 uint64_t flags; 3980 boolean_t changed_arp_muxid = _B_FALSE; 3981 int save_errno; 3982 3983 strptr = strchr(name, ':'); 3984 if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) { 3985 /* Can't unplumb logical interface zero */ 3986 if (strptr != NULL && strcmp(strptr, ":0") == 0) { 3987 (void) fprintf(stderr, "ifconfig: unplumb:" 3988 " Cannot unplumb %s: Invalid interface\n", name); 3989 exit(1); 3990 } 3991 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3992 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3993 3994 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) 3995 Perror0_exit("unplumb: SIOCLIFREMOVEIF"); 3996 return (0); 3997 } 3998 3999 /* 4000 * We used /dev/udp or udp6 to set up the mux. So we have to use 4001 * the same now for PUNLINK also. 4002 */ 4003 if (afp->af_af == AF_INET6) 4004 udp_dev_name = UDP6_DEV_NAME; 4005 else 4006 udp_dev_name = UDP_DEV_NAME; 4007 4008 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) 4009 exit(EXIT_FAILURE); 4010 4011 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 4012 exit(EXIT_FAILURE); 4013 4014 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4015 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 4016 Perror0_exit("unplumb: SIOCGLIFFLAGS"); 4017 } 4018 flags = lifr.lifr_flags; 4019 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 4020 Perror0_exit("unplumb: SIOCGLIFMUXID"); 4021 } 4022 arp_muxid = lifr.lifr_arp_muxid; 4023 ip_muxid = lifr.lifr_ip_muxid; 4024 /* 4025 * We don't have a good way of knowing whether the arp stream is 4026 * plumbed. We can't rely on IFF_NOARP because someone could 4027 * have turned it off later using "ifconfig xxx -arp". 4028 */ 4029 if (arp_muxid != 0) { 4030 if (debug) 4031 (void) printf("arp_muxid %d\n", arp_muxid); 4032 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 4033 if ((errno == EINVAL) && 4034 (flags & (IFF_NOARP | IFF_IPV6))) { 4035 /* 4036 * Some plumbing utilities set the muxid to 4037 * -1 or some invalid value to signify that 4038 * there is no arp stream. Set the muxid to 0 4039 * before trying to unplumb the IP stream. 4040 * IP does not allow the IP stream to be 4041 * unplumbed if it sees a non-null arp muxid, 4042 * for consistency of IP-ARP streams. 4043 */ 4044 lifr.lifr_arp_muxid = 0; 4045 (void) ioctl(muxid_fd, SIOCSLIFMUXID, 4046 (caddr_t)&lifr); 4047 changed_arp_muxid = _B_TRUE; 4048 } else { 4049 Perror0("I_PUNLINK for arp"); 4050 } 4051 } 4052 } 4053 if (debug) 4054 (void) printf("ip_muxid %d\n", ip_muxid); 4055 4056 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 4057 if (changed_arp_muxid) { 4058 /* 4059 * Some error occurred, and we need to restore 4060 * everything back to what it was. 4061 */ 4062 save_errno = errno; 4063 lifr.lifr_arp_muxid = arp_muxid; 4064 lifr.lifr_ip_muxid = ip_muxid; 4065 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 4066 errno = save_errno; 4067 } 4068 Perror0_exit("I_PUNLINK for ip"); 4069 } 4070 (void) close(mux_fd); 4071 (void) close(muxid_fd); 4072 return (0); 4073 } 4074 4075 /* 4076 * If this is a physical interface then create it unless it is already 4077 * present. If it is a logical interface name use SIOCLIFADDIF to 4078 * create and (and fail it if already exists.) 4079 * As a special case send SIOCLIFADDIF for the loopback interface. This 4080 * is needed since there is no other notion of plumbing the loopback 4081 * interface. 4082 */ 4083 /* ARGSUSED */ 4084 static int 4085 inetplumb(char *arg, int64_t param) 4086 { 4087 char *strptr; 4088 boolean_t islo; 4089 zoneid_t zoneid; 4090 4091 strptr = strchr(name, ':'); 4092 islo = (strcmp(name, LOOPBACK_IF) == 0); 4093 4094 if (strptr != NULL || islo) { 4095 (void) memset(&lifr, 0, sizeof (lifr)); 4096 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4097 if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) { 4098 if (debug) { 4099 (void) fprintf(stderr, 4100 "ifconfig: %s already exists\n", name); 4101 } 4102 return (0); 4103 } 4104 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) { 4105 if (errno == EEXIST) { 4106 if (debug) { 4107 (void) fprintf(stderr, 4108 "ifconfig: %s already exists\n", 4109 name); 4110 } 4111 } else { 4112 Perror2_exit("plumb: SIOCLIFADDIF", name); 4113 } 4114 } 4115 /* 4116 * IP can create the new logical interface on a different 4117 * physical interface in the same IPMP group. Take the new 4118 * interface into account for further operations. 4119 */ 4120 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 4121 return (0); 4122 } 4123 4124 /* 4125 * For global zone, check if the interface is used by a non-global 4126 * zone, note that the non-global zones doesn't need this check, 4127 * because zoneadm has taken care of this when the zone boots. 4128 */ 4129 zoneid = getzoneid(); 4130 if (zoneid == GLOBAL_ZONEID) { 4131 int ret; 4132 4133 zoneid = ALL_ZONES; 4134 ret = zone_check_datalink(&zoneid, name); 4135 if (ret == 0) { 4136 char zonename[ZONENAME_MAX]; 4137 4138 (void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX); 4139 (void) fprintf(stderr, "%s is used by non-global" 4140 "zone: %s\n", name, zonename); 4141 return (1); 4142 } 4143 } 4144 4145 if (debug) 4146 (void) printf("inetplumb: %s af %d\n", name, afp->af_af); 4147 4148 plumb_one_device(afp->af_af); 4149 return (0); 4150 } 4151 4152 void 4153 Perror0(char *cmd) 4154 { 4155 int save_errno; 4156 4157 save_errno = errno; 4158 (void) fprintf(stderr, "ifconfig: "); 4159 errno = save_errno; 4160 switch (errno) { 4161 4162 case ENXIO: 4163 (void) fprintf(stderr, "%s: %s: no such interface\n", 4164 cmd, lifr.lifr_name); 4165 break; 4166 4167 case EPERM: 4168 (void) fprintf(stderr, "%s: %s: permission denied\n", 4169 cmd, lifr.lifr_name); 4170 break; 4171 4172 case EEXIST: 4173 (void) fprintf(stderr, "%s: %s: already exists\n", 4174 cmd, lifr.lifr_name); 4175 break; 4176 4177 default: { 4178 char buf[BUFSIZ]; 4179 4180 (void) snprintf(buf, sizeof (buf), "%s: %s", 4181 cmd, lifr.lifr_name); 4182 perror(buf); 4183 } 4184 } 4185 } 4186 4187 void 4188 Perror0_exit(char *cmd) 4189 { 4190 Perror0(cmd); 4191 exit(1); 4192 /* NOTREACHED */ 4193 } 4194 4195 void 4196 Perror2(char *cmd, char *str) 4197 { 4198 int save_errno; 4199 4200 save_errno = errno; 4201 (void) fprintf(stderr, "ifconfig: "); 4202 errno = save_errno; 4203 switch (errno) { 4204 4205 case ENXIO: 4206 (void) fprintf(stderr, "%s: %s: no such interface\n", 4207 cmd, str); 4208 break; 4209 4210 case EPERM: 4211 (void) fprintf(stderr, "%s: %s: permission denied\n", 4212 cmd, str); 4213 break; 4214 4215 default: { 4216 char buf[BUFSIZ]; 4217 4218 (void) snprintf(buf, sizeof (buf), "%s: %s", cmd, str); 4219 perror(buf); 4220 } 4221 } 4222 } 4223 4224 /* 4225 * Print out error message (Perror2()) and exit 4226 */ 4227 void 4228 Perror2_exit(char *cmd, char *str) 4229 { 4230 Perror2(cmd, str); 4231 exit(1); 4232 /* NOTREACHED */ 4233 } 4234 4235 void 4236 Perrdlpi(const char *cmd, const char *linkname, int err) 4237 { 4238 (void) fprintf(stderr, "ifconfig: %s \"%s\": %s\n", cmd, 4239 linkname, dlpi_strerror(err)); 4240 } 4241 4242 /* 4243 * Print out error message (Perrdlpi()) and exit 4244 */ 4245 void 4246 Perrdlpi_exit(const char *cmd, const char *linkname, int err) 4247 { 4248 Perrdlpi(cmd, linkname, err); 4249 exit(1); 4250 } 4251 4252 /* 4253 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4254 * pass out <n> in *plenp. 4255 * If <n> doesn't parse return BAD_ADDR as *plenp. 4256 * If no /<n> is present return NO_PREFIX as *plenp. 4257 */ 4258 static void 4259 in_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4260 { 4261 /* LINTED: alignment */ 4262 struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 4263 struct hostent *hp; 4264 struct netent *np; 4265 char str[BUFSIZ]; 4266 int error_num; 4267 4268 (void) strncpy(str, s, sizeof (str)); 4269 4270 /* 4271 * Look for '/'<n> is plenp 4272 */ 4273 if (plenp != NULL) { 4274 char *cp; 4275 4276 *plenp = in_getprefixlen(str, _B_TRUE, IP_ABITS); 4277 if (*plenp == BAD_ADDR) 4278 return; 4279 cp = strchr(str, '/'); 4280 if (cp != NULL) 4281 *cp = '\0'; 4282 } else if (strchr(str, '/') != NULL) { 4283 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4284 exit(1); 4285 } 4286 4287 (void) memset(sin, 0, sizeof (*sin)); 4288 4289 /* 4290 * Try to catch attempts to set the broadcast address to all 1's. 4291 */ 4292 if (strcmp(str, "255.255.255.255") == 0 || 4293 (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) { 4294 sin->sin_family = AF_INET; 4295 sin->sin_addr.s_addr = 0xffffffff; 4296 return; 4297 } 4298 4299 hp = getipnodebyname(str, AF_INET, 0, &error_num); 4300 if (hp) { 4301 sin->sin_family = hp->h_addrtype; 4302 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); 4303 freehostent(hp); 4304 return; 4305 } 4306 np = getnetbyname(str); 4307 if (np) { 4308 sin->sin_family = np->n_addrtype; 4309 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 4310 return; 4311 } 4312 if (error_num == TRY_AGAIN) { 4313 (void) fprintf(stderr, "ifconfig: %s: bad address " 4314 "(try again later)\n", s); 4315 } else { 4316 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4317 } 4318 exit(1); 4319 } 4320 4321 /* 4322 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4323 * pass out <n> in *plenp. 4324 * If <n> doesn't parse return BAD_ADDR as *plenp. 4325 * If no /<n> is present return NO_PREFIX as *plenp. 4326 */ 4327 static void 4328 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4329 { 4330 /* LINTED: alignment */ 4331 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr; 4332 struct hostent *hp; 4333 char str[BUFSIZ]; 4334 int error_num; 4335 4336 (void) strncpy(str, s, sizeof (str)); 4337 4338 /* 4339 * Look for '/'<n> is plenp 4340 */ 4341 if (plenp != NULL) { 4342 char *cp; 4343 4344 *plenp = in_getprefixlen(str, _B_TRUE, IPV6_ABITS); 4345 if (*plenp == BAD_ADDR) 4346 return; 4347 cp = strchr(str, '/'); 4348 if (cp != NULL) 4349 *cp = '\0'; 4350 } else if (strchr(str, '/') != NULL) { 4351 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4352 exit(1); 4353 } 4354 4355 (void) memset(sin6, 0, sizeof (*sin6)); 4356 4357 hp = getipnodebyname(str, AF_INET6, 0, &error_num); 4358 if (hp) { 4359 sin6->sin6_family = hp->h_addrtype; 4360 (void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length); 4361 freehostent(hp); 4362 return; 4363 } 4364 if (error_num == TRY_AGAIN) { 4365 (void) fprintf(stderr, "ifconfig: %s: bad address " 4366 "(try again later)\n", s); 4367 } else { 4368 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4369 } 4370 exit(1); 4371 } 4372 4373 /* 4374 * If "slash" is zero this parses the whole string as 4375 * an integer. With "slash" non zero it parses the tail part as an integer. 4376 * 4377 * If it is not a valid integer this returns BAD_ADDR. 4378 * If there is /<n> present this returns NO_PREFIX. 4379 */ 4380 static int 4381 in_getprefixlen(char *addr, boolean_t slash, int max_plen) 4382 { 4383 int prefixlen; 4384 char *str, *end; 4385 4386 if (slash) { 4387 str = strchr(addr, '/'); 4388 if (str == NULL) 4389 return (NO_PREFIX); 4390 str++; 4391 } else 4392 str = addr; 4393 4394 prefixlen = strtol(str, &end, 10); 4395 if (prefixlen < 0) 4396 return (BAD_ADDR); 4397 if (str == end) 4398 return (BAD_ADDR); 4399 if (max_plen != 0 && max_plen < prefixlen) 4400 return (BAD_ADDR); 4401 return (prefixlen); 4402 } 4403 4404 /* 4405 * Convert a prefix length to a mask. 4406 * Returns 1 if ok. 0 otherwise. 4407 * Assumes the mask array is zero'ed by the caller. 4408 */ 4409 static boolean_t 4410 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 4411 { 4412 if (prefixlen < 0 || prefixlen > maxlen) 4413 return (0); 4414 4415 while (prefixlen > 0) { 4416 if (prefixlen >= 8) { 4417 *mask++ = 0xFF; 4418 prefixlen -= 8; 4419 continue; 4420 } 4421 *mask |= 1 << (8 - prefixlen); 4422 prefixlen--; 4423 } 4424 return (1); 4425 } 4426 4427 static void 4428 print_flags(uint64_t flags) 4429 { 4430 boolean_t first = _B_TRUE; 4431 int cnt, i; 4432 4433 (void) printf("flags=%llx", flags); 4434 cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t); 4435 for (i = 0; i < cnt; i++) { 4436 if (flags & if_flags_tbl[i].iff_value) { 4437 if (first) { 4438 (void) printf("<"); 4439 first = _B_FALSE; 4440 } else { 4441 /* 4442 * It has to be here and not with the 4443 * printf below because for the last one, 4444 * we don't want a comma before the ">". 4445 */ 4446 (void) printf(","); 4447 } 4448 (void) printf("%s", if_flags_tbl[i].iff_name); 4449 } 4450 } 4451 if (!first) 4452 (void) printf(">"); 4453 } 4454 4455 static void 4456 print_config_flags(uint64_t flags) 4457 { 4458 int cnt, i; 4459 4460 cnt = sizeof (if_config_cmd_tbl) / sizeof (if_config_cmd_t); 4461 for (i = 0; i < cnt; i++) { 4462 if (flags & if_config_cmd_tbl[i].iff_flag) { 4463 (void) printf("%s ", if_config_cmd_tbl[i].iff_name); 4464 } 4465 } 4466 } 4467 4468 /* 4469 * Use the configured directory lookup mechanism (e.g. files/NIS/NIS+/...) 4470 * to find the network mask. Returns true if we found one to set. 4471 * 4472 * The parameter addr_set controls whether we should get the address of 4473 * the working interface for the netmask query. If addr_set is true, 4474 * we will use the address provided. Otherwise, we will find the working 4475 * interface's address and use it instead. 4476 */ 4477 static boolean_t 4478 in_getmask(struct sockaddr_in *saddr, boolean_t addr_set) 4479 { 4480 struct sockaddr_in ifaddr; 4481 4482 /* 4483 * Read the address from the interface if it is not passed in. 4484 */ 4485 if (!addr_set) { 4486 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4487 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 4488 if (errno != EADDRNOTAVAIL) { 4489 (void) fprintf(stderr, "Need net number for " 4490 "mask\n"); 4491 } 4492 return (_B_FALSE); 4493 } 4494 ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr); 4495 } else { 4496 ifaddr.sin_addr = saddr->sin_addr; 4497 } 4498 if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) { 4499 saddr->sin_family = AF_INET; 4500 return (_B_TRUE); 4501 } 4502 return (_B_FALSE); 4503 } 4504 4505 static int 4506 strioctl(int s, int cmd, char *buf, int buflen) 4507 { 4508 struct strioctl ioc; 4509 4510 (void) memset(&ioc, 0, sizeof (ioc)); 4511 ioc.ic_cmd = cmd; 4512 ioc.ic_timout = 0; 4513 ioc.ic_len = buflen; 4514 ioc.ic_dp = buf; 4515 return (ioctl(s, I_STR, (char *)&ioc)); 4516 } 4517 4518 static void 4519 add_ni(char *name) 4520 { 4521 ni_t **pp; 4522 ni_t *p; 4523 4524 for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) { 4525 if (strcmp(p->ni_name, name) == 0) { 4526 if (debug > 2) 4527 (void) fprintf(stderr, "'%s' is a duplicate\n", 4528 name); 4529 return; 4530 } 4531 } 4532 4533 if (debug > 2) 4534 (void) fprintf(stderr, "adding '%s'\n", 4535 name); 4536 4537 if ((p = malloc(sizeof (ni_t))) == NULL) 4538 return; 4539 4540 (void) strlcpy(p->ni_name, name, sizeof (p->ni_name)); 4541 p->ni_next = NULL; 4542 4543 *pp = p; 4544 num_ni++; 4545 } 4546 4547 /* ARGSUSED2 */ 4548 static int 4549 devfs_entry(di_node_t node, di_minor_t minor, void *arg) 4550 { 4551 char *provider; 4552 char linkname[DLPI_LINKNAME_MAX]; 4553 dlpi_handle_t dh; 4554 4555 provider = di_minor_name(minor); 4556 if (debug > 2) 4557 (void) fprintf(stderr, "provider = %s\n", provider); 4558 4559 if (dlpi_makelink(linkname, provider, 4560 di_instance(node)) != DLPI_SUCCESS) 4561 return (DI_WALK_CONTINUE); 4562 4563 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) 4564 return (DI_WALK_CONTINUE); 4565 4566 if (di_minor_type(minor) == DDM_ALIAS) { 4567 if (debug > 2) 4568 (void) fprintf(stderr, "alias node, using instance\n"); 4569 add_ni(linkname); 4570 } else { 4571 if (debug > 2) 4572 (void) fprintf(stderr, "non-alias node, ignoring\n"); 4573 } 4574 4575 dlpi_close(dh); 4576 return (DI_WALK_CONTINUE); 4577 } 4578 4579 /* 4580 * dhcp-related routines 4581 */ 4582 4583 static int 4584 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[]) 4585 { 4586 dhcp_ipc_request_t *request; 4587 dhcp_ipc_reply_t *reply = NULL; 4588 int timeout = DHCP_IPC_WAIT_DEFAULT; 4589 dhcp_ipc_type_t type = DHCP_START; 4590 int error; 4591 boolean_t is_primary = _B_FALSE; 4592 boolean_t started = _B_FALSE; 4593 4594 for (argv++; --argc > 0; argv++) { 4595 4596 if (strcmp(*argv, "primary") == 0) { 4597 is_primary = _B_TRUE; 4598 continue; 4599 } 4600 4601 if (strcmp(*argv, "wait") == 0) { 4602 if (--argc <= 0) { 4603 usage(); 4604 return (DHCP_EXIT_BADARGS); 4605 } 4606 argv++; 4607 4608 if (strcmp(*argv, "forever") == 0) { 4609 timeout = DHCP_IPC_WAIT_FOREVER; 4610 continue; 4611 } 4612 4613 if (sscanf(*argv, "%d", &timeout) != 1) { 4614 usage(); 4615 return (DHCP_EXIT_BADARGS); 4616 } 4617 4618 if (timeout < 0) { 4619 usage(); 4620 return (DHCP_EXIT_BADARGS); 4621 } 4622 continue; 4623 } 4624 4625 type = dhcp_string_to_request(*argv); 4626 if (type == -1) { 4627 usage(); 4628 return (DHCP_EXIT_BADARGS); 4629 } 4630 } 4631 4632 /* 4633 * Only try to start agent on start or inform; in all other cases it 4634 * has to already be running for anything to make sense. 4635 */ 4636 if (type == DHCP_START || type == DHCP_INFORM) { 4637 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) { 4638 (void) fprintf(stderr, "%s: unable to start %s\n", 4639 caller, DHCP_AGENT_PATH); 4640 return (DHCP_EXIT_FAILURE); 4641 } 4642 started = _B_TRUE; 4643 } 4644 4645 if (is_primary) 4646 type |= DHCP_PRIMARY; 4647 4648 if (af != AF_INET) 4649 type |= DHCP_V6; 4650 4651 request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE); 4652 if (request == NULL) { 4653 (void) fprintf(stderr, "%s: out of memory\n", caller); 4654 return (DHCP_EXIT_SYSTEM); 4655 } 4656 4657 error = dhcp_ipc_make_request(request, &reply, timeout); 4658 if (error != 0) { 4659 free(request); 4660 /* 4661 * Re-map connect error to not under control if we didn't try a 4662 * start operation, as this has to be true and results in a 4663 * clearer message, not to mention preserving compatibility 4664 * with the days when we always started dhcpagent for every 4665 * request. 4666 */ 4667 if (error == DHCP_IPC_E_CONNECT && !started) 4668 error = DHCP_IPC_E_UNKIF; 4669 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4670 dhcp_ipc_strerror(error)); 4671 return (DHCP_EXIT_FAILURE); 4672 } 4673 4674 error = reply->return_code; 4675 if (error != 0) { 4676 free(request); 4677 free(reply); 4678 4679 if (error == DHCP_IPC_E_TIMEOUT && timeout == 0) 4680 return (DHCP_EXIT_SUCCESS); 4681 4682 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4683 dhcp_ipc_strerror(error)); 4684 4685 if (error == DHCP_IPC_E_TIMEOUT) 4686 return (DHCP_EXIT_TIMEOUT); 4687 else 4688 return (DHCP_EXIT_IF_FAILURE); 4689 } 4690 4691 if (DHCP_IPC_CMD(type) == DHCP_STATUS) { 4692 (void) printf("%s", dhcp_status_hdr_string()); 4693 (void) printf("%s", dhcp_status_reply_to_string(reply)); 4694 } 4695 4696 free(request); 4697 free(reply); 4698 return (DHCP_EXIT_SUCCESS); 4699 } 4700 4701 static void 4702 usage(void) 4703 { 4704 (void) fprintf(stderr, 4705 "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n"); 4706 4707 (void) fprintf(stderr, "%s", 4708 "\t[ <addr_family> ]\n" 4709 "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n" 4710 "\t[ set [ <address>][/<prefix_length>] ]" 4711 " [ <address>/<prefix_length>] ]\n" 4712 "\t[ destination <dest_address> ]\n" 4713 "\t[ addif <address>[/<prefix_length>]" 4714 " [ <dest_address> ] ]\n" 4715 "\t[ removeif <address>[/<prefix_length>] ]\n" 4716 "\t[ arp | -arp ]\n" 4717 "\t[ auto-revarp ]\n" 4718 "\t[ broadcast <broad_addr> ]\n" 4719 "\t[ index <if_index> ]\n" 4720 "\t[ metric <n> ] [ mtu <n> ]\n" 4721 "\t[ netmask <mask> ]\n" 4722 "\t[ plumb ] [ unplumb ]\n" 4723 "\t[ preferred | -preferred ]\n" 4724 "\t[ private | -private ]\n" 4725 "\t[ local | -local ]\n" 4726 "\t[ router | -router ]\n" 4727 "\t[ subnet <subnet_address>]\n" 4728 "\t[ trailers | -trailers ]\n" 4729 "\t[ token <address>/<prefix_length> ]\n" 4730 "\t[ tsrc <tunnel_src_address> ]\n" 4731 "\t[ tdst <tunnel_dest_address> ]\n" 4732 "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n" 4733 "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n" 4734 "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n" 4735 "\t[ up ] [ down ]\n" 4736 "\t[ xmit | -xmit ]\n" 4737 "\t[ modlist ]\n" 4738 "\t[ modinsert <module_name@position> ]\n" 4739 "\t[ modremove <module_name@position> ]\n" 4740 "\t[ group <groupname>] | [ group \"\"]\n" 4741 "\t[ deprecated | -deprecated ]\n" 4742 "\t[ standby | -standby ]\n" 4743 "\t[ failover | -failover ]\n" 4744 "\t[ zone <zonename> | -zone ]\n" 4745 "\t[ usesrc <interface> ]\n" 4746 "\t[ all-zones ]\n"); 4747 4748 (void) fprintf(stderr, "or\n"); 4749 (void) fprintf(stderr, 4750 "\tifconfig <interface> | -a[ 4 | 6 | D ] [ u | d ]\n"); 4751 4752 (void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n" 4753 "\t[ wait <time> | forever ]\n\t[ primary ]\n" 4754 "\tstart | drop | ping | release | status | inform\n"); 4755 } 4756