--- net-tools-1.52/ifconfig.c Wed Apr 21 13:48:53 1999 +++ net-tools-NEW/ifconfig.c Mon Mar 6 11:09:35 2000 @@ -13,6 +13,10 @@ * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. + * + * Patched to support 'add' and 'del' keywords for INET(4) addresses + * by Mrs. Brisby + * * {1.34} - 19980630 - Arnaldo Carvalho de Melo * - gettext instead of catgets for i18n * 10/1998 - Andi Kleen. Use interface list primitives. @@ -117,6 +121,15 @@ int addr_family = 0; /* currently selected AF */ +/* for ipv4 add/del modes */ +static int get_nmbc_parent(char *parent, + unsigned long *nm, unsigned long *bc); +static int set_ifstate(char *parent, + unsigned long ip, + unsigned long nm, + unsigned long bc, + int flag); + void ife_print(struct interface *ptr) { @@ -418,16 +431,9 @@ static void usage(void) { fprintf(stderr, _("Usage:\n ifconfig [-a] [-i] [-v] [[]
]\n")); - /* XXX: it would be useful to have the add/del syntax even without IPv6. - the 2.1 interface address lists make this natural */ -#ifdef HAVE_AFINET6 +#if HAVE_AFINET fprintf(stderr, _(" [add
[/]]\n")); -#ifdef SIOCDIFADDR fprintf(stderr, _(" [del
[/]]\n")); -#endif - /* XXX the kernel supports tunneling even without ipv6 */ -#endif -#if HAVE_AFINET fprintf(stderr, _(" [[-]broadcast [
]] [[-]pointopoint [
]]\n")); fprintf(stderr, _(" [netmask
] [dstaddr
] [tunnel
]\n")); #endif @@ -478,6 +484,7 @@ int main(int argc, char **argv) { struct sockaddr sa; + struct sockaddr_in sin; char host[128]; struct aftype *ap; struct hwtype *hw; @@ -492,6 +499,9 @@ unsigned long prefix_len; char *cp; #endif +#if HAVE_AFINET + extern struct aftype inet_aftype; +#endif #if I18N bindtextdomain("net-tools", "/usr/share/locale"); @@ -892,10 +902,13 @@ spp++; continue; } -#if HAVE_AFINET6 +#if HAVE_AFINET if (!strcmp(*spp, "add")) { if (*++spp == NULL) usage(); + if (strchr(*spp, '.') == 0) { + /* INET6 */ +#if HAVE_AFINET6 if ((cp = strchr(*spp, '/'))) { prefix_len = atol(cp + 1); if ((prefix_len < 0) || (prefix_len > 128)) @@ -933,12 +946,56 @@ perror("SIOCSIFADDR"); goterr = 1; } + } +#else /* InetV4 */ + fprintf(stderr, _("No support for INET6 on this system.\n")); + goterr = 1; + spp++; + continue; + } +#endif +else { /* ipv4 address a.b.c.d */ +auto unsigned long ip, nm, bc; + safe_strncpy(host, *spp, (sizeof host)); + if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) { + ap->herror(host); + goterr = 1; + spp++; + continue; + } + fd = get_socket_for_af(AF_INET); + if (fd < 0) { + fprintf(stderr, _("No support for INET on this system.\n")); + goterr = 1; + spp++; + continue; + } + + memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long)); + + if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) { + fprintf(stderr, _("Interface %s not initialized\n"), + ifr.ifr_name); + goterr = 1; + spp++; + continue; + } + set_ifstate(ifr.ifr_name, ip, nm, bc, 1); + + } spp++; continue; } +#endif + +#if HAVE_AFINET if (!strcmp(*spp, "del")) { if (*++spp == NULL) usage(); + + if (strchr(*spp, '.') == 0) { + /* INET6 */ +#if HAVE_AFINET6 if ((cp = strchr(*spp, '/'))) { prefix_len = atol(cp + 1); if ((prefix_len < 0) || (prefix_len > 128)) @@ -981,9 +1038,48 @@ #else fprintf(stderr, _("Address deletion not supported on this system.\n")); #endif + } +#else /* InetV4 */ + fprintf(stderr, _("No support for INET6 on this system.\n")); + goterr = 1; + spp++; + continue; + } +#endif +else { /* ipv4 address a.b.c.d */ +auto unsigned long ip, nm, bc; + safe_strncpy(host, *spp, (sizeof host)); + if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) { + ap->herror(host); + goterr = 1; + spp++; + continue; + } + fd = get_socket_for_af(AF_INET); + if (fd < 0) { + fprintf(stderr, _("No support for INET on this system.\n")); + goterr = 1; + spp++; + continue; + } + + memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long)); + + if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) { + fprintf(stderr, _("Interface %s not initialized\n"), + ifr.ifr_name); + goterr = 1; + spp++; + continue; + } + set_ifstate(ifr.ifr_name, ip, nm, bc, 0); + + } spp++; continue; } +#endif +#if HAVE_AFINET6 if (!strcmp(*spp, "tunnel")) { if (*++spp == NULL) usage(); @@ -1109,4 +1205,122 @@ } return (goterr); +} +struct ifcmd { + int flag; + unsigned long addr; + char *base; + int baselen; +}; +static unsigned char searcher[256]; + +static int set_ip_using(const char *name, int c, unsigned long ip) +{ + struct ifreq ifr; + struct sockaddr_in sin; + + strcpy(ifr.ifr_name, name); + memset(&sin, 0, sizeof(struct sockaddr)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ip; + memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); + if (ioctl(skfd, c, &ifr) < 0) + return -1; + return 0; +} +static int do_ifcmd(struct interface *x, struct ifcmd *ptr) +{ + char *z, *e; + struct sockaddr_in *sin; + int i; + + if (do_if_fetch(x) < 0) + return 0; + if (strncmp(x->name, ptr->base, ptr->baselen) != 0) + return 0; /* skip */ + z = strchr(x->name, ':'); + if (!z || !*z) + return 0; + z++; + for (e = z; *e; e++) + if (*e == '-') /* deleted */ + return 0; + i = atoi(z); + searcher[i] = 1; + + /* copy */ + sin = (struct sockaddr_in *)&x->dstaddr; + if (sin->sin_addr.s_addr != ptr->addr) { + return 0; + } + + if (ptr->flag) { + /* turn UP */ + if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1) + return -1; + } else { + /* turn DOWN */ + if (clr_flag(x->name, IFF_UP) == -1) + return -1; + } + + return 1; /* all done! */ +} + + +static int get_nmbc_parent(char *parent, + unsigned long *nm, unsigned long *bc) +{ + struct interface *i; + struct sockaddr_in *sin; + + i = lookup_interface(parent); + if (!i) + return -1; + if (do_if_fetch(i) < 0) + return 0; + sin = (struct sockaddr_in *)&i->netmask; + memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long)); + sin = (struct sockaddr_in *)&i->broadaddr; + memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long)); + return 0; +} +static int set_ifstate(char *parent, + unsigned long ip, + unsigned long nm, + unsigned long bc, + int flag) +{ + char buf[IFNAMSIZ]; + struct ifcmd pt; + int i; + + pt.base = parent; + pt.baselen = strlen(parent); + pt.addr = ip; + pt.flag = flag; + memset(searcher, 0, sizeof(searcher)); + i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd, &pt); + if (i == -1) + return -1; + if (i == 1) + return 0; + + /* add a new interface */ + for (i = 0; i < 256; i++) + if (searcher[i] == 0) + break; + if (i == 256) + return -1; /* FAILURE!!! out of ip addresses */ + + sprintf(buf, "%s:%d", parent, i); + if (set_ip_using(buf, SIOCSIFADDR, ip) == -1) + return -1; + if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1) + return -1; + if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1) + return -1; + if (set_flag(buf, IFF_BROADCAST) == -1) + return -1; + return 0; }