route.c revision 58034
1139826Simp/* 253541Sshin * PPP Routing related Module 353541Sshin * 453541Sshin * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 553541Sshin * 653541Sshin * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms are permitted 953541Sshin * provided that the above copyright notice and this paragraph are 1053541Sshin * duplicated in all such forms and that any documentation, 1153541Sshin * advertising materials, and other materials related to such 1253541Sshin * distribution and use acknowledge that the software was developed 1353541Sshin * by the Internet Initiative Japan, Inc. The name of the 1453541Sshin * IIJ may not be used to endorse or promote products derived 1553541Sshin * from this software without specific prior written permission. 1653541Sshin * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1753541Sshin * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1853541Sshin * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1953541Sshin * 2053541Sshin * $FreeBSD: head/usr.sbin/ppp/route.c 58034 2000-03-14 01:46:54Z brian $ 2153541Sshin * 2253541Sshin */ 2353541Sshin 2453541Sshin#include <sys/param.h> 2553541Sshin#include <sys/socket.h> 2653541Sshin#include <net/if_types.h> 2753541Sshin#include <net/route.h> 28174510Sobrien#include <net/if.h> 29174510Sobrien#include <netinet/in.h> 3053541Sshin#include <arpa/inet.h> 3153541Sshin#include <net/if_dl.h> 32139826Simp#include <netinet/in_systm.h> 3353541Sshin#include <netinet/ip.h> 3453541Sshin#include <sys/un.h> 3553541Sshin#ifndef NOINET6 3653541Sshin#include <netinet6/in6.h> 3753541Sshin#endif 3853541Sshin#include <netdb.h> 3953541Sshin 4053541Sshin#include <errno.h> 4153541Sshin#include <stdio.h> 4253541Sshin#include <stdlib.h> 4353541Sshin#include <string.h> 4453541Sshin#include <sys/sysctl.h> 4553541Sshin#include <termios.h> 4653541Sshin 4753541Sshin#include "layer.h" 4853541Sshin#include "defs.h" 4953541Sshin#include "command.h" 5053541Sshin#include "mbuf.h" 5153541Sshin#include "log.h" 5253541Sshin#include "iplist.h" 5353541Sshin#include "timer.h" 5453541Sshin#include "throughput.h" 5553541Sshin#include "lqr.h" 5653541Sshin#include "hdlc.h" 5753541Sshin#include "fsm.h" 5853541Sshin#include "lcp.h" 5953541Sshin#include "ccp.h" 6053541Sshin#include "link.h" 6153541Sshin#include "slcompress.h" 62174510Sobrien#include "ipcp.h" 63174510Sobrien#include "filter.h" 64174510Sobrien#include "descriptor.h" 6553541Sshin#include "mp.h" 6653541Sshin#ifndef NORADIUS 6753541Sshin#include "radius.h" 68185751Simp#endif 6953541Sshin#include "bundle.h" 7053541Sshin#include "route.h" 7153541Sshin#include "prompt.h" 7253541Sshin#include "iface.h" 73185747Skmacy 7453541Sshin 75120727Ssamstatic void 7653541Sshinp_sockaddr(struct prompt *prompt, struct sockaddr *phost, 7753541Sshin struct sockaddr *pmask, int width) 78257176Sglebius{ 79194714Sbz char buf[29]; 80185571Sbz struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 8153541Sshin struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 8253541Sshin struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 8353541Sshin 8453541Sshin if (log_IsKept(LogDEBUG)) { 8562587Sitojun char tmp[50]; 8653541Sshin 8753541Sshin log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 8862587Sitojun log_Printf(LogDEBUG, " Family %d, len %d\n", 89121283Sume (int)phost->sa_family, (int)phost->sa_len); 9053541Sshin inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 9153541Sshin log_Printf(LogDEBUG, " Addr %s\n", tmp); 9253541Sshin if (pmask) { 9353541Sshin inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 9453541Sshin log_Printf(LogDEBUG, " Mask %s\n", tmp); 9553541Sshin } 96175162Sobrien } 97193731Szec 98193731Szec switch (phost->sa_family) { 99193731Szec case AF_INET: 10053541Sshin if (!phost) 10153541Sshin buf[0] = '\0'; 10253541Sshin else if (ihost4->sin_addr.s_addr == INADDR_ANY) 10353541Sshin strcpy(buf, "default"); 10453541Sshin else if (!pmask) 10553541Sshin strcpy(buf, inet_ntoa(ihost4->sin_addr)); 106171260Sdelphij else { 10753541Sshin u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 10853541Sshin u_int32_t tst; 10953541Sshin int bits; 11053541Sshin int len; 11153541Sshin struct sockaddr_in net; 112186119Sqingli 11353541Sshin for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 11453541Sshin if (msk & tst) 11553541Sshin break; 11653541Sshin 11753541Sshin for (tst <<= 1; tst; tst <<= 1) 11853541Sshin if (!(msk & tst)) 11953541Sshin break; 12053541Sshin 12153541Sshin net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 12253541Sshin strcpy(buf, inet_ntoa(net.sin_addr)); 12353541Sshin for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 12453541Sshin if (strcmp(buf + len - 2, ".0")) 12553541Sshin break; 12653541Sshin 12753541Sshin if (tst) /* non-contiguous :-( */ 12853541Sshin sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 12953541Sshin else 13053541Sshin sprintf(buf + strlen(buf), "/%d", bits); 13153541Sshin } 13253541Sshin break; 13353541Sshin 13453541Sshin case AF_LINK: 13553541Sshin if (dl->sdl_nlen) 13653541Sshin snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 13753541Sshin else if (dl->sdl_alen) { 138274175Smelifaro if (dl->sdl_type == IFT_ETHER) { 13953541Sshin if (dl->sdl_alen < sizeof buf / 3) { 140274175Smelifaro int f; 141274175Smelifaro u_char *MAC; 142274175Smelifaro 143274175Smelifaro MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 144274175Smelifaro for (f = 0; f < dl->sdl_alen; f++) 145274175Smelifaro sprintf(buf+f*3, "%02x:", MAC[f]); 146274175Smelifaro buf[f*3-1] = '\0'; 147274175Smelifaro } else 148274175Smelifaro strcpy(buf, "??:??:??:??:??:??"); 149274175Smelifaro } else 150274175Smelifaro sprintf(buf, "<IFT type %d>", dl->sdl_type); 15153541Sshin } else if (dl->sdl_slen) 152186119Sqingli sprintf(buf, "<slen %d?>", dl->sdl_slen); 15353541Sshin else 15453541Sshin sprintf(buf, "link#%d", dl->sdl_index); 15553541Sshin break; 15653541Sshin 15753541Sshin#ifndef NOINET6 15853541Sshin case AF_INET6: 15953541Sshin if (!phost) 16053541Sshin buf[0] = '\0'; 16153541Sshin else { 16253541Sshin const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 16353541Sshin struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 16453541Sshin struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 16553541Sshin int masklen, len; 166231852Sbz const u_char *c; 167231852Sbz 16853541Sshin /* XXX: ?????!?!?!!!!! This is horrible ! */ 169186119Sqingli if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 17053541Sshin IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 17153541Sshin ihost6->sin6_scope_id = 17253541Sshin ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 17353541Sshin *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 17453541Sshin } 175120727Ssam 17653541Sshin if (mask6) { 17753541Sshin const u_char *p, *end; 178186119Sqingli 17953541Sshin p = (const u_char *)&mask6->sin6_addr; 18053541Sshin end = p + 16; 18153541Sshin for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 18253541Sshin masklen += 8; 18353541Sshin 18453541Sshin if (p < end) { 18553541Sshin for (c = masks; c < masks + sizeof masks; c++) 18653541Sshin if (*c == *p) { 18753541Sshin masklen += c - masks; 188215701Sdim break; 189195727Srwatson } 190195699Srwatson } 19153541Sshin } else 192286458Smelifaro masklen = 128; 19353541Sshin 19453541Sshin if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 19553541Sshin snprintf(buf, sizeof buf, "default"); 196262763Sglebius else { 197262763Sglebius getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 19853541Sshin NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 19953541Sshin if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 200262763Sglebius snprintf(buf + len, sizeof buf - len, "/%d", masklen); 20153541Sshin } 20253541Sshin } 20353541Sshin break; 204286458Smelifaro#endif 20553541Sshin 20653541Sshin default: 20753541Sshin sprintf(buf, "<AF type %d>", phost->sa_family); 20853541Sshin break; 20953541Sshin } 210286594Smelifaro 211286594Smelifaro prompt_Printf(prompt, "%-*s ", width-1, buf); 21253541Sshin} 213286458Smelifaro 21453541Sshinstatic struct bits { 215286458Smelifaro u_int32_t b_mask; 216286458Smelifaro char b_val; 217286458Smelifaro} bits[] = { 218231852Sbz { RTF_UP, 'U' }, 21953541Sshin { RTF_GATEWAY, 'G' }, 220231852Sbz { RTF_HOST, 'H' }, 221231852Sbz { RTF_REJECT, 'R' }, 222231852Sbz { RTF_DYNAMIC, 'D' }, 223231852Sbz { RTF_MODIFIED, 'M' }, 224231852Sbz { RTF_DONE, 'd' }, 225286458Smelifaro { RTF_CLONING, 'C' }, 226231852Sbz { RTF_XRESOLVE, 'X' }, 227286594Smelifaro { RTF_LLINFO, 'L' }, 228231852Sbz { RTF_STATIC, 'S' }, 229231852Sbz { RTF_PROTO1, '1' }, 23053541Sshin { RTF_PROTO2, '2' }, 231181803Sbz { RTF_BLACKHOLE, 'B' }, 232183550Szec#ifdef RTF_WASCLONED 23353541Sshin { RTF_WASCLONED, 'W' }, 23453541Sshin#endif 23553541Sshin#ifdef RTF_PRCLONING 23653541Sshin { RTF_PRCLONING, 'c' }, 23753541Sshin#endif 238231852Sbz#ifdef RTF_PROTO3 239231852Sbz { RTF_PROTO3, '3' }, 240231852Sbz#endif 24153541Sshin#ifdef RTF_BROADCAST 24253541Sshin { RTF_BROADCAST, 'b' }, 24353541Sshin#endif 24453541Sshin { 0, '\0' } 24553541Sshin}; 246178888Sjulian 247274118Smelifaro#ifndef RTF_WASCLONED 24853541Sshin#define RTF_WASCLONED (0) 249272361Smelifaro#endif 250272361Smelifaro 251272361Smelifarostatic void 25253541Sshinp_flags(struct prompt *prompt, u_int32_t f, int max) 253231852Sbz{ 254231852Sbz char name[33], *flags; 255283291Sjkim register struct bits *p = bits; 256231852Sbz 257231852Sbz if (max > sizeof name - 1) 258231852Sbz max = sizeof name - 1; 259231852Sbz 260274118Smelifaro for (flags = name; p->b_mask && flags - name < max; p++) 26153541Sshin if (p->b_mask & f) 262193731Szec *flags++ = p->b_val; 263193731Szec *flags = '\0'; 264193731Szec prompt_Printf(prompt, "%-*.*s", max, max, name); 265193731Szec} 266193731Szec 267193731Szecconst char * 268193731SzecIndex2Nam(int idx) 269193731Szec{ 270193731Szec /* 271193731Szec * XXX: Maybe we should select() on the routing socket so that we can 272231852Sbz * notice interfaces that come & go (PCCARD support). 273231852Sbz * Or we could even support a signal that resets these so that 274231852Sbz * the PCCARD insert/remove events can signal ppp. 275231852Sbz */ 276231852Sbz static char **ifs; /* Figure these out once */ 277231852Sbz static int nifs, debug_done; /* Figure out how many once, and debug once */ 278231852Sbz 279231852Sbz if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 280231852Sbz int mib[6], have, had; 281231852Sbz size_t needed; 282231852Sbz char *buf, *ptr, *end; 283231852Sbz struct sockaddr_dl *dl; 284231852Sbz struct if_msghdr *ifm; 285231852Sbz 286231852Sbz if (ifs) { 287231852Sbz free(ifs); 288231852Sbz ifs = NULL; 289231852Sbz nifs = 0; 290231852Sbz } 291231852Sbz debug_done = 0; 292231852Sbz 293231852Sbz mib[0] = CTL_NET; 294231852Sbz mib[1] = PF_ROUTE; 295231852Sbz mib[2] = 0; 296231852Sbz mib[3] = 0; 297231852Sbz mib[4] = NET_RT_IFLIST; 298231852Sbz mib[5] = 0; 299231852Sbz 300231852Sbz if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 301231852Sbz log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 302231852Sbz strerror(errno)); 303231852Sbz return NumStr(idx, NULL, 0); 304231852Sbz } 305231852Sbz if ((buf = malloc(needed)) == NULL) 306231852Sbz return NumStr(idx, NULL, 0); 307231852Sbz if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 308231852Sbz free(buf); 309231852Sbz return NumStr(idx, NULL, 0); 310231852Sbz } 311231852Sbz end = buf + needed; 312 313 have = 0; 314 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 315 ifm = (struct if_msghdr *)ptr; 316 if (ifm->ifm_type != RTM_IFINFO) 317 break; 318 dl = (struct sockaddr_dl *)(ifm + 1); 319 if (ifm->ifm_index > 0) { 320 if (ifm->ifm_index > have) { 321 char **newifs; 322 323 had = have; 324 have = ifm->ifm_index + 5; 325 if (had) 326 newifs = (char **)realloc(ifs, sizeof(char *) * have); 327 else 328 newifs = (char **)malloc(sizeof(char *) * have); 329 if (!newifs) { 330 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 331 nifs = 0; 332 if (ifs) { 333 free(ifs); 334 ifs = NULL; 335 } 336 free(buf); 337 return NumStr(idx, NULL, 0); 338 } 339 ifs = newifs; 340 memset(ifs + had, '\0', sizeof(char *) * (have - had)); 341 } 342 if (ifs[ifm->ifm_index-1] == NULL) { 343 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 344 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 345 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 346 if (nifs < ifm->ifm_index) 347 nifs = ifm->ifm_index; 348 } 349 } else if (log_IsKept(LogDEBUG)) 350 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 351 ifm->ifm_index); 352 } 353 free(buf); 354 } 355 356 if (log_IsKept(LogDEBUG) && !debug_done) { 357 int f; 358 359 log_Printf(LogDEBUG, "Found the following interfaces:\n"); 360 for (f = 0; f < nifs; f++) 361 if (ifs[f] != NULL) 362 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 363 debug_done = 1; 364 } 365 366 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 367 return NumStr(idx, NULL, 0); 368 369 return ifs[idx-1]; 370} 371 372void 373route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 374{ 375 char *wp; 376 int rtax; 377 378 wp = (char *)(rtm + 1); 379 380 for (rtax = 0; rtax < RTAX_MAX; rtax++) 381 if (rtm->rtm_addrs & (1 << rtax)) { 382 sa[rtax] = (struct sockaddr *)wp; 383 wp += ROUNDUP(sa[rtax]->sa_len); 384 } else 385 sa[rtax] = NULL; 386} 387 388int 389route_Show(struct cmdargs const *arg) 390{ 391 struct rt_msghdr *rtm; 392 struct sockaddr *sa[RTAX_MAX]; 393 char *sp, *ep, *cp; 394 size_t needed; 395 int mib[6]; 396 397 mib[0] = CTL_NET; 398 mib[1] = PF_ROUTE; 399 mib[2] = 0; 400 mib[3] = 0; 401 mib[4] = NET_RT_DUMP; 402 mib[5] = 0; 403 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 404 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 405 return (1); 406 } 407 sp = malloc(needed); 408 if (sp == NULL) 409 return (1); 410 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 411 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 412 free(sp); 413 return (1); 414 } 415 ep = sp + needed; 416 417 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 418 "Destination", "Gateway"); 419 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 420 rtm = (struct rt_msghdr *)cp; 421 422 route_ParseHdr(rtm, sa); 423 424 if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 425 p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 426 p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 427 428 p_flags(arg->prompt, rtm->rtm_flags, 6); 429 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 430 } else 431 prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 432 } 433 free(sp); 434 return 0; 435} 436 437/* 438 * Delete routes associated with our interface 439 */ 440void 441route_IfDelete(struct bundle *bundle, int all) 442{ 443 struct rt_msghdr *rtm; 444 struct sockaddr *sa[RTAX_MAX]; 445 struct sockaddr_in **in; 446 struct in_addr sa_none; 447 int pass; 448 size_t needed; 449 char *sp, *cp, *ep; 450 int mib[6]; 451 452 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 453 sa_none.s_addr = INADDR_ANY; 454 in = (struct sockaddr_in **)sa; 455 456 mib[0] = CTL_NET; 457 mib[1] = PF_ROUTE; 458 mib[2] = 0; 459 mib[3] = 0; 460 mib[4] = NET_RT_DUMP; 461 mib[5] = 0; 462 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 463 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 464 strerror(errno)); 465 return; 466 } 467 468 sp = malloc(needed); 469 if (sp == NULL) 470 return; 471 472 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 473 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 474 strerror(errno)); 475 free(sp); 476 return; 477 } 478 ep = sp + needed; 479 480 for (pass = 0; pass < 2; pass++) { 481 /* 482 * We do 2 passes. The first deletes all cloned routes. The second 483 * deletes all non-cloned routes. This is done to avoid 484 * potential errors from trying to delete route X after route Y where 485 * route X was cloned from route Y (and is no longer there 'cos it 486 * may have gone with route Y). 487 */ 488 if (RTF_WASCLONED == 0 && pass == 0) 489 /* So we can't tell ! */ 490 continue; 491 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 492 rtm = (struct rt_msghdr *)cp; 493 route_ParseHdr(rtm, sa); 494 if (sa[RTAX_DST]) { 495 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 496 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 497 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 498 inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 499 if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 500 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 501 if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 502 sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 503 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 504 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 505 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 506 pass); 507 bundle_SetRoute(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 508 sa_none, sa_none, 0, 0); 509 } else 510 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 511 } else 512 log_Printf(LogDEBUG, 513 "route_IfDelete: Can't remove routes of %d family !\n", 514 sa[RTAX_GATEWAY]->sa_family); 515 } 516 } 517 } 518 } 519 free(sp); 520} 521 522int 523GetIfIndex(char *name) 524{ 525 int idx; 526 const char *got; 527 528 idx = 1; 529 while (strcmp(got = Index2Nam(idx), "???")) 530 if (!strcmp(got, name)) 531 return idx; 532 else 533 idx++; 534 return -1; 535} 536 537void 538route_Change(struct bundle *bundle, struct sticky_route *r, 539 struct in_addr me, struct in_addr peer) 540{ 541 struct in_addr none, del; 542 543 none.s_addr = INADDR_ANY; 544 for (; r; r = r->next) { 545 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 546 del.s_addr = r->dst.s_addr & r->mask.s_addr; 547 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 548 r->dst = me; 549 if (r->type & ROUTE_GWHISADDR) 550 r->gw = peer; 551 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 552 del.s_addr = r->dst.s_addr & r->mask.s_addr; 553 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 554 r->dst = peer; 555 if (r->type & ROUTE_GWHISADDR) 556 r->gw = peer; 557 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 558 r->gw = peer; 559 bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 560 } 561} 562 563void 564route_Clean(struct bundle *bundle, struct sticky_route *r) 565{ 566 struct in_addr none, del; 567 568 none.s_addr = INADDR_ANY; 569 for (; r; r = r->next) { 570 del.s_addr = r->dst.s_addr & r->mask.s_addr; 571 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 572 } 573} 574 575void 576route_Add(struct sticky_route **rp, int type, struct in_addr dst, 577 struct in_addr mask, struct in_addr gw) 578{ 579 struct sticky_route *r; 580 int dsttype = type & ROUTE_DSTANY; 581 582 r = NULL; 583 while (*rp) { 584 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 585 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 586 /* Oops, we already have this route - unlink it */ 587 free(r); /* impossible really */ 588 r = *rp; 589 *rp = r->next; 590 } else 591 rp = &(*rp)->next; 592 } 593 594 if (!r) 595 r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 596 r->type = type; 597 r->next = NULL; 598 r->dst = dst; 599 r->mask = mask; 600 r->gw = gw; 601 *rp = r; 602} 603 604void 605route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 606{ 607 struct sticky_route *r; 608 int dsttype = type & ROUTE_DSTANY; 609 610 for (; *rp; rp = &(*rp)->next) { 611 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 612 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 613 r = *rp; 614 *rp = r->next; 615 free(r); 616 break; 617 } 618 } 619} 620 621void 622route_DeleteAll(struct sticky_route **rp) 623{ 624 struct sticky_route *r, *rn; 625 626 for (r = *rp; r; r = rn) { 627 rn = r->next; 628 free(r); 629 } 630 *rp = NULL; 631} 632 633void 634route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 635 int indent) 636{ 637 int def; 638 int tlen = strlen(tag); 639 640 if (tlen + 2 > indent) 641 prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 642 else 643 prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 644 645 for (; r; r = r->next) { 646 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 647 648 prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 649 tlen = 0; 650 if (r->type & ROUTE_DSTMYADDR) 651 prompt_Printf(p, "MYADDR"); 652 else if (r->type & ROUTE_DSTHISADDR) 653 prompt_Printf(p, "HISADDR"); 654 else if (!def) 655 prompt_Printf(p, "%s", inet_ntoa(r->dst)); 656 657 if (def) 658 prompt_Printf(p, "default "); 659 else 660 prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 661 662 if (r->type & ROUTE_GWHISADDR) 663 prompt_Printf(p, "HISADDR\n"); 664 else 665 prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 666 } 667} 668