xref: /freebsd/usr.sbin/ppp/route.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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.6 1996/05/11 20:48:42 phk 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     return(1);
202   }
203 #else
204   if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
205     return(1);
206 #endif
207   ep = sp + needed;
208 
209   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
210     rtm = (struct rt_msghdr *)cp;
211     sa = (struct sockaddr *)(rtm + 1);
212     mask = 0xffffffff;
213     if (rtm->rtm_addrs == RTA_DST)
214       p_sockaddr(sa, 36);
215     else {
216       wp = (u_char *)cp + rtm->rtm_msglen;
217       p_sockaddr(sa, 16);
218       if (sa->sa_len == 0)
219 	sa->sa_len = sizeof(long);
220       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
221       p_sockaddr(sa, 18);
222       lp = (int *)(sa->sa_len + (char *)sa);
223       if ((char *)lp < (char *)wp && *lp) {
224 #ifdef DEBUG
225 	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
226 #endif
227 	wp = (u_char *)(lp + 1);
228 	mask = 0;
229 	for (nb = *lp; nb > 4; nb--) {
230 	  mask <<= 8;
231 	  mask |= *wp++;
232 	}
233 	for (nb = 8 - *lp; nb > 0; nb--)
234 	  mask <<= 8;
235       }
236     }
237     printf("%08lx  ", mask);
238     p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
239     printf("(%d)\n", rtm->rtm_index);
240   }
241 
242   return(1);
243 }
244 
245 /*
246  *  Delete routes associated with our interface
247  */
248 void
249 DeleteIfRoutes(all)
250 int all;
251 {
252   struct rt_msghdr *rtm;
253   struct sockaddr *sa;
254   struct in_addr dstnet, gateway, maddr;
255   int needed;
256   char *sp, *cp, *ep;
257   u_long mask;
258   int *lp, nb;
259   u_char *wp;
260 #if (BSD >= 199306)
261   int mib[6];
262 #endif
263 
264 #ifdef DEBUG
265   logprintf("DeleteIfRoutes (%d)\n", IfIndex);
266 #endif
267 #if (BSD >= 199306)
268   mib[0] = CTL_NET;
269   mib[1] = PF_ROUTE;
270   mib[2] = 0;
271   mib[3] = 0;
272   mib[4] = NET_RT_DUMP;
273   mib[5] = 0;
274   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
275     perror("sysctl-estimate");
276     return;
277   }
278 #else
279   needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
280 #endif
281 
282   if (needed < 0)
283     return;
284 
285   sp = malloc(needed);
286   if (sp == NULL)
287     return;
288 
289 #if (BSD >= 199306)
290   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
291     free(sp);
292     perror("sysctl-getroute");
293     return;
294   }
295 #else
296   if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
297     free(sp);
298     return;
299   }
300 #endif
301   ep = sp + needed;
302 
303   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
304     rtm = (struct rt_msghdr *)cp;
305     sa = (struct sockaddr *)(rtm + 1);
306 #ifdef DEBUG
307     logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
308 	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
309 	((struct sockaddr_in *)sa)->sin_addr);
310 #endif
311     if (rtm->rtm_addrs != RTA_DST &&
312        (rtm->rtm_index == IfIndex) &&
313        (all || (rtm->rtm_flags & RTF_GATEWAY))) {
314       dstnet = ((struct sockaddr_in *)sa)->sin_addr;
315       wp = (u_char *)cp + rtm->rtm_msglen;
316       if (sa->sa_len == 0)
317 	sa->sa_len = sizeof(long);
318       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
319       gateway = ((struct sockaddr_in *)sa)->sin_addr;
320       lp = (int *)(sa->sa_len + (char *)sa);
321       mask = 0;
322       if ((char *)lp < (char *)wp && *lp) {
323 #ifdef DEBUG
324 	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
325 #endif
326 	wp = (u_char *)(lp + 1);
327 	for (nb = *lp; nb > 4; nb--) {
328 	  mask <<= 8;
329 	  mask |= *wp++;
330 	}
331 	for (nb = 8 - *lp; nb > 0; nb--)
332 	  mask <<= 8;
333       }
334 #ifdef DEBUG
335       logprintf("## %s ", inet_ntoa(dstnet));
336       logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
337 #endif
338       if (dstnet.s_addr == INADDR_ANY) {
339         gateway.s_addr = INADDR_ANY;
340         mask = INADDR_ANY;
341       }
342       maddr.s_addr = htonl(mask);
343       OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
344     }
345 #ifdef DEBUG
346     else if (rtm->rtm_index == IfIndex) {
347       logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
348     }
349 #endif
350   }
351   free(sp);
352 }
353 
354 int
355 GetIfIndex(name)
356 char *name;
357 {
358   struct ifreq *ifrp;
359   int s, len, elen, index;
360   struct ifconf ifconfs;
361   struct ifreq reqbuf[32];
362 
363   s = socket(AF_INET, SOCK_DGRAM, 0);
364   if (s < 0) {
365     perror("socket");
366     return(-1);
367   }
368 
369   ifconfs.ifc_len = sizeof(reqbuf);
370   ifconfs.ifc_buf = (caddr_t)reqbuf;
371   if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
372     perror("IFCONF");
373     return(-1);
374   }
375 
376   ifrp = ifconfs.ifc_req;
377 
378   index = 1;
379   for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
380     elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
381     if (ifrp->ifr_addr.sa_family == AF_LINK) {
382 #ifdef DEBUG
383       logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
384 	   ifrp->ifr_addr.sa_family, elen);
385 #endif
386       if (strcmp(ifrp->ifr_name, name) == 0) {
387         IfIndex = index;
388         return(index);
389       }
390       index++;
391     }
392 
393     len -= elen;
394     ifrp = (struct ifreq *)((char *)ifrp + elen);
395     ifrp++;
396   }
397 
398   close(s);
399   return(-1);
400 }
401