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