route.c revision 51449
1/* 2 * PPP Routing related Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $FreeBSD: head/usr.sbin/ppp/route.c 51449 1999-09-20 07:36:46Z brian $ 21 * 22 */ 23 24#include <sys/param.h> 25#include <sys/socket.h> 26#include <net/if_types.h> 27#include <net/route.h> 28#include <net/if.h> 29#include <netinet/in.h> 30#include <arpa/inet.h> 31#include <net/if_dl.h> 32#include <netinet/in_systm.h> 33#include <netinet/ip.h> 34#include <sys/un.h> 35 36#include <errno.h> 37#ifdef __NetBSD__ 38#include <signal.h> /* for `errno' ?!? */ 39#endif 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <sys/sysctl.h> 44#include <termios.h> 45 46#include "layer.h" 47#include "defs.h" 48#include "command.h" 49#include "mbuf.h" 50#include "log.h" 51#include "iplist.h" 52#include "timer.h" 53#include "throughput.h" 54#include "lqr.h" 55#include "hdlc.h" 56#include "fsm.h" 57#include "lcp.h" 58#include "ccp.h" 59#include "link.h" 60#include "slcompress.h" 61#include "ipcp.h" 62#include "filter.h" 63#include "descriptor.h" 64#include "mp.h" 65#ifndef NORADIUS 66#include "radius.h" 67#endif 68#include "bundle.h" 69#include "route.h" 70#include "prompt.h" 71#include "iface.h" 72 73static void 74p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 75 struct sockaddr *pmask, int width) 76{ 77 char buf[29]; 78 struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 79 struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 80 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 81 82 switch (phost->sa_family) { 83 case AF_INET: 84 if (!phost) 85 buf[0] = '\0'; 86 else if (ihost->sin_addr.s_addr == INADDR_ANY) 87 strcpy(buf, "default"); 88 else if (!mask) 89 strcpy(buf, inet_ntoa(ihost->sin_addr)); 90 else { 91 u_int32_t msk = ntohl(mask->sin_addr.s_addr); 92 u_int32_t tst; 93 int bits; 94 int len; 95 struct sockaddr_in net; 96 97 for (tst = 1, bits=32; tst; tst <<= 1, bits--) 98 if (msk & tst) 99 break; 100 101 for (tst <<= 1; tst; tst <<= 1) 102 if (!(msk & tst)) 103 break; 104 105 net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 106 strcpy(buf, inet_ntoa(net.sin_addr)); 107 for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 108 if (strcmp(buf + len - 2, ".0")) 109 break; 110 111 if (tst) /* non-contiguous :-( */ 112 sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 113 else 114 sprintf(buf + strlen(buf), "/%d", bits); 115 } 116 break; 117 118 case AF_LINK: 119 if (dl->sdl_nlen) 120 snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 121 else if (dl->sdl_alen) { 122 if (dl->sdl_type == IFT_ETHER) { 123 if (dl->sdl_alen < sizeof buf / 3) { 124 int f; 125 u_char *MAC; 126 127 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 128 for (f = 0; f < dl->sdl_alen; f++) 129 sprintf(buf+f*3, "%02x:", MAC[f]); 130 buf[f*3-1] = '\0'; 131 } else 132 strcpy(buf, "??:??:??:??:??:??"); 133 } else 134 sprintf(buf, "<IFT type %d>", dl->sdl_type); 135 } else if (dl->sdl_slen) 136 sprintf(buf, "<slen %d?>", dl->sdl_slen); 137 else 138 sprintf(buf, "link#%d", dl->sdl_index); 139 break; 140 141 default: 142 sprintf(buf, "<AF type %d>", phost->sa_family); 143 break; 144 } 145 146 prompt_Printf(prompt, "%-*s ", width-1, buf); 147} 148 149static struct bits { 150 u_int32_t b_mask; 151 char b_val; 152} bits[] = { 153 { RTF_UP, 'U' }, 154 { RTF_GATEWAY, 'G' }, 155 { RTF_HOST, 'H' }, 156 { RTF_REJECT, 'R' }, 157 { RTF_DYNAMIC, 'D' }, 158 { RTF_MODIFIED, 'M' }, 159 { RTF_DONE, 'd' }, 160 { RTF_CLONING, 'C' }, 161 { RTF_XRESOLVE, 'X' }, 162 { RTF_LLINFO, 'L' }, 163 { RTF_STATIC, 'S' }, 164 { RTF_PROTO1, '1' }, 165 { RTF_PROTO2, '2' }, 166 { RTF_BLACKHOLE, 'B' }, 167#ifdef RTF_WASCLONED 168 { RTF_WASCLONED, 'W' }, 169#endif 170#ifdef RTF_PRCLONING 171 { RTF_PRCLONING, 'c' }, 172#endif 173#ifdef RTF_PROTO3 174 { RTF_PROTO3, '3' }, 175#endif 176#ifdef RTF_BROADCAST 177 { RTF_BROADCAST, 'b' }, 178#endif 179 { 0, '\0' } 180}; 181 182#ifndef RTF_WASCLONED 183#define RTF_WASCLONED (0) 184#endif 185 186static void 187p_flags(struct prompt *prompt, u_int32_t f, int max) 188{ 189 char name[33], *flags; 190 register struct bits *p = bits; 191 192 if (max > sizeof name - 1) 193 max = sizeof name - 1; 194 195 for (flags = name; p->b_mask && flags - name < max; p++) 196 if (p->b_mask & f) 197 *flags++ = p->b_val; 198 *flags = '\0'; 199 prompt_Printf(prompt, "%-*.*s", max, max, name); 200} 201 202const char * 203Index2Nam(int idx) 204{ 205 /* 206 * XXX: Maybe we should select() on the routing socket so that we can 207 * notice interfaces that come & go (PCCARD support). 208 * Or we could even support a signal that resets these so that 209 * the PCCARD insert/remove events can signal ppp. 210 */ 211 static char **ifs; /* Figure these out once */ 212 static int nifs, debug_done; /* Figure out how many once, and debug once */ 213 214 if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 215 int mib[6], have, had; 216 size_t needed; 217 char *buf, *ptr, *end; 218 struct sockaddr_dl *dl; 219 struct if_msghdr *ifm; 220 221 if (ifs) { 222 free(ifs); 223 ifs = NULL; 224 nifs = 0; 225 } 226 debug_done = 0; 227 228 mib[0] = CTL_NET; 229 mib[1] = PF_ROUTE; 230 mib[2] = 0; 231 mib[3] = 0; 232 mib[4] = NET_RT_IFLIST; 233 mib[5] = 0; 234 235 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 236 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 237 strerror(errno)); 238 return "???"; 239 } 240 if ((buf = malloc(needed)) == NULL) 241 return "???"; 242 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 243 free(buf); 244 return "???"; 245 } 246 end = buf + needed; 247 248 have = 0; 249 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 250 ifm = (struct if_msghdr *)ptr; 251 dl = (struct sockaddr_dl *)(ifm + 1); 252 if (ifm->ifm_index > 0) { 253 if (ifm->ifm_index > have) { 254 char **newifs; 255 256 had = have; 257 have = ifm->ifm_index + 5; 258 if (had) 259 newifs = (char **)realloc(ifs, sizeof(char *) * have); 260 else 261 newifs = (char **)malloc(sizeof(char *) * have); 262 if (!newifs) { 263 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 264 nifs = 0; 265 if (ifs) { 266 free(ifs); 267 ifs = NULL; 268 } 269 free(buf); 270 return "???"; 271 } 272 ifs = newifs; 273 memset(ifs + had, '\0', sizeof(char *) * (have - had)); 274 } 275 if (ifs[ifm->ifm_index-1] == NULL) { 276 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 277 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 278 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 279 if (nifs < ifm->ifm_index) 280 nifs = ifm->ifm_index; 281 } 282 } else if (log_IsKept(LogDEBUG)) 283 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 284 ifm->ifm_index); 285 } 286 free(buf); 287 } 288 289 if (log_IsKept(LogDEBUG) && !debug_done) { 290 int f; 291 292 log_Printf(LogDEBUG, "Found the following interfaces:\n"); 293 for (f = 0; f < nifs; f++) 294 if (ifs[f] != NULL) 295 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 296 debug_done = 1; 297 } 298 299 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 300 return "???"; 301 302 return ifs[idx-1]; 303} 304 305int 306route_Show(struct cmdargs const *arg) 307{ 308 struct rt_msghdr *rtm; 309 struct sockaddr *sa_dst, *sa_gw, *sa_mask; 310 char *sp, *ep, *cp, *wp; 311 size_t needed; 312 int mib[6]; 313 314 mib[0] = CTL_NET; 315 mib[1] = PF_ROUTE; 316 mib[2] = 0; 317 mib[3] = 0; 318 mib[4] = NET_RT_DUMP; 319 mib[5] = 0; 320 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 321 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 322 return (1); 323 } 324 sp = malloc(needed); 325 if (sp == NULL) 326 return (1); 327 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 328 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 329 free(sp); 330 return (1); 331 } 332 ep = sp + needed; 333 334 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 335 "Destination", "Gateway"); 336 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 337 rtm = (struct rt_msghdr *) cp; 338 wp = (char *)(rtm+1); 339 340 if (rtm->rtm_addrs & RTA_DST) { 341 sa_dst = (struct sockaddr *)wp; 342 wp += sa_dst->sa_len; 343 } else 344 sa_dst = NULL; 345 346 if (rtm->rtm_addrs & RTA_GATEWAY) { 347 sa_gw = (struct sockaddr *)wp; 348 wp += sa_gw->sa_len; 349 } else 350 sa_gw = NULL; 351 352 if (rtm->rtm_addrs & RTA_NETMASK) { 353 sa_mask = (struct sockaddr *)wp; 354 wp += sa_mask->sa_len; 355 } else 356 sa_mask = NULL; 357 358 p_sockaddr(arg->prompt, sa_dst, sa_mask, 20); 359 p_sockaddr(arg->prompt, sa_gw, NULL, 20); 360 361 p_flags(arg->prompt, rtm->rtm_flags, 6); 362 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 363 } 364 free(sp); 365 return 0; 366} 367 368/* 369 * Delete routes associated with our interface 370 */ 371void 372route_IfDelete(struct bundle *bundle, int all) 373{ 374 struct rt_msghdr *rtm; 375 struct sockaddr *sa; 376 struct in_addr sa_dst, sa_none; 377 int pass; 378 size_t needed; 379 char *sp, *cp, *ep; 380 int mib[6]; 381 382 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 383 sa_none.s_addr = INADDR_ANY; 384 385 mib[0] = CTL_NET; 386 mib[1] = PF_ROUTE; 387 mib[2] = 0; 388 mib[3] = 0; 389 mib[4] = NET_RT_DUMP; 390 mib[5] = 0; 391 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 392 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 393 strerror(errno)); 394 return; 395 } 396 397 sp = malloc(needed); 398 if (sp == NULL) 399 return; 400 401 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 402 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 403 strerror(errno)); 404 free(sp); 405 return; 406 } 407 ep = sp + needed; 408 409 for (pass = 0; pass < 2; pass++) { 410 /* 411 * We do 2 passes. The first deletes all cloned routes. The second 412 * deletes all non-cloned routes. This is necessary to avoid 413 * potential errors from trying to delete route X after route Y where 414 * route X was cloned from route Y (and is no longer there 'cos it 415 * may have gone with route Y). 416 */ 417 if (RTF_WASCLONED == 0 && pass == 0) 418 /* So we can't tell ! */ 419 continue; 420 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 421 rtm = (struct rt_msghdr *) cp; 422 sa = (struct sockaddr *) (rtm + 1); 423 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 424 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 425 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 426 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 427 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 428 rtm->rtm_index == bundle->iface->index && 429 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 430 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 431 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 432 if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { 433 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 434 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 435 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass); 436 bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0, 0); 437 } else 438 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 439 } else 440 log_Printf(LogDEBUG, 441 "route_IfDelete: Can't remove routes of %d family !\n", 442 sa->sa_family); 443 } 444 } 445 } 446 free(sp); 447} 448 449int 450GetIfIndex(char *name) 451{ 452 int idx; 453 const char *got; 454 455 idx = 1; 456 while (strcmp(got = Index2Nam(idx), "???")) 457 if (!strcmp(got, name)) 458 return idx; 459 else 460 idx++; 461 return -1; 462} 463 464void 465route_Change(struct bundle *bundle, struct sticky_route *r, 466 struct in_addr me, struct in_addr peer) 467{ 468 struct in_addr none, del; 469 470 none.s_addr = INADDR_ANY; 471 for (; r; r = r->next) { 472 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 473 del.s_addr = r->dst.s_addr & r->mask.s_addr; 474 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 475 r->dst = me; 476 if (r->type & ROUTE_GWHISADDR) 477 r->gw = peer; 478 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 479 del.s_addr = r->dst.s_addr & r->mask.s_addr; 480 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 481 r->dst = peer; 482 if (r->type & ROUTE_GWHISADDR) 483 r->gw = peer; 484 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 485 r->gw = peer; 486 bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 487 } 488} 489 490void 491route_Clean(struct bundle *bundle, struct sticky_route *r) 492{ 493 struct in_addr none, del; 494 495 none.s_addr = INADDR_ANY; 496 for (; r; r = r->next) { 497 del.s_addr = r->dst.s_addr & r->mask.s_addr; 498 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 499 } 500} 501 502void 503route_Add(struct sticky_route **rp, int type, struct in_addr dst, 504 struct in_addr mask, struct in_addr gw) 505{ 506 struct sticky_route *r; 507 int dsttype = type & ROUTE_DSTANY; 508 509 r = NULL; 510 while (*rp) { 511 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 512 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 513 /* Oops, we already have this route - unlink it */ 514 free(r); /* impossible really */ 515 r = *rp; 516 *rp = r->next; 517 } else 518 rp = &(*rp)->next; 519 } 520 521 if (!r) 522 r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 523 r->type = type; 524 r->next = NULL; 525 r->dst = dst; 526 r->mask = mask; 527 r->gw = gw; 528 *rp = r; 529} 530 531void 532route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 533{ 534 struct sticky_route *r; 535 int dsttype = type & ROUTE_DSTANY; 536 537 for (; *rp; rp = &(*rp)->next) { 538 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 539 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 540 r = *rp; 541 *rp = r->next; 542 free(r); 543 break; 544 } 545 } 546} 547 548void 549route_DeleteAll(struct sticky_route **rp) 550{ 551 struct sticky_route *r, *rn; 552 553 for (r = *rp; r; r = rn) { 554 rn = r->next; 555 free(r); 556 } 557 *rp = NULL; 558} 559 560void 561route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 562 int indent) 563{ 564 int def; 565 int tlen = strlen(tag); 566 567 if (tlen + 2 > indent) 568 prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 569 else 570 prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 571 572 for (; r; r = r->next) { 573 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 574 575 prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 576 tlen = 0; 577 if (r->type & ROUTE_DSTMYADDR) 578 prompt_Printf(p, "MYADDR"); 579 else if (r->type & ROUTE_DSTHISADDR) 580 prompt_Printf(p, "HISADDR"); 581 else if (!def) 582 prompt_Printf(p, "%s", inet_ntoa(r->dst)); 583 584 if (def) 585 prompt_Printf(p, "default "); 586 else 587 prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 588 589 if (r->type & ROUTE_GWHISADDR) 590 prompt_Printf(p, "HISADDR\n"); 591 else 592 prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 593 } 594} 595