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