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