Add in ifconfig and route
authorEric Andersen <andersen@codepoet.org>
Wed, 14 Feb 2001 08:11:27 +0000 (08:11 -0000)
committerEric Andersen <andersen@codepoet.org>
Wed, 14 Feb 2001 08:11:27 +0000 (08:11 -0000)
12 files changed:
Config.h
applets.h
applets/usage.c
busybox.h
ifconfig.c [new file with mode: 0644]
include/applets.h
include/busybox.h
networking/ifconfig.c [new file with mode: 0644]
networking/route.c [new file with mode: 0644]
route.c [new file with mode: 0644]
usage.c
utility.c

index c9e6750..38a9559 100644 (file)
--- a/Config.h
+++ b/Config.h
@@ -47,6 +47,7 @@
 //#define BB_HOSTID
 //#define BB_HOSTNAME
 #define BB_ID
+//#define BB_IFCONFIG
 #define BB_INIT
 //#define BB_INSMOD
 #define BB_KILL
@@ -87,6 +88,7 @@
 #define BB_RM
 #define BB_RMDIR
 //#define BB_RMMOD
+//#define BB_ROUTE
 //#define BB_RPMUNPACK
 #define BB_SED
 //#define BB_SETKEYCODES
index 4bd8b79..9aa65da 100644 (file)
--- a/applets.h
+++ b/applets.h
@@ -158,6 +158,9 @@ const struct BB_applet applets[] = {
 #ifdef BB_ID
        APPLET("id", id_main, _BB_DIR_USR_BIN, id_usage)
 #endif
+#ifdef BB_IFCONFIG
+       APPLET("ifconfig", ifconfig_main, _BB_DIR_SBIN, ifconfig_usage)
+#endif
 #ifdef BB_INIT
        APPLET_NOUSAGE("init", init_main, _BB_DIR_SBIN)
 #endif
@@ -284,6 +287,9 @@ const struct BB_applet applets[] = {
 #ifdef BB_RMMOD
        APPLET("rmmod", rmmod_main, _BB_DIR_SBIN, rmmod_usage)
 #endif
+#ifdef BB_ROUTE
+       APPLET("route", route_main, _BB_DIR_USR_BIN, route_usage)
+#endif
 #ifdef BB_RPMUNPACK
        APPLET("rpmunpack", rpmunpack_main, _BB_DIR_USR_BIN, rpmunpack_usage)
 #endif
index 13107c6..bdd4d3d 100644 (file)
@@ -556,6 +556,26 @@ const char id_usage[] =
        ;
 #endif
 
+#if defined BB_IFCONFIG
+const char ifconfig_usage[] =
+       "ifconfig [-a] [-i] [-v] <interface> [<address>]"
+#ifndef BB_FEATURE_TRIVIAL_HELP
+       "\n\nconfigure a network interface\n\n"
+       "Options:\n"
+       "  [[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n"
+       "  [netmask <address>]  [dstaddr <address>]  [tunnel <adress>]\n"
+#ifdef SIOCSKEEPALIVE
+       "  [outfill <NN>] [keepalive <NN>]\n"
+#endif
+       "  [hw ether <address>]  [metric <NN>]  [mtu <NN>]\n"
+       "  [[-]trailers]  [[-]arp]  [[-]allmulti]\n"
+       "  [multicast]  [[-]promisc]\n"
+       "  [mem_start <NN>]  [io_addr <NN>]  [irq <NN>]  [media <type>]\n"
+       "  [up|down] ..."
+#endif
+       ;
+#endif
+
 #if defined BB_INSMOD
 const char insmod_usage[] =
        "insmod [OPTION]... MODULE [symbol=value]..."
@@ -1144,6 +1164,15 @@ const char rmmod_usage[] =
        ;
 #endif
 
+#if defined BB_ROUTE
+const char route_usage[] =
+       "route [{add|del|flush}]"
+#ifndef BB_FEATURE_TRIVIAL_HELP
+       "\n\nEdit the kernel's routing tables"
+#endif
+       ;
+#endif
+
 #if defined BB_RPMUNPACK
 const char rpmunpack_usage[] =
        "rpmunpack < package.rpm | gunzip | cpio -idmuv"
index 101e659..39580b5 100644 (file)
--- a/busybox.h
+++ b/busybox.h
@@ -161,6 +161,7 @@ extern void *xcalloc(size_t nmemb, size_t size);
 extern char *xstrdup (const char *s);
 #endif
 extern char *xstrndup (const char *s, int n);
+extern char * safe_strncpy(char *dst, const char *src, size_t size);
 
 struct suffix_mult {
        char *suffix;
diff --git a/ifconfig.c b/ifconfig.c
new file mode 100644 (file)
index 0000000..2134f8a
--- /dev/null
@@ -0,0 +1,476 @@
+/* ifconfig
+ *
+ * Similar to the standard Unix ifconfig, but with only the necessary
+ * parts for AF_INET, and without any printing of if info (for now).
+ *
+ * Bjorn Wesen, Axis Communications AB
+ *
+ *
+ * Authors of the original ifconfig was:      
+ *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * 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: ifconfig.c,v 1.1 2001/02/14 08:11:27 andersen Exp $
+ *
+ */
+
+#include "busybox.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>   // strcmp and friends
+#include <ctype.h>    // isdigit and friends
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
+static int sockfd;  /* socket fd we use to manipulate stuff with */
+
+/* print usage and exit */
+
+#define _(x) x
+
+/* Set a certain interface flag. */
+static int
+set_flag(char *ifname, short flag)
+{
+       struct ifreq ifr;
+       
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+               perror("SIOCGIFFLAGS"); 
+               return (-1);
+       }
+       strcpy(ifr.ifr_name, ifname);
+       ifr.ifr_flags |= flag;
+       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+               perror("SIOCSIFFLAGS");
+               return -1;
+       }
+       return (0);
+}
+
+
+/* Clear a certain interface flag. */
+static int
+clr_flag(char *ifname, short flag)
+{
+       struct ifreq ifr;
+       
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+               perror("SIOCGIFFLAGS");
+               return -1;
+       }
+       strcpy(ifr.ifr_name, ifname);
+       ifr.ifr_flags &= ~flag;
+       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+               perror("SIOCSIFFLAGS");
+               return -1;
+       }
+       return (0);
+}
+
+/* resolve XXX.YYY.ZZZ.QQQ -> binary */
+
+static int
+INET_resolve(char *name, struct sockaddr_in *sin)
+{
+       sin->sin_family = AF_INET;
+       sin->sin_port = 0;
+
+       /* Default is special, meaning 0.0.0.0. */
+       if (!strcmp(name, "default")) {
+               sin->sin_addr.s_addr = INADDR_ANY;
+               return (1);
+       }
+       /* Look to see if it's a dotted quad. */
+       if (inet_aton(name, &sin->sin_addr)) {
+               return 0;
+       }
+       /* guess not.. */
+       return -1;
+}
+
+/* Input an Ethernet address and convert to binary. */
+static int
+in_ether(char *bufp, struct sockaddr *sap)
+{
+       unsigned char *ptr;
+       char c, *orig;
+       int i;
+       unsigned val;
+       
+       sap->sa_family = ARPHRD_ETHER;
+       ptr = sap->sa_data;
+       
+       i = 0;
+       orig = bufp;
+       while ((*bufp != '\0') && (i < ETH_ALEN)) {
+               val = 0;
+               c = *bufp++;
+               if (isdigit(c))
+                       val = c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       val = c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       val = c - 'A' + 10;
+               else {
+#ifdef DEBUG
+                       fprintf(stderr,
+                               _("in_ether(%s): invalid ether address!\n"),
+                               orig);
+#endif
+                       errno = EINVAL;
+                       return (-1);
+               }
+               val <<= 4;
+               c = *bufp;
+               if (isdigit(c))
+                       val |= c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       val |= c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       val |= c - 'A' + 10;
+               else if (c == ':' || c == 0)
+                       val >>= 4;
+               else {
+#ifdef DEBUG
+                       fprintf(stderr,
+                               _("in_ether(%s): invalid ether address!\n"),
+                               orig);
+#endif
+                       errno = EINVAL;
+                       return (-1);
+               }
+               if (c != 0)
+                       bufp++;
+               *ptr++ = (unsigned char) (val & 0377);
+               i++;
+               
+               /* We might get a semicolon here - not required. */
+               if (*bufp == ':')
+                       bufp++;
+               
+       }
+
+       if(i != ETH_ALEN) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+int ifconfig_main(int argc, char **argv)
+{
+       struct ifreq ifr;
+       struct sockaddr_in sa;
+       struct sockaddr sa2;
+       char **spp;
+       int goterr = 0;
+       int r, didnetmask = 0;
+       char host[128];
+
+       if(argc < 2) {
+               usage(ifconfig_usage);
+       }
+
+       /* Create a channel to the NET kernel. */
+       if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               perror("socket");
+               exit(1);
+       }
+
+       /* skip argv[0] */
+
+       argc--;
+       argv++;
+
+       spp = argv;
+
+       /* get interface name */
+
+       safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
+
+       /* Process the remaining arguments. */
+       while (*spp != (char *) NULL) {
+               if (!strcmp(*spp, "arp")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-arp")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
+                       spp++;
+                       continue;
+               }
+               
+               if (!strcmp(*spp, "trailers")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-trailers")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "promisc")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-promisc")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "multicast")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-multicast")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "allmulti")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-allmulti")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "up")) {
+                       goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "down")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_UP);
+                       spp++;
+                       continue;
+               }
+
+               if (!strcmp(*spp, "metric")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_metric = atoi(*spp);
+                       if (ioctl(sockfd, SIOCSIFMETRIC, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "mtu")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_mtu = atoi(*spp);
+                       if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+#ifdef SIOCSKEEPALIVE
+               if (!strcmp(*spp, "keepalive")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_data = (caddr_t) atoi(*spp);
+                       if (ioctl(sockfd, SIOCSKEEPALIVE, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+#endif
+
+#ifdef SIOCSOUTFILL
+               if (!strcmp(*spp, "outfill")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_data = (caddr_t) atoi(*spp);
+                       if (ioctl(sockfd, SIOCSOUTFILL, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+#endif
+
+               if (!strcmp(*spp, "-broadcast")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "broadcast")) {
+                       if (*++spp != NULL) {
+                               safe_strncpy(host, *spp, (sizeof host));
+                               if (INET_resolve(host, &sa) < 0) {
+                                       goterr++;
+                                       spp++;
+                                       continue;
+                               }
+                               memcpy((char *) &ifr.ifr_broadaddr,
+                                      (char *) &sa,
+                                      sizeof(struct sockaddr));
+                               if (ioctl(sockfd, SIOCSIFBRDADDR, &ifr) < 0) {
+                                       perror("SIOCSIFBRDADDR");
+                                       goterr++;
+                               }
+                               spp++;
+                       }
+                       goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
+                       continue;
+               }
+               if (!strcmp(*spp, "dstaddr")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       safe_strncpy(host, *spp, (sizeof host));
+                       if (INET_resolve(host, &sa) < 0) {
+                               goterr++;
+                               spp++;
+                               continue;
+                       }
+                       memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
+                              sizeof(struct sockaddr));
+                       if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
+                                       strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "netmask")) {
+                       if (*++spp == NULL || didnetmask)
+                               usage(ifconfig_usage);
+                       safe_strncpy(host, *spp, (sizeof host));
+                       if (INET_resolve(host, &sa) < 0) {
+                               goterr++;
+                               spp++;
+                               continue;
+                       }
+                       didnetmask++;
+                       memcpy((char *) &ifr.ifr_netmask, (char *) &sa,
+                              sizeof(struct sockaddr));
+                       if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
+                               perror("SIOCSIFNETMASK");
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+
+               if (!strcmp(*spp, "-pointopoint")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "pointopoint")) {
+                       if (*(spp + 1) != NULL) {
+                               spp++;
+                               safe_strncpy(host, *spp, (sizeof host));
+                               if (INET_resolve(host, &sa)) {
+                                       goterr++;
+                                       spp++;
+                                       continue;
+                               }
+                               memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
+                                      sizeof(struct sockaddr));
+                               if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
+                                       perror("SIOCSIFDSTADDR");
+                                       goterr++;
+                               }
+                       }
+                       goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
+                       spp++;
+                       continue;
+               };
+
+               if (!strcmp(*spp, "hw")) {
+                       if (*++spp == NULL || strcmp("ether", *spp)) {
+                               usage(ifconfig_usage);
+                       }
+                               
+                       if (*++spp == NULL) {
+                               /* silently ignore it if no address */
+                               continue;
+                       }
+
+                       safe_strncpy(host, *spp, (sizeof host));
+                       if (in_ether(host, &sa2) < 0) {
+                               fprintf(stderr, "invalid hw-addr %s\n", host);
+                               goterr++;
+                               spp++;
+                               continue;
+                       }
+                       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa2,
+                              sizeof(struct sockaddr));
+                       if (ioctl(sockfd, SIOCSIFHWADDR, &ifr) < 0) {
+                               perror("SIOCSIFHWADDR");
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+
+               /* If the next argument is a valid hostname, assume OK. */
+               safe_strncpy(host, *spp, (sizeof host));
+
+               if (INET_resolve(host, &sa) < 0) {
+                       usage(ifconfig_usage);
+               }
+               memcpy((char *) &ifr.ifr_addr,
+                      (char *) &sa, sizeof(struct sockaddr));
+
+               r = ioctl(sockfd, SIOCSIFADDR, &ifr);
+
+               if (r < 0) {
+                       perror("SIOCSIFADDR");
+                       goterr++;
+               }
+
+               /*
+                * Don't do the set_flag() if the address is an alias with a - at the
+                * end, since it's deleted already! - Roman
+                *
+                * Should really use regex.h here, not sure though how well it'll go
+                * with the cross-platform support etc. 
+                */
+               {
+                       char *ptr;
+                       short int found_colon = 0;
+                       for (ptr = ifr.ifr_name; *ptr; ptr++ )
+                               if (*ptr == ':') found_colon++;
+                       
+                       if (!(found_colon && *(ptr - 1) == '-'))
+                               goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
+               }
+               
+               spp++;
+
+       } /* end of while-loop */
+
+        exit(0);
+}
+
index 4bd8b79..9aa65da 100644 (file)
@@ -158,6 +158,9 @@ const struct BB_applet applets[] = {
 #ifdef BB_ID
        APPLET("id", id_main, _BB_DIR_USR_BIN, id_usage)
 #endif
+#ifdef BB_IFCONFIG
+       APPLET("ifconfig", ifconfig_main, _BB_DIR_SBIN, ifconfig_usage)
+#endif
 #ifdef BB_INIT
        APPLET_NOUSAGE("init", init_main, _BB_DIR_SBIN)
 #endif
@@ -284,6 +287,9 @@ const struct BB_applet applets[] = {
 #ifdef BB_RMMOD
        APPLET("rmmod", rmmod_main, _BB_DIR_SBIN, rmmod_usage)
 #endif
+#ifdef BB_ROUTE
+       APPLET("route", route_main, _BB_DIR_USR_BIN, route_usage)
+#endif
 #ifdef BB_RPMUNPACK
        APPLET("rpmunpack", rpmunpack_main, _BB_DIR_USR_BIN, rpmunpack_usage)
 #endif
index 101e659..39580b5 100644 (file)
@@ -161,6 +161,7 @@ extern void *xcalloc(size_t nmemb, size_t size);
 extern char *xstrdup (const char *s);
 #endif
 extern char *xstrndup (const char *s, int n);
+extern char * safe_strncpy(char *dst, const char *src, size_t size);
 
 struct suffix_mult {
        char *suffix;
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
new file mode 100644 (file)
index 0000000..2134f8a
--- /dev/null
@@ -0,0 +1,476 @@
+/* ifconfig
+ *
+ * Similar to the standard Unix ifconfig, but with only the necessary
+ * parts for AF_INET, and without any printing of if info (for now).
+ *
+ * Bjorn Wesen, Axis Communications AB
+ *
+ *
+ * Authors of the original ifconfig was:      
+ *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * 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: ifconfig.c,v 1.1 2001/02/14 08:11:27 andersen Exp $
+ *
+ */
+
+#include "busybox.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>   // strcmp and friends
+#include <ctype.h>    // isdigit and friends
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
+static int sockfd;  /* socket fd we use to manipulate stuff with */
+
+/* print usage and exit */
+
+#define _(x) x
+
+/* Set a certain interface flag. */
+static int
+set_flag(char *ifname, short flag)
+{
+       struct ifreq ifr;
+       
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+               perror("SIOCGIFFLAGS"); 
+               return (-1);
+       }
+       strcpy(ifr.ifr_name, ifname);
+       ifr.ifr_flags |= flag;
+       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+               perror("SIOCSIFFLAGS");
+               return -1;
+       }
+       return (0);
+}
+
+
+/* Clear a certain interface flag. */
+static int
+clr_flag(char *ifname, short flag)
+{
+       struct ifreq ifr;
+       
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+               perror("SIOCGIFFLAGS");
+               return -1;
+       }
+       strcpy(ifr.ifr_name, ifname);
+       ifr.ifr_flags &= ~flag;
+       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+               perror("SIOCSIFFLAGS");
+               return -1;
+       }
+       return (0);
+}
+
+/* resolve XXX.YYY.ZZZ.QQQ -> binary */
+
+static int
+INET_resolve(char *name, struct sockaddr_in *sin)
+{
+       sin->sin_family = AF_INET;
+       sin->sin_port = 0;
+
+       /* Default is special, meaning 0.0.0.0. */
+       if (!strcmp(name, "default")) {
+               sin->sin_addr.s_addr = INADDR_ANY;
+               return (1);
+       }
+       /* Look to see if it's a dotted quad. */
+       if (inet_aton(name, &sin->sin_addr)) {
+               return 0;
+       }
+       /* guess not.. */
+       return -1;
+}
+
+/* Input an Ethernet address and convert to binary. */
+static int
+in_ether(char *bufp, struct sockaddr *sap)
+{
+       unsigned char *ptr;
+       char c, *orig;
+       int i;
+       unsigned val;
+       
+       sap->sa_family = ARPHRD_ETHER;
+       ptr = sap->sa_data;
+       
+       i = 0;
+       orig = bufp;
+       while ((*bufp != '\0') && (i < ETH_ALEN)) {
+               val = 0;
+               c = *bufp++;
+               if (isdigit(c))
+                       val = c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       val = c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       val = c - 'A' + 10;
+               else {
+#ifdef DEBUG
+                       fprintf(stderr,
+                               _("in_ether(%s): invalid ether address!\n"),
+                               orig);
+#endif
+                       errno = EINVAL;
+                       return (-1);
+               }
+               val <<= 4;
+               c = *bufp;
+               if (isdigit(c))
+                       val |= c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       val |= c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       val |= c - 'A' + 10;
+               else if (c == ':' || c == 0)
+                       val >>= 4;
+               else {
+#ifdef DEBUG
+                       fprintf(stderr,
+                               _("in_ether(%s): invalid ether address!\n"),
+                               orig);
+#endif
+                       errno = EINVAL;
+                       return (-1);
+               }
+               if (c != 0)
+                       bufp++;
+               *ptr++ = (unsigned char) (val & 0377);
+               i++;
+               
+               /* We might get a semicolon here - not required. */
+               if (*bufp == ':')
+                       bufp++;
+               
+       }
+
+       if(i != ETH_ALEN) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+int ifconfig_main(int argc, char **argv)
+{
+       struct ifreq ifr;
+       struct sockaddr_in sa;
+       struct sockaddr sa2;
+       char **spp;
+       int goterr = 0;
+       int r, didnetmask = 0;
+       char host[128];
+
+       if(argc < 2) {
+               usage(ifconfig_usage);
+       }
+
+       /* Create a channel to the NET kernel. */
+       if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               perror("socket");
+               exit(1);
+       }
+
+       /* skip argv[0] */
+
+       argc--;
+       argv++;
+
+       spp = argv;
+
+       /* get interface name */
+
+       safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
+
+       /* Process the remaining arguments. */
+       while (*spp != (char *) NULL) {
+               if (!strcmp(*spp, "arp")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-arp")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
+                       spp++;
+                       continue;
+               }
+               
+               if (!strcmp(*spp, "trailers")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-trailers")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "promisc")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-promisc")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "multicast")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-multicast")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "allmulti")) {
+                       goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "-allmulti")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "up")) {
+                       goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "down")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_UP);
+                       spp++;
+                       continue;
+               }
+
+               if (!strcmp(*spp, "metric")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_metric = atoi(*spp);
+                       if (ioctl(sockfd, SIOCSIFMETRIC, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "mtu")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_mtu = atoi(*spp);
+                       if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+#ifdef SIOCSKEEPALIVE
+               if (!strcmp(*spp, "keepalive")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_data = (caddr_t) atoi(*spp);
+                       if (ioctl(sockfd, SIOCSKEEPALIVE, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+#endif
+
+#ifdef SIOCSOUTFILL
+               if (!strcmp(*spp, "outfill")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       ifr.ifr_data = (caddr_t) atoi(*spp);
+                       if (ioctl(sockfd, SIOCSOUTFILL, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+#endif
+
+               if (!strcmp(*spp, "-broadcast")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "broadcast")) {
+                       if (*++spp != NULL) {
+                               safe_strncpy(host, *spp, (sizeof host));
+                               if (INET_resolve(host, &sa) < 0) {
+                                       goterr++;
+                                       spp++;
+                                       continue;
+                               }
+                               memcpy((char *) &ifr.ifr_broadaddr,
+                                      (char *) &sa,
+                                      sizeof(struct sockaddr));
+                               if (ioctl(sockfd, SIOCSIFBRDADDR, &ifr) < 0) {
+                                       perror("SIOCSIFBRDADDR");
+                                       goterr++;
+                               }
+                               spp++;
+                       }
+                       goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
+                       continue;
+               }
+               if (!strcmp(*spp, "dstaddr")) {
+                       if (*++spp == NULL)
+                               usage(ifconfig_usage);
+                       safe_strncpy(host, *spp, (sizeof host));
+                       if (INET_resolve(host, &sa) < 0) {
+                               goterr++;
+                               spp++;
+                               continue;
+                       }
+                       memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
+                              sizeof(struct sockaddr));
+                       if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
+                               fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
+                                       strerror(errno));
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "netmask")) {
+                       if (*++spp == NULL || didnetmask)
+                               usage(ifconfig_usage);
+                       safe_strncpy(host, *spp, (sizeof host));
+                       if (INET_resolve(host, &sa) < 0) {
+                               goterr++;
+                               spp++;
+                               continue;
+                       }
+                       didnetmask++;
+                       memcpy((char *) &ifr.ifr_netmask, (char *) &sa,
+                              sizeof(struct sockaddr));
+                       if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
+                               perror("SIOCSIFNETMASK");
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+
+               if (!strcmp(*spp, "-pointopoint")) {
+                       goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
+                       spp++;
+                       continue;
+               }
+               if (!strcmp(*spp, "pointopoint")) {
+                       if (*(spp + 1) != NULL) {
+                               spp++;
+                               safe_strncpy(host, *spp, (sizeof host));
+                               if (INET_resolve(host, &sa)) {
+                                       goterr++;
+                                       spp++;
+                                       continue;
+                               }
+                               memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
+                                      sizeof(struct sockaddr));
+                               if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
+                                       perror("SIOCSIFDSTADDR");
+                                       goterr++;
+                               }
+                       }
+                       goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
+                       spp++;
+                       continue;
+               };
+
+               if (!strcmp(*spp, "hw")) {
+                       if (*++spp == NULL || strcmp("ether", *spp)) {
+                               usage(ifconfig_usage);
+                       }
+                               
+                       if (*++spp == NULL) {
+                               /* silently ignore it if no address */
+                               continue;
+                       }
+
+                       safe_strncpy(host, *spp, (sizeof host));
+                       if (in_ether(host, &sa2) < 0) {
+                               fprintf(stderr, "invalid hw-addr %s\n", host);
+                               goterr++;
+                               spp++;
+                               continue;
+                       }
+                       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa2,
+                              sizeof(struct sockaddr));
+                       if (ioctl(sockfd, SIOCSIFHWADDR, &ifr) < 0) {
+                               perror("SIOCSIFHWADDR");
+                               goterr++;
+                       }
+                       spp++;
+                       continue;
+               }
+
+               /* If the next argument is a valid hostname, assume OK. */
+               safe_strncpy(host, *spp, (sizeof host));
+
+               if (INET_resolve(host, &sa) < 0) {
+                       usage(ifconfig_usage);
+               }
+               memcpy((char *) &ifr.ifr_addr,
+                      (char *) &sa, sizeof(struct sockaddr));
+
+               r = ioctl(sockfd, SIOCSIFADDR, &ifr);
+
+               if (r < 0) {
+                       perror("SIOCSIFADDR");
+                       goterr++;
+               }
+
+               /*
+                * Don't do the set_flag() if the address is an alias with a - at the
+                * end, since it's deleted already! - Roman
+                *
+                * Should really use regex.h here, not sure though how well it'll go
+                * with the cross-platform support etc. 
+                */
+               {
+                       char *ptr;
+                       short int found_colon = 0;
+                       for (ptr = ifr.ifr_name; *ptr; ptr++ )
+                               if (*ptr == ':') found_colon++;
+                       
+                       if (!(found_colon && *(ptr - 1) == '-'))
+                               goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
+               }
+               
+               spp++;
+
+       } /* end of while-loop */
+
+        exit(0);
+}
+
diff --git a/networking/route.c b/networking/route.c
new file mode 100644 (file)
index 0000000..76b2306
--- /dev/null
@@ -0,0 +1,372 @@
+/* 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.1 2001/02/14 08:11:27 andersen Exp $
+ *
+ */
+
+#include "busybox.h"
+#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>
+
+#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
+
+/* resolve XXX.YYY.ZZZ.QQQ -> binary */
+
+static int
+INET_resolve(char *name, struct sockaddr *sa)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+       
+       sin->sin_family = AF_INET;
+       sin->sin_port = 0;
+
+       /* Default is special, meaning 0.0.0.0. */
+       if (!strcmp(name, "default")) {
+               sin->sin_addr.s_addr = INADDR_ANY;
+               return (1);
+       }
+       /* Look to see if it's a dotted quad. */
+       if (inet_aton(name, &sin->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")) {
+               xflag = 1;
+               args++;
+       } else if (!strcmp(*args, "-host")) {
+               xflag = 2;
+               args++;
+       }
+       if (*args == NULL)
+               usage(route_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) {
+               fprintf(stderr, "cant resolve %s\n", target);
+               return (1);
+       }
+
+       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")) {
+                       int metric;
+                       
+                       args++;
+                       if (!*args || !isdigit(**args))
+                               usage(route_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")) {
+                       struct sockaddr mask;
+                       
+                       args++;
+                       if (!*args || mask_in_addr(rt))
+                               usage(route_usage);
+                       safe_strncpy(netmask, *args, (sizeof netmask));
+                       if ((isnet = INET_resolve(netmask, &mask)) < 0) {
+                               fprintf(stderr, "cant resolve netmask %s\n", netmask);
+                               return (E_LOOKUP);
+                       }
+                       rt.rt_genmask = full_mask(mask);
+                       args++;
+                       continue;
+               }
+
+               if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
+                       args++;
+                       if (!*args)
+                               usage(route_usage);
+                       if (rt.rt_flags & RTF_GATEWAY)
+                               usage(route_usage);
+                       safe_strncpy(gateway, *args, (sizeof gateway));
+                       if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
+                               fprintf(stderr, "cant resolve gw %s\n", gateway);
+                               return (E_LOOKUP);
+                       }
+                       if (isnet) {
+                               fprintf(stderr,
+                                       _("route: %s: cannot use a NETWORK as gateway!\n"),
+                                       gateway);
+                               return (E_OPTERR);
+                       }
+                       rt.rt_flags |= RTF_GATEWAY;
+                       args++;
+                       continue;
+               }
+
+               if (!strcmp(*args, "mss")) {
+                       args++;
+                       rt.rt_flags |= RTF_MSS;
+                       if (!*args)
+                               usage(route_usage);
+                       rt.rt_mss = atoi(*args);
+                       args++;
+                       if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
+                               fprintf(stderr, _("route: Invalid MSS.\n"));
+                               return (E_OPTERR);
+                       }
+                       continue;
+               }
+
+               if (!strcmp(*args, "window")) {
+                       args++;
+                       if (!*args)
+                               usage(route_usage);
+                       rt.rt_flags |= RTF_WINDOW;
+                       rt.rt_window = atoi(*args);
+                       args++;
+                       if (rt.rt_window < 128) {
+                               fprintf(stderr, _("route: Invalid window.\n"));
+                               return (E_OPTERR);
+                       }
+                       continue;
+               }
+
+               if (!strcmp(*args, "irtt")) {
+                       args++;
+                       if (!*args)
+                               usage(route_usage);
+                       args++;
+#if HAVE_RTF_IRTT
+                       rt.rt_flags |= RTF_IRTT;
+                       rt.rt_irtt = atoi(*(args - 1));
+                       rt.rt_irtt *= (HZ / 100);       /* FIXME */
+#if 0                          /* FIXME: do we need to check anything of this? */
+                       if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
+                               fprintf(stderr, _("route: Invalid initial rtt.\n"));
+                               return (E_OPTERR);
+                       }
+#endif
+#else
+                       ENOSUPP("inet_setroute", "RTF_IRTT");
+#endif
+                       continue;
+               }
+
+               if (!strcmp(*args, "reject")) {
+                       args++;
+#if HAVE_RTF_REJECT
+                       rt.rt_flags |= RTF_REJECT;
+#else
+                       ENOSUPP("inet_setroute", "RTF_REJECT");
+#endif
+                       continue;
+               }
+               if (!strcmp(*args, "mod")) {
+                       args++;
+                       rt.rt_flags |= RTF_MODIFIED;
+                       continue;
+               }
+               if (!strcmp(*args, "dyn")) {
+                       args++;
+                       rt.rt_flags |= RTF_DYNAMIC;
+                       continue;
+               }
+               if (!strcmp(*args, "reinstate")) {
+                       args++;
+                       rt.rt_flags |= RTF_REINSTATE;
+                       continue;
+               }
+               if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
+                       args++;
+                       if (rt.rt_dev || *args == NULL)
+                               usage(route_usage);
+                       rt.rt_dev = *args++;
+                       continue;
+               }
+               /* nothing matches */
+               if (!rt.rt_dev) {
+                       rt.rt_dev = *args++;
+                       if (*args)
+                               usage(route_usage);     /* must be last to catch typos */
+               } else
+                       usage(route_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) {
+                       fprintf(stderr,
+                               _("route: netmask %.8x doesn't make sense with host route\n"),
+                               (unsigned int)mask);
+                       return (E_OPTERR);
+               }
+               if (mask & (mask + 1)) {
+                       fprintf(stderr, _("route: bogus netmask %s\n"), netmask);
+                       return (E_OPTERR);
+               }
+               mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
+               if (mask & ~mask_in_addr(rt)) {
+                       fprintf(stderr, _("route: netmask doesn't match route address\n"));
+                       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 (0);
+}
+
+int route_main(int argc, char **argv)
+{
+       int what = 0;
+
+       argc--;
+       argv++;
+
+       if (*argv == NULL) {
+               //displayroutes();
+               fprintf(stderr, "print routes is not implemented yet\n");
+               usage(route_usage);
+       } else {
+               /* check verb */
+               if (!strcmp(*argv, "add"))
+                       what = RTACTION_ADD;
+               else if (!strcmp(*argv, "del") || !strcmp(*argv, "delete"))
+                       what = RTACTION_DEL;
+               else if (!strcmp(*argv, "flush"))
+                       what = RTACTION_FLUSH;
+               else
+                       usage(route_usage);
+       }
+
+       INET_setroute(what, 0, ++argv);
+
+       exit(0);
+}
diff --git a/route.c b/route.c
new file mode 100644 (file)
index 0000000..76b2306
--- /dev/null
+++ b/route.c
@@ -0,0 +1,372 @@
+/* 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.1 2001/02/14 08:11:27 andersen Exp $
+ *
+ */
+
+#include "busybox.h"
+#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>
+
+#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
+
+/* resolve XXX.YYY.ZZZ.QQQ -> binary */
+
+static int
+INET_resolve(char *name, struct sockaddr *sa)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+       
+       sin->sin_family = AF_INET;
+       sin->sin_port = 0;
+
+       /* Default is special, meaning 0.0.0.0. */
+       if (!strcmp(name, "default")) {
+               sin->sin_addr.s_addr = INADDR_ANY;
+               return (1);
+       }
+       /* Look to see if it's a dotted quad. */
+       if (inet_aton(name, &sin->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")) {
+               xflag = 1;
+               args++;
+       } else if (!strcmp(*args, "-host")) {
+               xflag = 2;
+               args++;
+       }
+       if (*args == NULL)
+               usage(route_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) {
+               fprintf(stderr, "cant resolve %s\n", target);
+               return (1);
+       }
+
+       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")) {
+                       int metric;
+                       
+                       args++;
+                       if (!*args || !isdigit(**args))
+                               usage(route_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")) {
+                       struct sockaddr mask;
+                       
+                       args++;
+                       if (!*args || mask_in_addr(rt))
+                               usage(route_usage);
+                       safe_strncpy(netmask, *args, (sizeof netmask));
+                       if ((isnet = INET_resolve(netmask, &mask)) < 0) {
+                               fprintf(stderr, "cant resolve netmask %s\n", netmask);
+                               return (E_LOOKUP);
+                       }
+                       rt.rt_genmask = full_mask(mask);
+                       args++;
+                       continue;
+               }
+
+               if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
+                       args++;
+                       if (!*args)
+                               usage(route_usage);
+                       if (rt.rt_flags & RTF_GATEWAY)
+                               usage(route_usage);
+                       safe_strncpy(gateway, *args, (sizeof gateway));
+                       if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
+                               fprintf(stderr, "cant resolve gw %s\n", gateway);
+                               return (E_LOOKUP);
+                       }
+                       if (isnet) {
+                               fprintf(stderr,
+                                       _("route: %s: cannot use a NETWORK as gateway!\n"),
+                                       gateway);
+                               return (E_OPTERR);
+                       }
+                       rt.rt_flags |= RTF_GATEWAY;
+                       args++;
+                       continue;
+               }
+
+               if (!strcmp(*args, "mss")) {
+                       args++;
+                       rt.rt_flags |= RTF_MSS;
+                       if (!*args)
+                               usage(route_usage);
+                       rt.rt_mss = atoi(*args);
+                       args++;
+                       if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
+                               fprintf(stderr, _("route: Invalid MSS.\n"));
+                               return (E_OPTERR);
+                       }
+                       continue;
+               }
+
+               if (!strcmp(*args, "window")) {
+                       args++;
+                       if (!*args)
+                               usage(route_usage);
+                       rt.rt_flags |= RTF_WINDOW;
+                       rt.rt_window = atoi(*args);
+                       args++;
+                       if (rt.rt_window < 128) {
+                               fprintf(stderr, _("route: Invalid window.\n"));
+                               return (E_OPTERR);
+                       }
+                       continue;
+               }
+
+               if (!strcmp(*args, "irtt")) {
+                       args++;
+                       if (!*args)
+                               usage(route_usage);
+                       args++;
+#if HAVE_RTF_IRTT
+                       rt.rt_flags |= RTF_IRTT;
+                       rt.rt_irtt = atoi(*(args - 1));
+                       rt.rt_irtt *= (HZ / 100);       /* FIXME */
+#if 0                          /* FIXME: do we need to check anything of this? */
+                       if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
+                               fprintf(stderr, _("route: Invalid initial rtt.\n"));
+                               return (E_OPTERR);
+                       }
+#endif
+#else
+                       ENOSUPP("inet_setroute", "RTF_IRTT");
+#endif
+                       continue;
+               }
+
+               if (!strcmp(*args, "reject")) {
+                       args++;
+#if HAVE_RTF_REJECT
+                       rt.rt_flags |= RTF_REJECT;
+#else
+                       ENOSUPP("inet_setroute", "RTF_REJECT");
+#endif
+                       continue;
+               }
+               if (!strcmp(*args, "mod")) {
+                       args++;
+                       rt.rt_flags |= RTF_MODIFIED;
+                       continue;
+               }
+               if (!strcmp(*args, "dyn")) {
+                       args++;
+                       rt.rt_flags |= RTF_DYNAMIC;
+                       continue;
+               }
+               if (!strcmp(*args, "reinstate")) {
+                       args++;
+                       rt.rt_flags |= RTF_REINSTATE;
+                       continue;
+               }
+               if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
+                       args++;
+                       if (rt.rt_dev || *args == NULL)
+                               usage(route_usage);
+                       rt.rt_dev = *args++;
+                       continue;
+               }
+               /* nothing matches */
+               if (!rt.rt_dev) {
+                       rt.rt_dev = *args++;
+                       if (*args)
+                               usage(route_usage);     /* must be last to catch typos */
+               } else
+                       usage(route_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) {
+                       fprintf(stderr,
+                               _("route: netmask %.8x doesn't make sense with host route\n"),
+                               (unsigned int)mask);
+                       return (E_OPTERR);
+               }
+               if (mask & (mask + 1)) {
+                       fprintf(stderr, _("route: bogus netmask %s\n"), netmask);
+                       return (E_OPTERR);
+               }
+               mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
+               if (mask & ~mask_in_addr(rt)) {
+                       fprintf(stderr, _("route: netmask doesn't match route address\n"));
+                       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 (0);
+}
+
+int route_main(int argc, char **argv)
+{
+       int what = 0;
+
+       argc--;
+       argv++;
+
+       if (*argv == NULL) {
+               //displayroutes();
+               fprintf(stderr, "print routes is not implemented yet\n");
+               usage(route_usage);
+       } else {
+               /* check verb */
+               if (!strcmp(*argv, "add"))
+                       what = RTACTION_ADD;
+               else if (!strcmp(*argv, "del") || !strcmp(*argv, "delete"))
+                       what = RTACTION_DEL;
+               else if (!strcmp(*argv, "flush"))
+                       what = RTACTION_FLUSH;
+               else
+                       usage(route_usage);
+       }
+
+       INET_setroute(what, 0, ++argv);
+
+       exit(0);
+}
diff --git a/usage.c b/usage.c
index 13107c6..bdd4d3d 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -556,6 +556,26 @@ const char id_usage[] =
        ;
 #endif
 
