github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/containers/compilers/rump/go/patches/buildrump.sh/brlib/libnetconfig/dhcp_configure.c (about)

     1  /*
     2   * dhcpcd - DHCP client daemon
     3   * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
     4   * All rights reserved
     5  
     6   * Redistribution and use in source and binary forms, with or without
     7   * modification, are permitted provided that the following conditions
     8   * are met:
     9   * 1. Redistributions of source code must retain the above copyright
    10   *    notice, this list of conditions and the following disclaimer.
    11   * 2. Redistributions in binary form must reproduce the above copyright
    12   *    notice, this list of conditions and the following disclaimer in the
    13   *    documentation and/or other materials provided with the distribution.
    14   *
    15   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    16   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    17   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    18   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    19   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    20   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    21   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    22   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    23   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    24   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    25   * SUCH DAMAGE.
    26   */
    27  
    28  #include <sys/param.h>
    29  #include <sys/kmem.h>
    30  #include <sys/stat.h>
    31  #include <sys/uio.h>
    32  #include <sys/wait.h>
    33  
    34  #include <netinet/in.h>
    35  
    36  #include "dhcp_common.h"
    37  #include "dhcp_configure.h"
    38  #include "dhcp_dhcp.h"
    39  #include "dhcp_if-options.h"
    40  #include "dhcp_net.h"
    41  
    42  #define HAVE_ROUTE_METRIC 0
    43  
    44  static struct rt *routes;
    45  
    46  //enough to hold 4 dns addrs
    47  uint8_t kludge_dns_addrs[16];
    48  unsigned int kludge_dns_addr_count;
    49  
    50  static struct rt *
    51  find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
    52      const struct rt *srt)
    53  {
    54  	struct rt *rt;
    55  
    56  	if (lrt)
    57  		*lrt = NULL;
    58  	for (rt = rts; rt; rt = rt->next) {
    59  		if (rt->dest.s_addr == r->dest.s_addr &&
    60  #if HAVE_ROUTE_METRIC
    61  		    (srt || (!rt->iface ||
    62  			rt->iface->metric == r->iface->metric)) &&
    63  #endif
    64                      (!srt || srt != rt) &&
    65  		    rt->net.s_addr == r->net.s_addr)
    66  			return rt;
    67  		if (lrt)
    68  			*lrt = rt;
    69  	}
    70  	return NULL;
    71  }
    72  
    73  static void
    74  desc_route(const char *cmd, const struct rt *rt, const char *ifname)
    75  {
    76  	char addr[sizeof("000.000.000.000") + 1];
    77  
    78  	strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
    79  	if (rt->gate.s_addr == INADDR_ANY)
    80  		printf("dhcp: %s: %s route to %s/%d\n", ifname, cmd,
    81  		    addr, inet_ntocidr(rt->net));
    82  	else if (rt->gate.s_addr == rt->dest.s_addr &&
    83  	    rt->net.s_addr == INADDR_BROADCAST)
    84  		printf("dhcp: %s: %s host route to %s\n", ifname, cmd,
    85  		    addr);
    86  	else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
    87  		printf("dhcp: %s: %s default route via %s\n", ifname, cmd,
    88  		    inet_ntoa(rt->gate));
    89  	else
    90  		printf("dhcp: %s: %s route to %s/%d via %s\n", ifname, cmd,
    91  		    addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
    92  }
    93  
    94  /* If something other than dhcpcd removes a route,
    95   * we need to remove it from our internal table. */
    96  int
    97  route_deleted(const struct rt *rt)
    98  {
    99  	struct rt *f, *l;
   100  
   101  	f = find_route(routes, rt, &l, NULL);
   102  	if (f == NULL)
   103  		return 0;
   104  	desc_route("removing", f, f->iface->name);
   105  	if (l)
   106  		l->next = f->next;
   107  	else
   108  		routes = f->next;
   109  	kmem_free(f, sizeof(*f));
   110  	return 1;
   111  }
   112  
   113  static int
   114  n_route(struct rt *rt, const struct interface *iface)
   115  {
   116  	int error;
   117  
   118  	/* Don't set default routes if not asked to */
   119  	if (rt->dest.s_addr == 0 &&
   120  	    rt->net.s_addr == 0 &&
   121  	    !(iface->state->options->options & DHCPCD_GATEWAY))
   122  		return -1;
   123  
   124  	desc_route("adding", rt, iface->name);
   125  	if ((error = add_route(iface, &rt->dest, &rt->net, &rt->gate, iface->metric)) == 0)
   126  		return 0;
   127  	if (error == EEXIST) {
   128  		/* Pretend we added the subnet route */
   129  		if (rt->dest.s_addr == (iface->addr.s_addr & iface->net.s_addr) &&
   130  		    rt->net.s_addr == iface->net.s_addr &&
   131  		    rt->gate.s_addr == 0)
   132  			return 0;
   133  		else
   134  			return error;
   135  	}
   136  	printf("dhcp: %s: add_route failed\n", iface->name);
   137  	return error;
   138  }
   139  
   140  static int
   141  c_route(struct rt *ort, struct rt *nrt, const struct interface *iface)
   142  {
   143  	int error;
   144  
   145  	/* Don't set default routes if not asked to */
   146  	if (nrt->dest.s_addr == 0 &&
   147  	    nrt->net.s_addr == 0 &&
   148  	    !(iface->state->options->options & DHCPCD_GATEWAY))
   149  		return 1;
   150  
   151  	desc_route("changing", nrt, iface->name);
   152  	/* We delete and add the route so that we can change metric.
   153  	 * This also has the nice side effect of flushing ARP entries so
   154  	 * we don't have to do that manually. */
   155  	del_route(ort->iface, &ort->dest, &ort->net, &ort->gate,
   156  	    ort->iface->metric);
   157  	if ((error = add_route(iface, &nrt->dest, &nrt->net, &nrt->gate,
   158  		iface->metric)) == 0)
   159  		return 0;
   160  	printf("%s: add_route failed: %d\n", iface->name, error);
   161  	return 1;
   162  }
   163  
   164  static int
   165  d_route(struct rt *rt, const struct interface *iface, int metric)
   166  {
   167  	int retval;
   168  
   169  	desc_route("deleting", rt, iface->name);
   170  	retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
   171  	if (retval != ENOENT && retval != ESRCH)
   172  		printf("%s: del_route: %d\n", iface->name, retval);
   173  	return retval;
   174  }
   175  
   176  static struct rt *
   177  get_subnet_route(struct dhcp_message *dhcp)
   178  {
   179  	in_addr_t addr;
   180  	struct in_addr net;
   181  	struct rt *rt;
   182  
   183  	addr = dhcp->yiaddr;
   184  	if (addr == 0)
   185  		addr = dhcp->ciaddr;
   186  	/* Ensure we have all the needed values */
   187  	if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) != 0)
   188  		net.s_addr = get_netmask(addr);
   189  	if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
   190  		return NULL;
   191  	rt = kmem_alloc(sizeof(*rt), KM_SLEEP);
   192  	rt->dest.s_addr = addr & net.s_addr;
   193  	rt->net.s_addr = net.s_addr;
   194  	rt->gate.s_addr = 0;
   195  	return rt;
   196  }
   197  
   198  static struct rt *
   199  add_subnet_route(struct rt *rt, const struct interface *iface)
   200  {
   201  	struct rt *r;
   202  
   203  	if (iface->net.s_addr == INADDR_BROADCAST ||
   204  	    iface->net.s_addr == INADDR_ANY ||
   205  	    (iface->state->options->options &
   206  	     (DHCPCD_INFORM | DHCPCD_STATIC) &&
   207  	     iface->state->options->req_addr.s_addr == INADDR_ANY))
   208  		return rt;
   209  
   210  	r = kmem_alloc(sizeof(*r), KM_SLEEP);
   211  	r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
   212  	r->net.s_addr = iface->net.s_addr;
   213  	r->gate.s_addr = 0;
   214  	r->next = rt;
   215  	return r;
   216  }
   217  
   218  static struct rt *
   219  get_routes(const struct interface *iface)
   220  {
   221  	struct rt *rt, *nrt = NULL, *r = NULL;
   222  
   223  	if (iface->state->options->routes != NULL) {
   224  		for (rt = iface->state->options->routes;
   225  		     rt != NULL;
   226  		     rt = rt->next)
   227  		{
   228  			if (rt->gate.s_addr == 0)
   229  				break;
   230  			if (r == NULL)
   231  				r = nrt = kmem_alloc(sizeof(*r), KM_SLEEP);
   232  			else {
   233  				r->next = kmem_alloc(sizeof(*r), KM_SLEEP);
   234  				r = r->next;
   235  			}
   236  			memcpy(r, rt, sizeof(*r));
   237  			r->next = NULL;
   238  		}
   239  		return nrt;
   240  	}
   241  
   242  	return get_option_routes(iface->state->new,
   243  	    iface->name, &iface->state->options->options);
   244  }
   245  
   246  //static struct rt *
   247  //hack_google_cloud(struct rt *rt, const struct interface *iface)
   248  //{
   249  //    struct rt *r;
   250  //
   251  //    for (r = rt; r; r = r->next) {
   252  //        printf("inspecting cidr %x ", r->net.s_addr);
   253  //        if (r->net.s_addr == INADDR_BROADCAST) {
   254  //            r->net.s_addr = 0x00ffFFff;
   255  //            printf("; changed to %x\n", r->net.s_addr);
   256  //        } else {
   257  //            printf("\n");
   258  //        }
   259  //
   260  //    }
   261  //
   262  //    return rt;
   263  //}
   264  
   265  /* Some DHCP servers add set host routes by setting the gateway
   266   * to the assinged IP address. This differs from our notion of a host route
   267   * where the gateway is the destination address, so we fix it. */
   268  static struct rt *
   269  massage_host_routes(struct rt *rt, const struct interface *iface)
   270  {
   271  	struct rt *r;
   272  
   273  	for (r = rt; r; r = r->next) {
   274  		if (r->gate.s_addr == iface->addr.s_addr &&
   275  		    r->net.s_addr == INADDR_BROADCAST)
   276  			r->gate.s_addr = r->dest.s_addr;
   277  
   278      /*
   279      Some DHCP servers (GCE) set a route with a netmask of 255.255.255.255
   280      we need to set the gate on there so that this route actually works
   281      https://code.google.com/p/google-compute-engine/issues/detail?id=77
   282      */
   283  		if (r->gate.s_addr == INADDR_ANY && r->net.s_addr == INADDR_BROADCAST)
   284  			r->gate.s_addr = r->dest.s_addr;
   285  	}
   286  
   287  	return rt;
   288  }
   289  
   290  static struct rt *
   291  add_destination_route(struct rt *rt, const struct interface *iface)
   292  {
   293  	struct rt *r;
   294  
   295  	if (!(iface->flags & IFF_POINTOPOINT) ||
   296  	    !has_option_mask(iface->state->options->dstmask, DHO_ROUTER))
   297  		return rt;
   298  	r = kmem_alloc(sizeof(*r), KM_SLEEP);
   299  	r->dest.s_addr = INADDR_ANY;
   300  	r->net.s_addr = INADDR_ANY;
   301  	r->gate.s_addr = iface->dst.s_addr;
   302  	r->next = rt;
   303  	return r;
   304  }
   305  
   306  /* We should check to ensure the routers are on the same subnet
   307   * OR supply a host route. If not, warn and add a host route. */
   308  static struct rt *
   309  add_router_host_route(struct rt *rt, const struct interface *ifp)
   310  {
   311  	struct rt *rtp, *rtl, *rtn;
   312  	const char *cp, *cp2, *cp3, *cplim;
   313  
   314  	for (rtp = rt, rtl = NULL; rtp; rtl = rtp, rtp = rtp->next) {
   315  		if (rtp->dest.s_addr != INADDR_ANY)
   316  			continue;
   317  		/* Scan for a route to match */
   318  		for (rtn = rt; rtn != rtp; rtn = rtn->next) {
   319  			/* match host */
   320  			if (rtn->dest.s_addr == rtp->gate.s_addr)
   321  				break;
   322  			/* match subnet */
   323  			cp = (const char *)&rtp->gate.s_addr;
   324  			cp2 = (const char *)&rtn->dest.s_addr;
   325  			cp3 = (const char *)&rtn->net.s_addr;
   326  			cplim = cp3 + sizeof(rtn->net.s_addr);
   327  			while (cp3 < cplim) {
   328  				if ((*cp++ ^ *cp2++) & *cp3++)
   329  					break;
   330  			}
   331  			if (cp3 == cplim)
   332  				break;
   333  		}
   334  		if (rtn != rtp)
   335  			continue;
   336  		if (ifp->flags & IFF_NOARP) {
   337  			printf("%s: forcing router %s through interface\n",
   338  			    ifp->name, inet_ntoa(rtp->gate));
   339  			rtp->gate.s_addr = 0;
   340  			continue;
   341  		}
   342  		printf("%s: router %s requires a host route\n",
   343  		    ifp->name, inet_ntoa(rtp->gate));
   344  		rtn = kmem_alloc(sizeof(*rtn), KM_SLEEP);
   345  		rtn->dest.s_addr = rtp->gate.s_addr;
   346  		rtn->net.s_addr = INADDR_BROADCAST;
   347  		rtn->gate.s_addr = rtp->gate.s_addr;
   348  		rtn->next = rtp;
   349  		if (rtl == NULL)
   350  			rt = rtn;
   351  		else
   352  			rtl->next = rtn;
   353  	}
   354  	return rt;
   355  }
   356  
   357  void
   358  build_routes(void)
   359  {
   360  	struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
   361  	const struct interface *ifp;
   362  
   363  	for (ifp = ifaces; ifp; ifp = ifp->next) {
   364  		if (ifp->state->new == NULL)
   365  			continue;
   366  		dnr = get_routes(ifp);
   367  		dnr = massage_host_routes(dnr, ifp);
   368  		dnr = add_subnet_route(dnr, ifp);
   369  		dnr = add_router_host_route(dnr, ifp);
   370  		dnr = add_destination_route(dnr, ifp);
   371  //		dnr = hack_google_cloud(dnr, ifp);
   372  		for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
   373  			rt->iface = ifp;
   374  			/* Is this route already in our table? */
   375  			if ((find_route(nrs, rt, NULL, NULL)) != NULL)
   376  				continue;
   377  			/* Do we already manage it? */
   378  			if ((or = find_route(routes, rt, &rtl, NULL))) {
   379  				if (or->iface != ifp ||
   380  				    rt->gate.s_addr != or->gate.s_addr)
   381  				{
   382  					if (c_route(or, rt, ifp) != 0)
   383  						continue;
   384  				}
   385  				if (rtl != NULL)
   386  					rtl->next = or->next;
   387  				else
   388  					routes = or->next;
   389  				kmem_free(or, sizeof(*or));
   390  			} else {
   391  				if (n_route(rt, ifp) != 0)
   392  					continue;
   393  			}
   394  			if (dnr == rt)
   395  				dnr = rtn;
   396  			else if (lrt)
   397  				lrt->next = rtn;
   398  			rt->next = nrs;
   399  			nrs = rt;
   400  		}
   401  		free_routes(dnr);
   402  	}
   403  
   404  	/* Remove old routes we used to manage */
   405  	for (rt = routes; rt; rt = rt->next) {
   406  		if (find_route(nrs, rt, NULL, NULL) == NULL)
   407  			d_route(rt, rt->iface, rt->iface->metric);
   408  	}
   409  
   410  	free_routes(routes);
   411  	routes = nrs;
   412  }
   413  
   414  static int
   415  delete_address(struct interface *iface)
   416  {
   417  	int error;
   418  	struct if_options *ifo;
   419  
   420  	ifo = iface->state->options;
   421  	if (ifo->options & DHCPCD_INFORM ||
   422  	    (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
   423  		return 0;
   424  	printf("%s: deleting IP address %s/%d\n",
   425  	    iface->name,
   426  	    inet_ntoa(iface->addr),
   427  	    inet_ntocidr(iface->net));
   428  	error = del_address(iface, &iface->addr, &iface->net);
   429  	if (error != EADDRNOTAVAIL)
   430  		printf("dhcp: del_address failed: %d\n", error);
   431  	iface->addr.s_addr = 0;
   432  	iface->net.s_addr = 0;
   433  	return error;
   434  }
   435  
   436  int
   437  configure(struct interface *iface)
   438  {
   439  	struct dhcp_message *dhcp = iface->state->new;
   440  	struct dhcp_lease *lease = &iface->state->lease;
   441  	struct if_options *ifo = iface->state->options;
   442  	struct rt *rt;
   443  	int error;
   444  
   445      if (lease->net.s_addr == INADDR_BROADCAST) {
   446          printf("hacking the lease\n");
   447          lease->net.s_addr = 0x00ffFFff;
   448      }
   449  
   450      kludge_dns_addr_count = 0;
   451  
   452      for (int i=0; i < DHCP_OPTION_LEN-1; i++) {
   453          uint8_t message_type = dhcp->options[i];
   454          uint8_t message_len = dhcp->options[++i];
   455          if (message_type != 6) {
   456            i += message_len;
   457            continue;
   458          }
   459  
   460          if ((message_len == 0) || (message_len % 4 != 0)) {
   461            printf("message_len should be a multiple of 4, but is %d\n", message_len);
   462            continue;
   463          }
   464  
   465          for (int j=0; j < message_len / 4; j++) {
   466              //don't store more than 4 addresses
   467              if (kludge_dns_addr_count > 4)
   468                  break;
   469  
   470              int offset =  j*4 + i;
   471              int message[4] = {dhcp->options[offset+1], dhcp->options[offset+2], dhcp->options[offset+3], dhcp->options[offset+4]};
   472  
   473              printf("adding dns addr: %d.%d.%d.%d\n", message[0], message[1], message[2], message[3]);
   474  
   475              kludge_dns_addrs[j*4 + 0] = message[0];
   476              kludge_dns_addrs[j*4 + 1] = message[1];
   477              kludge_dns_addrs[j*4 + 2] = message[2];
   478              kludge_dns_addrs[j*4 + 3] = message[3];
   479              kludge_dns_addr_count++;
   480          }
   481      }
   482  
   483  	/* This also changes netmask */
   484  	if (!(ifo->options & DHCPCD_INFORM) ||
   485  	    !has_address(iface->name, &lease->addr, &lease->net))
   486  	{
   487  		printf("dhcp: %s: adding IP address %s/%d\n",
   488  		    iface->name, inet_ntoa(lease->addr),
   489  		    inet_ntocidr(lease->net));
   490  		if ((error = add_address(iface,
   491  			&lease->addr, &lease->net, &lease->brd)) != 0 &&
   492  		    error != EEXIST)
   493  		{
   494  			printf("dhcp: add_address failed\n");
   495  			return error;
   496  		}
   497  	}
   498  
   499  	/* Now delete the old address if different */
   500  	if (iface->addr.s_addr != lease->addr.s_addr &&
   501  	    iface->addr.s_addr != 0)
   502  		delete_address(iface);
   503  
   504  	iface->addr.s_addr = lease->addr.s_addr;
   505  	iface->net.s_addr = lease->net.s_addr;
   506  
   507  	/* We need to delete the subnet route to have our metric or
   508  	 * prefer the interface. */
   509  	rt = get_subnet_route(dhcp);
   510  	if (rt != NULL) {
   511  		rt->iface = iface;
   512  		if (!find_route(routes, rt, NULL, NULL))
   513  			del_route(iface, &rt->dest, &rt->net, &rt->gate, 0);
   514  		kmem_free(rt, sizeof(*rt));
   515  	}
   516  
   517  	build_routes();
   518  
   519  	printf("lease time: ");
   520  	if (lease->leasetime == ~0U)
   521  		printf("infinite\n");
   522  	else
   523  		printf("%u seconds\n", lease->leasetime);
   524  
   525  	return 0;
   526  }