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 }