route.c revision 15738
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.5 1996/01/11 17:48:56 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
45static int IfIndex;
46
47struct rtmsg {
48  struct rt_msghdr m_rtm;
49  char m_space[64];
50};
51
52static int seqno;
53
54void
55OsSetRoute(cmd, dst, gateway, mask)
56int cmd;
57struct in_addr dst;
58struct in_addr gateway;
59struct 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;
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
121static void
122p_sockaddr(sa, width)
123struct sockaddr *sa;
124int 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
134struct 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
150static void
151p_flags(f, format)
152register int f;
153char *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
165int
166ShowRoute()
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 */
248void
249DeleteIfRoutes(all)
250int 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
354int
355GetIfIndex(name)
356char *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