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         (void) 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 #if 0 /* XXX KEBE SAYS NOT YET */
 191 static int
 192 zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
 193     const char **result)
 194 {
 195         while (attrs != NULL) {
 196                 if (strncmp(attrs->zone_res_attr_name, name,
 197                     MAXNAMELEN) == 0) {
 198                         *result = attrs->zone_res_attr_value;
 199                         return (0);
 200                 }
 201                 attrs = attrs->zone_res_attr_next;
 202         }
 203         return (-1);
 204 }
 205 #endif /* XXX KEBE SAYS NOT YET */
 206 
 207 static void
 208 lxi_svc_start(char *name, char *path, char *fmri)
 209 {
 210         pid_t pid;
 211         int status;
 212         char *argv[] = {
 213                 NULL,
 214                 NULL
 215         };
 216         char *envp[] = {
 217                 NULL,
 218                 NULL
 219         };
 220         argv[0] = name;
 221         envp[0] = fmri;
 222 
 223         pid = fork();
 224         if (pid == -1) {
 225                 lxi_err("fork() failed: %s", strerror(errno));
 226         }
 227 
 228         if (pid == 0) {
 229                 /* child */
 230                 const char *zroot = zone_get_nroot();
 231                 char cmd[MAXPATHLEN];
 232 
 233                 /*
 234                  * Construct the full path to the binary, including the native
 235                  * system root (e.g. "/native") if in use for this zone:
 236                  */
 237                 (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot != NULL ?
 238                     zroot : "", path);
 239 
 240                 (void) execve(cmd, argv, envp);
 241 
 242                 lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
 243                 /* NOTREACHED */
 244         }
 245 
 246         /* parent */
 247         while (wait(&status) != pid)
 248                 ;
 249 
 250         if (WIFEXITED(status)) {
 251                 if (WEXITSTATUS(status) != 0) {
 252                         lxi_err("%s[%d] exited: %d", name,
 253                             (int)pid, WEXITSTATUS(status));
 254                 }
 255         } else if (WIFSIGNALED(status)) {
 256                 lxi_err("%s[%d] died on signal: %d", name,
 257                     (int)pid, WTERMSIG(status));
 258         } else {
 259                 lxi_err("%s[%d] failed in unknown way", name,
 260                     (int)pid);
 261         }
 262 }
 263 
 264 void
 265 lxi_net_ipmgmtd_start()
 266 {
 267         lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
 268             "SMF_FMRI=svc:/network/ip-interface-management:default");
 269 }
 270 
 271 void
 272 lxi_net_ndpd_start()
 273 {
 274         lxi_svc_start("in.ndpd", IN_NDPD_PATH,
 275             "SMF_FMRI=svc:/network/routing/ndp:default");
 276 }
 277 
 278 
 279 static void
 280 lxi_net_ipadm_open()
 281 {
 282         ipadm_status_t status;
 283 
 284         if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS) {
 285                 lxi_err("Error opening ipadm handle: %s",
 286                     ipadm_status2str(status));
 287         }
 288 }
 289 
 290 static void
 291 lxi_net_ipadm_close()
 292 {
 293         ipadm_close(iph);
 294 }
 295 
 296 void
 297 lxi_net_plumb(const char *iface)
 298 {
 299         ipadm_status_t status;
 300         char ifbuf[LIFNAMSIZ];
 301 
 302         /* ipadm_create_if stomps on ifbuf, so create a copy: */
 303         (void) strncpy(ifbuf, iface, sizeof (ifbuf));
 304 
 305         if ((status = ipadm_create_if(iph, ifbuf, AF_INET, IPADM_OPT_ACTIVE))
 306             != IPADM_SUCCESS) {
 307                 lxi_err("ipadm_create_if error %d: %s/v4: %s",
 308                     status, iface, ipadm_status2str(status));
 309         }
 310 
 311         if ((status = ipadm_create_if(iph, ifbuf, AF_INET6, IPADM_OPT_ACTIVE))
 312             != IPADM_SUCCESS) {
 313                 lxi_err("ipadm_create_if error %d: %s/v6: %s",
 314                     status, iface, ipadm_status2str(status));
 315         }
 316 }
 317 
 318 static int
 319 lxi_getif(int af, char *iface, int len, boolean_t first_ipv4_configured)
 320 {
 321         struct lifreq lifr;
 322         int s = socket(af, SOCK_DGRAM, 0);
 323         if (s < 0) {
 324                 lxi_warn("socket error %d: bringing up %s: %s",
 325                     errno, iface, strerror(errno));
 326                 return (-1);
 327         }
 328 
 329         /*
 330          * We need a new logical interface for every IP address we add, except
 331          * for the very first IPv4 address.
 332          */
 333         if (af == AF_INET6 || first_ipv4_configured) {
 334                 (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
 335                 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
 336                 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
 337                         if (close(s) != 0) {
 338                                 lxi_warn("failed to close socket: %s\n",
 339                                     strerror(errno));
 340                         }
 341                         return (-1);
 342                 }
 343                 (void) strncpy(iface, lifr.lifr_name, len);
 344         }
 345 
 346         if (close(s) != 0) {
 347                 lxi_warn("failed to close socket: %s\n",
 348                     strerror(errno));
 349         }
 350         return (0);
 351 }
 352 
 353 static int
 354 lxi_iface_ip(const char *origiface, const char *addr,
 355     boolean_t *first_ipv4_configured)
 356 {
 357         static int addrnum = 0;
 358         ipadm_status_t status;
 359         ipadm_addrobj_t ipaddr = NULL;
 360         char iface[LIFNAMSIZ];
 361         char aobjname[IPADM_AOBJSIZ];
 362         int af, err = 0;
 363 
 364         (void) strncpy(iface, origiface, sizeof (iface));
 365 
 366         af = strstr(addr, ":") == NULL ? AF_INET : AF_INET6;
 367         if (lxi_getif(af, iface, sizeof (iface), *first_ipv4_configured) != 0) {
 368                 lxi_warn("failed to create new logical interface "
 369                     "on %s: %s", origiface, strerror(errno));
 370                 return (-1);
 371         }
 372 
 373         (void) snprintf(aobjname, IPADM_AOBJSIZ, "%s/addr%d", iface,
 374             addrnum++);
 375 
 376         if ((status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname,
 377             &ipaddr)) != IPADM_SUCCESS) {
 378                 lxi_warn("ipadm_create_addrobj error %d: addr %s, "
 379                     "interface %s: %s\n", status, addr, iface,
 380                     ipadm_status2str(status));
 381                 return (-2);
 382         }
 383 
 384         if ((status = ipadm_set_addr(ipaddr, addr, AF_UNSPEC))
 385             != IPADM_SUCCESS) {
 386                 lxi_warn("ipadm_set_addr error %d: addr %s"
 387                     ", interface %s: %s\n", status, addr,
 388                     iface, ipadm_status2str(status));
 389                 err = -3;
 390                 goto done;
 391         }
 392 
 393         if ((status = ipadm_create_addr(iph, ipaddr,
 394             IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
 395                 lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
 396                     ipadm_status2str(status));
 397                 err = -4;
 398                 goto done;
 399         }
 400 
 401         if (af == AF_INET) {
 402                 *first_ipv4_configured = B_TRUE;
 403         }
 404 
 405 done:
 406         ipadm_destroy_addrobj(ipaddr);
 407         return (err);
 408 }
 409 
 410 #if 0 /* XXX KEBE SAYS NOT YET */
 411 static int
 412 lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
 413 {
 414         dhcp_ipc_request_t *dhcpreq = NULL;
 415         dhcp_ipc_reply_t *dhcpreply = NULL;
 416         int err = 0, timeout = 5;
 417         char iface[LIFNAMSIZ];
 418 
 419         (void) strncpy(iface, origiface, sizeof (iface));
 420 
 421         if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
 422             != 0) {
 423                 lxi_warn("failed to create new logical interface "
 424                     "on %s: %s", origiface, strerror(errno));
 425                 return (-1);
 426         }
 427 
 428         if (dhcp_start_agent(timeout) != 0) {
 429                 lxi_err("Failed to start dhcpagent\n");
 430                 /* NOTREACHED */
 431         }
 432 
 433         dhcpreq = dhcp_ipc_alloc_request(DHCP_START, iface,
 434             NULL, 0, DHCP_TYPE_NONE);
 435         if (dhcpreq == NULL) {
 436                 lxi_warn("Unable to allocate memory "
 437                     "to start DHCP on %s\n", iface);
 438                 return (-1);
 439         }
 440 
 441         err = dhcp_ipc_make_request(dhcpreq, &dhcpreply, timeout);
 442         if (err != 0) {
 443                 free(dhcpreq);
 444                 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
 445                     dhcp_ipc_strerror(err));
 446                 return (-1);
 447         }
 448         err = dhcpreply->return_code;
 449         if (err != 0) {
 450                 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
 451                     dhcp_ipc_strerror(err));
 452                 goto done;
 453         }
 454 
 455         *first_ipv4_configured = B_TRUE;
 456 
 457 done:
 458         free(dhcpreq);
 459         free(dhcpreply);
 460         return (err);
 461 }
 462 #endif /* XXX KEBE SAYS NOT YET */
 463 
 464 /*
 465  * Initialize an IPv6 link-local address on a given interface
 466  */
 467 static int
 468 lxi_iface_ipv6_link_local(const char *iface)
 469 {
 470         struct lifreq lifr;
 471         int s;
 472 
 473         s = socket(AF_INET6, SOCK_DGRAM, 0);
 474         if (s == -1) {
 475                 lxi_warn("socket error %d: bringing up %s: %s",
 476                     errno, iface, strerror(errno));
 477         }
 478 
 479         (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
 480         if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
 481                 lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
 482                     errno, iface, strerror(errno));
 483                 return (-1);
 484         }
 485 
 486         lifr.lifr_flags |= IFF_UP;
 487         if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 488                 lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
 489                     errno, iface, strerror(errno));
 490                 return (-1);
 491         }
 492 
 493         (void) close(s);
 494         return (0);
 495 }
 496 
 497 static int
 498 lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
 499     const char *gwaddr)
 500 {
 501         int idx, len, sockfd;
 502         /* For lint-happy alignment, use a uint32_t array... */
 503         uint32_t rtbuf[RTMBUFSZ / sizeof (uint32_t)];
 504         struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
 505         struct sockaddr_in *dst_sin = (struct sockaddr_in *)(rtm + 1);
 506         struct sockaddr_in *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
 507         struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
 508 
 509         (void) bzero(rtm, RTMBUFSZ);
 510         rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 511         rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
 512         rtm->rtm_msglen = sizeof (rtbuf);
 513         rtm->rtm_pid = getpid();
 514         rtm->rtm_type = RTM_ADD;
 515         rtm->rtm_version = RTM_VERSION;
 516 
 517 
 518         /*
 519          * The destination and netmask components have already been zeroed,
 520          * which represents the default gateway.  If we were passed a more
 521          * specific destination network, use that instead.
 522          */
 523         dst_sin->sin_family = AF_INET;
 524         netmask_sin->sin_family = AF_INET;
 525         if (dst != NULL) {
 526                 struct sockaddr *mask = (struct sockaddr *)netmask_sin;
 527 
 528                 if ((inet_pton(AF_INET, dst, &(dst_sin->sin_addr))) != 1 ||
 529                     plen2mask(dstpfx, AF_INET, mask) != 0) {
 530                         lxi_warn("bad destination network %s/%d: %s", dst,
 531                             dstpfx, strerror(errno));
 532                         return (-1);
 533                 }
 534         }
 535 
 536         if ((inet_pton(AF_INET, gwaddr, &(gw_sin->sin_addr))) != 1) {
 537                 lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
 538                 return (-1);
 539         }
 540 
 541         if (iface != NULL) {
 542                 if ((idx = if_nametoindex(iface)) == 0) {
 543                         lxi_warn("unable to get interface index for %s: %s\n",
 544                             iface, strerror(errno));
 545                         return (-1);
 546                 }
 547                 rtm->rtm_index = idx;
 548         }
 549 
 550         if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
 551                 lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
 552                 return (-1);
 553         }
 554 
 555         if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
 556                 lxi_warn("could not write rtmsg: %s", strerror(errno));
 557                 (void) close(sockfd);
 558                 return (-1);
 559         } else if (len < rtm->rtm_msglen) {
 560                 lxi_warn("write() rtmsg incomplete");
 561                 (void) close(sockfd);
 562                 return (-1);
 563         }
 564 
 565         (void) close(sockfd);
 566         return (0);
 567 }
 568 
 569 static void
 570 lxi_net_loopback()
 571 {
 572         const char *iface = "lo0";
 573         boolean_t first_ipv4_configured = B_FALSE;
 574 
 575         lxi_net_plumb(iface);
 576         (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
 577         (void) lxi_iface_ipv6_link_local(iface);
 578 }
 579 
 580 
 581 
 582 #if 0 /* XXX KEBE SAYS NOT YET */
 583 /*
 584  * This function is used when the "ips" property doesn't exist in a zone's
 585  * configuration. It may be an older configuration, so we should search for
 586  * "ip" and "netmask" and convert them into the new format.
 587  */
 588 static int
 589 lxi_get_old_ip(struct zone_res_attrtab *attrs, const char **ipaddrs,
 590     char *cidraddr, int len)
 591 {
 592 
 593         const char *netmask;
 594         int prefixlen;
 595         struct sockaddr_in mask_sin;
 596 
 597         lxi_warn("Could not find \"ips\" property for zone. Looking "
 598             "for older \"ip\" and \"netmask\" properties, instead.");
 599 
 600         if (zone_find_attr(attrs, "ip", ipaddrs) != 0) {
 601                 return (-1);
 602         }
 603 
 604         if (strcmp(*ipaddrs, "dhcp") == 0) {
 605                 return (0);
 606         }
 607 
 608         if (zone_find_attr(attrs, "netmask", &netmask) != 0) {
 609                 lxi_err("could not find netmask for interface");
 610                 /* NOTREACHED */
 611         }
 612 
 613         /* Convert the netmask to a number */
 614         mask_sin.sin_family = AF_INET;
 615         if (inet_pton(AF_INET, netmask, &mask_sin.sin_addr) != 1) {
 616                 lxi_err("invalid netmask address: %s\n",
 617                     strerror(errno));
 618                 /* NOTREACHED */
 619         }
 620         prefixlen = mask2plen((struct sockaddr *)&mask_sin);
 621 
 622         /*
 623          * Write out the IP address in the new format and use
 624          * that instead
 625          */
 626         (void) snprintf(cidraddr, len, "%s/%d", *ipaddrs, prefixlen);
 627 
 628         *ipaddrs = cidraddr;
 629         return (0);
 630 }
 631 #endif /* XXX KEBE SAYS NOT YET */
 632 
 633 static void
 634 lxi_net_setup(zone_dochandle_t handle)
 635 {
 636         struct zone_nwiftab lookup;
 637         boolean_t do_addrconf = B_FALSE;
 638 
 639         if (zonecfg_setnwifent(handle) != Z_OK)
 640                 return;
 641         while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
 642                 const char *iface = lookup.zone_nwif_physical;
 643 #if 0   /* XXX KEBE SAYS NOT YET */
 644                 struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
 645                 const char *ipaddrs, *primary, *gateway;
 646                 char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
 647                     *ipaddr, *tmp, *lasts;
 648                 boolean_t first_ipv4_configured = B_FALSE;
 649                 boolean_t *ficp = &first_ipv4_configured;
 650 #endif  /* XXX KEBE */
 651 
 652                 lxi_net_plumb(iface);
 653 
 654                 /* XXX KEBE SAYS this bit was shuffled around. */
 655                 if (lxi_iface_ipv6_link_local(iface) != 0) {
 656                         lxi_warn("unable to bring up link-local address on "
 657                             "interface %s", iface);
 658                 } else {
 659                         /* XXX KEBE SAYS this bit is new. */
 660                         do_addrconf = B_TRUE;
 661                 }
 662 
 663 #if 0   /* XXX KEBE SAYS NOT YET */
 664                 if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 &&
 665                     lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0) {
 666                         lxi_warn("Could not find a valid network configuration "
 667                             "for the %s interface", iface);
 668                         continue;
 669                 }
 670 
 671                 /*
 672                  * If we're going to be doing DHCP, we have to do it first since
 673                  * dhcpagent doesn't like to operate on non-zero logical
 674                  * interfaces.
 675                  */
 676                 if (strstr(ipaddrs, "dhcp") != NULL &&
 677                     lxi_iface_dhcp(iface, ficp) != 0) {
 678                         lxi_warn("Failed to start DHCP on %s\n", iface);
 679                 }
 680 
 681                 /*
 682                  * Copy the ipaddrs string, since strtok_r will write NUL
 683                  * characters into it.
 684                  */
 685                 (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
 686                 tmp = ipaddrs_copy;
 687 
 688                 /*
 689                  * Iterate over each IP and then set it up on the interface.
 690                  */
 691                 while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
 692                         tmp = NULL;
 693                         if (strcmp(ipaddr, "addrconf") == 0) {
 694                                 do_addrconf = B_TRUE;
 695                         } else if (strcmp(ipaddr, "dhcp") == 0) {
 696                                 continue;
 697                         } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
 698                                 lxi_warn("Unable to add new IP address (%s) "
 699                                     "to interface %s", ipaddr, iface);
 700                         }
 701                 }
 702 
 703                 if (zone_find_attr(attrs, "primary", &primary) == 0 &&
 704                     strncmp(primary, "true", MAXNAMELEN) == 0 &&
 705                     zone_find_attr(attrs, "gateway", &gateway) == 0) {
 706                         lxi_iface_gateway(iface, NULL, 0, gateway);
 707                 }
 708 #endif /* XXX KEBE */
 709         }
 710 
 711         if (do_addrconf) {
 712                 lxi_net_ndpd_start();
 713         }
 714 
 715         (void) zonecfg_endnwifent(handle);
 716 }
 717 
 718 static void
 719 lxi_net_static_route(const char *line)
 720 {
 721         /*
 722          * Each static route line is a string of the form:
 723          *
 724          *      "10.77.77.2|10.1.1.0/24|false"
 725          *
 726          * i.e. gateway address, destination network, and whether this is
 727          * a "link local" route or a next hop route.
 728          */
 729         custr_t *cu = NULL;
 730         char *gw = NULL, *dst = NULL;
 731         int pfx = -1;
 732         int i;
 733 
 734         if (custr_alloc(&cu) != 0) {
 735                 lxi_err("custr_alloc failure");
 736         }
 737 
 738         for (i = 0; line[i] != '\0'; i++) {
 739                 if (gw == NULL) {
 740                         if (line[i] == '|') {
 741                                 if ((gw = strdup(custr_cstr(cu))) == NULL) {
 742                                         lxi_err("strdup failure");
 743                                 }
 744                                 custr_reset(cu);
 745                         } else {
 746                                 if (custr_appendc(cu, line[i]) != 0) {
 747                                         lxi_err("custr_appendc failure");
 748                                 }
 749                         }
 750                         continue;
 751                 }
 752 
 753                 if (dst == NULL) {
 754                         if (line[i] == '/') {
 755                                 if ((dst = strdup(custr_cstr(cu))) == NULL) {
 756                                         lxi_err("strdup failure");
 757                                 }
 758                                 custr_reset(cu);
 759                         } else {
 760                                 if (custr_appendc(cu, line[i]) != 0) {
 761                                         lxi_err("custr_appendc failure");
 762                                 }
 763                         }
 764                         continue;
 765                 }
 766 
 767                 if (pfx == -1) {
 768                         if (line[i] == '|') {
 769                                 pfx = atoi(custr_cstr(cu));
 770                                 custr_reset(cu);
 771                         } else {
 772                                 if (custr_appendc(cu, line[i]) != 0) {
 773                                         lxi_err("custr_appendc failure");
 774                                 }
 775                         }
 776                         continue;
 777                 }
 778 
 779                 if (custr_appendc(cu, line[i]) != 0) {
 780                         lxi_err("custr_appendc failure");
 781                 }
 782         }
 783 
 784         /*
 785          * We currently only support "next hop" routes, so ensure that
 786          * "linklocal" is false:
 787          */
 788         if (strcmp(custr_cstr(cu), "false") != 0) {
 789                 lxi_warn("invalid static route: %s", line);
 790         }
 791 
 792         if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
 793                 lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
 794         }
 795 
 796         custr_free(cu);
 797         free(gw);
 798         free(dst);
 799 }
 800 
 801 static void
 802 lxi_net_static_routes(void)
 803 {
 804         const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
 805         char *const argv[] = { "routeinfo", NULL };
 806         char *const envp[] = { NULL };
 807         int code;
 808         struct stat st;
 809         char errbuf[512];
 810 
 811         if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
 812                 /*
 813                  * This binary is (potentially) shipped from another
 814                  * consolidation.  If it does not exist, then the platform does
 815                  * not currently support static routes for LX-branded zones.
 816                  */
 817                 return;
 818         }
 819 
 820         /*
 821          * Run the command, firing the callback for each line that it
 822          * outputs.  When this function returns, static route processing
 823          * is complete.
 824          */
 825         if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
 826             lxi_net_static_route, &code) != 0 || code != 0) {
 827                 lxi_err("failed to run \"%s\": %s", cmd, errbuf);
 828         }
 829 }
 830 
 831 static void
 832 lxi_config_close(zone_dochandle_t handle)
 833 {
 834         zonecfg_fini_handle(handle);
 835 }
 836 
 837 static void
 838 lxi_init_exec(char **argv)
 839 {
 840         const char *cmd = "/sbin/init";
 841         char *const envp[] = { "container=zone", NULL };
 842         int e;
 843 
 844         argv[0] = "init";
 845 
 846         /*
 847          * systemd uses the 'container' env var to determine it is running
 848          * inside a container. It only supports a few well-known types and
 849          * treats anything else as 'other' but this is enough to make it
 850          * behave better inside a zone. See 'detect_container' in systemd.
 851          */
 852         (void) execve(cmd, argv, envp);
 853         e = errno;
 854 
 855         /*
 856          * Because stdout was closed prior to exec, it must be opened again in
 857          * the face of failure to log the error.
 858          */
 859         lxi_log_open();
 860         lxi_err("execve(%s) failed: %s", cmd, strerror(e));
 861 }
 862 
 863 /*ARGSUSED*/
 864 int
 865 main(int argc, char *argv[])
 866 {
 867         zone_dochandle_t handle;
 868 
 869         lxi_log_open();
 870 
 871         lxi_net_ipmgmtd_start();
 872         lxi_net_ipadm_open();
 873 
 874         handle = lxi_config_open();
 875         lxi_net_loopback();
 876         lxi_net_setup(handle);
 877         lxi_config_close(handle);
 878 
 879         lxi_net_static_routes();
 880 
 881         lxi_net_ipadm_close();
 882 
 883         lxi_log_close();
 884 
 885         lxi_init_exec(argv);
 886 
 887         /* NOTREACHED */
 888         return (0);
 889 }