route.c revision 36285
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 * 2036285Sbrian * $Id: route.c,v 1.42.2.25 1998/05/16 21:19:00 brian Exp $ 218857Srgrimes * 226059Samurai */ 2330715Sbrian 2436285Sbrian#include <sys/types.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 4331343Sbrian#include "command.h" 4430715Sbrian#include "mbuf.h" 459439Samurai#include "log.h" 4631070Sbrian#include "defs.h" 4736285Sbrian#include "iplist.h" 4836285Sbrian#include "timer.h" 4936285Sbrian#include "throughput.h" 5036285Sbrian#include "lqr.h" 5136285Sbrian#include "hdlc.h" 5236285Sbrian#include "fsm.h" 5336285Sbrian#include "lcp.h" 5436285Sbrian#include "ccp.h" 5536285Sbrian#include "link.h" 5636285Sbrian#include "slcompress.h" 5731690Sbrian#include "ipcp.h" 5836285Sbrian#include "filter.h" 5936285Sbrian#include "descriptor.h" 6036285Sbrian#include "mp.h" 6136285Sbrian#include "bundle.h" 6230715Sbrian#include "route.h" 6336285Sbrian#include "prompt.h" 646059Samurai 656059Samuraistatic void 6636285Sbrianp_sockaddr(struct prompt *prompt, struct sockaddr *phost, 6736285Sbrian struct sockaddr *pmask, int width) 686059Samurai{ 6931343Sbrian char buf[29]; 7031176Sbrian struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 7131176Sbrian struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 7231176Sbrian struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 736059Samurai 7431176Sbrian switch (phost->sa_family) { 7531176Sbrian case AF_INET: 7631176Sbrian if (!phost) 7731541Sbrian buf[0] = '\0'; 7831176Sbrian else if (ihost->sin_addr.s_addr == INADDR_ANY) 7931541Sbrian strcpy(buf, "default"); 8031176Sbrian else if (!mask) 8131541Sbrian strcpy(buf, inet_ntoa(ihost->sin_addr)); 8231176Sbrian else { 8331176Sbrian u_int msk = ntohl(mask->sin_addr.s_addr); 8431176Sbrian u_int tst; 8531176Sbrian int bits; 8631176Sbrian int len; 8731176Sbrian struct sockaddr_in net; 8831176Sbrian 8931176Sbrian for (tst = 1, bits=32; tst; tst <<= 1, bits--) 9031176Sbrian if (msk & tst) 9131176Sbrian break; 9231176Sbrian 9331176Sbrian for (tst <<=1; tst; tst <<= 1) 9431176Sbrian if (!(msk & tst)) 9531176Sbrian break; 9631176Sbrian 9731176Sbrian net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 9831791Sbrian strcpy(buf, inet_ntoa(net.sin_addr)); 9931176Sbrian for (len = strlen(buf); len > 3; buf[len-=2] = '\0') 10031176Sbrian if (strcmp(buf+len-2, ".0")) 10131176Sbrian break; 10231176Sbrian 10331176Sbrian if (tst) /* non-contiguous :-( */ 10431176Sbrian sprintf(buf+strlen(buf),"&0x%08x", msk); 10531176Sbrian else 10631176Sbrian sprintf(buf+strlen(buf), "/%d", bits); 10731176Sbrian } 10831176Sbrian break; 10931176Sbrian 11031176Sbrian case AF_LINK: 11131541Sbrian if (dl->sdl_nlen) 11231541Sbrian snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 11334536Sbrian else if (dl->sdl_alen) { 11434536Sbrian if (dl->sdl_type == IFT_ETHER) { 11531962Sbrian if (dl->sdl_alen < sizeof buf / 3) { 11631541Sbrian int f; 11731541Sbrian u_char *MAC; 11831541Sbrian 11931541Sbrian MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 12031541Sbrian for (f = 0; f < dl->sdl_alen; f++) 12131541Sbrian sprintf(buf+f*3, "%02x:", MAC[f]); 12231541Sbrian buf[f*3-1] = '\0'; 12331541Sbrian } else 12431791Sbrian strcpy(buf, "??:??:??:??:??:??"); 12534536Sbrian } else 12631541Sbrian sprintf(buf, "<IFT type %d>", dl->sdl_type); 12736285Sbrian } else if (dl->sdl_slen) 12831541Sbrian sprintf(buf, "<slen %d?>", dl->sdl_slen); 12931541Sbrian else 13031176Sbrian sprintf(buf, "link#%d", dl->sdl_index); 13131176Sbrian break; 13231176Sbrian 13331176Sbrian default: 13431541Sbrian sprintf(buf, "<AF type %d>", phost->sa_family); 13531176Sbrian break; 13626516Sbrian } 13731176Sbrian 13836285Sbrian prompt_Printf(prompt, "%-*s ", width-1, buf); 1396059Samurai} 1406059Samurai 14132663Sbrianstatic struct bits { 14231176Sbrian u_long b_mask; 14328679Sbrian char b_val; 14431176Sbrian} bits[] = { 14531176Sbrian { RTF_UP, 'U' }, 14631176Sbrian { RTF_GATEWAY, 'G' }, 14731176Sbrian { RTF_HOST, 'H' }, 14831176Sbrian { RTF_REJECT, 'R' }, 14931176Sbrian { RTF_DYNAMIC, 'D' }, 15031176Sbrian { RTF_MODIFIED, 'M' }, 15131176Sbrian { RTF_DONE, 'd' }, 15231176Sbrian { RTF_CLONING, 'C' }, 15331176Sbrian { RTF_XRESOLVE, 'X' }, 15431176Sbrian { RTF_LLINFO, 'L' }, 15531176Sbrian { RTF_STATIC, 'S' }, 15631176Sbrian { RTF_PROTO1, '1' }, 15731176Sbrian { RTF_PROTO2, '2' }, 15831176Sbrian { RTF_BLACKHOLE, 'B' }, 15931739Sbrian#ifdef RTF_WASCLONED 16031176Sbrian { RTF_WASCLONED, 'W' }, 16131739Sbrian#endif 16231739Sbrian#ifdef RTF_PRCLONING 16331176Sbrian { RTF_PRCLONING, 'c' }, 16431739Sbrian#endif 16531739Sbrian#ifdef RTF_PROTO3 16631176Sbrian { RTF_PROTO3, '3' }, 16731739Sbrian#endif 16831739Sbrian#ifdef RTF_BROADCAST 16931176Sbrian { RTF_BROADCAST, 'b' }, 17031176Sbrian#endif 17131176Sbrian { 0, '\0' } 1726059Samurai}; 1736059Samurai 17431739Sbrian#ifndef RTF_WASCLONED 17531739Sbrian#define RTF_WASCLONED (0) 17631739Sbrian#endif 17731739Sbrian 1786059Samuraistatic void 17936285Sbrianp_flags(struct prompt *prompt, u_long f, int max) 1806059Samurai{ 18136285Sbrian char name[33], *flags; 18236285Sbrian register struct bits *p = bits; 1836059Samurai 18436285Sbrian if (max > sizeof name - 1) 18536285Sbrian max = sizeof name - 1; 18631827Sbrian 18736285Sbrian for (flags = name; p->b_mask && flags - name < max; p++) 18836285Sbrian if (p->b_mask & f) 18936285Sbrian *flags++ = p->b_val; 19036285Sbrian *flags = '\0'; 19136285Sbrian prompt_Printf(prompt, "%-*.*s", max, max, name); 1926059Samurai} 1936059Samurai 19432616Sbrianconst char * 19531176SbrianIndex2Nam(int idx) 19631176Sbrian{ 19732425Sbrian static char **ifs; 19831354Sbrian static int nifs, debug_done; 19931176Sbrian 20031176Sbrian if (!nifs) { 20132425Sbrian int mib[6], have, had; 20232021Sbrian size_t needed; 20331176Sbrian char *buf, *ptr, *end; 20431176Sbrian struct sockaddr_dl *dl; 20531176Sbrian struct if_msghdr *ifm; 20631176Sbrian 20731176Sbrian mib[0] = CTL_NET; 20831176Sbrian mib[1] = PF_ROUTE; 20931176Sbrian mib[2] = 0; 21031176Sbrian mib[3] = 0; 21131176Sbrian mib[4] = NET_RT_IFLIST; 21231176Sbrian mib[5] = 0; 21331176Sbrian 21431176Sbrian if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 21536285Sbrian log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); 21631176Sbrian return "???"; 21731176Sbrian } 21831176Sbrian if ((buf = malloc(needed)) == NULL) 21931176Sbrian return "???"; 22031176Sbrian if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 22131176Sbrian free(buf); 22231176Sbrian return "???"; 22331176Sbrian } 22431176Sbrian end = buf + needed; 22531176Sbrian 22632425Sbrian have = 0; 22731354Sbrian for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 22831176Sbrian ifm = (struct if_msghdr *)ptr; 22931176Sbrian dl = (struct sockaddr_dl *)(ifm + 1); 23032425Sbrian if (ifm->ifm_index > 0) { 23132425Sbrian if (ifm->ifm_index > have) { 23232425Sbrian had = have; 23332425Sbrian have = ifm->ifm_index + 5; 23432425Sbrian if (had) 23532425Sbrian ifs = (char **)realloc(ifs, sizeof(char *) * have); 23632425Sbrian else 23732425Sbrian ifs = (char **)malloc(sizeof(char *) * have); 23832425Sbrian if (!ifs) { 23936285Sbrian log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 24032425Sbrian nifs = 0; 24132425Sbrian return "???"; 24232425Sbrian } 24332425Sbrian memset(ifs + had, '\0', sizeof(char *) * (have - had)); 24432425Sbrian } 24532425Sbrian if (ifs[ifm->ifm_index-1] == NULL) { 24632425Sbrian ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 24732425Sbrian memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 24832425Sbrian ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 24932425Sbrian if (nifs < ifm->ifm_index) 25032425Sbrian nifs = ifm->ifm_index; 25132425Sbrian } 25236285Sbrian } else if (log_IsKept(LogDEBUG)) 25336285Sbrian log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 25431354Sbrian ifm->ifm_index); 25531176Sbrian } 25631176Sbrian free(buf); 25731176Sbrian } 25831176Sbrian 25936285Sbrian if (log_IsKept(LogDEBUG) && !debug_done) { 26031354Sbrian int f; 26131354Sbrian 26236285Sbrian log_Printf(LogDEBUG, "Found the following interfaces:\n"); 26331354Sbrian for (f = 0; f < nifs; f++) 26432425Sbrian if (ifs[f] != NULL) 26536285Sbrian log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 26631354Sbrian debug_done = 1; 26731354Sbrian } 26831354Sbrian 26932425Sbrian if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 27031176Sbrian return "???"; 27131354Sbrian 27231354Sbrian return ifs[idx-1]; 27331176Sbrian} 27431176Sbrian 2756059Samuraiint 27636285Sbrianroute_Show(struct cmdargs const *arg) 2776059Samurai{ 2786059Samurai struct rt_msghdr *rtm; 27931176Sbrian struct sockaddr *sa_dst, *sa_gw, *sa_mask; 28031176Sbrian char *sp, *ep, *cp, *wp; 28132021Sbrian size_t needed; 2826735Samurai int mib[6]; 2836059Samurai 2846059Samurai mib[0] = CTL_NET; 2856059Samurai mib[1] = PF_ROUTE; 2866735Samurai mib[2] = 0; 2876735Samurai mib[3] = 0; 2886059Samurai mib[4] = NET_RT_DUMP; 2896735Samurai mib[5] = 0; 2906735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 29136285Sbrian log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 29228679Sbrian return (1); 2936735Samurai } 2946059Samurai if (needed < 0) 29528679Sbrian return (1); 2966059Samurai sp = malloc(needed); 2976059Samurai if (sp == NULL) 29828679Sbrian return (1); 2996735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 30036285Sbrian log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 30118885Sjkh free(sp); 30228679Sbrian return (1); 3036735Samurai } 3046059Samurai ep = sp + needed; 3056059Samurai 30636285Sbrian prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 30736285Sbrian "Destination", "Gateway"); 3086059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 30928679Sbrian rtm = (struct rt_msghdr *) cp; 31031176Sbrian wp = (char *)(rtm+1); 31131176Sbrian 31231176Sbrian if (rtm->rtm_addrs & RTA_DST) { 31331176Sbrian sa_dst = (struct sockaddr *)wp; 31431176Sbrian wp += sa_dst->sa_len; 31531176Sbrian } else 31631176Sbrian sa_dst = NULL; 31731176Sbrian 31831176Sbrian if (rtm->rtm_addrs & RTA_GATEWAY) { 31931176Sbrian sa_gw = (struct sockaddr *)wp; 32031176Sbrian wp += sa_gw->sa_len; 32131176Sbrian } else 32231176Sbrian sa_gw = NULL; 32331176Sbrian 32431176Sbrian if (rtm->rtm_addrs & RTA_NETMASK) { 32531176Sbrian sa_mask = (struct sockaddr *)wp; 32631176Sbrian wp += sa_mask->sa_len; 32731176Sbrian } else 32831176Sbrian sa_mask = NULL; 32931176Sbrian 33036285Sbrian p_sockaddr(arg->prompt, sa_dst, sa_mask, 20); 33136285Sbrian p_sockaddr(arg->prompt, sa_gw, NULL, 20); 33231176Sbrian 33336285Sbrian p_flags(arg->prompt, rtm->rtm_flags, 6); 33436285Sbrian prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3356059Samurai } 33618885Sjkh free(sp); 33726516Sbrian return 0; 3386059Samurai} 3396059Samurai 3406059Samurai/* 3416059Samurai * Delete routes associated with our interface 3426059Samurai */ 3436059Samuraivoid 34436285Sbrianroute_IfDelete(struct bundle *bundle, int all) 3456059Samurai{ 3466059Samurai struct rt_msghdr *rtm; 3476059Samurai struct sockaddr *sa; 34831598Sbrian struct in_addr sa_dst, sa_none; 34932021Sbrian int pass; 35032021Sbrian size_t needed; 3516059Samurai char *sp, *cp, *ep; 3526735Samurai int mib[6]; 3536059Samurai 35436285Sbrian log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->ifp.Index); 35531598Sbrian sa_none.s_addr = INADDR_ANY; 35626516Sbrian 3576059Samurai mib[0] = CTL_NET; 3586059Samurai mib[1] = PF_ROUTE; 3596735Samurai mib[2] = 0; 3606735Samurai mib[3] = 0; 3616059Samurai mib[4] = NET_RT_DUMP; 3626735Samurai mib[5] = 0; 3636735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 36436285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 36528974Sbrian strerror(errno)); 3666735Samurai return; 3676735Samurai } 3686059Samurai if (needed < 0) 3696059Samurai return; 3706059Samurai 3716059Samurai sp = malloc(needed); 3726059Samurai if (sp == NULL) 3736059Samurai return; 3746059Samurai 3756735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 37636285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 37728974Sbrian strerror(errno)); 3786059Samurai free(sp); 3796059Samurai return; 3806059Samurai } 3816059Samurai ep = sp + needed; 3826059Samurai 38331739Sbrian for (pass = 0; pass < 2; pass++) { 38431739Sbrian /* 38531739Sbrian * We do 2 passes. The first deletes all cloned routes. The second 38631739Sbrian * deletes all non-cloned routes. This is necessary to avoid 38731739Sbrian * potential errors from trying to delete route X after route Y where 38836285Sbrian * route X was cloned from route Y (and is no longer there 'cos it 38936285Sbrian * may have gone with route Y). 39031739Sbrian */ 39131739Sbrian if (RTF_WASCLONED == 0 && pass == 0) 39231739Sbrian /* So we can't tell ! */ 39331739Sbrian continue; 39431739Sbrian for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 39531739Sbrian rtm = (struct rt_msghdr *) cp; 39631739Sbrian sa = (struct sockaddr *) (rtm + 1); 39736285Sbrian log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 39831739Sbrian " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 39931739Sbrian Index2Nam(rtm->rtm_index), rtm->rtm_flags, 40031739Sbrian inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 40131739Sbrian if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 40236285Sbrian rtm->rtm_index == bundle->ifp.Index && 40331739Sbrian (all || (rtm->rtm_flags & RTF_GATEWAY))) { 40431739Sbrian sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 40531739Sbrian sa = (struct sockaddr *)((char *)sa + sa->sa_len); 40631739Sbrian if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { 40731739Sbrian if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 40831739Sbrian (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 40936285Sbrian log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass); 41036285Sbrian bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0); 41131739Sbrian } else 41236285Sbrian log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 41331739Sbrian } else 41436285Sbrian log_Printf(LogDEBUG, 41536285Sbrian "route_IfDelete: Can't remove routes of %d family !\n", 41631739Sbrian sa->sa_family); 41731739Sbrian } 4186059Samurai } 4196059Samurai } 4206059Samurai free(sp); 4216059Samurai} 4226059Samurai 4236059Samuraiint 42428679SbrianGetIfIndex(char *name) 4256059Samurai{ 42631176Sbrian int idx; 42731343Sbrian const char *got; 42828679Sbrian 42931354Sbrian idx = 1; 43031176Sbrian while (strcmp(got = Index2Nam(idx), "???")) 43131176Sbrian if (!strcmp(got, name)) 43236285Sbrian return idx; 43331176Sbrian else 43431176Sbrian idx++; 43531176Sbrian return -1; 4366059Samurai} 43731690Sbrian 43836285Sbrianvoid 43936285Sbrianroute_Change(struct bundle *bundle, struct sticky_route *r, 44036285Sbrian struct in_addr me, struct in_addr peer) 44131690Sbrian{ 44236285Sbrian struct in_addr none, del; 44331690Sbrian 44436285Sbrian none.s_addr = INADDR_ANY; 44536285Sbrian for (; r; r = r->next) { 44636285Sbrian if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 44736285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 44836285Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1); 44936285Sbrian r->dst = me; 45036285Sbrian if (r->type & ROUTE_GWHISADDR) 45136285Sbrian r->gw = peer; 45236285Sbrian } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 45336285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 45436285Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1); 45536285Sbrian r->dst = peer; 45636285Sbrian if (r->type & ROUTE_GWHISADDR) 45736285Sbrian r->gw = peer; 45836285Sbrian } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 45936285Sbrian r->gw = peer; 46036285Sbrian bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1); 46136285Sbrian } 46236285Sbrian} 46336285Sbrian 46436285Sbrianvoid 46536285Sbrianroute_Clean(struct bundle *bundle, struct sticky_route *r) 46636285Sbrian{ 46736285Sbrian struct in_addr none, del; 46836285Sbrian 46936285Sbrian none.s_addr = INADDR_ANY; 47036285Sbrian for (; r; r = r->next) { 47136285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 47236285Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1); 47336285Sbrian } 47436285Sbrian} 47536285Sbrian 47636285Sbrianvoid 47736285Sbrianroute_Add(struct sticky_route **rp, int type, struct in_addr dst, 47836285Sbrian struct in_addr mask, struct in_addr gw) 47936285Sbrian{ 48036285Sbrian if (type != ROUTE_STATIC) { 48136285Sbrian struct sticky_route *r; 48236285Sbrian int dsttype = type & ROUTE_DSTANY; 48336285Sbrian 48436285Sbrian r = NULL; 48536285Sbrian while (*rp) { 48636285Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 48736285Sbrian (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 48836285Sbrian r = *rp; 48936285Sbrian *rp = r->next; 49036285Sbrian } else 49136285Sbrian rp = &(*rp)->next; 49236285Sbrian } 49336285Sbrian 49436285Sbrian if (!r) 49536285Sbrian r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 49636285Sbrian r->type = type; 49736285Sbrian r->next = NULL; 49836285Sbrian r->dst = dst; 49936285Sbrian r->mask = mask; 50036285Sbrian r->gw = gw; 50136285Sbrian *rp = r; 50236285Sbrian } 50336285Sbrian} 50436285Sbrian 50536285Sbrianvoid 50636285Sbrianroute_Delete(struct sticky_route **rp, int type, struct in_addr dst) 50736285Sbrian{ 50836285Sbrian struct sticky_route *r; 50936285Sbrian int dsttype = type & ROUTE_DSTANY; 51036285Sbrian 51136285Sbrian for (; *rp; rp = &(*rp)->next) { 51236285Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 51336285Sbrian (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 51436285Sbrian r = *rp; 51536285Sbrian *rp = r->next; 51636285Sbrian free(r); 51731690Sbrian break; 51831690Sbrian } 51931690Sbrian } 52036285Sbrian} 52131690Sbrian 52236285Sbrianvoid 52336285Sbrianroute_DeleteAll(struct sticky_route **rp) 52436285Sbrian{ 52536285Sbrian struct sticky_route *r, *rn; 52636285Sbrian 52736285Sbrian for (r = *rp; r; r = rn) { 52836285Sbrian rn = r->next; 52936285Sbrian free(r); 53031690Sbrian } 53136285Sbrian *rp = NULL; 53236285Sbrian} 53331690Sbrian 53436285Sbrianvoid 53536285Sbrianroute_ShowSticky(struct prompt *p, struct sticky_route *r) 53636285Sbrian{ 53736285Sbrian int def; 53836285Sbrian 53936285Sbrian prompt_Printf(p, "Sticky routes:\n"); 54036285Sbrian for (; r; r = r->next) { 54136285Sbrian def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 54236285Sbrian 54336285Sbrian prompt_Printf(p, " add "); 54436285Sbrian if (r->type & ROUTE_DSTMYADDR) 54536285Sbrian prompt_Printf(p, "MYADDR"); 54636285Sbrian else if (r->type & ROUTE_DSTHISADDR) 54736285Sbrian prompt_Printf(p, "HISADDR"); 54836285Sbrian else if (!def) 54936285Sbrian prompt_Printf(p, "%s", inet_ntoa(r->dst)); 55036285Sbrian 55136285Sbrian if (def) 55236285Sbrian prompt_Printf(p, "default "); 55336285Sbrian else 55436285Sbrian prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 55536285Sbrian 55636285Sbrian if (r->type & ROUTE_GWHISADDR) 55736285Sbrian prompt_Printf(p, "HISADDR\n"); 55836285Sbrian else 55936285Sbrian prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 56036285Sbrian } 56131690Sbrian} 562