1 /* 2 * dhcpcd - route management 3 * Copyright (c) 2006-2018 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 <assert.h> 29 #include <ctype.h> 30 #include <errno.h> 31 #include <stdbool.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 36 #include "config.h" 37 #include "common.h" 38 #include "dhcpcd.h" 39 #include "if.h" 40 #include "ipv4.h" 41 #include "ipv4ll.h" 42 #include "ipv6.h" 43 #include "logerr.h" 44 #include "route.h" 45 #include "sa.h" 46 47 void 48 rt_init(struct dhcpcd_ctx *ctx) 49 { 50 51 TAILQ_INIT(&ctx->routes); 52 TAILQ_INIT(&ctx->kroutes); 53 TAILQ_INIT(&ctx->froutes); 54 } 55 56 static void 57 rt_desc(const char *cmd, const struct rt *rt) 58 { 59 char dest[INET_MAX_ADDRSTRLEN], gateway[INET_MAX_ADDRSTRLEN]; 60 int prefix; 61 const char *ifname; 62 bool gateway_unspec; 63 64 assert(cmd != NULL); 65 assert(rt != NULL); 66 assert(rt->rt_ifp != NULL); 67 68 ifname = rt->rt_ifp->name; 69 sa_addrtop(&rt->rt_dest, dest, sizeof(dest)); 70 prefix = sa_toprefix(&rt->rt_netmask); 71 sa_addrtop(&rt->rt_gateway, gateway, sizeof(gateway)); 72 73 gateway_unspec = sa_is_unspecified(&rt->rt_gateway); 74 75 if (rt->rt_flags & RTF_HOST) { 76 if (gateway_unspec) 77 loginfox("%s: %s host route to %s", 78 ifname, cmd, dest); 79 else 80 loginfox("%s: %s host route to %s via %s", 81 ifname, cmd, dest, gateway); 82 } else if (sa_is_unspecified(&rt->rt_dest) && 83 sa_is_unspecified(&rt->rt_netmask)) 84 { 85 if (gateway_unspec) 86 loginfox("%s: %s default route", 87 ifname, cmd); 88 else 89 loginfox("%s: %s default route via %s", 90 ifname, cmd, gateway); 91 } else if (gateway_unspec) 92 loginfox("%s: %s%s route to %s/%d", 93 ifname, cmd, 94 rt->rt_flags & RTF_REJECT ? " reject" : "", 95 dest, prefix); 96 else 97 loginfox("%s: %s%s route to %s/%d via %s", 98 ifname, cmd, 99 rt->rt_flags & RTF_REJECT ? " reject" : "", 100 dest, prefix, gateway); 101 } 102 103 void 104 rt_headclear0(struct dhcpcd_ctx *ctx, struct rt_head *rts, int af) 105 { 106 struct rt *rt, *rtn; 107 108 if (rts == NULL) 109 return; 110 assert(ctx != NULL); 111 assert(&ctx->froutes != rts); 112 113 TAILQ_FOREACH_SAFE(rt, rts, rt_next, rtn) { 114 if (af != AF_UNSPEC && 115 rt->rt_dest.sa_family != af && 116 rt->rt_gateway.sa_family != af) 117 continue; 118 TAILQ_REMOVE(rts, rt, rt_next); 119 TAILQ_INSERT_TAIL(&ctx->froutes, rt, rt_next); 120 } 121 } 122 123 void 124 rt_headclear(struct rt_head *rts, int af) 125 { 126 struct rt *rt; 127 128 if (rts == NULL || (rt = TAILQ_FIRST(rts)) == NULL) 129 return; 130 rt_headclear0(rt->rt_ifp->ctx, rts, af); 131 } 132 133 static void 134 rt_headfree(struct rt_head *rts) 135 { 136 struct rt *rt; 137 138 while ((rt = TAILQ_FIRST(rts))) { 139 TAILQ_REMOVE(rts, rt, rt_next); 140 free(rt); 141 } 142 } 143 144 void 145 rt_dispose(struct dhcpcd_ctx *ctx) 146 { 147 148 assert(ctx != NULL); 149 rt_headfree(&ctx->routes); 150 rt_headfree(&ctx->kroutes); 151 rt_headfree(&ctx->froutes); 152 } 153 154 struct rt * 155 rt_new0(struct dhcpcd_ctx *ctx) 156 { 157 struct rt *rt; 158 159 assert(ctx != NULL); 160 if ((rt = TAILQ_FIRST(&ctx->froutes)) != NULL) 161 TAILQ_REMOVE(&ctx->froutes, rt, rt_next); 162 else if ((rt = malloc(sizeof(*rt))) == NULL) { 163 logerr(__func__); 164 return NULL; 165 } 166 memset(rt, 0, sizeof(*rt)); 167 return rt; 168 } 169 170 void 171 rt_setif(struct rt *rt, struct interface *ifp) 172 { 173 174 assert(rt != NULL); 175 assert(ifp != NULL); 176 rt->rt_ifp = ifp; 177 #ifdef HAVE_ROUTE_METRIC 178 rt->rt_metric = ifp->metric; 179 #endif 180 } 181 182 struct rt * 183 rt_new(struct interface *ifp) 184 { 185 struct rt *rt; 186 187 assert(ifp != NULL); 188 if ((rt = rt_new0(ifp->ctx)) == NULL) 189 return NULL; 190 rt_setif(rt, ifp); 191 return rt; 192 } 193 194 void 195 rt_free(struct rt *rt) 196 { 197 198 assert(rt != NULL); 199 assert(rt->rt_ifp->ctx != NULL); 200 TAILQ_INSERT_TAIL(&rt->rt_ifp->ctx->froutes, rt, rt_next); 201 } 202 203 void 204 rt_freeif(struct interface *ifp) 205 { 206 struct dhcpcd_ctx *ctx; 207 struct rt *rt, *rtn; 208 209 if (ifp == NULL) 210 return; 211 ctx = ifp->ctx; 212 TAILQ_FOREACH_SAFE(rt, &ctx->routes, rt_next, rtn) { 213 if (rt->rt_ifp == ifp) { 214 TAILQ_REMOVE(&ctx->routes, rt, rt_next); 215 rt_free(rt); 216 } 217 } 218 TAILQ_FOREACH_SAFE(rt, &ctx->kroutes, rt_next, rtn) { 219 if (rt->rt_ifp == ifp) { 220 TAILQ_REMOVE(&ctx->kroutes, rt, rt_next); 221 rt_free(rt); 222 } 223 } 224 } 225 226 struct rt * 227 rt_find(struct rt_head *rts, const struct rt *f) 228 { 229 struct rt *rt; 230 231 assert(rts != NULL); 232 assert(f != NULL); 233 TAILQ_FOREACH(rt, rts, rt_next) { 234 if (sa_cmp(&rt->rt_dest, &f->rt_dest) == 0 && 235 #ifdef HAVE_ROUTE_METRIC 236 (f->rt_ifp == NULL || 237 rt->rt_ifp->metric == f->rt_ifp->metric) && 238 #endif 239 sa_cmp(&rt->rt_netmask, &f->rt_netmask) == 0) 240 return rt; 241 } 242 return NULL; 243 } 244 245 static void 246 rt_kfree(struct rt *rt) 247 { 248 struct dhcpcd_ctx *ctx; 249 struct rt *f; 250 251 assert(rt != NULL); 252 ctx = rt->rt_ifp->ctx; 253 if ((f = rt_find(&ctx->kroutes, rt)) != NULL) { 254 TAILQ_REMOVE(&ctx->kroutes, f, rt_next); 255 rt_free(f); 256 } 257 } 258 259 /* If something other than dhcpcd removes a route, 260 * we need to remove it from our internal table. */ 261 void 262 rt_recvrt(int cmd, const struct rt *rt) 263 { 264 struct dhcpcd_ctx *ctx; 265 struct rt *f; 266 267 assert(rt != NULL); 268 ctx = rt->rt_ifp->ctx; 269 f = rt_find(&ctx->kroutes, rt); 270 271 switch(cmd) { 272 case RTM_DELETE: 273 if (f != NULL) { 274 TAILQ_REMOVE(&ctx->kroutes, f, rt_next); 275 rt_free(f); 276 } 277 if ((f = rt_find(&ctx->routes, rt)) != NULL) { 278 TAILQ_REMOVE(&ctx->routes, f, rt_next); 279 rt_desc("deleted", f); 280 rt_free(f); 281 } 282 break; 283 case RTM_ADD: 284 if (f != NULL) 285 break; 286 if ((f = rt_new(rt->rt_ifp)) == NULL) 287 break; 288 memcpy(f, rt, sizeof(*f)); 289 TAILQ_INSERT_TAIL(&ctx->kroutes, f, rt_next); 290 break; 291 } 292 293 #if defined(INET) && defined(HAVE_ROUTE_METRIC) 294 if (rt->rt_dest.sa_family == AF_INET) 295 ipv4ll_recvrt(cmd, rt); 296 #endif 297 } 298 299 static bool 300 rt_add(struct rt *nrt, struct rt *ort) 301 { 302 struct dhcpcd_ctx *ctx; 303 bool change; 304 305 assert(nrt != NULL); 306 ctx = nrt->rt_ifp->ctx; 307 308 /* 309 * Don't install a gateway if not asked to. 310 * This option is mainly for VPN users who want their VPN to be the 311 * default route. 312 * Because VPN's generally don't care about route management 313 * beyond their own, a longer term solution would be to remove this 314 * and get the VPN to inject the default route into dhcpcd somehow. 315 */ 316 if (((nrt->rt_ifp->active && 317 !(nrt->rt_ifp->options->options & DHCPCD_GATEWAY)) || 318 (!nrt->rt_ifp->active && !(ctx->options & DHCPCD_GATEWAY))) && 319 sa_is_unspecified(&nrt->rt_dest) && 320 sa_is_unspecified(&nrt->rt_netmask)) 321 return false; 322 323 rt_desc(ort == NULL ? "adding" : "changing", nrt); 324 325 change = false; 326 if (ort == NULL) { 327 ort = rt_find(&ctx->kroutes, nrt); 328 if (ort != NULL && 329 ((ort->rt_flags & RTF_REJECT && 330 nrt->rt_flags & RTF_REJECT) || 331 (ort->rt_ifp == nrt->rt_ifp && 332 #ifdef HAVE_ROUTE_METRIC 333 ort->rt_metric == nrt->rt_metric && 334 #endif 335 sa_cmp(&ort->rt_gateway, &nrt->rt_gateway) == 0))) 336 { 337 if (ort->rt_mtu == nrt->rt_mtu) 338 return true; 339 change = true; 340 } 341 } else if (ort->rt_dflags & RTDF_FAKE && 342 !(nrt->rt_dflags & RTDF_FAKE) && 343 ort->rt_ifp == nrt->rt_ifp && 344 #ifdef HAVE_ROUTE_METRIC 345 ort->rt_metric == nrt->rt_metric && 346 #endif 347 sa_cmp(&ort->rt_dest, &nrt->rt_dest) == 0 && 348 sa_cmp(&ort->rt_netmask, &nrt->rt_netmask) == 0 && 349 sa_cmp(&ort->rt_gateway, &nrt->rt_gateway) == 0) 350 { 351 if (ort->rt_mtu == nrt->rt_mtu) 352 return true; 353 change = true; 354 } 355 356 #ifdef RTF_CLONING 357 /* BSD can set routes to be cloning routes. 358 * Cloned routes inherit the parent flags. 359 * As such, we need to delete and re-add the route to flush children 360 * to correct the flags. */ 361 if (change && ort != NULL && ort->rt_flags & RTF_CLONING) 362 change = false; 363 #endif 364 365 if (change) { 366 if (if_route(RTM_CHANGE, nrt) != -1) 367 return true; 368 if (errno != ESRCH) 369 logerr("if_route (CHG)"); 370 } 371 372 #ifdef HAVE_ROUTE_METRIC 373 /* With route metrics, we can safely add the new route before 374 * deleting the old route. */ 375 if (if_route(RTM_ADD, nrt) != -1) { 376 if (ort != NULL) { 377 if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH) 378 logerr("if_route (DEL)"); 379 rt_kfree(ort); 380 } 381 return true; 382 } 383 384 /* If the kernel claims the route exists we need to rip out the 385 * old one first. */ 386 if (errno != EEXIST || ort == NULL) 387 goto logerr; 388 #endif 389 390 /* No route metrics, we need to delete the old route before 391 * adding the new one. */ 392 #ifdef ROUTE_PER_GATEWAY 393 errno = 0; 394 #endif 395 if (ort != NULL) { 396 if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH) 397 logerr("if_route (DEL)"); 398 else 399 rt_kfree(ort); 400 } 401 #ifdef ROUTE_PER_GATEWAY 402 /* The OS allows many routes to the same dest with different gateways. 403 * dhcpcd does not support this yet, so for the time being just keep on 404 * deleting the route until there is an error. */ 405 if (ort != NULL && errno == 0) { 406 for (;;) { 407 if (if_route(RTM_DELETE, ort) == -1) 408 break; 409 } 410 } 411 #endif 412 if (if_route(RTM_ADD, nrt) != -1) 413 return true; 414 #ifdef HAVE_ROUTE_METRIC 415 logerr: 416 #endif 417 logerr("if_route (ADD)"); 418 return false; 419 } 420 421 static bool 422 rt_delete(struct rt *rt) 423 { 424 int retval; 425 426 rt_desc("deleting", rt); 427 retval = if_route(RTM_DELETE, rt) == -1 ? false : true; 428 if (!retval && errno != ENOENT && errno != ESRCH) 429 logerr(__func__); 430 /* Remove the route from our kernel table so we can add a 431 * IPv4LL default route if possible. */ 432 else 433 rt_kfree(rt); 434 return retval; 435 } 436 437 static bool 438 rt_cmp(const struct rt *r1, const struct rt *r2) 439 { 440 441 return (r1->rt_ifp == r2->rt_ifp && 442 #ifdef HAVE_ROUTE_METRIC 443 r1->rt_metric == r2->rt_metric && 444 #endif 445 sa_cmp(&r1->rt_gateway, &r2->rt_gateway) == 0); 446 } 447 448 static bool 449 rt_doroute(struct rt *rt) 450 { 451 struct dhcpcd_ctx *ctx; 452 struct rt *or; 453 454 ctx = rt->rt_ifp->ctx; 455 /* Do we already manage it? */ 456 if ((or = rt_find(&ctx->routes, rt))) { 457 if (rt->rt_dflags & RTDF_FAKE) 458 return true; 459 if (or->rt_dflags & RTDF_FAKE || 460 !rt_cmp(rt, or) || 461 (rt->rt_ifa.sa_family != AF_UNSPEC && 462 sa_cmp(&or->rt_ifa, &rt->rt_ifa) != 0) || 463 or->rt_mtu != rt->rt_mtu) 464 { 465 if (!rt_add(rt, or)) 466 return false; 467 } 468 TAILQ_REMOVE(&ctx->routes, or, rt_next); 469 rt_free(or); 470 } else { 471 if (rt->rt_dflags & RTDF_FAKE) { 472 if ((or = rt_find(&ctx->kroutes, rt)) == NULL) 473 return false; 474 if (!rt_cmp(rt, or)) 475 return false; 476 } else { 477 if (!rt_add(rt, NULL)) 478 return false; 479 } 480 } 481 482 return true; 483 } 484 485 void 486 rt_build(struct dhcpcd_ctx *ctx, int af) 487 { 488 struct rt_head routes, added; 489 struct rt *rt, *rtn; 490 unsigned long long o; 491 492 /* We need to have the interfaces in the correct order to ensure 493 * our routes are managed correctly. */ 494 if_sortinterfaces(ctx); 495 496 TAILQ_INIT(&routes); 497 TAILQ_INIT(&added); 498 499 switch (af) { 500 #ifdef INET 501 case AF_INET: 502 if (!inet_getroutes(ctx, &routes)) 503 goto getfail; 504 break; 505 #endif 506 #ifdef INET6 507 case AF_INET6: 508 if (!inet6_getroutes(ctx, &routes)) 509 goto getfail; 510 break; 511 #endif 512 } 513 514 TAILQ_FOREACH_SAFE(rt, &routes, rt_next, rtn) { 515 if (rt->rt_dest.sa_family != af && 516 rt->rt_gateway.sa_family != af) 517 continue; 518 /* Is this route already in our table? */ 519 if ((rt_find(&added, rt)) != NULL) 520 continue; 521 if (rt_doroute(rt)) { 522 TAILQ_REMOVE(&routes, rt, rt_next); 523 TAILQ_INSERT_TAIL(&added, rt, rt_next); 524 } 525 } 526 527 /* Remove old routes we used to manage. */ 528 TAILQ_FOREACH_SAFE(rt, &ctx->routes, rt_next, rtn) { 529 if (rt->rt_dest.sa_family != af && 530 rt->rt_gateway.sa_family != af) 531 continue; 532 TAILQ_REMOVE(&ctx->routes, rt, rt_next); 533 if (rt_find(&added, rt) == NULL) { 534 o = rt->rt_ifp->options ? 535 rt->rt_ifp->options->options : 536 ctx->options; 537 if ((o & 538 (DHCPCD_EXITING | DHCPCD_PERSISTENT)) != 539 (DHCPCD_EXITING | DHCPCD_PERSISTENT)) 540 rt_delete(rt); 541 } 542 TAILQ_INSERT_TAIL(&ctx->froutes, rt, rt_next); 543 } 544 545 rt_headclear(&ctx->routes, af); 546 TAILQ_CONCAT(&ctx->routes, &added, rt_next); 547 548 getfail: 549 rt_headclear(&routes, AF_UNSPEC); 550 } 551