1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1983, 1993\n\
33 The Regents of the University of California. All rights reserved.\n";
34 #endif /* not lint */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
39 #endif
40 static const char rcsid[] =
41 "$FreeBSD$";
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <sys/time.h>
48 #include <sys/module.h>
49 #include <sys/linker.h>
50
51 #include <net/ethernet.h>
52 #include <net/if.h>
53 #include <net/if_var.h>
54 #include <net/if_dl.h>
55 #include <net/if_types.h>
56 #include <net/route.h>
57
58 /* IP */
59 #include <netinet/in.h>
60 #include <netinet/in_var.h>
61 #include <arpa/inet.h>
62 #include <netdb.h>
63
64 #include <ifaddrs.h>
65 #include <ctype.h>
66 #include <err.h>
67 #include <errno.h>
68 #include <fcntl.h>
69 #ifdef JAIL
70 #include <jail.h>
71 #endif
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <unistd.h>
76
77 #include "ifconfig.h"
78
79 /*
80 * Since "struct ifreq" is composed of various union members, callers
81 * should pay special attention to interpret the value.
82 * (.e.g. little/big endian difference in the structure.)
83 */
84 struct ifreq ifr;
85
86 char name[IFNAMSIZ];
87 char *descr = NULL;
88 size_t descrlen = 64;
89 int setaddr;
90 int setmask;
91 int doalias;
92 int clearaddr;
93 int newaddr = 1;
94 int verbose;
95 int noload;
96
97 int supmedia = 0;
98 int printkeys = 0; /* Print keying material for interfaces. */
99
100 static int ifconfig(int argc, char *const *argv, int iscreate,
101 const struct afswtch *afp);
102 static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
103 struct ifaddrs *ifa);
104 static void tunnel_status(int s);
105 static void usage(void);
106
107 static struct afswtch *af_getbyname(const char *name);
108 static struct afswtch *af_getbyfamily(int af);
109 static void af_other_status(int);
110
111 static struct option *opts = NULL;
112
113 void
opt_register(struct option * p)114 opt_register(struct option *p)
115 {
116 p->next = opts;
117 opts = p;
118 }
119
120 static void
usage(void)121 usage(void)
122 {
123 char options[1024];
124 struct option *p;
125
126 /* XXX not right but close enough for now */
127 options[0] = '\0';
128 for (p = opts; p != NULL; p = p->next) {
129 strlcat(options, p->opt_usage, sizeof(options));
130 strlcat(options, " ", sizeof(options));
131 }
132
133 fprintf(stderr,
134 "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
135 " [parameters]\n"
136 " ifconfig interface create\n"
137 " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
138 " ifconfig -l [-d] [-u] [address_family]\n"
139 " ifconfig %s[-d] [-m] [-u] [-v]\n",
140 options, options, options);
141 exit(1);
142 }
143
144 int
main(int argc,char * argv[])145 main(int argc, char *argv[])
146 {
147 int c, all, namesonly, downonly, uponly;
148 const struct afswtch *afp = NULL;
149 int ifindex;
150 struct ifaddrs *ifap, *ifa;
151 struct ifreq paifr;
152 const struct sockaddr_dl *sdl;
153 char options[1024], *cp, *namecp = NULL;
154 const char *ifname;
155 struct option *p;
156 size_t iflen;
157
158 all = downonly = uponly = namesonly = noload = verbose = 0;
159
160 /* Parse leading line options */
161 strlcpy(options, "adklmnuv", sizeof(options));
162 for (p = opts; p != NULL; p = p->next)
163 strlcat(options, p->opt, sizeof(options));
164 while ((c = getopt(argc, argv, options)) != -1) {
165 switch (c) {
166 case 'a': /* scan all interfaces */
167 all++;
168 break;
169 case 'd': /* restrict scan to "down" interfaces */
170 downonly++;
171 break;
172 case 'k':
173 printkeys++;
174 break;
175 case 'l': /* scan interface names only */
176 namesonly++;
177 break;
178 case 'm': /* show media choices in status */
179 supmedia = 1;
180 break;
181 case 'n': /* suppress module loading */
182 noload++;
183 break;
184 case 'u': /* restrict scan to "up" interfaces */
185 uponly++;
186 break;
187 case 'v':
188 verbose++;
189 break;
190 default:
191 for (p = opts; p != NULL; p = p->next)
192 if (p->opt[0] == c) {
193 p->cb(optarg);
194 break;
195 }
196 if (p == NULL)
197 usage();
198 break;
199 }
200 }
201 argc -= optind;
202 argv += optind;
203
204 /* -l cannot be used with -a or -m */
205 if (namesonly && (all || supmedia))
206 usage();
207
208 /* nonsense.. */
209 if (uponly && downonly)
210 usage();
211
212 /* no arguments is equivalent to '-a' */
213 if (!namesonly && argc < 1)
214 all = 1;
215
216 /* -a and -l allow an address family arg to limit the output */
217 if (all || namesonly) {
218 if (argc > 1)
219 usage();
220
221 ifname = NULL;
222 ifindex = 0;
223 if (argc == 1) {
224 afp = af_getbyname(*argv);
225 if (afp == NULL) {
226 warnx("Address family '%s' unknown.", *argv);
227 usage();
228 }
229 if (afp->af_name != NULL)
230 argc--, argv++;
231 /* leave with afp non-zero */
232 }
233 } else {
234 /* not listing, need an argument */
235 if (argc < 1)
236 usage();
237
238 ifname = *argv;
239 argc--, argv++;
240
241 /* check and maybe load support for this interface */
242 ifmaybeload(ifname);
243
244 ifindex = if_nametoindex(ifname);
245 if (ifindex == 0) {
246 /*
247 * NOTE: We must special-case the `create' command
248 * right here as we would otherwise fail when trying
249 * to find the interface.
250 */
251 if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
252 strcmp(argv[0], "plumb") == 0)) {
253 iflen = strlcpy(name, ifname, sizeof(name));
254 if (iflen >= sizeof(name))
255 errx(1, "%s: cloning name too long",
256 ifname);
257 ifconfig(argc, argv, 1, NULL);
258 exit(0);
259 }
260 #ifdef JAIL
261 /*
262 * NOTE: We have to special-case the `-vnet' command
263 * right here as we would otherwise fail when trying
264 * to find the interface as it lives in another vnet.
265 */
266 if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) {
267 iflen = strlcpy(name, ifname, sizeof(name));
268 if (iflen >= sizeof(name))
269 errx(1, "%s: interface name too long",
270 ifname);
271 ifconfig(argc, argv, 0, NULL);
272 exit(0);
273 }
274 #endif
275 errx(1, "interface %s does not exist", ifname);
276 }
277 }
278
279 /* Check for address family */
280 if (argc > 0) {
281 afp = af_getbyname(*argv);
282 if (afp != NULL)
283 argc--, argv++;
284 }
285
286 if (getifaddrs(&ifap) != 0)
287 err(EXIT_FAILURE, "getifaddrs");
288 cp = NULL;
289 ifindex = 0;
290 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
291 memset(&paifr, 0, sizeof(paifr));
292 strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
293 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
294 memcpy(&paifr.ifr_addr, ifa->ifa_addr,
295 ifa->ifa_addr->sa_len);
296 }
297
298 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
299 continue;
300 if (ifa->ifa_addr->sa_family == AF_LINK)
301 sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
302 else
303 sdl = NULL;
304 if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !namesonly)
305 continue;
306 iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
307 if (iflen >= sizeof(name)) {
308 warnx("%s: interface name too long, skipping",
309 ifa->ifa_name);
310 continue;
311 }
312 cp = ifa->ifa_name;
313
314 if ((ifa->ifa_flags & IFF_CANTCONFIG) != 0)
315 continue;
316 if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
317 continue;
318 if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
319 continue;
320 /*
321 * Are we just listing the interfaces?
322 */
323 if (namesonly) {
324 if (namecp == cp)
325 continue;
326 if (afp != NULL) {
327 /* special case for "ether" address family */
328 if (!strcmp(afp->af_name, "ether")) {
329 if (sdl == NULL ||
330 (sdl->sdl_type != IFT_ETHER &&
331 sdl->sdl_type != IFT_L2VLAN &&
332 sdl->sdl_type != IFT_BRIDGE) ||
333 sdl->sdl_alen != ETHER_ADDR_LEN)
334 continue;
335 } else {
336 if (ifa->ifa_addr->sa_family != afp->af_af)
337 continue;
338 }
339 }
340 namecp = cp;
341 ifindex++;
342 if (ifindex > 1)
343 printf(" ");
344 fputs(name, stdout);
345 continue;
346 }
347 ifindex++;
348
349 if (argc > 0)
350 ifconfig(argc, argv, 0, afp);
351 else
352 status(afp, sdl, ifa);
353 }
354 if (namesonly)
355 printf("\n");
356 freeifaddrs(ifap);
357
358 exit(0);
359 }
360
361 static struct afswtch *afs = NULL;
362
363 void
af_register(struct afswtch * p)364 af_register(struct afswtch *p)
365 {
366 p->af_next = afs;
367 afs = p;
368 }
369
370 static struct afswtch *
af_getbyname(const char * name)371 af_getbyname(const char *name)
372 {
373 struct afswtch *afp;
374
375 for (afp = afs; afp != NULL; afp = afp->af_next)
376 if (strcmp(afp->af_name, name) == 0)
377 return afp;
378 return NULL;
379 }
380
381 static struct afswtch *
af_getbyfamily(int af)382 af_getbyfamily(int af)
383 {
384 struct afswtch *afp;
385
386 for (afp = afs; afp != NULL; afp = afp->af_next)
387 if (afp->af_af == af)
388 return afp;
389 return NULL;
390 }
391
392 static void
af_other_status(int s)393 af_other_status(int s)
394 {
395 struct afswtch *afp;
396 uint8_t afmask[howmany(AF_MAX, NBBY)];
397
398 memset(afmask, 0, sizeof(afmask));
399 for (afp = afs; afp != NULL; afp = afp->af_next) {
400 if (afp->af_other_status == NULL)
401 continue;
402 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
403 continue;
404 afp->af_other_status(s);
405 setbit(afmask, afp->af_af);
406 }
407 }
408
409 static void
af_all_tunnel_status(int s)410 af_all_tunnel_status(int s)
411 {
412 struct afswtch *afp;
413 uint8_t afmask[howmany(AF_MAX, NBBY)];
414
415 memset(afmask, 0, sizeof(afmask));
416 for (afp = afs; afp != NULL; afp = afp->af_next) {
417 if (afp->af_status_tunnel == NULL)
418 continue;
419 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
420 continue;
421 afp->af_status_tunnel(s);
422 setbit(afmask, afp->af_af);
423 }
424 }
425
426 static struct cmd *cmds = NULL;
427
428 void
cmd_register(struct cmd * p)429 cmd_register(struct cmd *p)
430 {
431 p->c_next = cmds;
432 cmds = p;
433 }
434
435 static const struct cmd *
cmd_lookup(const char * name,int iscreate)436 cmd_lookup(const char *name, int iscreate)
437 {
438 #define N(a) (sizeof(a)/sizeof(a[0]))
439 const struct cmd *p;
440
441 for (p = cmds; p != NULL; p = p->c_next)
442 if (strcmp(name, p->c_name) == 0) {
443 if (iscreate) {
444 if (p->c_iscloneop)
445 return p;
446 } else {
447 if (!p->c_iscloneop)
448 return p;
449 }
450 }
451 return NULL;
452 #undef N
453 }
454
455 struct callback {
456 callback_func *cb_func;
457 void *cb_arg;
458 struct callback *cb_next;
459 };
460 static struct callback *callbacks = NULL;
461
462 void
callback_register(callback_func * func,void * arg)463 callback_register(callback_func *func, void *arg)
464 {
465 struct callback *cb;
466
467 cb = malloc(sizeof(struct callback));
468 if (cb == NULL)
469 errx(1, "unable to allocate memory for callback");
470 cb->cb_func = func;
471 cb->cb_arg = arg;
472 cb->cb_next = callbacks;
473 callbacks = cb;
474 }
475
476 /* specially-handled commands */
477 static void setifaddr(const char *, int, int, const struct afswtch *);
478 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
479
480 static void setifdstaddr(const char *, int, int, const struct afswtch *);
481 static const struct cmd setifdstaddr_cmd =
482 DEF_CMD("ifdstaddr", 0, setifdstaddr);
483
484 static int
ifconfig(int argc,char * const * argv,int iscreate,const struct afswtch * uafp)485 ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
486 {
487 const struct afswtch *afp, *nafp;
488 const struct cmd *p;
489 struct callback *cb;
490 int s;
491
492 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
493 afp = NULL;
494 if (uafp != NULL)
495 afp = uafp;
496 /*
497 * This is the historical "accident" allowing users to configure IPv4
498 * addresses without the "inet" keyword which while a nice feature has
499 * proven to complicate other things. We cannot remove this but only
500 * make sure we will never have a similar implicit default for IPv6 or
501 * any other address familiy. We need a fallback though for
502 * ifconfig IF up/down etc. to work without INET support as people
503 * never used ifconfig IF link up/down, etc. either.
504 */
505 #ifndef RESCUE
506 #ifdef INET
507 if (afp == NULL && feature_present("inet"))
508 afp = af_getbyname("inet");
509 #endif
510 #endif
511 if (afp == NULL)
512 afp = af_getbyname("link");
513 if (afp == NULL) {
514 warnx("Please specify an address_family.");
515 usage();
516 }
517 top:
518 ifr.ifr_addr.sa_family =
519 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
520 AF_LOCAL : afp->af_af;
521
522 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
523 (uafp != NULL || errno != EAFNOSUPPORT ||
524 (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
525 err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
526
527 while (argc > 0) {
528 p = cmd_lookup(*argv, iscreate);
529 if (iscreate && p == NULL) {
530 /*
531 * Push the clone create callback so the new
532 * device is created and can be used for any
533 * remaining arguments.
534 */
535 cb = callbacks;
536 if (cb == NULL)
537 errx(1, "internal error, no callback");
538 callbacks = cb->cb_next;
539 cb->cb_func(s, cb->cb_arg);
540 iscreate = 0;
541 /*
542 * Handle any address family spec that
543 * immediately follows and potentially
544 * recreate the socket.
545 */
546 nafp = af_getbyname(*argv);
547 if (nafp != NULL) {
548 argc--, argv++;
549 if (nafp != afp) {
550 close(s);
551 afp = nafp;
552 goto top;
553 }
554 }
555 /*
556 * Look for a normal parameter.
557 */
558 continue;
559 }
560 if (p == NULL) {
561 /*
562 * Not a recognized command, choose between setting
563 * the interface address and the dst address.
564 */
565 p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
566 }
567 if (p->c_u.c_func || p->c_u.c_func2) {
568 if (p->c_parameter == NEXTARG) {
569 if (argv[1] == NULL)
570 errx(1, "'%s' requires argument",
571 p->c_name);
572 p->c_u.c_func(argv[1], 0, s, afp);
573 argc--, argv++;
574 } else if (p->c_parameter == OPTARG) {
575 p->c_u.c_func(argv[1], 0, s, afp);
576 if (argv[1] != NULL)
577 argc--, argv++;
578 } else if (p->c_parameter == NEXTARG2) {
579 if (argc < 3)
580 errx(1, "'%s' requires 2 arguments",
581 p->c_name);
582 p->c_u.c_func2(argv[1], argv[2], s, afp);
583 argc -= 2, argv += 2;
584 } else
585 p->c_u.c_func(*argv, p->c_parameter, s, afp);
586 }
587 argc--, argv++;
588 }
589
590 /*
591 * Do any post argument processing required by the address family.
592 */
593 if (afp->af_postproc != NULL)
594 afp->af_postproc(s, afp);
595 /*
596 * Do deferred callbacks registered while processing
597 * command-line arguments.
598 */
599 for (cb = callbacks; cb != NULL; cb = cb->cb_next)
600 cb->cb_func(s, cb->cb_arg);
601 /*
602 * Do deferred operations.
603 */
604 if (clearaddr) {
605 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
606 warnx("interface %s cannot change %s addresses!",
607 name, afp->af_name);
608 clearaddr = 0;
609 }
610 }
611 if (clearaddr) {
612 int ret;
613 strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
614 ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
615 if (ret < 0) {
616 if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
617 /* means no previous address for interface */
618 } else
619 Perror("ioctl (SIOCDIFADDR)");
620 }
621 }
622 if (newaddr) {
623 if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
624 warnx("interface %s cannot change %s addresses!",
625 name, afp->af_name);
626 newaddr = 0;
627 }
628 }
629 if (newaddr && (setaddr || setmask)) {
630 strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
631 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
632 Perror("ioctl (SIOCAIFADDR)");
633 }
634
635 close(s);
636 return(0);
637 }
638
639 /*ARGSUSED*/
640 static void
setifaddr(const char * addr,int param,int s,const struct afswtch * afp)641 setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
642 {
643 if (afp->af_getaddr == NULL)
644 return;
645 /*
646 * Delay the ioctl to set the interface addr until flags are all set.
647 * The address interpretation may depend on the flags,
648 * and the flags may change when the address is set.
649 */
650 setaddr++;
651 if (doalias == 0 && afp->af_af != AF_LINK)
652 clearaddr = 1;
653 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
654 }
655
656 static void
settunnel(const char * src,const char * dst,int s,const struct afswtch * afp)657 settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
658 {
659 struct addrinfo *srcres, *dstres;
660 int ecode;
661
662 if (afp->af_settunnel == NULL) {
663 warn("address family %s does not support tunnel setup",
664 afp->af_name);
665 return;
666 }
667
668 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
669 errx(1, "error in parsing address string: %s",
670 gai_strerror(ecode));
671
672 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
673 errx(1, "error in parsing address string: %s",
674 gai_strerror(ecode));
675
676 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
677 errx(1,
678 "source and destination address families do not match");
679
680 afp->af_settunnel(s, srcres, dstres);
681
682 freeaddrinfo(srcres);
683 freeaddrinfo(dstres);
684 }
685
686 /* ARGSUSED */
687 static void
deletetunnel(const char * vname,int param,int s,const struct afswtch * afp)688 deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
689 {
690
691 if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
692 err(1, "SIOCDIFPHYADDR");
693 }
694
695 #ifdef JAIL
696 static void
setifvnet(const char * jname,int dummy __unused,int s,const struct afswtch * afp)697 setifvnet(const char *jname, int dummy __unused, int s,
698 const struct afswtch *afp)
699 {
700 struct ifreq my_ifr;
701
702 memcpy(&my_ifr, &ifr, sizeof(my_ifr));
703 my_ifr.ifr_jid = jail_getid(jname);
704 if (my_ifr.ifr_jid < 0)
705 errx(1, "%s", jail_errmsg);
706 if (ioctl(s, SIOCSIFVNET, &my_ifr) < 0)
707 err(1, "SIOCSIFVNET");
708 }
709
710 static void
setifrvnet(const char * jname,int dummy __unused,int s,const struct afswtch * afp)711 setifrvnet(const char *jname, int dummy __unused, int s,
712 const struct afswtch *afp)
713 {
714 struct ifreq my_ifr;
715
716 memcpy(&my_ifr, &ifr, sizeof(my_ifr));
717 my_ifr.ifr_jid = jail_getid(jname);
718 if (my_ifr.ifr_jid < 0)
719 errx(1, "%s", jail_errmsg);
720 if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0)
721 err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name);
722 }
723 #endif
724
725 static void
setifnetmask(const char * addr,int dummy __unused,int s,const struct afswtch * afp)726 setifnetmask(const char *addr, int dummy __unused, int s,
727 const struct afswtch *afp)
728 {
729 if (afp->af_getaddr != NULL) {
730 setmask++;
731 afp->af_getaddr(addr, MASK);
732 }
733 }
734
735 static void
setifbroadaddr(const char * addr,int dummy __unused,int s,const struct afswtch * afp)736 setifbroadaddr(const char *addr, int dummy __unused, int s,
737 const struct afswtch *afp)
738 {
739 if (afp->af_getaddr != NULL)
740 afp->af_getaddr(addr, DSTADDR);
741 }
742
743 static void
setifipdst(const char * addr,int dummy __unused,int s,const struct afswtch * afp)744 setifipdst(const char *addr, int dummy __unused, int s,
745 const struct afswtch *afp)
746 {
747 const struct afswtch *inet;
748
749 inet = af_getbyname("inet");
750 if (inet == NULL)
751 return;
752 inet->af_getaddr(addr, DSTADDR);
753 clearaddr = 0;
754 newaddr = 0;
755 }
756
757 static void
notealias(const char * addr,int param,int s,const struct afswtch * afp)758 notealias(const char *addr, int param, int s, const struct afswtch *afp)
759 {
760 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
761 if (setaddr && doalias == 0 && param < 0)
762 if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
763 bcopy((caddr_t)rqtosa(af_addreq),
764 (caddr_t)rqtosa(af_ridreq),
765 rqtosa(af_addreq)->sa_len);
766 doalias = param;
767 if (param < 0) {
768 clearaddr = 1;
769 newaddr = 0;
770 } else
771 clearaddr = 0;
772 #undef rqtosa
773 }
774
775 /*ARGSUSED*/
776 static void
setifdstaddr(const char * addr,int param __unused,int s,const struct afswtch * afp)777 setifdstaddr(const char *addr, int param __unused, int s,
778 const struct afswtch *afp)
779 {
780 if (afp->af_getaddr != NULL)
781 afp->af_getaddr(addr, DSTADDR);
782 }
783
784 /*
785 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
786 * of the ifreq structure, which may confuse other parts of ifconfig.
787 * Make a private copy so we can avoid that.
788 */
789 static void
setifflags(const char * vname,int value,int s,const struct afswtch * afp)790 setifflags(const char *vname, int value, int s, const struct afswtch *afp)
791 {
792 struct ifreq my_ifr;
793 int flags;
794
795 memset(&my_ifr, 0, sizeof(my_ifr));
796 (void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
797
798 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
799 Perror("ioctl (SIOCGIFFLAGS)");
800 exit(1);
801 }
802 flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16);
803
804 if (value < 0) {
805 value = -value;
806 flags &= ~value;
807 } else
808 flags |= value;
809 my_ifr.ifr_flags = flags & 0xffff;
810 my_ifr.ifr_flagshigh = flags >> 16;
811 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
812 Perror(vname);
813 }
814
815 void
setifcap(const char * vname,int value,int s,const struct afswtch * afp)816 setifcap(const char *vname, int value, int s, const struct afswtch *afp)
817 {
818 int flags;
819
820 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
821 Perror("ioctl (SIOCGIFCAP)");
822 exit(1);
823 }
824 flags = ifr.ifr_curcap;
825 if (value < 0) {
826 value = -value;
827 flags &= ~value;
828 } else
829 flags |= value;
830 flags &= ifr.ifr_reqcap;
831 ifr.ifr_reqcap = flags;
832 if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
833 Perror(vname);
834 }
835
836 static void
setifmetric(const char * val,int dummy __unused,int s,const struct afswtch * afp)837 setifmetric(const char *val, int dummy __unused, int s,
838 const struct afswtch *afp)
839 {
840 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
841 ifr.ifr_metric = atoi(val);
842 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
843 warn("ioctl (set metric)");
844 }
845
846 static void
setifmtu(const char * val,int dummy __unused,int s,const struct afswtch * afp)847 setifmtu(const char *val, int dummy __unused, int s,
848 const struct afswtch *afp)
849 {
850 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
851 ifr.ifr_mtu = atoi(val);
852 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
853 warn("ioctl (set mtu)");
854 }
855
856 static void
setifname(const char * val,int dummy __unused,int s,const struct afswtch * afp)857 setifname(const char *val, int dummy __unused, int s,
858 const struct afswtch *afp)
859 {
860 char *newname;
861
862 newname = strdup(val);
863 if (newname == NULL) {
864 warn("no memory to set ifname");
865 return;
866 }
867 ifr.ifr_data = newname;
868 if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
869 warn("ioctl (set name)");
870 free(newname);
871 return;
872 }
873 strlcpy(name, newname, sizeof(name));
874 free(newname);
875 }
876
877 /* ARGSUSED */
878 static void
setifdescr(const char * val,int dummy __unused,int s,const struct afswtch * afp)879 setifdescr(const char *val, int dummy __unused, int s,
880 const struct afswtch *afp)
881 {
882 char *newdescr;
883
884 ifr.ifr_buffer.length = strlen(val) + 1;
885 if (ifr.ifr_buffer.length == 1) {
886 ifr.ifr_buffer.buffer = newdescr = NULL;
887 ifr.ifr_buffer.length = 0;
888 } else {
889 newdescr = strdup(val);
890 ifr.ifr_buffer.buffer = newdescr;
891 if (newdescr == NULL) {
892 warn("no memory to set ifdescr");
893 return;
894 }
895 }
896
897 if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0)
898 warn("ioctl (set descr)");
899
900 free(newdescr);
901 }
902
903 /* ARGSUSED */
904 static void
unsetifdescr(const char * val,int value,int s,const struct afswtch * afp)905 unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
906 {
907
908 setifdescr("", 0, s, 0);
909 }
910
911 #define IFFBITS \
912 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
913 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
914 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
915
916 #define IFCAPBITS \
917 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
918 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
919 "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \
920 "\26RXCSUM_IPV6\27TXCSUM_IPV6"
921
922 /*
923 * Print the status of the interface. If an address family was
924 * specified, show only it; otherwise, show them all.
925 */
926 static void
status(const struct afswtch * afp,const struct sockaddr_dl * sdl,struct ifaddrs * ifa)927 status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
928 struct ifaddrs *ifa)
929 {
930 struct ifaddrs *ift;
931 int allfamilies, s;
932 struct ifstat ifs;
933
934 if (afp == NULL) {
935 allfamilies = 1;
936 ifr.ifr_addr.sa_family = AF_LOCAL;
937 } else {
938 allfamilies = 0;
939 ifr.ifr_addr.sa_family =
940 afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
941 }
942 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
943
944 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
945 if (s < 0)
946 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
947
948 printf("%s: ", name);
949 printb("flags", ifa->ifa_flags, IFFBITS);
950 if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
951 printf(" metric %d", ifr.ifr_metric);
952 if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
953 printf(" mtu %d", ifr.ifr_mtu);
954 putchar('\n');
955
956 for (;;) {
957 if ((descr = reallocf(descr, descrlen)) != NULL) {
958 ifr.ifr_buffer.buffer = descr;
959 ifr.ifr_buffer.length = descrlen;
960 if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) {
961 if (ifr.ifr_buffer.buffer == descr) {
962 if (strlen(descr) > 0)
963 printf("\tdescription: %s\n",
964 descr);
965 } else if (ifr.ifr_buffer.length > descrlen) {
966 descrlen = ifr.ifr_buffer.length;
967 continue;
968 }
969 }
970 } else
971 warn("unable to allocate memory for interface"
972 "description");
973 break;
974 }
975
976 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
977 if (ifr.ifr_curcap != 0) {
978 printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
979 putchar('\n');
980 }
981 if (supmedia && ifr.ifr_reqcap != 0) {
982 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
983 putchar('\n');
984 }
985 }
986
987 tunnel_status(s);
988
989 for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
990 if (ift->ifa_addr == NULL)
991 continue;
992 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
993 continue;
994 if (allfamilies) {
995 const struct afswtch *p;
996 p = af_getbyfamily(ift->ifa_addr->sa_family);
997 if (p != NULL && p->af_status != NULL)
998 p->af_status(s, ift);
999 } else if (afp->af_af == ift->ifa_addr->sa_family)
1000 afp->af_status(s, ift);
1001 }
1002 #if 0
1003 if (allfamilies || afp->af_af == AF_LINK) {
1004 const struct afswtch *lafp;
1005
1006 /*
1007 * Hack; the link level address is received separately
1008 * from the routing information so any address is not
1009 * handled above. Cobble together an entry and invoke
1010 * the status method specially.
1011 */
1012 lafp = af_getbyname("lladdr");
1013 if (lafp != NULL) {
1014 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
1015 lafp->af_status(s, &info);
1016 }
1017 }
1018 #endif
1019 if (allfamilies)
1020 af_other_status(s);
1021 else if (afp->af_other_status != NULL)
1022 afp->af_other_status(s);
1023
1024 strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
1025 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
1026 printf("%s", ifs.ascii);
1027
1028 close(s);
1029 return;
1030 }
1031
1032 static void
tunnel_status(int s)1033 tunnel_status(int s)
1034 {
1035 af_all_tunnel_status(s);
1036 }
1037
1038 void
Perror(const char * cmd)1039 Perror(const char *cmd)
1040 {
1041 switch (errno) {
1042
1043 case ENXIO:
1044 errx(1, "%s: no such interface", cmd);
1045 break;
1046
1047 case EPERM:
1048 errx(1, "%s: permission denied", cmd);
1049 break;
1050
1051 default:
1052 err(1, "%s", cmd);
1053 }
1054 }
1055
1056 /*
1057 * Print a value a la the %b format of the kernel's printf
1058 */
1059 void
printb(const char * s,unsigned v,const char * bits)1060 printb(const char *s, unsigned v, const char *bits)
1061 {
1062 int i, any = 0;
1063 char c;
1064
1065 if (bits && *bits == 8)
1066 printf("%s=%o", s, v);
1067 else
1068 printf("%s=%x", s, v);
1069 bits++;
1070 if (bits) {
1071 putchar('<');
1072 while ((i = *bits++) != '\0') {
1073 if (v & (1 << (i-1))) {
1074 if (any)
1075 putchar(',');
1076 any = 1;
1077 for (; (c = *bits) > 32; bits++)
1078 putchar(c);
1079 } else
1080 for (; *bits > 32; bits++)
1081 ;
1082 }
1083 putchar('>');
1084 }
1085 }
1086
1087 void
print_vhid(const struct ifaddrs * ifa,const char * s)1088 print_vhid(const struct ifaddrs *ifa, const char *s)
1089 {
1090 struct if_data *ifd;
1091
1092 if (ifa->ifa_data == NULL)
1093 return;
1094
1095 ifd = ifa->ifa_data;
1096 if (ifd->ifi_vhid == 0)
1097 return;
1098
1099 printf("vhid %d ", ifd->ifi_vhid);
1100 }
1101
1102 void
ifmaybeload(const char * name)1103 ifmaybeload(const char *name)
1104 {
1105 #define MOD_PREFIX_LEN 3 /* "if_" */
1106 struct module_stat mstat;
1107 int fileid, modid;
1108 char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
1109 const char *cp;
1110
1111 /* loading suppressed by the user */
1112 if (noload)
1113 return;
1114
1115 /* trim the interface number off the end */
1116 strlcpy(ifname, name, sizeof(ifname));
1117 for (dp = ifname; *dp != 0; dp++)
1118 if (isdigit(*dp)) {
1119 *dp = 0;
1120 break;
1121 }
1122
1123 /* turn interface and unit into module name */
1124 strlcpy(ifkind, "if_", sizeof(ifkind));
1125 strlcat(ifkind, ifname, sizeof(ifkind));
1126
1127 /* scan files in kernel */
1128 mstat.version = sizeof(struct module_stat);
1129 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
1130 /* scan modules in file */
1131 for (modid = kldfirstmod(fileid); modid > 0;
1132 modid = modfnext(modid)) {
1133 if (modstat(modid, &mstat) < 0)
1134 continue;
1135 /* strip bus name if present */
1136 if ((cp = strchr(mstat.name, '/')) != NULL) {
1137 cp++;
1138 } else {
1139 cp = mstat.name;
1140 }
1141 /* already loaded? */
1142 if (strcmp(ifname, cp) == 0 ||
1143 strcmp(ifkind, cp) == 0)
1144 return;
1145 }
1146 }
1147
1148 /* not present, we should try to load it */
1149 kldload(ifkind);
1150 }
1151
1152 static struct cmd basic_cmds[] = {
1153 DEF_CMD("up", IFF_UP, setifflags),
1154 DEF_CMD("down", -IFF_UP, setifflags),
1155 DEF_CMD("arp", -IFF_NOARP, setifflags),
1156 DEF_CMD("-arp", IFF_NOARP, setifflags),
1157 DEF_CMD("debug", IFF_DEBUG, setifflags),
1158 DEF_CMD("-debug", -IFF_DEBUG, setifflags),
1159 DEF_CMD_ARG("description", setifdescr),
1160 DEF_CMD_ARG("descr", setifdescr),
1161 DEF_CMD("-description", 0, unsetifdescr),
1162 DEF_CMD("-descr", 0, unsetifdescr),
1163 DEF_CMD("promisc", IFF_PPROMISC, setifflags),
1164 DEF_CMD("-promisc", -IFF_PPROMISC, setifflags),
1165 DEF_CMD("add", IFF_UP, notealias),
1166 DEF_CMD("alias", IFF_UP, notealias),
1167 DEF_CMD("-alias", -IFF_UP, notealias),
1168 DEF_CMD("delete", -IFF_UP, notealias),
1169 DEF_CMD("remove", -IFF_UP, notealias),
1170 #ifdef notdef
1171 #define EN_SWABIPS 0x1000
1172 DEF_CMD("swabips", EN_SWABIPS, setifflags),
1173 DEF_CMD("-swabips", -EN_SWABIPS, setifflags),
1174 #endif
1175 DEF_CMD_ARG("netmask", setifnetmask),
1176 DEF_CMD_ARG("metric", setifmetric),
1177 DEF_CMD_ARG("broadcast", setifbroadaddr),
1178 DEF_CMD_ARG("ipdst", setifipdst),
1179 DEF_CMD_ARG2("tunnel", settunnel),
1180 DEF_CMD("-tunnel", 0, deletetunnel),
1181 DEF_CMD("deletetunnel", 0, deletetunnel),
1182 #ifdef JAIL
1183 DEF_CMD_ARG("vnet", setifvnet),
1184 DEF_CMD_ARG("-vnet", setifrvnet),
1185 #endif
1186 DEF_CMD("link0", IFF_LINK0, setifflags),
1187 DEF_CMD("-link0", -IFF_LINK0, setifflags),
1188 DEF_CMD("link1", IFF_LINK1, setifflags),
1189 DEF_CMD("-link1", -IFF_LINK1, setifflags),
1190 DEF_CMD("link2", IFF_LINK2, setifflags),
1191 DEF_CMD("-link2", -IFF_LINK2, setifflags),
1192 DEF_CMD("monitor", IFF_MONITOR, setifflags),
1193 DEF_CMD("-monitor", -IFF_MONITOR, setifflags),
1194 DEF_CMD("staticarp", IFF_STATICARP, setifflags),
1195 DEF_CMD("-staticarp", -IFF_STATICARP, setifflags),
1196 DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap),
1197 DEF_CMD("-rxcsum6", -IFCAP_RXCSUM_IPV6, setifcap),
1198 DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap),
1199 DEF_CMD("-txcsum6", -IFCAP_TXCSUM_IPV6, setifcap),
1200 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
1201 DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap),
1202 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
1203 DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap),
1204 DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
1205 DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap),
1206 DEF_CMD("polling", IFCAP_POLLING, setifcap),
1207 DEF_CMD("-polling", -IFCAP_POLLING, setifcap),
1208 DEF_CMD("tso6", IFCAP_TSO6, setifcap),
1209 DEF_CMD("-tso6", -IFCAP_TSO6, setifcap),
1210 DEF_CMD("tso4", IFCAP_TSO4, setifcap),
1211 DEF_CMD("-tso4", -IFCAP_TSO4, setifcap),
1212 DEF_CMD("tso", IFCAP_TSO, setifcap),
1213 DEF_CMD("-tso", -IFCAP_TSO, setifcap),
1214 DEF_CMD("toe", IFCAP_TOE, setifcap),
1215 DEF_CMD("-toe", -IFCAP_TOE, setifcap),
1216 DEF_CMD("lro", IFCAP_LRO, setifcap),
1217 DEF_CMD("-lro", -IFCAP_LRO, setifcap),
1218 DEF_CMD("wol", IFCAP_WOL, setifcap),
1219 DEF_CMD("-wol", -IFCAP_WOL, setifcap),
1220 DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap),
1221 DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap),
1222 DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap),
1223 DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap),
1224 DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap),
1225 DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap),
1226 DEF_CMD("normal", -IFF_LINK0, setifflags),
1227 DEF_CMD("compress", IFF_LINK0, setifflags),
1228 DEF_CMD("noicmp", IFF_LINK1, setifflags),
1229 DEF_CMD_ARG("mtu", setifmtu),
1230 DEF_CMD_ARG("name", setifname),
1231 };
1232
1233 static __constructor void
ifconfig_ctor(void)1234 ifconfig_ctor(void)
1235 {
1236 #define N(a) (sizeof(a) / sizeof(a[0]))
1237 size_t i;
1238
1239 for (i = 0; i < N(basic_cmds); i++)
1240 cmd_register(&basic_cmds[i]);
1241 #undef N
1242 }
1243