1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 /* 6 * Copyright (c) 1983 Regents of the University of California. 7 * All rights reserved. The Berkeley software License Agreement 8 * specifies the terms and conditions for redistribution. 9 */ 10 11 #pragma ident "%Z%%M% %I% %E% SMI" 12 13 #include "defs.h" 14 #include "strings.h" 15 #include "ifconfig.h" 16 #include <compat.h> 17 #include <libdlpi.h> 18 #include <inet/ip.h> 19 20 #define LOOPBACK_IF "lo0" 21 #define NONE_STR "none" 22 #define ARP_MOD_NAME "arp" 23 #define TUN_NAME "tun" 24 #define ATUN_NAME "atun" 25 #define TUN6TO4_NAME "6to4tun" 26 27 typedef struct if_flags { 28 uint64_t iff_value; 29 char *iff_name; 30 } if_flags_t; 31 32 static if_flags_t if_flags_tbl[] = { 33 { IFF_UP, "UP" }, 34 { IFF_BROADCAST, "BROADCAST" }, 35 { IFF_DEBUG, "DEBUG" }, 36 { IFF_LOOPBACK, "LOOPBACK" }, 37 { IFF_POINTOPOINT, "POINTOPOINT" }, 38 { IFF_NOTRAILERS, "NOTRAILERS" }, 39 { IFF_RUNNING, "RUNNING" }, 40 { IFF_NOARP, "NOARP" }, 41 { IFF_PROMISC, "PROMISC" }, 42 { IFF_ALLMULTI, "ALLMULTI" }, 43 { IFF_INTELLIGENT, "INTELLIGENT" }, 44 { IFF_MULTICAST, "MULTICAST" }, 45 { IFF_MULTI_BCAST, "MULTI_BCAST" }, 46 { IFF_UNNUMBERED, "UNNUMBERED" }, 47 { IFF_DHCPRUNNING, "DHCP" }, 48 { IFF_PRIVATE, "PRIVATE" }, 49 { IFF_NOXMIT, "NOXMIT" }, 50 { IFF_NOLOCAL, "NOLOCAL" }, 51 { IFF_DEPRECATED, "DEPRECATED" }, 52 { IFF_ADDRCONF, "ADDRCONF" }, 53 { IFF_ROUTER, "ROUTER" }, 54 { IFF_NONUD, "NONUD" }, 55 { IFF_ANYCAST, "ANYCAST" }, 56 { IFF_NORTEXCH, "NORTEXCH" }, 57 { IFF_IPV4, "IPv4" }, 58 { IFF_IPV6, "IPv6" }, 59 { IFF_NOFAILOVER, "NOFAILOVER" }, 60 { IFF_FAILED, "FAILED" }, 61 { IFF_STANDBY, "STANDBY" }, 62 { IFF_INACTIVE, "INACTIVE" }, 63 { IFF_OFFLINE, "OFFLINE" }, 64 { IFF_XRESOLV, "XRESOLV" }, 65 { IFF_COS_ENABLED, "CoS" }, 66 { IFF_PREFERRED, "PREFERRED" }, 67 { IFF_TEMPORARY, "TEMPORARY" }, 68 { IFF_FIXEDMTU, "FIXEDMTU" }, 69 { IFF_VIRTUAL, "VIRTUAL" }, 70 { IFF_DUPLICATE, "DUPLICATE" } 71 }; 72 73 static struct lifreq lifr; 74 /* current interface name a particular function is accessing */ 75 static char name[LIFNAMSIZ]; 76 /* foreach interface saved name */ 77 static char origname[LIFNAMSIZ]; 78 static char savedname[LIFNAMSIZ]; /* For addif */ 79 static int setaddr; 80 81 /* 82 * Make sure the algorithm variables hold more than the sizeof an algorithm 83 * in PF_KEY. (For now, more than a uint8_t.) The NO_***_?ALG indicates that 84 * there was no algorithm requested, and in the ipsec_req that service should 85 * be disabled. (E.g. if ah_aalg remains NO_AH_AALG, then AH will be 86 * disabled on that tunnel.) 87 */ 88 #define NO_AH_AALG 256 89 #define NO_ESP_AALG 256 90 #define NO_ESP_EALG 256 91 92 /* 93 * iface_t 94 * used by setifether to create a list of interfaces to mark 95 * down-up when changing the ethernet address of an interface 96 */ 97 typedef struct iface { 98 struct lifreq lifr; 99 struct iface *next; /* pointer to the next list element */ 100 } iface_t; 101 102 static iface_t *logifs = NULL; /* list of logical interfaces */ 103 static iface_t *phyif = NULL; /* physical interface */ 104 105 int s; 106 int af = AF_INET; /* default address family */ 107 int debug = 0; 108 int all = 0; /* setifdhcp() needs to know this */ 109 int verbose = 0; 110 int v4compat = 0; /* Compatible printing format */ 111 112 /* 113 * Function prototypes for command functions. 114 */ 115 static int addif(char *arg, int64_t param); 116 static int inetplumb(char *arg, int64_t param); 117 static int inetunplumb(char *arg, int64_t param); 118 static int removeif(char *arg, int64_t param); 119 static int setdebugflag(char *arg, int64_t param); 120 static int setifaddr(char *arg, int64_t param); 121 static int setifbroadaddr(char *arg, int64_t param); 122 static int setifdstaddr(char *arg, int64_t param); 123 static int setifether(char *arg, int64_t param); 124 static int setifflags(char *arg, int64_t param); 125 static int setifindex(char *arg, int64_t param); 126 static int setifmetric(char *arg, int64_t param); 127 static int setifmtu(char *arg, int64_t param); 128 static int setifnetmask(char *arg, int64_t param); 129 static int setifprefixlen(char *arg, int64_t param); 130 static int setifrevarp(char *arg, int64_t param); 131 static int setifsubnet(char *arg, int64_t param); 132 static int setiftdst(char *arg, int64_t param); 133 static int setiftoken(char *arg, int64_t param); 134 static int setiftsrc(char *arg, int64_t param); 135 static int setverboseflag(char *arg, int64_t param); 136 static int set_tun_ah_alg(char *arg, int64_t param); 137 static int set_tun_esp_auth_alg(char *arg, int64_t param); 138 static int set_tun_esp_encr_alg(char *arg, int64_t param); 139 static int modlist(char *arg, int64_t param); 140 static int modinsert(char *arg, int64_t param); 141 static int modremove(char *arg, int64_t param); 142 static int setifgroupname(char *arg, int64_t param); 143 static int configinfo(char *arg, int64_t param); 144 static void print_config_flags(uint64_t flags); 145 static void print_flags(uint64_t flags); 146 static void print_ifether(char *ifname); 147 static int set_tun_encap_limit(char *arg, int64_t param); 148 static int clr_tun_encap_limit(char *arg, int64_t param); 149 static int set_tun_hop_limit(char *arg, int64_t param); 150 static int setzone(char *arg, int64_t param); 151 static int setallzones(char *arg, int64_t param); 152 static int setifsrc(char *arg, int64_t param); 153 154 /* 155 * Address family specific function prototypes. 156 */ 157 static void in_getaddr(char *s, struct sockaddr *saddr, int *plenp); 158 static void in_status(int force, uint64_t flags); 159 static void in_configinfo(int force, uint64_t flags); 160 static void in6_getaddr(char *s, struct sockaddr *saddr, int *plenp); 161 static void in6_status(int force, uint64_t flags); 162 static void in6_configinfo(int force, uint64_t flags); 163 164 /* 165 * Misc support functions 166 */ 167 static boolean_t ni_entry(const char *, void *); 168 static void foreachinterface(void (*func)(), int argc, char *argv[], 169 int af, int64_t onflags, int64_t offflags, 170 int64_t lifc_flags); 171 static void ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp); 172 static boolean_t in_getmask(struct sockaddr_in *saddr, 173 boolean_t addr_set); 174 static int in_getprefixlen(char *addr, boolean_t slash, int plen); 175 static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 176 uchar_t *mask); 177 static int settaddr(char *, int (*)(icfg_handle_t, 178 const struct sockaddr *, socklen_t)); 179 static void status(void); 180 static void ifstatus(const char *); 181 static void usage(void); 182 static int strioctl(int s, int cmd, char *buf, int buflen); 183 static int setifdhcp(const char *caller, const char *ifname, 184 int argc, char *argv[]); 185 static int ip_domux2fd(int *, int *, int *, int *, int *); 186 static int ip_plink(int, int, int, int, int); 187 static int modop(char *arg, char op); 188 static 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 for the 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 data links for the global zone. 1759 * 1760 * It takes in input a pointer to struct lifconf to receive interfaces 1761 * informations, a **char to hold allocated buffer, and a lifc_flags. 1762 * 1763 * Return values: 1764 * 0 = everything OK 1765 * -1 = problem 1766 */ 1767 static int 1768 find_all_global_interfaces(struct lifconf *lifcp, char **buf, 1769 int64_t lifc_flags) 1770 { 1771 unsigned bufsize; 1772 int n; 1773 ni_t *nip; 1774 struct lifreq *lifrp; 1775 1776 (void) dlpi_walk(ni_entry, NULL, 0); 1777 1778 /* 1779 * Now, translate the linked list into 1780 * a struct lifreq buffer 1781 */ 1782 if (num_ni == 0) { 1783 lifcp->lifc_family = AF_UNSPEC; 1784 lifcp->lifc_flags = lifc_flags; 1785 lifcp->lifc_len = 0; 1786 lifcp->lifc_buf = NULL; 1787 return (0); 1788 } 1789 1790 bufsize = num_ni * sizeof (struct lifreq); 1791 if ((*buf = malloc(bufsize)) == NULL) 1792 Perror0_exit("find_all_interfaces: malloc failed"); 1793 1794 lifcp->lifc_family = AF_UNSPEC; 1795 lifcp->lifc_flags = lifc_flags; 1796 lifcp->lifc_len = bufsize; 1797 lifcp->lifc_buf = *buf; 1798 1799 for (n = 0, lifrp = lifcp->lifc_req; n < num_ni; n++, lifrp++) { 1800 nip = ni_list; 1801 (void) strncpy(lifrp->lifr_name, nip->ni_name, 1802 sizeof (lifr.lifr_name)); 1803 ni_list = nip->ni_next; 1804 free(nip); 1805 } 1806 return (0); 1807 } 1808 1809 /* 1810 * static int find_all_zone_interfaces(struct lifconf *lifcp, char **buf, 1811 * int64_t lifc_flags) 1812 * 1813 * It finds all interfaces for an exclusive-IP zone, that is all the interfaces 1814 * assigned to it. 1815 * 1816 * It takes in input a pointer to struct lifconf to receive interfaces 1817 * informations, a **char to hold allocated buffer, and a lifc_flags. 1818 * 1819 * Return values: 1820 * 0 = everything OK 1821 * -1 = problem 1822 */ 1823 static int 1824 find_all_zone_interfaces(struct lifconf *lifcp, char **buf, int64_t lifc_flags) 1825 { 1826 zoneid_t zoneid; 1827 unsigned bufsize; 1828 char *dlnames, *ptr; 1829 struct lifreq *lifrp; 1830 int num_ni_saved, i; 1831 1832 zoneid = getzoneid(); 1833 1834 num_ni = 0; 1835 if (zone_list_datalink(zoneid, &num_ni, NULL) != 0) 1836 Perror0_exit("find_all_interfaces: list interfaces failed"); 1837 again: 1838 /* this zone doesn't have any data-links */ 1839 if (num_ni == 0) { 1840 lifcp->lifc_family = AF_UNSPEC; 1841 lifcp->lifc_flags = lifc_flags; 1842 lifcp->lifc_len = 0; 1843 lifcp->lifc_buf = NULL; 1844 return (0); 1845 } 1846 1847 dlnames = malloc(num_ni * LIFNAMSIZ); 1848 if (dlnames == NULL) 1849 Perror0_exit("find_all_interfaces: out of memory"); 1850 num_ni_saved = num_ni; 1851 1852 if (zone_list_datalink(zoneid, &num_ni, dlnames) != 0) 1853 Perror0_exit("find_all_interfaces: list interfaces failed"); 1854 1855 if (num_ni_saved < num_ni) { 1856 /* list increased, try again */ 1857 free(dlnames); 1858 goto again; 1859 } 1860 1861 /* this zone doesn't have any data-links now */ 1862 if (num_ni == 0) { 1863 free(dlnames); 1864 lifcp->lifc_family = AF_UNSPEC; 1865 lifcp->lifc_flags = lifc_flags; 1866 lifcp->lifc_len = 0; 1867 lifcp->lifc_buf = NULL; 1868 return (0); 1869 } 1870 1871 bufsize = num_ni * sizeof (struct lifreq); 1872 if ((*buf = malloc(bufsize)) == NULL) { 1873 free(dlnames); 1874 Perror0_exit("find_all_interfaces: malloc failed"); 1875 } 1876 1877 lifrp = (struct lifreq *)*buf; 1878 ptr = dlnames; 1879 for (i = 0; i < num_ni; i++) { 1880 if (strlcpy(lifrp->lifr_name, ptr, LIFNAMSIZ) >= 1881 LIFNAMSIZ) 1882 Perror0_exit("find_all_interfaces: overflow"); 1883 ptr += LIFNAMSIZ; 1884 lifrp++; 1885 } 1886 1887 free(dlnames); 1888 lifcp->lifc_family = AF_UNSPEC; 1889 lifcp->lifc_flags = lifc_flags; 1890 lifcp->lifc_len = bufsize; 1891 lifcp->lifc_buf = *buf; 1892 return (0); 1893 } 1894 1895 /* 1896 * Create the next unused logical interface using the original name 1897 * and assign the address (and mask if '/<n>' is part of the address). 1898 * Use the new logical interface for subsequent subcommands by updating 1899 * the name variable. 1900 * 1901 * This allows syntax like: 1902 * ifconfig le0 addif 109.106.86.130 netmask + up \ 1903 * addif 109.106.86.131 netmask + up 1904 */ 1905 /* ARGSUSED */ 1906 static int 1907 addif(char *str, int64_t param) 1908 { 1909 int prefixlen = 0; 1910 struct sockaddr_storage laddr; 1911 struct sockaddr_storage mask; 1912 1913 (void) strncpy(name, origname, sizeof (name)); 1914 1915 if (strchr(name, ':') != NULL) { 1916 (void) fprintf(stderr, 1917 "ifconfig: addif: bad physical interface name %s\n", 1918 name); 1919 exit(1); 1920 } 1921 1922 /* 1923 * clear so parser will interpret next address as source followed 1924 * by possible dest 1925 */ 1926 setaddr = 0; 1927 (*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen); 1928 1929 switch (prefixlen) { 1930 case NO_PREFIX: 1931 /* Nothing there - ok */ 1932 break; 1933 case BAD_ADDR: 1934 (void) fprintf(stderr, 1935 "ifconfig: Bad prefix length in %s\n", str); 1936 exit(1); 1937 default: 1938 (void) memset(&mask, 0, sizeof (mask)); 1939 mask.ss_family = afp->af_af; 1940 if (afp->af_af == AF_INET6) { 1941 struct sockaddr_in6 *sin6; 1942 sin6 = (struct sockaddr_in6 *)&mask; 1943 if (!in_prefixlentomask(prefixlen, IPV6_ABITS, 1944 (uchar_t *)&sin6->sin6_addr)) { 1945 (void) fprintf(stderr, "ifconfig: " 1946 "Bad prefix length: %d\n", 1947 prefixlen); 1948 exit(1); 1949 } 1950 } else { 1951 struct sockaddr_in *sin; 1952 1953 sin = (struct sockaddr_in *)&mask; 1954 if (!in_prefixlentomask(prefixlen, IP_ABITS, 1955 (uchar_t *)&sin->sin_addr)) { 1956 (void) fprintf(stderr, "ifconfig: " 1957 "Bad prefix length: %d\n", 1958 prefixlen); 1959 exit(1); 1960 } 1961 } 1962 g_netmask_set = G_NETMASK_NIL; 1963 break; 1964 } 1965 1966 /* 1967 * This is a "hack" to get around the problem of SIOCLIFADDIF. The 1968 * problem is that this ioctl does not include the netmask when 1969 * adding a logical interface. This is the same problem described 1970 * in the ifconfig() comments. To get around this problem, we first 1971 * add the logical interface with a 0 address. After that, we set 1972 * the netmask if provided. Finally we set the interface address. 1973 */ 1974 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1975 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 1976 1977 /* Note: no need to do DAD here since the interface isn't up yet. */ 1978 1979 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 1980 Perror0_exit("addif: SIOCLIFADDIF"); 1981 1982 (void) printf("Created new logical interface %s\n", 1983 lifr.lifr_name); 1984 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 1985 1986 /* 1987 * Check and see if any "netmask" command is used and perform the 1988 * necessary operation. 1989 */ 1990 set_mask_lifreq(&lifr, &laddr, &mask); 1991 /* 1992 * Only set the netmask if "netmask" command is used or a prefix is 1993 * provided. 1994 */ 1995 if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) { 1996 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1997 Perror0_exit("addif: SIOCSLIFNETMASK"); 1998 } 1999 2000 /* Finally, we set the interface address. */ 2001 lifr.lifr_addr = laddr; 2002 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 2003 Perror0_exit("SIOCSLIFADDR"); 2004 2005 /* 2006 * let parser know we got a source. 2007 * Next address, if given, should be dest 2008 */ 2009 setaddr++; 2010 return (0); 2011 } 2012 2013 /* 2014 * Remove a logical interface based on its IP address. Unlike addif 2015 * there is no '/<n>' here. 2016 * Verifies that the interface is down before it is removed. 2017 */ 2018 /* ARGSUSED */ 2019 static int 2020 removeif(char *str, int64_t param) 2021 { 2022 struct sockaddr_storage laddr; 2023 2024 if (strchr(name, ':') != NULL) { 2025 (void) fprintf(stderr, 2026 "ifconfig: removeif: bad physical interface name %s\n", 2027 name); 2028 exit(1); 2029 } 2030 2031 (*afp->af_getaddr)(str, &laddr, NULL); 2032 lifr.lifr_addr = laddr; 2033 2034 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2035 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 2036 if (errno == EBUSY) { 2037 /* This can only happen if ipif_id = 0 */ 2038 (void) fprintf(stderr, 2039 "ifconfig: removeif: can't remove interface: %s\n", 2040 name); 2041 exit(1); 2042 } 2043 Perror0_exit("removeif: SIOCLIFREMOVEIF"); 2044 } 2045 return (0); 2046 } 2047 2048 /* 2049 * Set the address token for IPv6. 2050 */ 2051 /* ARGSUSED */ 2052 static int 2053 setiftoken(char *addr, int64_t param) 2054 { 2055 int prefixlen = 0; 2056 struct sockaddr_in6 token; 2057 2058 in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen); 2059 switch (prefixlen) { 2060 case NO_PREFIX: 2061 (void) fprintf(stderr, 2062 "ifconfig: Missing prefix length in subnet %s\n", addr); 2063 exit(1); 2064 /* NOTREACHED */ 2065 case BAD_ADDR: 2066 (void) fprintf(stderr, 2067 "ifconfig: Bad prefix length in %s\n", addr); 2068 exit(1); 2069 default: 2070 break; 2071 } 2072 (void) memcpy(&lifr.lifr_addr, &token, sizeof (token)); 2073 lifr.lifr_addrlen = prefixlen; 2074 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2075 if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0) { 2076 Perror0_exit("setiftoken: SIOCSLIFTOKEN"); 2077 } 2078 return (0); 2079 } 2080 2081 /* 2082 * Return value: 0 on success, -1 on failure. 2083 */ 2084 static int 2085 connect_to_mpathd(int family) 2086 { 2087 int s; 2088 struct sockaddr_storage ss; 2089 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 2090 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 2091 struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 2092 int addrlen; 2093 int ret; 2094 int on; 2095 2096 s = socket(family, SOCK_STREAM, 0); 2097 if (s < 0) { 2098 Perror0_exit("connect_to_mpathd: socket"); 2099 } 2100 (void) bzero((char *)&ss, sizeof (ss)); 2101 ss.ss_family = family; 2102 /* 2103 * Need to bind to a privileged port. For non-root, this 2104 * will fail. in.mpathd verifies that only commands coming 2105 * from privileged ports succeed so that ordinary users 2106 * can't connect and start talking to in.mpathd 2107 */ 2108 on = 1; 2109 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2110 sizeof (on)) < 0) { 2111 Perror0_exit("connect_to_mpathd: setsockopt"); 2112 } 2113 switch (family) { 2114 case AF_INET: 2115 sin->sin_port = 0; 2116 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2117 addrlen = sizeof (struct sockaddr_in); 2118 break; 2119 case AF_INET6: 2120 sin6->sin6_port = 0; 2121 sin6->sin6_addr = loopback_addr; 2122 addrlen = sizeof (struct sockaddr_in6); 2123 break; 2124 } 2125 ret = bind(s, (struct sockaddr *)&ss, addrlen); 2126 if (ret != 0) { 2127 (void) close(s); 2128 return (-1); 2129 } 2130 2131 switch (family) { 2132 case AF_INET: 2133 sin->sin_port = htons(MPATHD_PORT); 2134 break; 2135 case AF_INET6: 2136 sin6->sin6_port = htons(MPATHD_PORT); 2137 break; 2138 } 2139 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2140 (void) close(s); 2141 return (ret); 2142 } 2143 2144 /* ARGSUSED */ 2145 static int 2146 setifgroupname(char *grpname, int64_t param) 2147 { 2148 if (debug) { 2149 (void) printf("Setting groupname %s on interface %s\n", 2150 grpname, name); 2151 } 2152 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2153 (void) strncpy(lifr.lifr_groupname, grpname, 2154 sizeof (lifr.lifr_groupname)); 2155 if (ioctl(s, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) { 2156 Perror0_exit("setifgroupname: SIOCSLIFGROUPNAME"); 2157 } 2158 2159 /* 2160 * If the SUNW_NO_MPATHD environment variable is set then don't 2161 * bother starting up in.mpathd. See PSARC/2002/249 for the 2162 * depressing details on this bit of stupidity. 2163 */ 2164 if (getenv("SUNW_NO_MPATHD") != NULL) { 2165 return (0); 2166 } 2167 2168 /* 2169 * Try to connect to in.mpathd using IPv4. If we succeed, 2170 * we conclude that in.mpathd is running, and quit. 2171 */ 2172 if (connect_to_mpathd(AF_INET) == 0) { 2173 /* connect succeeded, mpathd is already running */ 2174 return (0); 2175 } 2176 /* 2177 * Try to connect to in.mpathd using IPv6. If we succeed, 2178 * we conclude that in.mpathd is running, and quit. 2179 */ 2180 if (connect_to_mpathd(AF_INET6) == 0) { 2181 /* connect succeeded, mpathd is already running */ 2182 return (0); 2183 } 2184 2185 /* 2186 * in.mpathd may not be running. Start it now. If it is already 2187 * running, in.mpathd will take care of handling multiple incarnations 2188 * of itself. ifconfig only tries to optimize performance by not 2189 * starting another incarnation of in.mpathd. 2190 */ 2191 switch (fork()) { 2192 2193 case -1: 2194 Perror0_exit("setifgroupname: fork"); 2195 /* NOTREACHED */ 2196 case 0: 2197 (void) execl(MPATHD_PATH, MPATHD_PATH, NULL); 2198 _exit(1); 2199 /* NOTREACHED */ 2200 default: 2201 return (0); 2202 } 2203 } 2204 2205 2206 /* 2207 * To list all the modules above a given network interface. 2208 */ 2209 /* ARGSUSED */ 2210 static int 2211 modlist(char *null, int64_t param) 2212 { 2213 int muxid_fd; 2214 int muxfd; 2215 int ipfd_lowstr; 2216 int arpfd_lowstr; 2217 int num_mods; 2218 int i; 2219 struct str_list strlist; 2220 int orig_arpid; 2221 2222 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2223 if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr, 2224 &orig_arpid) < 0) { 2225 return (-1); 2226 } 2227 if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) { 2228 Perror0("cannot I_LIST to get the number of modules"); 2229 } else { 2230 if (debug > 0) { 2231 (void) printf("Listing (%d) modules above %s\n", 2232 num_mods, name); 2233 } 2234 2235 strlist.sl_nmods = num_mods; 2236 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * 2237 num_mods); 2238 if (strlist.sl_modlist == NULL) { 2239 Perror0("cannot malloc"); 2240 } else { 2241 if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) { 2242 Perror0("cannot I_LIST for module names"); 2243 } else { 2244 for (i = 0; i < strlist.sl_nmods; i++) { 2245 (void) printf("%d %s\n", i, 2246 strlist.sl_modlist[i].l_name); 2247 } 2248 } 2249 free(strlist.sl_modlist); 2250 } 2251 } 2252 return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr, 2253 orig_arpid)); 2254 } 2255 2256 #define MODINSERT_OP 'i' 2257 #define MODREMOVE_OP 'r' 2258 2259 /* 2260 * To insert a module to the stream of the interface. It is just a 2261 * wrapper. The real function is modop(). 2262 */ 2263 /* ARGSUSED */ 2264 static int 2265 modinsert(char *arg, int64_t param) 2266 { 2267 return (modop(arg, MODINSERT_OP)); 2268 } 2269 2270 /* 2271 * To remove a module from the stream of the interface. It is just a 2272 * wrapper. The real function is modop(). 2273 */ 2274 /* ARGSUSED */ 2275 static int 2276 modremove(char *arg, int64_t param) 2277 { 2278 return (modop(arg, MODREMOVE_OP)); 2279 } 2280 2281 /* 2282 * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that 2283 * the user may have configured autopush to add modules above 2284 * udp), and push the arp module onto the resulting stream. 2285 * This is used to make IP+ARP be able to atomically track the muxid 2286 * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP 2287 * protocol. 2288 */ 2289 static int 2290 open_arp_on_udp(char *udp_dev_name) 2291 { 2292 int fd; 2293 2294 if ((fd = open(udp_dev_name, O_RDWR)) == -1) { 2295 Perror2("open", udp_dev_name); 2296 return (-1); 2297 } 2298 errno = 0; 2299 while (ioctl(fd, I_POP, 0) != -1) 2300 ; 2301 if (errno != EINVAL) { 2302 Perror2("pop", udp_dev_name); 2303 } else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) { 2304 Perror2("arp PUSH", udp_dev_name); 2305 } else { 2306 return (fd); 2307 } 2308 (void) close(fd); 2309 return (-1); 2310 } 2311 2312 /* 2313 * Helper function for mod*() functions. It gets a fd to the lower IP 2314 * stream and I_PUNLINK's the lower stream. It also initializes the 2315 * global variable lifr. 2316 * 2317 * Param: 2318 * int *muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK 2319 * int *muxid_fd: fd to /dev/udp{,6} for LIFMUXID 2320 * int *ipfd_lowstr: fd to the lower IP stream. 2321 * int *arpfd_lowstr: fd to the lower ARP stream. 2322 * 2323 * Return: 2324 * -1 if operation fails, 0 otherwise. 2325 * 2326 * Please see the big block comment above plumb_one_device() 2327 * for the logic of the PLINK/PUNLINK 2328 */ 2329 static int 2330 ip_domux2fd(int *muxfd, int *muxid_fd, int *ipfd_lowstr, int *arpfd_lowstr, 2331 int *orig_arpid) 2332 { 2333 uint64_t flags; 2334 char *udp_dev_name; 2335 2336 *orig_arpid = 0; 2337 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2338 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2339 Perror0_exit("status: SIOCGLIFFLAGS"); 2340 } 2341 flags = lifr.lifr_flags; 2342 if (flags & IFF_IPV4) { 2343 udp_dev_name = UDP_DEV_NAME; 2344 } else if (flags & IFF_IPV6) { 2345 udp_dev_name = UDP6_DEV_NAME; 2346 } else { 2347 return (-1); 2348 } 2349 2350 if ((*muxid_fd = open(udp_dev_name, O_RDWR)) < 0) { 2351 Perror2("open", udp_dev_name); 2352 return (-1); 2353 } 2354 if (ioctl(*muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 2355 Perror2("SIOCGLIFMUXID", udp_dev_name); 2356 return (-1); 2357 } 2358 if (debug > 0) { 2359 (void) printf("ARP_muxid %d IP_muxid %d\n", 2360 lifr.lifr_arp_muxid, lifr.lifr_ip_muxid); 2361 } 2362 2363 /* 2364 * Use /dev/udp{,6} as the mux to avoid linkcycles. 2365 */ 2366 if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1) 2367 return (-1); 2368 2369 if (lifr.lifr_arp_muxid != 0) { 2370 if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2371 lifr.lifr_arp_muxid)) < 0) { 2372 if ((errno == EINVAL) && 2373 (flags & (IFF_NOARP | IFF_IPV6))) { 2374 /* 2375 * Some plumbing utilities set the muxid to 2376 * -1 or some invalid value to signify that 2377 * there is no arp stream. Set the muxid to 0 2378 * before trying to unplumb the IP stream. 2379 * IP does not allow the IP stream to be 2380 * unplumbed if it sees a non-null arp muxid, 2381 * for consistency of IP-ARP streams. 2382 */ 2383 *orig_arpid = lifr.lifr_arp_muxid; 2384 lifr.lifr_arp_muxid = 0; 2385 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, 2386 (caddr_t)&lifr); 2387 *arpfd_lowstr = -1; 2388 } else { 2389 Perror0("_I_MUXID2FD"); 2390 return (-1); 2391 } 2392 } else if (ioctl(*muxfd, I_PUNLINK, 2393 lifr.lifr_arp_muxid) < 0) { 2394 Perror2("I_PUNLINK", udp_dev_name); 2395 return (-1); 2396 } 2397 } else { 2398 *arpfd_lowstr = -1; 2399 } 2400 2401 if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2402 lifr.lifr_ip_muxid)) < 0) { 2403 Perror0("_I_MUXID2FD"); 2404 /* Undo any changes we made */ 2405 if (*orig_arpid != 0) { 2406 lifr.lifr_arp_muxid = *orig_arpid; 2407 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 2408 } 2409 return (-1); 2410 } 2411 if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) { 2412 Perror2("I_PUNLINK", udp_dev_name); 2413 /* Undo any changes we made */ 2414 if (*orig_arpid != 0) { 2415 lifr.lifr_arp_muxid = *orig_arpid; 2416 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 2417 } 2418 return (-1); 2419 } 2420 return (0); 2421 } 2422 2423 /* 2424 * Helper function for mod*() functions. It I_PLINK's back the upper and 2425 * lower IP streams. Note that this function must be called after 2426 * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized 2427 * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink() 2428 * must be called in pairs. 2429 * 2430 * Param: 2431 * int muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK 2432 * int muxid_fd: fd to /dev/udp{,6} for LIFMUXID 2433 * int ipfd_lowstr: fd to the lower IP stream. 2434 * int arpfd_lowstr: fd to the lower ARP stream. 2435 * 2436 * Return: 2437 * -1 if operation fails, 0 otherwise. 2438 * 2439 * Please see the big block comment above plumb_one_device() 2440 * for the logic of the PLINK/PUNLINK 2441 */ 2442 static int 2443 ip_plink(int muxfd, int muxid_fd, int ipfd_lowstr, int arpfd_lowstr, 2444 int orig_arpid) 2445 { 2446 int ip_muxid; 2447 2448 ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr); 2449 if (ip_muxid < 0) { 2450 Perror2("I_PLINK", UDP_DEV_NAME); 2451 return (-1); 2452 } 2453 2454 /* 2455 * If there is an arp stream, plink it. If there is no 2456 * arp stream, then it is possible that the plumbing 2457 * utility could have stored any value in the arp_muxid. 2458 * If so, restore it from orig_arpid. 2459 */ 2460 if (arpfd_lowstr != -1) { 2461 if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) { 2462 Perror2("I_PLINK", UDP_DEV_NAME); 2463 return (-1); 2464 } 2465 } else if (orig_arpid != 0) { 2466 /* Undo the changes we did in ip_domux2fd */ 2467 lifr.lifr_arp_muxid = orig_arpid; 2468 lifr.lifr_ip_muxid = ip_muxid; 2469 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 2470 } 2471 2472 (void) close(muxfd); 2473 (void) close(muxid_fd); 2474 return (0); 2475 } 2476 2477 /* 2478 * The real function to perform module insertion/removal. 2479 * 2480 * Param: 2481 * char *arg: the argument string module_name@position 2482 * char op: operation, either MODINSERT_OP or MODREMOVE_OP. 2483 * 2484 * Return: 2485 * Before doing ip_domux2fd(), this function calls exit(1) in case of 2486 * error. After ip_domux2fd() is done, it returns -1 for error, 0 2487 * otherwise. 2488 */ 2489 static int 2490 modop(char *arg, char op) 2491 { 2492 char *pos_p; 2493 int muxfd; 2494 int muxid_fd; 2495 int ipfd_lowstr; /* IP stream (lower stream of mux) to be plinked */ 2496 int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */ 2497 struct strmodconf mod; 2498 char *at_char = "@"; 2499 char *arg_str; 2500 int orig_arpid; 2501 2502 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2503 2504 /* Need to save the original string for -a option. */ 2505 if ((arg_str = malloc(strlen(arg) + 1)) == NULL) { 2506 Perror0("cannot malloc"); 2507 return (-1); 2508 } 2509 (void) strcpy(arg_str, arg); 2510 2511 if (*arg_str == *at_char) { 2512 (void) fprintf(stderr, 2513 "ifconfig: must supply a module name\n"); 2514 exit(1); 2515 } 2516 mod.mod_name = strtok(arg_str, at_char); 2517 if (strlen(mod.mod_name) > FMNAMESZ) { 2518 (void) fprintf(stderr, "ifconfig: module name too long: %s\n", 2519 mod.mod_name); 2520 exit(1); 2521 } 2522 2523 /* 2524 * Need to make sure that the core TCP/IP stack modules are not 2525 * removed. Otherwise, "bad" things can happen. If a module 2526 * is removed and inserted back, it loses its old state. But 2527 * the modules above it still have the old state. E.g. IP assumes 2528 * fast data path while tunnel after re-inserted assumes that it can 2529 * receive M_DATA only in fast data path for which it does not have 2530 * any state. This is a general caveat of _I_REMOVE/_I_INSERT. 2531 */ 2532 if (op == MODREMOVE_OP && 2533 (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 || 2534 strcmp(mod.mod_name, IP_MOD_NAME) == 0 || 2535 strcmp(mod.mod_name, TUN_NAME) == 0 || 2536 strcmp(mod.mod_name, ATUN_NAME) == 0 || 2537 strcmp(mod.mod_name, TUN6TO4_NAME) == 0)) { 2538 (void) fprintf(stderr, "ifconfig: cannot remove %s\n", 2539 mod.mod_name); 2540 exit(1); 2541 } 2542 2543 if ((pos_p = strtok(NULL, at_char)) == NULL) { 2544 (void) fprintf(stderr, "ifconfig: must supply a position\n"); 2545 exit(1); 2546 } 2547 mod.pos = atoi(pos_p); 2548 2549 if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr, 2550 &orig_arpid) < 0) { 2551 free(arg_str); 2552 return (-1); 2553 } 2554 switch (op) { 2555 case MODINSERT_OP: 2556 if (debug > 0) { 2557 (void) printf("Inserting module %s at %d\n", 2558 mod.mod_name, mod.pos); 2559 } 2560 if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) { 2561 Perror2("fail to insert module", mod.mod_name); 2562 } 2563 break; 2564 case MODREMOVE_OP: 2565 if (debug > 0) { 2566 (void) printf("Removing module %s at %d\n", 2567 mod.mod_name, mod.pos); 2568 } 2569 if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) { 2570 Perror2("fail to remove module", mod.mod_name); 2571 } 2572 break; 2573 default: 2574 /* Should never get to here. */ 2575 (void) fprintf(stderr, "Unknown operation\n"); 2576 break; 2577 } 2578 free(arg_str); 2579 return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr, 2580 orig_arpid)); 2581 } 2582 2583 /* 2584 * Set tunnel source address 2585 */ 2586 /* ARGSUSED */ 2587 static int 2588 setiftsrc(char *addr, int64_t param) 2589 { 2590 return (settaddr(addr, icfg_set_tunnel_src)); 2591 } 2592 2593 /* 2594 * Set tunnel destination address 2595 */ 2596 /* ARGSUSED */ 2597 static int 2598 setiftdst(char *addr, int64_t param) 2599 { 2600 return (settaddr(addr, icfg_set_tunnel_dest)); 2601 } 2602 2603 /* 2604 * sets tunnels src|dst address. settaddr() expects the following: 2605 * addr: Points to a printable string containing the address to be 2606 * set, e.g. 129.153.128.110. 2607 * fn: Pointer to a libinetcfg routine that will do the actual work. 2608 * The only valid functions are icfg_set_tunnel_src and 2609 * icfg_set_tunnel_dest. 2610 */ 2611 static int 2612 settaddr(char *addr, 2613 int (*fn)(icfg_handle_t, const struct sockaddr *, socklen_t)) 2614 { 2615 icfg_handle_t handle; 2616 icfg_if_t interface; 2617 struct sockaddr_storage laddr; 2618 int lower; 2619 int rc; 2620 2621 if (strchr(name, ':') != NULL) { 2622 errno = EPERM; 2623 Perror0_exit("Tunnel params on logical interfaces"); 2624 } 2625 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2626 interface.if_protocol = SOCKET_AF(af); 2627 2628 /* Open interface. */ 2629 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 2630 Perror0_exit((char *)icfg_errmsg(rc)); 2631 2632 rc = icfg_get_tunnel_lower(handle, &lower); 2633 if (rc != ICFG_SUCCESS) 2634 Perror0_exit((char *)icfg_errmsg(rc)); 2635 2636 if (lower == AF_INET) { 2637 in_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2638 } else { 2639 in6_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2640 } 2641 2642 /* Call fn to do the real work, and close the interface. */ 2643 rc = (*fn)(handle, (struct sockaddr *)&laddr, 2644 sizeof (struct sockaddr_storage)); 2645 icfg_close(handle); 2646 2647 if (rc != ICFG_SUCCESS) 2648 Perror0_exit((char *)icfg_errmsg(rc)); 2649 2650 return (0); 2651 } 2652 2653 /* Set tunnel encapsulation limit. */ 2654 /* ARGSUSED */ 2655 static int 2656 set_tun_encap_limit(char *arg, int64_t param) 2657 { 2658 short limit; 2659 icfg_if_t interface; 2660 icfg_handle_t handle; 2661 int rc; 2662 2663 if (strchr(name, ':') != NULL) { 2664 errno = EPERM; 2665 Perror0_exit("Tunnel params on logical interfaces"); 2666 } 2667 2668 if ((sscanf(arg, "%hd", &limit) != 1) || (limit < 0) || 2669 (limit > 255)) { 2670 errno = EINVAL; 2671 Perror0_exit("Invalid encapsulation limit"); 2672 } 2673 2674 /* Open interface for configuration. */ 2675 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2676 interface.if_protocol = SOCKET_AF(af); 2677 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2678 Perror0_exit("couldn't open interface"); 2679 2680 rc = icfg_set_tunnel_encaplimit(handle, (int)limit); 2681 icfg_close(handle); 2682 2683 if (rc != ICFG_SUCCESS) 2684 Perror0_exit("Could not configure tunnel encapsulation limit"); 2685 2686 return (0); 2687 } 2688 2689 /* Disable encapsulation limit. */ 2690 /* ARGSUSED */ 2691 static int 2692 clr_tun_encap_limit(char *arg, int64_t param) 2693 { 2694 icfg_if_t interface; 2695 icfg_handle_t handle; 2696 int rc; 2697 2698 if (strchr(name, ':') != NULL) { 2699 errno = EPERM; 2700 Perror0_exit("Tunnel params on logical interfaces"); 2701 } 2702 2703 /* Open interface for configuration. */ 2704 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2705 interface.if_protocol = SOCKET_AF(af); 2706 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2707 Perror0_exit("couldn't open interface"); 2708 2709 rc = icfg_set_tunnel_encaplimit(handle, -1); 2710 icfg_close(handle); 2711 2712 if (rc != ICFG_SUCCESS) 2713 Perror0_exit((char *)icfg_errmsg(rc)); 2714 2715 return (0); 2716 } 2717 2718 /* Set tunnel hop limit. */ 2719 /* ARGSUSED */ 2720 static int 2721 set_tun_hop_limit(char *arg, int64_t param) 2722 { 2723 unsigned short limit; 2724 icfg_if_t interface; 2725 icfg_handle_t handle; 2726 int rc; 2727 2728 if (strchr(name, ':') != NULL) { 2729 errno = EPERM; 2730 Perror0_exit("Tunnel params on logical interfaces"); 2731 } 2732 2733 /* 2734 * Check limit here since it's really only an 8-bit unsigned quantity. 2735 */ 2736 if ((sscanf(arg, "%hu", &limit) != 1) || (limit > 255)) { 2737 errno = EINVAL; 2738 Perror0_exit("Invalid hop limit"); 2739 } 2740 2741 /* Open interface for configuration. */ 2742 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2743 interface.if_protocol = SOCKET_AF(af); 2744 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2745 Perror0_exit("couldn't open interface"); 2746 2747 rc = icfg_set_tunnel_hoplimit(handle, (uint8_t)limit); 2748 icfg_close(handle); 2749 2750 if (rc != ICFG_SUCCESS) 2751 Perror0_exit("Could not configure tunnel hop limit"); 2752 2753 return (0); 2754 } 2755 2756 /* Set zone ID */ 2757 static int 2758 setzone(char *arg, int64_t param) 2759 { 2760 zoneid_t zoneid = GLOBAL_ZONEID; 2761 2762 if (param == NEXTARG) { 2763 /* zone must be active */ 2764 if ((zoneid = getzoneidbyname(arg)) == -1) { 2765 (void) fprintf(stderr, 2766 "ifconfig: unknown zone '%s'\n", arg); 2767 exit(1); 2768 } 2769 } 2770 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2771 lifr.lifr_zoneid = zoneid; 2772 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1) 2773 Perror0_exit("SIOCSLIFZONE"); 2774 return (0); 2775 } 2776 2777 /* Put interface into all zones */ 2778 /* ARGSUSED */ 2779 static int 2780 setallzones(char *arg, int64_t param) 2781 { 2782 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2783 lifr.lifr_zoneid = ALL_ZONES; 2784 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1) 2785 Perror0_exit("SIOCSLIFZONE"); 2786 return (0); 2787 } 2788 2789 /* Set source address to use */ 2790 /* ARGSUSED */ 2791 static int 2792 setifsrc(char *arg, int64_t param) 2793 { 2794 uint_t ifindex = 0; 2795 int rval; 2796 2797 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2798 2799 /* 2800 * Argument can be either an interface name or "none". The latter means 2801 * that any previous selection is cleared. 2802 */ 2803 2804 rval = strcmp(arg, name); 2805 if (rval == 0) { 2806 (void) fprintf(stderr, 2807 "ifconfig: Cannot specify same interface for usesrc" 2808 " group\n"); 2809 exit(1); 2810 } 2811 2812 rval = strcmp(arg, NONE_STR); 2813 if (rval != 0) { 2814 if ((ifindex = if_nametoindex(arg)) == 0) { 2815 (void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ); 2816 Perror0_exit("Could not get interface index"); 2817 } 2818 lifr.lifr_index = ifindex; 2819 } else { 2820 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0) 2821 Perror0_exit("Not a valid usesrc consumer"); 2822 lifr.lifr_index = 0; 2823 } 2824 2825 if (debug) 2826 (void) printf("setifsrc: lifr_name %s, lifr_index %d\n", 2827 lifr.lifr_name, lifr.lifr_index); 2828 2829 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) { 2830 if (rval == 0) 2831 Perror0_exit("Cannot reset usesrc group"); 2832 else 2833 Perror0_exit("Could not set source interface"); 2834 } 2835 2836 return (0); 2837 } 2838 2839 /* 2840 * Print the interface status line associated with `ifname' 2841 */ 2842 static void 2843 ifstatus(const char *ifname) 2844 { 2845 uint64_t flags; 2846 char if_usesrc_name[LIFNAMSIZ]; 2847 char *newbuf; 2848 int n, numifs, rval = 0; 2849 struct lifreq *lifrp; 2850 struct lifsrcof lifs; 2851 2852 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2853 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2854 Perror0_exit("status: SIOCGLIFFLAGS"); 2855 } 2856 flags = lifr.lifr_flags; 2857 2858 /* 2859 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or 2860 * interfaces with IFF_IPV6 set. 2861 */ 2862 if (v4compat) { 2863 flags &= ~IFF_IPV4; 2864 if (flags & IFF_IPV6) 2865 return; 2866 } 2867 2868 (void) printf("%s: ", ifname); 2869 print_flags(flags); 2870 2871 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2872 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 2873 Perror0_exit("status: SIOCGLIFMETRIC"); 2874 } else { 2875 if (lifr.lifr_metric) 2876 (void) printf(" metric %d", lifr.lifr_metric); 2877 } 2878 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 2879 (void) printf(" mtu %d", lifr.lifr_metric); 2880 2881 /* don't print index or zone when in compatibility mode */ 2882 if (!v4compat) { 2883 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 2884 (void) printf(" index %d", lifr.lifr_index); 2885 /* 2886 * Stack instances use GLOBAL_ZONEID for IP data structures 2887 * even in the non-global zone. 2888 */ 2889 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 && 2890 lifr.lifr_zoneid != getzoneid() && 2891 lifr.lifr_zoneid != GLOBAL_ZONEID) { 2892 char zone_name[ZONENAME_MAX]; 2893 2894 if (lifr.lifr_zoneid == ALL_ZONES) { 2895 (void) printf("\n\tall-zones"); 2896 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name, 2897 sizeof (zone_name)) < 0) { 2898 (void) printf("\n\tzone %d", lifr.lifr_zoneid); 2899 } else { 2900 (void) printf("\n\tzone %s", zone_name); 2901 } 2902 } 2903 } 2904 2905 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) { 2906 lifs.lifs_ifindex = lifr.lifr_index; 2907 2908 /* 2909 * Find the number of interfaces that use this interfaces' 2910 * address as a source address 2911 */ 2912 lifs.lifs_buf = NULL; 2913 lifs.lifs_maxlen = 0; 2914 for (;;) { 2915 /* The first pass will give the bufsize we need */ 2916 rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs); 2917 if (rval < 0) { 2918 if (lifs.lifs_buf != NULL) { 2919 free(lifs.lifs_buf); 2920 lifs.lifs_buf = NULL; 2921 } 2922 lifs.lifs_len = 0; 2923 break; 2924 } 2925 if (lifs.lifs_len <= lifs.lifs_maxlen) 2926 break; 2927 /* Use kernel's size + a small margin to avoid loops */ 2928 lifs.lifs_maxlen = lifs.lifs_len + 2929 5 * sizeof (struct lifreq); 2930 /* For the first pass, realloc acts like malloc */ 2931 newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen); 2932 if (newbuf == NULL) { 2933 if (lifs.lifs_buf != NULL) { 2934 free(lifs.lifs_buf); 2935 lifs.lifs_buf = NULL; 2936 } 2937 lifs.lifs_len = 0; 2938 break; 2939 } 2940 lifs.lifs_buf = newbuf; 2941 } 2942 2943 2944 numifs = lifs.lifs_len / sizeof (struct lifreq); 2945 if (numifs > 0) { 2946 lifrp = lifs.lifs_req; 2947 (void) printf("\n\tsrcof"); 2948 for (n = numifs; n > 0; n--, lifrp++) { 2949 (void) printf(" %s", lifrp->lifr_name); 2950 } 2951 } 2952 2953 if (lifs.lifs_buf != NULL) 2954 free(lifs.lifs_buf); 2955 } 2956 2957 /* Find the interface whose source address this interface uses */ 2958 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 2959 if (lifr.lifr_index != 0) { 2960 if (if_indextoname(lifr.lifr_index, 2961 if_usesrc_name) == NULL) { 2962 (void) printf("\n\tusesrc ifIndex %d", 2963 lifr.lifr_index); 2964 } else { 2965 (void) printf("\n\tusesrc %s", if_usesrc_name); 2966 } 2967 } 2968 } 2969 2970 (void) putchar('\n'); 2971 } 2972 2973 2974 /* 2975 * Print the status of the interface. If an address family was 2976 * specified, show it and it only; otherwise, show them all. 2977 */ 2978 static void 2979 status(void) 2980 { 2981 struct afswtch *p = afp; 2982 uint64_t flags; 2983 2984 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2985 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2986 Perror0_exit("status: SIOCGLIFFLAGS"); 2987 } 2988 2989 flags = lifr.lifr_flags; 2990 2991 /* 2992 * Only print the interface status if the address family matches 2993 * the interface family flag. 2994 */ 2995 if (p != NULL) { 2996 if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) || 2997 ((p->af_af == AF_INET) && (flags & IFF_IPV6))) 2998 return; 2999 } 3000 3001 /* 3002 * In V4 compatibility mode, don't print IFF_IPV6 interfaces. 3003 */ 3004 if (v4compat && (flags & IFF_IPV6)) 3005 return; 3006 3007 ifstatus(name); 3008 3009 if (p != NULL) { 3010 (*p->af_status)(1, flags); 3011 } else { 3012 for (p = afs; p->af_name; p++) { 3013 (void) close(s); 3014 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3015 /* set global af for use in p->af_status */ 3016 af = p->af_af; 3017 if (s == -1) { 3018 Perror0_exit("socket"); 3019 } 3020 (*p->af_status)(0, flags); 3021 } 3022 3023 /* 3024 * Historically, 'ether' has been an address family, 3025 * so print it here. 3026 */ 3027 print_ifether(name); 3028 } 3029 } 3030 3031 /* 3032 * Print the status of the interface in a format that can be used to 3033 * reconfigure the interface later. Code stolen from status() above. 3034 */ 3035 /* ARGSUSED */ 3036 static int 3037 configinfo(char *null, int64_t param) 3038 { 3039 struct afswtch *p = afp; 3040 uint64_t flags; 3041 char phydevname[LIFNAMSIZ]; 3042 char if_usesrc_name[LIFNAMSIZ]; 3043 char *cp; 3044 3045 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3046 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3047 Perror0_exit("status: SIOCGLIFFLAGS"); 3048 } 3049 flags = lifr.lifr_flags; 3050 3051 if (debug) { 3052 (void) printf("configinfo: name %s flags 0x%llx af_af %d\n", 3053 name, flags, p != NULL ? p->af_af : -1); 3054 } 3055 3056 /* remove LIF component */ 3057 (void) strncpy(phydevname, name, sizeof (phydevname)); 3058 cp = strchr(phydevname, ':'); 3059 if (cp) { 3060 *cp = 0; 3061 } 3062 phydevname[sizeof (phydevname) - 1] = '\0'; 3063 3064 /* 3065 * if the interface is IPv4 3066 * if we have a IPv6 address family restriction return 3067 * so it won't print 3068 * if we are in IPv4 compatibility mode, clear out IFF_IPV4 3069 * so we don't print it. 3070 */ 3071 if (flags & IFF_IPV4) { 3072 if (p && p->af_af == AF_INET6) 3073 return (-1); 3074 if (v4compat) 3075 flags &= ~IFF_IPV4; 3076 3077 (void) printf("%s inet plumb", phydevname); 3078 } else if (flags & IFF_IPV6) { 3079 /* 3080 * else if the interface is IPv6 3081 * if we have a IPv4 address family restriction return 3082 * or we are in IPv4 compatibiltiy mode, return. 3083 */ 3084 if (p && p->af_af == AF_INET) 3085 return (-1); 3086 if (v4compat) 3087 return (-1); 3088 3089 (void) printf("%s inet6 plumb", phydevname); 3090 } 3091 3092 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3093 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 3094 Perror0_exit("configinfo: SIOCGLIFMETRIC"); 3095 } else { 3096 if (lifr.lifr_metric) 3097 (void) printf(" metric %d ", lifr.lifr_metric); 3098 } 3099 if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) && 3100 ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 3101 (void) printf(" mtu %d", lifr.lifr_metric); 3102 3103 /* don't print index when in compatibility mode */ 3104 if (!v4compat) { 3105 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 3106 (void) printf(" index %d", lifr.lifr_index); 3107 } 3108 3109 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 3110 if (lifr.lifr_index != 0) { 3111 if (if_indextoname(lifr.lifr_index, 3112 if_usesrc_name) != NULL) { 3113 (void) printf(" usesrc %s", if_usesrc_name); 3114 } 3115 } 3116 } 3117 3118 if (p != NULL) { 3119 (*p->af_configinfo)(1, flags); 3120 } else { 3121 for (p = afs; p->af_name; p++) { 3122 (void) close(s); 3123 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3124 /* set global af for use in p->af_configinfo */ 3125 af = p->af_af; 3126 if (s == -1) { 3127 Perror0_exit("socket"); 3128 } 3129 (*p->af_configinfo)(0, flags); 3130 } 3131 } 3132 3133 (void) printf("\n"); 3134 3135 return (0); 3136 } 3137 3138 static void 3139 print_tsec(struct iftun_req *tparams) 3140 { 3141 ipsec_req_t *ipsr; 3142 3143 (void) printf("\ttunnel security settings "); 3144 /* 3145 * Deal with versioning, for now just point 3146 * an ipsec_req_t at ifta_secinfo. If versions 3147 * change, something else will overlay ifta_secinfo. 3148 */ 3149 assert(tparams->ifta_vers == IFTUN_VERSION); 3150 3151 if (tparams->ifta_flags & IFTUN_COMPLEX_SECURITY) { 3152 (void) printf("--> use 'ipsecconf -ln -i %s'", 3153 tparams->ifta_lifr_name); 3154 } else { 3155 ipsr = (ipsec_req_t *)(&tparams->ifta_secinfo); 3156 if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) { 3157 (void) printf("ah (%s) ", 3158 rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH)); 3159 } 3160 if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) { 3161 (void) printf("esp (%s", 3162 rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP)); 3163 (void) printf("/%s)", 3164 rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH)); 3165 } 3166 } 3167 (void) printf("\n"); 3168 } 3169 3170 static void 3171 tun_status(void) 3172 { 3173 icfg_if_t interface; 3174 int rc; 3175 icfg_handle_t handle; 3176 int protocol; 3177 char srcbuf[INET6_ADDRSTRLEN]; 3178 char dstbuf[INET6_ADDRSTRLEN]; 3179 boolean_t tabbed; 3180 uint8_t hoplimit; 3181 int16_t encaplimit; 3182 struct sockaddr_storage taddr; 3183 socklen_t socklen = sizeof (taddr); 3184 3185 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 3186 interface.if_protocol = SOCKET_AF(af); 3187 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 3188 Perror0_exit((char *)icfg_errmsg(rc)); 3189 3190 /* 3191 * only print tunnel info for lun 0. If ioctl fails, assume 3192 * we are not a tunnel 3193 */ 3194 if (strchr(name, ':') != NULL || 3195 icfg_get_tunnel_lower(handle, &protocol) != ICFG_SUCCESS) { 3196 icfg_close(handle); 3197 return; 3198 } 3199 3200 switch (protocol) { 3201 case AF_INET: 3202 (void) printf("\tinet"); 3203 break; 3204 case AF_INET6: 3205 (void) printf("\tinet6"); 3206 break; 3207 default: 3208 Perror0_exit("\ttunnel: Illegal lower stream\n\t"); 3209 break; 3210 } 3211 3212 rc = icfg_get_tunnel_src(handle, (struct sockaddr *)&taddr, &socklen); 3213 if (rc == ICFG_NOT_SET) { 3214 (void) strlcpy(srcbuf, (protocol == AF_INET) ? "0.0.0.0" : 3215 "::", sizeof (srcbuf)); 3216 } else if (rc != ICFG_SUCCESS) { 3217 Perror0_exit((char *)icfg_errmsg(rc)); 3218 } else { 3219 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3220 srcbuf, sizeof (srcbuf)); 3221 if (rc != ICFG_SUCCESS) { 3222 Perror0_exit((char *)icfg_errmsg(rc)); 3223 } 3224 } 3225 3226 (void) printf(" tunnel src %s ", srcbuf); 3227 3228 rc = icfg_get_tunnel_dest(handle, (struct sockaddr *)&taddr, &socklen); 3229 if (rc == ICFG_NOT_SET) { 3230 (void) printf("\n"); 3231 } else { 3232 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3233 dstbuf, sizeof (dstbuf)); 3234 if (rc != ICFG_SUCCESS) { 3235 Perror0_exit((char *)icfg_errmsg(rc)); 3236 } 3237 (void) printf("tunnel dst %s\n", dstbuf); 3238 } 3239 3240 if (handle->ifh_tunnel_params != NULL && 3241 (handle->ifh_tunnel_params->ifta_flags & IFTUN_SECURITY)) 3242 print_tsec(handle->ifh_tunnel_params); 3243 3244 /* 3245 * tabbed indicates tabbed and printed. Use it tell us whether 3246 * to tab and that we've printed something here, so we need a 3247 * newline 3248 */ 3249 tabbed = _B_FALSE; 3250 3251 if (icfg_get_tunnel_hoplimit(handle, &hoplimit) == ICFG_SUCCESS) { 3252 (void) printf("\ttunnel hop limit %d ", hoplimit); 3253 tabbed = _B_TRUE; 3254 } 3255 3256 if ((protocol == AF_INET6) && 3257 (icfg_get_tunnel_encaplimit(handle, &encaplimit) == 3258 ICFG_SUCCESS)) { 3259 if (!tabbed) { 3260 (void) printf("\t"); 3261 tabbed = _B_TRUE; 3262 } 3263 if (encaplimit >= 0) { 3264 (void) printf("tunnel encapsulation limit %d", 3265 encaplimit); 3266 } else { 3267 (void) printf("tunnel encapsulation limit disabled"); 3268 } 3269 } 3270 3271 if (tabbed) 3272 (void) printf("\n"); 3273 3274 icfg_close(handle); 3275 } 3276 3277 static void 3278 in_status(int force, uint64_t flags) 3279 { 3280 struct sockaddr_in *sin, *laddr; 3281 struct sockaddr_in netmask = { AF_INET }; 3282 3283 if (debug) 3284 (void) printf("in_status(%s) flags 0x%llx\n", name, flags); 3285 3286 /* only print status for IPv4 interfaces */ 3287 if (!(flags & IFF_IPV4)) 3288 return; 3289 3290 /* if the interface is a tunnel, print the tunnel status */ 3291 tun_status(); 3292 3293 if (!(flags & IFF_NOLOCAL)) { 3294 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3295 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3296 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3297 errno == ENXIO) { 3298 if (!force) 3299 return; 3300 (void) memset(&lifr.lifr_addr, 0, 3301 sizeof (lifr.lifr_addr)); 3302 } else 3303 Perror0_exit("in_status: SIOCGLIFADDR"); 3304 } 3305 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3306 (void) printf("\tinet %s ", inet_ntoa(sin->sin_addr)); 3307 laddr = sin; 3308 } else { 3309 (void) printf("\tinet "); 3310 } 3311 3312 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3313 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3314 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3315 errno == ENXIO) { 3316 if (!force) 3317 return; 3318 (void) memset(&lifr.lifr_addr, 0, 3319 sizeof (lifr.lifr_addr)); 3320 } else { 3321 Perror0_exit("in_status: SIOCGLIFSUBNET"); 3322 } 3323 } 3324 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3325 if ((flags & IFF_NOLOCAL) || 3326 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3327 (void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr), 3328 lifr.lifr_addrlen); 3329 } 3330 if (sin->sin_family != AF_INET) { 3331 (void) printf("Wrong family: %d\n", sin->sin_family); 3332 } 3333 3334 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3335 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3336 if (errno != EADDRNOTAVAIL) 3337 Perror0_exit("in_status: SIOCGLIFNETMASK"); 3338 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3339 } else 3340 netmask.sin_addr = 3341 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3342 if (flags & IFF_POINTOPOINT) { 3343 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3344 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3345 if (errno == EADDRNOTAVAIL) 3346 (void) memset(&lifr.lifr_addr, 0, 3347 sizeof (lifr.lifr_addr)); 3348 else 3349 Perror0_exit("in_status: SIOCGLIFDSTADDR"); 3350 } 3351 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3352 (void) printf("--> %s ", inet_ntoa(sin->sin_addr)); 3353 } 3354 (void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr)); 3355 if (flags & IFF_BROADCAST) { 3356 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3357 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3358 if (errno == EADDRNOTAVAIL) 3359 (void) memset(&lifr.lifr_addr, 0, 3360 sizeof (lifr.lifr_addr)); 3361 else 3362 Perror0_exit("in_status: SIOCGLIFBRDADDR"); 3363 } 3364 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3365 if (sin->sin_addr.s_addr != 0) { 3366 (void) printf("broadcast %s", 3367 inet_ntoa(sin->sin_addr)); 3368 } 3369 } 3370 /* If there is a groupname, print it for lun 0 alone */ 3371 if (strchr(name, ':') == NULL) { 3372 (void) memset(lifr.lifr_groupname, 0, 3373 sizeof (lifr.lifr_groupname)); 3374 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3375 if (strlen(lifr.lifr_groupname) > 0) { 3376 (void) printf("\n\tgroupname %s", 3377 lifr.lifr_groupname); 3378 } 3379 } 3380 } 3381 (void) putchar('\n'); 3382 } 3383 3384 static void 3385 in6_status(int force, uint64_t flags) 3386 { 3387 char abuf[INET6_ADDRSTRLEN]; 3388 struct sockaddr_in6 *sin6, *laddr6; 3389 3390 if (debug) 3391 (void) printf("in6_status(%s) flags 0x%llx\n", name, flags); 3392 3393 if (!(flags & IFF_IPV6)) 3394 return; 3395 3396 /* if the interface is a tunnel, print the tunnel status */ 3397 tun_status(); 3398 3399 if (!(flags & IFF_NOLOCAL)) { 3400 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3401 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3402 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3403 errno == ENXIO) { 3404 if (!force) 3405 return; 3406 (void) memset(&lifr.lifr_addr, 0, 3407 sizeof (lifr.lifr_addr)); 3408 } else 3409 Perror0_exit("in_status6: SIOCGLIFADDR"); 3410 } 3411 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3412 (void) printf("\tinet6 %s/%d ", 3413 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3414 abuf, sizeof (abuf)), 3415 lifr.lifr_addrlen); 3416 laddr6 = sin6; 3417 } else { 3418 (void) printf("\tinet6 "); 3419 } 3420 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3421 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3422 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3423 errno == ENXIO) { 3424 if (!force) 3425 return; 3426 (void) memset(&lifr.lifr_addr, 0, 3427 sizeof (lifr.lifr_addr)); 3428 } else 3429 Perror0_exit("in_status6: SIOCGLIFSUBNET"); 3430 } 3431 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3432 if ((flags & IFF_NOLOCAL) || 3433 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3434 (void) printf("subnet %s/%d ", 3435 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3436 abuf, sizeof (abuf)), 3437 lifr.lifr_addrlen); 3438 } 3439 if (sin6->sin6_family != AF_INET6) { 3440 (void) printf("Wrong family: %d\n", sin6->sin6_family); 3441 } 3442 if (flags & IFF_POINTOPOINT) { 3443 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3444 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3445 if (errno == EADDRNOTAVAIL) 3446 (void) memset(&lifr.lifr_addr, 0, 3447 sizeof (lifr.lifr_addr)); 3448 else 3449 Perror0_exit("in_status6: SIOCGLIFDSTADDR"); 3450 } 3451 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3452 (void) printf("--> %s ", 3453 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3454 abuf, sizeof (abuf))); 3455 } 3456 if (verbose) { 3457 (void) putchar('\n'); 3458 (void) putchar('\t'); 3459 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3460 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3461 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3462 (void) memset(&lifr.lifr_addr, 0, 3463 sizeof (lifr.lifr_addr)); 3464 else 3465 Perror0_exit("in_status6: SIOCGLIFTOKEN"); 3466 } else { 3467 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3468 (void) printf("token %s/%d ", 3469 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3470 abuf, sizeof (abuf)), 3471 lifr.lifr_addrlen); 3472 } 3473 if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) { 3474 if (errno != EINVAL) { 3475 Perror0_exit("in_status6: SIOCGLIFLNKINFO"); 3476 } 3477 } else { 3478 (void) printf("maxhops %u, reachtime %u ms, " 3479 "reachretrans %u ms, maxmtu %u ", 3480 lifr.lifr_ifinfo.lir_maxhops, 3481 lifr.lifr_ifinfo.lir_reachtime, 3482 lifr.lifr_ifinfo.lir_reachretrans, 3483 lifr.lifr_ifinfo.lir_maxmtu); 3484 } 3485 } 3486 /* If there is a groupname, print it for lun 0 alone */ 3487 if (strchr(name, ':') == NULL) { 3488 (void) memset(lifr.lifr_groupname, 0, 3489 sizeof (lifr.lifr_groupname)); 3490 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3491 if (strlen(lifr.lifr_groupname) > 0) { 3492 (void) printf("\n\tgroupname %s", 3493 lifr.lifr_groupname); 3494 } 3495 } 3496 } 3497 (void) putchar('\n'); 3498 } 3499 3500 static void 3501 in_configinfo(int force, uint64_t flags) 3502 { 3503 struct sockaddr_in *sin, *laddr; 3504 struct sockaddr_in netmask = { AF_INET }; 3505 3506 if (debug) 3507 (void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags); 3508 3509 /* only configinfo info for IPv4 interfaces */ 3510 if (!(flags & IFF_IPV4)) 3511 return; 3512 3513 if (!(flags & IFF_NOLOCAL)) { 3514 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3515 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3516 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3517 errno == ENXIO) { 3518 if (!force) 3519 return; 3520 (void) memset(&lifr.lifr_addr, 0, 3521 sizeof (lifr.lifr_addr)); 3522 } else 3523 Perror0_exit("in_configinfo: SIOCGLIFADDR"); 3524 } 3525 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3526 if (get_lun(name) != 0) { 3527 (void) printf(" addif %s ", inet_ntoa(sin->sin_addr)); 3528 } else { 3529 (void) printf(" set %s ", inet_ntoa(sin->sin_addr)); 3530 } 3531 laddr = sin; 3532 } 3533 3534 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3535 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3536 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3537 errno == ENXIO) { 3538 if (!force) 3539 return; 3540 (void) memset(&lifr.lifr_addr, 0, 3541 sizeof (lifr.lifr_addr)); 3542 } else { 3543 Perror0_exit("in_configinfo: SIOCGLIFSUBNET"); 3544 } 3545 } 3546 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3547 3548 if ((flags & IFF_NOLOCAL) || 3549 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3550 (void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr), 3551 lifr.lifr_addrlen); 3552 } 3553 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3554 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3555 if (errno != EADDRNOTAVAIL) 3556 Perror0_exit("in_configinfo: SIOCGLIFNETMASK"); 3557 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3558 } else 3559 netmask.sin_addr = 3560 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3561 if (flags & IFF_POINTOPOINT) { 3562 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3563 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3564 if (errno == EADDRNOTAVAIL) 3565 (void) memset(&lifr.lifr_addr, 0, 3566 sizeof (lifr.lifr_addr)); 3567 else 3568 Perror0_exit("in_configinfo: SIOCGLIFDSTADDR"); 3569 } 3570 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3571 (void) printf(" destination %s ", inet_ntoa(sin->sin_addr)); 3572 } 3573 (void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr)); 3574 if (flags & IFF_BROADCAST) { 3575 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3576 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3577 if (errno == EADDRNOTAVAIL) 3578 (void) memset(&lifr.lifr_addr, 0, 3579 sizeof (lifr.lifr_addr)); 3580 else 3581 Perror0_exit("in_configinfo: SIOCGLIFBRDADDR"); 3582 } 3583 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3584 if (sin->sin_addr.s_addr != 0) { 3585 (void) printf(" broadcast %s ", 3586 inet_ntoa(sin->sin_addr)); 3587 } 3588 } 3589 3590 /* If there is a groupname, print it for lun 0 alone */ 3591 if (get_lun(name) == 0) { 3592 (void) memset(lifr.lifr_groupname, 0, 3593 sizeof (lifr.lifr_groupname)); 3594 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3595 if (strlen(lifr.lifr_groupname) > 0) { 3596 (void) printf(" group %s ", 3597 lifr.lifr_groupname); 3598 } 3599 } 3600 } 3601 3602 /* Print flags to configure */ 3603 print_config_flags(flags); 3604 3605 /* IFF_NOARP applies to AF_INET only */ 3606 if (flags & IFF_NOARP) { 3607 (void) printf("-arp "); 3608 } 3609 } 3610 3611 static void 3612 in6_configinfo(int force, uint64_t flags) 3613 { 3614 char abuf[INET6_ADDRSTRLEN]; 3615 struct sockaddr_in6 *sin6, *laddr6; 3616 3617 if (debug) 3618 (void) printf("in6_configinfo(%s) flags 0x%llx\n", name, 3619 flags); 3620 3621 if (!(flags & IFF_IPV6)) 3622 return; 3623 3624 if (!(flags & IFF_NOLOCAL)) { 3625 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3626 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3627 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3628 errno == ENXIO) { 3629 if (!force) 3630 return; 3631 (void) memset(&lifr.lifr_addr, 0, 3632 sizeof (lifr.lifr_addr)); 3633 } else 3634 Perror0_exit("in6_configinfo: SIOCGLIFADDR"); 3635 } 3636 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3637 if (get_lun(name) != 0) { 3638 (void) printf(" addif %s/%d ", 3639 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3640 abuf, sizeof (abuf)), 3641 lifr.lifr_addrlen); 3642 } else { 3643 (void) printf(" set %s/%d ", 3644 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3645 abuf, sizeof (abuf)), 3646 lifr.lifr_addrlen); 3647 } 3648 laddr6 = sin6; 3649 } 3650 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3651 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3652 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3653 errno == ENXIO) { 3654 if (!force) 3655 return; 3656 (void) memset(&lifr.lifr_addr, 0, 3657 sizeof (lifr.lifr_addr)); 3658 } else 3659 Perror0_exit("in6_configinfo: SIOCGLIFSUBNET"); 3660 } 3661 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3662 if ((flags & IFF_NOLOCAL) || 3663 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3664 (void) printf(" subnet %s/%d ", 3665 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3666 abuf, sizeof (abuf)), 3667 lifr.lifr_addrlen); 3668 } 3669 3670 if (flags & IFF_POINTOPOINT) { 3671 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3672 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3673 if (errno == EADDRNOTAVAIL) 3674 (void) memset(&lifr.lifr_addr, 0, 3675 sizeof (lifr.lifr_addr)); 3676 else 3677 Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR"); 3678 } 3679 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3680 (void) printf(" destination %s ", 3681 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3682 abuf, sizeof (abuf))); 3683 } 3684 3685 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3686 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3687 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3688 (void) memset(&lifr.lifr_addr, 0, 3689 sizeof (lifr.lifr_addr)); 3690 else 3691 Perror0_exit("in6_configinfo: SIOCGLIFTOKEN"); 3692 } else { 3693 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3694 (void) printf(" token %s/%d ", 3695 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3696 abuf, sizeof (abuf)), 3697 lifr.lifr_addrlen); 3698 } 3699 3700 /* If there is a groupname, print it for lun 0 alone */ 3701 if (get_lun(name) == 0) { 3702 (void) memset(lifr.lifr_groupname, 0, 3703 sizeof (lifr.lifr_groupname)); 3704 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3705 if (strlen(lifr.lifr_groupname) > 0) { 3706 (void) printf(" group %s ", 3707 lifr.lifr_groupname); 3708 } 3709 } 3710 } 3711 3712 /* Print flags to configure */ 3713 print_config_flags(flags); 3714 3715 /* IFF_NONUD applies to AF_INET6 only */ 3716 if (flags & IFF_NONUD) { 3717 (void) printf("-nud "); 3718 } 3719 } 3720 3721 /* ARGSUSED */ 3722 static int 3723 get_lun(char *rsrc) 3724 { 3725 char resource[LIFNAMSIZ]; 3726 char *cp; 3727 3728 (void) strcpy(resource, rsrc); 3729 3730 /* remove LIF component */ 3731 cp = strchr(resource, ':'); 3732 if (cp) { 3733 cp++; 3734 return (atoi(cp)); 3735 } 3736 3737 return (0); 3738 } 3739 3740 /* 3741 * We need to plink both the arp-device stream and the arp-ip-device stream. 3742 * However the muxid is stored only in IP. Plumbing 2 streams individually 3743 * is not atomic, and if ifconfig is killed, the resulting plumbing can 3744 * be inconsistent. For eg. if only the arp stream is plumbed, we have lost 3745 * the muxid, and the half-baked plumbing can neither be unplumbed nor 3746 * replumbed, thus requiring a reboot. To avoid the above the following 3747 * scheme is used. 3748 * 3749 * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams. 3750 * This is done by pushing arp on to the mux (/dev/udp). ARP adds some 3751 * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know 3752 * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs 3753 * the IP stream first, and unplumbs it last. The kernel (IP) does not 3754 * allow IP stream to be unplumbed without unplumbing arp stream. Similarly 3755 * it does not allow arp stream to be plumbed before IP stream is plumbed. 3756 * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic, 3757 * and IP uses the info in the I_PLINK message to get the muxid. 3758 * 3759 * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use 3760 * /dev/udp{,6}. 3761 * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream 3762 * depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp 3763 * or /dev/udp6 for SIOCGLIFMUXID and SIOCSLIFMUXID. 3764 * c. We need to push ARP in order to get the required kernel support for 3765 * atomic plumbings. The actual work done by ARP is explained in arp.c 3766 * Without pushing ARP, we will still be able to plumb/unplumb. But 3767 * it is not atomic, and is supported by the kernel for backward 3768 * compatibility for other utilities like atmifconfig etc. In this case 3769 * the utility must use SIOCSLIFMUXID. 3770 */ 3771 static void 3772 plumb_one_device(int af) 3773 { 3774 int arp_muxid = -1, ip_muxid; 3775 int mux_fd, ip_fd, arp_fd; 3776 int retval; 3777 uint_t ppa; 3778 char *udp_dev_name; 3779 char provider[DLPI_LINKNAME_MAX]; 3780 dlpi_handle_t dh_arp, dh_ip; 3781 3782 /* 3783 * We use DLPI_NOATTACH because the ip module will do the attach 3784 * itself for DLPI style-2 devices. 3785 */ 3786 retval = dlpi_open(name, &dh_ip, DLPI_NOATTACH); 3787 if (retval != DLPI_SUCCESS) 3788 Perrdlpi_exit("cannot open link", name, retval); 3789 3790 if ((retval = dlpi_parselink(name, provider, &ppa)) != DLPI_SUCCESS) 3791 Perrdlpi_exit("dlpi_parselink", name, retval); 3792 3793 if (debug) { 3794 (void) printf("ifconfig: plumb_one_device: provider %s," 3795 " ppa %u\n", provider, ppa); 3796 } 3797 3798 ip_fd = dlpi_fd(dh_ip); 3799 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) 3800 Perror2_exit("I_PUSH", IP_MOD_NAME); 3801 3802 /* 3803 * Push the ARP module onto the interface stream. IP uses 3804 * this to send resolution requests up to ARP. We need to 3805 * do this before the SLIFNAME ioctl is sent down because 3806 * the interface becomes publicly known as soon as the SLIFNAME 3807 * ioctl completes. Thus some other process trying to bring up 3808 * the interface after SLIFNAME but before we have pushed ARP 3809 * could hang. We pop the module again later if it is not needed. 3810 */ 3811 if (ioctl(ip_fd, I_PUSH, ARP_MOD_NAME) == -1) 3812 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3813 3814 /* 3815 * Set IFF_IPV4/IFF_IPV6 flags. 3816 * At this point in time the kernel also allows an 3817 * override of the CANTCHANGE flags. 3818 */ 3819 lifr.lifr_name[0] = '\0'; 3820 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3821 Perror0_exit("plumb_one_device: SIOCGLIFFLAGS"); 3822 3823 /* Set the name string and the IFF_IPV* flag */ 3824 if (af == AF_INET6) { 3825 lifr.lifr_flags |= IFF_IPV6; 3826 lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4); 3827 } else { 3828 lifr.lifr_flags |= IFF_IPV4; 3829 lifr.lifr_flags &= ~IFF_IPV6; 3830 } 3831 3832 /* record the device and module names as interface name */ 3833 lifr.lifr_ppa = ppa; 3834 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3835 3836 /* set the interface name */ 3837 if (ioctl(ip_fd, SIOCSLIFNAME, (char *)&lifr) == -1) { 3838 if (errno != EEXIST) 3839 Perror0_exit("SIOCSLIFNAME for ip"); 3840 /* 3841 * This difference between the way we behave for EEXIST 3842 * and that with other errors exists to preserve legacy 3843 * behaviour. Earlier when foreachinterface() and matcif() 3844 * were doing the duplicate interface name checks, for 3845 * already existing interfaces, inetplumb() returned "0". 3846 * To preserve this behaviour, Perror0() and return are 3847 * called for EEXIST. 3848 */ 3849 Perror0("SIOCSLIFNAME for ip"); 3850 return; 3851 } 3852 3853 /* Get the full set of existing flags for this stream */ 3854 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3855 Perror0_exit("plumb_one_device: SIOCFLIFFLAGS"); 3856 3857 if (debug) { 3858 (void) printf("ifconfig: plumb_one_device: %s got flags:\n", 3859 lifr.lifr_name); 3860 print_flags(lifr.lifr_flags); 3861 (void) putchar('\n'); 3862 } 3863 3864 /* Check if arp is not actually needed */ 3865 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3866 if (ioctl(ip_fd, I_POP, 0) == -1) 3867 Perror2_exit("I_POP", ARP_MOD_NAME); 3868 } 3869 3870 /* 3871 * Open "/dev/udp" for use as a multiplexor to PLINK the 3872 * interface stream under. We use "/dev/udp" instead of "/dev/ip" 3873 * since STREAMS will not let you PLINK a driver under itself, 3874 * and "/dev/ip" is typically the driver at the bottom of 3875 * the stream for tunneling interfaces. 3876 */ 3877 if (af == AF_INET6) 3878 udp_dev_name = UDP6_DEV_NAME; 3879 else 3880 udp_dev_name = UDP_DEV_NAME; 3881 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 3882 exit(EXIT_FAILURE); 3883 3884 /* Check if arp is not needed */ 3885 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3886 /* 3887 * PLINK the interface stream so that ifconfig can exit 3888 * without tearing down the stream. 3889 */ 3890 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 3891 Perror0_exit("I_PLINK for ip"); 3892 (void) close(mux_fd); 3893 return; 3894 } 3895 3896 /* 3897 * This interface does use ARP, so set up a separate stream 3898 * from the interface to ARP. 3899 * 3900 * Note: modules specified by the user are pushed 3901 * only on the interface stream, not on the ARP stream. 3902 */ 3903 if (debug) 3904 (void) printf("ifconfig: plumb_one_device: ifname: %s\n", name); 3905 3906 /* 3907 * We use DLPI_NOATTACH because the arp module will do the attach 3908 * itself for DLPI style-2 devices. 3909 */ 3910 retval = dlpi_open(name, &dh_arp, DLPI_NOATTACH); 3911 if (retval != DLPI_SUCCESS) 3912 Perrdlpi_exit("cannot open link", name, retval); 3913 3914 arp_fd = dlpi_fd(dh_arp); 3915 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) 3916 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3917 3918 /* 3919 * Tell ARP the name and unit number for this interface. 3920 * Note that arp has no support for transparent ioctls. 3921 */ 3922 if (strioctl(arp_fd, SIOCSLIFNAME, (char *)&lifr, 3923 sizeof (lifr)) == -1) { 3924 if (errno != EEXIST) 3925 Perror0_exit("SIOCSLIFNAME for arp"); 3926 Perror0("SIOCSLIFNAME for arp"); 3927 dlpi_close(dh_arp); 3928 dlpi_close(dh_ip); 3929 (void) close(mux_fd); 3930 return; 3931 } 3932 /* 3933 * PLINK the IP and ARP streams so that ifconfig can exit 3934 * without tearing down the stream. 3935 */ 3936 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 3937 Perror0_exit("I_PLINK for ip"); 3938 if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) { 3939 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 3940 Perror0_exit("I_PLINK for arp"); 3941 } 3942 3943 if (debug) 3944 (void) printf("arp muxid = %d\n", arp_muxid); 3945 dlpi_close(dh_ip); 3946 dlpi_close(dh_arp); 3947 (void) close(mux_fd); 3948 } 3949 3950 3951 /* 3952 * If this is a physical interface then remove it. 3953 * If it is a logical interface name use SIOCLIFREMOVEIF to 3954 * remove it. In both cases fail if it doesn't exist. 3955 */ 3956 /* ARGSUSED */ 3957 static int 3958 inetunplumb(char *arg, int64_t param) 3959 { 3960 int ip_muxid, arp_muxid; 3961 int mux_fd; 3962 int muxid_fd; 3963 char *udp_dev_name; 3964 char *strptr; 3965 uint64_t flags; 3966 boolean_t changed_arp_muxid = _B_FALSE; 3967 int save_errno; 3968 3969 strptr = strchr(name, ':'); 3970 if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) { 3971 /* Can't unplumb logical interface zero */ 3972 if (strptr != NULL && strcmp(strptr, ":0") == 0) { 3973 (void) fprintf(stderr, "ifconfig: unplumb:" 3974 " Cannot unplumb %s: Invalid interface\n", name); 3975 exit(1); 3976 } 3977 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3978 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3979 3980 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) 3981 Perror0_exit("unplumb: SIOCLIFREMOVEIF"); 3982 return (0); 3983 } 3984 3985 /* 3986 * We used /dev/udp or udp6 to set up the mux. So we have to use 3987 * the same now for PUNLINK also. 3988 */ 3989 if (afp->af_af == AF_INET6) 3990 udp_dev_name = UDP6_DEV_NAME; 3991 else 3992 udp_dev_name = UDP_DEV_NAME; 3993 3994 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) 3995 exit(EXIT_FAILURE); 3996 3997 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 3998 exit(EXIT_FAILURE); 3999 4000 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4001 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 4002 Perror0_exit("unplumb: SIOCGLIFFLAGS"); 4003 } 4004 flags = lifr.lifr_flags; 4005 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 4006 Perror0_exit("unplumb: SIOCGLIFMUXID"); 4007 } 4008 arp_muxid = lifr.lifr_arp_muxid; 4009 ip_muxid = lifr.lifr_ip_muxid; 4010 /* 4011 * We don't have a good way of knowing whether the arp stream is 4012 * plumbed. We can't rely on IFF_NOARP because someone could 4013 * have turned it off later using "ifconfig xxx -arp". 4014 */ 4015 if (arp_muxid != 0) { 4016 if (debug) 4017 (void) printf("arp_muxid %d\n", arp_muxid); 4018 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 4019 if ((errno == EINVAL) && 4020 (flags & (IFF_NOARP | IFF_IPV6))) { 4021 /* 4022 * Some plumbing utilities set the muxid to 4023 * -1 or some invalid value to signify that 4024 * there is no arp stream. Set the muxid to 0 4025 * before trying to unplumb the IP stream. 4026 * IP does not allow the IP stream to be 4027 * unplumbed if it sees a non-null arp muxid, 4028 * for consistency of IP-ARP streams. 4029 */ 4030 lifr.lifr_arp_muxid = 0; 4031 (void) ioctl(muxid_fd, SIOCSLIFMUXID, 4032 (caddr_t)&lifr); 4033 changed_arp_muxid = _B_TRUE; 4034 } else { 4035 Perror0("I_PUNLINK for arp"); 4036 } 4037 } 4038 } 4039 if (debug) 4040 (void) printf("ip_muxid %d\n", ip_muxid); 4041 4042 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 4043 if (changed_arp_muxid) { 4044 /* 4045 * Some error occurred, and we need to restore 4046 * everything back to what it was. 4047 */ 4048 save_errno = errno; 4049 lifr.lifr_arp_muxid = arp_muxid; 4050 lifr.lifr_ip_muxid = ip_muxid; 4051 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 4052 errno = save_errno; 4053 } 4054 Perror0_exit("I_PUNLINK for ip"); 4055 } 4056 (void) close(mux_fd); 4057 (void) close(muxid_fd); 4058 return (0); 4059 } 4060 4061 /* 4062 * If this is a physical interface then create it unless it is already 4063 * present. If it is a logical interface name use SIOCLIFADDIF to 4064 * create and (and fail it if already exists.) 4065 * As a special case send SIOCLIFADDIF for the loopback interface. This 4066 * is needed since there is no other notion of plumbing the loopback 4067 * interface. 4068 */ 4069 /* ARGSUSED */ 4070 static int 4071 inetplumb(char *arg, int64_t param) 4072 { 4073 char *strptr; 4074 boolean_t islo; 4075 zoneid_t zoneid; 4076 4077 strptr = strchr(name, ':'); 4078 islo = (strcmp(name, LOOPBACK_IF) == 0); 4079 4080 if (strptr != NULL || islo) { 4081 (void) memset(&lifr, 0, sizeof (lifr)); 4082 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4083 if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) { 4084 if (debug) { 4085 (void) fprintf(stderr, 4086 "ifconfig: %s already exists\n", name); 4087 } 4088 return (0); 4089 } 4090 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) { 4091 if (errno == EEXIST) { 4092 if (debug) { 4093 (void) fprintf(stderr, 4094 "ifconfig: %s already exists\n", 4095 name); 4096 } 4097 } else { 4098 Perror2_exit("plumb: SIOCLIFADDIF", name); 4099 } 4100 } 4101 /* 4102 * IP can create the new logical interface on a different 4103 * physical interface in the same IPMP group. Take the new 4104 * interface into account for further operations. 4105 */ 4106 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 4107 return (0); 4108 } 4109 4110 /* 4111 * For global zone, check if the interface is used by a non-global 4112 * zone, note that the non-global zones doesn't need this check, 4113 * because zoneadm has taken care of this when the zone boots. 4114 */ 4115 zoneid = getzoneid(); 4116 if (zoneid == GLOBAL_ZONEID) { 4117 int ret; 4118 4119 zoneid = ALL_ZONES; 4120 ret = zone_check_datalink(&zoneid, name); 4121 if (ret == 0) { 4122 char zonename[ZONENAME_MAX]; 4123 4124 (void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX); 4125 (void) fprintf(stderr, "%s is used by non-global" 4126 "zone: %s\n", name, zonename); 4127 return (1); 4128 } 4129 } 4130 4131 if (debug) 4132 (void) printf("inetplumb: %s af %d\n", name, afp->af_af); 4133 4134 plumb_one_device(afp->af_af); 4135 return (0); 4136 } 4137 4138 void 4139 Perror0(char *cmd) 4140 { 4141 int save_errno; 4142 4143 save_errno = errno; 4144 (void) fprintf(stderr, "ifconfig: "); 4145 errno = save_errno; 4146 switch (errno) { 4147 4148 case ENXIO: 4149 (void) fprintf(stderr, "%s: %s: no such interface\n", 4150 cmd, lifr.lifr_name); 4151 break; 4152 4153 case EPERM: 4154 (void) fprintf(stderr, "%s: %s: permission denied\n", 4155 cmd, lifr.lifr_name); 4156 break; 4157 4158 case EEXIST: 4159 (void) fprintf(stderr, "%s: %s: already exists\n", 4160 cmd, lifr.lifr_name); 4161 break; 4162 4163 default: { 4164 char buf[BUFSIZ]; 4165 4166 (void) snprintf(buf, sizeof (buf), "%s: %s", 4167 cmd, lifr.lifr_name); 4168 perror(buf); 4169 } 4170 } 4171 } 4172 4173 void 4174 Perror0_exit(char *cmd) 4175 { 4176 Perror0(cmd); 4177 exit(1); 4178 /* NOTREACHED */ 4179 } 4180 4181 void 4182 Perror2(char *cmd, char *str) 4183 { 4184 int save_errno; 4185 4186 save_errno = errno; 4187 (void) fprintf(stderr, "ifconfig: "); 4188 errno = save_errno; 4189 switch (errno) { 4190 4191 case ENXIO: 4192 (void) fprintf(stderr, "%s: %s: no such interface\n", 4193 cmd, str); 4194 break; 4195 4196 case EPERM: 4197 (void) fprintf(stderr, "%s: %s: permission denied\n", 4198 cmd, str); 4199 break; 4200 4201 default: { 4202 char buf[BUFSIZ]; 4203 4204 (void) snprintf(buf, sizeof (buf), "%s: %s", cmd, str); 4205 perror(buf); 4206 } 4207 } 4208 } 4209 4210 /* 4211 * Print out error message (Perror2()) and exit 4212 */ 4213 void 4214 Perror2_exit(char *cmd, char *str) 4215 { 4216 Perror2(cmd, str); 4217 exit(1); 4218 /* NOTREACHED */ 4219 } 4220 4221 void 4222 Perrdlpi(const char *cmd, const char *linkname, int err) 4223 { 4224 (void) fprintf(stderr, "ifconfig: %s \"%s\": %s\n", cmd, 4225 linkname, dlpi_strerror(err)); 4226 } 4227 4228 /* 4229 * Print out error message (Perrdlpi()) and exit 4230 */ 4231 void 4232 Perrdlpi_exit(const char *cmd, const char *linkname, int err) 4233 { 4234 Perrdlpi(cmd, linkname, err); 4235 exit(1); 4236 } 4237 4238 /* 4239 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4240 * pass out <n> in *plenp. 4241 * If <n> doesn't parse return BAD_ADDR as *plenp. 4242 * If no /<n> is present return NO_PREFIX as *plenp. 4243 */ 4244 static void 4245 in_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4246 { 4247 /* LINTED: alignment */ 4248 struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 4249 struct hostent *hp; 4250 struct netent *np; 4251 char str[BUFSIZ]; 4252 int error_num; 4253 4254 (void) strncpy(str, s, sizeof (str)); 4255 4256 /* 4257 * Look for '/'<n> is plenp 4258 */ 4259 if (plenp != NULL) { 4260 char *cp; 4261 4262 *plenp = in_getprefixlen(str, _B_TRUE, IP_ABITS); 4263 if (*plenp == BAD_ADDR) 4264 return; 4265 cp = strchr(str, '/'); 4266 if (cp != NULL) 4267 *cp = '\0'; 4268 } else if (strchr(str, '/') != NULL) { 4269 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4270 exit(1); 4271 } 4272 4273 (void) memset(sin, 0, sizeof (*sin)); 4274 4275 /* 4276 * Try to catch attempts to set the broadcast address to all 1's. 4277 */ 4278 if (strcmp(str, "255.255.255.255") == 0 || 4279 (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) { 4280 sin->sin_family = AF_INET; 4281 sin->sin_addr.s_addr = 0xffffffff; 4282 return; 4283 } 4284 4285 hp = getipnodebyname(str, AF_INET, 0, &error_num); 4286 if (hp) { 4287 sin->sin_family = hp->h_addrtype; 4288 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); 4289 freehostent(hp); 4290 return; 4291 } 4292 np = getnetbyname(str); 4293 if (np) { 4294 sin->sin_family = np->n_addrtype; 4295 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 4296 return; 4297 } 4298 if (error_num == TRY_AGAIN) { 4299 (void) fprintf(stderr, "ifconfig: %s: bad address " 4300 "(try again later)\n", s); 4301 } else { 4302 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4303 } 4304 exit(1); 4305 } 4306 4307 /* 4308 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4309 * pass out <n> in *plenp. 4310 * If <n> doesn't parse return BAD_ADDR as *plenp. 4311 * If no /<n> is present return NO_PREFIX as *plenp. 4312 */ 4313 static void 4314 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4315 { 4316 /* LINTED: alignment */ 4317 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr; 4318 struct hostent *hp; 4319 char str[BUFSIZ]; 4320 int error_num; 4321 4322 (void) strncpy(str, s, sizeof (str)); 4323 4324 /* 4325 * Look for '/'<n> is plenp 4326 */ 4327 if (plenp != NULL) { 4328 char *cp; 4329 4330 *plenp = in_getprefixlen(str, _B_TRUE, IPV6_ABITS); 4331 if (*plenp == BAD_ADDR) 4332 return; 4333 cp = strchr(str, '/'); 4334 if (cp != NULL) 4335 *cp = '\0'; 4336 } else if (strchr(str, '/') != NULL) { 4337 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4338 exit(1); 4339 } 4340 4341 (void) memset(sin6, 0, sizeof (*sin6)); 4342 4343 hp = getipnodebyname(str, AF_INET6, 0, &error_num); 4344 if (hp) { 4345 sin6->sin6_family = hp->h_addrtype; 4346 (void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length); 4347 freehostent(hp); 4348 return; 4349 } 4350 if (error_num == TRY_AGAIN) { 4351 (void) fprintf(stderr, "ifconfig: %s: bad address " 4352 "(try again later)\n", s); 4353 } else { 4354 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4355 } 4356 exit(1); 4357 } 4358 4359 /* 4360 * If "slash" is zero this parses the whole string as 4361 * an integer. With "slash" non zero it parses the tail part as an integer. 4362 * 4363 * If it is not a valid integer this returns BAD_ADDR. 4364 * If there is /<n> present this returns NO_PREFIX. 4365 */ 4366 static int 4367 in_getprefixlen(char *addr, boolean_t slash, int max_plen) 4368 { 4369 int prefixlen; 4370 char *str, *end; 4371 4372 if (slash) { 4373 str = strchr(addr, '/'); 4374 if (str == NULL) 4375 return (NO_PREFIX); 4376 str++; 4377 } else 4378 str = addr; 4379 4380 prefixlen = strtol(str, &end, 10); 4381 if (prefixlen < 0) 4382 return (BAD_ADDR); 4383 if (str == end) 4384 return (BAD_ADDR); 4385 if (max_plen != 0 && max_plen < prefixlen) 4386 return (BAD_ADDR); 4387 return (prefixlen); 4388 } 4389 4390 /* 4391 * Convert a prefix length to a mask. 4392 * Returns 1 if ok. 0 otherwise. 4393 * Assumes the mask array is zero'ed by the caller. 4394 */ 4395 static boolean_t 4396 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 4397 { 4398 if (prefixlen < 0 || prefixlen > maxlen) 4399 return (0); 4400 4401 while (prefixlen > 0) { 4402 if (prefixlen >= 8) { 4403 *mask++ = 0xFF; 4404 prefixlen -= 8; 4405 continue; 4406 } 4407 *mask |= 1 << (8 - prefixlen); 4408 prefixlen--; 4409 } 4410 return (1); 4411 } 4412 4413 static void 4414 print_flags(uint64_t flags) 4415 { 4416 boolean_t first = _B_TRUE; 4417 int cnt, i; 4418 4419 (void) printf("flags=%llx", flags); 4420 cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t); 4421 for (i = 0; i < cnt; i++) { 4422 if (flags & if_flags_tbl[i].iff_value) { 4423 if (first) { 4424 (void) printf("<"); 4425 first = _B_FALSE; 4426 } else { 4427 /* 4428 * It has to be here and not with the 4429 * printf below because for the last one, 4430 * we don't want a comma before the ">". 4431 */ 4432 (void) printf(","); 4433 } 4434 (void) printf("%s", if_flags_tbl[i].iff_name); 4435 } 4436 } 4437 if (!first) 4438 (void) printf(">"); 4439 } 4440 4441 static void 4442 print_config_flags(uint64_t flags) 4443 { 4444 int cnt, i; 4445 4446 cnt = sizeof (if_config_cmd_tbl) / sizeof (if_config_cmd_t); 4447 for (i = 0; i < cnt; i++) { 4448 if (flags & if_config_cmd_tbl[i].iff_flag) { 4449 (void) printf("%s ", if_config_cmd_tbl[i].iff_name); 4450 } 4451 } 4452 } 4453 4454 /* 4455 * Use the configured directory lookup mechanism (e.g. files/NIS/NIS+/...) 4456 * to find the network mask. Returns true if we found one to set. 4457 * 4458 * The parameter addr_set controls whether we should get the address of 4459 * the working interface for the netmask query. If addr_set is true, 4460 * we will use the address provided. Otherwise, we will find the working 4461 * interface's address and use it instead. 4462 */ 4463 static boolean_t 4464 in_getmask(struct sockaddr_in *saddr, boolean_t addr_set) 4465 { 4466 struct sockaddr_in ifaddr; 4467 4468 /* 4469 * Read the address from the interface if it is not passed in. 4470 */ 4471 if (!addr_set) { 4472 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4473 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 4474 if (errno != EADDRNOTAVAIL) { 4475 (void) fprintf(stderr, "Need net number for " 4476 "mask\n"); 4477 } 4478 return (_B_FALSE); 4479 } 4480 ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr); 4481 } else { 4482 ifaddr.sin_addr = saddr->sin_addr; 4483 } 4484 if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) { 4485 saddr->sin_family = AF_INET; 4486 return (_B_TRUE); 4487 } 4488 return (_B_FALSE); 4489 } 4490 4491 static int 4492 strioctl(int s, int cmd, char *buf, int buflen) 4493 { 4494 struct strioctl ioc; 4495 4496 (void) memset(&ioc, 0, sizeof (ioc)); 4497 ioc.ic_cmd = cmd; 4498 ioc.ic_timout = 0; 4499 ioc.ic_len = buflen; 4500 ioc.ic_dp = buf; 4501 return (ioctl(s, I_STR, (char *)&ioc)); 4502 } 4503 4504 static void 4505 add_ni(const char *name) 4506 { 4507 ni_t **pp; 4508 ni_t *p; 4509 4510 for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) { 4511 if (strcmp(p->ni_name, name) == 0) { 4512 if (debug > 2) 4513 (void) fprintf(stderr, "'%s' is a duplicate\n", 4514 name); 4515 return; 4516 } 4517 } 4518 4519 if (debug > 2) 4520 (void) fprintf(stderr, "adding '%s'\n", 4521 name); 4522 4523 if ((p = malloc(sizeof (ni_t))) == NULL) 4524 return; 4525 4526 (void) strlcpy(p->ni_name, name, sizeof (p->ni_name)); 4527 p->ni_next = NULL; 4528 4529 *pp = p; 4530 num_ni++; 4531 } 4532 4533 /* ARGSUSED2 */ 4534 static boolean_t 4535 ni_entry(const char *linkname, void *arg) 4536 { 4537 dlpi_handle_t dh; 4538 4539 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) 4540 return (_B_FALSE); 4541 4542 add_ni(linkname); 4543 4544 dlpi_close(dh); 4545 return (_B_FALSE); 4546 } 4547 4548 /* 4549 * dhcp-related routines 4550 */ 4551 4552 static int 4553 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[]) 4554 { 4555 dhcp_ipc_request_t *request; 4556 dhcp_ipc_reply_t *reply = NULL; 4557 int timeout = DHCP_IPC_WAIT_DEFAULT; 4558 dhcp_ipc_type_t type = DHCP_START; 4559 int error; 4560 boolean_t is_primary = _B_FALSE; 4561 boolean_t started = _B_FALSE; 4562 4563 for (argv++; --argc > 0; argv++) { 4564 4565 if (strcmp(*argv, "primary") == 0) { 4566 is_primary = _B_TRUE; 4567 continue; 4568 } 4569 4570 if (strcmp(*argv, "wait") == 0) { 4571 if (--argc <= 0) { 4572 usage(); 4573 return (DHCP_EXIT_BADARGS); 4574 } 4575 argv++; 4576 4577 if (strcmp(*argv, "forever") == 0) { 4578 timeout = DHCP_IPC_WAIT_FOREVER; 4579 continue; 4580 } 4581 4582 if (sscanf(*argv, "%d", &timeout) != 1) { 4583 usage(); 4584 return (DHCP_EXIT_BADARGS); 4585 } 4586 4587 if (timeout < 0) { 4588 usage(); 4589 return (DHCP_EXIT_BADARGS); 4590 } 4591 continue; 4592 } 4593 4594 type = dhcp_string_to_request(*argv); 4595 if (type == -1) { 4596 usage(); 4597 return (DHCP_EXIT_BADARGS); 4598 } 4599 } 4600 4601 /* 4602 * Only try to start agent on start or inform; in all other cases it 4603 * has to already be running for anything to make sense. 4604 */ 4605 if (type == DHCP_START || type == DHCP_INFORM) { 4606 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) { 4607 (void) fprintf(stderr, "%s: unable to start %s\n", 4608 caller, DHCP_AGENT_PATH); 4609 return (DHCP_EXIT_FAILURE); 4610 } 4611 started = _B_TRUE; 4612 } 4613 4614 if (is_primary) 4615 type |= DHCP_PRIMARY; 4616 4617 if (af != AF_INET) 4618 type |= DHCP_V6; 4619 4620 request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE); 4621 if (request == NULL) { 4622 (void) fprintf(stderr, "%s: out of memory\n", caller); 4623 return (DHCP_EXIT_SYSTEM); 4624 } 4625 4626 error = dhcp_ipc_make_request(request, &reply, timeout); 4627 if (error != 0) { 4628 free(request); 4629 /* 4630 * Re-map connect error to not under control if we didn't try a 4631 * start operation, as this has to be true and results in a 4632 * clearer message, not to mention preserving compatibility 4633 * with the days when we always started dhcpagent for every 4634 * request. 4635 */ 4636 if (error == DHCP_IPC_E_CONNECT && !started) 4637 error = DHCP_IPC_E_UNKIF; 4638 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4639 dhcp_ipc_strerror(error)); 4640 return (DHCP_EXIT_FAILURE); 4641 } 4642 4643 error = reply->return_code; 4644 if (error != 0) { 4645 free(request); 4646 free(reply); 4647 4648 if (error == DHCP_IPC_E_TIMEOUT && timeout == 0) 4649 return (DHCP_EXIT_SUCCESS); 4650 4651 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4652 dhcp_ipc_strerror(error)); 4653 4654 if (error == DHCP_IPC_E_TIMEOUT) 4655 return (DHCP_EXIT_TIMEOUT); 4656 else 4657 return (DHCP_EXIT_IF_FAILURE); 4658 } 4659 4660 if (DHCP_IPC_CMD(type) == DHCP_STATUS) { 4661 (void) printf("%s", dhcp_status_hdr_string()); 4662 (void) printf("%s", dhcp_status_reply_to_string(reply)); 4663 } 4664 4665 free(request); 4666 free(reply); 4667 return (DHCP_EXIT_SUCCESS); 4668 } 4669 4670 static void 4671 usage(void) 4672 { 4673 (void) fprintf(stderr, 4674 "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n"); 4675 4676 (void) fprintf(stderr, "%s", 4677 "\t[ <addr_family> ]\n" 4678 "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n" 4679 "\t[ set [ <address>][/<prefix_length>] ]" 4680 " [ <address>/<prefix_length>] ]\n" 4681 "\t[ destination <dest_address> ]\n" 4682 "\t[ addif <address>[/<prefix_length>]" 4683 " [ <dest_address> ] ]\n" 4684 "\t[ removeif <address>[/<prefix_length>] ]\n" 4685 "\t[ arp | -arp ]\n" 4686 "\t[ auto-revarp ]\n" 4687 "\t[ broadcast <broad_addr> ]\n" 4688 "\t[ index <if_index> ]\n" 4689 "\t[ metric <n> ] [ mtu <n> ]\n" 4690 "\t[ netmask <mask> ]\n" 4691 "\t[ plumb ] [ unplumb ]\n" 4692 "\t[ preferred | -preferred ]\n" 4693 "\t[ private | -private ]\n" 4694 "\t[ local | -local ]\n" 4695 "\t[ router | -router ]\n" 4696 "\t[ subnet <subnet_address>]\n" 4697 "\t[ trailers | -trailers ]\n" 4698 "\t[ token <address>/<prefix_length> ]\n" 4699 "\t[ tsrc <tunnel_src_address> ]\n" 4700 "\t[ tdst <tunnel_dest_address> ]\n" 4701 "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n" 4702 "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n" 4703 "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n" 4704 "\t[ up ] [ down ]\n" 4705 "\t[ xmit | -xmit ]\n" 4706 "\t[ modlist ]\n" 4707 "\t[ modinsert <module_name@position> ]\n" 4708 "\t[ modremove <module_name@position> ]\n" 4709 "\t[ group <groupname>] | [ group \"\"]\n" 4710 "\t[ deprecated | -deprecated ]\n" 4711 "\t[ standby | -standby ]\n" 4712 "\t[ failover | -failover ]\n" 4713 "\t[ zone <zonename> | -zone ]\n" 4714 "\t[ usesrc <interface> ]\n" 4715 "\t[ all-zones ]\n"); 4716 4717 (void) fprintf(stderr, "or\n"); 4718 (void) fprintf(stderr, 4719 "\tifconfig <interface> | -a[ 4 | 6 | D ] [ u | d ]\n"); 4720 4721 (void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n" 4722 "\t[ wait <time> | forever ]\n\t[ primary ]\n" 4723 "\tstart | drop | ping | release | status | inform\n"); 4724 } 4725