route.c revision 26516
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.13 1997/05/10 01:22:18 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
47static int IfIndex;
48
49struct rtmsg {
50  struct rt_msghdr m_rtm;
51  char m_space[64];
52};
53
54static int seqno;
55
56void
57OsSetRoute(cmd, dst, gateway, mask)
58int cmd;
59struct in_addr dst;
60struct in_addr gateway;
61struct in_addr mask;
62{
63  struct rtmsg rtmes;
64  int s, nb, wb;
65  char *cp;
66  u_long *lp;
67  struct sockaddr_in rtdata;
68
69  s = socket(PF_ROUTE, SOCK_RAW, 0);
70  if (s < 0)
71    LogPrintf(LogERROR, "socket: %s", strerror(errno));
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;
77  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
78  rtmes.m_rtm.rtm_seq = ++seqno;
79  rtmes.m_rtm.rtm_pid = getpid();
80  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
81
82  bzero(&rtdata, sizeof(rtdata));
83  rtdata.sin_len = 16;
84  rtdata.sin_family = AF_INET;
85  rtdata.sin_port = 0;
86  rtdata.sin_addr = dst;
87
88  cp = rtmes.m_space;
89  bcopy(&rtdata, cp, 16);
90  cp += 16;
91  if (gateway.s_addr) {
92    rtdata.sin_addr = gateway;
93    bcopy(&rtdata, cp, 16);
94    cp += 16;
95  }
96
97  if (dst.s_addr == INADDR_ANY)
98    mask.s_addr = INADDR_ANY;
99
100  lp = (u_long *)cp;
101
102  if (mask.s_addr) {
103    *lp++ = 8;
104    cp += sizeof(int);
105    *lp = mask.s_addr;
106  } else
107    *lp = 0;
108  cp += sizeof(u_long);
109
110  nb = cp - (char *)&rtmes;
111  rtmes.m_rtm.rtm_msglen = nb;
112  wb = write(s, &rtmes, nb);
113  if (wb < 0) {
114     LogPrintf(LogTCPIP, "Already set route addr dst=%x, gateway=%x\n"
115         ,dst.s_addr, gateway.s_addr);
116  }
117  LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb,
118            dst.s_addr, gateway.s_addr);
119  close(s);
120}
121
122static void
123p_sockaddr(sa, width)
124struct sockaddr *sa;
125int width;
126{
127  if (VarTerm) {
128    register char *cp;
129    register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
130
131    cp = (sin->sin_addr.s_addr == 0) ? "default" :
132	   inet_ntoa(sin->sin_addr);
133    fprintf(VarTerm, "%-*.*s ", width, width, cp);
134  }
135}
136
137struct bits {
138  short b_mask;
139  char  b_val;
140} bits[] = {
141  { RTF_UP,	  'U' },
142  { RTF_GATEWAY,  'G' },
143  { RTF_HOST,	  'H' },
144  { RTF_DYNAMIC,  'D' },
145  { RTF_MODIFIED, 'M' },
146  { RTF_CLONING,  'C' },
147  { RTF_XRESOLVE, 'X' },
148  { RTF_LLINFO,   'L' },
149  { RTF_REJECT,   'R' },
150  { 0 }
151};
152
153static void
154p_flags(f, format)
155register int f;
156char *format;
157{
158  if (VarTerm) {
159    char name[33], *flags;
160    register struct bits *p = bits;
161
162    for (flags = name; p->b_mask; p++)
163      if (p->b_mask & f)
164        *flags++ = p->b_val;
165    *flags = '\0';
166    fprintf(VarTerm, format, name);
167  }
168}
169
170int
171ShowRoute()
172{
173  struct rt_msghdr *rtm;
174  struct sockaddr *sa;
175  char *sp, *ep, *cp;
176  u_char *wp;
177  int *lp;
178  int needed, nb;
179  u_long mask;
180  int mib[6];
181
182  if (!VarTerm)
183    return 1;
184
185  mib[0] = CTL_NET;
186  mib[1] = PF_ROUTE;
187  mib[2] = 0;
188  mib[3] = 0;
189  mib[4] = NET_RT_DUMP;
190  mib[5] = 0;
191  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
192    LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno));
193    return(1);
194  }
195
196  if (needed < 0)
197    return(1);
198  sp = malloc(needed);
199  if (sp == NULL)
200    return(1);
201  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
202    LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno));
203    free(sp);
204    return(1);
205  }
206
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	LogPrintf(LogDEBUG, " flag = %x, rest = %d", rtm->rtm_flags, *lp);
225	wp = (u_char *)(lp + 1);
226	mask = 0;
227	for (nb = *(char *)lp; nb > 4; nb--) {
228	  mask <<= 8;
229	  mask |= *wp++;
230	}
231	for (nb = 8 - *(char *)lp; nb > 0; nb--)
232	  mask <<= 8;
233      }
234    }
235    fprintf(VarTerm, "%08lx  ", mask);
236    p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
237    fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
238  }
239  free(sp);
240  return 0;
241}
242
243/*
244 *  Delete routes associated with our interface
245 */
246void
247DeleteIfRoutes(all)
248int all;
249{
250  struct rt_msghdr *rtm;
251  struct sockaddr *sa;
252  struct in_addr dstnet, gateway, maddr;
253  int needed;
254  char *sp, *cp, *ep;
255  u_long mask;
256  int *lp, nb;
257  u_char *wp;
258  int mib[6];
259
260  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
261
262  mib[0] = CTL_NET;
263  mib[1] = PF_ROUTE;
264  mib[2] = 0;
265  mib[3] = 0;
266  mib[4] = NET_RT_DUMP;
267  mib[5] = 0;
268  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
269    LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno));
270    return;
271  }
272
273  if (needed < 0)
274    return;
275
276  sp = malloc(needed);
277  if (sp == NULL)
278    return;
279
280  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
281    LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno));
282    free(sp);
283    return;
284  }
285  ep = sp + needed;
286
287  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
288    rtm = (struct rt_msghdr *)cp;
289    sa = (struct sockaddr *)(rtm + 1);
290    LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
291			" dstnet: %x\n",
292			rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
293			((struct sockaddr_in *)sa)->sin_addr);
294    if (rtm->rtm_addrs != RTA_DST &&
295       (rtm->rtm_index == IfIndex) &&
296       (all || (rtm->rtm_flags & RTF_GATEWAY))) {
297      dstnet = ((struct sockaddr_in *)sa)->sin_addr;
298      wp = (u_char *)cp + rtm->rtm_msglen;
299      if (sa->sa_len == 0)
300	sa->sa_len = sizeof(long);
301      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
302      gateway = ((struct sockaddr_in *)sa)->sin_addr;
303      lp = (int *)(sa->sa_len + (char *)sa);
304      mask = 0;
305      if ((char *)lp < (char *)wp && *lp) {
306	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d",
307		  rtm->rtm_flags, *lp);
308	wp = (u_char *)(lp + 1);
309	for (nb = *lp; nb > 4; nb--) {
310	  mask <<= 8;
311	  mask |= *wp++;
312	}
313	for (nb = 8 - *lp; nb > 0; nb--)
314	  mask <<= 8;
315      }
316      LogPrintf(LogDEBUG, "DeleteIfRoutes: Dest: %s\n", inet_ntoa(dstnet));
317      LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
318      LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
319      if (dstnet.s_addr == INADDR_ANY) {
320        gateway.s_addr = INADDR_ANY;
321        mask = INADDR_ANY;
322      }
323      maddr.s_addr = htonl(mask);
324      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
325    }
326    else if(rtm->rtm_index == IfIndex)
327      LogPrintf(LogDEBUG, "DeleteIfRoutes: Ignoring (looking for index %d)\n",
328		IfIndex);
329  }
330  free(sp);
331}
332
333 /*
334  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
335  */
336
337int
338GetIfIndex(name)
339char *name;
340{
341  char *buffer;
342  struct ifreq *ifrp;
343  int s, len, elen, index;
344  struct ifconf ifconfs;
345  /* struct ifreq reqbuf[256]; -- obsoleted :) */
346  int oldbufsize, bufsize = sizeof(struct ifreq);
347
348  s = socket(AF_INET, SOCK_DGRAM, 0);
349  if (s < 0) {
350    LogPrintf(LogERROR, "socket: %s", strerror(errno));
351    return(-1);
352  }
353
354  buffer = malloc(bufsize);   /* allocate first buffer */
355  ifconfs.ifc_len = bufsize;  /* Initial setting */
356  /*
357   * Iterate through here until we don't get many more data
358   */
359
360  do {
361      oldbufsize = ifconfs.ifc_len;
362      bufsize += 1+sizeof(struct ifreq);
363      buffer = realloc((void *)buffer, bufsize);      /* Make it bigger */
364      LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
365      ifconfs.ifc_len = bufsize;
366      ifconfs.ifc_buf = buffer;
367      if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
368          LogPrintf(LogERROR, "ioctl(SIOCGIFCONF): %s", strerror(errno));
369          free(buffer);
370          return(-1);
371      }
372  } while (ifconfs.ifc_len > oldbufsize);
373
374  ifrp = ifconfs.ifc_req;
375
376  index = 1;
377  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
378    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
379    if (ifrp->ifr_addr.sa_family == AF_LINK) {
380      LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
381		index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
382		ifrp->ifr_addr.sa_family, elen);
383      if (strcmp(ifrp->ifr_name, name) == 0) {
384        IfIndex = index;
385	free(buffer);
386        return(index);
387      }
388      index++;
389    }
390
391    len -= elen;
392    ifrp = (struct ifreq *)((char *)ifrp + elen);
393    ifrp++;
394  }
395
396  close(s);
397  free(buffer);
398  return(-1);
399}
400