xref: /freebsd/usr.sbin/ppp/route.c (revision aa8e05197cf50f96207ce5e9cc07395ca319f3e0)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *	      PPP Routing related Module
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan, Inc.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
20aa8e0519SBrian Somers  * $Id: route.c,v 1.41 1998/01/19 02:59:33 brian Exp $
2153c9f6c0SAtsushi Murai  *
22af57ed9fSAtsushi Murai  */
2375240ed1SBrian Somers 
24af57ed9fSAtsushi Murai #include <sys/param.h>
25628d2ac1SGarrett Wollman #include <sys/time.h>
2675240ed1SBrian Somers #include <sys/socket.h>
275d5e5070SBrian Somers #include <net/if_types.h>
28628d2ac1SGarrett Wollman #include <net/route.h>
29628d2ac1SGarrett Wollman #include <net/if.h>
30628d2ac1SGarrett Wollman #include <netinet/in.h>
31628d2ac1SGarrett Wollman #include <arpa/inet.h>
325d5e5070SBrian Somers #include <net/if_dl.h>
33628d2ac1SGarrett Wollman 
3475240ed1SBrian Somers #include <errno.h>
3575240ed1SBrian Somers #include <machine/endian.h>
3675240ed1SBrian Somers #include <stdio.h>
3775240ed1SBrian Somers #include <stdlib.h>
3875240ed1SBrian Somers #include <string.h>
3975240ed1SBrian Somers #include <sys/ioctl.h>
4075240ed1SBrian Somers #include <sys/sysctl.h>
4175240ed1SBrian Somers #include <unistd.h>
4275240ed1SBrian Somers 
43b6e82f33SBrian Somers #include "command.h"
4475240ed1SBrian Somers #include "mbuf.h"
45215a4696SAtsushi Murai #include "log.h"
46927145beSBrian Somers #include "loadalias.h"
4786e02934SBrian Somers #include "defs.h"
48927145beSBrian Somers #include "vars.h"
495106c671SBrian Somers #include "id.h"
50bcc332bdSBrian Somers #include "os.h"
51bcc332bdSBrian Somers #include "ipcp.h"
52bcc332bdSBrian Somers #include "iplist.h"
5375240ed1SBrian Somers #include "route.h"
54af57ed9fSAtsushi Murai 
55af57ed9fSAtsushi Murai static int IfIndex;
56af57ed9fSAtsushi Murai 
57af57ed9fSAtsushi Murai struct rtmsg {
58af57ed9fSAtsushi Murai   struct rt_msghdr m_rtm;
59af57ed9fSAtsushi Murai   char m_space[64];
60af57ed9fSAtsushi Murai };
61af57ed9fSAtsushi Murai 
62af57ed9fSAtsushi Murai static int seqno;
63af57ed9fSAtsushi Murai 
64af57ed9fSAtsushi Murai void
65944f7098SBrian Somers OsSetRoute(int cmd,
66944f7098SBrian Somers 	   struct in_addr dst,
67944f7098SBrian Somers 	   struct in_addr gateway,
6865eea2e0SBrian Somers 	   struct in_addr mask,
6965eea2e0SBrian Somers 	   int bang)
70af57ed9fSAtsushi Murai {
71af57ed9fSAtsushi Murai   struct rtmsg rtmes;
72af57ed9fSAtsushi Murai   int s, nb, wb;
73b6e82f33SBrian Somers   char *cp;
74b6e82f33SBrian Somers   const char *cmdstr;
75af57ed9fSAtsushi Murai   struct sockaddr_in rtdata;
76af57ed9fSAtsushi Murai 
7765eea2e0SBrian Somers   if (bang)
7865eea2e0SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
7965eea2e0SBrian Somers   else
805106c671SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
815106c671SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
826614d8c5SBrian Somers   if (s < 0) {
83afc7fa2cSBrian Somers     LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
846614d8c5SBrian Somers     return;
856614d8c5SBrian Somers   }
8670ee81ffSBrian Somers   memset(&rtmes, '\0', sizeof rtmes);
87af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_version = RTM_VERSION;
88af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_type = cmd;
89f01e577bSBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
90af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_seq = ++seqno;
91af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_pid = getpid();
922db86e5bSPeter Wemm   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
93af57ed9fSAtsushi Murai 
9470ee81ffSBrian Somers   memset(&rtdata, '\0', sizeof rtdata);
95af57ed9fSAtsushi Murai   rtdata.sin_len = 16;
96af57ed9fSAtsushi Murai   rtdata.sin_family = AF_INET;
97af57ed9fSAtsushi Murai   rtdata.sin_port = 0;
98af57ed9fSAtsushi Murai   rtdata.sin_addr = dst;
99af57ed9fSAtsushi Murai 
100af57ed9fSAtsushi Murai   cp = rtmes.m_space;
10175240ed1SBrian Somers   memcpy(cp, &rtdata, 16);
102af57ed9fSAtsushi Murai   cp += 16;
103f01e577bSBrian Somers   if (cmd == RTM_ADD)
104f01e577bSBrian Somers     if (gateway.s_addr == INADDR_ANY) {
105f01e577bSBrian Somers       /* Add a route through the interface */
106f01e577bSBrian Somers       struct sockaddr_dl dl;
107f01e577bSBrian Somers       const char *iname;
108f01e577bSBrian Somers       int ilen;
109f01e577bSBrian Somers 
110f01e577bSBrian Somers       iname = Index2Nam(IfIndex);
111f01e577bSBrian Somers       ilen = strlen(iname);
11270ee81ffSBrian Somers       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
113f01e577bSBrian Somers       dl.sdl_family = AF_LINK;
114f01e577bSBrian Somers       dl.sdl_index = IfIndex;
115f01e577bSBrian Somers       dl.sdl_type = 0;
116f01e577bSBrian Somers       dl.sdl_nlen = ilen;
117f01e577bSBrian Somers       dl.sdl_alen = 0;
118f01e577bSBrian Somers       dl.sdl_slen = 0;
11970ee81ffSBrian Somers       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
120f01e577bSBrian Somers 
121f01e577bSBrian Somers       memcpy(cp, &dl, dl.sdl_len);
122f01e577bSBrian Somers       cp += dl.sdl_len;
123f01e577bSBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
124f01e577bSBrian Somers     } else {
125af57ed9fSAtsushi Murai       rtdata.sin_addr = gateway;
12675240ed1SBrian Somers       memcpy(cp, &rtdata, 16);
127af57ed9fSAtsushi Murai       cp += 16;
128d3a3ec3bSBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
129af57ed9fSAtsushi Murai     }
130f01e577bSBrian Somers 
131af57ed9fSAtsushi Murai   if (dst.s_addr == INADDR_ANY)
132af57ed9fSAtsushi Murai     mask.s_addr = INADDR_ANY;
133af57ed9fSAtsushi Murai 
134f01e577bSBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
135f01e577bSBrian Somers     rtdata.sin_addr = mask;
136f01e577bSBrian Somers     memcpy(cp, &rtdata, 16);
137f01e577bSBrian Somers     cp += 16;
138f01e577bSBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
139f01e577bSBrian Somers   }
140af57ed9fSAtsushi Murai 
141af57ed9fSAtsushi Murai   nb = cp - (char *) &rtmes;
142af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_msglen = nb;
143de7453bbSBrian Somers   wb = ID0write(s, &rtmes, nb);
144af57ed9fSAtsushi Murai   if (wb < 0) {
14532ca3341SBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute failure:\n");
14632ca3341SBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Cmd = %s\n", cmd);
147e696ee3bSBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Dst = %s\n", inet_ntoa(dst));
148e696ee3bSBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
149e696ee3bSBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
15065eea2e0SBrian Somers failed:
15165eea2e0SBrian Somers     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
15265eea2e0SBrian Somers                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST)))
15365eea2e0SBrian Somers       if (!bang)
154bcc332bdSBrian Somers         LogPrintf(LogWARN, "Add route failed: %s already exists\n",
155bcc332bdSBrian Somers                   inet_ntoa(dst));
15665eea2e0SBrian Somers       else {
15765eea2e0SBrian Somers         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
15865eea2e0SBrian Somers         if ((wb = ID0write(s, &rtmes, nb)) < 0)
15965eea2e0SBrian Somers           goto failed;
16065eea2e0SBrian Somers       }
16165eea2e0SBrian Somers     else if (cmd == RTM_DELETE &&
16265eea2e0SBrian Somers              (rtmes.m_rtm.rtm_errno == ESRCH ||
16365eea2e0SBrian Somers               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
16465eea2e0SBrian Somers       if (!bang)
165bcc332bdSBrian Somers         LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n",
166bcc332bdSBrian Somers                   inet_ntoa(dst));
16765eea2e0SBrian Somers     } else if (rtmes.m_rtm.rtm_errno == 0)
16832ca3341SBrian Somers       LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
16932ca3341SBrian Somers                 inet_ntoa(dst), strerror(errno));
17065eea2e0SBrian Somers     else
17132ca3341SBrian Somers       LogPrintf(LogWARN, "%s route failed: %s: %s\n",
17232ca3341SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
173e696ee3bSBrian Somers   }
1745106c671SBrian Somers   LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
1755106c671SBrian Somers             wb, cmdstr, dst.s_addr, gateway.s_addr);
176af57ed9fSAtsushi Murai   close(s);
177af57ed9fSAtsushi Murai }
178af57ed9fSAtsushi Murai 
179af57ed9fSAtsushi Murai static void
1805d5e5070SBrian Somers p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width)
181af57ed9fSAtsushi Murai {
182b6e82f33SBrian Somers   char buf[29];
1835d5e5070SBrian Somers   struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
1845d5e5070SBrian Somers   struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
1855d5e5070SBrian Somers   struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
186af57ed9fSAtsushi Murai 
1875d5e5070SBrian Somers   switch (phost->sa_family) {
1885d5e5070SBrian Somers   case AF_INET:
1895d5e5070SBrian Somers     if (!phost)
1904bfaee90SBrian Somers       buf[0] = '\0';
1915d5e5070SBrian Somers     else if (ihost->sin_addr.s_addr == INADDR_ANY)
1924bfaee90SBrian Somers       strcpy(buf, "default");
1935d5e5070SBrian Somers     else if (!mask)
1944bfaee90SBrian Somers       strcpy(buf, inet_ntoa(ihost->sin_addr));
1955d5e5070SBrian Somers     else {
1965d5e5070SBrian Somers       u_int msk = ntohl(mask->sin_addr.s_addr);
1975d5e5070SBrian Somers       u_int tst;
1985d5e5070SBrian Somers       int bits;
1995d5e5070SBrian Somers       int len;
2005d5e5070SBrian Somers       struct sockaddr_in net;
2015d5e5070SBrian Somers 
2025d5e5070SBrian Somers       for (tst = 1, bits=32; tst; tst <<= 1, bits--)
2035d5e5070SBrian Somers         if (msk & tst)
2045d5e5070SBrian Somers           break;
2055d5e5070SBrian Somers 
2065d5e5070SBrian Somers       for (tst <<=1; tst; tst <<= 1)
2075d5e5070SBrian Somers         if (!(msk & tst))
2085d5e5070SBrian Somers           break;
2095d5e5070SBrian Somers 
2105d5e5070SBrian Somers       net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
21183c0952dSBrian Somers       strcpy(buf, inet_ntoa(net.sin_addr));
2125d5e5070SBrian Somers       for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
2135d5e5070SBrian Somers         if (strcmp(buf+len-2, ".0"))
2145d5e5070SBrian Somers           break;
2155d5e5070SBrian Somers 
2165d5e5070SBrian Somers       if (tst)    /* non-contiguous :-( */
2175d5e5070SBrian Somers         sprintf(buf+strlen(buf),"&0x%08x", msk);
2185d5e5070SBrian Somers       else
2195d5e5070SBrian Somers         sprintf(buf+strlen(buf), "/%d", bits);
220927145beSBrian Somers     }
2215d5e5070SBrian Somers     break;
2225d5e5070SBrian Somers 
2235d5e5070SBrian Somers   case AF_LINK:
2244bfaee90SBrian Somers     if (dl->sdl_nlen)
2254bfaee90SBrian Somers       snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
2264bfaee90SBrian Somers     else if (dl->sdl_alen)
2274bfaee90SBrian Somers       if (dl->sdl_type == IFT_ETHER)
22870ee81ffSBrian Somers         if (dl->sdl_alen < sizeof buf / 3) {
2295d5e5070SBrian Somers           int f;
2305d5e5070SBrian Somers           u_char *MAC;
2315d5e5070SBrian Somers 
2325d5e5070SBrian Somers           MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
2335d5e5070SBrian Somers           for (f = 0; f < dl->sdl_alen; f++)
2345d5e5070SBrian Somers             sprintf(buf+f*3, "%02x:", MAC[f]);
2355d5e5070SBrian Somers           buf[f*3-1] = '\0';
2365d5e5070SBrian Somers         } else
23783c0952dSBrian Somers 	  strcpy(buf, "??:??:??:??:??:??");
2384bfaee90SBrian Somers       else
2394bfaee90SBrian Somers         sprintf(buf, "<IFT type %d>", dl->sdl_type);
2404bfaee90SBrian Somers     else if (dl->sdl_slen)
2414bfaee90SBrian Somers       sprintf(buf, "<slen %d?>", dl->sdl_slen);
2424bfaee90SBrian Somers     else
2434bfaee90SBrian Somers       sprintf(buf, "link#%d", dl->sdl_index);
2445d5e5070SBrian Somers     break;
2455d5e5070SBrian Somers 
2465d5e5070SBrian Somers   default:
2474bfaee90SBrian Somers     sprintf(buf, "<AF type %d>", phost->sa_family);
2485d5e5070SBrian Somers     break;
2495d5e5070SBrian Somers   }
2505d5e5070SBrian Somers 
2514bfaee90SBrian Somers   fprintf(VarTerm, "%-*s ", width-1, buf);
252af57ed9fSAtsushi Murai }
253af57ed9fSAtsushi Murai 
254aa8e0519SBrian Somers static struct bits {
2555d5e5070SBrian Somers   u_long b_mask;
256af57ed9fSAtsushi Murai   char b_val;
257af57ed9fSAtsushi Murai } bits[] = {
2585d5e5070SBrian Somers   { RTF_UP, 'U' },
2595d5e5070SBrian Somers   { RTF_GATEWAY, 'G' },
2605d5e5070SBrian Somers   { RTF_HOST, 'H' },
2615d5e5070SBrian Somers   { RTF_REJECT, 'R' },
2625d5e5070SBrian Somers   { RTF_DYNAMIC, 'D' },
2635d5e5070SBrian Somers   { RTF_MODIFIED, 'M' },
2645d5e5070SBrian Somers   { RTF_DONE, 'd' },
2655d5e5070SBrian Somers   { RTF_CLONING, 'C' },
2665d5e5070SBrian Somers   { RTF_XRESOLVE, 'X' },
2675d5e5070SBrian Somers   { RTF_LLINFO, 'L' },
2685d5e5070SBrian Somers   { RTF_STATIC, 'S' },
2695d5e5070SBrian Somers   { RTF_PROTO1, '1' },
2705d5e5070SBrian Somers   { RTF_PROTO2, '2' },
2715d5e5070SBrian Somers   { RTF_BLACKHOLE, 'B' },
27232ca3341SBrian Somers #ifdef RTF_WASCLONED
2735d5e5070SBrian Somers   { RTF_WASCLONED, 'W' },
27432ca3341SBrian Somers #endif
27532ca3341SBrian Somers #ifdef RTF_PRCLONING
2765d5e5070SBrian Somers   { RTF_PRCLONING, 'c' },
27732ca3341SBrian Somers #endif
27832ca3341SBrian Somers #ifdef RTF_PROTO3
2795d5e5070SBrian Somers   { RTF_PROTO3, '3' },
28032ca3341SBrian Somers #endif
28132ca3341SBrian Somers #ifdef RTF_BROADCAST
2825d5e5070SBrian Somers   { RTF_BROADCAST, 'b' },
2835d5e5070SBrian Somers #endif
2845d5e5070SBrian Somers   { 0, '\0' }
285af57ed9fSAtsushi Murai };
286af57ed9fSAtsushi Murai 
28732ca3341SBrian Somers #ifndef RTF_WASCLONED
28832ca3341SBrian Somers #define RTF_WASCLONED (0)
28932ca3341SBrian Somers #endif
29032ca3341SBrian Somers 
291af57ed9fSAtsushi Murai static void
292d27d502cSBrian Somers p_flags(u_long f, int max)
293af57ed9fSAtsushi Murai {
294927145beSBrian Somers   if (VarTerm) {
295af57ed9fSAtsushi Murai     char name[33], *flags;
296af57ed9fSAtsushi Murai     register struct bits *p = bits;
297af57ed9fSAtsushi Murai 
29870ee81ffSBrian Somers     if (max > sizeof name - 1)
29970ee81ffSBrian Somers       max = sizeof name - 1;
300d27d502cSBrian Somers 
301d27d502cSBrian Somers     for (flags = name; p->b_mask && flags - name < max; p++)
302af57ed9fSAtsushi Murai       if (p->b_mask & f)
303af57ed9fSAtsushi Murai 	*flags++ = p->b_val;
304af57ed9fSAtsushi Murai     *flags = '\0';
305d27d502cSBrian Somers     fprintf(VarTerm, "%-*.*s", max, max, name);
306927145beSBrian Somers   }
307af57ed9fSAtsushi Murai }
308af57ed9fSAtsushi Murai 
309c6fe0cb2SBrian Somers const char *
3105d5e5070SBrian Somers Index2Nam(int idx)
3115d5e5070SBrian Somers {
312b1435e41SBrian Somers   static char **ifs;
3139cb1d89eSBrian Somers   static int nifs, debug_done;
3145d5e5070SBrian Somers 
3155d5e5070SBrian Somers   if (!nifs) {
316b1435e41SBrian Somers     int mib[6], have, had;
317e7250038SBrian Somers     size_t needed;
3185d5e5070SBrian Somers     char *buf, *ptr, *end;
3195d5e5070SBrian Somers     struct sockaddr_dl *dl;
3205d5e5070SBrian Somers     struct if_msghdr *ifm;
3215d5e5070SBrian Somers 
3225d5e5070SBrian Somers     mib[0] = CTL_NET;
3235d5e5070SBrian Somers     mib[1] = PF_ROUTE;
3245d5e5070SBrian Somers     mib[2] = 0;
3255d5e5070SBrian Somers     mib[3] = 0;
3265d5e5070SBrian Somers     mib[4] = NET_RT_IFLIST;
3275d5e5070SBrian Somers     mib[5] = 0;
3285d5e5070SBrian Somers 
3295d5e5070SBrian Somers     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
3305d5e5070SBrian Somers       LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
3315d5e5070SBrian Somers       return "???";
3325d5e5070SBrian Somers     }
3335d5e5070SBrian Somers     if ((buf = malloc(needed)) == NULL)
3345d5e5070SBrian Somers       return "???";
3355d5e5070SBrian Somers     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
3365d5e5070SBrian Somers       free(buf);
3375d5e5070SBrian Somers       return "???";
3385d5e5070SBrian Somers     }
3395d5e5070SBrian Somers     end = buf + needed;
3405d5e5070SBrian Somers 
341b1435e41SBrian Somers     have = 0;
3429cb1d89eSBrian Somers     for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
3435d5e5070SBrian Somers       ifm = (struct if_msghdr *)ptr;
3445d5e5070SBrian Somers       dl = (struct sockaddr_dl *)(ifm + 1);
345b1435e41SBrian Somers       if (ifm->ifm_index > 0) {
346b1435e41SBrian Somers         if (ifm->ifm_index > have) {
347b1435e41SBrian Somers           had = have;
348b1435e41SBrian Somers           have = ifm->ifm_index + 5;
349b1435e41SBrian Somers           if (had)
350b1435e41SBrian Somers             ifs = (char **)realloc(ifs, sizeof(char *) * have);
351b1435e41SBrian Somers           else
352b1435e41SBrian Somers             ifs = (char **)malloc(sizeof(char *) * have);
353b1435e41SBrian Somers           if (!ifs) {
354b1435e41SBrian Somers             LogPrintf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
355b1435e41SBrian Somers             nifs = 0;
356b1435e41SBrian Somers             return "???";
357b1435e41SBrian Somers           }
358b1435e41SBrian Somers           memset(ifs + had, '\0', sizeof(char *) * (have - had));
359b1435e41SBrian Somers         }
360b1435e41SBrian Somers         if (ifs[ifm->ifm_index-1] == NULL) {
361b1435e41SBrian Somers           ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
362b1435e41SBrian Somers           memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
363b1435e41SBrian Somers           ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
364b1435e41SBrian Somers           if (nifs < ifm->ifm_index)
3659cb1d89eSBrian Somers             nifs = ifm->ifm_index;
366b1435e41SBrian Somers         }
3679cb1d89eSBrian Somers       } else if (LogIsKept(LogDEBUG))
3689cb1d89eSBrian Somers         LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n",
3699cb1d89eSBrian Somers                   ifm->ifm_index);
3705d5e5070SBrian Somers     }
3715d5e5070SBrian Somers     free(buf);
3725d5e5070SBrian Somers   }
3735d5e5070SBrian Somers 
3749cb1d89eSBrian Somers   if (LogIsKept(LogDEBUG) && !debug_done) {
3759cb1d89eSBrian Somers     int f;
3769cb1d89eSBrian Somers 
3779cb1d89eSBrian Somers     LogPrintf(LogDEBUG, "Found the following interfaces:\n");
3789cb1d89eSBrian Somers     for (f = 0; f < nifs; f++)
379b1435e41SBrian Somers       if (ifs[f] != NULL)
3809cb1d89eSBrian Somers         LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
3819cb1d89eSBrian Somers     debug_done = 1;
3829cb1d89eSBrian Somers   }
3839cb1d89eSBrian Somers 
384b1435e41SBrian Somers   if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
3855d5e5070SBrian Somers     return "???";
3869cb1d89eSBrian Somers 
3879cb1d89eSBrian Somers   return ifs[idx-1];
3885d5e5070SBrian Somers }
3895d5e5070SBrian Somers 
390af57ed9fSAtsushi Murai int
391b6e82f33SBrian Somers ShowRoute(struct cmdargs const *arg)
392af57ed9fSAtsushi Murai {
393af57ed9fSAtsushi Murai   struct rt_msghdr *rtm;
3945d5e5070SBrian Somers   struct sockaddr *sa_dst, *sa_gw, *sa_mask;
3955d5e5070SBrian Somers   char *sp, *ep, *cp, *wp;
396e7250038SBrian Somers   size_t needed;
397af57ed9fSAtsushi Murai   int mib[6];
398af57ed9fSAtsushi Murai 
399927145beSBrian Somers   if (!VarTerm)
400927145beSBrian Somers     return 1;
401927145beSBrian Somers 
402af57ed9fSAtsushi Murai   mib[0] = CTL_NET;
403af57ed9fSAtsushi Murai   mib[1] = PF_ROUTE;
40453c9f6c0SAtsushi Murai   mib[2] = 0;
40553c9f6c0SAtsushi Murai   mib[3] = 0;
406af57ed9fSAtsushi Murai   mib[4] = NET_RT_DUMP;
40753c9f6c0SAtsushi Murai   mib[5] = 0;
40853c9f6c0SAtsushi Murai   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
409afc7fa2cSBrian Somers     LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
41053c9f6c0SAtsushi Murai     return (1);
41153c9f6c0SAtsushi Murai   }
412af57ed9fSAtsushi Murai   if (needed < 0)
413af57ed9fSAtsushi Murai     return (1);
414af57ed9fSAtsushi Murai   sp = malloc(needed);
415af57ed9fSAtsushi Murai   if (sp == NULL)
416af57ed9fSAtsushi Murai     return (1);
41753c9f6c0SAtsushi Murai   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
418afc7fa2cSBrian Somers     LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
419b0cdb3ceSJordan K. Hubbard     free(sp);
420af57ed9fSAtsushi Murai     return (1);
42153c9f6c0SAtsushi Murai   }
422af57ed9fSAtsushi Murai   ep = sp + needed;
423af57ed9fSAtsushi Murai 
4245d5e5070SBrian Somers   fprintf(VarTerm, "%-20s%-20sFlags  Netif\n", "Destination", "Gateway");
425af57ed9fSAtsushi Murai   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
426af57ed9fSAtsushi Murai     rtm = (struct rt_msghdr *) cp;
4275d5e5070SBrian Somers     wp = (char *)(rtm+1);
4285d5e5070SBrian Somers 
4295d5e5070SBrian Somers     if (rtm->rtm_addrs & RTA_DST) {
4305d5e5070SBrian Somers       sa_dst = (struct sockaddr *)wp;
4315d5e5070SBrian Somers       wp += sa_dst->sa_len;
4325d5e5070SBrian Somers     } else
4335d5e5070SBrian Somers       sa_dst = NULL;
4345d5e5070SBrian Somers 
4355d5e5070SBrian Somers     if (rtm->rtm_addrs & RTA_GATEWAY) {
4365d5e5070SBrian Somers       sa_gw = (struct sockaddr *)wp;
4375d5e5070SBrian Somers       wp += sa_gw->sa_len;
4385d5e5070SBrian Somers     } else
4395d5e5070SBrian Somers       sa_gw = NULL;
4405d5e5070SBrian Somers 
4415d5e5070SBrian Somers     if (rtm->rtm_addrs & RTA_NETMASK) {
4425d5e5070SBrian Somers       sa_mask = (struct sockaddr *)wp;
4435d5e5070SBrian Somers       wp += sa_mask->sa_len;
4445d5e5070SBrian Somers     } else
4455d5e5070SBrian Somers       sa_mask = NULL;
4465d5e5070SBrian Somers 
4475d5e5070SBrian Somers     p_sockaddr(sa_dst, sa_mask, 20);
4485d5e5070SBrian Somers     p_sockaddr(sa_gw, NULL, 20);
4495d5e5070SBrian Somers 
450d27d502cSBrian Somers     p_flags(rtm->rtm_flags, 6);
4515d5e5070SBrian Somers     fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index));
452af57ed9fSAtsushi Murai   }
453b0cdb3ceSJordan K. Hubbard   free(sp);
454927145beSBrian Somers   return 0;
455af57ed9fSAtsushi Murai }
456af57ed9fSAtsushi Murai 
457af57ed9fSAtsushi Murai /*
458af57ed9fSAtsushi Murai  *  Delete routes associated with our interface
459af57ed9fSAtsushi Murai  */
460af57ed9fSAtsushi Murai void
461944f7098SBrian Somers DeleteIfRoutes(int all)
462af57ed9fSAtsushi Murai {
463af57ed9fSAtsushi Murai   struct rt_msghdr *rtm;
464af57ed9fSAtsushi Murai   struct sockaddr *sa;
465f01e577bSBrian Somers   struct in_addr sa_dst, sa_none;
466e7250038SBrian Somers   int pass;
467e7250038SBrian Somers   size_t needed;
468af57ed9fSAtsushi Murai   char *sp, *cp, *ep;
469af57ed9fSAtsushi Murai   int mib[6];
470af57ed9fSAtsushi Murai 
471927145beSBrian Somers   LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
472f01e577bSBrian Somers   sa_none.s_addr = INADDR_ANY;
473927145beSBrian Somers 
474af57ed9fSAtsushi Murai   mib[0] = CTL_NET;
475af57ed9fSAtsushi Murai   mib[1] = PF_ROUTE;
47653c9f6c0SAtsushi Murai   mib[2] = 0;
47753c9f6c0SAtsushi Murai   mib[3] = 0;
478af57ed9fSAtsushi Murai   mib[4] = NET_RT_DUMP;
47953c9f6c0SAtsushi Murai   mib[5] = 0;
48053c9f6c0SAtsushi Murai   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
481afc7fa2cSBrian Somers     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
482afc7fa2cSBrian Somers 	      strerror(errno));
48353c9f6c0SAtsushi Murai     return;
48453c9f6c0SAtsushi Murai   }
485af57ed9fSAtsushi Murai   if (needed < 0)
486af57ed9fSAtsushi Murai     return;
487af57ed9fSAtsushi Murai 
488af57ed9fSAtsushi Murai   sp = malloc(needed);
489af57ed9fSAtsushi Murai   if (sp == NULL)
490af57ed9fSAtsushi Murai     return;
491af57ed9fSAtsushi Murai 
492af57ed9fSAtsushi Murai   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
493afc7fa2cSBrian Somers     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
494afc7fa2cSBrian Somers 	      strerror(errno));
495af57ed9fSAtsushi Murai     free(sp);
496af57ed9fSAtsushi Murai     return;
497af57ed9fSAtsushi Murai   }
498af57ed9fSAtsushi Murai   ep = sp + needed;
499af57ed9fSAtsushi Murai 
50032ca3341SBrian Somers   for (pass = 0; pass < 2; pass++) {
50132ca3341SBrian Somers     /*
50232ca3341SBrian Somers      * We do 2 passes.  The first deletes all cloned routes.  The second
50332ca3341SBrian Somers      * deletes all non-cloned routes.  This is necessary to avoid
50432ca3341SBrian Somers      * potential errors from trying to delete route X after route Y where
50532ca3341SBrian Somers      * route X was cloned from route Y (which is no longer there).
50632ca3341SBrian Somers      */
50732ca3341SBrian Somers     if (RTF_WASCLONED == 0 && pass == 0)
50832ca3341SBrian Somers       /* So we can't tell ! */
50932ca3341SBrian Somers       continue;
510af57ed9fSAtsushi Murai     for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
511af57ed9fSAtsushi Murai       rtm = (struct rt_msghdr *) cp;
512af57ed9fSAtsushi Murai       sa = (struct sockaddr *) (rtm + 1);
51332ca3341SBrian Somers       LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s),"
51432ca3341SBrian Somers                 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
5155d5e5070SBrian Somers                 Index2Nam(rtm->rtm_index), rtm->rtm_flags,
5169b5a20e1SBrian Somers 	        inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
5175d5e5070SBrian Somers       if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
5185d5e5070SBrian Somers 	  rtm->rtm_index == IfIndex &&
519af57ed9fSAtsushi Murai 	  (all || (rtm->rtm_flags & RTF_GATEWAY))) {
5205d5e5070SBrian Somers         sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
5215d5e5070SBrian Somers         sa = (struct sockaddr *)((char *)sa + sa->sa_len);
522f01e577bSBrian Somers         if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
52332ca3341SBrian Somers           if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
52432ca3341SBrian Somers               (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
52532ca3341SBrian Somers             LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass);
52665eea2e0SBrian Somers             OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none, 0);
5275d5e5070SBrian Somers           } else
52832ca3341SBrian Somers             LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass);
52932ca3341SBrian Somers         } else
530f01e577bSBrian Somers           LogPrintf(LogDEBUG,
531f01e577bSBrian Somers                     "DeleteIfRoutes: Can't remove routes of %d family !\n",
532f01e577bSBrian Somers                     sa->sa_family);
533af57ed9fSAtsushi Murai       }
534af57ed9fSAtsushi Murai     }
53532ca3341SBrian Somers   }
536af57ed9fSAtsushi Murai   free(sp);
537af57ed9fSAtsushi Murai }
538af57ed9fSAtsushi Murai 
539af57ed9fSAtsushi Murai int
540944f7098SBrian Somers GetIfIndex(char *name)
541af57ed9fSAtsushi Murai {
5425d5e5070SBrian Somers   int idx;
543b6e82f33SBrian Somers   const char *got;
544944f7098SBrian Somers 
5459cb1d89eSBrian Somers   idx = 1;
5465d5e5070SBrian Somers   while (strcmp(got = Index2Nam(idx), "???"))
5475d5e5070SBrian Somers     if (!strcmp(got, name))
5485d5e5070SBrian Somers       return IfIndex = idx;
5495d5e5070SBrian Somers     else
5505d5e5070SBrian Somers       idx++;
5515d5e5070SBrian Somers   return -1;
552af57ed9fSAtsushi Murai }
553bcc332bdSBrian Somers 
554bcc332bdSBrian Somers struct in_addr
555bcc332bdSBrian Somers ChooseHisAddr(const struct in_addr gw)
556bcc332bdSBrian Somers {
557bcc332bdSBrian Somers   struct in_addr try;
558bcc332bdSBrian Somers   int f;
559bcc332bdSBrian Somers 
560bcc332bdSBrian Somers   for (f = 0; f < DefHisChoice.nItems; f++) {
561bcc332bdSBrian Somers     try = iplist_next(&DefHisChoice);
562bcc332bdSBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
563bcc332bdSBrian Somers               f, inet_ntoa(try));
564bcc332bdSBrian Somers     if (OsTrySetIpaddress(gw, try) == 0) {
565bcc332bdSBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
566bcc332bdSBrian Somers                 inet_ntoa(try));
567bcc332bdSBrian Somers       break;
568bcc332bdSBrian Somers     }
569bcc332bdSBrian Somers   }
570bcc332bdSBrian Somers 
571bcc332bdSBrian Somers   if (f == DefHisChoice.nItems) {
572bcc332bdSBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
573bcc332bdSBrian Somers     try.s_addr = INADDR_ANY;
574bcc332bdSBrian Somers   }
575bcc332bdSBrian Somers 
576bcc332bdSBrian Somers   return try;
577bcc332bdSBrian Somers }
578