xref: /freebsd/usr.sbin/ppp/route.c (revision 8c07a7b2e0d7046e042a0c38fb62f75013bcf072)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *	      PPP Routing related Module
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan, Inc.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
208c07a7b2SBrian Somers  * $Id: route.c,v 1.42.2.1 1998/01/29 23:11:42 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  */
231ae349f5Scvs2svn 
241ae349f5Scvs2svn #include <sys/param.h>
251ae349f5Scvs2svn #include <sys/time.h>
261ae349f5Scvs2svn #include <sys/socket.h>
271ae349f5Scvs2svn #include <net/if_types.h>
281ae349f5Scvs2svn #include <net/route.h>
291ae349f5Scvs2svn #include <net/if.h>
301ae349f5Scvs2svn #include <netinet/in.h>
311ae349f5Scvs2svn #include <arpa/inet.h>
321ae349f5Scvs2svn #include <net/if_dl.h>
331ae349f5Scvs2svn 
341ae349f5Scvs2svn #include <errno.h>
351ae349f5Scvs2svn #include <machine/endian.h>
361ae349f5Scvs2svn #include <stdio.h>
371ae349f5Scvs2svn #include <stdlib.h>
381ae349f5Scvs2svn #include <string.h>
391ae349f5Scvs2svn #include <sys/ioctl.h>
401ae349f5Scvs2svn #include <sys/sysctl.h>
411ae349f5Scvs2svn #include <unistd.h>
421ae349f5Scvs2svn 
431ae349f5Scvs2svn #include "command.h"
441ae349f5Scvs2svn #include "mbuf.h"
451ae349f5Scvs2svn #include "log.h"
461ae349f5Scvs2svn #include "loadalias.h"
471ae349f5Scvs2svn #include "defs.h"
481ae349f5Scvs2svn #include "vars.h"
491ae349f5Scvs2svn #include "id.h"
501ae349f5Scvs2svn #include "os.h"
511ae349f5Scvs2svn #include "iplist.h"
5229e275ceSBrian Somers #include "timer.h"
5329e275ceSBrian Somers #include "throughput.h"
548c07a7b2SBrian Somers #include "hdlc.h"
558c07a7b2SBrian Somers #include "link.h"
5629e275ceSBrian Somers #include "ipcp.h"
571ae349f5Scvs2svn #include "route.h"
581ae349f5Scvs2svn 
591ae349f5Scvs2svn static int IfIndex;
601ae349f5Scvs2svn 
611ae349f5Scvs2svn struct rtmsg {
621ae349f5Scvs2svn   struct rt_msghdr m_rtm;
631ae349f5Scvs2svn   char m_space[64];
641ae349f5Scvs2svn };
651ae349f5Scvs2svn 
661ae349f5Scvs2svn static int seqno;
671ae349f5Scvs2svn 
681ae349f5Scvs2svn void
691ae349f5Scvs2svn OsSetRoute(int cmd,
701ae349f5Scvs2svn 	   struct in_addr dst,
711ae349f5Scvs2svn 	   struct in_addr gateway,
721ae349f5Scvs2svn 	   struct in_addr mask,
731ae349f5Scvs2svn 	   int bang)
741ae349f5Scvs2svn {
751ae349f5Scvs2svn   struct rtmsg rtmes;
761ae349f5Scvs2svn   int s, nb, wb;
771ae349f5Scvs2svn   char *cp;
781ae349f5Scvs2svn   const char *cmdstr;
791ae349f5Scvs2svn   struct sockaddr_in rtdata;
801ae349f5Scvs2svn 
811ae349f5Scvs2svn   if (bang)
821ae349f5Scvs2svn     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
831ae349f5Scvs2svn   else
841ae349f5Scvs2svn     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
851ae349f5Scvs2svn   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
861ae349f5Scvs2svn   if (s < 0) {
871ae349f5Scvs2svn     LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
881ae349f5Scvs2svn     return;
891ae349f5Scvs2svn   }
901ae349f5Scvs2svn   memset(&rtmes, '\0', sizeof rtmes);
911ae349f5Scvs2svn   rtmes.m_rtm.rtm_version = RTM_VERSION;
921ae349f5Scvs2svn   rtmes.m_rtm.rtm_type = cmd;
931ae349f5Scvs2svn   rtmes.m_rtm.rtm_addrs = RTA_DST;
941ae349f5Scvs2svn   rtmes.m_rtm.rtm_seq = ++seqno;
951ae349f5Scvs2svn   rtmes.m_rtm.rtm_pid = getpid();
961ae349f5Scvs2svn   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
971ae349f5Scvs2svn 
981ae349f5Scvs2svn   memset(&rtdata, '\0', sizeof rtdata);
991ae349f5Scvs2svn   rtdata.sin_len = 16;
1001ae349f5Scvs2svn   rtdata.sin_family = AF_INET;
1011ae349f5Scvs2svn   rtdata.sin_port = 0;
1021ae349f5Scvs2svn   rtdata.sin_addr = dst;
1031ae349f5Scvs2svn 
1041ae349f5Scvs2svn   cp = rtmes.m_space;
1051ae349f5Scvs2svn   memcpy(cp, &rtdata, 16);
1061ae349f5Scvs2svn   cp += 16;
1071ae349f5Scvs2svn   if (cmd == RTM_ADD)
1081ae349f5Scvs2svn     if (gateway.s_addr == INADDR_ANY) {
1091ae349f5Scvs2svn       /* Add a route through the interface */
1101ae349f5Scvs2svn       struct sockaddr_dl dl;
1111ae349f5Scvs2svn       const char *iname;
1121ae349f5Scvs2svn       int ilen;
1131ae349f5Scvs2svn 
1141ae349f5Scvs2svn       iname = Index2Nam(IfIndex);
1151ae349f5Scvs2svn       ilen = strlen(iname);
1161ae349f5Scvs2svn       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
1171ae349f5Scvs2svn       dl.sdl_family = AF_LINK;
1181ae349f5Scvs2svn       dl.sdl_index = IfIndex;
1191ae349f5Scvs2svn       dl.sdl_type = 0;
1201ae349f5Scvs2svn       dl.sdl_nlen = ilen;
1211ae349f5Scvs2svn       dl.sdl_alen = 0;
1221ae349f5Scvs2svn       dl.sdl_slen = 0;
1231ae349f5Scvs2svn       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
1241ae349f5Scvs2svn 
1251ae349f5Scvs2svn       memcpy(cp, &dl, dl.sdl_len);
1261ae349f5Scvs2svn       cp += dl.sdl_len;
1271ae349f5Scvs2svn       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
1281ae349f5Scvs2svn     } else {
1291ae349f5Scvs2svn       rtdata.sin_addr = gateway;
1301ae349f5Scvs2svn       memcpy(cp, &rtdata, 16);
1311ae349f5Scvs2svn       cp += 16;
1321ae349f5Scvs2svn       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
1331ae349f5Scvs2svn     }
1341ae349f5Scvs2svn 
1351ae349f5Scvs2svn   if (dst.s_addr == INADDR_ANY)
1361ae349f5Scvs2svn     mask.s_addr = INADDR_ANY;
1371ae349f5Scvs2svn 
1381ae349f5Scvs2svn   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
1391ae349f5Scvs2svn     rtdata.sin_addr = mask;
1401ae349f5Scvs2svn     memcpy(cp, &rtdata, 16);
1411ae349f5Scvs2svn     cp += 16;
1421ae349f5Scvs2svn     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
1431ae349f5Scvs2svn   }
1441ae349f5Scvs2svn 
1451ae349f5Scvs2svn   nb = cp - (char *) &rtmes;
1461ae349f5Scvs2svn   rtmes.m_rtm.rtm_msglen = nb;
1471ae349f5Scvs2svn   wb = ID0write(s, &rtmes, nb);
1481ae349f5Scvs2svn   if (wb < 0) {
1491ae349f5Scvs2svn     LogPrintf(LogTCPIP, "OsSetRoute failure:\n");
1501ae349f5Scvs2svn     LogPrintf(LogTCPIP, "OsSetRoute:  Cmd = %s\n", cmd);
1511ae349f5Scvs2svn     LogPrintf(LogTCPIP, "OsSetRoute:  Dst = %s\n", inet_ntoa(dst));
1521ae349f5Scvs2svn     LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
1531ae349f5Scvs2svn     LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
1541ae349f5Scvs2svn failed:
1551ae349f5Scvs2svn     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
1561ae349f5Scvs2svn                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST)))
1571ae349f5Scvs2svn       if (!bang)
1581ae349f5Scvs2svn         LogPrintf(LogWARN, "Add route failed: %s already exists\n",
1591ae349f5Scvs2svn                   inet_ntoa(dst));
1601ae349f5Scvs2svn       else {
1611ae349f5Scvs2svn         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
1621ae349f5Scvs2svn         if ((wb = ID0write(s, &rtmes, nb)) < 0)
1631ae349f5Scvs2svn           goto failed;
1641ae349f5Scvs2svn       }
1651ae349f5Scvs2svn     else if (cmd == RTM_DELETE &&
1661ae349f5Scvs2svn              (rtmes.m_rtm.rtm_errno == ESRCH ||
1671ae349f5Scvs2svn               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
1681ae349f5Scvs2svn       if (!bang)
1691ae349f5Scvs2svn         LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n",
1701ae349f5Scvs2svn                   inet_ntoa(dst));
1711ae349f5Scvs2svn     } else if (rtmes.m_rtm.rtm_errno == 0)
1721ae349f5Scvs2svn       LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
1731ae349f5Scvs2svn                 inet_ntoa(dst), strerror(errno));
1741ae349f5Scvs2svn     else
1751ae349f5Scvs2svn       LogPrintf(LogWARN, "%s route failed: %s: %s\n",
1761ae349f5Scvs2svn 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
1771ae349f5Scvs2svn   }
1781ae349f5Scvs2svn   LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
1791ae349f5Scvs2svn             wb, cmdstr, dst.s_addr, gateway.s_addr);
1801ae349f5Scvs2svn   close(s);
1811ae349f5Scvs2svn }
1821ae349f5Scvs2svn 
1831ae349f5Scvs2svn static void
1841ae349f5Scvs2svn p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width)
1851ae349f5Scvs2svn {
1861ae349f5Scvs2svn   char buf[29];
1871ae349f5Scvs2svn   struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
1881ae349f5Scvs2svn   struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
1891ae349f5Scvs2svn   struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
1901ae349f5Scvs2svn 
1911ae349f5Scvs2svn   switch (phost->sa_family) {
1921ae349f5Scvs2svn   case AF_INET:
1931ae349f5Scvs2svn     if (!phost)
1941ae349f5Scvs2svn       buf[0] = '\0';
1951ae349f5Scvs2svn     else if (ihost->sin_addr.s_addr == INADDR_ANY)
1961ae349f5Scvs2svn       strcpy(buf, "default");
1971ae349f5Scvs2svn     else if (!mask)
1981ae349f5Scvs2svn       strcpy(buf, inet_ntoa(ihost->sin_addr));
1991ae349f5Scvs2svn     else {
2001ae349f5Scvs2svn       u_int msk = ntohl(mask->sin_addr.s_addr);
2011ae349f5Scvs2svn       u_int tst;
2021ae349f5Scvs2svn       int bits;
2031ae349f5Scvs2svn       int len;
2041ae349f5Scvs2svn       struct sockaddr_in net;
2051ae349f5Scvs2svn 
2061ae349f5Scvs2svn       for (tst = 1, bits=32; tst; tst <<= 1, bits--)
2071ae349f5Scvs2svn         if (msk & tst)
2081ae349f5Scvs2svn           break;
2091ae349f5Scvs2svn 
2101ae349f5Scvs2svn       for (tst <<=1; tst; tst <<= 1)
2111ae349f5Scvs2svn         if (!(msk & tst))
2121ae349f5Scvs2svn           break;
2131ae349f5Scvs2svn 
2141ae349f5Scvs2svn       net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
2151ae349f5Scvs2svn       strcpy(buf, inet_ntoa(net.sin_addr));
2161ae349f5Scvs2svn       for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
2171ae349f5Scvs2svn         if (strcmp(buf+len-2, ".0"))
2181ae349f5Scvs2svn           break;
2191ae349f5Scvs2svn 
2201ae349f5Scvs2svn       if (tst)    /* non-contiguous :-( */
2211ae349f5Scvs2svn         sprintf(buf+strlen(buf),"&0x%08x", msk);
2221ae349f5Scvs2svn       else
2231ae349f5Scvs2svn         sprintf(buf+strlen(buf), "/%d", bits);
2241ae349f5Scvs2svn     }
2251ae349f5Scvs2svn     break;
2261ae349f5Scvs2svn 
2271ae349f5Scvs2svn   case AF_LINK:
2281ae349f5Scvs2svn     if (dl->sdl_nlen)
2291ae349f5Scvs2svn       snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
2301ae349f5Scvs2svn     else if (dl->sdl_alen)
2311ae349f5Scvs2svn       if (dl->sdl_type == IFT_ETHER)
2321ae349f5Scvs2svn         if (dl->sdl_alen < sizeof buf / 3) {
2331ae349f5Scvs2svn           int f;
2341ae349f5Scvs2svn           u_char *MAC;
2351ae349f5Scvs2svn 
2361ae349f5Scvs2svn           MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
2371ae349f5Scvs2svn           for (f = 0; f < dl->sdl_alen; f++)
2381ae349f5Scvs2svn             sprintf(buf+f*3, "%02x:", MAC[f]);
2391ae349f5Scvs2svn           buf[f*3-1] = '\0';
2401ae349f5Scvs2svn         } else
2411ae349f5Scvs2svn 	  strcpy(buf, "??:??:??:??:??:??");
2421ae349f5Scvs2svn       else
2431ae349f5Scvs2svn         sprintf(buf, "<IFT type %d>", dl->sdl_type);
2441ae349f5Scvs2svn     else if (dl->sdl_slen)
2451ae349f5Scvs2svn       sprintf(buf, "<slen %d?>", dl->sdl_slen);
2461ae349f5Scvs2svn     else
2471ae349f5Scvs2svn       sprintf(buf, "link#%d", dl->sdl_index);
2481ae349f5Scvs2svn     break;
2491ae349f5Scvs2svn 
2501ae349f5Scvs2svn   default:
2511ae349f5Scvs2svn     sprintf(buf, "<AF type %d>", phost->sa_family);
2521ae349f5Scvs2svn     break;
2531ae349f5Scvs2svn   }
2541ae349f5Scvs2svn 
2551ae349f5Scvs2svn   fprintf(VarTerm, "%-*s ", width-1, buf);
2561ae349f5Scvs2svn }
2571ae349f5Scvs2svn 
2581ae349f5Scvs2svn static struct bits {
2591ae349f5Scvs2svn   u_long b_mask;
2601ae349f5Scvs2svn   char b_val;
2611ae349f5Scvs2svn } bits[] = {
2621ae349f5Scvs2svn   { RTF_UP, 'U' },
2631ae349f5Scvs2svn   { RTF_GATEWAY, 'G' },
2641ae349f5Scvs2svn   { RTF_HOST, 'H' },
2651ae349f5Scvs2svn   { RTF_REJECT, 'R' },
2661ae349f5Scvs2svn   { RTF_DYNAMIC, 'D' },
2671ae349f5Scvs2svn   { RTF_MODIFIED, 'M' },
2681ae349f5Scvs2svn   { RTF_DONE, 'd' },
2691ae349f5Scvs2svn   { RTF_CLONING, 'C' },
2701ae349f5Scvs2svn   { RTF_XRESOLVE, 'X' },
2711ae349f5Scvs2svn   { RTF_LLINFO, 'L' },
2721ae349f5Scvs2svn   { RTF_STATIC, 'S' },
2731ae349f5Scvs2svn   { RTF_PROTO1, '1' },
2741ae349f5Scvs2svn   { RTF_PROTO2, '2' },
2751ae349f5Scvs2svn   { RTF_BLACKHOLE, 'B' },
2761ae349f5Scvs2svn #ifdef RTF_WASCLONED
2771ae349f5Scvs2svn   { RTF_WASCLONED, 'W' },
2781ae349f5Scvs2svn #endif
2791ae349f5Scvs2svn #ifdef RTF_PRCLONING
2801ae349f5Scvs2svn   { RTF_PRCLONING, 'c' },
2811ae349f5Scvs2svn #endif
2821ae349f5Scvs2svn #ifdef RTF_PROTO3
2831ae349f5Scvs2svn   { RTF_PROTO3, '3' },
2841ae349f5Scvs2svn #endif
2851ae349f5Scvs2svn #ifdef RTF_BROADCAST
2861ae349f5Scvs2svn   { RTF_BROADCAST, 'b' },
2871ae349f5Scvs2svn #endif
2881ae349f5Scvs2svn   { 0, '\0' }
2891ae349f5Scvs2svn };
2901ae349f5Scvs2svn 
2911ae349f5Scvs2svn #ifndef RTF_WASCLONED
2921ae349f5Scvs2svn #define RTF_WASCLONED (0)
2931ae349f5Scvs2svn #endif
2941ae349f5Scvs2svn 
2951ae349f5Scvs2svn static void
2961ae349f5Scvs2svn p_flags(u_long f, int max)
2971ae349f5Scvs2svn {
2981ae349f5Scvs2svn   if (VarTerm) {
2991ae349f5Scvs2svn     char name[33], *flags;
3001ae349f5Scvs2svn     register struct bits *p = bits;
3011ae349f5Scvs2svn 
3021ae349f5Scvs2svn     if (max > sizeof name - 1)
3031ae349f5Scvs2svn       max = sizeof name - 1;
3041ae349f5Scvs2svn 
3051ae349f5Scvs2svn     for (flags = name; p->b_mask && flags - name < max; p++)
3061ae349f5Scvs2svn       if (p->b_mask & f)
3071ae349f5Scvs2svn 	*flags++ = p->b_val;
3081ae349f5Scvs2svn     *flags = '\0';
3091ae349f5Scvs2svn     fprintf(VarTerm, "%-*.*s", max, max, name);
3101ae349f5Scvs2svn   }
3111ae349f5Scvs2svn }
3121ae349f5Scvs2svn 
3131ae349f5Scvs2svn const char *
3141ae349f5Scvs2svn Index2Nam(int idx)
3151ae349f5Scvs2svn {
3161ae349f5Scvs2svn   static char **ifs;
3171ae349f5Scvs2svn   static int nifs, debug_done;
3181ae349f5Scvs2svn 
3191ae349f5Scvs2svn   if (!nifs) {
3201ae349f5Scvs2svn     int mib[6], have, had;
3211ae349f5Scvs2svn     size_t needed;
3221ae349f5Scvs2svn     char *buf, *ptr, *end;
3231ae349f5Scvs2svn     struct sockaddr_dl *dl;
3241ae349f5Scvs2svn     struct if_msghdr *ifm;
3251ae349f5Scvs2svn 
3261ae349f5Scvs2svn     mib[0] = CTL_NET;
3271ae349f5Scvs2svn     mib[1] = PF_ROUTE;
3281ae349f5Scvs2svn     mib[2] = 0;
3291ae349f5Scvs2svn     mib[3] = 0;
3301ae349f5Scvs2svn     mib[4] = NET_RT_IFLIST;
3311ae349f5Scvs2svn     mib[5] = 0;
3321ae349f5Scvs2svn 
3331ae349f5Scvs2svn     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
3341ae349f5Scvs2svn       LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
3351ae349f5Scvs2svn       return "???";
3361ae349f5Scvs2svn     }
3371ae349f5Scvs2svn     if ((buf = malloc(needed)) == NULL)
3381ae349f5Scvs2svn       return "???";
3391ae349f5Scvs2svn     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
3401ae349f5Scvs2svn       free(buf);
3411ae349f5Scvs2svn       return "???";
3421ae349f5Scvs2svn     }
3431ae349f5Scvs2svn     end = buf + needed;
3441ae349f5Scvs2svn 
3451ae349f5Scvs2svn     have = 0;
3461ae349f5Scvs2svn     for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
3471ae349f5Scvs2svn       ifm = (struct if_msghdr *)ptr;
3481ae349f5Scvs2svn       dl = (struct sockaddr_dl *)(ifm + 1);
3491ae349f5Scvs2svn       if (ifm->ifm_index > 0) {
3501ae349f5Scvs2svn         if (ifm->ifm_index > have) {
3511ae349f5Scvs2svn           had = have;
3521ae349f5Scvs2svn           have = ifm->ifm_index + 5;
3531ae349f5Scvs2svn           if (had)
3541ae349f5Scvs2svn             ifs = (char **)realloc(ifs, sizeof(char *) * have);
3551ae349f5Scvs2svn           else
3561ae349f5Scvs2svn             ifs = (char **)malloc(sizeof(char *) * have);
3571ae349f5Scvs2svn           if (!ifs) {
3581ae349f5Scvs2svn             LogPrintf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
3591ae349f5Scvs2svn             nifs = 0;
3601ae349f5Scvs2svn             return "???";
3611ae349f5Scvs2svn           }
3621ae349f5Scvs2svn           memset(ifs + had, '\0', sizeof(char *) * (have - had));
3631ae349f5Scvs2svn         }
3641ae349f5Scvs2svn         if (ifs[ifm->ifm_index-1] == NULL) {
3651ae349f5Scvs2svn           ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
3661ae349f5Scvs2svn           memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
3671ae349f5Scvs2svn           ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
3681ae349f5Scvs2svn           if (nifs < ifm->ifm_index)
3691ae349f5Scvs2svn             nifs = ifm->ifm_index;
3701ae349f5Scvs2svn         }
3711ae349f5Scvs2svn       } else if (LogIsKept(LogDEBUG))
3721ae349f5Scvs2svn         LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n",
3731ae349f5Scvs2svn                   ifm->ifm_index);
3741ae349f5Scvs2svn     }
3751ae349f5Scvs2svn     free(buf);
3761ae349f5Scvs2svn   }
3771ae349f5Scvs2svn 
3781ae349f5Scvs2svn   if (LogIsKept(LogDEBUG) && !debug_done) {
3791ae349f5Scvs2svn     int f;
3801ae349f5Scvs2svn 
3811ae349f5Scvs2svn     LogPrintf(LogDEBUG, "Found the following interfaces:\n");
3821ae349f5Scvs2svn     for (f = 0; f < nifs; f++)
3831ae349f5Scvs2svn       if (ifs[f] != NULL)
3841ae349f5Scvs2svn         LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
3851ae349f5Scvs2svn     debug_done = 1;
3861ae349f5Scvs2svn   }
3871ae349f5Scvs2svn 
3881ae349f5Scvs2svn   if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
3891ae349f5Scvs2svn     return "???";
3901ae349f5Scvs2svn 
3911ae349f5Scvs2svn   return ifs[idx-1];
3921ae349f5Scvs2svn }
3931ae349f5Scvs2svn 
3941ae349f5Scvs2svn int
3951ae349f5Scvs2svn ShowRoute(struct cmdargs const *arg)
3961ae349f5Scvs2svn {
3971ae349f5Scvs2svn   struct rt_msghdr *rtm;
3981ae349f5Scvs2svn   struct sockaddr *sa_dst, *sa_gw, *sa_mask;
3991ae349f5Scvs2svn   char *sp, *ep, *cp, *wp;
4001ae349f5Scvs2svn   size_t needed;
4011ae349f5Scvs2svn   int mib[6];
4021ae349f5Scvs2svn 
4031ae349f5Scvs2svn   if (!VarTerm)
4041ae349f5Scvs2svn     return 1;
4051ae349f5Scvs2svn 
4061ae349f5Scvs2svn   mib[0] = CTL_NET;
4071ae349f5Scvs2svn   mib[1] = PF_ROUTE;
4081ae349f5Scvs2svn   mib[2] = 0;
4091ae349f5Scvs2svn   mib[3] = 0;
4101ae349f5Scvs2svn   mib[4] = NET_RT_DUMP;
4111ae349f5Scvs2svn   mib[5] = 0;
4121ae349f5Scvs2svn   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
4131ae349f5Scvs2svn     LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
4141ae349f5Scvs2svn     return (1);
4151ae349f5Scvs2svn   }
4161ae349f5Scvs2svn   if (needed < 0)
4171ae349f5Scvs2svn     return (1);
4181ae349f5Scvs2svn   sp = malloc(needed);
4191ae349f5Scvs2svn   if (sp == NULL)
4201ae349f5Scvs2svn     return (1);
4211ae349f5Scvs2svn   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
4221ae349f5Scvs2svn     LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
4231ae349f5Scvs2svn     free(sp);
4241ae349f5Scvs2svn     return (1);
4251ae349f5Scvs2svn   }
4261ae349f5Scvs2svn   ep = sp + needed;
4271ae349f5Scvs2svn 
4281ae349f5Scvs2svn   fprintf(VarTerm, "%-20s%-20sFlags  Netif\n", "Destination", "Gateway");
4291ae349f5Scvs2svn   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
4301ae349f5Scvs2svn     rtm = (struct rt_msghdr *) cp;
4311ae349f5Scvs2svn     wp = (char *)(rtm+1);
4321ae349f5Scvs2svn 
4331ae349f5Scvs2svn     if (rtm->rtm_addrs & RTA_DST) {
4341ae349f5Scvs2svn       sa_dst = (struct sockaddr *)wp;
4351ae349f5Scvs2svn       wp += sa_dst->sa_len;
4361ae349f5Scvs2svn     } else
4371ae349f5Scvs2svn       sa_dst = NULL;
4381ae349f5Scvs2svn 
4391ae349f5Scvs2svn     if (rtm->rtm_addrs & RTA_GATEWAY) {
4401ae349f5Scvs2svn       sa_gw = (struct sockaddr *)wp;
4411ae349f5Scvs2svn       wp += sa_gw->sa_len;
4421ae349f5Scvs2svn     } else
4431ae349f5Scvs2svn       sa_gw = NULL;
4441ae349f5Scvs2svn 
4451ae349f5Scvs2svn     if (rtm->rtm_addrs & RTA_NETMASK) {
4461ae349f5Scvs2svn       sa_mask = (struct sockaddr *)wp;
4471ae349f5Scvs2svn       wp += sa_mask->sa_len;
4481ae349f5Scvs2svn     } else
4491ae349f5Scvs2svn       sa_mask = NULL;
4501ae349f5Scvs2svn 
4511ae349f5Scvs2svn     p_sockaddr(sa_dst, sa_mask, 20);
4521ae349f5Scvs2svn     p_sockaddr(sa_gw, NULL, 20);
4531ae349f5Scvs2svn 
4541ae349f5Scvs2svn     p_flags(rtm->rtm_flags, 6);
4551ae349f5Scvs2svn     fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index));
4561ae349f5Scvs2svn   }
4571ae349f5Scvs2svn   free(sp);
4581ae349f5Scvs2svn   return 0;
4591ae349f5Scvs2svn }
4601ae349f5Scvs2svn 
4611ae349f5Scvs2svn /*
4621ae349f5Scvs2svn  *  Delete routes associated with our interface
4631ae349f5Scvs2svn  */
4641ae349f5Scvs2svn void
4651ae349f5Scvs2svn DeleteIfRoutes(int all)
4661ae349f5Scvs2svn {
4671ae349f5Scvs2svn   struct rt_msghdr *rtm;
4681ae349f5Scvs2svn   struct sockaddr *sa;
4691ae349f5Scvs2svn   struct in_addr sa_dst, sa_none;
4701ae349f5Scvs2svn   int pass;
4711ae349f5Scvs2svn   size_t needed;
4721ae349f5Scvs2svn   char *sp, *cp, *ep;
4731ae349f5Scvs2svn   int mib[6];
4741ae349f5Scvs2svn 
4751ae349f5Scvs2svn   LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
4761ae349f5Scvs2svn   sa_none.s_addr = INADDR_ANY;
4771ae349f5Scvs2svn 
4781ae349f5Scvs2svn   mib[0] = CTL_NET;
4791ae349f5Scvs2svn   mib[1] = PF_ROUTE;
4801ae349f5Scvs2svn   mib[2] = 0;
4811ae349f5Scvs2svn   mib[3] = 0;
4821ae349f5Scvs2svn   mib[4] = NET_RT_DUMP;
4831ae349f5Scvs2svn   mib[5] = 0;
4841ae349f5Scvs2svn   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
4851ae349f5Scvs2svn     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
4861ae349f5Scvs2svn 	      strerror(errno));
4871ae349f5Scvs2svn     return;
4881ae349f5Scvs2svn   }
4891ae349f5Scvs2svn   if (needed < 0)
4901ae349f5Scvs2svn     return;
4911ae349f5Scvs2svn 
4921ae349f5Scvs2svn   sp = malloc(needed);
4931ae349f5Scvs2svn   if (sp == NULL)
4941ae349f5Scvs2svn     return;
4951ae349f5Scvs2svn 
4961ae349f5Scvs2svn   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
4971ae349f5Scvs2svn     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
4981ae349f5Scvs2svn 	      strerror(errno));
4991ae349f5Scvs2svn     free(sp);
5001ae349f5Scvs2svn     return;
5011ae349f5Scvs2svn   }
5021ae349f5Scvs2svn   ep = sp + needed;
5031ae349f5Scvs2svn 
5041ae349f5Scvs2svn   for (pass = 0; pass < 2; pass++) {
5051ae349f5Scvs2svn     /*
5061ae349f5Scvs2svn      * We do 2 passes.  The first deletes all cloned routes.  The second
5071ae349f5Scvs2svn      * deletes all non-cloned routes.  This is necessary to avoid
5081ae349f5Scvs2svn      * potential errors from trying to delete route X after route Y where
5091ae349f5Scvs2svn      * route X was cloned from route Y (which is no longer there).
5101ae349f5Scvs2svn      */
5111ae349f5Scvs2svn     if (RTF_WASCLONED == 0 && pass == 0)
5121ae349f5Scvs2svn       /* So we can't tell ! */
5131ae349f5Scvs2svn       continue;
5141ae349f5Scvs2svn     for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
5151ae349f5Scvs2svn       rtm = (struct rt_msghdr *) cp;
5161ae349f5Scvs2svn       sa = (struct sockaddr *) (rtm + 1);
5171ae349f5Scvs2svn       LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s),"
5181ae349f5Scvs2svn                 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
5191ae349f5Scvs2svn                 Index2Nam(rtm->rtm_index), rtm->rtm_flags,
5201ae349f5Scvs2svn 	        inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
5211ae349f5Scvs2svn       if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
5221ae349f5Scvs2svn 	  rtm->rtm_index == IfIndex &&
5231ae349f5Scvs2svn 	  (all || (rtm->rtm_flags & RTF_GATEWAY))) {
5241ae349f5Scvs2svn         sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
5251ae349f5Scvs2svn         sa = (struct sockaddr *)((char *)sa + sa->sa_len);
5261ae349f5Scvs2svn         if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
5271ae349f5Scvs2svn           if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
5281ae349f5Scvs2svn               (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
5291ae349f5Scvs2svn             LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass);
5301ae349f5Scvs2svn             OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none, 0);
5311ae349f5Scvs2svn           } else
5321ae349f5Scvs2svn             LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass);
5331ae349f5Scvs2svn         } else
5341ae349f5Scvs2svn           LogPrintf(LogDEBUG,
5351ae349f5Scvs2svn                     "DeleteIfRoutes: Can't remove routes of %d family !\n",
5361ae349f5Scvs2svn                     sa->sa_family);
5371ae349f5Scvs2svn       }
5381ae349f5Scvs2svn     }
5391ae349f5Scvs2svn   }
5401ae349f5Scvs2svn   free(sp);
5411ae349f5Scvs2svn }
5421ae349f5Scvs2svn 
5431ae349f5Scvs2svn int
5441ae349f5Scvs2svn GetIfIndex(char *name)
5451ae349f5Scvs2svn {
5461ae349f5Scvs2svn   int idx;
5471ae349f5Scvs2svn   const char *got;
5481ae349f5Scvs2svn 
5491ae349f5Scvs2svn   idx = 1;
5501ae349f5Scvs2svn   while (strcmp(got = Index2Nam(idx), "???"))
5511ae349f5Scvs2svn     if (!strcmp(got, name))
5521ae349f5Scvs2svn       return IfIndex = idx;
5531ae349f5Scvs2svn     else
5541ae349f5Scvs2svn       idx++;
5551ae349f5Scvs2svn   return -1;
5561ae349f5Scvs2svn }
5571ae349f5Scvs2svn 
5581ae349f5Scvs2svn struct in_addr
5591ae349f5Scvs2svn ChooseHisAddr(const struct in_addr gw)
5601ae349f5Scvs2svn {
5611ae349f5Scvs2svn   struct in_addr try;
5621ae349f5Scvs2svn   int f;
5631ae349f5Scvs2svn 
56429e275ceSBrian Somers   for (f = 0; f < IpcpInfo.DefHisChoice.nItems; f++) {
56529e275ceSBrian Somers     try = iplist_next(&IpcpInfo.DefHisChoice);
5661ae349f5Scvs2svn     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
5671ae349f5Scvs2svn               f, inet_ntoa(try));
5681ae349f5Scvs2svn     if (OsTrySetIpaddress(gw, try) == 0) {
5691ae349f5Scvs2svn       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
5701ae349f5Scvs2svn                 inet_ntoa(try));
5711ae349f5Scvs2svn       break;
5721ae349f5Scvs2svn     }
5731ae349f5Scvs2svn   }
5741ae349f5Scvs2svn 
57529e275ceSBrian Somers   if (f == IpcpInfo.DefHisChoice.nItems) {
5761ae349f5Scvs2svn     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
5771ae349f5Scvs2svn     try.s_addr = INADDR_ANY;
5781ae349f5Scvs2svn   }
5791ae349f5Scvs2svn 
5801ae349f5Scvs2svn   return try;
5811ae349f5Scvs2svn }
582