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 2015 Joyent, Inc.
  24  */
  25 
  26 /*
  27  * lxinit performs zone-specific initialization prior to handing control to the
  28  * guest Linux init.  This primarily consists of:
  29  *
  30  * - Starting ipmgmtd
  31  * - Configuring network interfaces
  32  * - Adding a default route
  33  */
  34 
  35 #include <ctype.h>
  36 #include <errno.h>
  37 #include <fcntl.h>
  38 #include <libgen.h>
  39 #include <limits.h>
  40 #include <net/if.h>
  41 #include <stdarg.h>
  42 #include <stdio.h>
  43 #include <stdlib.h>
  44 #include <string.h>
  45 #include <strings.h>
  46 #include <stropts.h>
  47 #include <sys/ioccom.h>
  48 #include <sys/stat.h>
  49 #include <sys/systeminfo.h>
  50 #include <sys/sockio.h>
  51 #include <sys/types.h>
  52 #include <sys/wait.h>
  53 #include <sys/varargs.h>
  54 #include <unistd.h>
  55 #include <libintl.h>
  56 #include <locale.h>
  57 #include <libcmdutils.h>
  58 
  59 #include <netinet/dhcp.h>
  60 #include <dhcpagent_util.h>
  61 #include <dhcpagent_ipc.h>
  62 
  63 #include <arpa/inet.h>
  64 #include <net/route.h>
  65 #include <libipadm.h>
  66 #include <libzonecfg.h>
  67 #include <libinetutil.h>
  68 #include <sys/lx_brand.h>
  69 
  70 #include "run_command.h"
  71 
  72 static void lxi_err(char *msg, ...) __NORETURN;
  73 static void lxi_err(char *msg, ...);
  74 
  75 #define IPMGMTD_PATH    "/lib/inet/ipmgmtd"
  76 #define IN_NDPD_PATH    "/usr/lib/inet/in.ndpd"
  77 
  78 #define PREFIX_LOG_WARN "lx_init warn: "
  79 #define PREFIX_LOG_ERR  "lx_init err: "
  80 
  81 #define RTMBUFSZ        (sizeof (struct rt_msghdr) + \
  82                 (3 * sizeof (struct sockaddr_in)))
  83 
  84 ipadm_handle_t iph;
  85 
  86 static void
  87 lxi_err(char *msg, ...)
  88 {
  89         char buf[1024];
  90         int len;
  91         va_list ap;
  92 
  93         va_start(ap, msg);
  94         /*LINTED*/
  95         len = vsnprintf(buf, sizeof (buf), msg, ap);
  96         va_end(ap);
  97 
  98         (void) write(1, PREFIX_LOG_ERR, strlen(PREFIX_LOG_ERR));
  99         (void) write(1, buf, len);
 100         (void) write(1, "\n", 1);
 101 
 102         /*
 103          * Since a non-zero exit will cause the zone to reboot, a pause here
 104          * will prevent a mis-configured zone from spinning in a reboot loop.
 105          */
 106         pause();
 107         exit(1);
 108         /*NOTREACHED*/
 109 }
 110 
 111 static void
 112 lxi_warn(char *msg, ...)
 113 {
 114         char buf[1024];
 115         int len;
 116         va_list ap;
 117 
 118         va_start(ap, msg);
 119         /*LINTED*/
 120         len = vsnprintf(buf, sizeof (buf), msg, ap);
 121         va_end(ap);
 122 
 123         (void) write(1, PREFIX_LOG_WARN, strlen(PREFIX_LOG_WARN));
 124         (void) write(1, buf, len);
 125         (void) write(1, "\n", 1);
 126 }
 127 
 128 static void
 129 lxi_log_open()
 130 {
 131         int fd = open("/dev/console", O_WRONLY);
 132 
 133         if (fd < 0) {
 134                 /* hard to log at this point... */
 135                 exit(1);
 136         } else if (fd != 1) {
 137                 /*
 138                  * Use stdout as the log fd.  Init should start with no files
 139                  * open, so we should be required to perform this relocation
 140                  * every time.
 141                  */
 142                 if (dup2(fd, 1) != 1) {
 143                         exit(1);
 144                 }
 145         }
 146 }
 147 
 148 static void
 149 lxi_log_close()
 150 {
 151         (void) close(0);
 152         (void) close(1);
 153 }
 154 
 155 static zone_dochandle_t
 156 lxi_config_open()
 157 {
 158         zoneid_t zoneid;
 159         char zonename[ZONENAME_MAX];
 160         zone_dochandle_t handle;
 161         zone_iptype_t iptype;
 162         int res;
 163 
 164         zoneid = getzoneid();
 165         if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) < 0) {
 166                 lxi_err("could not determine zone name");
 167         }
 168 
 169         if ((handle = zonecfg_init_handle()) == NULL)
 170                 lxi_err("internal libzonecfg.so.1 error", 0);
 171 
 172         if ((res = zonecfg_get_handle(zonename, handle)) != Z_OK) {
 173                 zonecfg_fini_handle(handle);
 174                 lxi_err("could not locate zone config %d", res);
 175         }
 176 
 177         /*
 178          * Only exclusive stack is supported.
 179          */
 180         if (zonecfg_get_iptype(handle, &iptype) != Z_OK ||
 181             iptype != ZS_EXCLUSIVE) {
 182                 zonecfg_fini_handle(handle);
 183                 lxi_err("lx zones do not support shared IP stacks");
 184         }
 185 
 186         return (handle);
 187 
 188 }
 189 
 190 static int
 191 zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
 192     const char **result)
 193 {
 194         while (attrs != NULL) {
 195                 if (strncmp(attrs->zone_res_attr_name, name,
 196                     MAXNAMELEN) == 0) {
 197                         *result = attrs->zone_res_attr_value;
 198                         return (0);
 199                 }
 200                 attrs = attrs->zone_res_attr_next;
 201         }
 202         return (-1);
 203 }
 204 
 205 void
 206 lxi_svc_start(char *name, char *path, char *fmri)
 207 {
 208         pid_t pid;
 209         int status;
 210         char *const argv[] = {
 211                 name,
 212                 NULL
 213         };
 214         char *const envp[] = {
 215                 fmri,
 216                 NULL
 217         };
 218 
 219         pid = fork();
 220         if (pid == -1) {
 221                 lxi_err("fork() failed: %s", strerror(errno));
 222         }
 223 
 224         if (pid == 0) {
 225                 /* child */
 226                 const char *zroot = zone_get_nroot();
 227                 char cmd[MAXPATHLEN];
 228 
 229                 /*
 230                  * Construct the full path to the binary, including the native
 231                  * system root (e.g. "/native") if in use for this zone:
 232                  */
 233                 (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot != NULL ?
 234                     zroot : "", path);
 235 
 236                 execve(cmd, argv, envp);
 237 
 238                 lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
 239                 /* NOTREACHED */
 240         }
 241 
 242         /* parent */
 243         while (wait(&status) != pid) {
 244                 /* EMPTY */;
 245         }
 246 
 247         if (WIFEXITED(status)) {
 248                 if (WEXITSTATUS(status) != 0) {
 249                         lxi_err("%s[%d] exited: %d", name,
 250                             (int)pid, WEXITSTATUS(status));
 251                 }
 252         } else if (WIFSIGNALED(status)) {
 253                 lxi_err("%s[%d] died on signal: %d", name,
 254                     (int)pid, WTERMSIG(status));
 255         } else {
 256                 lxi_err("%s[%d] failed in unknown way", name,
 257                     (int)pid);
 258         }
 259 }
 260 
 261 void
 262 lxi_net_ipmgmtd_start()
 263 {
 264         lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
 265             "SMF_FMRI=svc:/network/ip-interface-management:default");
 266 }
 267 
 268 void
 269 lxi_net_ndpd_start()
 270 {
 271         lxi_svc_start("in.ndpd", IN_NDPD_PATH,
 272             "SMF_FMRI=svc:/network/routing/ndp:default");
 273 }
 274 
 275 
 276 static void
 277 lxi_net_ipadm_open()
 278 {
 279         ipadm_status_t status;
 280 
 281         if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS) {
 282                 lxi_err("Error opening ipadm handle: %s",
 283                     ipadm_status2str(status));
 284         }
 285 }
 286 
 287 static void
 288 lxi_net_ipadm_close()
 289 {
 290         ipadm_close(iph);
 291 }
 292 
 293 void
 294 lxi_net_plumb(const char *iface)
 295 {
 296         ipadm_status_t status;
 297         char ifbuf[LIFNAMSIZ];
 298 
 299         /* ipadm_create_if stomps on ifbuf, so create a copy: */
 300         (void) strncpy(ifbuf, iface, sizeof (ifbuf));
 301 
 302         if ((status = ipadm_create_if(iph, ifbuf, AF_INET, IPADM_OPT_ACTIVE))
 303             != IPADM_SUCCESS) {
 304                 lxi_err("ipadm_create_if error %d: %s/v4: %s",
 305                     status, iface, ipadm_status2str(status));
 306         }
 307 
 308         if ((status = ipadm_create_if(iph, ifbuf, AF_INET6, IPADM_OPT_ACTIVE))
 309             != IPADM_SUCCESS) {
 310                 lxi_err("ipadm_create_if error %d: %s/v6: %s",
 311                     status, iface, ipadm_status2str(status));
 312         }
 313 }
 314 
 315 static int
 316 lxi_getif(int af, char *iface, int len, boolean_t first_ipv4_configured)
 317 {
 318         struct lifreq lifr;
 319         int s = socket(af, SOCK_DGRAM, 0);
 320         if (s < 0) {
 321                 lxi_warn("socket error %d: bringing up %s: %s",
 322                     errno, iface, strerror(errno));
 323                 return (-1);
 324         }
 325 
 326         /*
 327          * We need a new logical interface for every IP address we add, except
 328          * for the very first IPv4 address.
 329          */
 330         if (af == AF_INET6 || first_ipv4_configured) {
 331                 (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
 332                 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
 333                 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
 334                         if (close(s) != 0) {
 335                                 lxi_warn("failed to close socket: %s\n",
 336                                     strerror(errno));
 337                         }
 338                         return (-1);
 339                 }
 340                 (void) strncpy(iface, lifr.lifr_name, len);
 341         }
 342 
 343         if (close(s) != 0) {
 344                 lxi_warn("failed to close socket: %s\n",
 345                     strerror(errno));
 346         }
 347         return (0);
 348 }
 349 
 350 static int
 351 lxi_iface_ip(const char *origiface, const char *addr,
 352     boolean_t *first_ipv4_configured)
 353 {
 354         static int addrnum = 0;
 355         ipadm_status_t status;
 356         ipadm_addrobj_t ipaddr = NULL;
 357         char iface[LIFNAMSIZ];
 358         char aobjname[IPADM_AOBJSIZ];
 359         int af, err = 0;
 360 
 361         (void) strncpy(iface, origiface, sizeof (iface));
 362 
 363         af = strstr(addr, ":") == NULL ? AF_INET : AF_INET6;
 364         if (lxi_getif(af, iface, sizeof (iface), *first_ipv4_configured) != 0) {
 365                 lxi_warn("failed to create new logical interface "
 366                     "on %s: %s", origiface, strerror(errno));
 367                 return (-1);
 368         }
 369 
 370         (void) snprintf(aobjname, IPADM_AOBJSIZ, "%s/addr%d", iface,
 371             addrnum++);
 372 
 373         if ((status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname,
 374             &ipaddr)) != IPADM_SUCCESS) {
 375                 lxi_warn("ipadm_create_addrobj error %d: addr %s, "
 376                     "interface %s: %s\n", status, addr, iface,
 377                     ipadm_status2str(status));
 378                 return (-2);
 379         }
 380 
 381         if ((status = ipadm_set_addr(ipaddr, addr, AF_UNSPEC))
 382             != IPADM_SUCCESS) {
 383                 lxi_warn("ipadm_set_addr error %d: addr %s"
 384                     ", interface %s: %s\n", status, addr,
 385                     iface, ipadm_status2str(status));
 386                 err = -3;
 387                 goto done;
 388         }
 389 
 390         if ((status = ipadm_create_addr(iph, ipaddr,
 391             IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
 392                 lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
 393                     ipadm_status2str(status));
 394                 err = -4;
 395                 goto done;
 396         }
 397 
 398         if (af == AF_INET) {
 399                 *first_ipv4_configured = B_TRUE;
 400         }
 401 
 402 done:
 403         ipadm_destroy_addrobj(ipaddr);
 404         return (err);
 405 }
 406 
 407 static int
 408 lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
 409 {
 410         dhcp_ipc_request_t *dhcpreq = NULL;
 411         dhcp_ipc_reply_t *dhcpreply = NULL;
 412         int err = 0, timeout = 5;
 413         char iface[LIFNAMSIZ];
 414 
 415         (void) strncpy(iface, origiface, sizeof (iface));
 416 
 417         if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
 418             != 0) {
 419                 lxi_warn("failed to create new logical interface "
 420                     "on %s: %s", origiface, strerror(errno));
 421                 return (-1);
 422         }
 423 
 424         if (dhcp_start_agent(timeout) != 0) {
 425                 lxi_err("Failed to start dhcpagent\n");
 426                 /* NOTREACHED */
 427         }
 428 
 429         dhcpreq = dhcp_ipc_alloc_request(DHCP_START, iface,
 430             NULL, 0, DHCP_TYPE_NONE);
 431         if (dhcpreq == NULL) {
 432                 lxi_warn("Unable to allocate memory "
 433                     "to start DHCP on %s\n", iface);
 434                 return (-1);
 435         }
 436 
 437         err = dhcp_ipc_make_request(dhcpreq, &dhcpreply, timeout);
 438         if (err != 0) {
 439                 free(dhcpreq);
 440                 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
 441                     dhcp_ipc_strerror(err));
 442                 return (-1);
 443         }
 444         err = dhcpreply->return_code;
 445         if (err != 0) {
 446                 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
 447                     dhcp_ipc_strerror(err));
 448                 goto done;
 449         }
 450 
 451         *first_ipv4_configured = B_TRUE;
 452 
 453 done:
 454         free(dhcpreq);
 455         free(dhcpreply);
 456         return (err);
 457 }
 458 
 459 /*
 460  * Initialize an IPv6 link-local address on a given interface
 461  */
 462 static int
 463 lxi_iface_ipv6_link_local(const char *iface)
 464 {
 465         struct lifreq lifr;
 466         int s;
 467 
 468         s = socket(AF_INET6, SOCK_DGRAM, 0);
 469         if (s == -1) {
 470                 lxi_warn("socket error %d: bringing up %s: %s",
 471                     errno, iface, strerror(errno));
 472         }
 473 
 474         (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
 475         if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
 476                 lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
 477                     errno, iface, strerror(errno));
 478                 return (-1);
 479         }
 480 
 481         lifr.lifr_flags |= IFF_UP;
 482         if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 483                 lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
 484                     errno, iface, strerror(errno));
 485                 return (-1);
 486         }
 487 
 488         (void) close(s);
 489         return (0);
 490 }
 491 
 492 static int
 493 lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
 494     const char *gwaddr)
 495 {
 496         int idx, len, sockfd;
 497         char rtbuf[RTMBUFSZ];
 498         struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
 499         struct sockaddr_in *dst_sin = (struct sockaddr_in *)
 500             (rtbuf + sizeof (struct rt_msghdr));
 501         struct sockaddr_in *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
 502         struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
 503 
 504         (void) bzero(rtm, RTMBUFSZ);
 505         rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 506         rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
 507         rtm->rtm_msglen = sizeof (rtbuf);
 508         rtm->rtm_pid = getpid();
 509         rtm->rtm_type = RTM_ADD;
 510         rtm->rtm_version = RTM_VERSION;
 511 
 512 
 513         /*
 514          * The destination and netmask components have already been zeroed,
 515          * which represents the default gateway.  If we were passed a more
 516          * specific destination network, use that instead.
 517          */
 518         dst_sin->sin_family = AF_INET;
 519         netmask_sin->sin_family = AF_INET;
 520         if (dst != NULL) {
 521                 struct sockaddr *mask = (struct sockaddr *)netmask_sin;
 522 
 523                 if ((inet_pton(AF_INET, dst, &(dst_sin->sin_addr))) != 1 ||
 524                     plen2mask(dstpfx, AF_INET, mask) != 0) {
 525                         lxi_warn("bad destination network %s/%d: %s", dst,
 526                             dstpfx, strerror(errno));
 527                         return (-1);
 528                 }
 529         }
 530 
 531         if ((inet_pton(AF_INET, gwaddr, &(gw_sin->sin_addr))) != 1) {
 532                 lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
 533                 return (-1);
 534         }
 535 
 536         if (iface != NULL) {
 537                 if ((idx = if_nametoindex(iface)) == 0) {
 538                         lxi_warn("unable to get interface index for %s: %s\n",
 539                             iface, strerror(errno));
 540                         return (-1);
 541                 }
 542                 rtm->rtm_index = idx;
 543         }
 544 
 545         if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
 546                 lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
 547                 return (-1);
 548         }
 549 
 550         if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
 551                 lxi_warn("could not write rtmsg: %s", strerror(errno));
 552                 close(sockfd);
 553                 return (-1);
 554         } else if (len < rtm->rtm_msglen) {
 555                 lxi_warn("write() rtmsg incomplete");
 556                 close(sockfd);
 557                 return (-1);
 558         }
 559 
 560         close(sockfd);
 561         return (0);
 562 }
 563 
 564 static void
 565 lxi_net_loopback()
 566 {
 567         const char *iface = "lo0";
 568         boolean_t first_ipv4_configured = B_FALSE;
 569 
 570         lxi_net_plumb(iface);
 571         (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
 572         (void) lxi_iface_ipv6_link_local(iface);
 573 }
 574 
 575 
 576 /*
 577  * This function is used when the "ips" property doesn't exist in a zone's
 578  * configuration. It may be an older configuration, so we should search for
 579  * "ip" and "netmask" and convert them into the new format.
 580  */
 581 static int
 582 lxi_get_old_ip(struct zone_res_attrtab *attrs, const char **ipaddrs,
 583     char *cidraddr, int len)
 584 {
 585 
 586         const char *netmask;
 587         int prefixlen;
 588         struct sockaddr_in mask_sin;
 589 
 590         lxi_warn("Could not find \"ips\" property for zone. Looking "
 591             "for older \"ip\" and \"netmask\" properties, instead.");
 592 
 593         if (zone_find_attr(attrs, "ip", ipaddrs) != 0) {
 594                 return (-1);
 595         }
 596 
 597         if (strcmp(*ipaddrs, "dhcp") == 0) {
 598                 return (0);
 599         }
 600 
 601         if (zone_find_attr(attrs, "netmask", &netmask) != 0) {
 602                 lxi_err("could not find netmask for interface");
 603                 /* NOTREACHED */
 604         }
 605 
 606         /* Convert the netmask to a number */
 607         mask_sin.sin_family = AF_INET;
 608         if (inet_pton(AF_INET, netmask, &mask_sin.sin_addr) != 1) {
 609                 lxi_err("invalid netmask address: %s\n",
 610                     strerror(errno));
 611                 /* NOTREACHED */
 612         }
 613         prefixlen = mask2plen((struct sockaddr *)&mask_sin);
 614 
 615         /*
 616          * Write out the IP address in the new format and use
 617          * that instead
 618          */
 619         (void) snprintf(cidraddr, len, "%s/%d", *ipaddrs, prefixlen);
 620 
 621         *ipaddrs = cidraddr;
 622         return (0);
 623 }
 624 
 625 static void
 626 lxi_net_setup(zone_dochandle_t handle)
 627 {
 628         struct zone_nwiftab lookup;
 629         boolean_t do_addrconf = B_FALSE;
 630 
 631         if (zonecfg_setnwifent(handle) != Z_OK)
 632                 return;
 633         while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
 634                 const char *iface = lookup.zone_nwif_physical;
 635                 struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
 636                 const char *ipaddrs, *primary, *gateway;
 637                 char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
 638                     *ipaddr, *tmp, *lasts;
 639                 boolean_t first_ipv4_configured = B_FALSE;
 640                 boolean_t *ficp = &first_ipv4_configured;
 641 
 642                 lxi_net_plumb(iface);
 643                 if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 &&
 644                     lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0) {
 645                         lxi_warn("Could not find a valid network configuration "
 646                             "for the %s interface", iface);
 647                         continue;
 648                 }
 649 
 650                 if (lxi_iface_ipv6_link_local(iface) != 0) {
 651                         lxi_warn("unable to bring up link-local address on "
 652                             "interface %s", iface);
 653                 }
 654 
 655                 /*
 656                  * If we're going to be doing DHCP, we have to do it first since
 657                  * dhcpagent doesn't like to operate on non-zero logical
 658                  * interfaces.
 659                  */
 660                 if (strstr(ipaddrs, "dhcp") != NULL &&
 661                     lxi_iface_dhcp(iface, ficp) != 0) {
 662                         lxi_warn("Failed to start DHCP on %s\n", iface);
 663                 }
 664 
 665                 /*
 666                  * Copy the ipaddrs string, since strtok_r will write NUL
 667                  * characters into it.
 668                  */
 669                 (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
 670                 tmp = ipaddrs_copy;
 671 
 672                 /*
 673                  * Iterate over each IP and then set it up on the interface.
 674                  */
 675                 while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
 676                         tmp = NULL;
 677                         if (strcmp(ipaddr, "addrconf") == 0) {
 678                                 do_addrconf = B_TRUE;
 679                         } else if (strcmp(ipaddr, "dhcp") == 0) {
 680                                 continue;
 681                         } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
 682                                 lxi_warn("Unable to add new IP address (%s) "
 683                                     "to interface %s", ipaddr, iface);
 684                         }
 685                 }
 686 
 687                 if (zone_find_attr(attrs, "primary", &primary) == 0 &&
 688                     strncmp(primary, "true", MAXNAMELEN) == 0 &&
 689                     zone_find_attr(attrs, "gateway", &gateway) == 0) {
 690                         lxi_iface_gateway(iface, NULL, 0, gateway);
 691                 }
 692         }
 693 
 694         if (do_addrconf) {
 695                 lxi_net_ndpd_start();
 696         }
 697 
 698         (void) zonecfg_endnwifent(handle);
 699 }
 700 
 701 static void
 702 lxi_net_static_route(const char *line)
 703 {
 704         /*
 705          * Each static route line is a string of the form:
 706          *
 707          *      "10.77.77.2|10.1.1.0/24|false"
 708          *
 709          * i.e. gateway address, destination network, and whether this is
 710          * a "link local" route or a next hop route.
 711          */
 712         custr_t *cu = NULL;
 713         char *gw = NULL, *dst = NULL;
 714         int pfx = -1;
 715         int i;
 716 
 717         if (custr_alloc(&cu) != 0) {
 718                 lxi_err("custr_alloc failure");
 719         }
 720 
 721         for (i = 0; line[i] != '\0'; i++) {
 722                 if (gw == NULL) {
 723                         if (line[i] == '|') {
 724                                 if ((gw = strdup(custr_cstr(cu))) == NULL) {
 725                                         lxi_err("strdup failure");
 726                                 }
 727                                 custr_reset(cu);
 728                         } else {
 729                                 if (custr_appendc(cu, line[i]) != 0) {
 730                                         lxi_err("custr_appendc failure");
 731                                 }
 732                         }
 733                         continue;
 734                 }
 735 
 736                 if (dst == NULL) {
 737                         if (line[i] == '/') {
 738                                 if ((dst = strdup(custr_cstr(cu))) == NULL) {
 739                                         lxi_err("strdup failure");
 740                                 }
 741                                 custr_reset(cu);
 742                         } else {
 743                                 if (custr_appendc(cu, line[i]) != 0) {
 744                                         lxi_err("custr_appendc failure");
 745                                 }
 746                         }
 747                         continue;
 748                 }
 749 
 750                 if (pfx == -1) {
 751                         if (line[i] == '|') {
 752                                 pfx = atoi(custr_cstr(cu));
 753                                 custr_reset(cu);
 754                         } else {
 755                                 if (custr_appendc(cu, line[i]) != 0) {
 756                                         lxi_err("custr_appendc failure");
 757                                 }
 758                         }
 759                         continue;
 760                 }
 761 
 762                 if (custr_appendc(cu, line[i]) != 0) {
 763                         lxi_err("custr_appendc failure");
 764                 }
 765         }
 766 
 767         /*
 768          * We currently only support "next hop" routes, so ensure that
 769          * "linklocal" is false:
 770          */
 771         if (strcmp(custr_cstr(cu), "false") != 0) {
 772                 lxi_warn("invalid static route: %s", line);
 773         }
 774 
 775         if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
 776                 lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
 777         }
 778 
 779         custr_free(cu);
 780         free(gw);
 781         free(dst);
 782 }
 783 
 784 static void
 785 lxi_net_static_routes(void)
 786 {
 787         const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
 788         char *const argv[] = { "routeinfo", NULL };
 789         char *const envp[] = { NULL };
 790         int code;
 791         struct stat st;
 792         char errbuf[512];
 793 
 794         if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
 795                 /*
 796                  * This binary is (potentially) shipped from another
 797                  * consolidation.  If it does not exist, then the platform does
 798                  * not currently support static routes for LX-branded zones.
 799                  */
 800                 return;
 801         }
 802 
 803         /*
 804          * Run the command, firing the callback for each line that it
 805          * outputs.  When this function returns, static route processing
 806          * is complete.
 807          */
 808         if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
 809             lxi_net_static_route, &code) != 0 || code != 0) {
 810                 lxi_err("failed to run \"%s\": %s", cmd, errbuf);
 811         }
 812 }
 813 
 814 static void
 815 lxi_config_close(zone_dochandle_t handle)
 816 {
 817         zonecfg_fini_handle(handle);
 818 }
 819 
 820 static void
 821 lxi_init_exec(char **argv)
 822 {
 823         const char *cmd = "/sbin/init";
 824         char *const envp[] = { "container=zone", NULL };
 825         int e;
 826 
 827         argv[0] = "init";
 828 
 829         /*
 830          * systemd uses the 'container' env var to determine it is running
 831          * inside a container. It only supports a few well-known types and
 832          * treats anything else as 'other' but this is enough to make it
 833          * behave better inside a zone. See 'detect_container' in systemd.
 834          */
 835         execve(cmd, argv, envp);
 836         e = errno;
 837 
 838         /*
 839          * Because stdout was closed prior to exec, it must be opened again in
 840          * the face of failure to log the error.
 841          */
 842         lxi_log_open();
 843         lxi_err("execve(%s) failed: %s", cmd, strerror(e));
 844 }
 845 
 846 /*ARGSUSED*/
 847 int
 848 main(int argc, char *argv[])
 849 {
 850         zone_dochandle_t handle;
 851 
 852         lxi_log_open();
 853 
 854         lxi_net_ipmgmtd_start();
 855         lxi_net_ipadm_open();
 856 
 857         handle = lxi_config_open();
 858         lxi_net_loopback();
 859         lxi_net_setup(handle);
 860         lxi_config_close(handle);
 861 
 862         lxi_net_static_routes();
 863 
 864         lxi_net_ipadm_close();
 865 
 866         lxi_log_close();
 867 
 868         lxi_init_exec(argv);
 869 
 870         /* NOTREACHED */
 871         return (0);
 872 }