route.c revision 34536
14Srgrimes/*
21690Sdg *	      PPP Routing related Module
31690Sdg *
41690Sdg *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
54Srgrimes *
64Srgrimes *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
74Srgrimes *
84Srgrimes * Redistribution and use in source and binary forms are permitted
94Srgrimes * provided that the above copyright notice and this paragraph are
104Srgrimes * duplicated in all such forms and that any documentation,
114Srgrimes * advertising materials, and other materials related to such
124Srgrimes * distribution and use acknowledge that the software was developed
134Srgrimes * by the Internet Initiative Japan, Inc.  The name of the
144Srgrimes * IIJ may not be used to endorse or promote products derived
154Srgrimes * from this software without specific prior written permission.
164Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
174Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
184Srgrimes * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
194Srgrimes *
204Srgrimes * $Id: route.c,v 1.42 1998/01/21 02:15:26 brian Exp $
214Srgrimes *
224Srgrimes */
234Srgrimes
244Srgrimes#include <sys/param.h>
254Srgrimes#include <sys/time.h>
264Srgrimes#include <sys/socket.h>
274Srgrimes#include <net/if_types.h>
284Srgrimes#include <net/route.h>
294Srgrimes#include <net/if.h>
304Srgrimes#include <netinet/in.h>
314Srgrimes#include <arpa/inet.h>
324Srgrimes#include <net/if_dl.h>
334Srgrimes
344Srgrimes#include <errno.h>
354Srgrimes#include <machine/endian.h>
364Srgrimes#include <stdio.h>
37608Srgrimes#include <stdlib.h>
385603Sbde#include <string.h>
394Srgrimes#include <sys/ioctl.h>
404Srgrimes#include <sys/sysctl.h>
414Srgrimes#include <unistd.h>
421704Sdg
434Srgrimes#include "command.h"
444Srgrimes#include "mbuf.h"
451549Srgrimes#include "log.h"
461549Srgrimes#include "loadalias.h"
471549Srgrimes#include "defs.h"
481549Srgrimes#include "vars.h"
491549Srgrimes#include "id.h"
501549Srgrimes#include "os.h"
511549Srgrimes#include "ipcp.h"
522257Ssos#include "iplist.h"
534Srgrimes#include "route.h"
541549Srgrimes
554Srgrimesstatic int IfIndex;
564Srgrimes
571549Srgrimesstruct rtmsg {
581549Srgrimes  struct rt_msghdr m_rtm;
591549Srgrimes  char m_space[64];
601549Srgrimes};
614Srgrimes
621549Srgrimesstatic int seqno;
631549Srgrimes
641549Srgrimesvoid
651549SrgrimesOsSetRoute(int cmd,
663436Sphk	   struct in_addr dst,
671549Srgrimes	   struct in_addr gateway,
681549Srgrimes	   struct in_addr mask,
691549Srgrimes	   int bang)
701549Srgrimes{
711690Sdg  struct rtmsg rtmes;
721690Sdg  int s, nb, wb;
734Srgrimes  char *cp;
74757Sdg  const char *cmdstr;
75757Sdg  struct sockaddr_in rtdata;
765603Sbde
77757Sdg  if (bang)
785603Sbde    cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
79757Sdg  else
80757Sdg    cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
815603Sbde  s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
82757Sdg  if (s < 0) {
83757Sdg    LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
845603Sbde    return;
851690Sdg  }
86757Sdg  memset(&rtmes, '\0', sizeof rtmes);
87757Sdg  rtmes.m_rtm.rtm_version = RTM_VERSION;
88757Sdg  rtmes.m_rtm.rtm_type = cmd;
895603Sbde  rtmes.m_rtm.rtm_addrs = RTA_DST;
90757Sdg  rtmes.m_rtm.rtm_seq = ++seqno;
915603Sbde  rtmes.m_rtm.rtm_pid = getpid();
925603Sbde  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
935603Sbde
94757Sdg  memset(&rtdata, '\0', sizeof rtdata);
95757Sdg  rtdata.sin_len = 16;
96757Sdg  rtdata.sin_family = AF_INET;
97757Sdg  rtdata.sin_port = 0;
98757Sdg  rtdata.sin_addr = dst;
99757Sdg
100757Sdg  cp = rtmes.m_space;
101757Sdg  memcpy(cp, &rtdata, 16);
102757Sdg  cp += 16;
103757Sdg  if (cmd == RTM_ADD) {
104757Sdg    if (gateway.s_addr == INADDR_ANY) {
1054Srgrimes      /* Add a route through the interface */
1061690Sdg      struct sockaddr_dl dl;
1071690Sdg      const char *iname;
1081690Sdg      int ilen;
1091690Sdg
1101690Sdg      iname = Index2Nam(IfIndex);
1111690Sdg      ilen = strlen(iname);
1121690Sdg      dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
113757Sdg      dl.sdl_family = AF_LINK;
1143436Sphk      dl.sdl_index = IfIndex;
1151690Sdg      dl.sdl_type = 0;
1161690Sdg      dl.sdl_nlen = ilen;
1171690Sdg      dl.sdl_alen = 0;
1181690Sdg      dl.sdl_slen = 0;
1191690Sdg      strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
1201690Sdg
1211690Sdg      memcpy(cp, &dl, dl.sdl_len);
1221690Sdg      cp += dl.sdl_len;
1231690Sdg      rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
1241690Sdg    } else {
1251690Sdg      rtdata.sin_addr = gateway;
1261690Sdg      memcpy(cp, &rtdata, 16);
1271690Sdg      cp += 16;
1281690Sdg      rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
1291690Sdg    }
1301690Sdg  }
1313436Sphk
1321690Sdg  if (dst.s_addr == INADDR_ANY)
1331690Sdg    mask.s_addr = INADDR_ANY;
1341690Sdg
1351690Sdg  if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
1361690Sdg    rtdata.sin_addr = mask;
1371690Sdg    memcpy(cp, &rtdata, 16);
1381690Sdg    cp += 16;
1391690Sdg    rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
1401690Sdg  }
1411690Sdg
1421690Sdg  nb = cp - (char *) &rtmes;
1431690Sdg  rtmes.m_rtm.rtm_msglen = nb;
1441690Sdg  wb = ID0write(s, &rtmes, nb);
1451690Sdg  if (wb < 0) {
1461690Sdg    LogPrintf(LogTCPIP, "OsSetRoute failure:\n");
1471690Sdg    LogPrintf(LogTCPIP, "OsSetRoute:  Cmd = %s\n", cmd);
1481690Sdg    LogPrintf(LogTCPIP, "OsSetRoute:  Dst = %s\n", inet_ntoa(dst));
1491690Sdg    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
1504Srgrimes    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
1514Srgrimesfailed:
1521690Sdg    if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
1531690Sdg                           (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
1544Srgrimes      if (!bang)
1551690Sdg        LogPrintf(LogWARN, "Add route failed: %s already exists\n",
1564Srgrimes                  inet_ntoa(dst));
1574Srgrimes      else {
1584Srgrimes        rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
159798Swollman        if ((wb = ID0write(s, &rtmes, nb)) < 0)
1604Srgrimes          goto failed;
1614Srgrimes      }
1624Srgrimes    } else if (cmd == RTM_DELETE &&
1631690Sdg             (rtmes.m_rtm.rtm_errno == ESRCH ||
1641549Srgrimes              (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
1653436Sphk      if (!bang)
1663744Swollman        LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n",
1673744Swollman                  inet_ntoa(dst));
1683744Swollman    } else if (rtmes.m_rtm.rtm_errno == 0)
1694Srgrimes      LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
1704Srgrimes                inet_ntoa(dst), strerror(errno));
1711690Sdg    else
1724Srgrimes      LogPrintf(LogWARN, "%s route failed: %s: %s\n",
1731690Sdg		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
1741690Sdg  }
175200Sdg  LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
1761690Sdg            wb, cmdstr, dst.s_addr, gateway.s_addr);
1771549Srgrimes  close(s);
1784Srgrimes}
1791690Sdg
1801690Sdgstatic void
1811690Sdgp_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width)
1821690Sdg{
1831690Sdg  char buf[29];
184974Sdg  struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
1851690Sdg  struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
1861690Sdg  struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
1871690Sdg
1881690Sdg  switch (phost->sa_family) {
1891690Sdg  case AF_INET:
190974Sdg    if (!phost)
1911690Sdg      buf[0] = '\0';
1921690Sdg    else if (ihost->sin_addr.s_addr == INADDR_ANY)
1931690Sdg      strcpy(buf, "default");
1941690Sdg    else if (!mask)
1954Srgrimes      strcpy(buf, inet_ntoa(ihost->sin_addr));
1961690Sdg    else {
1971690Sdg      u_int msk = ntohl(mask->sin_addr.s_addr);
1981690Sdg      u_int tst;
1991690Sdg      int bits;
2001690Sdg      int len;
2011690Sdg      struct sockaddr_in net;
2021690Sdg
2031690Sdg      for (tst = 1, bits=32; tst; tst <<= 1, bits--)
2044Srgrimes        if (msk & tst)
2051690Sdg          break;
2061690Sdg
2071690Sdg      for (tst <<=1; tst; tst <<= 1)
2085603Sbde        if (!(msk & tst))
2095603Sbde          break;
2105603Sbde
2111690Sdg      net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
2121690Sdg      strcpy(buf, inet_ntoa(net.sin_addr));
2131690Sdg      for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
2144Srgrimes        if (strcmp(buf+len-2, ".0"))
2151690Sdg          break;
2161690Sdg
2174014Sbde      if (tst)    /* non-contiguous :-( */
2184014Sbde        sprintf(buf+strlen(buf),"&0x%08x", msk);
2191690Sdg      else
2201690Sdg        sprintf(buf+strlen(buf), "/%d", bits);
2214Srgrimes    }
2221690Sdg    break;
2231690Sdg
2244Srgrimes  case AF_LINK:
2251690Sdg    if (dl->sdl_nlen)
2261690Sdg      snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
2271690Sdg    else if (dl->sdl_alen) {
2281690Sdg      if (dl->sdl_type == IFT_ETHER) {
2294Srgrimes        if (dl->sdl_alen < sizeof buf / 3) {
2301690Sdg          int f;
2311690Sdg          u_char *MAC;
2322320Sdg
2331690Sdg          MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
2341690Sdg          for (f = 0; f < dl->sdl_alen; f++)
2351690Sdg            sprintf(buf+f*3, "%02x:", MAC[f]);
2361690Sdg          buf[f*3-1] = '\0';
2371690Sdg        } else
2381690Sdg	  strcpy(buf, "??:??:??:??:??:??");
2391690Sdg      } else
2402001Swollman        sprintf(buf, "<IFT type %d>", dl->sdl_type);
2411690Sdg    } else if (dl->sdl_slen)
2424Srgrimes      sprintf(buf, "<slen %d?>", dl->sdl_slen);
2431690Sdg    else
2441690Sdg      sprintf(buf, "link#%d", dl->sdl_index);
2451690Sdg    break;
2461690Sdg
2474Srgrimes  default:
2481690Sdg    sprintf(buf, "<AF type %d>", phost->sa_family);
2491690Sdg    break;
2501690Sdg  }
2511690Sdg
2524Srgrimes  fprintf(VarTerm, "%-*s ", width-1, buf);
2531690Sdg}
2541690Sdg
2551690Sdgstatic struct bits {
2561690Sdg  u_long b_mask;
2571690Sdg  char b_val;
2581690Sdg} bits[] = {
2591127Sdg  { RTF_UP, 'U' },
2601690Sdg  { RTF_GATEWAY, 'G' },
2611690Sdg  { RTF_HOST, 'H' },
2625220Sbde  { RTF_REJECT, 'R' },
2635220Sbde  { RTF_DYNAMIC, 'D' },
2645220Sbde  { RTF_MODIFIED, 'M' },
2655220Sbde  { RTF_DONE, 'd' },
2665220Sbde  { RTF_CLONING, 'C' },
2675220Sbde  { RTF_XRESOLVE, 'X' },
2685220Sbde  { RTF_LLINFO, 'L' },
2691690Sdg  { RTF_STATIC, 'S' },
2705220Sbde  { RTF_PROTO1, '1' },
2715220Sbde  { RTF_PROTO2, '2' },
2721690Sdg  { RTF_BLACKHOLE, 'B' },
2731690Sdg#ifdef RTF_WASCLONED
274974Sdg  { RTF_WASCLONED, 'W' },
2751690Sdg#endif
2761690Sdg#ifdef RTF_PRCLONING
2771690Sdg  { RTF_PRCLONING, 'c' },
2781690Sdg#endif
279974Sdg#ifdef RTF_PROTO3
2801690Sdg  { RTF_PROTO3, '3' },
2811690Sdg#endif
282974Sdg#ifdef RTF_BROADCAST
2831690Sdg  { RTF_BROADCAST, 'b' },
2841690Sdg#endif
2851690Sdg  { 0, '\0' }
2861690Sdg};
2874Srgrimes
2881690Sdg#ifndef RTF_WASCLONED
2891690Sdg#define RTF_WASCLONED (0)
2905603Sbde#endif
2915603Sbde
2925603Sbdestatic void
2935603Sbdep_flags(u_long f, int max)
2945603Sbde{
2955603Sbde  if (VarTerm) {
2965603Sbde    char name[33], *flags;
2975603Sbde    register struct bits *p = bits;
2985603Sbde
2995603Sbde    if (max > sizeof name - 1)
3005603Sbde      max = sizeof name - 1;
3015603Sbde
3025603Sbde    for (flags = name; p->b_mask && flags - name < max; p++)
3035603Sbde      if (p->b_mask & f)
3045603Sbde	*flags++ = p->b_val;
3055603Sbde    *flags = '\0';
3065603Sbde    fprintf(VarTerm, "%-*.*s", max, max, name);
3075603Sbde  }
3085603Sbde}
3095603Sbde
3105603Sbdeconst char *
3115603SbdeIndex2Nam(int idx)
3125603Sbde{
3135603Sbde  static char **ifs;
3145603Sbde  static int nifs, debug_done;
3155603Sbde
3165603Sbde  if (!nifs) {
3175603Sbde    int mib[6], have, had;
3181690Sdg    size_t needed;
3191690Sdg    char *buf, *ptr, *end;
3201690Sdg    struct sockaddr_dl *dl;
321849Sdg    struct if_msghdr *ifm;
3221690Sdg
3234Srgrimes    mib[0] = CTL_NET;
3245603Sbde    mib[1] = PF_ROUTE;
3255603Sbde    mib[2] = 0;
3265603Sbde    mib[3] = 0;
3275603Sbde    mib[4] = NET_RT_IFLIST;
3285603Sbde    mib[5] = 0;
3295603Sbde
3305603Sbde    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
3315603Sbde      LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
3325603Sbde      return "???";
3335603Sbde    }
3345603Sbde    if ((buf = malloc(needed)) == NULL)
3355603Sbde      return "???";
3365603Sbde    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
3375603Sbde      free(buf);
3385603Sbde      return "???";
3395603Sbde    }
3402320Sdg    end = buf + needed;
3411690Sdg
3421690Sdg    have = 0;
3431690Sdg    for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
3444Srgrimes      ifm = (struct if_msghdr *)ptr;
3451690Sdg      dl = (struct sockaddr_dl *)(ifm + 1);
3461690Sdg      if (ifm->ifm_index > 0) {
3471690Sdg        if (ifm->ifm_index > have) {
3484Srgrimes          had = have;
3491690Sdg          have = ifm->ifm_index + 5;
3501690Sdg          if (had)
3514Srgrimes            ifs = (char **)realloc(ifs, sizeof(char *) * have);
3524Srgrimes          else
3531072Sdg            ifs = (char **)malloc(sizeof(char *) * have);
3541690Sdg          if (!ifs) {
3552320Sdg            LogPrintf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
3561690Sdg            nifs = 0;
3571690Sdg            return "???";
3581342Sdg          }
3591342Sdg          memset(ifs + had, '\0', sizeof(char *) * (have - had));
3601342Sdg        }
3611690Sdg        if (ifs[ifm->ifm_index-1] == NULL) {
3621690Sdg          ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
3631690Sdg          memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
3641690Sdg          ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
3651072Sdg          if (nifs < ifm->ifm_index)
3661072Sdg            nifs = ifm->ifm_index;
3671690Sdg        }
3684014Sbde      } else if (LogIsKept(LogDEBUG))
3694Srgrimes        LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n",
3704Srgrimes                  ifm->ifm_index);
3714Srgrimes    }
3721342Sdg    free(buf);
3731342Sdg  }
3741690Sdg
3751690Sdg  if (LogIsKept(LogDEBUG) && !debug_done) {
3761342Sdg    int f;
3771690Sdg
3781690Sdg    LogPrintf(LogDEBUG, "Found the following interfaces:\n");
3791342Sdg    for (f = 0; f < nifs; f++)
3801342Sdg      if (ifs[f] != NULL)
3811342Sdg        LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
3821342Sdg    debug_done = 1;
3831342Sdg  }
3844Srgrimes
3851690Sdg  if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
3861690Sdg    return "???";
3871690Sdg
3881690Sdg  return ifs[idx-1];
3891690Sdg}
3901690Sdg
3911690Sdgint
3921690SdgShowRoute(struct cmdargs const *arg)
3931690Sdg{
3942660Sdg  struct rt_msghdr *rtm;
3951690Sdg  struct sockaddr *sa_dst, *sa_gw, *sa_mask;
3963436Sphk  char *sp, *ep, *cp, *wp;
3971690Sdg  size_t needed;
3981690Sdg  int mib[6];
3991690Sdg
4001690Sdg  if (!VarTerm)
4011690Sdg    return 1;
4021690Sdg
4031690Sdg  mib[0] = CTL_NET;
4041690Sdg  mib[1] = PF_ROUTE;
4052660Sdg  mib[2] = 0;
4062660Sdg  mib[3] = 0;
4072660Sdg  mib[4] = NET_RT_DUMP;
4082660Sdg  mib[5] = 0;
4092660Sdg  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
4102660Sdg    LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
4111690Sdg    return (1);
4121690Sdg  }
4131690Sdg  if (needed < 0)
4142660Sdg    return (1);
4152660Sdg  sp = malloc(needed);
4162660Sdg  if (sp == NULL)
4172660Sdg    return (1);
4182660Sdg  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
4192660Sdg    LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
4202660Sdg    free(sp);
4212660Sdg    return (1);
4222660Sdg  }
4232660Sdg  ep = sp + needed;
4242660Sdg
4251690Sdg  fprintf(VarTerm, "%-20s%-20sFlags  Netif\n", "Destination", "Gateway");
4261690Sdg  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
4271690Sdg    rtm = (struct rt_msghdr *) cp;
4281690Sdg    wp = (char *)(rtm+1);
4291690Sdg
4301690Sdg    if (rtm->rtm_addrs & RTA_DST) {
4311690Sdg      sa_dst = (struct sockaddr *)wp;
4321690Sdg      wp += sa_dst->sa_len;
4331690Sdg    } else
4341690Sdg      sa_dst = NULL;
4351690Sdg
4361690Sdg    if (rtm->rtm_addrs & RTA_GATEWAY) {
4374Srgrimes      sa_gw = (struct sockaddr *)wp;
4381690Sdg      wp += sa_gw->sa_len;
4391690Sdg    } else
4404Srgrimes      sa_gw = NULL;
4411690Sdg
4421690Sdg    if (rtm->rtm_addrs & RTA_NETMASK) {
4431690Sdg      sa_mask = (struct sockaddr *)wp;
4441690Sdg      wp += sa_mask->sa_len;
4451690Sdg    } else
4461690Sdg      sa_mask = NULL;
4471690Sdg
4481690Sdg    p_sockaddr(sa_dst, sa_mask, 20);
4491690Sdg    p_sockaddr(sa_gw, NULL, 20);
4501690Sdg
4511690Sdg    p_flags(rtm->rtm_flags, 6);
4521690Sdg    fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index));
4531690Sdg  }
4541690Sdg  free(sp);
4551690Sdg  return 0;
4561690Sdg}
4571690Sdg
4581690Sdg/*
4591690Sdg *  Delete routes associated with our interface
4601690Sdg */
4611690Sdgvoid
4621690SdgDeleteIfRoutes(int all)
4631690Sdg{
4641690Sdg  struct rt_msghdr *rtm;
4651690Sdg  struct sockaddr *sa;
4661690Sdg  struct in_addr sa_dst, sa_none;
4671690Sdg  int pass;
4681690Sdg  size_t needed;
4691690Sdg  char *sp, *cp, *ep;
4701690Sdg  int mib[6];
4711690Sdg
4721690Sdg  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
4731690Sdg  sa_none.s_addr = INADDR_ANY;
4741690Sdg
4751690Sdg  mib[0] = CTL_NET;
4761690Sdg  mib[1] = PF_ROUTE;
4771690Sdg  mib[2] = 0;
4781690Sdg  mib[3] = 0;
4791690Sdg  mib[4] = NET_RT_DUMP;
4801690Sdg  mib[5] = 0;
4811690Sdg  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
4821690Sdg    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
4831690Sdg	      strerror(errno));
4841690Sdg    return;
4851690Sdg  }
4861690Sdg  if (needed < 0)
4871690Sdg    return;
4881690Sdg
4894Srgrimes  sp = malloc(needed);
4904Srgrimes  if (sp == NULL)
4911690Sdg    return;
4921690Sdg
4931690Sdg  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
4941690Sdg    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
4952660Sdg	      strerror(errno));
4961690Sdg    free(sp);
4971690Sdg    return;
4984Srgrimes  }
4991690Sdg  ep = sp + needed;
5004014Sbde
5014Srgrimes  for (pass = 0; pass < 2; pass++) {
5021690Sdg    /*
5031690Sdg     * We do 2 passes.  The first deletes all cloned routes.  The second
5041690Sdg     * deletes all non-cloned routes.  This is necessary to avoid
5051690Sdg     * potential errors from trying to delete route X after route Y where
5061690Sdg     * route X was cloned from route Y (which is no longer there).
5074Srgrimes     */
5084Srgrimes    if (RTF_WASCLONED == 0 && pass == 0)
5091690Sdg      /* So we can't tell ! */
5101690Sdg      continue;
5111690Sdg    for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
5121690Sdg      rtm = (struct rt_msghdr *) cp;
5131690Sdg      sa = (struct sockaddr *) (rtm + 1);
5143258Sdg      LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s),"
5151690Sdg                " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
5161690Sdg                Index2Nam(rtm->rtm_index), rtm->rtm_flags,
5171690Sdg	        inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
5181690Sdg      if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
5194014Sbde	  rtm->rtm_index == IfIndex &&
5201690Sdg	  (all || (rtm->rtm_flags & RTF_GATEWAY))) {
5211690Sdg        sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
5221690Sdg        sa = (struct sockaddr *)((char *)sa + sa->sa_len);
5231690Sdg        if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
5241690Sdg          if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
5251690Sdg              (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
5261690Sdg            LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass);
5271690Sdg            OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none, 0);
5281690Sdg          } else
5291690Sdg            LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass);
5301690Sdg        } else
5311690Sdg          LogPrintf(LogDEBUG,
5323258Sdg                    "DeleteIfRoutes: Can't remove routes of %d family !\n",
5333258Sdg                    sa->sa_family);
5343258Sdg      }
5353258Sdg    }
5363258Sdg  }
5371690Sdg  free(sp);
5382578Sbde}
5391690Sdg
5402578Sbdeint
5411690SdgGetIfIndex(char *name)
5422578Sbde{
5431690Sdg  int idx;
5442578Sbde  const char *got;
5451690Sdg
5462578Sbde  idx = 1;
5471690Sdg  while (strcmp(got = Index2Nam(idx), "???"))
5482578Sbde    if (!strcmp(got, name))
5491690Sdg      return IfIndex = idx;
5501690Sdg    else
5513436Sphk      idx++;
5523436Sphk  return -1;
5531690Sdg}
5541690Sdg
5551690Sdgstruct in_addr
5561690SdgChooseHisAddr(const struct in_addr gw)
5571690Sdg{
5581690Sdg  struct in_addr try;
5591690Sdg  int f;
5601690Sdg
5611690Sdg  for (f = 0; f < DefHisChoice.nItems; f++) {
5621690Sdg    try = iplist_next(&DefHisChoice);
5631690Sdg    LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
5641690Sdg              f, inet_ntoa(try));
5651690Sdg    if (OsTrySetIpaddress(gw, try) == 0) {
5661690Sdg      LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
5671690Sdg                inet_ntoa(try));
5681690Sdg      break;
5691690Sdg    }
5701690Sdg  }
5711690Sdg
5722320Sdg  if (f == DefHisChoice.nItems) {
5731690Sdg    LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
5741690Sdg    try.s_addr = INADDR_ANY;
5751690Sdg  }
5761690Sdg
5771690Sdg  return try;
5781690Sdg}
5791690Sdg