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