+#if defined BB_IFCONFIG
+const char ifconfig_usage[] =
+       "ifconfig [-a] [-i] [-v] <interface> [<address>]"
+#ifndef BB_FEATURE_TRIVIAL_HELP
+       "\n\nconfigure a network interface\n\n"
+       "Options:\n"
+       "  [[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n"
+       "  [netmask <address>]  [dstaddr <address>]  [tunnel <adress>]\n"
+#ifdef SIOCSKEEPALIVE
+       "  [outfill <NN>] [keepalive <NN>]\n"
+#endif
+       "  [hw ether <address>]  [metric <NN>]  [mtu <NN>]\n"
+       "  [[-]trailers]  [[-]arp]  [[-]allmulti]\n"
+       "  [multicast]  [[-]promisc]\n"
+       "  [mem_start <NN>]  [io_addr <NN>]  [irq <NN>]  [media <type>]\n"
+       "  [up|down] ..."
+#endif
+       ;
+#endif
+
 #if defined BB_INSMOD
 const char insmod_usage[] =
        "insmod [OPTION]... MODULE [symbol=value]..."
@@ -1144,6 +1164,15 @@ const char rmmod_usage[] =
        ;
 #endif
 
+#if defined BB_ROUTE
+const char route_usage[] =
+       "route [{add|del|flush}]"
+#ifndef BB_FEATURE_TRIVIAL_HELP
+       "\n\nEdit the kernel's routing tables"
+#endif
+       ;
+#endif
+
 #if defined BB_RPMUNPACK
 const char rpmunpack_usage[] =
        "rpmunpack < package.rpm | gunzip | cpio -idmuv"
index f3c184e..368dfc5 100644 (file)
--- a/utility.c
+++ b/utility.c
@@ -1377,6 +1377,14 @@ extern char * xstrndup (const char *s, int n) {
 }
 #endif
 
+#if defined BB_IFCONFIG || defined BB_ROUTE
+/* Like strncpy but make sure the resulting string is always 0 terminated. */  
+extern char * safe_strncpy(char *dst, const char *src, size_t size)
+{   
+       dst[size-1] = '\0';
+       return strncpy(dst, src, size-1);   
+}
+#endif
 
 #if (__GLIBC__ < 2) && (defined BB_SYSLOGD || defined BB_INIT)
 extern int vdprintf(int d, const char *format, va_list ap)