xref: /freebsd/usr.sbin/ppp/route.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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.18 1997/08/25 00:29:26 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(int cmd,
58 	   struct in_addr dst,
59 	   struct in_addr gateway,
60 	   struct in_addr mask)
61 {
62   struct rtmsg rtmes;
63   int s, nb, wb;
64   char *cp;
65   u_long *lp;
66   struct sockaddr_in rtdata;
67 
68   s = socket(PF_ROUTE, SOCK_RAW, 0);
69   if (s < 0) {
70     LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
71     return;
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   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(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
113     LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
114     LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
115     switch (rtmes.m_rtm.rtm_errno) {
116     case EEXIST:
117       LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
118       break;
119     case ESRCH:
120       LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
121       break;
122     case ENOBUFS:
123     default:
124       LogPrintf(LogTCPIP, "Add/Del route failed: %s\n",
125 		strerror(rtmes.m_rtm.rtm_errno));
126       break;
127     }
128   }
129   LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb,
130 	    dst.s_addr, gateway.s_addr);
131   close(s);
132 }
133 
134 static void
135 p_sockaddr(struct sockaddr * sa, int width)
136 {
137   if (VarTerm) {
138     register char *cp;
139     register struct sockaddr_in *sin = (struct sockaddr_in *) sa;
140 
141     cp = (sin->sin_addr.s_addr == 0) ? "default" :
142       inet_ntoa(sin->sin_addr);
143     fprintf(VarTerm, "%-*.*s ", width, width, cp);
144   }
145 }
146 
147 struct bits {
148   short b_mask;
149   char b_val;
150 }    bits[] = {
151 
152   {
153     RTF_UP, 'U'
154   },
155   {
156     RTF_GATEWAY, 'G'
157   },
158   {
159     RTF_HOST, 'H'
160   },
161   {
162     RTF_DYNAMIC, 'D'
163   },
164   {
165     RTF_MODIFIED, 'M'
166   },
167   {
168     RTF_CLONING, 'C'
169   },
170   {
171     RTF_XRESOLVE, 'X'
172   },
173   {
174     RTF_LLINFO, 'L'
175   },
176   {
177     RTF_REJECT, 'R'
178   },
179   {
180     0
181   }
182 };
183 
184 static void
185 p_flags(int f, char *format)
186 {
187   if (VarTerm) {
188     char name[33], *flags;
189     register struct bits *p = bits;
190 
191     for (flags = name; p->b_mask; p++)
192       if (p->b_mask & f)
193 	*flags++ = p->b_val;
194     *flags = '\0';
195     fprintf(VarTerm, format, name);
196   }
197 }
198 
199 int
200 ShowRoute()
201 {
202   struct rt_msghdr *rtm;
203   struct sockaddr *sa;
204   char *sp, *ep, *cp;
205   u_char *wp;
206   int *lp;
207   int needed, nb;
208   u_long mask;
209   int mib[6];
210 
211   if (!VarTerm)
212     return 1;
213 
214   mib[0] = CTL_NET;
215   mib[1] = PF_ROUTE;
216   mib[2] = 0;
217   mib[3] = 0;
218   mib[4] = NET_RT_DUMP;
219   mib[5] = 0;
220   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
221     LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
222     return (1);
223   }
224   if (needed < 0)
225     return (1);
226   sp = malloc(needed);
227   if (sp == NULL)
228     return (1);
229   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
230     LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
231     free(sp);
232     return (1);
233   }
234   ep = sp + needed;
235 
236   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
237     rtm = (struct rt_msghdr *) cp;
238     sa = (struct sockaddr *) (rtm + 1);
239     mask = 0xffffffff;
240     if (rtm->rtm_addrs == RTA_DST)
241       p_sockaddr(sa, 36);
242     else {
243       wp = (u_char *) cp + rtm->rtm_msglen;
244       p_sockaddr(sa, 16);
245       if (sa->sa_len == 0)
246 	sa->sa_len = sizeof(long);
247       sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
248       p_sockaddr(sa, 18);
249       lp = (int *) (sa->sa_len + (char *) sa);
250       if ((char *) lp < (char *) wp && *lp) {
251 	LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp);
252 	wp = (u_char *) (lp + 1);
253 	mask = 0;
254 	for (nb = *(char *) lp; nb > 4; nb--) {
255 	  mask <<= 8;
256 	  mask |= *wp++;
257 	}
258 	for (nb = 8 - *(char *) lp; nb > 0; nb--)
259 	  mask <<= 8;
260       }
261     }
262     fprintf(VarTerm, "%08lx  ", mask);
263     p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s ");
264     fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
265   }
266   free(sp);
267   return 0;
268 }
269 
270 /*
271  *  Delete routes associated with our interface
272  */
273 void
274 DeleteIfRoutes(int all)
275 {
276   struct rt_msghdr *rtm;
277   struct sockaddr *sa;
278   struct in_addr dstnet, gateway, maddr;
279   int needed;
280   char *sp, *cp, *ep;
281   u_long mask;
282   int *lp, nb;
283   u_char *wp;
284   int mib[6];
285 
286   LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
287 
288   mib[0] = CTL_NET;
289   mib[1] = PF_ROUTE;
290   mib[2] = 0;
291   mib[3] = 0;
292   mib[4] = NET_RT_DUMP;
293   mib[5] = 0;
294   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
295     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
296 	      strerror(errno));
297     return;
298   }
299   if (needed < 0)
300     return;
301 
302   sp = malloc(needed);
303   if (sp == NULL)
304     return;
305 
306   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
307     LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
308 	      strerror(errno));
309     free(sp);
310     return;
311   }
312   ep = sp + needed;
313 
314   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
315     rtm = (struct rt_msghdr *) cp;
316     sa = (struct sockaddr *) (rtm + 1);
317     LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
318 	      " dstnet: %s\n",
319 	      rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
320 	      inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
321     if (rtm->rtm_addrs != RTA_DST &&
322 	(rtm->rtm_index == IfIndex) &&
323 	(all || (rtm->rtm_flags & RTF_GATEWAY))) {
324       LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
325       dstnet = ((struct sockaddr_in *) sa)->sin_addr;
326       wp = (u_char *) cp + rtm->rtm_msglen;
327       if (sa->sa_len == 0)
328 	sa->sa_len = sizeof(long);
329       sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
330       gateway = ((struct sockaddr_in *) sa)->sin_addr;
331       lp = (int *) (sa->sa_len + (char *) sa);
332       mask = 0;
333       if ((char *) lp < (char *) wp && *lp) {
334 	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n",
335 		  rtm->rtm_flags, *lp);
336 	wp = (u_char *) (lp + 1);
337 	for (nb = *lp; nb > 4; nb--) {
338 	  mask <<= 8;
339 	  mask |= *wp++;
340 	}
341 	for (nb = 8 - *lp; nb > 0; nb--)
342 	  mask <<= 8;
343       }
344       LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
345       LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
346       LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
347       if (dstnet.s_addr == INADDR_ANY)
348 	mask = INADDR_ANY;
349       maddr.s_addr = htonl(mask);
350       OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
351     }
352   }
353   free(sp);
354 }
355 
356  /*
357   * 960603 - Modified to use dynamic buffer allocator as in ifconfig
358   */
359 
360 int
361 GetIfIndex(char *name)
362 {
363   char *buffer;
364   struct ifreq *ifrp;
365   int s, len, elen, index;
366   struct ifconf ifconfs;
367 
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     LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno));
374     return (-1);
375   }
376   buffer = malloc(bufsize);	/* allocate first buffer */
377   ifconfs.ifc_len = bufsize;	/* Initial setting */
378 
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     LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
388     ifconfs.ifc_len = bufsize;
389     ifconfs.ifc_buf = buffer;
390     if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
391       LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n",
392 		strerror(errno));
393       close(s);
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       LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
406 		index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
407 		ifrp->ifr_addr.sa_family, elen);
408       if (strcmp(ifrp->ifr_name, name) == 0) {
409 	IfIndex = index;
410 	close(s);
411 	free(buffer);
412 	return (index);
413       }
414       index++;
415     }
416     len -= elen;
417     ifrp = (struct ifreq *) ((char *) ifrp + elen);
418     ifrp++;
419   }
420 
421   close(s);
422   free(buffer);
423   return (-1);
424 }
425