diff options
-rw-r--r-- | Config.h | 2 | ||||
-rw-r--r-- | applets.h | 6 | ||||
-rw-r--r-- | applets/usage.c | 29 | ||||
-rw-r--r-- | busybox.h | 1 | ||||
-rw-r--r-- | ifconfig.c | 476 | ||||
-rw-r--r-- | include/applets.h | 6 | ||||
-rw-r--r-- | include/busybox.h | 1 | ||||
-rw-r--r-- | networking/ifconfig.c | 476 | ||||
-rw-r--r-- | networking/route.c | 372 | ||||
-rw-r--r-- | route.c | 372 | ||||
-rw-r--r-- | usage.c | 29 | ||||
-rw-r--r-- | utility.c | 8 |
12 files changed, 1778 insertions, 0 deletions
@@ -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 @@ -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 diff --git a/applets/usage.c b/applets/usage.c index 13107c6e0..bdd4d3d83 100644 --- a/applets/usage.c +++ b/applets/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" @@ -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 index 000000000..2134f8a48 --- /dev/null +++ b/ifconfig.c @@ -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/include/applets.h b/include/applets.h index 4bd8b79e4..9aa65dac0 100644 --- a/include/applets.h +++ b/include/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 diff --git a/include/busybox.h b/include/busybox.h index 101e65989..39580b548 100644 --- a/include/busybox.h +++ b/include/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/networking/ifconfig.c b/networking/ifconfig.c new file mode 100644 index 000000000..2134f8a48 --- /dev/null +++ b/networking/ifconfig.c @@ -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 index 000000000..76b2306fd --- /dev/null +++ b/networking/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/route.c b/route.c new file mode 100644 index 000000000..76b2306fd --- /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); +} @@ -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" @@ -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) |