xref: /freebsd/usr.sbin/ppp/route.c (revision 952d112864d8008aa87278a30a539d888a8493cd)
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$
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 #if (BSD >= 199306)
29 #include <sys/sysctl.h>
30 #else
31 #include <sys/kinfo.h>
32 #endif
33 #include <sys/time.h>
34 
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include <net/route.h>
42 #include <net/if.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 
47 #include "log.h"
48 
49 static int IfIndex;
50 
51 struct rtmsg {
52   struct rt_msghdr m_rtm;
53   char m_space[64];
54 };
55 
56 static int seqno;
57 
58 void
59 OsSetRoute(cmd, dst, gateway, mask)
60 int cmd;
61 struct in_addr dst;
62 struct in_addr gateway;
63 struct in_addr mask;
64 {
65   struct rtmsg rtmes;
66   int s, nb, wb;
67   char *cp;
68   u_long *lp;
69   struct sockaddr_in rtdata;
70 
71   s = socket(PF_ROUTE, SOCK_RAW, 0);
72   if (s < 0)
73     logprintf("socket\n");
74 
75   bzero(&rtmes, sizeof(rtmes));
76   rtmes.m_rtm.rtm_version = RTM_VERSION;
77   rtmes.m_rtm.rtm_type = cmd;
78   rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
79   if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
80   rtmes.m_rtm.rtm_seq = ++seqno;
81   rtmes.m_rtm.rtm_pid = getpid();
82   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
83 
84   bzero(&rtdata, sizeof(rtdata));
85   rtdata.sin_len = 16;
86   rtdata.sin_family = AF_INET;
87   rtdata.sin_port = 0;
88   rtdata.sin_addr = dst;
89 
90   cp = rtmes.m_space;
91   bcopy(&rtdata, cp, 16);
92   cp += 16;
93   if (gateway.s_addr) {
94     rtdata.sin_addr = gateway;
95     bcopy(&rtdata, cp, 16);
96     cp += 16;
97   }
98 
99   if (dst.s_addr == INADDR_ANY)
100     mask.s_addr = INADDR_ANY;
101 
102   lp = (u_long *)cp;
103 
104   if (mask.s_addr) {
105     *lp++ = 8;
106     cp += sizeof(int);
107     *lp = mask.s_addr;
108   } else
109     *lp = 0;
110   cp += sizeof(u_long);
111 
112   nb = cp - (char *)&rtmes;
113   rtmes.m_rtm.rtm_msglen = nb;
114   wb = write(s, &rtmes, nb);
115   if (wb < 0) {
116      LogPrintf(LOG_TCPIP_BIT, "Already set route addr dst=%x, gateway=%x\n"
117          ,dst.s_addr, gateway.s_addr);
118   }
119 #ifdef DEBUG
120   logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
121 #endif
122   close(s);
123 }
124 
125 static void
126 p_sockaddr(sa, width)
127 struct sockaddr *sa;
128 int width;
129 {
130   register char *cp;
131   register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
132 
133   cp = (sin->sin_addr.s_addr == 0) ? "default" :
134 	   inet_ntoa(sin->sin_addr);
135   printf("%-*.*s ", width, width, cp);
136 }
137 
138 struct bits {
139   short b_mask;
140   char  b_val;
141 } bits[] = {
142   { RTF_UP,	  'U' },
143   { RTF_GATEWAY,  'G' },
144   { RTF_HOST,	  'H' },
145   { RTF_DYNAMIC,  'D' },
146   { RTF_MODIFIED, 'M' },
147   { RTF_CLONING,  'C' },
148   { RTF_XRESOLVE, 'X' },
149   { RTF_LLINFO,   'L' },
150   { RTF_REJECT,   'R' },
151   { 0 }
152 };
153 
154 static void
155 p_flags(f, format)
156 register int f;
157 char *format;
158 {
159   char name[33], *flags;
160   register struct bits *p = bits;
161 
162   for (flags = name; p->b_mask; p++)
163     if (p->b_mask & f)
164       *flags++ = p->b_val;
165   *flags = '\0';
166   printf(format, name);
167 }
168 
169 int
170 ShowRoute()
171 {
172   struct rt_msghdr *rtm;
173   struct sockaddr *sa;
174   char *sp, *ep, *cp;
175   u_char *wp;
176   int *lp;
177   int needed, nb;
178   u_long mask;
179 #if (BSD >= 199306)
180   int mib[6];
181 #endif
182 
183 #if (BSD >= 199306)
184   mib[0] = CTL_NET;
185   mib[1] = PF_ROUTE;
186   mib[2] = 0;
187   mib[3] = 0;
188   mib[4] = NET_RT_DUMP;
189   mib[5] = 0;
190   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
191     perror("sysctl-estimate");
192     return(1);
193   }
194 #else
195   needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
196 #endif
197   if (needed < 0)
198     return(1);
199   sp = malloc(needed);
200   if (sp == NULL)
201     return(1);
202 #if (BSD >= 199306)
203   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
204     perror("sysctl-getroute");
205     free(sp);
206     return(1);
207   }
208 #else
209   if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
210     free(sp);
211     return(1);
212 #endif
213   ep = sp + needed;
214 
215   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
216     rtm = (struct rt_msghdr *)cp;
217     sa = (struct sockaddr *)(rtm + 1);
218     mask = 0xffffffff;
219     if (rtm->rtm_addrs == RTA_DST)
220       p_sockaddr(sa, 36);
221     else {
222       wp = (u_char *)cp + rtm->rtm_msglen;
223       p_sockaddr(sa, 16);
224       if (sa->sa_len == 0)
225 	sa->sa_len = sizeof(long);
226       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
227       p_sockaddr(sa, 18);
228       lp = (int *)(sa->sa_len + (char *)sa);
229       if ((char *)lp < (char *)wp && *lp) {
230 #ifdef DEBUG
231 	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
232 #endif
233 	wp = (u_char *)(lp + 1);
234 	mask = 0;
235 	for (nb = *(char *)lp; nb > 4; nb--) {
236 	  mask <<= 8;
237 	  mask |= *wp++;
238 	}
239 	for (nb = 8 - *(char *)lp; nb > 0; nb--)
240 	  mask <<= 8;
241       }
242     }
243     printf("%08lx  ", mask);
244     p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
245     printf("(%d)\n", rtm->rtm_index);
246   }
247   free(sp);
248   return(1);
249 }
250 
251 /*
252  *  Delete routes associated with our interface
253  */
254 void
255 DeleteIfRoutes(all)
256 int all;
257 {
258   struct rt_msghdr *rtm;
259   struct sockaddr *sa;
260   struct in_addr dstnet, gateway, maddr;
261   int needed;
262   char *sp, *cp, *ep;
263   u_long mask;
264   int *lp, nb;
265   u_char *wp;
266 #if (BSD >= 199306)
267   int mib[6];
268 #endif
269 
270 #ifdef DEBUG
271   logprintf("DeleteIfRoutes (%d)\n", IfIndex);
272 #endif
273 #if (BSD >= 199306)
274   mib[0] = CTL_NET;
275   mib[1] = PF_ROUTE;
276   mib[2] = 0;
277   mib[3] = 0;
278   mib[4] = NET_RT_DUMP;
279   mib[5] = 0;
280   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
281     perror("sysctl-estimate");
282     return;
283   }
284 #else
285   needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
286 #endif
287 
288   if (needed < 0)
289     return;
290 
291   sp = malloc(needed);
292   if (sp == NULL)
293     return;
294 
295 #if (BSD >= 199306)
296   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
297     free(sp);
298     perror("sysctl-getroute");
299     return;
300   }
301 #else
302   if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
303     free(sp);
304     return;
305   }
306 #endif
307   ep = sp + needed;
308 
309   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
310     rtm = (struct rt_msghdr *)cp;
311     sa = (struct sockaddr *)(rtm + 1);
312 #ifdef DEBUG
313     logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
314 	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
315 	((struct sockaddr_in *)sa)->sin_addr);
316 #endif
317     if (rtm->rtm_addrs != RTA_DST &&
318        (rtm->rtm_index == IfIndex) &&
319        (all || (rtm->rtm_flags & RTF_GATEWAY))) {
320       dstnet = ((struct sockaddr_in *)sa)->sin_addr;
321       wp = (u_char *)cp + rtm->rtm_msglen;
322       if (sa->sa_len == 0)
323 	sa->sa_len = sizeof(long);
324       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
325       gateway = ((struct sockaddr_in *)sa)->sin_addr;
326       lp = (int *)(sa->sa_len + (char *)sa);
327       mask = 0;
328       if ((char *)lp < (char *)wp && *lp) {
329 #ifdef DEBUG
330 	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
331 #endif
332 	wp = (u_char *)(lp + 1);
333 	for (nb = *lp; nb > 4; nb--) {
334 	  mask <<= 8;
335 	  mask |= *wp++;
336 	}
337 	for (nb = 8 - *lp; nb > 0; nb--)
338 	  mask <<= 8;
339       }
340 #ifdef DEBUG
341       logprintf("## %s ", inet_ntoa(dstnet));
342       logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
343 #endif
344       if (dstnet.s_addr == INADDR_ANY) {
345         gateway.s_addr = INADDR_ANY;
346         mask = INADDR_ANY;
347       }
348       maddr.s_addr = htonl(mask);
349       OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
350     }
351 #ifdef DEBUG
352     else if (rtm->rtm_index == IfIndex) {
353       logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
354     }
355 #endif
356   }
357   free(sp);
358 }
359 
360  /*
361   * 960603 - Modified to use dynamic buffer allocator as in ifconfig
362   */
363 
364 int
365 GetIfIndex(name)
366 char *name;
367 {
368   char *buffer;
369   struct ifreq *ifrp;
370   int s, len, elen, index;
371   struct ifconf ifconfs;
372   /* struct ifreq reqbuf[256]; -- obsoleted :) */
373   int oldbufsize, bufsize = sizeof(struct ifreq);
374 
375   s = socket(AF_INET, SOCK_DGRAM, 0);
376   if (s < 0) {
377     perror("socket");
378     return(-1);
379   }
380 
381   buffer = malloc(bufsize);   /* allocate first buffer */
382   ifconfs.ifc_len = bufsize;  /* Initial setting */
383   /*
384    * Iterate through here until we don't get many more data
385    */
386 
387   do {
388       oldbufsize = ifconfs.ifc_len;
389       bufsize += 1+sizeof(struct ifreq);
390       buffer = realloc((void *)buffer, bufsize);      /* Make it bigger */
391 #ifdef DEBUG
392       logprintf ("Growing buffer to %d\n", bufsize);
393 #endif
394       ifconfs.ifc_len = bufsize;
395       ifconfs.ifc_buf = buffer;
396       if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
397           perror("IFCONF");
398           free(buffer);
399           return(-1);
400       }
401   } while (ifconfs.ifc_len > oldbufsize);
402 
403   ifrp = ifconfs.ifc_req;
404 
405   index = 1;
406   for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
407     elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
408     if (ifrp->ifr_addr.sa_family == AF_LINK) {
409 #ifdef DEBUG
410       logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
411 	   ifrp->ifr_addr.sa_family, elen);
412 #endif
413       if (strcmp(ifrp->ifr_name, name) == 0) {
414         IfIndex = index;
415       free(buffer);
416         return(index);
417       }
418       index++;
419     }
420 
421     len -= elen;
422     ifrp = (struct ifreq *)((char *)ifrp + elen);
423     ifrp++;
424   }
425 
426   close(s);
427   free(buffer);
428   return(-1);
429 }
430