fixing debian bug #151130 reported by Dan Jacobson where netstat
[oss-qm-packages.git] / ifconfig.c
blobe496b2668a4d99be92d806695726330cccb3106d
1 /*
2 * ifconfig This file contains an implementation of the command
3 * that either displays or sets the characteristics of
4 * one or more of the system's networking interfaces.
6 * Version: $Id: ifconfig.c,v 1.54 2001/11/01 03:00:13 ecki Exp $
8 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
9 * and others. Copyright 1993 MicroWalt Corporation
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * Patched to support 'add' and 'del' keywords for INET(4) addresses
18 * by Mrs. Brisby <mrs.brisby@nimh.org>
20 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
21 * - gettext instead of catgets for i18n
22 * 10/1998 - Andi Kleen. Use interface list primitives.
23 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
24 * (default AF was wrong)
25 * 20010404 - Arnaldo Carvalho de Melo, use setlocale
28 #define DFLT_AF "inet"
30 #include "config.h"
32 #include <features.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <netinet/in.h>
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <stdio.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <netdb.h>
48 /* Ugh. But libc5 doesn't provide POSIX types. */
49 #include <asm/types.h>
52 #ifdef HAVE_HWSLIP
53 #include <linux/if_slip.h>
54 #endif
56 #if HAVE_AFINET6
58 #ifndef _LINUX_IN6_H
60 * This is in linux/include/net/ipv6.h.
63 struct in6_ifreq {
64 struct in6_addr ifr6_addr;
65 __u32 ifr6_prefixlen;
66 unsigned int ifr6_ifindex;
69 #endif
71 #endif /* HAVE_AFINET6 */
73 #if HAVE_AFIPX
74 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
75 #include <netipx/ipx.h>
76 #else
77 #include "ipx.h"
78 #endif
79 #endif
80 #include "net-support.h"
81 #include "pathnames.h"
82 #include "version.h"
83 #include "../intl.h"
84 #include "interface.h"
85 #include "sockets.h"
86 #include "util.h"
88 char *Release = RELEASE, *Version = "ifconfig 1.42 (2001-04-13)";
90 int opt_a = 0; /* show all interfaces */
91 int opt_i = 0; /* show the statistics */
92 int opt_v = 0; /* debugging output flag */
94 int addr_family = 0; /* currently selected AF */
96 /* for ipv4 add/del modes */
97 static int get_nmbc_parent(char *parent, unsigned long *nm,
98 unsigned long *bc);
99 static int set_ifstate(char *parent, unsigned long ip,
100 unsigned long nm, unsigned long bc,
101 int flag);
103 static int if_print(char *ifname)
105 int res;
107 if (ife_short)
108 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
110 if (!ifname) {
111 res = for_all_interfaces(do_if_print, &opt_a);
112 } else {
113 struct interface *ife;
115 ife = lookup_interface(ifname);
116 res = do_if_fetch(ife);
117 if (res >= 0)
118 ife_print(ife);
120 return res;
123 /* Set a certain interface flag. */
124 static int set_flag(char *ifname, short flag)
126 struct ifreq ifr;
128 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
129 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
130 fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
131 ifname, strerror(errno));
132 return (-1);
134 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
135 ifr.ifr_flags |= flag;
136 if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
137 perror("SIOCSIFFLAGS");
138 return -1;
140 return (0);
143 /* Clear a certain interface flag. */
144 static int clr_flag(char *ifname, short flag)
146 struct ifreq ifr;
147 int fd;
149 if (strchr(ifname, ':')) {
150 /* This is a v4 alias interface. Downing it via a socket for
151 another AF may have bad consequences. */
152 fd = get_socket_for_af(AF_INET);
153 if (fd < 0) {
154 fprintf(stderr, _("No support for INET on this system.\n"));
155 return -1;
157 } else
158 fd = skfd;
160 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
161 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
162 fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
163 ifname, strerror(errno));
164 return -1;
166 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
167 ifr.ifr_flags &= ~flag;
168 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
169 perror("SIOCSIFFLAGS");
170 return -1;
172 return (0);
175 /** test is a specified flag is set */
176 static int test_flag(char *ifname, short flags)
178 struct ifreq ifr;
179 int fd;
181 if (strchr(ifname, ':')) {
182 /* This is a v4 alias interface. Downing it via a socket for
183 another AF may have bad consequences. */
184 fd = get_socket_for_af(AF_INET);
185 if (fd < 0) {
186 fprintf(stderr, _("No support for INET on this system.\n"));
187 return -1;
189 } else
190 fd = skfd;
192 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
193 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
194 fprintf(stderr, _("%s: ERROR while testing interface flags: %s\n"),
195 ifname, strerror(errno));
196 return -1;
198 return (ifr.ifr_flags & flags);
201 static void usage(void)
203 fprintf(stderr, _("Usage:\n ifconfig [-a] [-i] [-v] [-s] <interface> [[<AF>] <address>]\n"));
204 #if HAVE_AFINET
205 fprintf(stderr, _(" [add <address>[/<prefixlen>]]\n"));
206 fprintf(stderr, _(" [del <address>[/<prefixlen>]]\n"));
207 fprintf(stderr, _(" [[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n"));
208 fprintf(stderr, _(" [netmask <address>] [dstaddr <address>] [tunnel <address>]\n"));
209 #endif
210 #ifdef SIOCSKEEPALIVE
211 fprintf(stderr, _(" [outfill <NN>] [keepalive <NN>]\n"));
212 #endif
213 fprintf(stderr, _(" [hw <HW> <address>] [metric <NN>] [mtu <NN>]\n"));
214 fprintf(stderr, _(" [[-]trailers] [[-]arp] [[-]allmulti]\n"));
215 fprintf(stderr, _(" [multicast] [[-]promisc]\n"));
216 fprintf(stderr, _(" [mem_start <NN>] [io_addr <NN>] [irq <NN>] [media <type>]\n"));
217 #ifdef HAVE_TXQUEUELEN
218 fprintf(stderr, _(" [txqueuelen <NN>]\n"));
219 #endif
220 #ifdef HAVE_DYNAMIC
221 fprintf(stderr, _(" [[-]dynamic]\n"));
222 #endif
223 fprintf(stderr, _(" [up|down] ...\n\n"));
225 fprintf(stderr, _(" <HW>=Hardware Type.\n"));
226 fprintf(stderr, _(" List of possible hardware types:\n"));
227 print_hwlist(0); /* 1 = ARPable */
228 fprintf(stderr, _(" <AF>=Address family. Default: %s\n"), DFLT_AF);
229 fprintf(stderr, _(" List of possible address families:\n"));
230 print_aflist(0); /* 1 = routeable */
231 exit(E_USAGE);
234 static void version(void)
236 fprintf(stderr, "%s\n%s\n", Release, Version);
237 exit(E_USAGE);
240 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
242 int err = 0;
244 memcpy((char *) &ifr->ifr_netmask, (char *) sa,
245 sizeof(struct sockaddr));
246 if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
247 fprintf(stderr, "SIOCSIFNETMASK: %s\n",
248 strerror(errno));
249 err = 1;
251 return err;
254 int main(int argc, char **argv)
256 struct sockaddr sa;
257 struct sockaddr samask;
258 struct sockaddr_in sin;
259 char host[128];
260 struct aftype *ap;
261 struct hwtype *hw;
262 struct ifreq ifr;
263 int goterr = 0, didnetmask = 0, neednetmask=0;
264 char **spp;
265 int fd;
266 #if HAVE_AFINET6
267 extern struct aftype inet6_aftype;
268 struct sockaddr_in6 sa6;
269 struct in6_ifreq ifr6;
270 unsigned long prefix_len;
271 char *cp;
272 #endif
273 #if HAVE_AFINET
274 extern struct aftype inet_aftype;
275 #endif
277 #if I18N
278 setlocale (LC_ALL, "");
279 bindtextdomain("net-tools", "/usr/share/locale");
280 textdomain("net-tools");
281 #endif
283 /* Find any options. */
284 argc--;
285 argv++;
286 while (argc && *argv[0] == '-') {
287 if (!strcmp(*argv, "-a"))
288 opt_a = 1;
290 else if (!strcmp(*argv, "-s"))
291 ife_short = 1;
293 else if (!strcmp(*argv, "-v"))
294 opt_v = 1;
296 else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
297 !strcmp(*argv, "--version"))
298 version();
300 else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
301 !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
302 usage();
304 else {
305 fprintf(stderr, _("ifconfig: option `%s' not recognised.\n"),
306 argv[0]);
307 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
308 exit(1);
311 argv++;
312 argc--;
315 /* Create a channel to the NET kernel. */
316 if ((skfd = sockets_open(0)) < 0) {
317 perror("socket");
318 exit(1);
321 /* Do we have to show the current setup? */
322 if (argc == 0) {
323 int err = if_print((char *) NULL);
324 (void) close(skfd);
325 exit(err < 0);
327 /* No. Fetch the interface name. */
328 spp = argv;
329 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
330 if (*spp == (char *) NULL) {
331 int err = if_print(ifr.ifr_name);
332 (void) close(skfd);
333 exit(err < 0);
336 /* The next argument is either an address family name, or an option. */
337 if ((ap = get_aftype(*spp)) != NULL)
338 spp++; /* it was a AF name */
339 else
340 ap = get_aftype(DFLT_AF);
342 if (ap) {
343 addr_family = ap->af;
344 skfd = ap->fd;
347 /* Process the remaining arguments. */
348 while (*spp != (char *) NULL) {
349 if (!strcmp(*spp, "arp")) {
350 goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
351 spp++;
352 continue;
354 if (!strcmp(*spp, "-arp")) {
355 goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
356 spp++;
357 continue;
359 #ifdef IFF_PORTSEL
360 if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
361 if (*++spp == NULL)
362 usage();
363 if (!strcasecmp(*spp, "auto")) {
364 goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
365 } else {
366 int i, j, newport;
367 char *endp;
368 newport = strtol(*spp, &endp, 10);
369 if (*endp != 0) {
370 newport = -1;
371 for (i = 0; if_port_text[i][0] && newport == -1; i++) {
372 for (j = 0; if_port_text[i][j]; j++) {
373 if (!strcasecmp(*spp, if_port_text[i][j])) {
374 newport = i;
375 break;
380 spp++;
381 if (newport == -1) {
382 fprintf(stderr, _("Unknown media type.\n"));
383 goterr = 1;
384 } else {
385 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
386 perror("port: SIOCGIFMAP");
387 goterr = 1;
388 continue;
390 ifr.ifr_map.port = newport;
391 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
392 perror("port: SIOCSIFMAP");
393 goterr = 1;
397 continue;
399 #endif
401 if (!strcmp(*spp, "trailers")) {
402 goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
403 spp++;
404 continue;
406 if (!strcmp(*spp, "-trailers")) {
407 goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
408 spp++;
409 continue;
411 if (!strcmp(*spp, "promisc")) {
412 goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
413 spp++;
414 continue;
416 if (!strcmp(*spp, "-promisc")) {
417 goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
418 if (test_flag(ifr.ifr_name, IFF_PROMISC) > 0)
419 fprintf(stderr, _("Warning: Interface %s still in promisc mode... maybe other application is running?\n"), ifr.ifr_name);
420 spp++;
421 continue;
423 if (!strcmp(*spp, "multicast")) {
424 goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
425 spp++;
426 continue;
428 if (!strcmp(*spp, "-multicast")) {
429 goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
430 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
431 fprintf(stderr, _("Warning: Interface %s still in MULTICAST mode.\n"), ifr.ifr_name);
432 spp++;
433 continue;
435 if (!strcmp(*spp, "allmulti")) {
436 goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
437 spp++;
438 continue;
440 if (!strcmp(*spp, "-allmulti")) {
441 goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
442 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
443 fprintf(stderr, _("Warning: Interface %s still in ALLMULTI mode.\n"), ifr.ifr_name);
444 spp++;
445 continue;
447 if (!strcmp(*spp, "up")) {
448 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
449 spp++;
450 continue;
452 if (!strcmp(*spp, "down")) {
453 goterr |= clr_flag(ifr.ifr_name, IFF_UP);
454 spp++;
455 continue;
457 #ifdef HAVE_DYNAMIC
458 if (!strcmp(*spp, "dynamic")) {
459 goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
460 spp++;
461 continue;
463 if (!strcmp(*spp, "-dynamic")) {
464 goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
465 spp++;
466 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
467 fprintf(stderr, _("Warning: Interface %s still in DYNAMIC mode.\n"), ifr.ifr_name);
468 continue;
470 #endif
472 if (!strcmp(*spp, "metric")) {
473 if (*++spp == NULL)
474 usage();
475 ifr.ifr_metric = atoi(*spp);
476 if (ioctl(skfd, SIOCSIFMETRIC, &ifr) < 0) {
477 fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
478 goterr = 1;
480 spp++;
481 continue;
483 if (!strcmp(*spp, "mtu")) {
484 if (*++spp == NULL)
485 usage();
486 ifr.ifr_mtu = atoi(*spp);
487 if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
488 fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
489 goterr = 1;
491 spp++;
492 continue;
494 #ifdef SIOCSKEEPALIVE
495 if (!strcmp(*spp, "keepalive")) {
496 if (*++spp == NULL)
497 usage();
498 ifr.ifr_data = (caddr_t) atoi(*spp);
499 if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
500 fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
501 goterr = 1;
503 spp++;
504 continue;
506 #endif
508 #ifdef SIOCSOUTFILL
509 if (!strcmp(*spp, "outfill")) {
510 if (*++spp == NULL)
511 usage();
512 ifr.ifr_data = (caddr_t) atoi(*spp);
513 if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
514 fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
515 goterr = 1;
517 spp++;
518 continue;
520 #endif
522 if (!strcmp(*spp, "-broadcast")) {
523 goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
524 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
525 fprintf(stderr, _("Warning: Interface %s still in BROADCAST mode.\n"), ifr.ifr_name);
526 spp++;
527 continue;
529 if (!strcmp(*spp, "broadcast")) {
530 if (*++spp != NULL) {
531 safe_strncpy(host, *spp, (sizeof host));
532 if (ap->input(0, host, &sa) < 0) {
533 ap->herror(host);
534 goterr = 1;
535 spp++;
536 continue;
538 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
539 sizeof(struct sockaddr));
540 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
541 fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
542 strerror(errno));
543 goterr = 1;
545 spp++;
547 goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
548 continue;
550 if (!strcmp(*spp, "dstaddr")) {
551 if (*++spp == NULL)
552 usage();
553 safe_strncpy(host, *spp, (sizeof host));
554 if (ap->input(0, host, &sa) < 0) {
555 ap->herror(host);
556 goterr = 1;
557 spp++;
558 continue;
560 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
561 sizeof(struct sockaddr));
562 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
563 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
564 strerror(errno));
565 goterr = 1;
567 spp++;
568 continue;
570 if (!strcmp(*spp, "netmask")) {
571 if (*++spp == NULL || didnetmask)
572 usage();
573 safe_strncpy(host, *spp, (sizeof host));
574 if (ap->input(0, host, &sa) < 0) {
575 ap->herror(host);
576 goterr = 1;
577 spp++;
578 continue;
580 didnetmask++;
581 goterr |= set_netmask(ap->fd, &ifr, &sa);
582 spp++;
583 continue;
585 #ifdef HAVE_TXQUEUELEN
586 if (!strcmp(*spp, "txqueuelen")) {
587 if (*++spp == NULL)
588 usage();
589 ifr.ifr_qlen = strtoul(*spp, NULL, 0);
590 if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
591 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
592 goterr = 1;
594 spp++;
595 continue;
597 #endif
599 if (!strcmp(*spp, "mem_start")) {
600 if (*++spp == NULL)
601 usage();
602 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
603 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno));
604 spp++;
605 goterr = 1;
606 continue;
608 ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
609 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
610 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
611 goterr = 1;
613 spp++;
614 continue;
616 if (!strcmp(*spp, "io_addr")) {
617 if (*++spp == NULL)
618 usage();
619 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
620 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno));
621 spp++;
622 goterr = 1;
623 continue;
625 ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
626 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
627 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
628 goterr = 1;
630 spp++;
631 continue;
633 if (!strcmp(*spp, "irq")) {
634 if (*++spp == NULL)
635 usage();
636 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
637 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno));
638 goterr = 1;
639 spp++;
640 continue;
642 ifr.ifr_map.irq = atoi(*spp);
643 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
644 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
645 goterr = 1;
647 spp++;
648 continue;
650 if (!strcmp(*spp, "-pointopoint")) {
651 goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
652 spp++;
653 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
654 fprintf(stderr, _("Warning: Interface %s still in POINTOPOINT mode.\n"), ifr.ifr_name);
655 continue;
657 if (!strcmp(*spp, "pointopoint")) {
658 if (*(spp + 1) != NULL) {
659 spp++;
660 safe_strncpy(host, *spp, (sizeof host));
661 if (ap->input(0, host, &sa)) {
662 ap->herror(host);
663 goterr = 1;
664 spp++;
665 continue;
667 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
668 sizeof(struct sockaddr));
669 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
670 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
671 strerror(errno));
672 goterr = 1;
675 goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
676 spp++;
677 continue;
680 if (!strcmp(*spp, "hw")) {
681 if (*++spp == NULL)
682 usage();
683 if ((hw = get_hwtype(*spp)) == NULL)
684 usage();
685 if (hw->input == NULL) {
686 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
687 spp+=2;
688 goterr = 1;
689 continue;
691 if (*++spp == NULL)
692 usage();
693 safe_strncpy(host, *spp, (sizeof host));
694 if (hw->input(host, &sa) < 0) {
695 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
696 goterr = 1;
697 spp++;
698 continue;
700 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
701 sizeof(struct sockaddr));
702 if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
703 fprintf(stderr, "SIOCSIFHWADDR: %s\n",
704 strerror(errno));
705 goterr = 1;
707 spp++;
708 continue;
710 #if HAVE_AFINET || HAVE_AFINET6
711 if (!strcmp(*spp, "add")) {
712 if (*++spp == NULL)
713 usage();
714 #if HAVE_AFINET6
715 if (strchr(*spp, ':')) {
716 /* INET6 */
717 if ((cp = strchr(*spp, '/'))) {
718 prefix_len = atol(cp + 1);
719 if ((prefix_len < 0) || (prefix_len > 128))
720 usage();
721 *cp = 0;
722 } else {
723 prefix_len = 0;
725 safe_strncpy(host, *spp, (sizeof host));
726 if (inet6_aftype.input(1, host,
727 (struct sockaddr *) &sa6) < 0) {
728 inet6_aftype.herror(host);
729 goterr = 1;
730 spp++;
731 continue;
733 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
734 sizeof(struct in6_addr));
736 fd = get_socket_for_af(AF_INET6);
737 if (fd < 0) {
738 fprintf(stderr,
739 _("No support for INET6 on this system.\n"));
740 goterr = 1;
741 spp++;
742 continue;
744 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
745 perror("SIOGIFINDEX");
746 goterr = 1;
747 spp++;
748 continue;
750 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
751 ifr6.ifr6_prefixlen = prefix_len;
752 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
753 perror("SIOCSIFADDR");
754 goterr = 1;
756 spp++;
757 continue;
759 #endif
760 #ifdef HAVE_AFINET
761 { /* ipv4 address a.b.c.d */
762 unsigned long ip, nm, bc;
763 safe_strncpy(host, *spp, (sizeof host));
764 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
765 ap->herror(host);
766 goterr = 1;
767 spp++;
768 continue;
770 fd = get_socket_for_af(AF_INET);
771 if (fd < 0) {
772 fprintf(stderr,
773 _("No support for INET on this system.\n"));
774 goterr = 1;
775 spp++;
776 continue;
779 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
781 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
782 fprintf(stderr, _("Interface %s not initialized\n"),
783 ifr.ifr_name);
784 goterr = 1;
785 spp++;
786 continue;
788 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
791 spp++;
792 continue;
793 #else
794 fprintf(stderr, _("Bad address.\n"));
795 #endif
797 #endif
799 #if HAVE_AFINET || HAVE_AFINET6
800 if (!strcmp(*spp, "del")) {
801 if (*++spp == NULL)
802 usage();
804 #ifdef SIOCDIFADDR
805 #if HAVE_AFINET6
806 if (strchr(*spp, ':')) { /* INET6 */
807 if ((cp = strchr(*spp, '/'))) {
808 prefix_len = atol(cp + 1);
809 if ((prefix_len < 0) || (prefix_len > 128))
810 usage();
811 *cp = 0;
812 } else {
813 prefix_len = 0;
815 safe_strncpy(host, *spp, (sizeof host));
816 if (inet6_aftype.input(1, host,
817 (struct sockaddr *) &sa6) < 0) {
818 inet6_aftype.herror(host);
819 goterr = 1;
820 spp++;
821 continue;
823 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
824 sizeof(struct in6_addr));
826 fd = get_socket_for_af(AF_INET6);
827 if (fd < 0) {
828 fprintf(stderr,
829 _("No support for INET6 on this system.\n"));
830 goterr = 1;
831 spp++;
832 continue;
834 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
835 perror("SIOGIFINDEX");
836 goterr = 1;
837 spp++;
838 continue;
840 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
841 ifr6.ifr6_prefixlen = prefix_len;
842 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
843 fprintf(stderr, "SIOCDIFADDR: %s\n",
844 strerror(errno));
845 goterr = 1;
847 spp++;
848 continue;
850 #endif
851 #ifdef HAVE_AFINET
853 /* ipv4 address a.b.c.d */
854 unsigned long ip, nm, bc;
855 safe_strncpy(host, *spp, (sizeof host));
856 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
857 ap->herror(host);
858 goterr = 1;
859 spp++;
860 continue;
862 fd = get_socket_for_af(AF_INET);
863 if (fd < 0) {
864 fprintf(stderr, _("No support for INET on this system.\n"));
865 goterr = 1;
866 spp++;
867 continue;
870 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
872 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
873 fprintf(stderr, _("Interface %s not initialized\n"),
874 ifr.ifr_name);
875 goterr = 1;
876 spp++;
877 continue;
879 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
881 spp++;
882 continue;
883 #else
884 fprintf(stderr, _("Bad address.\n"));
885 #endif
886 #else
887 fprintf(stderr, _("Address deletion not supported on this system.\n"));
888 #endif
890 #endif
891 #if HAVE_AFINET6
892 if (!strcmp(*spp, "tunnel")) {
893 if (*++spp == NULL)
894 usage();
895 if ((cp = strchr(*spp, '/'))) {
896 prefix_len = atol(cp + 1);
897 if ((prefix_len < 0) || (prefix_len > 128))
898 usage();
899 *cp = 0;
900 } else {
901 prefix_len = 0;
903 safe_strncpy(host, *spp, (sizeof host));
904 if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
905 inet6_aftype.herror(host);
906 goterr = 1;
907 spp++;
908 continue;
910 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
911 sizeof(struct in6_addr));
913 fd = get_socket_for_af(AF_INET6);
914 if (fd < 0) {
915 fprintf(stderr, _("No support for INET6 on this system.\n"));
916 goterr = 1;
917 spp++;
918 continue;
920 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
921 perror("SIOGIFINDEX");
922 goterr = 1;
923 spp++;
924 continue;
926 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
927 ifr6.ifr6_prefixlen = prefix_len;
929 if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
930 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
931 strerror(errno));
932 goterr = 1;
934 spp++;
935 continue;
937 #endif
939 /* If the next argument is a valid hostname, assume OK. */
940 safe_strncpy(host, *spp, (sizeof host));
942 /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
943 broadcast is unexpected */
944 if (ap->getmask) {
945 switch (ap->getmask(host, &samask, NULL)) {
946 case -1:
947 usage();
948 break;
949 case 1:
950 if (didnetmask)
951 usage();
953 // remeber to set the netmask from samask later
954 neednetmask = 1;
955 break;
958 if (ap->input == NULL) {
959 fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
960 exit(1);
962 if (ap->input(0, host, &sa) < 0) {
963 ap->herror(host);
964 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
965 exit(1);
967 memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
969 int r = 0; /* to shut gcc up */
970 switch (ap->af) {
971 #if HAVE_AFINET
972 case AF_INET:
973 fd = get_socket_for_af(AF_INET);
974 if (fd < 0) {
975 fprintf(stderr, _("No support for INET on this system.\n"));
976 exit(1);
978 r = ioctl(fd, SIOCSIFADDR, &ifr);
979 break;
980 #endif
981 #if HAVE_AFECONET
982 case AF_ECONET:
983 fd = get_socket_for_af(AF_ECONET);
984 if (fd < 0) {
985 fprintf(stderr, _("No support for ECONET on this system.\n"));
986 exit(1);
988 r = ioctl(fd, SIOCSIFADDR, &ifr);
989 break;
990 #endif
991 default:
992 fprintf(stderr,
993 _("Don't know how to set addresses for family %d.\n"), ap->af);
994 exit(1);
996 if (r < 0) {
997 perror("SIOCSIFADDR");
998 goterr = 1;
1003 * Don't do the set_flag() if the address is an alias with a - at the
1004 * end, since it's deleted already! - Roman
1006 * Should really use regex.h here, not sure though how well it'll go
1007 * with the cross-platform support etc.
1010 char *ptr;
1011 short int found_colon = 0;
1012 for (ptr = ifr.ifr_name; *ptr; ptr++ )
1013 if (*ptr == ':') found_colon++;
1015 if (!(found_colon && *(ptr - 1) == '-'))
1016 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
1019 spp++;
1022 if (neednetmask) {
1023 goterr |= set_netmask(skfd, &ifr, &samask);
1024 didnetmask++;
1027 if (opt_v && goterr)
1028 fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);
1030 return (goterr);
1033 struct ifcmd {
1034 int flag;
1035 unsigned long addr;
1036 char *base;
1037 int baselen;
1040 static unsigned char searcher[256];
1042 static int set_ip_using(const char *name, int c, unsigned long ip)
1044 struct ifreq ifr;
1045 struct sockaddr_in sin;
1047 safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1048 memset(&sin, 0, sizeof(struct sockaddr));
1049 sin.sin_family = AF_INET;
1050 sin.sin_addr.s_addr = ip;
1051 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1052 if (ioctl(skfd, c, &ifr) < 0)
1053 return -1;
1054 return 0;
1057 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1059 char *z, *e;
1060 struct sockaddr_in *sin;
1061 int i;
1063 if (do_if_fetch(x) < 0)
1064 return 0;
1065 if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1066 return 0; /* skip */
1067 z = strchr(x->name, ':');
1068 if (!z || !*z)
1069 return 0;
1070 z++;
1071 for (e = z; *e; e++)
1072 if (*e == '-') /* deleted */
1073 return 0;
1074 i = atoi(z);
1075 if (i < 0 || i > 255)
1076 abort();
1077 searcher[i] = 1;
1079 /* copy */
1080 sin = (struct sockaddr_in *)&x->dstaddr;
1081 if (sin->sin_addr.s_addr != ptr->addr) {
1082 return 0;
1085 if (ptr->flag) {
1086 /* turn UP */
1087 if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1088 return -1;
1089 } else {
1090 /* turn DOWN */
1091 if (clr_flag(x->name, IFF_UP) == -1)
1092 return -1;
1095 return 1; /* all done! */
1099 static int get_nmbc_parent(char *parent,
1100 unsigned long *nm, unsigned long *bc)
1102 struct interface *i;
1103 struct sockaddr_in *sin;
1105 i = lookup_interface(parent);
1106 if (!i)
1107 return -1;
1108 if (do_if_fetch(i) < 0)
1109 return 0;
1110 sin = (struct sockaddr_in *)&i->netmask;
1111 memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1112 sin = (struct sockaddr_in *)&i->broadaddr;
1113 memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1114 return 0;
1117 static int set_ifstate(char *parent, unsigned long ip,
1118 unsigned long nm, unsigned long bc,
1119 int flag)
1121 char buf[IFNAMSIZ];
1122 struct ifcmd pt;
1123 int i;
1125 pt.base = parent;
1126 pt.baselen = strlen(parent);
1127 pt.addr = ip;
1128 pt.flag = flag;
1129 memset(searcher, 0, sizeof(searcher));
1130 i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
1131 &pt);
1132 if (i == -1)
1133 return -1;
1134 if (i == 1)
1135 return 0;
1137 /* add a new interface */
1138 for (i = 0; i < 256; i++)
1139 if (searcher[i] == 0)
1140 break;
1142 if (i == 256)
1143 return -1; /* FAILURE!!! out of ip addresses */
1145 if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1146 return -1;
1147 if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1148 return -1;
1149 if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1150 return -1;
1151 if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1152 return -1;
1153 if (set_flag(buf, IFF_BROADCAST) == -1)
1154 return -1;
1155 return 0;