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