route.c revision 50427
1214501Srpaulo/* 2214501Srpaulo * PPP Routing related Module 3214501Srpaulo * 4214501Srpaulo * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5214501Srpaulo * 6214501Srpaulo * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7214501Srpaulo * 8214501Srpaulo * Redistribution and use in source and binary forms are permitted 9214501Srpaulo * provided that the above copyright notice and this paragraph are 10214501Srpaulo * duplicated in all such forms and that any documentation, 11252726Srpaulo * advertising materials, and other materials related to such 12214501Srpaulo * distribution and use acknowledge that the software was developed 13252726Srpaulo * by the Internet Initiative Japan, Inc. The name of the 14252726Srpaulo * IIJ may not be used to endorse or promote products derived 15214501Srpaulo * from this software without specific prior written permission. 16214501Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17214501Srpaulo * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18214501Srpaulo * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19214501Srpaulo * 20214501Srpaulo * $Id: route.c,v 1.56 1999/05/08 11:07:36 brian Exp $ 21214501Srpaulo * 22214501Srpaulo */ 23252726Srpaulo 24214501Srpaulo#include <sys/param.h> 25214501Srpaulo#include <sys/socket.h> 26214501Srpaulo#include <net/if_types.h> 27214501Srpaulo#include <net/route.h> 28214501Srpaulo#include <net/if.h> 29214501Srpaulo#include <netinet/in.h> 30214501Srpaulo#include <arpa/inet.h> 31214501Srpaulo#include <net/if_dl.h> 32214501Srpaulo#include <netinet/in_systm.h> 33214501Srpaulo#include <netinet/ip.h> 34214501Srpaulo#include <sys/un.h> 35214501Srpaulo 36214501Srpaulo#include <errno.h> 37214501Srpaulo#include <stdio.h> 38214501Srpaulo#include <stdlib.h> 39214501Srpaulo#include <string.h> 40214501Srpaulo#include <sys/sysctl.h> 41214501Srpaulo#include <termios.h> 42214501Srpaulo 43214501Srpaulo#include "layer.h" 44214501Srpaulo#include "defs.h" 45214501Srpaulo#include "command.h" 46214501Srpaulo#include "mbuf.h" 47214501Srpaulo#include "log.h" 48214501Srpaulo#include "iplist.h" 49214501Srpaulo#include "timer.h" 50214501Srpaulo#include "throughput.h" 51214501Srpaulo#include "lqr.h" 52214501Srpaulo#include "hdlc.h" 53214501Srpaulo#include "fsm.h" 54214501Srpaulo#include "lcp.h" 55214501Srpaulo#include "ccp.h" 56252726Srpaulo#include "link.h" 57252726Srpaulo#include "slcompress.h" 58252726Srpaulo#include "ipcp.h" 59252726Srpaulo#include "filter.h" 60252726Srpaulo#include "descriptor.h" 61252726Srpaulo#include "mp.h" 62252726Srpaulo#ifndef NORADIUS 63252726Srpaulo#include "radius.h" 64214501Srpaulo#endif 65214501Srpaulo#include "bundle.h" 66214501Srpaulo#include "route.h" 67214501Srpaulo#include "prompt.h" 68214501Srpaulo#include "iface.h" 69214501Srpaulo 70214501Srpaulostatic void 71214501Srpaulop_sockaddr(struct prompt *prompt, struct sockaddr *phost, 72214501Srpaulo struct sockaddr *pmask, int width) 73214501Srpaulo{ 74214501Srpaulo char buf[29]; 75214501Srpaulo struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 76214501Srpaulo struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 77214501Srpaulo struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 78214501Srpaulo 79214501Srpaulo switch (phost->sa_family) { 80214501Srpaulo case AF_INET: 81214501Srpaulo if (!phost) 82214501Srpaulo buf[0] = '\0'; 83214501Srpaulo else if (ihost->sin_addr.s_addr == INADDR_ANY) 84214501Srpaulo strcpy(buf, "default"); 85214501Srpaulo else if (!mask) 86214501Srpaulo strcpy(buf, inet_ntoa(ihost->sin_addr)); 87214501Srpaulo else { 88214501Srpaulo u_int32_t msk = ntohl(mask->sin_addr.s_addr); 89214501Srpaulo u_int32_t tst; 90214501Srpaulo int bits; 91214501Srpaulo int len; 92214501Srpaulo struct sockaddr_in net; 93214501Srpaulo 94214501Srpaulo for (tst = 1, bits=32; tst; tst <<= 1, bits--) 95214501Srpaulo if (msk & tst) 96214501Srpaulo break; 97214501Srpaulo 98214501Srpaulo for (tst <<= 1; tst; tst <<= 1) 99214501Srpaulo if (!(msk & tst)) 100214501Srpaulo break; 101252726Srpaulo 102214501Srpaulo net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 103214501Srpaulo strcpy(buf, inet_ntoa(net.sin_addr)); 104214501Srpaulo for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 105252726Srpaulo if (strcmp(buf + len - 2, ".0")) 106252726Srpaulo break; 107252726Srpaulo 108252726Srpaulo if (tst) /* non-contiguous :-( */ 109252726Srpaulo sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 110252726Srpaulo else 111214501Srpaulo sprintf(buf + strlen(buf), "/%d", bits); 112214501Srpaulo } 113214501Srpaulo break; 114214501Srpaulo 115214501Srpaulo case AF_LINK: 116214501Srpaulo if (dl->sdl_nlen) 117252726Srpaulo snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 118252726Srpaulo else if (dl->sdl_alen) { 119214501Srpaulo if (dl->sdl_type == IFT_ETHER) { 120214501Srpaulo if (dl->sdl_alen < sizeof buf / 3) { 121214501Srpaulo int f; 122214501Srpaulo u_char *MAC; 123214501Srpaulo 124214501Srpaulo MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 125214501Srpaulo for (f = 0; f < dl->sdl_alen; f++) 126214501Srpaulo sprintf(buf+f*3, "%02x:", MAC[f]); 127 buf[f*3-1] = '\0'; 128 } else 129 strcpy(buf, "??:??:??:??:??:??"); 130 } else 131 sprintf(buf, "<IFT type %d>", dl->sdl_type); 132 } else if (dl->sdl_slen) 133 sprintf(buf, "<slen %d?>", dl->sdl_slen); 134 else 135 sprintf(buf, "link#%d", dl->sdl_index); 136 break; 137 138 default: 139 sprintf(buf, "<AF type %d>", phost->sa_family); 140 break; 141 } 142 143 prompt_Printf(prompt, "%-*s ", width-1, buf); 144} 145 146static struct bits { 147 u_int32_t b_mask; 148 char b_val; 149} bits[] = { 150 { RTF_UP, 'U' }, 151 { RTF_GATEWAY, 'G' }, 152 { RTF_HOST, 'H' }, 153 { RTF_REJECT, 'R' }, 154 { RTF_DYNAMIC, 'D' }, 155 { RTF_MODIFIED, 'M' }, 156 { RTF_DONE, 'd' }, 157 { RTF_CLONING, 'C' }, 158 { RTF_XRESOLVE, 'X' }, 159 { RTF_LLINFO, 'L' }, 160 { RTF_STATIC, 'S' }, 161 { RTF_PROTO1, '1' }, 162 { RTF_PROTO2, '2' }, 163 { RTF_BLACKHOLE, 'B' }, 164#ifdef RTF_WASCLONED 165 { RTF_WASCLONED, 'W' }, 166#endif 167#ifdef RTF_PRCLONING 168 { RTF_PRCLONING, 'c' }, 169#endif 170#ifdef RTF_PROTO3 171 { RTF_PROTO3, '3' }, 172#endif 173#ifdef RTF_BROADCAST 174 { RTF_BROADCAST, 'b' }, 175#endif 176 { 0, '\0' } 177}; 178 179#ifndef RTF_WASCLONED 180#define RTF_WASCLONED (0) 181#endif 182 183static void 184p_flags(struct prompt *prompt, u_int32_t f, int max) 185{ 186 char name[33], *flags; 187 register struct bits *p = bits; 188 189 if (max > sizeof name - 1) 190 max = sizeof name - 1; 191 192 for (flags = name; p->b_mask && flags - name < max; p++) 193 if (p->b_mask & f) 194 *flags++ = p->b_val; 195 *flags = '\0'; 196 prompt_Printf(prompt, "%-*.*s", max, max, name); 197} 198 199const char * 200Index2Nam(int idx) 201{ 202 /* 203 * XXX: Maybe we should select() on the routing socket so that we can 204 * notice interfaces that come & go (PCCARD support). 205 * Or we could even support a signal that resets these so that 206 * the PCCARD insert/remove events can signal ppp. 207 */ 208 static char **ifs; /* Figure these out once */ 209 static int nifs, debug_done; /* Figure out how many once, and debug once */ 210 211 if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 212 int mib[6], have, had; 213 size_t needed; 214 char *buf, *ptr, *end; 215 struct sockaddr_dl *dl; 216 struct if_msghdr *ifm; 217 218 if (ifs) { 219 free(ifs); 220 ifs = NULL; 221 nifs = 0; 222 } 223 debug_done = 0; 224 225 mib[0] = CTL_NET; 226 mib[1] = PF_ROUTE; 227 mib[2] = 0; 228 mib[3] = 0; 229 mib[4] = NET_RT_IFLIST; 230 mib[5] = 0; 231 232 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 233 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 234 strerror(errno)); 235 return "???"; 236 } 237 if ((buf = malloc(needed)) == NULL) 238 return "???"; 239 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 240 free(buf); 241 return "???"; 242 } 243 end = buf + needed; 244 245 have = 0; 246 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 247 ifm = (struct if_msghdr *)ptr; 248 dl = (struct sockaddr_dl *)(ifm + 1); 249 if (ifm->ifm_index > 0) { 250 if (ifm->ifm_index > have) { 251 char **newifs; 252 253 had = have; 254 have = ifm->ifm_index + 5; 255 if (had) 256 newifs = (char **)realloc(ifs, sizeof(char *) * have); 257 else 258 newifs = (char **)malloc(sizeof(char *) * have); 259 if (!newifs) { 260 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 261 nifs = 0; 262 if (ifs) { 263 free(ifs); 264 ifs = NULL; 265 } 266 free(buf); 267 return "???"; 268 } 269 ifs = newifs; 270 memset(ifs + had, '\0', sizeof(char *) * (have - had)); 271 } 272 if (ifs[ifm->ifm_index-1] == NULL) { 273 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 274 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 275 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 276 if (nifs < ifm->ifm_index) 277 nifs = ifm->ifm_index; 278 } 279 } else if (log_IsKept(LogDEBUG)) 280 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 281 ifm->ifm_index); 282 } 283 free(buf); 284 } 285 286 if (log_IsKept(LogDEBUG) && !debug_done) { 287 int f; 288 289 log_Printf(LogDEBUG, "Found the following interfaces:\n"); 290 for (f = 0; f < nifs; f++) 291 if (ifs[f] != NULL) 292 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 293 debug_done = 1; 294 } 295 296 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 297 return "???"; 298 299 return ifs[idx-1]; 300} 301 302int 303route_Show(struct cmdargs const *arg) 304{ 305 struct rt_msghdr *rtm; 306 struct sockaddr *sa_dst, *sa_gw, *sa_mask; 307 char *sp, *ep, *cp, *wp; 308 size_t needed; 309 int mib[6]; 310 311 mib[0] = CTL_NET; 312 mib[1] = PF_ROUTE; 313 mib[2] = 0; 314 mib[3] = 0; 315 mib[4] = NET_RT_DUMP; 316 mib[5] = 0; 317 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 318 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 319 return (1); 320 } 321 sp = malloc(needed); 322 if (sp == NULL) 323 return (1); 324 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 325 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 326 free(sp); 327 return (1); 328 } 329 ep = sp + needed; 330 331 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 332 "Destination", "Gateway"); 333 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 334 rtm = (struct rt_msghdr *) cp; 335 wp = (char *)(rtm+1); 336 337 if (rtm->rtm_addrs & RTA_DST) { 338 sa_dst = (struct sockaddr *)wp; 339 wp += sa_dst->sa_len; 340 } else 341 sa_dst = NULL; 342 343 if (rtm->rtm_addrs & RTA_GATEWAY) { 344 sa_gw = (struct sockaddr *)wp; 345 wp += sa_gw->sa_len; 346 } else 347 sa_gw = NULL; 348 349 if (rtm->rtm_addrs & RTA_NETMASK) { 350 sa_mask = (struct sockaddr *)wp; 351 wp += sa_mask->sa_len; 352 } else 353 sa_mask = NULL; 354 355 p_sockaddr(arg->prompt, sa_dst, sa_mask, 20); 356 p_sockaddr(arg->prompt, sa_gw, NULL, 20); 357 358 p_flags(arg->prompt, rtm->rtm_flags, 6); 359 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 360 } 361 free(sp); 362 return 0; 363} 364 365/* 366 * Delete routes associated with our interface 367 */ 368void 369route_IfDelete(struct bundle *bundle, int all) 370{ 371 struct rt_msghdr *rtm; 372 struct sockaddr *sa; 373 struct in_addr sa_dst, sa_none; 374 int pass; 375 size_t needed; 376 char *sp, *cp, *ep; 377 int mib[6]; 378 379 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 380 sa_none.s_addr = INADDR_ANY; 381 382 mib[0] = CTL_NET; 383 mib[1] = PF_ROUTE; 384 mib[2] = 0; 385 mib[3] = 0; 386 mib[4] = NET_RT_DUMP; 387 mib[5] = 0; 388 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 389 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 390 strerror(errno)); 391 return; 392 } 393 394 sp = malloc(needed); 395 if (sp == NULL) 396 return; 397 398 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 399 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 400 strerror(errno)); 401 free(sp); 402 return; 403 } 404 ep = sp + needed; 405 406 for (pass = 0; pass < 2; pass++) { 407 /* 408 * We do 2 passes. The first deletes all cloned routes. The second 409 * deletes all non-cloned routes. This is necessary to avoid 410 * potential errors from trying to delete route X after route Y where 411 * route X was cloned from route Y (and is no longer there 'cos it 412 * may have gone with route Y). 413 */ 414 if (RTF_WASCLONED == 0 && pass == 0) 415 /* So we can't tell ! */ 416 continue; 417 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 418 rtm = (struct rt_msghdr *) cp; 419 sa = (struct sockaddr *) (rtm + 1); 420 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 421 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 422 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 423 inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 424 if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 425 rtm->rtm_index == bundle->iface->index && 426 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 427 sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 428 sa = (struct sockaddr *)((char *)sa + sa->sa_len); 429 if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { 430 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 431 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 432 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass); 433 bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0, 0); 434 } else 435 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 436 } else 437 log_Printf(LogDEBUG, 438 "route_IfDelete: Can't remove routes of %d family !\n", 439 sa->sa_family); 440 } 441 } 442 } 443 free(sp); 444} 445 446int 447GetIfIndex(char *name) 448{ 449 int idx; 450 const char *got; 451 452 idx = 1; 453 while (strcmp(got = Index2Nam(idx), "???")) 454 if (!strcmp(got, name)) 455 return idx; 456 else 457 idx++; 458 return -1; 459} 460 461void 462route_Change(struct bundle *bundle, struct sticky_route *r, 463 struct in_addr me, struct in_addr peer) 464{ 465 struct in_addr none, del; 466 467 none.s_addr = INADDR_ANY; 468 for (; r; r = r->next) { 469 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 470 del.s_addr = r->dst.s_addr & r->mask.s_addr; 471 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 472 r->dst = me; 473 if (r->type & ROUTE_GWHISADDR) 474 r->gw = peer; 475 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 476 del.s_addr = r->dst.s_addr & r->mask.s_addr; 477 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 478 r->dst = peer; 479 if (r->type & ROUTE_GWHISADDR) 480 r->gw = peer; 481 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 482 r->gw = peer; 483 bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 484 } 485} 486 487void 488route_Clean(struct bundle *bundle, struct sticky_route *r) 489{ 490 struct in_addr none, del; 491 492 none.s_addr = INADDR_ANY; 493 for (; r; r = r->next) { 494 del.s_addr = r->dst.s_addr & r->mask.s_addr; 495 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 496 } 497} 498 499void 500route_Add(struct sticky_route **rp, int type, struct in_addr dst, 501 struct in_addr mask, struct in_addr gw) 502{ 503 struct sticky_route *r; 504 int dsttype = type & ROUTE_DSTANY; 505 506 r = NULL; 507 while (*rp) { 508 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 509 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 510 /* Oops, we already have this route - unlink it */ 511 free(r); /* impossible really */ 512 r = *rp; 513 *rp = r->next; 514 } else 515 rp = &(*rp)->next; 516 } 517 518 if (!r) 519 r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 520 r->type = type; 521 r->next = NULL; 522 r->dst = dst; 523 r->mask = mask; 524 r->gw = gw; 525 *rp = r; 526} 527 528void 529route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 530{ 531 struct sticky_route *r; 532 int dsttype = type & ROUTE_DSTANY; 533 534 for (; *rp; rp = &(*rp)->next) { 535 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 536 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 537 r = *rp; 538 *rp = r->next; 539 free(r); 540 break; 541 } 542 } 543} 544 545void 546route_DeleteAll(struct sticky_route **rp) 547{ 548 struct sticky_route *r, *rn; 549 550 for (r = *rp; r; r = rn) { 551 rn = r->next; 552 free(r); 553 } 554 *rp = NULL; 555} 556 557void 558route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 559 int indent) 560{ 561 int def; 562 int tlen = strlen(tag); 563 564 if (tlen + 2 > indent) 565 prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 566 else 567 prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 568 569 for (; r; r = r->next) { 570 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 571 572 prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 573 tlen = 0; 574 if (r->type & ROUTE_DSTMYADDR) 575 prompt_Printf(p, "MYADDR"); 576 else if (r->type & ROUTE_DSTHISADDR) 577 prompt_Printf(p, "HISADDR"); 578 else if (!def) 579 prompt_Printf(p, "%s", inet_ntoa(r->dst)); 580 581 if (def) 582 prompt_Printf(p, "default "); 583 else 584 prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 585 586 if (r->type & ROUTE_GWHISADDR) 587 prompt_Printf(p, "HISADDR\n"); 588 else 589 prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 590 } 591} 592