route.c revision 32663
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 *
2032663Sbrian * $Id: route.c,v 1.41 1998/01/19 02:59:33 brian Exp $
218857Srgrimes *
226059Samurai */
2330715Sbrian
246059Samurai#include <sys/param.h>
2530715Sbrian#include <sys/time.h>
266059Samurai#include <sys/socket.h>
2731176Sbrian#include <net/if_types.h>
2830715Sbrian#include <net/route.h>
2930715Sbrian#include <net/if.h>
3030715Sbrian#include <netinet/in.h>
3130715Sbrian#include <arpa/inet.h>
3231176Sbrian#include <net/if_dl.h>
3320287Swollman
3420287Swollman#include <errno.h>
3530715Sbrian#include <machine/endian.h>
3630715Sbrian#include <stdio.h>
376059Samurai#include <stdlib.h>
386059Samurai#include <string.h>
3930715Sbrian#include <sys/ioctl.h>
4030715Sbrian#include <sys/sysctl.h>
416059Samurai#include <unistd.h>
4220287Swollman
4331343Sbrian#include "command.h"
4430715Sbrian#include "mbuf.h"
459439Samurai#include "log.h"
4626516Sbrian#include "loadalias.h"
4731070Sbrian#include "defs.h"
4826516Sbrian#include "vars.h"
4931061Sbrian#include "id.h"
5031690Sbrian#include "os.h"
5131690Sbrian#include "ipcp.h"
5231690Sbrian#include "iplist.h"
5330715Sbrian#include "route.h"
546059Samurai
556059Samuraistatic int IfIndex;
566059Samurai
576059Samuraistruct rtmsg {
586059Samurai  struct rt_msghdr m_rtm;
596059Samurai  char m_space[64];
606059Samurai};
616059Samurai
626059Samuraistatic int seqno;
636059Samurai
646059Samuraivoid
6528679SbrianOsSetRoute(int cmd,
6628679Sbrian	   struct in_addr dst,
6728679Sbrian	   struct in_addr gateway,
6832109Sbrian	   struct in_addr mask,
6932109Sbrian	   int bang)
706059Samurai{
716059Samurai  struct rtmsg rtmes;
726059Samurai  int s, nb, wb;
7331343Sbrian  char *cp;
7431343Sbrian  const char *cmdstr;
756059Samurai  struct sockaddr_in rtdata;
766059Samurai
7732109Sbrian  if (bang)
7832109Sbrian    cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
7932109Sbrian  else
8032109Sbrian    cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
8131061Sbrian  s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
8227725Sbrian  if (s < 0) {
8328974Sbrian    LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
8427725Sbrian    return;
8527725Sbrian  }
8631962Sbrian  memset(&rtmes, '\0', sizeof rtmes);
876059Samurai  rtmes.m_rtm.rtm_version = RTM_VERSION;
886059Samurai  rtmes.m_rtm.rtm_type = cmd;
8931598Sbrian  rtmes.m_rtm.rtm_addrs = RTA_DST;
906059Samurai  rtmes.m_rtm.rtm_seq = ++seqno;
916059Samurai  rtmes.m_rtm.rtm_pid = getpid();
9217571Speter  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
936059Samurai
9431962Sbrian  memset(&rtdata, '\0', sizeof rtdata);
956059Samurai  rtdata.sin_len = 16;
966059Samurai  rtdata.sin_family = AF_INET;
976059Samurai  rtdata.sin_port = 0;
986059Samurai  rtdata.sin_addr = dst;
996059Samurai
1006059Samurai  cp = rtmes.m_space;
10130715Sbrian  memcpy(cp, &rtdata, 16);
1026059Samurai  cp += 16;
10331598Sbrian  if (cmd == RTM_ADD)
10431598Sbrian    if (gateway.s_addr == INADDR_ANY) {
10531598Sbrian      /* Add a route through the interface */
10631598Sbrian      struct sockaddr_dl dl;
10731598Sbrian      const char *iname;
10831598Sbrian      int ilen;
10931598Sbrian
11031598Sbrian      iname = Index2Nam(IfIndex);
11131598Sbrian      ilen = strlen(iname);
11231962Sbrian      dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
11331598Sbrian      dl.sdl_family = AF_LINK;
11431598Sbrian      dl.sdl_index = IfIndex;
11531598Sbrian      dl.sdl_type = 0;
11631598Sbrian      dl.sdl_nlen = ilen;
11731598Sbrian      dl.sdl_alen = 0;
11831598Sbrian      dl.sdl_slen = 0;
11931962Sbrian      strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
12031598Sbrian
12131598Sbrian      memcpy(cp, &dl, dl.sdl_len);
12231598Sbrian      cp += dl.sdl_len;
12331598Sbrian      rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
12431598Sbrian    } else {
12531598Sbrian      rtdata.sin_addr = gateway;
12631598Sbrian      memcpy(cp, &rtdata, 16);
12731598Sbrian      cp += 16;
12831598Sbrian      rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
12931598Sbrian    }
13031598Sbrian
13131598Sbrian  if (dst.s_addr == INADDR_ANY)
13231598Sbrian    mask.s_addr = INADDR_ANY;
13331598Sbrian
13431598Sbrian  if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
13531598Sbrian    rtdata.sin_addr = mask;
13630715Sbrian    memcpy(cp, &rtdata, 16);
1376059Samurai    cp += 16;
13831598Sbrian    rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
1396059Samurai  }
1406059Samurai
14128679Sbrian  nb = cp - (char *) &rtmes;
1426059Samurai  rtmes.m_rtm.rtm_msglen = nb;
14332025Sbrian  wb = ID0write(s, &rtmes, nb);
1446059Samurai  if (wb < 0) {
14531739Sbrian    LogPrintf(LogTCPIP, "OsSetRoute failure:\n");
14631739Sbrian    LogPrintf(LogTCPIP, "OsSetRoute:  Cmd = %s\n", cmd);
14731739Sbrian    LogPrintf(LogTCPIP, "OsSetRoute:  Dst = %s\n", inet_ntoa(dst));
14826591Sbrian    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
14926591Sbrian    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
15032109Sbrianfailed:
15132109Sbrian    if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
15232109Sbrian                           (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST)))
15332109Sbrian      if (!bang)
15432109Sbrian        LogPrintf(LogWARN, "Add route failed: %s already exists\n",
15532109Sbrian                  inet_ntoa(dst));
15632109Sbrian      else {
15732109Sbrian        rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
15832109Sbrian        if ((wb = ID0write(s, &rtmes, nb)) < 0)
15932109Sbrian          goto failed;
16032109Sbrian      }
16132109Sbrian    else if (cmd == RTM_DELETE &&
16232109Sbrian             (rtmes.m_rtm.rtm_errno == ESRCH ||
16332109Sbrian              (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
16432109Sbrian      if (!bang)
16532109Sbrian        LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n",
16632109Sbrian                  inet_ntoa(dst));
16732109Sbrian    } else if (rtmes.m_rtm.rtm_errno == 0)
16831739Sbrian      LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
16931739Sbrian                inet_ntoa(dst), strerror(errno));
17032109Sbrian    else
17131739Sbrian      LogPrintf(LogWARN, "%s route failed: %s: %s\n",
17231739Sbrian		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
1736059Samurai  }
17431061Sbrian  LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
17531061Sbrian            wb, cmdstr, dst.s_addr, gateway.s_addr);
1766059Samurai  close(s);
1776059Samurai}
1786059Samurai
1796059Samuraistatic void
18031176Sbrianp_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width)
1816059Samurai{
18231343Sbrian  char buf[29];
18331176Sbrian  struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
18431176Sbrian  struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
18531176Sbrian  struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
1866059Samurai
18731176Sbrian  switch (phost->sa_family) {
18831176Sbrian  case AF_INET:
18931176Sbrian    if (!phost)
19031541Sbrian      buf[0] = '\0';
19131176Sbrian    else if (ihost->sin_addr.s_addr == INADDR_ANY)
19231541Sbrian      strcpy(buf, "default");
19331176Sbrian    else if (!mask)
19431541Sbrian      strcpy(buf, inet_ntoa(ihost->sin_addr));
19531176Sbrian    else {
19631176Sbrian      u_int msk = ntohl(mask->sin_addr.s_addr);
19731176Sbrian      u_int tst;
19831176Sbrian      int bits;
19931176Sbrian      int len;
20031176Sbrian      struct sockaddr_in net;
20131176Sbrian
20231176Sbrian      for (tst = 1, bits=32; tst; tst <<= 1, bits--)
20331176Sbrian        if (msk & tst)
20431176Sbrian          break;
20531176Sbrian
20631176Sbrian      for (tst <<=1; tst; tst <<= 1)
20731176Sbrian        if (!(msk & tst))
20831176Sbrian          break;
20931176Sbrian
21031176Sbrian      net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
21131791Sbrian      strcpy(buf, inet_ntoa(net.sin_addr));
21231176Sbrian      for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
21331176Sbrian        if (strcmp(buf+len-2, ".0"))
21431176Sbrian          break;
21531176Sbrian
21631176Sbrian      if (tst)    /* non-contiguous :-( */
21731176Sbrian        sprintf(buf+strlen(buf),"&0x%08x", msk);
21831176Sbrian      else
21931176Sbrian        sprintf(buf+strlen(buf), "/%d", bits);
22031176Sbrian    }
22131176Sbrian    break;
22231176Sbrian
22331176Sbrian  case AF_LINK:
22431541Sbrian    if (dl->sdl_nlen)
22531541Sbrian      snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
22631541Sbrian    else if (dl->sdl_alen)
22731541Sbrian      if (dl->sdl_type == IFT_ETHER)
22831962Sbrian        if (dl->sdl_alen < sizeof buf / 3) {
22931541Sbrian          int f;
23031541Sbrian          u_char *MAC;
23131541Sbrian
23231541Sbrian          MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
23331541Sbrian          for (f = 0; f < dl->sdl_alen; f++)
23431541Sbrian            sprintf(buf+f*3, "%02x:", MAC[f]);
23531541Sbrian          buf[f*3-1] = '\0';
23631541Sbrian        } else
23731791Sbrian	  strcpy(buf, "??:??:??:??:??:??");
23831541Sbrian      else
23931541Sbrian        sprintf(buf, "<IFT type %d>", dl->sdl_type);
24031541Sbrian    else if (dl->sdl_slen)
24131541Sbrian      sprintf(buf, "<slen %d?>", dl->sdl_slen);
24231541Sbrian    else
24331176Sbrian      sprintf(buf, "link#%d", dl->sdl_index);
24431176Sbrian    break;
24531176Sbrian
24631176Sbrian  default:
24731541Sbrian    sprintf(buf, "<AF type %d>", phost->sa_family);
24831176Sbrian    break;
24926516Sbrian  }
25031176Sbrian
25131541Sbrian  fprintf(VarTerm, "%-*s ", width-1, buf);
2526059Samurai}
2536059Samurai
25432663Sbrianstatic struct bits {
25531176Sbrian  u_long b_mask;
25628679Sbrian  char b_val;
25731176Sbrian} bits[] = {
25831176Sbrian  { RTF_UP, 'U' },
25931176Sbrian  { RTF_GATEWAY, 'G' },
26031176Sbrian  { RTF_HOST, 'H' },
26131176Sbrian  { RTF_REJECT, 'R' },
26231176Sbrian  { RTF_DYNAMIC, 'D' },
26331176Sbrian  { RTF_MODIFIED, 'M' },
26431176Sbrian  { RTF_DONE, 'd' },
26531176Sbrian  { RTF_CLONING, 'C' },
26631176Sbrian  { RTF_XRESOLVE, 'X' },
26731176Sbrian  { RTF_LLINFO, 'L' },
26831176Sbrian  { RTF_STATIC, 'S' },
26931176Sbrian  { RTF_PROTO1, '1' },
27031176Sbrian  { RTF_PROTO2, '2' },
27131176Sbrian  { RTF_BLACKHOLE, 'B' },
27231739Sbrian#ifdef RTF_WASCLONED
27331176Sbrian  { RTF_WASCLONED, 'W' },
27431739Sbrian#endif
27531739Sbrian#ifdef RTF_PRCLONING
27631176Sbrian  { RTF_PRCLONING, 'c' },
27731739Sbrian#endif
27831739Sbrian#ifdef RTF_PROTO3
27931176Sbrian  { RTF_PROTO3, '3' },
28031739Sbrian#endif
28131739Sbrian#ifdef RTF_BROADCAST
28231176Sbrian  { RTF_BROADCAST, 'b' },
28331176Sbrian#endif
28431176Sbrian  { 0, '\0' }
2856059Samurai};
2866059Samurai
28731739Sbrian#ifndef RTF_WASCLONED
28831739Sbrian#define RTF_WASCLONED (0)
28931739Sbrian#endif
29031739Sbrian
2916059Samuraistatic void
29231827Sbrianp_flags(u_long f, int max)
2936059Samurai{
29426516Sbrian  if (VarTerm) {
29526516Sbrian    char name[33], *flags;
29626516Sbrian    register struct bits *p = bits;
2976059Samurai
29831962Sbrian    if (max > sizeof name - 1)
29931962Sbrian      max = sizeof name - 1;
30031827Sbrian
30131827Sbrian    for (flags = name; p->b_mask && flags - name < max; p++)
30226516Sbrian      if (p->b_mask & f)
30328679Sbrian	*flags++ = p->b_val;
30426516Sbrian    *flags = '\0';
30531827Sbrian    fprintf(VarTerm, "%-*.*s", max, max, name);
30626516Sbrian  }
3076059Samurai}
3086059Samurai
30932616Sbrianconst char *
31031176SbrianIndex2Nam(int idx)
31131176Sbrian{
31232425Sbrian  static char **ifs;
31331354Sbrian  static int nifs, debug_done;
31431176Sbrian
31531176Sbrian  if (!nifs) {
31632425Sbrian    int mib[6], have, had;
31732021Sbrian    size_t needed;
31831176Sbrian    char *buf, *ptr, *end;
31931176Sbrian    struct sockaddr_dl *dl;
32031176Sbrian    struct if_msghdr *ifm;
32131176Sbrian
32231176Sbrian    mib[0] = CTL_NET;
32331176Sbrian    mib[1] = PF_ROUTE;
32431176Sbrian    mib[2] = 0;
32531176Sbrian    mib[3] = 0;
32631176Sbrian    mib[4] = NET_RT_IFLIST;
32731176Sbrian    mib[5] = 0;
32831176Sbrian
32931176Sbrian    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
33031176Sbrian      LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
33131176Sbrian      return "???";
33231176Sbrian    }
33331176Sbrian    if ((buf = malloc(needed)) == NULL)
33431176Sbrian      return "???";
33531176Sbrian    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
33631176Sbrian      free(buf);
33731176Sbrian      return "???";
33831176Sbrian    }
33931176Sbrian    end = buf + needed;
34031176Sbrian
34132425Sbrian    have = 0;
34231354Sbrian    for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
34331176Sbrian      ifm = (struct if_msghdr *)ptr;
34431176Sbrian      dl = (struct sockaddr_dl *)(ifm + 1);
34532425Sbrian      if (ifm->ifm_index > 0) {
34632425Sbrian        if (ifm->ifm_index > have) {
34732425Sbrian          had = have;
34832425Sbrian          have = ifm->ifm_index + 5;
34932425Sbrian          if (had)
35032425Sbrian            ifs = (char **)realloc(ifs, sizeof(char *) * have);
35132425Sbrian          else
35232425Sbrian            ifs = (char **)malloc(sizeof(char *) * have);
35332425Sbrian          if (!ifs) {
35432425Sbrian            LogPrintf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
35532425Sbrian            nifs = 0;
35632425Sbrian            return "???";
35732425Sbrian          }
35832425Sbrian          memset(ifs + had, '\0', sizeof(char *) * (have - had));
35932425Sbrian        }
36032425Sbrian        if (ifs[ifm->ifm_index-1] == NULL) {
36132425Sbrian          ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
36232425Sbrian          memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
36332425Sbrian          ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
36432425Sbrian          if (nifs < ifm->ifm_index)
36532425Sbrian            nifs = ifm->ifm_index;
36632425Sbrian        }
36731354Sbrian      } else if (LogIsKept(LogDEBUG))
36831354Sbrian        LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n",
36931354Sbrian                  ifm->ifm_index);
37031176Sbrian    }
37131176Sbrian    free(buf);
37231176Sbrian  }
37331176Sbrian
37431354Sbrian  if (LogIsKept(LogDEBUG) && !debug_done) {
37531354Sbrian    int f;
37631354Sbrian
37731354Sbrian    LogPrintf(LogDEBUG, "Found the following interfaces:\n");
37831354Sbrian    for (f = 0; f < nifs; f++)
37932425Sbrian      if (ifs[f] != NULL)
38031354Sbrian        LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
38131354Sbrian    debug_done = 1;
38231354Sbrian  }
38331354Sbrian
38432425Sbrian  if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
38531176Sbrian    return "???";
38631354Sbrian
38731354Sbrian  return ifs[idx-1];
38831176Sbrian}
38931176Sbrian
3906059Samuraiint
39131343SbrianShowRoute(struct cmdargs const *arg)
3926059Samurai{
3936059Samurai  struct rt_msghdr *rtm;
39431176Sbrian  struct sockaddr *sa_dst, *sa_gw, *sa_mask;
39531176Sbrian  char *sp, *ep, *cp, *wp;
39632021Sbrian  size_t needed;
3976735Samurai  int mib[6];
3986059Samurai
39926516Sbrian  if (!VarTerm)
40026516Sbrian    return 1;
40126516Sbrian
4026059Samurai  mib[0] = CTL_NET;
4036059Samurai  mib[1] = PF_ROUTE;
4046735Samurai  mib[2] = 0;
4056735Samurai  mib[3] = 0;
4066059Samurai  mib[4] = NET_RT_DUMP;
4076735Samurai  mib[5] = 0;
4086735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
40928974Sbrian    LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
41028679Sbrian    return (1);
4116735Samurai  }
4126059Samurai  if (needed < 0)
41328679Sbrian    return (1);
4146059Samurai  sp = malloc(needed);
4156059Samurai  if (sp == NULL)
41628679Sbrian    return (1);
4176735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
41828974Sbrian    LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
41918885Sjkh    free(sp);
42028679Sbrian    return (1);
4216735Samurai  }
4226059Samurai  ep = sp + needed;
4236059Samurai
42431176Sbrian  fprintf(VarTerm, "%-20s%-20sFlags  Netif\n", "Destination", "Gateway");
4256059Samurai  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
42628679Sbrian    rtm = (struct rt_msghdr *) cp;
42731176Sbrian    wp = (char *)(rtm+1);
42831176Sbrian
42931176Sbrian    if (rtm->rtm_addrs & RTA_DST) {
43031176Sbrian      sa_dst = (struct sockaddr *)wp;
43131176Sbrian      wp += sa_dst->sa_len;
43231176Sbrian    } else
43331176Sbrian      sa_dst = NULL;
43431176Sbrian
43531176Sbrian    if (rtm->rtm_addrs & RTA_GATEWAY) {
43631176Sbrian      sa_gw = (struct sockaddr *)wp;
43731176Sbrian      wp += sa_gw->sa_len;
43831176Sbrian    } else
43931176Sbrian      sa_gw = NULL;
44031176Sbrian
44131176Sbrian    if (rtm->rtm_addrs & RTA_NETMASK) {
44231176Sbrian      sa_mask = (struct sockaddr *)wp;
44331176Sbrian      wp += sa_mask->sa_len;
44431176Sbrian    } else
44531176Sbrian      sa_mask = NULL;
44631176Sbrian
44731176Sbrian    p_sockaddr(sa_dst, sa_mask, 20);
44831176Sbrian    p_sockaddr(sa_gw, NULL, 20);
44931176Sbrian
45031827Sbrian    p_flags(rtm->rtm_flags, 6);
45131827Sbrian    fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index));
4526059Samurai  }
45318885Sjkh  free(sp);
45426516Sbrian  return 0;
4556059Samurai}
4566059Samurai
4576059Samurai/*
4586059Samurai *  Delete routes associated with our interface
4596059Samurai */
4606059Samuraivoid
46128679SbrianDeleteIfRoutes(int all)
4626059Samurai{
4636059Samurai  struct rt_msghdr *rtm;
4646059Samurai  struct sockaddr *sa;
46531598Sbrian  struct in_addr sa_dst, sa_none;
46632021Sbrian  int pass;
46732021Sbrian  size_t needed;
4686059Samurai  char *sp, *cp, *ep;
4696735Samurai  int mib[6];
4706059Samurai
47126516Sbrian  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
47231598Sbrian  sa_none.s_addr = INADDR_ANY;
47326516Sbrian
4746059Samurai  mib[0] = CTL_NET;
4756059Samurai  mib[1] = PF_ROUTE;
4766735Samurai  mib[2] = 0;
4776735Samurai  mib[3] = 0;
4786059Samurai  mib[4] = NET_RT_DUMP;
4796735Samurai  mib[5] = 0;
4806735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
48128974Sbrian    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
48228974Sbrian	      strerror(errno));
4836735Samurai    return;
4846735Samurai  }
4856059Samurai  if (needed < 0)
4866059Samurai    return;
4876059Samurai
4886059Samurai  sp = malloc(needed);
4896059Samurai  if (sp == NULL)
4906059Samurai    return;
4916059Samurai
4926735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
49328974Sbrian    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
49428974Sbrian	      strerror(errno));
4956059Samurai    free(sp);
4966059Samurai    return;
4976059Samurai  }
4986059Samurai  ep = sp + needed;
4996059Samurai
50031739Sbrian  for (pass = 0; pass < 2; pass++) {
50131739Sbrian    /*
50231739Sbrian     * We do 2 passes.  The first deletes all cloned routes.  The second
50331739Sbrian     * deletes all non-cloned routes.  This is necessary to avoid
50431739Sbrian     * potential errors from trying to delete route X after route Y where
50531739Sbrian     * route X was cloned from route Y (which is no longer there).
50631739Sbrian     */
50731739Sbrian    if (RTF_WASCLONED == 0 && pass == 0)
50831739Sbrian      /* So we can't tell ! */
50931739Sbrian      continue;
51031739Sbrian    for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
51131739Sbrian      rtm = (struct rt_msghdr *) cp;
51231739Sbrian      sa = (struct sockaddr *) (rtm + 1);
51331739Sbrian      LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s),"
51431739Sbrian                " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
51531739Sbrian                Index2Nam(rtm->rtm_index), rtm->rtm_flags,
51631739Sbrian	        inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
51731739Sbrian      if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
51831739Sbrian	  rtm->rtm_index == IfIndex &&
51931739Sbrian	  (all || (rtm->rtm_flags & RTF_GATEWAY))) {
52031739Sbrian        sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
52131739Sbrian        sa = (struct sockaddr *)((char *)sa + sa->sa_len);
52231739Sbrian        if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
52331739Sbrian          if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
52431739Sbrian              (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
52531739Sbrian            LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass);
52632109Sbrian            OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none, 0);
52731739Sbrian          } else
52831739Sbrian            LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass);
52931739Sbrian        } else
53031739Sbrian          LogPrintf(LogDEBUG,
53131739Sbrian                    "DeleteIfRoutes: Can't remove routes of %d family !\n",
53231739Sbrian                    sa->sa_family);
53331739Sbrian      }
5346059Samurai    }
5356059Samurai  }
5366059Samurai  free(sp);
5376059Samurai}
5386059Samurai
5396059Samuraiint
54028679SbrianGetIfIndex(char *name)
5416059Samurai{
54231176Sbrian  int idx;
54331343Sbrian  const char *got;
54428679Sbrian
54531354Sbrian  idx = 1;
54631176Sbrian  while (strcmp(got = Index2Nam(idx), "???"))
54731176Sbrian    if (!strcmp(got, name))
54831176Sbrian      return IfIndex = idx;
54931176Sbrian    else
55031176Sbrian      idx++;
55131176Sbrian  return -1;
5526059Samurai}
55331690Sbrian
55431690Sbrianstruct in_addr
55531690SbrianChooseHisAddr(const struct in_addr gw)
55631690Sbrian{
55731690Sbrian  struct in_addr try;
55831690Sbrian  int f;
55931690Sbrian
56031690Sbrian  for (f = 0; f < DefHisChoice.nItems; f++) {
56131690Sbrian    try = iplist_next(&DefHisChoice);
56231690Sbrian    LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
56331690Sbrian              f, inet_ntoa(try));
56431690Sbrian    if (OsTrySetIpaddress(gw, try) == 0) {
56531690Sbrian      LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
56631690Sbrian                inet_ntoa(try));
56731690Sbrian      break;
56831690Sbrian    }
56931690Sbrian  }
57031690Sbrian
57131690Sbrian  if (f == DefHisChoice.nItems) {
57231690Sbrian    LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
57331690Sbrian    try.s_addr = INADDR_ANY;
57431690Sbrian  }
57531690Sbrian
57631690Sbrian  return try;
57731690Sbrian}
578