xref: /freebsd/usr.sbin/ppp/route.c (revision d27d502ce660521bca1789fc037711c7709a7bf3)
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  *
20d27d502cSBrian Somers  * $Id: route.c,v 1.33 1997/12/17 00:19:25 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_systm.h>
31628d2ac1SGarrett Wollman #include <netinet/in.h>
32628d2ac1SGarrett Wollman #include <arpa/inet.h>
335d5e5070SBrian Somers #include <net/if_dl.h>
34628d2ac1SGarrett Wollman 
3575240ed1SBrian Somers #include <errno.h>
3675240ed1SBrian Somers #include <machine/endian.h>
3775240ed1SBrian Somers #include <stdio.h>
3875240ed1SBrian Somers #include <stdlib.h>
3975240ed1SBrian Somers #include <string.h>
4075240ed1SBrian Somers #include <sys/ioctl.h>
4175240ed1SBrian Somers #include <sys/sysctl.h>
4275240ed1SBrian Somers #include <unistd.h>
4375240ed1SBrian Somers 
44b6e82f33SBrian Somers #include "command.h"
4575240ed1SBrian Somers #include "mbuf.h"
46215a4696SAtsushi Murai #include "log.h"
47927145beSBrian Somers #include "loadalias.h"
4886e02934SBrian Somers #include "defs.h"
49927145beSBrian Somers #include "vars.h"
505106c671SBrian Somers #include "id.h"
51bcc332bdSBrian Somers #include "os.h"
52bcc332bdSBrian Somers #include "ipcp.h"
53bcc332bdSBrian Somers #include "iplist.h"
5475240ed1SBrian Somers #include "route.h"
55af57ed9fSAtsushi Murai 
56af57ed9fSAtsushi Murai static int IfIndex;
57f01e577bSBrian Somers static const char *Index2Nam(int);
58af57ed9fSAtsushi Murai 
59af57ed9fSAtsushi Murai struct rtmsg {
60af57ed9fSAtsushi Murai   struct rt_msghdr m_rtm;
61af57ed9fSAtsushi Murai   char m_space[64];
62af57ed9fSAtsushi Murai };
63af57ed9fSAtsushi Murai 
64af57ed9fSAtsushi Murai static int seqno;
65af57ed9fSAtsushi Murai 
66af57ed9fSAtsushi Murai void
67944f7098SBrian Somers OsSetRoute(int cmd,
68944f7098SBrian Somers 	   struct in_addr dst,
69944f7098SBrian Somers 	   struct in_addr gateway,
70944f7098SBrian Somers 	   struct in_addr mask)
71af57ed9fSAtsushi Murai {
72af57ed9fSAtsushi Murai   struct rtmsg rtmes;
73af57ed9fSAtsushi Murai   int s, nb, wb;
74b6e82f33SBrian Somers   char *cp;
75b6e82f33SBrian Somers   const char *cmdstr;
76af57ed9fSAtsushi Murai   struct sockaddr_in rtdata;
77af57ed9fSAtsushi Murai 
785106c671SBrian Somers   cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
795106c671SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
806614d8c5SBrian Somers   if (s < 0) {
81afc7fa2cSBrian Somers     LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
826614d8c5SBrian Somers     return;
836614d8c5SBrian Somers   }
8475240ed1SBrian Somers   memset(&rtmes, '\0', sizeof(rtmes));
85af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_version = RTM_VERSION;
86af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_type = cmd;
87f01e577bSBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
88af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_seq = ++seqno;
89af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_pid = getpid();
902db86e5bSPeter Wemm   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
91af57ed9fSAtsushi Murai 
9275240ed1SBrian Somers   memset(&rtdata, '\0', sizeof(rtdata));
93af57ed9fSAtsushi Murai   rtdata.sin_len = 16;
94af57ed9fSAtsushi Murai   rtdata.sin_family = AF_INET;
95af57ed9fSAtsushi Murai   rtdata.sin_port = 0;
96af57ed9fSAtsushi Murai   rtdata.sin_addr = dst;
97af57ed9fSAtsushi Murai 
98af57ed9fSAtsushi Murai   cp = rtmes.m_space;
9975240ed1SBrian Somers   memcpy(cp, &rtdata, 16);
100af57ed9fSAtsushi Murai   cp += 16;
101f01e577bSBrian Somers   if (cmd == RTM_ADD)
102f01e577bSBrian Somers     if (gateway.s_addr == INADDR_ANY) {
103f01e577bSBrian Somers       /* Add a route through the interface */
104f01e577bSBrian Somers       struct sockaddr_dl dl;
105f01e577bSBrian Somers       const char *iname;
106f01e577bSBrian Somers       int ilen;
107f01e577bSBrian Somers 
108f01e577bSBrian Somers       iname = Index2Nam(IfIndex);
109f01e577bSBrian Somers       ilen = strlen(iname);
110f01e577bSBrian Somers       dl.sdl_len = sizeof(dl)-sizeof(dl.sdl_data)+ilen;
111f01e577bSBrian Somers       dl.sdl_family = AF_LINK;
112f01e577bSBrian Somers       dl.sdl_index = IfIndex;
113f01e577bSBrian Somers       dl.sdl_type = 0;
114f01e577bSBrian Somers       dl.sdl_nlen = ilen;
115f01e577bSBrian Somers       dl.sdl_alen = 0;
116f01e577bSBrian Somers       dl.sdl_slen = 0;
117f01e577bSBrian Somers       strcpy(dl.sdl_data, iname);
118f01e577bSBrian Somers 
119f01e577bSBrian Somers       memcpy(cp, &dl, dl.sdl_len);
120f01e577bSBrian Somers       cp += dl.sdl_len;
121f01e577bSBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
122f01e577bSBrian Somers     } else {
123af57ed9fSAtsushi Murai       rtdata.sin_addr = gateway;
12475240ed1SBrian Somers       memcpy(cp, &rtdata, 16);
125af57ed9fSAtsushi Murai       cp += 16;
126d3a3ec3bSBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
127af57ed9fSAtsushi Murai     }
128f01e577bSBrian Somers 
129af57ed9fSAtsushi Murai   if (dst.s_addr == INADDR_ANY)
130af57ed9fSAtsushi Murai     mask.s_addr = INADDR_ANY;
131af57ed9fSAtsushi Murai 
132f01e577bSBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
133f01e577bSBrian Somers     rtdata.sin_addr = mask;
134f01e577bSBrian Somers     memcpy(cp, &rtdata, 16);
135f01e577bSBrian Somers     cp += 16;
136f01e577bSBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
137f01e577bSBrian Somers   }
138af57ed9fSAtsushi Murai 
139af57ed9fSAtsushi Murai   nb = cp - (char *) &rtmes;
140af57ed9fSAtsushi Murai   rtmes.m_rtm.rtm_msglen = nb;
141af57ed9fSAtsushi Murai   wb = write(s, &rtmes, nb);
142af57ed9fSAtsushi Murai   if (wb < 0) {
14332ca3341SBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute failure:\n");
14432ca3341SBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Cmd = %s\n", cmd);
145e696ee3bSBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Dst = %s\n", inet_ntoa(dst));
146e696ee3bSBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
147e696ee3bSBrian Somers     LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
148e696ee3bSBrian Somers     switch (rtmes.m_rtm.rtm_errno) {
149e696ee3bSBrian Somers     case EEXIST:
150bcc332bdSBrian Somers       LogPrintf(LogWARN, "Add route failed: %s already exists\n",
151bcc332bdSBrian Somers                 inet_ntoa(dst));
152e696ee3bSBrian Somers       break;
153e696ee3bSBrian Somers     case ESRCH:
154bcc332bdSBrian Somers       LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n",
155bcc332bdSBrian Somers                 inet_ntoa(dst));
156e696ee3bSBrian Somers       break;
1575106c671SBrian Somers     case 0:
15832ca3341SBrian Somers       LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
15932ca3341SBrian Somers                 inet_ntoa(dst), strerror(errno));
1605106c671SBrian Somers       break;
161e696ee3bSBrian Somers     case ENOBUFS:
162e696ee3bSBrian Somers     default:
16332ca3341SBrian Somers       LogPrintf(LogWARN, "%s route failed: %s: %s\n",
16432ca3341SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
165e696ee3bSBrian Somers       break;
166af57ed9fSAtsushi Murai     }
167e696ee3bSBrian Somers   }
1685106c671SBrian Somers   LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
1695106c671SBrian Somers             wb, cmdstr, dst.s_addr, gateway.s_addr);
170af57ed9fSAtsushi Murai   close(s);
171af57ed9fSAtsushi Murai }
172af57ed9fSAtsushi Murai 
173af57ed9fSAtsushi Murai static void
1745d5e5070SBrian Somers p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width)
175af57ed9fSAtsushi Murai {
176b6e82f33SBrian Somers   char buf[29];
1775d5e5070SBrian Somers   struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
1785d5e5070SBrian Somers   struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
1795d5e5070SBrian Somers   struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
180af57ed9fSAtsushi Murai 
1815d5e5070SBrian Somers   switch (phost->sa_family) {
1825d5e5070SBrian Somers   case AF_INET:
1835d5e5070SBrian Somers     if (!phost)
1844bfaee90SBrian Somers       buf[0] = '\0';
1855d5e5070SBrian Somers     else if (ihost->sin_addr.s_addr == INADDR_ANY)
1864bfaee90SBrian Somers       strcpy(buf, "default");
1875d5e5070SBrian Somers     else if (!mask)
1884bfaee90SBrian Somers       strcpy(buf, inet_ntoa(ihost->sin_addr));
1895d5e5070SBrian Somers     else {
1905d5e5070SBrian Somers       u_int msk = ntohl(mask->sin_addr.s_addr);
1915d5e5070SBrian Somers       u_int tst;
1925d5e5070SBrian Somers       int bits;
1935d5e5070SBrian Somers       int len;
1945d5e5070SBrian Somers       struct sockaddr_in net;
1955d5e5070SBrian Somers 
1965d5e5070SBrian Somers       for (tst = 1, bits=32; tst; tst <<= 1, bits--)
1975d5e5070SBrian Somers         if (msk & tst)
1985d5e5070SBrian Somers           break;
1995d5e5070SBrian Somers 
2005d5e5070SBrian Somers       for (tst <<=1; tst; tst <<= 1)
2015d5e5070SBrian Somers         if (!(msk & tst))
2025d5e5070SBrian Somers           break;
2035d5e5070SBrian Somers 
2045d5e5070SBrian Somers       net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
20583c0952dSBrian Somers       strcpy(buf, inet_ntoa(net.sin_addr));
2065d5e5070SBrian Somers       for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
2075d5e5070SBrian Somers         if (strcmp(buf+len-2, ".0"))
2085d5e5070SBrian Somers           break;
2095d5e5070SBrian Somers 
2105d5e5070SBrian Somers       if (tst)    /* non-contiguous :-( */
2115d5e5070SBrian Somers         sprintf(buf+strlen(buf),"&0x%08x", msk);
2125d5e5070SBrian Somers       else
2135d5e5070SBrian Somers         sprintf(buf+strlen(buf), "/%d", bits);
214927145beSBrian Somers     }
2155d5e5070SBrian Somers     break;
2165d5e5070SBrian Somers 
2175d5e5070SBrian Somers   case AF_LINK:
2184bfaee90SBrian Somers     if (dl->sdl_nlen)
2194bfaee90SBrian Somers       snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
2204bfaee90SBrian Somers     else if (dl->sdl_alen)
2214bfaee90SBrian Somers       if (dl->sdl_type == IFT_ETHER)
2224bfaee90SBrian Somers         if (dl->sdl_alen < sizeof(buf)/3) {
2235d5e5070SBrian Somers           int f;
2245d5e5070SBrian Somers           u_char *MAC;
2255d5e5070SBrian Somers 
2265d5e5070SBrian Somers           MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
2275d5e5070SBrian Somers           for (f = 0; f < dl->sdl_alen; f++)
2285d5e5070SBrian Somers             sprintf(buf+f*3, "%02x:", MAC[f]);
2295d5e5070SBrian Somers           buf[f*3-1] = '\0';
2305d5e5070SBrian Somers         } else
23183c0952dSBrian Somers 	  strcpy(buf, "??:??:??:??:??:??");
2324bfaee90SBrian Somers       else
2334bfaee90SBrian Somers         sprintf(buf, "<IFT type %d>", dl->sdl_type);
2344bfaee90SBrian Somers     else if (dl->sdl_slen)
2354bfaee90SBrian Somers       sprintf(buf, "<slen %d?>", dl->sdl_slen);
2364bfaee90SBrian Somers     else
2374bfaee90SBrian Somers       sprintf(buf, "link#%d", dl->sdl_index);
2385d5e5070SBrian Somers     break;
2395d5e5070SBrian Somers 
2405d5e5070SBrian Somers   default:
2414bfaee90SBrian Somers     sprintf(buf, "<AF type %d>", phost->sa_family);
2425d5e5070SBrian Somers     break;
2435d5e5070SBrian Somers   }
2445d5e5070SBrian Somers 
2454bfaee90SBrian Somers   fprintf(VarTerm, "%-*s ", width-1, buf);
246af57ed9fSAtsushi Murai }
247af57ed9fSAtsushi Murai 
248af57ed9fSAtsushi Murai struct bits {
2495d5e5070SBrian Somers   u_long b_mask;
250af57ed9fSAtsushi Murai   char b_val;
251af57ed9fSAtsushi Murai } bits[] = {
2525d5e5070SBrian Somers   { RTF_UP, 'U' },
2535d5e5070SBrian Somers   { RTF_GATEWAY, 'G' },
2545d5e5070SBrian Somers   { RTF_HOST, 'H' },
2555d5e5070SBrian Somers   { RTF_REJECT, 'R' },
2565d5e5070SBrian Somers   { RTF_DYNAMIC, 'D' },
2575d5e5070SBrian Somers   { RTF_MODIFIED, 'M' },
2585d5e5070SBrian Somers   { RTF_DONE, 'd' },
2595d5e5070SBrian Somers   { RTF_CLONING, 'C' },
2605d5e5070SBrian Somers   { RTF_XRESOLVE, 'X' },
2615d5e5070SBrian Somers   { RTF_LLINFO, 'L' },
2625d5e5070SBrian Somers   { RTF_STATIC, 'S' },
2635d5e5070SBrian Somers   { RTF_PROTO1, '1' },
2645d5e5070SBrian Somers   { RTF_PROTO2, '2' },
2655d5e5070SBrian Somers   { RTF_BLACKHOLE, 'B' },
26632ca3341SBrian Somers #ifdef RTF_WASCLONED
2675d5e5070SBrian Somers   { RTF_WASCLONED, 'W' },
26832ca3341SBrian Somers #endif
26932ca3341SBrian Somers #ifdef RTF_PRCLONING
2705d5e5070SBrian Somers   { RTF_PRCLONING, 'c' },
27132ca3341SBrian Somers #endif
27232ca3341SBrian Somers #ifdef RTF_PROTO3
2735d5e5070SBrian Somers   { RTF_PROTO3, '3' },
27432ca3341SBrian Somers #endif
27532ca3341SBrian Somers #ifdef RTF_BROADCAST
2765d5e5070SBrian Somers   { RTF_BROADCAST, 'b' },
2775d5e5070SBrian Somers #endif
2785d5e5070SBrian Somers   { 0, '\0' }
279af57ed9fSAtsushi Murai };
280af57ed9fSAtsushi Murai 
28132ca3341SBrian Somers #ifndef RTF_WASCLONED
28232ca3341SBrian Somers #define RTF_WASCLONED (0)
28332ca3341SBrian Somers #endif
28432ca3341SBrian Somers 
285af57ed9fSAtsushi Murai static void
286d27d502cSBrian Somers p_flags(u_long f, int max)
287af57ed9fSAtsushi Murai {
288927145beSBrian Somers   if (VarTerm) {
289af57ed9fSAtsushi Murai     char name[33], *flags;
290af57ed9fSAtsushi Murai     register struct bits *p = bits;
291af57ed9fSAtsushi Murai 
292d27d502cSBrian Somers     if (max > sizeof(name)-1)
293d27d502cSBrian Somers       max = sizeof(name)-1;
294d27d502cSBrian Somers 
295d27d502cSBrian Somers     for (flags = name; p->b_mask && flags - name < max; p++)
296af57ed9fSAtsushi Murai       if (p->b_mask & f)
297af57ed9fSAtsushi Murai 	*flags++ = p->b_val;
298af57ed9fSAtsushi Murai     *flags = '\0';
299d27d502cSBrian Somers     fprintf(VarTerm, "%-*.*s", max, max, name);
300927145beSBrian Somers   }
301af57ed9fSAtsushi Murai }
302af57ed9fSAtsushi Murai 
303b6e82f33SBrian Somers static const char *
3045d5e5070SBrian Somers Index2Nam(int idx)
3055d5e5070SBrian Somers {
306bcc332bdSBrian Somers   static char ifs[200][6];	/* We could have 256 tun devices ! */
3079cb1d89eSBrian Somers   static int nifs, debug_done;
3085d5e5070SBrian Somers 
3095d5e5070SBrian Somers   if (!nifs) {
3105d5e5070SBrian Somers     int mib[6], needed, len;
3115d5e5070SBrian Somers     char *buf, *ptr, *end;
3125d5e5070SBrian Somers     struct sockaddr_dl *dl;
3135d5e5070SBrian Somers     struct if_msghdr *ifm;
3145d5e5070SBrian Somers 
3155d5e5070SBrian Somers     mib[0] = CTL_NET;
3165d5e5070SBrian Somers     mib[1] = PF_ROUTE;
3175d5e5070SBrian Somers     mib[2] = 0;
3185d5e5070SBrian Somers     mib[3] = 0;
3195d5e5070SBrian Somers     mib[4] = NET_RT_IFLIST;
3205d5e5070SBrian Somers     mib[5] = 0;
3215d5e5070SBrian Somers 
3225d5e5070SBrian Somers     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
3235d5e5070SBrian Somers       LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
3245d5e5070SBrian Somers       return "???";
3255d5e5070SBrian Somers     }
3265d5e5070SBrian Somers     if ((buf = malloc(needed)) == NULL)
3275d5e5070SBrian Somers       return "???";
3285d5e5070SBrian Somers     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
3295d5e5070SBrian Somers       free(buf);
3305d5e5070SBrian Somers       return "???";
3315d5e5070SBrian Somers     }
3325d5e5070SBrian Somers     end = buf + needed;
3335d5e5070SBrian Somers 
3349cb1d89eSBrian Somers     for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
3355d5e5070SBrian Somers       ifm = (struct if_msghdr *)ptr;
3365d5e5070SBrian Somers       dl = (struct sockaddr_dl *)(ifm + 1);
3379cb1d89eSBrian Somers       if (ifm->ifm_index > 0 && ifm->ifm_index <= sizeof(ifs)/sizeof(ifs[0])
3389cb1d89eSBrian Somers           && ifs[ifm->ifm_index-1][0] == '\0') {
3395d5e5070SBrian Somers         if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1)
3405d5e5070SBrian Somers           len = sizeof(ifs[0])-1;
3419cb1d89eSBrian Somers         strncpy(ifs[ifm->ifm_index-1], dl->sdl_data, len);
3429cb1d89eSBrian Somers         ifs[ifm->ifm_index-1][len] = '\0';
3439cb1d89eSBrian Somers         if (len && nifs < ifm->ifm_index)
3449cb1d89eSBrian Somers           nifs = ifm->ifm_index;
3459cb1d89eSBrian Somers       } else if (LogIsKept(LogDEBUG))
3469cb1d89eSBrian Somers         LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n",
3479cb1d89eSBrian Somers                   ifm->ifm_index);
3485d5e5070SBrian Somers     }
3495d5e5070SBrian Somers     free(buf);
3505d5e5070SBrian Somers   }
3515d5e5070SBrian Somers 
3529cb1d89eSBrian Somers   if (LogIsKept(LogDEBUG) && !debug_done) {
3539cb1d89eSBrian Somers     int f;
3549cb1d89eSBrian Somers 
3559cb1d89eSBrian Somers     LogPrintf(LogDEBUG, "Found the following interfaces:\n");
3569cb1d89eSBrian Somers     for (f = 0; f < nifs; f++)
3579cb1d89eSBrian Somers       if (*ifs[f] != '\0')
3589cb1d89eSBrian Somers         LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
3599cb1d89eSBrian Somers     debug_done = 1;
3609cb1d89eSBrian Somers   }
3619cb1d89eSBrian Somers 
3629cb1d89eSBrian Somers   if (idx < 1 || idx > nifs || ifs[idx-1][0] == '\0')
3635d5e5070SBrian Somers     return "???";
3649cb1d89eSBrian Somers 
3659cb1d89eSBrian Somers   return ifs[idx-1];
3665d5e5070SBrian Somers }
3675d5e5070SBrian Somers 
368af57ed9fSAtsushi Murai int
369b6e82f33SBrian Somers ShowRoute(struct cmdargs const *arg)
370af57ed9fSAtsushi Murai {
371af57ed9fSAtsushi Murai   struct rt_msghdr *rtm;
3725d5e5070SBrian Somers   struct sockaddr *sa_dst, *sa_gw, *sa_mask;
3735d5e5070SBrian Somers   char *sp, *ep, *cp, *wp;
3745d5e5070SBrian Somers   int needed;
375af57ed9fSAtsushi Murai   int mib[6];
376af57ed9fSAtsushi Murai 
377927145beSBrian Somers   if (!VarTerm)
378927145beSBrian Somers     return 1;
379927145beSBrian Somers 
380af57ed9fSAtsushi Murai   mib[0] = CTL_NET;
381af57ed9fSAtsushi Murai   mib[1] = PF_ROUTE;
38253c9f6c0SAtsushi Murai   mib[2] = 0;
38353c9f6c0SAtsushi Murai   mib[3] = 0;
384af57ed9fSAtsushi Murai   mib[4] = NET_RT_DUMP;
38553c9f6c0SAtsushi Murai   mib[5] = 0;
38653c9f6c0SAtsushi Murai   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
387afc7fa2cSBrian Somers     LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
38853c9f6c0SAtsushi Murai     return (1);
38953c9f6c0SAtsushi Murai   }
390af57ed9fSAtsushi Murai   if (needed < 0)
391af57ed9fSAtsushi Murai     return (1);
392af57ed9fSAtsushi Murai   sp = malloc(needed);
393af57ed9fSAtsushi Murai   if (sp == NULL)
394af57ed9fSAtsushi Murai     return (1);
39553c9f6c0SAtsushi Murai   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
396afc7fa2cSBrian Somers     LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
397b0cdb3ceSJordan K. Hubbard     free(sp);
398af57ed9fSAtsushi Murai     return (1);
39953c9f6c0SAtsushi Murai   }
400af57ed9fSAtsushi Murai   ep = sp + needed;
401af57ed9fSAtsushi Murai 
4025d5e5070SBrian Somers   fprintf(VarTerm, "%-20s%-20sFlags  Netif\n", "Destination", "Gateway");
403af57ed9fSAtsushi Murai   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
404af57ed9fSAtsushi Murai     rtm = (struct rt_msghdr *) cp;
4055d5e5070SBrian Somers     wp = (char *)(rtm+1);
4065d5e5070SBrian Somers 
4075d5e5070SBrian Somers     if (rtm->rtm_addrs & RTA_DST) {
4085d5e5070SBrian Somers       sa_dst = (struct sockaddr *)wp;
4095d5e5070SBrian Somers       wp += sa_dst->sa_len;
4105d5e5070SBrian Somers     } else
4115d5e5070SBrian Somers       sa_dst = NULL;
4125d5e5070SBrian Somers 
4135d5e5070SBrian Somers     if (rtm->rtm_addrs & RTA_GATEWAY) {
4145d5e5070SBrian Somers       sa_gw = (struct sockaddr *)wp;
4155d5e5070SBrian Somers       wp += sa_gw->sa_len;
4165d5e5070SBrian Somers     } else
4175d5e5070SBrian Somers       sa_gw = NULL;
4185d5e5070SBrian Somers 
4195d5e5070SBrian Somers     if (rtm->rtm_addrs & RTA_NETMASK) {
4205d5e5070SBrian Somers       sa_mask = (struct sockaddr *)wp;
4215d5e5070SBrian Somers       wp += sa_mask->sa_len;
4225d5e5070SBrian Somers     } else
4235d5e5070SBrian Somers       sa_mask = NULL;
4245d5e5070SBrian Somers 
4255d5e5070SBrian Somers     p_sockaddr(sa_dst, sa_mask, 20);
4265d5e5070SBrian Somers     p_sockaddr(sa_gw, NULL, 20);
4275d5e5070SBrian Somers 
428d27d502cSBrian Somers     p_flags(rtm->rtm_flags, 6);
4295d5e5070SBrian Somers     fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index));
430af57ed9fSAtsushi Murai   }
431b0cdb3ceSJordan K. Hubbard   free(sp);
432927145beSBrian Somers   return 0;
433af57ed9fSAtsushi Murai }
434af57ed9fSAtsushi Murai 
435af57ed9fSAtsushi Murai /*
436af57ed9fSAtsushi Murai  *  Delete routes associated with our interface
437af57ed9fSAtsushi Murai  */
438af57ed9fSAtsushi Murai void
439944f7098SBrian Somers DeleteIfRoutes(int all)
440af57ed9fSAtsushi Murai {
441af57ed9fSAtsushi Murai   struct rt_msghdr *rtm;
442af57ed9fSAtsushi Murai   struct sockaddr *sa;
443f01e577bSBrian Somers   struct in_addr sa_dst, sa_none;
44432ca3341SBrian Somers   int needed, pass;
445af57ed9fSAtsushi Murai   char *sp, *cp, *ep;
446af57ed9fSAtsushi Murai   int mib[6];
447af57ed9fSAtsushi Murai 
448927145beSBrian Somers   LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
449f01e577bSBrian Somers   sa_none.s_addr = INADDR_ANY;
450927145beSBrian Somers 
451af57ed9fSAtsushi Murai   mib[0] = CTL_NET;
452af57ed9fSAtsushi Murai   mib[1] = PF_ROUTE;
45353c9f6c0SAtsushi Murai   mib[2] = 0;
45453c9f6c0SAtsushi Murai   mib[3] = 0;
455af57ed9fSAtsushi Murai   mib[4] = NET_RT_DUMP;
45653c9f6c0SAtsushi Murai   mib[5] = 0;
45753c9f6c0SAtsushi Murai   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
458afc7fa2cSBrian Somers     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
459afc7fa2cSBrian Somers 	      strerror(errno));
46053c9f6c0SAtsushi Murai     return;
46153c9f6c0SAtsushi Murai   }
462af57ed9fSAtsushi Murai   if (needed < 0)
463af57ed9fSAtsushi Murai     return;
464af57ed9fSAtsushi Murai 
465af57ed9fSAtsushi Murai   sp = malloc(needed);
466af57ed9fSAtsushi Murai   if (sp == NULL)
467af57ed9fSAtsushi Murai     return;
468af57ed9fSAtsushi Murai 
469af57ed9fSAtsushi Murai   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
470afc7fa2cSBrian Somers     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
471afc7fa2cSBrian Somers 	      strerror(errno));
472af57ed9fSAtsushi Murai     free(sp);
473af57ed9fSAtsushi Murai     return;
474af57ed9fSAtsushi Murai   }
475af57ed9fSAtsushi Murai   ep = sp + needed;
476af57ed9fSAtsushi Murai 
47732ca3341SBrian Somers   for (pass = 0; pass < 2; pass++) {
47832ca3341SBrian Somers     /*
47932ca3341SBrian Somers      * We do 2 passes.  The first deletes all cloned routes.  The second
48032ca3341SBrian Somers      * deletes all non-cloned routes.  This is necessary to avoid
48132ca3341SBrian Somers      * potential errors from trying to delete route X after route Y where
48232ca3341SBrian Somers      * route X was cloned from route Y (which is no longer there).
48332ca3341SBrian Somers      */
48432ca3341SBrian Somers     if (RTF_WASCLONED == 0 && pass == 0)
48532ca3341SBrian Somers       /* So we can't tell ! */
48632ca3341SBrian Somers       continue;
487af57ed9fSAtsushi Murai     for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
488af57ed9fSAtsushi Murai       rtm = (struct rt_msghdr *) cp;
489af57ed9fSAtsushi Murai       sa = (struct sockaddr *) (rtm + 1);
49032ca3341SBrian Somers       LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s),"
49132ca3341SBrian Somers                 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
4925d5e5070SBrian Somers                 Index2Nam(rtm->rtm_index), rtm->rtm_flags,
4939b5a20e1SBrian Somers 	        inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
4945d5e5070SBrian Somers       if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
4955d5e5070SBrian Somers 	  rtm->rtm_index == IfIndex &&
496af57ed9fSAtsushi Murai 	  (all || (rtm->rtm_flags & RTF_GATEWAY))) {
4975d5e5070SBrian Somers         sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
4985d5e5070SBrian Somers         sa = (struct sockaddr *)((char *)sa + sa->sa_len);
499f01e577bSBrian Somers         if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
50032ca3341SBrian Somers           if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
50132ca3341SBrian Somers               (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
50232ca3341SBrian Somers             LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass);
503f01e577bSBrian Somers             OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none);
5045d5e5070SBrian Somers           } else
50532ca3341SBrian Somers             LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass);
50632ca3341SBrian Somers         } else
507f01e577bSBrian Somers           LogPrintf(LogDEBUG,
508f01e577bSBrian Somers                     "DeleteIfRoutes: Can't remove routes of %d family !\n",
509f01e577bSBrian Somers                     sa->sa_family);
510af57ed9fSAtsushi Murai       }
511af57ed9fSAtsushi Murai     }
51232ca3341SBrian Somers   }
513af57ed9fSAtsushi Murai   free(sp);
514af57ed9fSAtsushi Murai }
515af57ed9fSAtsushi Murai 
516af57ed9fSAtsushi Murai int
517944f7098SBrian Somers GetIfIndex(char *name)
518af57ed9fSAtsushi Murai {
5195d5e5070SBrian Somers   int idx;
520b6e82f33SBrian Somers   const char *got;
521944f7098SBrian Somers 
5229cb1d89eSBrian Somers   idx = 1;
5235d5e5070SBrian Somers   while (strcmp(got = Index2Nam(idx), "???"))
5245d5e5070SBrian Somers     if (!strcmp(got, name))
5255d5e5070SBrian Somers       return IfIndex = idx;
5265d5e5070SBrian Somers     else
5275d5e5070SBrian Somers       idx++;
5285d5e5070SBrian Somers   return -1;
529af57ed9fSAtsushi Murai }
530bcc332bdSBrian Somers 
531bcc332bdSBrian Somers struct in_addr
532bcc332bdSBrian Somers ChooseHisAddr(const struct in_addr gw)
533bcc332bdSBrian Somers {
534bcc332bdSBrian Somers   struct in_addr try;
535bcc332bdSBrian Somers   int f;
536bcc332bdSBrian Somers 
537bcc332bdSBrian Somers   for (f = 0; f < DefHisChoice.nItems; f++) {
538bcc332bdSBrian Somers     try = iplist_next(&DefHisChoice);
539bcc332bdSBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
540bcc332bdSBrian Somers               f, inet_ntoa(try));
541bcc332bdSBrian Somers     if (OsTrySetIpaddress(gw, try) == 0) {
542bcc332bdSBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
543bcc332bdSBrian Somers                 inet_ntoa(try));
544bcc332bdSBrian Somers       break;
545bcc332bdSBrian Somers     }
546bcc332bdSBrian Somers   }
547bcc332bdSBrian Somers 
548bcc332bdSBrian Somers   if (f == DefHisChoice.nItems) {
549bcc332bdSBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
550bcc332bdSBrian Somers     try.s_addr = INADDR_ANY;
551bcc332bdSBrian Somers   }
552bcc332bdSBrian Somers 
553bcc332bdSBrian Somers   return try;
554bcc332bdSBrian Somers }
555