route.c revision 31048
11984Scsgr/*
24246Sphk *	      PPP Routing related Module
34246Sphk *
44246Sphk *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
54246Sphk *
64246Sphk *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
74246Sphk *
81984Scsgr * Redistribution and use in source and binary forms are permitted
917141Sjkh * provided that the above copyright notice and this paragraph are
101984Scsgr * duplicated in all such forms and that any documentation,
111984Scsgr * advertising materials, and other materials related to such
121984Scsgr * distribution and use acknowledge that the software was developed
131984Scsgr * by the Internet Initiative Japan, Inc.  The name of the
1417141Sjkh * IIJ may not be used to endorse or promote products derived
151984Scsgr * from this software without specific prior written permission.
161984Scsgr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171984Scsgr * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181984Scsgr * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1917141Sjkh *
204246Sphk * $Id: route.c,v 1.21 1997/11/08 00:28:11 brian Exp $
211984Scsgr *
224246Sphk */
234246Sphk
244246Sphk#include <sys/param.h>
254246Sphk#include <sys/time.h>
264246Sphk#include <sys/socket.h>
274246Sphk#include <net/route.h>
284246Sphk#include <net/if.h>
294246Sphk#include <netinet/in_systm.h>
304246Sphk#include <netinet/in.h>
314246Sphk#include <arpa/inet.h>
324246Sphk
334246Sphk#include <errno.h>
344246Sphk#include <machine/endian.h>
354246Sphk#include <stdio.h>
364246Sphk#include <stdlib.h>
371984Scsgr#include <string.h>
381984Scsgr#include <sys/ioctl.h>
398870Srgrimes#include <sys/sysctl.h>
404246Sphk#include <unistd.h>
411984Scsgr
421984Scsgr#include "mbuf.h"
431984Scsgr#include "log.h"
441984Scsgr#include "loadalias.h"
451984Scsgr#include "command.h"
461984Scsgr#include "vars.h"
471984Scsgr#include "route.h"
484246Sphk
494246Sphkstatic int IfIndex;
504246Sphk
514246Sphkstruct rtmsg {
524246Sphk  struct rt_msghdr m_rtm;
534246Sphk  char m_space[64];
544246Sphk};
554246Sphk
564246Sphkstatic int seqno;
574246Sphk
584246Sphkvoid
594246SphkOsSetRoute(int cmd,
601984Scsgr	   struct in_addr dst,
614246Sphk	   struct in_addr gateway,
624246Sphk	   struct in_addr mask)
631984Scsgr{
644246Sphk  struct rtmsg rtmes;
654246Sphk  int s, nb, wb;
664246Sphk  char *cp;
671984Scsgr  u_long *lp;
684246Sphk  struct sockaddr_in rtdata;
694246Sphk
704246Sphk  s = socket(PF_ROUTE, SOCK_RAW, 0);
714246Sphk  if (s < 0) {
724246Sphk    LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
734246Sphk    return;
744246Sphk  }
754246Sphk  memset(&rtmes, '\0', sizeof(rtmes));
764246Sphk  rtmes.m_rtm.rtm_version = RTM_VERSION;
774246Sphk  rtmes.m_rtm.rtm_type = cmd;
784246Sphk  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
794246Sphk  rtmes.m_rtm.rtm_seq = ++seqno;
804246Sphk  rtmes.m_rtm.rtm_pid = getpid();
814246Sphk  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
824246Sphk
834246Sphk  memset(&rtdata, '\0', sizeof(rtdata));
844246Sphk  rtdata.sin_len = 16;
854246Sphk  rtdata.sin_family = AF_INET;
864246Sphk  rtdata.sin_port = 0;
874246Sphk  rtdata.sin_addr = dst;
884246Sphk
894246Sphk  cp = rtmes.m_space;
904246Sphk  memcpy(cp, &rtdata, 16);
914246Sphk  cp += 16;
928870Srgrimes  if (gateway.s_addr) {
934246Sphk    rtdata.sin_addr = gateway;
944246Sphk    memcpy(cp, &rtdata, 16);
954246Sphk    cp += 16;
964246Sphk    rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
974246Sphk  }
984246Sphk  if (dst.s_addr == INADDR_ANY)
994246Sphk    mask.s_addr = INADDR_ANY;
1004246Sphk
1014246Sphk  lp = (u_long *) cp;
1021984Scsgr
1034246Sphk  if (mask.s_addr) {
1041984Scsgr    *lp++ = 8;
1054246Sphk    cp += sizeof(int);
1064246Sphk    *lp = mask.s_addr;
1074246Sphk  } else
1084246Sphk    *lp = 0;
1091984Scsgr  cp += sizeof(u_long);
1104246Sphk
1114246Sphk  nb = cp - (char *) &rtmes;
1128870Srgrimes  rtmes.m_rtm.rtm_msglen = nb;
1138870Srgrimes  wb = write(s, &rtmes, nb);
1144246Sphk  if (wb < 0) {
1154246Sphk    LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
1164246Sphk    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
1174246Sphk    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
1184246Sphk    switch (rtmes.m_rtm.rtm_errno) {
1194246Sphk    case EEXIST:
1204246Sphk      LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
1211984Scsgr      break;
1224246Sphk    case ESRCH:
1231984Scsgr      LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
1244246Sphk      break;
1254246Sphk    case ENOBUFS:
1261984Scsgr    default:
1274246Sphk      LogPrintf(LogTCPIP, "Add/Del route failed: %s\n",
1284246Sphk		strerror(rtmes.m_rtm.rtm_errno));
1294246Sphk      break;
1304246Sphk    }
1314246Sphk  }
1324246Sphk  LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb,
1334246Sphk	    dst.s_addr, gateway.s_addr);
1344246Sphk  close(s);
1351984Scsgr}
1361984Scsgr
1374246Sphkstatic void
1388870Srgrimesp_sockaddr(struct sockaddr * sa, int width)
1394246Sphk{
1404246Sphk  if (VarTerm) {
1414246Sphk    register char *cp;
1424246Sphk    register struct sockaddr_in *sock_in = (struct sockaddr_in *) sa;
1434246Sphk
1444246Sphk    cp = (sock_in->sin_addr.s_addr == 0) ? "default" :
1454246Sphk      inet_ntoa(sock_in->sin_addr);
1464246Sphk    fprintf(VarTerm, "%-*.*s ", width, width, cp);
1474246Sphk  }
1484246Sphk}
1494246Sphk
1504246Sphkstruct bits {
1511984Scsgr  short b_mask;
1521984Scsgr  char b_val;
153}    bits[] = {
154
155  {
156    RTF_UP, 'U'
157  },
158  {
159    RTF_GATEWAY, 'G'
160  },
161  {
162    RTF_HOST, 'H'
163  },
164  {
165    RTF_DYNAMIC, 'D'
166  },
167  {
168    RTF_MODIFIED, 'M'
169  },
170  {
171    RTF_CLONING, 'C'
172  },
173  {
174    RTF_XRESOLVE, 'X'
175  },
176  {
177    RTF_LLINFO, 'L'
178  },
179  {
180    RTF_REJECT, 'R'
181  },
182  {
183    0
184  }
185};
186
187static void
188p_flags(int f, char *format)
189{
190  if (VarTerm) {
191    char name[33], *flags;
192    register struct bits *p = bits;
193
194    for (flags = name; p->b_mask; p++)
195      if (p->b_mask & f)
196	*flags++ = p->b_val;
197    *flags = '\0';
198    fprintf(VarTerm, format, name);
199  }
200}
201
202int
203ShowRoute()
204{
205  struct rt_msghdr *rtm;
206  struct sockaddr *sa;
207  char *sp, *ep, *cp;
208  u_char *wp;
209  int *lp;
210  int needed, nb;
211  u_long mask;
212  int mib[6];
213
214  if (!VarTerm)
215    return 1;
216
217  mib[0] = CTL_NET;
218  mib[1] = PF_ROUTE;
219  mib[2] = 0;
220  mib[3] = 0;
221  mib[4] = NET_RT_DUMP;
222  mib[5] = 0;
223  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
224    LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
225    return (1);
226  }
227  if (needed < 0)
228    return (1);
229  sp = malloc(needed);
230  if (sp == NULL)
231    return (1);
232  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
233    LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
234    free(sp);
235    return (1);
236  }
237  ep = sp + needed;
238
239  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
240    rtm = (struct rt_msghdr *) cp;
241    sa = (struct sockaddr *) (rtm + 1);
242    mask = 0xffffffff;
243    if (rtm->rtm_addrs == RTA_DST)
244      p_sockaddr(sa, 36);
245    else {
246      wp = (u_char *) cp + rtm->rtm_msglen;
247      p_sockaddr(sa, 16);
248      if (sa->sa_len == 0)
249	sa->sa_len = sizeof(long);
250      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
251      p_sockaddr(sa, 18);
252      lp = (int *) (sa->sa_len + (char *) sa);
253      if ((char *) lp < (char *) wp && *lp) {
254	LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp);
255	wp = (u_char *) (lp + 1);
256	mask = 0;
257	for (nb = *(char *) lp; nb > 4; nb--) {
258	  mask <<= 8;
259	  mask |= *wp++;
260	}
261	for (nb = 8 - *(char *) lp; nb > 0; nb--)
262	  mask <<= 8;
263      }
264    }
265    fprintf(VarTerm, "%08lx  ", mask);
266    p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s ");
267    fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
268  }
269  free(sp);
270  return 0;
271}
272
273/*
274 *  Delete routes associated with our interface
275 */
276void
277DeleteIfRoutes(int all)
278{
279  struct rt_msghdr *rtm;
280  struct sockaddr *sa;
281  struct in_addr dstnet, gateway, maddr;
282  int needed;
283  char *sp, *cp, *ep;
284  u_long mask;
285  int *lp, nb;
286  u_char *wp;
287  int mib[6];
288
289  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
290
291  mib[0] = CTL_NET;
292  mib[1] = PF_ROUTE;
293  mib[2] = 0;
294  mib[3] = 0;
295  mib[4] = NET_RT_DUMP;
296  mib[5] = 0;
297  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
298    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
299	      strerror(errno));
300    return;
301  }
302  if (needed < 0)
303    return;
304
305  sp = malloc(needed);
306  if (sp == NULL)
307    return;
308
309  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
310    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
311	      strerror(errno));
312    free(sp);
313    return;
314  }
315  ep = sp + needed;
316
317  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
318    rtm = (struct rt_msghdr *) cp;
319    sa = (struct sockaddr *) (rtm + 1);
320    LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
321	      " dstnet: %s\n",
322	      rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
323	      inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
324    if (rtm->rtm_addrs != RTA_DST &&
325	(rtm->rtm_index == IfIndex) &&
326	(all || (rtm->rtm_flags & RTF_GATEWAY))) {
327      LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
328      dstnet = ((struct sockaddr_in *) sa)->sin_addr;
329      wp = (u_char *) cp + rtm->rtm_msglen;
330      if (sa->sa_len == 0)
331	sa->sa_len = sizeof(long);
332      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
333      gateway = ((struct sockaddr_in *) sa)->sin_addr;
334      lp = (int *) (sa->sa_len + (char *) sa);
335      mask = 0;
336      if ((char *) lp < (char *) wp && *lp) {
337	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n",
338		  rtm->rtm_flags, *lp);
339	wp = (u_char *) (lp + 1);
340	for (nb = *lp; nb > 4; nb--) {
341	  mask <<= 8;
342	  mask |= *wp++;
343	}
344	for (nb = 8 - *lp; nb > 0; nb--)
345	  mask <<= 8;
346      }
347      LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
348      LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
349      LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
350      if (dstnet.s_addr == INADDR_ANY)
351	mask = INADDR_ANY;
352      maddr.s_addr = htonl(mask);
353      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
354    }
355  }
356  free(sp);
357}
358
359 /*
360  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
361  */
362
363int
364GetIfIndex(char *name)
365{
366  char *buffer;
367  struct ifreq *ifrp;
368  int s, len, elen, newIfIndex;
369  struct ifconf ifconfs;
370
371  /* struct ifreq reqbuf[256]; -- obsoleted :) */
372  int oldbufsize, bufsize = sizeof(struct ifreq);
373
374  s = socket(AF_INET, SOCK_DGRAM, 0);
375  if (s < 0) {
376    LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno));
377    return (-1);
378  }
379  buffer = malloc(bufsize);	/* allocate first buffer */
380  ifconfs.ifc_len = bufsize;	/* Initial setting */
381
382  /*
383   * Iterate through here until we don't get many more data
384   */
385
386  do {
387    oldbufsize = ifconfs.ifc_len;
388    bufsize += 1 + sizeof(struct ifreq);
389    buffer = realloc((void *) buffer, bufsize);	/* Make it bigger */
390    LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
391    ifconfs.ifc_len = bufsize;
392    ifconfs.ifc_buf = buffer;
393    if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
394      LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n",
395		strerror(errno));
396      close(s);
397      free(buffer);
398      return (-1);
399    }
400  } while (ifconfs.ifc_len > oldbufsize);
401
402  ifrp = ifconfs.ifc_req;
403
404  newIfIndex = 1;
405  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
406    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
407    if (ifrp->ifr_addr.sa_family == AF_LINK) {
408      LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
409		newIfIndex, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
410		ifrp->ifr_addr.sa_family, elen);
411      if (strcmp(ifrp->ifr_name, name) == 0) {
412	IfIndex = newIfIndex;
413	close(s);
414	free(buffer);
415	return (newIfIndex);
416      }
417      newIfIndex++;
418    }
419    len -= elen;
420    ifrp = (struct ifreq *) ((char *) ifrp + elen);
421    ifrp++;
422  }
423
424  close(s);
425  free(buffer);
426  return (-1);
427}
428