xref: /freebsd/usr.sbin/ppp/route.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
1 /*
2  *	      PPP Routing related Module
3  *
4  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5  *
6  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the Internet Initiative Japan, Inc.  The name of the
14  * IIJ may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * $Id: route.c,v 1.15 1997/06/13 03:59:36 brian Exp $
21  *
22  */
23 #include <sys/types.h>
24 #include <machine/endian.h>
25 #include <sys/ioctl.h>
26 #include <sys/param.h>
27 #include <sys/socket.h>
28 #include <sys/sysctl.h>
29 #include <sys/time.h>
30 
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include <net/route.h>
38 #include <net/if.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 
43 #include "log.h"
44 #include "loadalias.h"
45 #include "vars.h"
46 
47 static int IfIndex;
48 
49 struct rtmsg {
50   struct rt_msghdr m_rtm;
51   char m_space[64];
52 };
53 
54 static int seqno;
55 
56 void
57 OsSetRoute(cmd, dst, gateway, mask)
58 int cmd;
59 struct in_addr dst;
60 struct in_addr gateway;
61 struct in_addr mask;
62 {
63   struct rtmsg rtmes;
64   int s, nb, wb;
65   char *cp;
66   u_long *lp;
67   struct sockaddr_in rtdata;
68 
69   s = socket(PF_ROUTE, SOCK_RAW, 0);
70   if (s < 0)
71     LogPrintf(LogERROR, "socket: %s", strerror(errno));
72 
73   bzero(&rtmes, sizeof(rtmes));
74   rtmes.m_rtm.rtm_version = RTM_VERSION;
75   rtmes.m_rtm.rtm_type = cmd;
76   rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
77   rtmes.m_rtm.rtm_seq = ++seqno;
78   rtmes.m_rtm.rtm_pid = getpid();
79   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
80 
81   bzero(&rtdata, sizeof(rtdata));
82   rtdata.sin_len = 16;
83   rtdata.sin_family = AF_INET;
84   rtdata.sin_port = 0;
85   rtdata.sin_addr = dst;
86 
87   cp = rtmes.m_space;
88   bcopy(&rtdata, cp, 16);
89   cp += 16;
90   if (gateway.s_addr) {
91     rtdata.sin_addr = gateway;
92     bcopy(&rtdata, cp, 16);
93     cp += 16;
94   }
95 
96   if (dst.s_addr == INADDR_ANY)
97     mask.s_addr = INADDR_ANY;
98 
99   lp = (u_long *)cp;
100 
101   if (mask.s_addr) {
102     *lp++ = 8;
103     cp += sizeof(int);
104     *lp = mask.s_addr;
105   } else
106     *lp = 0;
107   cp += sizeof(u_long);
108 
109   nb = cp - (char *)&rtmes;
110   rtmes.m_rtm.rtm_msglen = nb;
111   wb = write(s, &rtmes, nb);
112   if (wb < 0) {
113     LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
114     LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
115     LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
116     switch(rtmes.m_rtm.rtm_errno) {
117       case EEXIST:
118         LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
119         break;
120       case ESRCH:
121         LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
122         break;
123       case ENOBUFS:
124       default:
125         LogPrintf(LogTCPIP, "Add/Del route failed: %s\n",
126                   strerror(rtmes.m_rtm.rtm_errno));
127         break;
128     }
129   }
130 
131   LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb,
132             dst.s_addr, gateway.s_addr);
133   close(s);
134 }
135 
136 static void
137 p_sockaddr(sa, width)
138 struct sockaddr *sa;
139 int width;
140 {
141   if (VarTerm) {
142     register char *cp;
143     register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
144 
145     cp = (sin->sin_addr.s_addr == 0) ? "default" :
146 	   inet_ntoa(sin->sin_addr);
147     fprintf(VarTerm, "%-*.*s ", width, width, cp);
148   }
149 }
150 
151 struct bits {
152   short b_mask;
153   char  b_val;
154 } bits[] = {
155   { RTF_UP,	  'U' },
156   { RTF_GATEWAY,  'G' },
157   { RTF_HOST,	  'H' },
158   { RTF_DYNAMIC,  'D' },
159   { RTF_MODIFIED, 'M' },
160   { RTF_CLONING,  'C' },
161   { RTF_XRESOLVE, 'X' },
162   { RTF_LLINFO,   'L' },
163   { RTF_REJECT,   'R' },
164   { 0 }
165 };
166 
167 static void
168 p_flags(f, format)
169 register int f;
170 char *format;
171 {
172   if (VarTerm) {
173     char name[33], *flags;
174     register struct bits *p = bits;
175 
176     for (flags = name; p->b_mask; p++)
177       if (p->b_mask & f)
178         *flags++ = p->b_val;
179     *flags = '\0';
180     fprintf(VarTerm, format, name);
181   }
182 }
183 
184 int
185 ShowRoute()
186 {
187   struct rt_msghdr *rtm;
188   struct sockaddr *sa;
189   char *sp, *ep, *cp;
190   u_char *wp;
191   int *lp;
192   int needed, nb;
193   u_long mask;
194   int mib[6];
195 
196   if (!VarTerm)
197     return 1;
198 
199   mib[0] = CTL_NET;
200   mib[1] = PF_ROUTE;
201   mib[2] = 0;
202   mib[3] = 0;
203   mib[4] = NET_RT_DUMP;
204   mib[5] = 0;
205   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
206     LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno));
207     return(1);
208   }
209 
210   if (needed < 0)
211     return(1);
212   sp = malloc(needed);
213   if (sp == NULL)
214     return(1);
215   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
216     LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno));
217     free(sp);
218     return(1);
219   }
220 
221   ep = sp + needed;
222 
223   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
224     rtm = (struct rt_msghdr *)cp;
225     sa = (struct sockaddr *)(rtm + 1);
226     mask = 0xffffffff;
227     if (rtm->rtm_addrs == RTA_DST)
228       p_sockaddr(sa, 36);
229     else {
230       wp = (u_char *)cp + rtm->rtm_msglen;
231       p_sockaddr(sa, 16);
232       if (sa->sa_len == 0)
233 	sa->sa_len = sizeof(long);
234       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
235       p_sockaddr(sa, 18);
236       lp = (int *)(sa->sa_len + (char *)sa);
237       if ((char *)lp < (char *)wp && *lp) {
238 	LogPrintf(LogDEBUG, " flag = %x, rest = %d", rtm->rtm_flags, *lp);
239 	wp = (u_char *)(lp + 1);
240 	mask = 0;
241 	for (nb = *(char *)lp; nb > 4; nb--) {
242 	  mask <<= 8;
243 	  mask |= *wp++;
244 	}
245 	for (nb = 8 - *(char *)lp; nb > 0; nb--)
246 	  mask <<= 8;
247       }
248     }
249     fprintf(VarTerm, "%08lx  ", mask);
250     p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
251     fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
252   }
253   free(sp);
254   return 0;
255 }
256 
257 /*
258  *  Delete routes associated with our interface
259  */
260 void
261 DeleteIfRoutes(all)
262 int all;
263 {
264   struct rt_msghdr *rtm;
265   struct sockaddr *sa;
266   struct in_addr dstnet, gateway, maddr;
267   int needed;
268   char *sp, *cp, *ep;
269   u_long mask;
270   int *lp, nb;
271   u_char *wp;
272   int mib[6];
273 
274   LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
275 
276   mib[0] = CTL_NET;
277   mib[1] = PF_ROUTE;
278   mib[2] = 0;
279   mib[3] = 0;
280   mib[4] = NET_RT_DUMP;
281   mib[5] = 0;
282   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
283     LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno));
284     return;
285   }
286 
287   if (needed < 0)
288     return;
289 
290   sp = malloc(needed);
291   if (sp == NULL)
292     return;
293 
294   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
295     LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno));
296     free(sp);
297     return;
298   }
299   ep = sp + needed;
300 
301   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
302     rtm = (struct rt_msghdr *)cp;
303     sa = (struct sockaddr *)(rtm + 1);
304     LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
305 			" dstnet: %s\n",
306 			rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
307 			inet_ntoa(((struct sockaddr_in *)sa)->sin_addr));
308     if (rtm->rtm_addrs != RTA_DST &&
309        (rtm->rtm_index == IfIndex) &&
310        (all || (rtm->rtm_flags & RTF_GATEWAY))) {
311       LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
312       dstnet = ((struct sockaddr_in *)sa)->sin_addr;
313       wp = (u_char *)cp + rtm->rtm_msglen;
314       if (sa->sa_len == 0)
315 	sa->sa_len = sizeof(long);
316       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
317       gateway = ((struct sockaddr_in *)sa)->sin_addr;
318       lp = (int *)(sa->sa_len + (char *)sa);
319       mask = 0;
320       if ((char *)lp < (char *)wp && *lp) {
321 	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d",
322 		  rtm->rtm_flags, *lp);
323 	wp = (u_char *)(lp + 1);
324 	for (nb = *lp; nb > 4; nb--) {
325 	  mask <<= 8;
326 	  mask |= *wp++;
327 	}
328 	for (nb = 8 - *lp; nb > 0; nb--)
329 	  mask <<= 8;
330       }
331       LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
332       LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
333       LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
334       if (dstnet.s_addr == INADDR_ANY)
335         mask = INADDR_ANY;
336       maddr.s_addr = htonl(mask);
337       OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
338     }
339   }
340   free(sp);
341 }
342 
343  /*
344   * 960603 - Modified to use dynamic buffer allocator as in ifconfig
345   */
346 
347 int
348 GetIfIndex(name)
349 char *name;
350 {
351   char *buffer;
352   struct ifreq *ifrp;
353   int s, len, elen, index;
354   struct ifconf ifconfs;
355   /* struct ifreq reqbuf[256]; -- obsoleted :) */
356   int oldbufsize, bufsize = sizeof(struct ifreq);
357 
358   s = socket(AF_INET, SOCK_DGRAM, 0);
359   if (s < 0) {
360     LogPrintf(LogERROR, "socket: %s", strerror(errno));
361     return(-1);
362   }
363 
364   buffer = malloc(bufsize);   /* allocate first buffer */
365   ifconfs.ifc_len = bufsize;  /* Initial setting */
366   /*
367    * Iterate through here until we don't get many more data
368    */
369 
370   do {
371       oldbufsize = ifconfs.ifc_len;
372       bufsize += 1+sizeof(struct ifreq);
373       buffer = realloc((void *)buffer, bufsize);      /* Make it bigger */
374       LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
375       ifconfs.ifc_len = bufsize;
376       ifconfs.ifc_buf = buffer;
377       if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
378           LogPrintf(LogERROR, "ioctl(SIOCGIFCONF): %s", strerror(errno));
379           free(buffer);
380           return(-1);
381       }
382   } while (ifconfs.ifc_len > oldbufsize);
383 
384   ifrp = ifconfs.ifc_req;
385 
386   index = 1;
387   for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
388     elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
389     if (ifrp->ifr_addr.sa_family == AF_LINK) {
390       LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
391 		index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
392 		ifrp->ifr_addr.sa_family, elen);
393       if (strcmp(ifrp->ifr_name, name) == 0) {
394         IfIndex = index;
395 	free(buffer);
396         return(index);
397       }
398       index++;
399     }
400 
401     len -= elen;
402     ifrp = (struct ifreq *)((char *)ifrp + elen);
403     ifrp++;
404   }
405 
406   close(s);
407   free(buffer);
408   return(-1);
409 }
410