route.c revision 6059
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
44static int IfIndex;
45
46struct rtmsg {
47  struct rt_msghdr m_rtm;
48  char m_space[64];
49};
50
51static int seqno;
52
53void
54OsSetRoute(cmd, dst, gateway, mask)
55int cmd;
56struct in_addr dst;
57struct in_addr gateway;
58struct 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
119static void
120p_sockaddr(sa, width)
121struct sockaddr *sa;
122int 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
132struct 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
148static void
149p_flags(f, format)
150register int f;
151char *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
163int
164ShowRoute()
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 */
241void
242DeleteIfRoutes(all)
243int 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
341int
342GetIfIndex(name)
343char *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