route.c revision 50479
16059Samurai/* 26059Samurai * PPP Routing related Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2050479Speter * $FreeBSD: head/usr.sbin/ppp/route.c 50479 1999-08-28 01:35:59Z peter $ 218857Srgrimes * 226059Samurai */ 2330715Sbrian 2443313Sbrian#include <sys/param.h> 256059Samurai#include <sys/socket.h> 2631176Sbrian#include <net/if_types.h> 2730715Sbrian#include <net/route.h> 2830715Sbrian#include <net/if.h> 2930715Sbrian#include <netinet/in.h> 3030715Sbrian#include <arpa/inet.h> 3131176Sbrian#include <net/if_dl.h> 3236285Sbrian#include <netinet/in_systm.h> 3336285Sbrian#include <netinet/ip.h> 3436285Sbrian#include <sys/un.h> 3520287Swollman 3620287Swollman#include <errno.h> 3730715Sbrian#include <stdio.h> 386059Samurai#include <stdlib.h> 396059Samurai#include <string.h> 4030715Sbrian#include <sys/sysctl.h> 4136285Sbrian#include <termios.h> 4220287Swollman 4346686Sbrian#include "layer.h" 4437009Sbrian#include "defs.h" 4531343Sbrian#include "command.h" 4630715Sbrian#include "mbuf.h" 479439Samurai#include "log.h" 4836285Sbrian#include "iplist.h" 4936285Sbrian#include "timer.h" 5036285Sbrian#include "throughput.h" 5136285Sbrian#include "lqr.h" 5236285Sbrian#include "hdlc.h" 5336285Sbrian#include "fsm.h" 5436285Sbrian#include "lcp.h" 5536285Sbrian#include "ccp.h" 5636285Sbrian#include "link.h" 5736285Sbrian#include "slcompress.h" 5831690Sbrian#include "ipcp.h" 5936285Sbrian#include "filter.h" 6036285Sbrian#include "descriptor.h" 6136285Sbrian#include "mp.h" 6243313Sbrian#ifndef NORADIUS 6343313Sbrian#include "radius.h" 6443313Sbrian#endif 6536285Sbrian#include "bundle.h" 6630715Sbrian#include "route.h" 6736285Sbrian#include "prompt.h" 6840561Sbrian#include "iface.h" 696059Samurai 706059Samuraistatic void 7136285Sbrianp_sockaddr(struct prompt *prompt, struct sockaddr *phost, 7236285Sbrian struct sockaddr *pmask, int width) 736059Samurai{ 7431343Sbrian char buf[29]; 7531176Sbrian struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 7631176Sbrian struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 7731176Sbrian struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 786059Samurai 7931176Sbrian switch (phost->sa_family) { 8031176Sbrian case AF_INET: 8131176Sbrian if (!phost) 8231541Sbrian buf[0] = '\0'; 8331176Sbrian else if (ihost->sin_addr.s_addr == INADDR_ANY) 8431541Sbrian strcpy(buf, "default"); 8531176Sbrian else if (!mask) 8631541Sbrian strcpy(buf, inet_ntoa(ihost->sin_addr)); 8731176Sbrian else { 8837210Sbrian u_int32_t msk = ntohl(mask->sin_addr.s_addr); 8937210Sbrian u_int32_t tst; 9031176Sbrian int bits; 9131176Sbrian int len; 9231176Sbrian struct sockaddr_in net; 9331176Sbrian 9431176Sbrian for (tst = 1, bits=32; tst; tst <<= 1, bits--) 9531176Sbrian if (msk & tst) 9631176Sbrian break; 9731176Sbrian 9837210Sbrian for (tst <<= 1; tst; tst <<= 1) 9931176Sbrian if (!(msk & tst)) 10031176Sbrian break; 10131176Sbrian 10231176Sbrian net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 10331791Sbrian strcpy(buf, inet_ntoa(net.sin_addr)); 10437210Sbrian for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 10537210Sbrian if (strcmp(buf + len - 2, ".0")) 10631176Sbrian break; 10731176Sbrian 10831176Sbrian if (tst) /* non-contiguous :-( */ 10937210Sbrian sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 11031176Sbrian else 11137210Sbrian sprintf(buf + strlen(buf), "/%d", bits); 11231176Sbrian } 11331176Sbrian break; 11431176Sbrian 11531176Sbrian case AF_LINK: 11631541Sbrian if (dl->sdl_nlen) 11731541Sbrian snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 11834536Sbrian else if (dl->sdl_alen) { 11934536Sbrian if (dl->sdl_type == IFT_ETHER) { 12031962Sbrian if (dl->sdl_alen < sizeof buf / 3) { 12131541Sbrian int f; 12231541Sbrian u_char *MAC; 12331541Sbrian 12431541Sbrian MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 12531541Sbrian for (f = 0; f < dl->sdl_alen; f++) 12631541Sbrian sprintf(buf+f*3, "%02x:", MAC[f]); 12731541Sbrian buf[f*3-1] = '\0'; 12831541Sbrian } else 12931791Sbrian strcpy(buf, "??:??:??:??:??:??"); 13034536Sbrian } else 13131541Sbrian sprintf(buf, "<IFT type %d>", dl->sdl_type); 13236285Sbrian } else if (dl->sdl_slen) 13331541Sbrian sprintf(buf, "<slen %d?>", dl->sdl_slen); 13431541Sbrian else 13531176Sbrian sprintf(buf, "link#%d", dl->sdl_index); 13631176Sbrian break; 13731176Sbrian 13831176Sbrian default: 13931541Sbrian sprintf(buf, "<AF type %d>", phost->sa_family); 14031176Sbrian break; 14126516Sbrian } 14231176Sbrian 14336285Sbrian prompt_Printf(prompt, "%-*s ", width-1, buf); 1446059Samurai} 1456059Samurai 14632663Sbrianstatic struct bits { 14737189Sbrian u_int32_t b_mask; 14828679Sbrian char b_val; 14931176Sbrian} bits[] = { 15031176Sbrian { RTF_UP, 'U' }, 15131176Sbrian { RTF_GATEWAY, 'G' }, 15231176Sbrian { RTF_HOST, 'H' }, 15331176Sbrian { RTF_REJECT, 'R' }, 15431176Sbrian { RTF_DYNAMIC, 'D' }, 15531176Sbrian { RTF_MODIFIED, 'M' }, 15631176Sbrian { RTF_DONE, 'd' }, 15731176Sbrian { RTF_CLONING, 'C' }, 15831176Sbrian { RTF_XRESOLVE, 'X' }, 15931176Sbrian { RTF_LLINFO, 'L' }, 16031176Sbrian { RTF_STATIC, 'S' }, 16131176Sbrian { RTF_PROTO1, '1' }, 16231176Sbrian { RTF_PROTO2, '2' }, 16331176Sbrian { RTF_BLACKHOLE, 'B' }, 16431739Sbrian#ifdef RTF_WASCLONED 16531176Sbrian { RTF_WASCLONED, 'W' }, 16631739Sbrian#endif 16731739Sbrian#ifdef RTF_PRCLONING 16831176Sbrian { RTF_PRCLONING, 'c' }, 16931739Sbrian#endif 17031739Sbrian#ifdef RTF_PROTO3 17131176Sbrian { RTF_PROTO3, '3' }, 17231739Sbrian#endif 17331739Sbrian#ifdef RTF_BROADCAST 17431176Sbrian { RTF_BROADCAST, 'b' }, 17531176Sbrian#endif 17631176Sbrian { 0, '\0' } 1776059Samurai}; 1786059Samurai 17931739Sbrian#ifndef RTF_WASCLONED 18031739Sbrian#define RTF_WASCLONED (0) 18131739Sbrian#endif 18231739Sbrian 1836059Samuraistatic void 18437189Sbrianp_flags(struct prompt *prompt, u_int32_t f, int max) 1856059Samurai{ 18636285Sbrian char name[33], *flags; 18736285Sbrian register struct bits *p = bits; 1886059Samurai 18936285Sbrian if (max > sizeof name - 1) 19036285Sbrian max = sizeof name - 1; 19131827Sbrian 19236285Sbrian for (flags = name; p->b_mask && flags - name < max; p++) 19336285Sbrian if (p->b_mask & f) 19436285Sbrian *flags++ = p->b_val; 19536285Sbrian *flags = '\0'; 19636285Sbrian prompt_Printf(prompt, "%-*.*s", max, max, name); 1976059Samurai} 1986059Samurai 19932616Sbrianconst char * 20031176SbrianIndex2Nam(int idx) 20131176Sbrian{ 20237010Sbrian /* 20337010Sbrian * XXX: Maybe we should select() on the routing socket so that we can 20437010Sbrian * notice interfaces that come & go (PCCARD support). 20537010Sbrian * Or we could even support a signal that resets these so that 20637010Sbrian * the PCCARD insert/remove events can signal ppp. 20737010Sbrian */ 20837010Sbrian static char **ifs; /* Figure these out once */ 20937010Sbrian static int nifs, debug_done; /* Figure out how many once, and debug once */ 21031176Sbrian 21150427Sbrian if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 21232425Sbrian int mib[6], have, had; 21332021Sbrian size_t needed; 21431176Sbrian char *buf, *ptr, *end; 21531176Sbrian struct sockaddr_dl *dl; 21631176Sbrian struct if_msghdr *ifm; 21731176Sbrian 21850427Sbrian if (ifs) { 21950427Sbrian free(ifs); 22050427Sbrian ifs = NULL; 22150427Sbrian nifs = 0; 22250427Sbrian } 22350427Sbrian debug_done = 0; 22450427Sbrian 22531176Sbrian mib[0] = CTL_NET; 22631176Sbrian mib[1] = PF_ROUTE; 22731176Sbrian mib[2] = 0; 22831176Sbrian mib[3] = 0; 22931176Sbrian mib[4] = NET_RT_IFLIST; 23031176Sbrian mib[5] = 0; 23131176Sbrian 23231176Sbrian if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 23337019Sbrian log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 23437019Sbrian strerror(errno)); 23531176Sbrian return "???"; 23631176Sbrian } 23731176Sbrian if ((buf = malloc(needed)) == NULL) 23831176Sbrian return "???"; 23931176Sbrian if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 24031176Sbrian free(buf); 24131176Sbrian return "???"; 24231176Sbrian } 24331176Sbrian end = buf + needed; 24431176Sbrian 24532425Sbrian have = 0; 24631354Sbrian for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 24731176Sbrian ifm = (struct if_msghdr *)ptr; 24831176Sbrian dl = (struct sockaddr_dl *)(ifm + 1); 24932425Sbrian if (ifm->ifm_index > 0) { 25032425Sbrian if (ifm->ifm_index > have) { 25138381Sbrian char **newifs; 25238381Sbrian 25332425Sbrian had = have; 25432425Sbrian have = ifm->ifm_index + 5; 25532425Sbrian if (had) 25638381Sbrian newifs = (char **)realloc(ifs, sizeof(char *) * have); 25732425Sbrian else 25838381Sbrian newifs = (char **)malloc(sizeof(char *) * have); 25938381Sbrian if (!newifs) { 26036285Sbrian log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 26132425Sbrian nifs = 0; 26250427Sbrian if (ifs) { 26338381Sbrian free(ifs); 26450427Sbrian ifs = NULL; 26550427Sbrian } 26650427Sbrian free(buf); 26732425Sbrian return "???"; 26832425Sbrian } 26938381Sbrian ifs = newifs; 27032425Sbrian memset(ifs + had, '\0', sizeof(char *) * (have - had)); 27132425Sbrian } 27232425Sbrian if (ifs[ifm->ifm_index-1] == NULL) { 27332425Sbrian ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 27432425Sbrian memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 27532425Sbrian ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 27632425Sbrian if (nifs < ifm->ifm_index) 27732425Sbrian nifs = ifm->ifm_index; 27832425Sbrian } 27936285Sbrian } else if (log_IsKept(LogDEBUG)) 28036285Sbrian log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 28131354Sbrian ifm->ifm_index); 28231176Sbrian } 28331176Sbrian free(buf); 28431176Sbrian } 28531176Sbrian 28636285Sbrian if (log_IsKept(LogDEBUG) && !debug_done) { 28731354Sbrian int f; 28831354Sbrian 28936285Sbrian log_Printf(LogDEBUG, "Found the following interfaces:\n"); 29031354Sbrian for (f = 0; f < nifs; f++) 29132425Sbrian if (ifs[f] != NULL) 29236285Sbrian log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 29331354Sbrian debug_done = 1; 29431354Sbrian } 29531354Sbrian 29632425Sbrian if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 29731176Sbrian return "???"; 29831354Sbrian 29931354Sbrian return ifs[idx-1]; 30031176Sbrian} 30131176Sbrian 3026059Samuraiint 30336285Sbrianroute_Show(struct cmdargs const *arg) 3046059Samurai{ 3056059Samurai struct rt_msghdr *rtm; 30631176Sbrian struct sockaddr *sa_dst, *sa_gw, *sa_mask; 30731176Sbrian char *sp, *ep, *cp, *wp; 30832021Sbrian size_t needed; 3096735Samurai int mib[6]; 3106059Samurai 3116059Samurai mib[0] = CTL_NET; 3126059Samurai mib[1] = PF_ROUTE; 3136735Samurai mib[2] = 0; 3146735Samurai mib[3] = 0; 3156059Samurai mib[4] = NET_RT_DUMP; 3166735Samurai mib[5] = 0; 3176735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 31836285Sbrian log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 31928679Sbrian return (1); 3206735Samurai } 3216059Samurai sp = malloc(needed); 3226059Samurai if (sp == NULL) 32328679Sbrian return (1); 3246735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 32536285Sbrian log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 32618885Sjkh free(sp); 32728679Sbrian return (1); 3286735Samurai } 3296059Samurai ep = sp + needed; 3306059Samurai 33136285Sbrian prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 33236285Sbrian "Destination", "Gateway"); 3336059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 33428679Sbrian rtm = (struct rt_msghdr *) cp; 33531176Sbrian wp = (char *)(rtm+1); 33631176Sbrian 33731176Sbrian if (rtm->rtm_addrs & RTA_DST) { 33831176Sbrian sa_dst = (struct sockaddr *)wp; 33931176Sbrian wp += sa_dst->sa_len; 34031176Sbrian } else 34131176Sbrian sa_dst = NULL; 34231176Sbrian 34331176Sbrian if (rtm->rtm_addrs & RTA_GATEWAY) { 34431176Sbrian sa_gw = (struct sockaddr *)wp; 34531176Sbrian wp += sa_gw->sa_len; 34631176Sbrian } else 34731176Sbrian sa_gw = NULL; 34831176Sbrian 34931176Sbrian if (rtm->rtm_addrs & RTA_NETMASK) { 35031176Sbrian sa_mask = (struct sockaddr *)wp; 35131176Sbrian wp += sa_mask->sa_len; 35231176Sbrian } else 35331176Sbrian sa_mask = NULL; 35431176Sbrian 35536285Sbrian p_sockaddr(arg->prompt, sa_dst, sa_mask, 20); 35636285Sbrian p_sockaddr(arg->prompt, sa_gw, NULL, 20); 35731176Sbrian 35836285Sbrian p_flags(arg->prompt, rtm->rtm_flags, 6); 35936285Sbrian prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3606059Samurai } 36118885Sjkh free(sp); 36226516Sbrian return 0; 3636059Samurai} 3646059Samurai 3656059Samurai/* 3666059Samurai * Delete routes associated with our interface 3676059Samurai */ 3686059Samuraivoid 36936285Sbrianroute_IfDelete(struct bundle *bundle, int all) 3706059Samurai{ 3716059Samurai struct rt_msghdr *rtm; 3726059Samurai struct sockaddr *sa; 37331598Sbrian struct in_addr sa_dst, sa_none; 37432021Sbrian int pass; 37532021Sbrian size_t needed; 3766059Samurai char *sp, *cp, *ep; 3776735Samurai int mib[6]; 3786059Samurai 37940561Sbrian log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 38031598Sbrian sa_none.s_addr = INADDR_ANY; 38126516Sbrian 3826059Samurai mib[0] = CTL_NET; 3836059Samurai mib[1] = PF_ROUTE; 3846735Samurai mib[2] = 0; 3856735Samurai mib[3] = 0; 3866059Samurai mib[4] = NET_RT_DUMP; 3876735Samurai mib[5] = 0; 3886735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 38936285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 39028974Sbrian strerror(errno)); 3916735Samurai return; 3926735Samurai } 3936059Samurai 3946059Samurai sp = malloc(needed); 3956059Samurai if (sp == NULL) 3966059Samurai return; 3976059Samurai 3986735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 39936285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 40028974Sbrian strerror(errno)); 4016059Samurai free(sp); 4026059Samurai return; 4036059Samurai } 4046059Samurai ep = sp + needed; 4056059Samurai 40631739Sbrian for (pass = 0; pass < 2; pass++) { 40731739Sbrian /* 40831739Sbrian * We do 2 passes. The first deletes all cloned routes. The second 40931739Sbrian * deletes all non-cloned routes. This is necessary to avoid 41031739Sbrian * potential errors from trying to delete route X after route Y where 41136285Sbrian * route X was cloned from route Y (and is no longer there 'cos it 41236285Sbrian * may have gone with route Y). 41331739Sbrian */ 41431739Sbrian if (RTF_WASCLONED == 0 && pass == 0) 41531739Sbrian /* So we can't tell ! */ 41631739Sbrian continue; 41731739Sbrian for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 41831739Sbrian rtm = (struct rt_msghdr *) cp; 41931739Sbrian sa = (struct sockaddr *) (rtm + 1); 42036285Sbrian log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 42131739Sbrian " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 42231739Sbrian Index2Nam(rtm->rtm_index), rtm->rtm_flags, 42331739Sbrian inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 42431739Sbrian if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 42540561Sbrian rtm->rtm_index == bundle->iface->index && 42631739Sbrian (all || (rtm->rtm_flags & RTF_GATEWAY))) { 42731739Sbrian sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 42831739Sbrian sa = (struct sockaddr *)((char *)sa + sa->sa_len); 42931739Sbrian if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { 43031739Sbrian if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 43131739Sbrian (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 43236285Sbrian log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass); 43337927Sbrian bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0, 0); 43431739Sbrian } else 43536285Sbrian log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 43631739Sbrian } else 43736285Sbrian log_Printf(LogDEBUG, 43836285Sbrian "route_IfDelete: Can't remove routes of %d family !\n", 43931739Sbrian sa->sa_family); 44031739Sbrian } 4416059Samurai } 4426059Samurai } 4436059Samurai free(sp); 4446059Samurai} 4456059Samurai 4466059Samuraiint 44728679SbrianGetIfIndex(char *name) 4486059Samurai{ 44931176Sbrian int idx; 45031343Sbrian const char *got; 45128679Sbrian 45231354Sbrian idx = 1; 45331176Sbrian while (strcmp(got = Index2Nam(idx), "???")) 45431176Sbrian if (!strcmp(got, name)) 45536285Sbrian return idx; 45631176Sbrian else 45731176Sbrian idx++; 45831176Sbrian return -1; 4596059Samurai} 46031690Sbrian 46136285Sbrianvoid 46236285Sbrianroute_Change(struct bundle *bundle, struct sticky_route *r, 46336285Sbrian struct in_addr me, struct in_addr peer) 46431690Sbrian{ 46536285Sbrian struct in_addr none, del; 46631690Sbrian 46736285Sbrian none.s_addr = INADDR_ANY; 46836285Sbrian for (; r; r = r->next) { 46936285Sbrian if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 47036285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 47137927Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 47236285Sbrian r->dst = me; 47336285Sbrian if (r->type & ROUTE_GWHISADDR) 47436285Sbrian r->gw = peer; 47536285Sbrian } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 47636285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 47737927Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 47836285Sbrian r->dst = peer; 47936285Sbrian if (r->type & ROUTE_GWHISADDR) 48036285Sbrian r->gw = peer; 48136285Sbrian } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 48236285Sbrian r->gw = peer; 48337927Sbrian bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 48436285Sbrian } 48536285Sbrian} 48636285Sbrian 48736285Sbrianvoid 48836285Sbrianroute_Clean(struct bundle *bundle, struct sticky_route *r) 48936285Sbrian{ 49036285Sbrian struct in_addr none, del; 49136285Sbrian 49236285Sbrian none.s_addr = INADDR_ANY; 49336285Sbrian for (; r; r = r->next) { 49436285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 49537927Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 49636285Sbrian } 49736285Sbrian} 49836285Sbrian 49936285Sbrianvoid 50036285Sbrianroute_Add(struct sticky_route **rp, int type, struct in_addr dst, 50136285Sbrian struct in_addr mask, struct in_addr gw) 50236285Sbrian{ 50343313Sbrian struct sticky_route *r; 50443313Sbrian int dsttype = type & ROUTE_DSTANY; 50536285Sbrian 50643313Sbrian r = NULL; 50743313Sbrian while (*rp) { 50843313Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 50943313Sbrian (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 51043313Sbrian /* Oops, we already have this route - unlink it */ 51143313Sbrian free(r); /* impossible really */ 51243313Sbrian r = *rp; 51343313Sbrian *rp = r->next; 51443313Sbrian } else 51543313Sbrian rp = &(*rp)->next; 51643313Sbrian } 51736285Sbrian 51843313Sbrian if (!r) 51943313Sbrian r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 52043313Sbrian r->type = type; 52143313Sbrian r->next = NULL; 52243313Sbrian r->dst = dst; 52343313Sbrian r->mask = mask; 52443313Sbrian r->gw = gw; 52543313Sbrian *rp = r; 52636285Sbrian} 52736285Sbrian 52836285Sbrianvoid 52936285Sbrianroute_Delete(struct sticky_route **rp, int type, struct in_addr dst) 53036285Sbrian{ 53136285Sbrian struct sticky_route *r; 53236285Sbrian int dsttype = type & ROUTE_DSTANY; 53336285Sbrian 53436285Sbrian for (; *rp; rp = &(*rp)->next) { 53536285Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 53636285Sbrian (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 53736285Sbrian r = *rp; 53836285Sbrian *rp = r->next; 53936285Sbrian free(r); 54031690Sbrian break; 54131690Sbrian } 54231690Sbrian } 54336285Sbrian} 54431690Sbrian 54536285Sbrianvoid 54636285Sbrianroute_DeleteAll(struct sticky_route **rp) 54736285Sbrian{ 54836285Sbrian struct sticky_route *r, *rn; 54936285Sbrian 55036285Sbrian for (r = *rp; r; r = rn) { 55136285Sbrian rn = r->next; 55236285Sbrian free(r); 55331690Sbrian } 55436285Sbrian *rp = NULL; 55536285Sbrian} 55631690Sbrian 55736285Sbrianvoid 55843313Sbrianroute_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 55943313Sbrian int indent) 56036285Sbrian{ 56136285Sbrian int def; 56243313Sbrian int tlen = strlen(tag); 56336285Sbrian 56443313Sbrian if (tlen + 2 > indent) 56543313Sbrian prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 56643313Sbrian else 56743313Sbrian prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 56843313Sbrian 56936285Sbrian for (; r; r = r->next) { 57036285Sbrian def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 57136285Sbrian 57243313Sbrian prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 57343313Sbrian tlen = 0; 57436285Sbrian if (r->type & ROUTE_DSTMYADDR) 57536285Sbrian prompt_Printf(p, "MYADDR"); 57636285Sbrian else if (r->type & ROUTE_DSTHISADDR) 57736285Sbrian prompt_Printf(p, "HISADDR"); 57836285Sbrian else if (!def) 57936285Sbrian prompt_Printf(p, "%s", inet_ntoa(r->dst)); 58036285Sbrian 58136285Sbrian if (def) 58236285Sbrian prompt_Printf(p, "default "); 58336285Sbrian else 58436285Sbrian prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 58536285Sbrian 58636285Sbrian if (r->type & ROUTE_GWHISADDR) 58736285Sbrian prompt_Printf(p, "HISADDR\n"); 58836285Sbrian else 58936285Sbrian prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 59036285Sbrian } 59131690Sbrian} 592