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