route.c revision 58044
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 58044 2000-03-14 01:47:27Z brian $
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>
3558031Sbrian#include <netdb.h>
3620287Swollman
3720287Swollman#include <errno.h>
3830715Sbrian#include <stdio.h>
396059Samurai#include <stdlib.h>
406059Samurai#include <string.h>
4130715Sbrian#include <sys/sysctl.h>
4236285Sbrian#include <termios.h>
4320287Swollman
4446686Sbrian#include "layer.h"
4537009Sbrian#include "defs.h"
4631343Sbrian#include "command.h"
4730715Sbrian#include "mbuf.h"
489439Samurai#include "log.h"
4936285Sbrian#include "iplist.h"
5036285Sbrian#include "timer.h"
5136285Sbrian#include "throughput.h"
5236285Sbrian#include "lqr.h"
5336285Sbrian#include "hdlc.h"
5436285Sbrian#include "fsm.h"
5536285Sbrian#include "lcp.h"
5636285Sbrian#include "ccp.h"
5736285Sbrian#include "link.h"
5836285Sbrian#include "slcompress.h"
5931690Sbrian#include "ipcp.h"
6036285Sbrian#include "filter.h"
6136285Sbrian#include "descriptor.h"
6236285Sbrian#include "mp.h"
6343313Sbrian#ifndef NORADIUS
6443313Sbrian#include "radius.h"
6543313Sbrian#endif
6636285Sbrian#include "bundle.h"
6730715Sbrian#include "route.h"
6836285Sbrian#include "prompt.h"
6940561Sbrian#include "iface.h"
706059Samurai
7158032Sbrian
726059Samuraistatic void
7336285Sbrianp_sockaddr(struct prompt *prompt, struct sockaddr *phost,
7436285Sbrian           struct sockaddr *pmask, int width)
756059Samurai{
7631343Sbrian  char buf[29];
7758031Sbrian  struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost;
7858031Sbrian  struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask;
7931176Sbrian  struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
806059Samurai
8158031Sbrian  if (log_IsKept(LogDEBUG)) {
8258031Sbrian    char tmp[50];
8358031Sbrian
8458031Sbrian    log_Printf(LogDEBUG, "Found the following sockaddr:\n");
8558031Sbrian    log_Printf(LogDEBUG, "  Family %d, len %d\n",
8658031Sbrian               (int)phost->sa_family, (int)phost->sa_len);
8758032Sbrian    inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp);
8858031Sbrian    log_Printf(LogDEBUG, "  Addr %s\n", tmp);
8958031Sbrian    if (pmask) {
9058032Sbrian      inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp);
9158031Sbrian      log_Printf(LogDEBUG, "  Mask %s\n", tmp);
9258031Sbrian    }
9358031Sbrian  }
9458031Sbrian
9531176Sbrian  switch (phost->sa_family) {
9631176Sbrian  case AF_INET:
9731176Sbrian    if (!phost)
9831541Sbrian      buf[0] = '\0';
9958031Sbrian    else if (ihost4->sin_addr.s_addr == INADDR_ANY)
10031541Sbrian      strcpy(buf, "default");
10158031Sbrian    else if (!pmask)
10258031Sbrian      strcpy(buf, inet_ntoa(ihost4->sin_addr));
10331176Sbrian    else {
10458031Sbrian      u_int32_t msk = ntohl(mask4->sin_addr.s_addr);
10537210Sbrian      u_int32_t tst;
10631176Sbrian      int bits;
10731176Sbrian      int len;
10831176Sbrian      struct sockaddr_in net;
10931176Sbrian
11058031Sbrian      for (tst = 1, bits = 32; tst; tst <<= 1, bits--)
11131176Sbrian        if (msk & tst)
11231176Sbrian          break;
11331176Sbrian
11437210Sbrian      for (tst <<= 1; tst; tst <<= 1)
11531176Sbrian        if (!(msk & tst))
11631176Sbrian          break;
11731176Sbrian
11858031Sbrian      net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr;
11931791Sbrian      strcpy(buf, inet_ntoa(net.sin_addr));
12037210Sbrian      for (len = strlen(buf); len > 3; buf[len -= 2] = '\0')
12137210Sbrian        if (strcmp(buf + len - 2, ".0"))
12231176Sbrian          break;
12331176Sbrian
12431176Sbrian      if (tst)    /* non-contiguous :-( */
12537210Sbrian        sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk);
12631176Sbrian      else
12737210Sbrian        sprintf(buf + strlen(buf), "/%d", bits);
12831176Sbrian    }
12931176Sbrian    break;
13031176Sbrian
13131176Sbrian  case AF_LINK:
13231541Sbrian    if (dl->sdl_nlen)
13331541Sbrian      snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
13434536Sbrian    else if (dl->sdl_alen) {
13534536Sbrian      if (dl->sdl_type == IFT_ETHER) {
13631962Sbrian        if (dl->sdl_alen < sizeof buf / 3) {
13731541Sbrian          int f;
13831541Sbrian          u_char *MAC;
13931541Sbrian
14031541Sbrian          MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
14131541Sbrian          for (f = 0; f < dl->sdl_alen; f++)
14231541Sbrian            sprintf(buf+f*3, "%02x:", MAC[f]);
14331541Sbrian          buf[f*3-1] = '\0';
14431541Sbrian        } else
14531791Sbrian	  strcpy(buf, "??:??:??:??:??:??");
14634536Sbrian      } else
14731541Sbrian        sprintf(buf, "<IFT type %d>", dl->sdl_type);
14836285Sbrian    }  else if (dl->sdl_slen)
14931541Sbrian      sprintf(buf, "<slen %d?>", dl->sdl_slen);
15031541Sbrian    else
15131176Sbrian      sprintf(buf, "link#%d", dl->sdl_index);
15231176Sbrian    break;
15331176Sbrian
15458031Sbrian#ifndef NOINET6
15558031Sbrian  case AF_INET6:
15658031Sbrian    if (!phost)
15758031Sbrian      buf[0] = '\0';
15858031Sbrian    else {
15958031Sbrian      const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
16058031Sbrian      struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost;
16158031Sbrian      struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask;
16258031Sbrian      int masklen, len;
16358031Sbrian      const u_char *c;
16458031Sbrian
16558031Sbrian      /* XXX: ?????!?!?!!!!!  This is horrible ! */
16658031Sbrian      if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) ||
16758031Sbrian          IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) {
16858031Sbrian        ihost6->sin6_scope_id =
16958031Sbrian          ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]);
17058031Sbrian        *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0;
17158031Sbrian      }
17258031Sbrian
17358031Sbrian      if (mask6) {
17458031Sbrian        const u_char *p, *end;
17558031Sbrian
17658031Sbrian        p = (const u_char *)&mask6->sin6_addr;
17758031Sbrian        end = p + 16;
17858031Sbrian        for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
17958031Sbrian          masklen += 8;
18058031Sbrian
18158031Sbrian        if (p < end) {
18258031Sbrian          for (c = masks; c < masks + sizeof masks; c++)
18358031Sbrian            if (*c == *p) {
18458031Sbrian              masklen += c - masks;
18558031Sbrian              break;
18658031Sbrian            }
18758031Sbrian        }
18858031Sbrian      } else
18958031Sbrian        masklen = 128;
19058031Sbrian
19158031Sbrian      if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr))
19258031Sbrian        snprintf(buf, sizeof buf, "default");
19358031Sbrian      else {
19458031Sbrian        getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf,
19558031Sbrian                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST);
19658031Sbrian        if (mask6 && (len = strlen(buf)) < sizeof buf - 1)
19758031Sbrian          snprintf(buf + len, sizeof buf - len, "/%d", masklen);
19858031Sbrian      }
19958031Sbrian    }
20058031Sbrian    break;
20158031Sbrian#endif
20258031Sbrian
20331176Sbrian  default:
20431541Sbrian    sprintf(buf, "<AF type %d>", phost->sa_family);
20531176Sbrian    break;
20626516Sbrian  }
20731176Sbrian
20836285Sbrian  prompt_Printf(prompt, "%-*s ", width-1, buf);
2096059Samurai}
2106059Samurai
21132663Sbrianstatic struct bits {
21237189Sbrian  u_int32_t b_mask;
21328679Sbrian  char b_val;
21431176Sbrian} bits[] = {
21531176Sbrian  { RTF_UP, 'U' },
21631176Sbrian  { RTF_GATEWAY, 'G' },
21731176Sbrian  { RTF_HOST, 'H' },
21831176Sbrian  { RTF_REJECT, 'R' },
21931176Sbrian  { RTF_DYNAMIC, 'D' },
22031176Sbrian  { RTF_MODIFIED, 'M' },
22131176Sbrian  { RTF_DONE, 'd' },
22231176Sbrian  { RTF_CLONING, 'C' },
22331176Sbrian  { RTF_XRESOLVE, 'X' },
22431176Sbrian  { RTF_LLINFO, 'L' },
22531176Sbrian  { RTF_STATIC, 'S' },
22631176Sbrian  { RTF_PROTO1, '1' },
22731176Sbrian  { RTF_PROTO2, '2' },
22831176Sbrian  { RTF_BLACKHOLE, 'B' },
22931739Sbrian#ifdef RTF_WASCLONED
23031176Sbrian  { RTF_WASCLONED, 'W' },
23131739Sbrian#endif
23231739Sbrian#ifdef RTF_PRCLONING
23331176Sbrian  { RTF_PRCLONING, 'c' },
23431739Sbrian#endif
23531739Sbrian#ifdef RTF_PROTO3
23631176Sbrian  { RTF_PROTO3, '3' },
23731739Sbrian#endif
23831739Sbrian#ifdef RTF_BROADCAST
23931176Sbrian  { RTF_BROADCAST, 'b' },
24031176Sbrian#endif
24131176Sbrian  { 0, '\0' }
2426059Samurai};
2436059Samurai
24431739Sbrian#ifndef RTF_WASCLONED
24531739Sbrian#define RTF_WASCLONED (0)
24631739Sbrian#endif
24731739Sbrian
2486059Samuraistatic void
24937189Sbrianp_flags(struct prompt *prompt, u_int32_t f, int max)
2506059Samurai{
25136285Sbrian  char name[33], *flags;
25236285Sbrian  register struct bits *p = bits;
2536059Samurai
25436285Sbrian  if (max > sizeof name - 1)
25536285Sbrian    max = sizeof name - 1;
25631827Sbrian
25736285Sbrian  for (flags = name; p->b_mask && flags - name < max; p++)
25836285Sbrian    if (p->b_mask & f)
25936285Sbrian      *flags++ = p->b_val;
26036285Sbrian  *flags = '\0';
26136285Sbrian  prompt_Printf(prompt, "%-*.*s", max, max, name);
2626059Samurai}
2636059Samurai
26432616Sbrianconst char *
26531176SbrianIndex2Nam(int idx)
26631176Sbrian{
26737010Sbrian  /*
26837010Sbrian   * XXX: Maybe we should select() on the routing socket so that we can
26937010Sbrian   *      notice interfaces that come & go (PCCARD support).
27037010Sbrian   *      Or we could even support a signal that resets these so that
27137010Sbrian   *      the PCCARD insert/remove events can signal ppp.
27237010Sbrian   */
27337010Sbrian  static char **ifs;		/* Figure these out once */
27437010Sbrian  static int nifs, debug_done;	/* Figure out how many once, and debug once */
27531176Sbrian
27650427Sbrian  if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) {
27732425Sbrian    int mib[6], have, had;
27832021Sbrian    size_t needed;
27931176Sbrian    char *buf, *ptr, *end;
28031176Sbrian    struct sockaddr_dl *dl;
28131176Sbrian    struct if_msghdr *ifm;
28231176Sbrian
28350427Sbrian    if (ifs) {
28450427Sbrian      free(ifs);
28550427Sbrian      ifs = NULL;
28650427Sbrian      nifs = 0;
28750427Sbrian    }
28850427Sbrian    debug_done = 0;
28950427Sbrian
29031176Sbrian    mib[0] = CTL_NET;
29131176Sbrian    mib[1] = PF_ROUTE;
29231176Sbrian    mib[2] = 0;
29331176Sbrian    mib[3] = 0;
29431176Sbrian    mib[4] = NET_RT_IFLIST;
29531176Sbrian    mib[5] = 0;
29631176Sbrian
29731176Sbrian    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
29837019Sbrian      log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n",
29937019Sbrian                 strerror(errno));
30058034Sbrian      return NumStr(idx, NULL, 0);
30131176Sbrian    }
30231176Sbrian    if ((buf = malloc(needed)) == NULL)
30358034Sbrian      return NumStr(idx, NULL, 0);
30431176Sbrian    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
30531176Sbrian      free(buf);
30658034Sbrian      return NumStr(idx, NULL, 0);
30731176Sbrian    }
30831176Sbrian    end = buf + needed;
30931176Sbrian
31032425Sbrian    have = 0;
31131354Sbrian    for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
31231176Sbrian      ifm = (struct if_msghdr *)ptr;
31358032Sbrian      if (ifm->ifm_type != RTM_IFINFO)
31458035Sbrian        continue;
31531176Sbrian      dl = (struct sockaddr_dl *)(ifm + 1);
31632425Sbrian      if (ifm->ifm_index > 0) {
31732425Sbrian        if (ifm->ifm_index > have) {
31838381Sbrian          char **newifs;
31938381Sbrian
32032425Sbrian          had = have;
32132425Sbrian          have = ifm->ifm_index + 5;
32232425Sbrian          if (had)
32338381Sbrian            newifs = (char **)realloc(ifs, sizeof(char *) * have);
32432425Sbrian          else
32538381Sbrian            newifs = (char **)malloc(sizeof(char *) * have);
32638381Sbrian          if (!newifs) {
32736285Sbrian            log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
32832425Sbrian            nifs = 0;
32950427Sbrian            if (ifs) {
33038381Sbrian              free(ifs);
33150427Sbrian              ifs = NULL;
33250427Sbrian            }
33350427Sbrian            free(buf);
33458034Sbrian            return NumStr(idx, NULL, 0);
33532425Sbrian          }
33638381Sbrian          ifs = newifs;
33732425Sbrian          memset(ifs + had, '\0', sizeof(char *) * (have - had));
33832425Sbrian        }
33932425Sbrian        if (ifs[ifm->ifm_index-1] == NULL) {
34032425Sbrian          ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
34132425Sbrian          memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
34232425Sbrian          ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
34332425Sbrian          if (nifs < ifm->ifm_index)
34432425Sbrian            nifs = ifm->ifm_index;
34532425Sbrian        }
34636285Sbrian      } else if (log_IsKept(LogDEBUG))
34736285Sbrian        log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n",
34831354Sbrian                  ifm->ifm_index);
34931176Sbrian    }
35031176Sbrian    free(buf);
35131176Sbrian  }
35231176Sbrian
35336285Sbrian  if (log_IsKept(LogDEBUG) && !debug_done) {
35431354Sbrian    int f;
35531354Sbrian
35636285Sbrian    log_Printf(LogDEBUG, "Found the following interfaces:\n");
35731354Sbrian    for (f = 0; f < nifs; f++)
35832425Sbrian      if (ifs[f] != NULL)
35936285Sbrian        log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
36031354Sbrian    debug_done = 1;
36131354Sbrian  }
36231354Sbrian
36332425Sbrian  if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
36458034Sbrian    return NumStr(idx, NULL, 0);
36531354Sbrian
36631354Sbrian  return ifs[idx-1];
36731176Sbrian}
36831176Sbrian
36958032Sbrianvoid
37058032Sbrianroute_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX])
37158032Sbrian{
37258032Sbrian  char *wp;
37358032Sbrian  int rtax;
37458032Sbrian
37558032Sbrian  wp = (char *)(rtm + 1);
37658032Sbrian
37758032Sbrian  for (rtax = 0; rtax < RTAX_MAX; rtax++)
37858032Sbrian    if (rtm->rtm_addrs & (1 << rtax)) {
37958032Sbrian      sa[rtax] = (struct sockaddr *)wp;
38058032Sbrian      wp += ROUNDUP(sa[rtax]->sa_len);
38158032Sbrian    } else
38258032Sbrian      sa[rtax] = NULL;
38358032Sbrian}
38458032Sbrian
3856059Samuraiint
38636285Sbrianroute_Show(struct cmdargs const *arg)
3876059Samurai{
3886059Samurai  struct rt_msghdr *rtm;
38958032Sbrian  struct sockaddr *sa[RTAX_MAX];
39058032Sbrian  char *sp, *ep, *cp;
39132021Sbrian  size_t needed;
3926735Samurai  int mib[6];
3936059Samurai
3946059Samurai  mib[0] = CTL_NET;
3956059Samurai  mib[1] = PF_ROUTE;
3966735Samurai  mib[2] = 0;
3976735Samurai  mib[3] = 0;
3986059Samurai  mib[4] = NET_RT_DUMP;
3996735Samurai  mib[5] = 0;
4006735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
40136285Sbrian    log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno));
40228679Sbrian    return (1);
4036735Samurai  }
4046059Samurai  sp = malloc(needed);
4056059Samurai  if (sp == NULL)
40628679Sbrian    return (1);
4076735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
40836285Sbrian    log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno));
40918885Sjkh    free(sp);
41028679Sbrian    return (1);
4116735Samurai  }
4126059Samurai  ep = sp + needed;
4136059Samurai
41436285Sbrian  prompt_Printf(arg->prompt, "%-20s%-20sFlags  Netif\n",
41536285Sbrian                "Destination", "Gateway");
4166059Samurai  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
41758032Sbrian    rtm = (struct rt_msghdr *)cp;
41831176Sbrian
41958032Sbrian    route_ParseHdr(rtm, sa);
42058031Sbrian
42158032Sbrian    if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) {
42258032Sbrian      p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20);
42358032Sbrian      p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20);
42431176Sbrian
42558031Sbrian      p_flags(arg->prompt, rtm->rtm_flags, 6);
42658031Sbrian      prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index));
42758031Sbrian    } else
42858031Sbrian      prompt_Printf(arg->prompt, "<can't parse routing entry>\n");
4296059Samurai  }
43018885Sjkh  free(sp);
43126516Sbrian  return 0;
4326059Samurai}
4336059Samurai
4346059Samurai/*
4356059Samurai *  Delete routes associated with our interface
4366059Samurai */
4376059Samuraivoid
43836285Sbrianroute_IfDelete(struct bundle *bundle, int all)
4396059Samurai{
4406059Samurai  struct rt_msghdr *rtm;
44158032Sbrian  struct sockaddr *sa[RTAX_MAX];
44258032Sbrian  struct sockaddr_in **in;
44358032Sbrian  struct in_addr sa_none;
44432021Sbrian  int pass;
44532021Sbrian  size_t needed;
4466059Samurai  char *sp, *cp, *ep;
4476735Samurai  int mib[6];
4486059Samurai
44940561Sbrian  log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index);
45031598Sbrian  sa_none.s_addr = INADDR_ANY;
45158032Sbrian  in = (struct sockaddr_in **)sa;
45226516Sbrian
4536059Samurai  mib[0] = CTL_NET;
4546059Samurai  mib[1] = PF_ROUTE;
4556735Samurai  mib[2] = 0;
4566735Samurai  mib[3] = 0;
4576059Samurai  mib[4] = NET_RT_DUMP;
4586735Samurai  mib[5] = 0;
4596735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
46036285Sbrian    log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n",
46128974Sbrian	      strerror(errno));
4626735Samurai    return;
4636735Samurai  }
4646059Samurai
4656059Samurai  sp = malloc(needed);
4666059Samurai  if (sp == NULL)
4676059Samurai    return;
4686059Samurai
4696735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
47036285Sbrian    log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n",
47128974Sbrian	      strerror(errno));
4726059Samurai    free(sp);
4736059Samurai    return;
4746059Samurai  }
4756059Samurai  ep = sp + needed;
4766059Samurai
47731739Sbrian  for (pass = 0; pass < 2; pass++) {
47831739Sbrian    /*
47931739Sbrian     * We do 2 passes.  The first deletes all cloned routes.  The second
48058032Sbrian     * deletes all non-cloned routes.  This is done to avoid
48131739Sbrian     * potential errors from trying to delete route X after route Y where
48236285Sbrian     * route X was cloned from route Y (and is no longer there 'cos it
48336285Sbrian     * may have gone with route Y).
48431739Sbrian     */
48531739Sbrian    if (RTF_WASCLONED == 0 && pass == 0)
48631739Sbrian      /* So we can't tell ! */
48731739Sbrian      continue;
48831739Sbrian    for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
48958032Sbrian      rtm = (struct rt_msghdr *)cp;
49058032Sbrian      route_ParseHdr(rtm, sa);
49158032Sbrian      if (sa[RTAX_DST]) {
49258032Sbrian        log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s),"
49358032Sbrian                  " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
49458032Sbrian                  Index2Nam(rtm->rtm_index), rtm->rtm_flags,
49558032Sbrian	          inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr));
49658032Sbrian        if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index &&
49758032Sbrian	    (all || (rtm->rtm_flags & RTF_GATEWAY))) {
49858032Sbrian          if (sa[RTAX_GATEWAY]->sa_family == AF_INET ||
49958032Sbrian              sa[RTAX_GATEWAY]->sa_family == AF_LINK) {
50058032Sbrian            if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
50158032Sbrian                (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
50258032Sbrian              log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n",
50358032Sbrian                         pass);
50458032Sbrian              bundle_SetRoute(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr,
50558032Sbrian                              sa_none, sa_none, 0, 0);
50658032Sbrian            } else
50758032Sbrian              log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
50831739Sbrian          } else
50958032Sbrian            log_Printf(LogDEBUG,
51058032Sbrian                      "route_IfDelete: Can't remove routes of %d family !\n",
51158032Sbrian                      sa[RTAX_GATEWAY]->sa_family);
51258032Sbrian        }
51331739Sbrian      }
5146059Samurai    }
5156059Samurai  }
5166059Samurai  free(sp);
5176059Samurai}
5186059Samurai
5196059Samuraiint
52028679SbrianGetIfIndex(char *name)
5216059Samurai{
52231176Sbrian  int idx;
52331343Sbrian  const char *got;
52428679Sbrian
52531354Sbrian  idx = 1;
52631176Sbrian  while (strcmp(got = Index2Nam(idx), "???"))
52731176Sbrian    if (!strcmp(got, name))
52836285Sbrian      return idx;
52931176Sbrian    else
53031176Sbrian      idx++;
53131176Sbrian  return -1;
5326059Samurai}
53331690Sbrian
53436285Sbrianvoid
53536285Sbrianroute_Change(struct bundle *bundle, struct sticky_route *r,
53658044Sbrian             struct in_addr me, struct in_addr peer, struct in_addr dns[2])
53731690Sbrian{
53836285Sbrian  struct in_addr none, del;
53931690Sbrian
54036285Sbrian  none.s_addr = INADDR_ANY;
54136285Sbrian  for (; r; r = r->next) {
54236285Sbrian    if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) {
54336285Sbrian      del.s_addr = r->dst.s_addr & r->mask.s_addr;
54437927Sbrian      bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0);
54536285Sbrian      r->dst = me;
54636285Sbrian      if (r->type & ROUTE_GWHISADDR)
54736285Sbrian        r->gw = peer;
54836285Sbrian    } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) {
54936285Sbrian      del.s_addr = r->dst.s_addr & r->mask.s_addr;
55037927Sbrian      bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0);
55136285Sbrian      r->dst = peer;
55236285Sbrian      if (r->type & ROUTE_GWHISADDR)
55336285Sbrian        r->gw = peer;
55458044Sbrian    } else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) {
55558044Sbrian      del.s_addr = r->dst.s_addr & r->mask.s_addr;
55658044Sbrian      bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0);
55758044Sbrian      r->dst = dns[0];
55858044Sbrian      if (r->type & ROUTE_GWHISADDR)
55958044Sbrian        r->gw = peer;
56058044Sbrian    } else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) {
56158044Sbrian      del.s_addr = r->dst.s_addr & r->mask.s_addr;
56258044Sbrian      bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0);
56358044Sbrian      r->dst = dns[1];
56458044Sbrian      if (r->type & ROUTE_GWHISADDR)
56558044Sbrian        r->gw = peer;
56636285Sbrian    } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr)
56736285Sbrian      r->gw = peer;
56837927Sbrian    bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0);
56936285Sbrian  }
57036285Sbrian}
57136285Sbrian
57236285Sbrianvoid
57336285Sbrianroute_Clean(struct bundle *bundle, struct sticky_route *r)
57436285Sbrian{
57536285Sbrian  struct in_addr none, del;
57636285Sbrian
57736285Sbrian  none.s_addr = INADDR_ANY;
57836285Sbrian  for (; r; r = r->next) {
57936285Sbrian    del.s_addr = r->dst.s_addr & r->mask.s_addr;
58037927Sbrian    bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0);
58136285Sbrian  }
58236285Sbrian}
58336285Sbrian
58436285Sbrianvoid
58536285Sbrianroute_Add(struct sticky_route **rp, int type, struct in_addr dst,
58636285Sbrian          struct in_addr mask, struct in_addr gw)
58736285Sbrian{
58843313Sbrian  struct sticky_route *r;
58943313Sbrian  int dsttype = type & ROUTE_DSTANY;
59036285Sbrian
59143313Sbrian  r = NULL;
59243313Sbrian  while (*rp) {
59343313Sbrian    if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
59443313Sbrian        (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) {
59543313Sbrian      /* Oops, we already have this route - unlink it */
59643313Sbrian      free(r);			/* impossible really  */
59743313Sbrian      r = *rp;
59843313Sbrian      *rp = r->next;
59943313Sbrian    } else
60043313Sbrian      rp = &(*rp)->next;
60143313Sbrian  }
60236285Sbrian
60343313Sbrian  if (!r)
60443313Sbrian    r = (struct sticky_route *)malloc(sizeof(struct sticky_route));
60543313Sbrian  r->type = type;
60643313Sbrian  r->next = NULL;
60743313Sbrian  r->dst = dst;
60843313Sbrian  r->mask = mask;
60943313Sbrian  r->gw = gw;
61043313Sbrian  *rp = r;
61136285Sbrian}
61236285Sbrian
61336285Sbrianvoid
61436285Sbrianroute_Delete(struct sticky_route **rp, int type, struct in_addr dst)
61536285Sbrian{
61636285Sbrian  struct sticky_route *r;
61736285Sbrian  int dsttype = type & ROUTE_DSTANY;
61836285Sbrian
61936285Sbrian  for (; *rp; rp = &(*rp)->next) {
62036285Sbrian    if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
62136285Sbrian        (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) {
62236285Sbrian      r = *rp;
62336285Sbrian      *rp = r->next;
62436285Sbrian      free(r);
62531690Sbrian      break;
62631690Sbrian    }
62731690Sbrian  }
62836285Sbrian}
62931690Sbrian
63036285Sbrianvoid
63136285Sbrianroute_DeleteAll(struct sticky_route **rp)
63236285Sbrian{
63336285Sbrian  struct sticky_route *r, *rn;
63436285Sbrian
63536285Sbrian  for (r = *rp; r; r = rn) {
63636285Sbrian    rn = r->next;
63736285Sbrian    free(r);
63831690Sbrian  }
63936285Sbrian  *rp = NULL;
64036285Sbrian}
64131690Sbrian
64236285Sbrianvoid
64343313Sbrianroute_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag,
64443313Sbrian                 int indent)
64536285Sbrian{
64636285Sbrian  int def;
64743313Sbrian  int tlen = strlen(tag);
64836285Sbrian
64943313Sbrian  if (tlen + 2 > indent)
65043313Sbrian    prompt_Printf(p, "%s:\n%*s", tag, indent, "");
65143313Sbrian  else
65243313Sbrian    prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, "");
65343313Sbrian
65436285Sbrian  for (; r; r = r->next) {
65536285Sbrian    def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY;
65636285Sbrian
65743313Sbrian    prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, "");
65843313Sbrian    tlen = 0;
65936285Sbrian    if (r->type & ROUTE_DSTMYADDR)
66036285Sbrian      prompt_Printf(p, "MYADDR");
66136285Sbrian    else if (r->type & ROUTE_DSTHISADDR)
66236285Sbrian      prompt_Printf(p, "HISADDR");
66358044Sbrian    else if (r->type & ROUTE_DSTDNS0)
66458044Sbrian      prompt_Printf(p, "DNS0");
66558044Sbrian    else if (r->type & ROUTE_DSTDNS1)
66658044Sbrian      prompt_Printf(p, "DNS1");
66736285Sbrian    else if (!def)
66836285Sbrian      prompt_Printf(p, "%s", inet_ntoa(r->dst));
66936285Sbrian
67036285Sbrian    if (def)
67136285Sbrian      prompt_Printf(p, "default ");
67236285Sbrian    else
67336285Sbrian      prompt_Printf(p, " %s ", inet_ntoa(r->mask));
67436285Sbrian
67536285Sbrian    if (r->type & ROUTE_GWHISADDR)
67636285Sbrian      prompt_Printf(p, "HISADDR\n");
67736285Sbrian    else
67836285Sbrian      prompt_Printf(p, "%s\n", inet_ntoa(r->gw));
67936285Sbrian  }
68031690Sbrian}
681