diff options
Diffstat (limited to 'release/src/router/busybox/route.c')
-rw-r--r-- | release/src/router/busybox/route.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/release/src/router/busybox/route.c b/release/src/router/busybox/route.c new file mode 100644 index 00000000..f1e569d0 --- /dev/null +++ b/release/src/router/busybox/route.c @@ -0,0 +1,423 @@ +/* route + * + * Similar to the standard Unix route, but with only the necessary + * parts for AF_INET + * + * Bjorn Wesen, Axis Communications AB + * + * Author of the original route: + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + * (derived from FvK's 'route.c 1.70 01/04/94') + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * $Id: route.c,v 1.2 2003/11/20 06:17:44 honor Exp $ + * + * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> + * adjustments by Larry Doolittle <LRDoolittle@lbl.gov> + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/route.h> +#include <linux/param.h> // HZ +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <ctype.h> +#include "busybox.h" + +#define _(x) x + +#define RTACTION_ADD 1 +#define RTACTION_DEL 2 +#define RTACTION_HELP 3 +#define RTACTION_FLUSH 4 +#define RTACTION_SHOW 5 + +#define E_NOTFOUND 8 +#define E_SOCK 7 +#define E_LOOKUP 6 +#define E_VERSION 5 +#define E_USAGE 4 +#define E_OPTERR 3 +#define E_INTERN 2 +#define E_NOSUPP 1 + + +static int +INET_resolve(char *name, struct sockaddr *sa) +{ + struct sockaddr_in *s_in = (struct sockaddr_in *)sa; + + s_in->sin_family = AF_INET; + s_in->sin_port = 0; + + /* Default is special, meaning 0.0.0.0. */ + if (strcmp(name, "default")==0) { + s_in->sin_addr.s_addr = INADDR_ANY; + return 1; + } + /* Look to see if it's a dotted quad. */ + if (inet_aton(name, &s_in->sin_addr)) { + return 0; + } + /* guess not.. */ + return -1; +} + +#if defined(SIOCADDRTOLD) || defined(RTF_IRTT) /* route */ +#define HAVE_NEW_ADDRT 1 +#endif +#ifdef RTF_IRTT /* route */ +#define HAVE_RTF_IRTT 1 +#endif +#ifdef RTF_REJECT /* route */ +#define HAVE_RTF_REJECT 1 +#endif + +#if HAVE_NEW_ADDRT +#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr) +#define full_mask(x) (x) +#else +#define mask_in_addr(x) ((x).rt_genmask) +#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr) +#endif + +/* add or delete a route depending on action */ + +static int +INET_setroute(int action, int options, char **args) +{ + struct rtentry rt; + char target[128], gateway[128] = "NONE", netmask[128] = "default"; + int xflag, isnet; + int skfd; + + xflag = 0; + + if (strcmp(*args, "-net")==0) { + xflag = 1; + args++; + } else if (strcmp(*args, "-host")==0) { + xflag = 2; + args++; + } + if (*args == NULL) + show_usage(); + + safe_strncpy(target, *args++, (sizeof target)); + + /* Clean out the RTREQ structure. */ + memset((char *) &rt, 0, sizeof(struct rtentry)); + + + if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) { + error_msg(_("can't resolve %s"), target); + return EXIT_FAILURE; + } + + switch (xflag) { + case 1: + isnet = 1; + break; + + case 2: + isnet = 0; + break; + + default: + break; + } + + /* Fill in the other fields. */ + rt.rt_flags = (RTF_UP | RTF_HOST); + if (isnet) + rt.rt_flags &= ~RTF_HOST; + + while (*args) { + if (strcmp(*args, "metric")==0) { + int metric; + + args++; + if (!*args || !isdigit(**args)) + show_usage(); + metric = atoi(*args); +#if HAVE_NEW_ADDRT + rt.rt_metric = metric + 1; +#else + ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); +#endif + args++; + continue; + } + + if (strcmp(*args, "netmask")==0) { + struct sockaddr mask; + + args++; + if (!*args || mask_in_addr(rt)) + show_usage(); + safe_strncpy(netmask, *args, (sizeof netmask)); + if ((isnet = INET_resolve(netmask, &mask)) < 0) { + error_msg(_("can't resolve netmask %s"), netmask); + return E_LOOKUP; + } + rt.rt_genmask = full_mask(mask); + args++; + continue; + } + + if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) { + args++; + if (!*args) + show_usage(); + if (rt.rt_flags & RTF_GATEWAY) + show_usage(); + safe_strncpy(gateway, *args, (sizeof gateway)); + if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) { + error_msg(_("can't resolve gw %s"), gateway); + return E_LOOKUP; + } + if (isnet) { + error_msg( + _("%s: cannot use a NETWORK as gateway!"), + gateway); + return E_OPTERR; + } + rt.rt_flags |= RTF_GATEWAY; + args++; + continue; + } + + if (strcmp(*args, "mss")==0) { + args++; + rt.rt_flags |= RTF_MSS; + if (!*args) + show_usage(); + rt.rt_mss = atoi(*args); + args++; + if (rt.rt_mss < 64 || rt.rt_mss > 32768) { + error_msg(_("Invalid MSS.")); + return E_OPTERR; + } + continue; + } + + if (strcmp(*args, "window")==0) { + args++; + if (!*args) + show_usage(); + rt.rt_flags |= RTF_WINDOW; + rt.rt_window = atoi(*args); + args++; + if (rt.rt_window < 128) { + error_msg(_("Invalid window.")); + return E_OPTERR; + } + continue; + } + + if (strcmp(*args, "irtt")==0) { + args++; + if (!*args) + show_usage(); + args++; +#if HAVE_RTF_IRTT + rt.rt_flags |= RTF_IRTT; + rt.rt_irtt = atoi(*(args - 1)); + rt.rt_irtt *= (HZ / 100); +#else + ENOSUPP("inet_setroute", "RTF_IRTT"); +#endif + continue; + } + + if (strcmp(*args, "reject")==0) { + args++; +#if HAVE_RTF_REJECT + rt.rt_flags |= RTF_REJECT; +#else + ENOSUPP("inet_setroute", "RTF_REJECT"); +#endif + continue; + } + if (strcmp(*args, "mod")==0) { + args++; + rt.rt_flags |= RTF_MODIFIED; + continue; + } + if (strcmp(*args, "dyn")==0) { + args++; + rt.rt_flags |= RTF_DYNAMIC; + continue; + } + if (strcmp(*args, "reinstate")==0) { + args++; + rt.rt_flags |= RTF_REINSTATE; + continue; + } + if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) { + args++; + if (rt.rt_dev || *args == NULL) + show_usage(); + rt.rt_dev = *args++; + continue; + } + /* nothing matches */ + if (!rt.rt_dev) { + rt.rt_dev = *args++; + if (*args) + show_usage(); /* must be last to catch typos */ + } else { + show_usage(); + } + } + +#if HAVE_RTF_REJECT + if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) + rt.rt_dev = "lo"; +#endif + + /* sanity checks.. */ + if (mask_in_addr(rt)) { + unsigned long mask = mask_in_addr(rt); + mask = ~ntohl(mask); + if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { + error_msg( + _("netmask %.8x doesn't make sense with host route"), + (unsigned int)mask); + return E_OPTERR; + } + if (mask & (mask + 1)) { + error_msg(_("bogus netmask %s"), netmask); + return E_OPTERR; + } + mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; + if (mask & ~mask_in_addr(rt)) { + error_msg(_("netmask doesn't match route address")); + return E_OPTERR; + } + } + /* Fill out netmask if still unset */ + if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) + mask_in_addr(rt) = 0xffffffff; + + /* Create a socket to the INET kernel. */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + return E_SOCK; + } + /* Tell the kernel to accept this route. */ + if (action == RTACTION_DEL) { + if (ioctl(skfd, SIOCDELRT, &rt) < 0) { + perror("SIOCDELRT"); + close(skfd); + return E_SOCK; + } + } else { + if (ioctl(skfd, SIOCADDRT, &rt) < 0) { + perror("SIOCADDRT"); + close(skfd); + return E_SOCK; + } + } + + /* Close the socket. */ + (void) close(skfd); + return EXIT_SUCCESS; +} + +static void displayroutes(void) +{ + char buff[256]; + int nl = 0 ; + struct in_addr dest; + struct in_addr gw; + struct in_addr mask; + int flgs, ref, use, metric; + char flags[4]; + unsigned long int d,g,m; + + char sdest[16], sgw[16]; + + + FILE *fp = xfopen("/proc/net/route", "r"); + + while( fgets(buff, sizeof(buff), fp) != NULL ) { + if(nl) { + int ifl = 0; + while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0') + ifl++; + buff[ifl]=0; /* interface */ + if(sscanf(buff+ifl+1, "%lx%lx%d%d%d%d%lx", + &d, &g, &flgs, &ref, &use, &metric, &m)!=7) { + error_msg_and_die( "Unsuported kernel route format\n"); + } + if(nl==1) { + printf("Kernel IP routing table\n" +"Destination Gateway Genmask Flags Metric Ref Use Iface\n"); + } + + if (!(flgs & RTF_UP)) + continue; + + ifl = 0; /* parse flags */ + if(flgs&1) + flags[ifl++]='U'; + if(flgs&2) + flags[ifl++]='G'; + if(flgs&4) + flags[ifl++]='H'; + flags[ifl]=0; + dest.s_addr = d; + gw.s_addr = g; + mask.s_addr = m; + strcpy(sdest, (dest.s_addr==0 ? "default" : + inet_ntoa(dest))); + strcpy(sgw, (gw.s_addr==0 ? "*" : + inet_ntoa(gw))); + printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", + sdest, sgw, + inet_ntoa(mask), + flags, metric, ref, use, buff); + } + nl++; + } +} + +int route_main(int argc, char **argv) +{ + int what = 0; + + argc--; + argv++; + + if (*argv == NULL) { + displayroutes(); + return EXIT_SUCCESS; + } else { + /* check verb */ + if (strcmp(*argv, "add")==0) + what = RTACTION_ADD; + else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0) + what = RTACTION_DEL; + else if (strcmp(*argv, "flush")==0) + what = RTACTION_FLUSH; + else + show_usage(); + } + + return INET_setroute(what, 0, ++argv); +} |