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