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