1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>. 25 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stropts.h> 35 #include <sys/sockio.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/socket.h> 39 #include <net/route.h> 40 #include <netinet/in.h> 41 #include <inet/ip.h> 42 #include <arpa/inet.h> 43 #include <libintl.h> 44 #include <libdlpi.h> 45 #include <libinetutil.h> 46 #include <libdladm.h> 47 #include <libdllink.h> 48 #include <libdliptun.h> 49 #include <strings.h> 50 #include <zone.h> 51 #include <ctype.h> 52 #include <limits.h> 53 #include <assert.h> 54 #include <netdb.h> 55 #include <pwd.h> 56 #include <auth_attr.h> 57 #include <secdb.h> 58 #include <nss_dbdefs.h> 59 #include "libipadm_impl.h" 60 61 /* error codes and text description */ 62 static struct ipadm_error_info { 63 ipadm_status_t error_code; 64 const char *error_desc; 65 } ipadm_errors[] = { 66 { IPADM_SUCCESS, "Operation succeeded" }, 67 { IPADM_FAILURE, "Operation failed" }, 68 { IPADM_EAUTH, "Insufficient user authorizations" }, 69 { IPADM_EPERM, "Permission denied" }, 70 { IPADM_NO_BUFS, "No buffer space available" }, 71 { IPADM_NO_MEMORY, "Insufficient memory" }, 72 { IPADM_BAD_ADDR, "Invalid address" }, 73 { IPADM_BAD_PROTOCOL, "Incorrect protocol family for operation" }, 74 { IPADM_DAD_FOUND, "Duplicate address detected" }, 75 { IPADM_EXISTS, "Already exists" }, 76 { IPADM_IF_EXISTS, "Interface already exists" }, 77 { IPADM_ADDROBJ_EXISTS, "Address object already exists" }, 78 { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" }, 79 { IPADM_ENXIO, "Interface does not exist" }, 80 { IPADM_GRP_NOTEMPTY, "IPMP group is not empty" }, 81 { IPADM_INVALID_ARG, "Invalid argument provided" }, 82 { IPADM_INVALID_NAME, "Invalid name" }, 83 { IPADM_DLPI_FAILURE, "Could not open DLPI link" }, 84 { IPADM_DLADM_FAILURE, "Datalink does not exist" }, 85 { IPADM_PROP_UNKNOWN, "Unknown property" }, 86 { IPADM_ERANGE, "Value is outside the allowed range" }, 87 { IPADM_ESRCH, "Value does not exist" }, 88 { IPADM_EOVERFLOW, "Number of values exceeds the allowed limit" }, 89 { IPADM_NOTFOUND, "Object not found" }, 90 { IPADM_IF_INUSE, "Interface already in use" }, 91 { IPADM_ADDR_INUSE, "Address already in use" }, 92 { IPADM_BAD_HOSTNAME, "Hostname maps to multiple IP addresses" }, 93 { IPADM_ADDR_NOTAVAIL, "Can't assign requested address" }, 94 { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" }, 95 { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" }, 96 { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" }, 97 { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" }, 98 { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" }, 99 { IPADM_TEMPORARY_OBJ, "Persistent operation on temporary object" }, 100 { IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" }, 101 { IPADM_NOTSUP, "Operation not supported" }, 102 { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" }, 103 { IPADM_EBADE, "Invalid data exchange with daemon" }, 104 { IPADM_GZ_PERM, "Operation not permitted on from-gz interface"} 105 }; 106 107 #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors)) 108 109 ipadm_status_t 110 ipadm_errno2status(int error) 111 { 112 switch (error) { 113 case 0: 114 return (IPADM_SUCCESS); 115 case ENXIO: 116 return (IPADM_ENXIO); 117 case ENOMEM: 118 return (IPADM_NO_MEMORY); 119 case ENOBUFS: 120 return (IPADM_NO_BUFS); 121 case EINVAL: 122 return (IPADM_INVALID_ARG); 123 case EBUSY: 124 return (IPADM_IF_INUSE); 125 case EEXIST: 126 return (IPADM_EXISTS); 127 case EADDRNOTAVAIL: 128 return (IPADM_ADDR_NOTAVAIL); 129 case EADDRINUSE: 130 return (IPADM_ADDR_INUSE); 131 case ENOENT: 132 return (IPADM_NOTFOUND); 133 case ERANGE: 134 return (IPADM_ERANGE); 135 case EPERM: 136 return (IPADM_EPERM); 137 case ENOTSUP: 138 case EOPNOTSUPP: 139 return (IPADM_NOTSUP); 140 case EBADF: 141 return (IPADM_IPC_ERROR); 142 case EBADE: 143 return (IPADM_EBADE); 144 case ESRCH: 145 return (IPADM_ESRCH); 146 case EOVERFLOW: 147 return (IPADM_EOVERFLOW); 148 default: 149 return (IPADM_FAILURE); 150 } 151 } 152 153 /* 154 * Returns a message string for the given libipadm error status. 155 */ 156 const char * 157 ipadm_status2str(ipadm_status_t status) 158 { 159 int i; 160 161 for (i = 0; i < IPADM_NUM_ERRORS; i++) { 162 if (status == ipadm_errors[i].error_code) 163 return (dgettext(TEXT_DOMAIN, 164 ipadm_errors[i].error_desc)); 165 } 166 167 return (dgettext(TEXT_DOMAIN, "<unknown error>")); 168 } 169 170 /* 171 * Opens a handle to libipadm. 172 * Possible values for flags: 173 * IPH_VRRP: Used by VRRP daemon to set the socket option SO_VRRP. 174 * IPH_LEGACY: This is used whenever an application needs to provide a 175 * logical interface name while creating or deleting 176 * interfaces and static addresses. 177 * IPH_INIT: Used by ipadm_init_prop(), to initialize protocol properties 178 * on reboot. 179 */ 180 ipadm_status_t 181 ipadm_open(ipadm_handle_t *handle, uint32_t flags) 182 { 183 ipadm_handle_t iph; 184 ipadm_status_t status = IPADM_SUCCESS; 185 zoneid_t zoneid; 186 ushort_t zflags; 187 int on = B_TRUE; 188 189 if (handle == NULL) 190 return (IPADM_INVALID_ARG); 191 *handle = NULL; 192 193 if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD)) 194 return (IPADM_INVALID_ARG); 195 196 if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL) 197 return (IPADM_NO_MEMORY); 198 iph->iph_sock = -1; 199 iph->iph_sock6 = -1; 200 iph->iph_door_fd = -1; 201 iph->iph_rtsock = -1; 202 iph->iph_flags = flags; 203 (void) pthread_mutex_init(&iph->iph_lock, NULL); 204 205 if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 206 (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 207 goto errnofail; 208 } 209 210 /* 211 * We open a handle to libdladm here, to facilitate some daemons (like 212 * nwamd) which opens handle to libipadm before devfsadmd installs the 213 * right device permissions into the kernel and requires "all" 214 * privileges to open DLD_CONTROL_DEV. 215 * 216 * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node 217 * and dladm_open() will fail. So, we avoid this by not calling 218 * dladm_open() for such zones. 219 */ 220 zoneid = getzoneid(); 221 iph->iph_zoneid = zoneid; 222 if (zoneid != GLOBAL_ZONEID) { 223 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, 224 sizeof (zflags)) < 0) { 225 goto errnofail; 226 } 227 } 228 if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) { 229 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) { 230 ipadm_close(iph); 231 return (IPADM_DLADM_FAILURE); 232 } 233 if (zoneid != GLOBAL_ZONEID) { 234 iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0); 235 /* 236 * Failure to open rtsock is ignored as this is 237 * only used in non-global zones to initialize 238 * routing socket information. 239 */ 240 } 241 } else { 242 assert(zoneid != GLOBAL_ZONEID); 243 iph->iph_dlh = NULL; 244 } 245 if (flags & IPH_VRRP) { 246 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on, 247 sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET, 248 SO_VRRP, &on, sizeof (on)) < 0) { 249 goto errnofail; 250 } 251 } 252 *handle = iph; 253 return (status); 254 255 errnofail: 256 status = ipadm_errno2status(errno); 257 ipadm_close(iph); 258 return (status); 259 } 260 261 /* 262 * Closes and frees the libipadm handle. 263 */ 264 void 265 ipadm_close(ipadm_handle_t iph) 266 { 267 if (iph == NULL) 268 return; 269 if (iph->iph_sock != -1) 270 (void) close(iph->iph_sock); 271 if (iph->iph_sock6 != -1) 272 (void) close(iph->iph_sock6); 273 if (iph->iph_rtsock != -1) 274 (void) close(iph->iph_rtsock); 275 if (iph->iph_door_fd != -1) 276 (void) close(iph->iph_door_fd); 277 dladm_close(iph->iph_dlh); 278 (void) pthread_mutex_destroy(&iph->iph_lock); 279 free(iph); 280 } 281 282 /* 283 * Checks if the caller has the authorization to configure network 284 * interfaces. 285 */ 286 boolean_t 287 ipadm_check_auth(void) 288 { 289 struct passwd pwd; 290 char buf[NSS_BUFLEN_PASSWD]; 291 292 /* get the password entry for the given user ID */ 293 if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL) 294 return (B_FALSE); 295 296 /* check for presence of given authorization */ 297 return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0); 298 } 299 300 /* 301 * Stores the index value of the interface in `ifname' for the address 302 * family `af' into the buffer pointed to by `index'. 303 */ 304 static ipadm_status_t 305 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af, 306 int *index) 307 { 308 struct lifreq lifr; 309 int sock; 310 311 bzero(&lifr, sizeof (lifr)); 312 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 313 if (af == AF_INET) 314 sock = iph->iph_sock; 315 else 316 sock = iph->iph_sock6; 317 318 if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0) 319 return (ipadm_errno2status(errno)); 320 *index = lifr.lifr_index; 321 322 return (IPADM_SUCCESS); 323 } 324 325 /* 326 * Maximum amount of time (in milliseconds) to wait for Duplicate Address 327 * Detection to complete in the kernel. 328 */ 329 #define DAD_WAIT_TIME 1000 330 331 /* 332 * Any time that flags are changed on an interface where either the new or the 333 * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to 334 * announce the new address added and its flag status. 335 * We wait here for that message and look for IFF_UP. 336 * If something's amiss with the kernel, though, we don't wait forever. 337 * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see 338 * it in the routing socket messages.) 339 */ 340 static ipadm_status_t 341 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af, 342 int rtsock) 343 { 344 struct pollfd fds[1]; 345 union { 346 struct if_msghdr ifm; 347 char buf[1024]; 348 } msg; 349 int index; 350 ipadm_status_t retv; 351 uint64_t flags; 352 hrtime_t starttime, now; 353 354 fds[0].fd = rtsock; 355 fds[0].events = POLLIN; 356 fds[0].revents = 0; 357 358 retv = i_ipadm_get_index(handle, lifname, af, &index); 359 if (retv != IPADM_SUCCESS) 360 return (retv); 361 362 starttime = gethrtime(); 363 for (;;) { 364 now = gethrtime(); 365 now = (now - starttime) / 1000000; 366 if (now >= DAD_WAIT_TIME) 367 break; 368 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0) 369 break; 370 if (read(rtsock, &msg, sizeof (msg)) <= 0) 371 break; 372 if (msg.ifm.ifm_type != RTM_NEWADDR) 373 continue; 374 /* Note that ifm_index is just 16 bits */ 375 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP)) 376 return (IPADM_SUCCESS); 377 } 378 379 retv = i_ipadm_get_flags(handle, lifname, af, &flags); 380 if (retv != IPADM_SUCCESS) 381 return (retv); 382 if (flags & IFF_DUPLICATE) 383 return (IPADM_DAD_FOUND); 384 385 return (IPADM_SUCCESS); 386 } 387 388 /* 389 * Sets the flags `on_flags' and resets the flags `off_flags' for the logical 390 * interface in `lifname'. 391 * 392 * If the new flags value will transition the interface from "down" to "up" 393 * then duplicate address detection is performed by the kernel. This routine 394 * waits to get the outcome of that test. 395 */ 396 ipadm_status_t 397 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af, 398 uint64_t on_flags, uint64_t off_flags) 399 { 400 struct lifreq lifr; 401 uint64_t oflags; 402 ipadm_status_t ret; 403 int rtsock = -1; 404 int sock, err; 405 406 ret = i_ipadm_get_flags(iph, lifname, af, &oflags); 407 if (ret != IPADM_SUCCESS) 408 return (ret); 409 410 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 411 412 /* 413 * Any time flags are changed on an interface that has IFF_UP set, 414 * we get a routing socket message. We care about the status, 415 * though, only when the new flags are marked "up." 416 */ 417 if (!(oflags & IFF_UP) && (on_flags & IFF_UP)) 418 rtsock = socket(PF_ROUTE, SOCK_RAW, af); 419 420 oflags |= on_flags; 421 oflags &= ~off_flags; 422 bzero(&lifr, sizeof (lifr)); 423 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 424 lifr.lifr_flags = oflags; 425 if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 426 err = errno; 427 if (rtsock != -1) 428 (void) close(rtsock); 429 return (ipadm_errno2status(err)); 430 } 431 if (rtsock == -1) { 432 return (IPADM_SUCCESS); 433 } else { 434 /* Wait for DAD to complete. */ 435 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock); 436 (void) close(rtsock); 437 return (ret); 438 } 439 } 440 441 /* 442 * Returns the flags value for the logical interface in `lifname' 443 * in the buffer pointed to by `flags'. 444 */ 445 ipadm_status_t 446 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af, 447 uint64_t *flags) 448 { 449 struct lifreq lifr; 450 int sock; 451 452 bzero(&lifr, sizeof (lifr)); 453 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 454 if (af == AF_INET) 455 sock = iph->iph_sock; 456 else 457 sock = iph->iph_sock6; 458 459 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 460 return (ipadm_errno2status(errno)); 461 } 462 *flags = lifr.lifr_flags; 463 464 return (IPADM_SUCCESS); 465 } 466 467 /* 468 * Determines whether or not an interface name represents a loopback 469 * interface, before the interface has been plumbed. 470 * It is assumed that the interface name in `ifname' is of correct format 471 * as verified by ifparse_ifspec(). 472 * 473 * Returns: B_TRUE if loopback, B_FALSE if not. 474 */ 475 boolean_t 476 i_ipadm_is_loopback(const char *ifname) 477 { 478 int len = strlen(LOOPBACK_IF); 479 480 return (strncmp(ifname, LOOPBACK_IF, len) == 0 && 481 (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP)); 482 } 483 484 /* 485 * Determines whether or not an interface name represents a vni 486 * interface, before the interface has been plumbed. 487 * It is assumed that the interface name in `ifname' is of correct format 488 * as verified by ifparse_ifspec(). 489 * 490 * Returns: B_TRUE if vni, B_FALSE if not. 491 */ 492 boolean_t 493 i_ipadm_is_vni(const char *ifname) 494 { 495 ifspec_t ifsp; 496 497 return (ifparse_ifspec(ifname, &ifsp) && 498 strcmp(ifsp.ifsp_devnm, "vni") == 0); 499 } 500 501 /* 502 * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel. 503 */ 504 boolean_t 505 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname) 506 { 507 dladm_status_t dlstatus; 508 datalink_class_t class; 509 iptun_params_t params; 510 datalink_id_t linkid; 511 512 if (iph->iph_dlh == NULL) { 513 assert(iph->iph_zoneid != GLOBAL_ZONEID); 514 return (B_FALSE); 515 } 516 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL, 517 &class, NULL); 518 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) { 519 params.iptun_param_linkid = linkid; 520 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms, 521 DLADM_OPT_ACTIVE); 522 if (dlstatus == DLADM_STATUS_OK && 523 params.iptun_param_type == IPTUN_TYPE_6TO4) { 524 return (B_TRUE); 525 } 526 } 527 return (B_FALSE); 528 } 529 530 /* 531 * For a given interface name, ipadm_if_enabled() checks if v4 532 * or v6 or both IP interfaces exist in the active configuration. 533 */ 534 boolean_t 535 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af) 536 { 537 struct lifreq lifr; 538 int s4 = iph->iph_sock; 539 int s6 = iph->iph_sock6; 540 541 bzero(&lifr, sizeof (lifr)); 542 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 543 switch (af) { 544 case AF_INET: 545 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) 546 return (B_TRUE); 547 break; 548 case AF_INET6: 549 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) 550 return (B_TRUE); 551 break; 552 case AF_UNSPEC: 553 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 || 554 ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) { 555 return (B_TRUE); 556 } 557 } 558 return (B_FALSE); 559 } 560 561 /* 562 * Apply the interface property by retrieving information from nvl. 563 */ 564 static ipadm_status_t 565 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl) 566 { 567 nvpair_t *nvp; 568 char *name, *pname = NULL; 569 char *protostr = NULL, *ifname = NULL, *pval = NULL; 570 uint_t proto; 571 int err = 0; 572 573 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 574 nvp = nvlist_next_nvpair(nvl, nvp)) { 575 name = nvpair_name(nvp); 576 if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 577 if ((err = nvpair_value_string(nvp, &ifname)) != 0) 578 break; 579 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) { 580 if ((err = nvpair_value_string(nvp, &protostr)) != 0) 581 break; 582 } else { 583 assert(!IPADM_PRIV_NVP(name)); 584 pname = name; 585 if ((err = nvpair_value_string(nvp, &pval)) != 0) 586 break; 587 } 588 } 589 if (err != 0) 590 return (ipadm_errno2status(err)); 591 proto = ipadm_str2proto(protostr); 592 return (ipadm_set_ifprop(iph, ifname, pname, pval, proto, 593 IPADM_OPT_ACTIVE)); 594 } 595 596 /* 597 * Instantiate the address object or set the address object property by 598 * retrieving the configuration from the nvlist `nvl'. 599 */ 600 ipadm_status_t 601 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl) 602 { 603 nvpair_t *nvp; 604 char *name; 605 char *aobjname = NULL, *pval = NULL, *ifname = NULL; 606 sa_family_t af = AF_UNSPEC; 607 ipadm_addr_type_t atype = IPADM_ADDR_NONE; 608 int err = 0; 609 ipadm_status_t status = IPADM_SUCCESS; 610 611 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 612 nvp = nvlist_next_nvpair(nvl, nvp)) { 613 name = nvpair_name(nvp); 614 if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 615 if ((err = nvpair_value_string(nvp, &ifname)) != 0) 616 break; 617 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 618 if ((err = nvpair_value_string(nvp, &aobjname)) != 0) 619 break; 620 } else if (i_ipadm_name2atype(name, &af, &atype)) { 621 break; 622 } else { 623 assert(!IPADM_PRIV_NVP(name)); 624 err = nvpair_value_string(nvp, &pval); 625 break; 626 } 627 } 628 if (err != 0) 629 return (ipadm_errno2status(err)); 630 631 switch (atype) { 632 case IPADM_ADDR_STATIC: 633 status = i_ipadm_enable_static(iph, ifname, nvl, af); 634 break; 635 case IPADM_ADDR_DHCP: 636 status = i_ipadm_enable_dhcp(iph, ifname, nvl); 637 if (status == IPADM_DHCP_IPC_TIMEOUT) 638 status = IPADM_SUCCESS; 639 break; 640 case IPADM_ADDR_IPV6_ADDRCONF: 641 status = i_ipadm_enable_addrconf(iph, ifname, nvl); 642 break; 643 case IPADM_ADDR_NONE: 644 status = ipadm_set_addrprop(iph, name, pval, aobjname, 645 IPADM_OPT_ACTIVE); 646 break; 647 } 648 649 return (status); 650 } 651 652 /* 653 * Instantiate the interface object by retrieving the configuration from 654 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration 655 * (interface properties and address objects on that interface) for the 656 * given `ifname'. 657 */ 658 ipadm_status_t 659 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl) 660 { 661 nvlist_t *nvl = NULL; 662 nvpair_t *nvp; 663 ipadm_status_t status = IPADM_ENXIO; 664 ipadm_status_t ret_status = IPADM_SUCCESS; 665 char newifname[LIFNAMSIZ]; 666 char *aobjstr; 667 uint16_t *afs; 668 char *gifname; 669 uint_t nelem = 0; 670 boolean_t init_from_gz = B_FALSE; 671 boolean_t move_to_group = B_FALSE; 672 673 (void) strlcpy(newifname, ifname, sizeof (newifname)); 674 675 /* 676 * First go through the ifnvl nvlist looking for nested nvlist 677 * containing interface class and address families. 678 */ 679 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL; 680 nvp = nvlist_next_nvpair(ifnvl, nvp)) { 681 char *icstr; 682 char **mifnames; 683 uint32_t ipadm_flags = IPADM_OPT_ACTIVE; 684 685 if (nvpair_value_nvlist(nvp, &nvl) != 0 || 686 nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES, 687 &afs, &nelem) != 0) 688 continue; 689 690 /* Check if this is IPMP group interface */ 691 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS, 692 &icstr) == 0 && atoi(icstr) == IPADM_IF_CLASS_IPMP) 693 ipadm_flags |= IPADM_OPT_IPMP; 694 695 /* Create interfaces for address families specified */ 696 while (nelem-- > 0) { 697 uint16_t af = afs[nelem]; 698 699 assert(af == AF_INET || af == AF_INET6); 700 701 status = i_ipadm_plumb_if(iph, newifname, af, 702 ipadm_flags); 703 if (status == IPADM_IF_EXISTS) 704 status = IPADM_SUCCESS; 705 if (status != IPADM_SUCCESS) 706 return (status); 707 } 708 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME, 709 &gifname) == 0) { 710 /* 711 * IPMP underlying interface. Move to the 712 * specified IPMP group. 713 */ 714 move_to_group = B_TRUE; 715 } else if ((ipadm_flags & IPADM_OPT_IPMP) && 716 nvlist_lookup_string_array(nvl, IPADM_NVP_MIFNAMES, 717 &mifnames, &nelem) == 0) { 718 /* Non-empty IPMP group interface */ 719 while (nelem-- > 0) { 720 (void) ipadm_add_ipmp_member(iph, newifname, 721 mifnames[nelem], IPADM_OPT_ACTIVE); 722 } 723 } 724 if (iph->iph_zoneid != GLOBAL_ZONEID) 725 init_from_gz = B_TRUE; 726 } 727 728 if (status != IPADM_SUCCESS) 729 return (status); 730 731 /* 732 * Go through the ifnvl nvlist again, applying persistent configuration. 733 */ 734 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL; 735 nvp = nvlist_next_nvpair(ifnvl, nvp)) { 736 if (nvpair_value_nvlist(nvp, &nvl) != 0) 737 continue; 738 if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME, 739 &aobjstr) == 0) { 740 /* 741 * For addresses, we need to relocate addrprops from the 742 * nvlist `ifnvl'. 743 */ 744 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) || 745 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) || 746 nvlist_exists(nvl, IPADM_NVP_DHCP)) { 747 status = i_ipadm_merge_addrprops_from_nvl(ifnvl, 748 nvl, aobjstr); 749 750 if (status != IPADM_SUCCESS) 751 continue; 752 } 753 status = i_ipadm_init_addrobj(iph, nvl); 754 755 /* 756 * If this address is in use on some other interface, 757 * we want to record an error to be returned as 758 * a soft error and continue processing the rest of 759 * the addresses. 760 */ 761 if (status == IPADM_ADDR_NOTAVAIL) { 762 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED; 763 status = IPADM_SUCCESS; 764 } 765 } else if (nvlist_exists(nvl, IPADM_NVP_PROTONAME) == B_TRUE) { 766 status = i_ipadm_init_ifprop(iph, nvl); 767 } 768 if (status != IPADM_SUCCESS) 769 return (status); 770 } 771 if (move_to_group) { 772 (void) ipadm_add_ipmp_member(iph, gifname, newifname, 773 IPADM_OPT_ACTIVE); 774 } 775 if (init_from_gz) 776 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL); 777 return (ret_status); 778 } 779 780 /* 781 * Retrieves the persistent configuration for the given interface(s) in `ifs' 782 * by contacting the daemon and dumps the information in `allifs'. 783 */ 784 ipadm_status_t 785 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs) 786 { 787 nvlist_t *nvl = NULL; 788 size_t nvlsize, bufsize; 789 ipmgmt_initif_arg_t *iargp; 790 char *buf = NULL, *nvlbuf = NULL; 791 ipmgmt_get_rval_t *rvalp = NULL; 792 int err; 793 ipadm_status_t status = IPADM_SUCCESS; 794 795 status = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL); 796 if (status != IPADM_SUCCESS) 797 return (status); 798 799 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0); 800 if (err != 0) { 801 status = ipadm_errno2status(err); 802 goto done; 803 } 804 bufsize = sizeof (*iargp) + nvlsize; 805 if ((buf = malloc(bufsize)) == NULL) { 806 status = ipadm_errno2status(errno); 807 goto done; 808 } 809 810 /* populate the door_call argument structure */ 811 iargp = (void *)buf; 812 iargp->ia_cmd = IPMGMT_CMD_INITIF; 813 iargp->ia_flags = 0; 814 iargp->ia_family = AF_UNSPEC; 815 iargp->ia_nvlsize = nvlsize; 816 (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize); 817 818 if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) { 819 status = ipadm_errno2status(errno); 820 goto done; 821 } 822 if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp, 823 sizeof (*rvalp), B_TRUE)) != 0) { 824 status = ipadm_errno2status(err); 825 goto done; 826 } 827 828 /* 829 * Daemon reply pointed to by rvalp contains ipmgmt_get_rval_t structure 830 * followed by a list of packed nvlists, each of which represents 831 * configuration information for the given interface(s). 832 */ 833 err = nvlist_unpack((char *)rvalp + sizeof (ipmgmt_get_rval_t), 834 rvalp->ir_nvlsize, allifs, 0); 835 if (err != 0) 836 status = ipadm_errno2status(err); 837 done: 838 nvlist_free(nvl); 839 free(buf); 840 free(nvlbuf); 841 free(rvalp); 842 return (status); 843 } 844 845 /* 846 * Returns B_FALSE if 847 * (1) `ifname' is NULL or has no string or has a string of invalid length 848 * (2) ifname is a logical interface and IPH_LEGACY is not set, or 849 */ 850 boolean_t 851 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname) 852 { 853 ifspec_t ifsp; 854 855 if (ifname == NULL || ifname[0] == '\0' || 856 !ifparse_ifspec(ifname, &ifsp)) 857 return (B_FALSE); 858 if (ifsp.ifsp_lunvalid) 859 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY)); 860 return (B_TRUE); 861 } 862 863 /* 864 * Wrapper for sending a non-transparent I_STR ioctl(). 865 * Returns: Result from ioctl(). 866 */ 867 int 868 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen) 869 { 870 struct strioctl ioc; 871 872 (void) memset(&ioc, 0, sizeof (ioc)); 873 ioc.ic_cmd = cmd; 874 ioc.ic_timout = 0; 875 ioc.ic_len = buflen; 876 ioc.ic_dp = buf; 877 878 return (ioctl(s, I_STR, (char *)&ioc)); 879 } 880 881 /* 882 * Make a door call to the server and checks if the door call succeeded or not. 883 * `is_varsize' specifies that the data returned by ipmgmtd daemon is of 884 * variable size and door will allocate buffer using mmap(). In such cases 885 * we re-allocate the required memory,n assign it to `rbufp', copy the data to 886 * `rbufp' and then call munmap() (see below). 887 * 888 * It also checks to see if the server side procedure ran successfully by 889 * checking for ir_err. Therefore, for some callers who just care about the 890 * return status can set `rbufp' to NULL and set `rsize' to 0. 891 */ 892 int 893 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp, 894 size_t rsize, boolean_t is_varsize) 895 { 896 door_arg_t darg; 897 int err; 898 ipmgmt_retval_t rval, *rvalp; 899 boolean_t reopen = B_FALSE; 900 901 if (rbufp == NULL) { 902 rvalp = &rval; 903 rbufp = (void **)&rvalp; 904 rsize = sizeof (rval); 905 } 906 907 darg.data_ptr = arg; 908 darg.data_size = asize; 909 darg.desc_ptr = NULL; 910 darg.desc_num = 0; 911 darg.rbuf = *rbufp; 912 darg.rsize = rsize; 913 914 reopen: 915 (void) pthread_mutex_lock(&iph->iph_lock); 916 /* The door descriptor is opened if it isn't already */ 917 if (iph->iph_door_fd == -1) { 918 if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) { 919 err = errno; 920 (void) pthread_mutex_unlock(&iph->iph_lock); 921 return (err); 922 } 923 } 924 (void) pthread_mutex_unlock(&iph->iph_lock); 925 926 if (door_call(iph->iph_door_fd, &darg) == -1) { 927 /* 928 * Stale door descriptor is possible if ipmgmtd was restarted 929 * since last iph_door_fd was opened, so try re-opening door 930 * descriptor. 931 */ 932 if (!reopen && errno == EBADF) { 933 (void) close(iph->iph_door_fd); 934 iph->iph_door_fd = -1; 935 reopen = B_TRUE; 936 goto reopen; 937 } 938 return (errno); 939 } 940 err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err; 941 if (darg.rbuf != *rbufp) { 942 /* 943 * if the caller is expecting the result to fit in specified 944 * buffer then return failure. 945 */ 946 if (!is_varsize) 947 err = EBADE; 948 /* 949 * The size of the buffer `*rbufp' was not big enough 950 * and the door itself allocated buffer, for us. We will 951 * hit this, on several occasion as for some cases 952 * we cannot predict the size of the return structure. 953 * Reallocate the buffer `*rbufp' and memcpy() the contents 954 * to new buffer. 955 */ 956 if (err == 0) { 957 void *newp; 958 959 /* allocated memory will be freed by the caller */ 960 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) { 961 err = ENOMEM; 962 } else { 963 *rbufp = newp; 964 (void) memcpy(*rbufp, darg.rbuf, darg.rsize); 965 } 966 } 967 /* munmap() the door buffer */ 968 (void) munmap(darg.rbuf, darg.rsize); 969 } else { 970 if (darg.rsize != rsize) 971 err = EBADE; 972 } 973 return (err); 974 } 975 976 /* 977 * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if 978 * to do a door_call to ipmgmtd, that should return persistent information 979 * about interfaces or/and addresses from ipadm DB 980 */ 981 ipadm_status_t 982 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg, size_t garg_size, 983 nvlist_t **onvl) 984 { 985 ipmgmt_get_rval_t *rvalp; 986 int err; 987 size_t nvlsize; 988 char *nvlbuf; 989 990 rvalp = malloc(sizeof (ipmgmt_get_rval_t)); 991 if (rvalp == NULL) 992 return (IPADM_NO_MEMORY); 993 994 err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp, 995 sizeof (*rvalp), B_TRUE); 996 if (err == 0) { 997 nvlsize = rvalp->ir_nvlsize; 998 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t); 999 err = nvlist_unpack(nvlbuf, nvlsize, onvl, 0); 1000 } 1001 free(rvalp); 1002 1003 return (ipadm_errno2status(err)); 1004 } 1005 1006 /* 1007 * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e., 1008 * NULL, empty, or a single space (e.g., as returned by 1009 * domainname(8)/sysinfo). 1010 * 1011 * input: const char *: the hostname to inspect; 1012 * output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the 1013 * criteria above; otherwise, B_FALSE; 1014 */ 1015 1016 boolean_t 1017 ipadm_is_nil_hostname(const char *hostname) 1018 { 1019 return (hostname == NULL || *hostname == '\0' || 1020 (*hostname == ' ' && hostname[1] == '\0')); 1021 } 1022 1023 /* 1024 * ipadm_is_valid_hostname(): check whether a string is a valid hostname 1025 * 1026 * input: const char *: the string to verify as a hostname 1027 * output: boolean_t: B_TRUE if the string is a valid hostname 1028 * 1029 * Note that we accept host names beginning with a digit, which is not 1030 * strictly legal according to the RFCs but is in common practice, so we 1031 * endeavour to not break what customers are using. 1032 * 1033 * RFC 1035 limits a wire-format domain name to 255 octets. For a printable 1034 * `hostname' as we have, the limit is therefore 253 characters (excluding 1035 * the terminating '\0'--or 254 characters if the last character of 1036 * `hostname' is a '.'. 1037 * 1038 * Excerpt from section 2.3.1., Preferred name syntax: 1039 * 1040 * <domain> ::= <subdomain> | " " 1041 * <subdomain> ::= <label> | <subdomain> "." <label> 1042 * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] 1043 * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> 1044 * <let-dig-hyp> ::= <let-dig> | "-" 1045 * <let-dig> ::= <letter> | <digit> 1046 */ 1047 boolean_t 1048 ipadm_is_valid_hostname(const char *hostname) 1049 { 1050 const size_t MAX_READABLE_NAME_LEN = 253; 1051 char last_char; 1052 size_t has_last_dot, namelen, i; 1053 1054 if (hostname == NULL) 1055 return (B_FALSE); 1056 1057 namelen = strlen(hostname); 1058 if (namelen < 1) 1059 return (B_FALSE); 1060 1061 last_char = hostname[namelen - 1]; 1062 has_last_dot = last_char == '.'; 1063 1064 if (namelen > MAX_READABLE_NAME_LEN + has_last_dot || 1065 last_char == '-') 1066 return (B_FALSE); 1067 1068 for (i = 0; hostname[i] != '\0'; i++) { 1069 /* 1070 * As noted above, this deviates from RFC 1035 in that it 1071 * allows a leading digit. 1072 */ 1073 if (isalpha(hostname[i]) || isdigit(hostname[i]) || 1074 (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0))) 1075 continue; 1076 1077 return (B_FALSE); 1078 } 1079 1080 return (B_TRUE); 1081 } 1082