xref: /openbsd/regress/sbin/ifconfig/ifaddr.c (revision 5b133f3f)
1 /*	$OpenBSD: ifaddr.c,v 1.8 2023/03/08 04:43:06 guenther Exp $	*/
2 
3 /*
4  * This file has been copied from ifconfig and adapted to test
5  * SIOCSIFADDR, SIOCSIFNETMASK, SIOCSIFDSTADDR, SIOCSIFBRDADDR
6  * ioctls.  Usually ifconfig uses SIOCAIFADDR and SIOCDIFADDR, but
7  * the old kernel interface has to be tested, too.
8  */
9 
10 /*
11  * Copyright (c) 1983, 1993
12  *	The Regents of the University of California.  All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
41  * All rights reserved.
42  *
43  * This code is derived from software contributed to The NetBSD Foundation
44  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
45  * NASA Ames Research Center.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
57  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
58  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
60  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
61  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
62  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
64  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
65  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66  * POSSIBILITY OF SUCH DAMAGE.
67  */
68 
69 /*
70  * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
71  *
72  * Permission to use, copy, modify, and distribute this software for any
73  * purpose with or without fee is hereby granted, provided that the above
74  * copyright notice and this permission notice appear in all copies.
75  *
76  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
77  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
78  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
79  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
80  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
81  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
82  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
83  */
84 
85 #include <sys/socket.h>
86 #include <sys/ioctl.h>
87 #include <sys/time.h>
88 
89 #include <net/if.h>
90 #include <net/if_dl.h>
91 #include <net/if_media.h>
92 #include <net/if_types.h>
93 #include <netinet/in.h>
94 #include <netinet/in_var.h>
95 #include <netinet6/in6_var.h>
96 #include <netinet6/nd6.h>
97 #include <arpa/inet.h>
98 #include <netinet/ip_ipsp.h>
99 #include <netinet/if_ether.h>
100 
101 #include <netdb.h>
102 
103 #include <net/if_vlan_var.h>
104 
105 #include <ctype.h>
106 #include <err.h>
107 #include <errno.h>
108 #include <stdio.h>
109 #include <stdint.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <unistd.h>
113 #include <limits.h>
114 #include <resolv.h>
115 #include <util.h>
116 #include <ifaddrs.h>
117 
118 #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
119 #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
120 
121 #define HWFEATURESBITS							\
122 	"\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4"			\
123 	"\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6"			\
124 	"\11CSUM_UDPv6\20WOL"
125 
126 struct	ifreq		ifr, ridreq;
127 struct	in_aliasreq	in_addreq;
128 struct	in6_ifreq	ifr6;
129 struct	in6_ifreq	in6_ridreq;
130 struct	in6_aliasreq	in6_addreq;
131 struct	sockaddr_in	netmask;
132 
133 char	ifname[IFNAMSIZ];
134 int	flags, xflags, setaddr, setmask, setipdst, setbroad, doalias;
135 u_long	metric, mtu;
136 int	rdomainid;
137 int	llprio;
138 int	clearaddr, sock;
139 int	newaddr = 0;
140 int	af = AF_INET;
141 int	explicit_prefix = 0;
142 int	Lflag = 1;
143 
144 int	showcapsflag;
145 
146 void	notealias(const char *, int);
147 void	setifaddr(const char *, int);
148 void	setifrtlabel(const char *, int);
149 void	setifdstaddr(const char *, int);
150 void	addaf(const char *, int);
151 void	removeaf(const char *, int);
152 void	setifbroadaddr(const char *, int);
153 void	setifnetmask(const char *, int);
154 void	setifprefixlen(const char *, int);
155 void	settunnel(const char *, const char *);
156 void	settunneladdr(const char *, int);
157 void	deletetunnel(const char *, int);
158 void	settunnelinst(const char *, int);
159 void	unsettunnelinst(const char *, int);
160 void	settunnelttl(const char *, int);
161 void	setia6flags(const char *, int);
162 void	setia6pltime(const char *, int);
163 void	setia6vltime(const char *, int);
164 void	setia6lifetime(const char *, const char *);
165 void	setia6eui64(const char *, int);
166 void	setrdomain(const char *, int);
167 void	unsetrdomain(const char *, int);
168 int	prefix(void *val, int);
169 int	printgroup(char *, int);
170 void	setifipdst(const char *, int);
171 void	setignore(const char *, int);
172 
173 int	actions;			/* Actions performed */
174 
175 #define A_SILENT	0x8000000	/* doing operation, do not print */
176 
177 #define	NEXTARG0	0xffffff
178 #define NEXTARG		0xfffffe
179 #define	NEXTARG2	0xfffffd
180 
181 const struct	cmd {
182 	char	*c_name;
183 	int	c_parameter;		/* NEXTARG means next argv */
184 	int	c_action;		/* defered action */
185 	void	(*c_func)(const char *, int);
186 	void	(*c_func2)(const char *, const char *);
187 } cmds[] = {
188 	{ "alias",	IFF_UP,		0,		notealias },
189 	{ "-alias",	-IFF_UP,	0,		notealias },
190 	{ "delete",	-IFF_UP,	0,		notealias },
191 	{ "netmask",	NEXTARG,	0,		setifnetmask },
192 	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
193 	{ "prefixlen",  NEXTARG,	0,		setifprefixlen},
194 	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
195 	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
196 	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
197 	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
198 	{ "pltime",	NEXTARG,	0,		setia6pltime },
199 	{ "vltime",	NEXTARG,	0,		setia6vltime },
200 	{ "eui64",	0,		0,		setia6eui64 },
201 #ifndef SMALL
202 	{ "rtlabel",	NEXTARG,	0,		setifrtlabel },
203 	{ "-rtlabel",	-1,		0,		setifrtlabel },
204 	{ "rdomain",	NEXTARG,	0,		setrdomain },
205 	{ "-rdomain",	0,		0,		unsetrdomain },
206 	{ "tunnel",	NEXTARG2,	0,		NULL, settunnel },
207 	{ "tunneladdr",	NEXTARG,	0,		settunneladdr },
208 	{ "-tunnel",	0,		0,		deletetunnel },
209 	{ "tunneldomain", NEXTARG,	0,		settunnelinst },
210 	{ "-tunneldomain", 0,		0,		unsettunnelinst },
211 	{ "tunnelttl",	NEXTARG,	0,		settunnelttl },
212 	{ "-inet",	AF_INET,	0,		removeaf },
213 	{ "-inet6",	AF_INET6,	0,		removeaf },
214 	{ "ipdst",	NEXTARG,	0,		setifipdst },
215 #endif /* SMALL */
216 	{ NULL, /*src*/	0,		0,		setifaddr },
217 	{ NULL, /*dst*/	0,		0,		setifdstaddr },
218 	{ NULL, /*illegal*/0,		0,		NULL },
219 };
220 
221 #define	IFFBITS								\
222 	"\024\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6STATICARP"	\
223 	"\7RUNNING\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX"	\
224 	"\15LINK0\16LINK1\17LINK2\20MULTICAST"				\
225 	"\23AUTOCONF6TEMP\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII"	\
226 	"\30AUTOCONF4"
227 
228 int	getinfo(struct ifreq *, int);
229 void	getsock(int);
230 void	printif(char *, int);
231 void	printb(char *, unsigned int, unsigned char *);
232 void	printb_status(unsigned short, unsigned char *);
233 const char *get_linkstate(int, int);
234 void	status(int, struct sockaddr_dl *, int);
235 __dead void	usage(void);
236 const char *get_string(const char *, const char *, u_int8_t *, int *);
237 int	len_string(const u_int8_t *, int);
238 int	print_string(const u_int8_t *, int);
239 char	*sec2str(time_t);
240 
241 unsigned long get_ts_map(int, int, int);
242 
243 void	in_status(int);
244 void	in_getaddr(const char *, int);
245 void	in_getprefix(const char *, int);
246 void	in6_fillscopeid(struct sockaddr_in6 *);
247 void	in6_alias(struct in6_ifreq *);
248 void	in6_status(int);
249 void	in6_getaddr(const char *, int);
250 void	in6_getprefix(const char *, int);
251 
252 /* Known address families */
253 const struct afswtch {
254 	char *af_name;
255 	short af_af;
256 	void (*af_status)(int);
257 	void (*af_getaddr)(const char *, int);
258 	void (*af_getprefix)(const char *, int);
259 	u_long af_difaddr;
260 	u_long af_aifaddr;
261 	caddr_t af_ridreq;
262 	caddr_t af_addreq;
263 } afs[] = {
264 #define C(x) ((caddr_t) &x)
265 	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
266 	    SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(in_addreq) },
267 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
268 	    SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
269 	{ 0,	0,	    0,		0 }
270 };
271 
272 const struct afswtch *afp;	/*the address family being set or asked about*/
273 
274 int ifaliases = 0;
275 int aflag = 0;
276 
277 int
main(int argc,char * argv[])278 main(int argc, char *argv[])
279 {
280 	const struct afswtch *rafp = NULL;
281 	int create = 0;
282 	int i;
283 
284 	/* If no args at all, print all interfaces.  */
285 	if (argc < 2) {
286 		/* no filesystem visibility */
287 		if (unveil("/", "") == -1)
288 			err(1, "unveil /");
289 		if (unveil(NULL, NULL) == -1)
290 			err(1, "unveil");
291 		aflag = 1;
292 		printif(NULL, 0);
293 		return (0);
294 	}
295 	argc--, argv++;
296 	if (*argv[0] == '-') {
297 		int nomore = 0;
298 
299 		for (i = 1; argv[0][i]; i++) {
300 			switch (argv[0][i]) {
301 			case 'a':
302 				aflag = 1;
303 				nomore = 1;
304 				break;
305 			case 'A':
306 				aflag = 1;
307 				ifaliases = 1;
308 				nomore = 1;
309 				break;
310 			default:
311 				usage();
312 				break;
313 			}
314 		}
315 		if (nomore == 0) {
316 			argc--, argv++;
317 			if (argc < 1)
318 				usage();
319 			if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
320 				errx(1, "interface name '%s' too long", *argv);
321 		}
322 	} else if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
323 		errx(1, "interface name '%s' too long", *argv);
324 	argc--, argv++;
325 
326 	if (unveil(_PATH_RESCONF, "r") == -1)
327 		err(1, "unveil %s", _PATH_RESCONF);
328 	if (unveil(_PATH_HOSTS, "r") == -1)
329 		err(1, "unveil %s", _PATH_HOSTS);
330 	if (unveil(_PATH_SERVICES, "r") == -1)
331 		err(1, "unveil %s", _PATH_SERVICES);
332 	if (unveil(NULL, NULL) == -1)
333 		err(1, "unveil");
334 
335 	if (argc > 0) {
336 		for (afp = rafp = afs; rafp->af_name; rafp++)
337 			if (strcmp(rafp->af_name, *argv) == 0) {
338 				afp = rafp;
339 				argc--;
340 				argv++;
341 				break;
342 			}
343 		rafp = afp;
344 		af = ifr.ifr_addr.sa_family = rafp->af_af;
345 	}
346 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
347 
348 	/* initialization */
349 	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
350 	in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
351 
352 	if (aflag == 0) {
353 		create = (argc > 0) && strcmp(argv[0], "destroy") != 0;
354 		(void)getinfo(&ifr, create);
355 	}
356 
357 	if (argc != 0 && af == AF_INET6)
358 		addaf(ifname, AF_INET6);
359 
360 	while (argc > 0) {
361 		const struct cmd *p;
362 
363 		for (p = cmds; p->c_name; p++)
364 			if (strcmp(*argv, p->c_name) == 0)
365 				break;
366 		if (p->c_name == 0 && setaddr)
367 			for (i = setaddr; i > 0; i--) {
368 				p++;
369 				if (p->c_func == NULL)
370 					errx(1, "%s: bad value", *argv);
371 			}
372 		if (p->c_func || p->c_func2) {
373 			if (p->c_parameter == NEXTARG0) {
374 				const struct cmd *p0;
375 				int noarg = 1;
376 
377 				if (argv[1]) {
378 					for (p0 = cmds; p0->c_name; p0++)
379 						if (strcmp(argv[1],
380 						    p0->c_name) == 0) {
381 							noarg = 0;
382 							break;
383 						}
384 				} else
385 					noarg = 0;
386 
387 				if (noarg == 0)
388 					(*p->c_func)(NULL, 0);
389 				else
390 					goto nextarg;
391 			} else if (p->c_parameter == NEXTARG) {
392 nextarg:
393 				if (argv[1] == NULL)
394 					errx(1, "'%s' requires argument",
395 					    p->c_name);
396 				(*p->c_func)(argv[1], 0);
397 				argc--, argv++;
398 				actions = actions | A_SILENT | p->c_action;
399 			} else if (p->c_parameter == NEXTARG2) {
400 				if ((argv[1] == NULL) ||
401 				    (argv[2] == NULL))
402 					errx(1, "'%s' requires 2 arguments",
403 					    p->c_name);
404 				(*p->c_func2)(argv[1], argv[2]);
405 				argc -= 2;
406 				argv += 2;
407 				actions = actions | A_SILENT | p->c_action;
408 			} else {
409 				(*p->c_func)(*argv, p->c_parameter);
410 				actions = actions | A_SILENT | p->c_action;
411 			}
412 		}
413 		argc--, argv++;
414 	}
415 
416 	if (argc == 0 && actions == 0) {
417 		printif(ifr.ifr_name, aflag ? ifaliases : 1);
418 		return (0);
419 	}
420 
421 	if (af == AF_INET6 && explicit_prefix == 0) {
422 		/*
423 		 * Aggregatable address architecture defines all prefixes
424 		 * are 64. So, it is convenient to set prefixlen to 64 if
425 		 * it is not specified. If we are setting a destination
426 		 * address on a point-to-point interface, 128 is required.
427 		 */
428 		if (setipdst && (flags & IFF_POINTOPOINT))
429 			setifprefixlen("128", 0);
430 		else
431 			setifprefixlen("64", 0);
432 		/* in6_getprefix("64", MASK) if MASK is available here... */
433 	}
434 
435 	if (doalias == 0 || (newaddr && clearaddr)) {
436 		(void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name));
437 		/* IPv4 only, inet6 does not have such ioctls */
438 		if (setaddr) {
439 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_addr,
440 			    in_addreq.ifra_addr.sin_len);
441 			if (ioctl(sock, SIOCSIFADDR, rafp->af_ridreq) == -1)
442 				err(1, "SIOCSIFADDR");
443 		}
444 		if (setmask) {
445 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_mask,
446 			    in_addreq.ifra_mask.sin_len);
447 			if (ioctl(sock, SIOCSIFNETMASK, rafp->af_ridreq) == -1)
448 				err(1, "SIOCSIFNETMASK");
449 		}
450 		if (setipdst) {
451 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_dstaddr,
452 			    in_addreq.ifra_dstaddr.sin_len);
453 			if (ioctl(sock, SIOCSIFDSTADDR, rafp->af_ridreq) == -1)
454 				err(1, "SIOCSIFDSTADDR");
455 		}
456 		if (setbroad) {
457 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_broadaddr,
458 			    in_addreq.ifra_broadaddr.sin_len);
459 			if (ioctl(sock, SIOCSIFBRDADDR, rafp->af_ridreq) == -1)
460 				err(1, "SIOCSIFBRDADDR");
461 		}
462 		return (0);
463 	}
464 	if (clearaddr) {
465 		(void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name));
466 		if (ioctl(sock, rafp->af_difaddr, rafp->af_ridreq) == -1) {
467 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
468 				/* means no previous address for interface */
469 			} else
470 				err(1, "SIOCDIFADDR");
471 		}
472 	}
473 	if (newaddr) {
474 		(void) strlcpy(rafp->af_addreq, ifname, sizeof(ifr.ifr_name));
475 		if (ioctl(sock, rafp->af_aifaddr, rafp->af_addreq) == -1)
476 			err(1, "SIOCAIFADDR");
477 	}
478 	return (0);
479 }
480 
481 void
getsock(int naf)482 getsock(int naf)
483 {
484 	static int oaf = -1;
485 
486 	if (oaf == naf)
487 		return;
488 	if (oaf != -1)
489 		close(sock);
490 	sock = socket(naf, SOCK_DGRAM, 0);
491 	if (sock == -1)
492 		oaf = -1;
493 	else
494 		oaf = naf;
495 }
496 
497 int
getinfo(struct ifreq * ifr,int create)498 getinfo(struct ifreq *ifr, int create)
499 {
500 
501 	getsock(af);
502 	if (sock == -1)
503 		err(1, "socket");
504 	if (!isdigit((unsigned char)ifname[strlen(ifname) - 1]))
505 		return (-1);	/* ignore groups here */
506 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1) {
507 		int oerrno = errno;
508 
509 		if (!create)
510 			return (-1);
511 		if (ioctl(sock, SIOCIFCREATE, (caddr_t)ifr) == -1) {
512 			errno = oerrno;
513 			return (-1);
514 		}
515 		if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1)
516 			return (-1);
517 	}
518 	flags = ifr->ifr_flags & 0xffff;
519 	if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)ifr) == -1)
520 		ifr->ifr_flags = 0;
521 	xflags = ifr->ifr_flags;
522 	if (ioctl(sock, SIOCGIFMETRIC, (caddr_t)ifr) == -1)
523 		metric = 0;
524 	else
525 		metric = ifr->ifr_metric;
526 	if (ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) == -1)
527 		mtu = 0;
528 	else
529 		mtu = ifr->ifr_mtu;
530 #ifndef SMALL
531 	if (ioctl(sock, SIOCGIFRDOMAIN, (caddr_t)ifr) == -1)
532 		rdomainid = 0;
533 	else
534 		rdomainid = ifr->ifr_rdomainid;
535 #endif
536 	if (ioctl(sock, SIOCGIFLLPRIO, (caddr_t)ifr) == -1)
537 		llprio = 0;
538 	else
539 		llprio = ifr->ifr_llprio;
540 
541 	return (0);
542 }
543 
544 int
printgroup(char * groupname,int ifaliases)545 printgroup(char *groupname, int ifaliases)
546 {
547 	struct ifgroupreq	 ifgr;
548 	struct ifg_req		*ifg;
549 	int			 len, cnt = 0;
550 
551 	getsock(AF_INET);
552 	bzero(&ifgr, sizeof(ifgr));
553 	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
554 	if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
555 		if (errno == EINVAL || errno == ENOTTY ||
556 		    errno == ENOENT)
557 			return (-1);
558 		else
559 			err(1, "SIOCGIFGMEMB");
560 	}
561 
562 	len = ifgr.ifgr_len;
563 	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
564 		err(1, "printgroup");
565 	if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
566 		err(1, "SIOCGIFGMEMB");
567 
568 	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
569 	    ifg++) {
570 		len -= sizeof(struct ifg_req);
571 		printif(ifg->ifgrq_member, ifaliases);
572 		cnt++;
573 	}
574 	free(ifgr.ifgr_groups);
575 
576 	return (cnt);
577 }
578 
579 void
printif(char * name,int ifaliases)580 printif(char *name, int ifaliases)
581 {
582 	struct ifaddrs *ifap, *ifa;
583 	struct if_data *ifdata;
584 	const char *namep;
585 	char *oname = NULL;
586 	struct ifreq *ifrp;
587 	int count = 0, noinet = 1;
588 	size_t nlen = 0;
589 
590 	if (aflag)
591 		name = NULL;
592 	if (name) {
593 		if ((oname = strdup(name)) == NULL)
594 			err(1, "strdup");
595 		nlen = strlen(oname);
596 		/* is it a group? */
597 		if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
598 			if (printgroup(oname, ifaliases) != -1) {
599 				free(oname);
600 				return;
601 			}
602 	}
603 
604 	if (getifaddrs(&ifap) != 0)
605 		err(1, "getifaddrs");
606 
607 	namep = NULL;
608 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
609 		if (oname) {
610 			if (nlen && isdigit((unsigned char)oname[nlen - 1])) {
611 				/* must have exact match */
612 				if (strcmp(oname, ifa->ifa_name) != 0)
613 					continue;
614 			} else {
615 				/* partial match OK if it ends w/ digit */
616 				if (strncmp(oname, ifa->ifa_name, nlen) != 0 ||
617 				    !isdigit((unsigned char)ifa->ifa_name[nlen]))
618 					continue;
619 			}
620 		}
621 		/* quickhack: sizeof(ifr) < sizeof(ifr6) */
622 		if (ifa->ifa_addr->sa_family == AF_INET6) {
623 			memset(&ifr6, 0, sizeof(ifr6));
624 			memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
625 			    MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
626 			ifrp = (struct ifreq *)&ifr6;
627 		} else {
628 			memset(&ifr, 0, sizeof(ifr));
629 			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
630 			    MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len));
631 			ifrp = &ifr;
632 		}
633 		strlcpy(ifname, ifa->ifa_name, sizeof(ifname));
634 		strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
635 
636 		if (ifa->ifa_addr->sa_family == AF_LINK) {
637 			namep = ifa->ifa_name;
638 			if (getinfo(ifrp, 0) < 0)
639 				continue;
640 			ifdata = ifa->ifa_data;
641 			status(1, (struct sockaddr_dl *)ifa->ifa_addr,
642 			    ifdata->ifi_link_state);
643 			count++;
644 			noinet = 1;
645 			continue;
646 		}
647 
648 		if (!namep || !strcmp(namep, ifa->ifa_name)) {
649 			const struct afswtch *p;
650 
651 			if (ifa->ifa_addr->sa_family == AF_INET &&
652 			    ifaliases == 0 && noinet == 0)
653 				continue;
654 			if ((p = afp) != NULL) {
655 				if (ifa->ifa_addr->sa_family == p->af_af)
656 					p->af_status(1);
657 			} else {
658 				for (p = afs; p->af_name; p++) {
659 					if (ifa->ifa_addr->sa_family ==
660 					    p->af_af)
661 						p->af_status(0);
662 				}
663 			}
664 			count++;
665 			if (ifa->ifa_addr->sa_family == AF_INET)
666 				noinet = 0;
667 			continue;
668 		}
669 	}
670 	freeifaddrs(ifap);
671 	free(oname);
672 	if (count == 0) {
673 		fprintf(stderr, "%s: no such interface\n", ifname);
674 		exit(1);
675 	}
676 }
677 
678 #define RIDADDR 0
679 #define ADDR	1
680 #define MASK	2
681 #define DSTADDR	3
682 
683 void
setifaddr(const char * addr,int param)684 setifaddr(const char *addr, int param)
685 {
686 	/*
687 	 * Delay the ioctl to set the interface addr until flags are all set.
688 	 * The address interpretation may depend on the flags,
689 	 * and the flags may change when the address is set.
690 	 */
691 	setaddr++;
692 	if (doalias >= 0)
693 		newaddr = 1;
694 	if (doalias == 0)
695 		clearaddr = 1;
696 	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
697 }
698 
699 #ifndef SMALL
700 void
setifrtlabel(const char * label,int d)701 setifrtlabel(const char *label, int d)
702 {
703 	if (d != 0)
704 		ifr.ifr_data = (caddr_t)(const char *)"";
705 	else
706 		ifr.ifr_data = (caddr_t)label;
707 	if (ioctl(sock, SIOCSIFRTLABEL, &ifr) == -1)
708 		warn("SIOCSIFRTLABEL");
709 }
710 #endif
711 
712 void
setifnetmask(const char * addr,int ignored)713 setifnetmask(const char *addr, int ignored)
714 {
715 	setmask++;
716 	afp->af_getaddr(addr, MASK);
717 	explicit_prefix = 1;
718 }
719 
720 void
setifbroadaddr(const char * addr,int ignored)721 setifbroadaddr(const char *addr, int ignored)
722 {
723 	setbroad++;
724 	afp->af_getaddr(addr, DSTADDR);
725 }
726 
727 void
setifipdst(const char * addr,int ignored)728 setifipdst(const char *addr, int ignored)
729 {
730 	in_getaddr(addr, DSTADDR);
731 	setipdst++;
732 	clearaddr = 0;
733 	newaddr = 0;
734 }
735 
736 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
737 void
notealias(const char * addr,int param)738 notealias(const char *addr, int param)
739 {
740 	if (setaddr && doalias == 0 && param < 0)
741 		memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
742 		    rqtosa(af_addreq)->sa_len);
743 	doalias = param;
744 	if (param < 0) {
745 		clearaddr = 1;
746 		newaddr = 0;
747 	} else
748 		clearaddr = 0;
749 }
750 
751 void
setifdstaddr(const char * addr,int param)752 setifdstaddr(const char *addr, int param)
753 {
754 	setaddr++;
755 	setipdst++;
756 	afp->af_getaddr(addr, DSTADDR);
757 }
758 
759 void
addaf(const char * vname,int value)760 addaf(const char *vname, int value)
761 {
762 	struct if_afreq	ifar;
763 
764 	strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
765 	ifar.ifar_af = value;
766 	if (ioctl(sock, SIOCIFAFATTACH, (caddr_t)&ifar) == -1)
767 		warn("SIOCIFAFATTACH");
768 }
769 
770 void
removeaf(const char * vname,int value)771 removeaf(const char *vname, int value)
772 {
773 	struct if_afreq	ifar;
774 
775 	strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
776 	ifar.ifar_af = value;
777 	if (ioctl(sock, SIOCIFAFDETACH, (caddr_t)&ifar) == -1)
778 		warn("SIOCIFAFDETACH");
779 }
780 
781 void
setia6flags(const char * vname,int value)782 setia6flags(const char *vname, int value)
783 {
784 
785 	if (value < 0) {
786 		value = -value;
787 		in6_addreq.ifra_flags &= ~value;
788 	} else
789 		in6_addreq.ifra_flags |= value;
790 }
791 
792 void
setia6pltime(const char * val,int d)793 setia6pltime(const char *val, int d)
794 {
795 
796 	setia6lifetime("pltime", val);
797 }
798 
799 void
setia6vltime(const char * val,int d)800 setia6vltime(const char *val, int d)
801 {
802 
803 	setia6lifetime("vltime", val);
804 }
805 
806 void
setia6lifetime(const char * cmd,const char * val)807 setia6lifetime(const char *cmd, const char *val)
808 {
809 	const char *errmsg = NULL;
810 	time_t newval, t;
811 
812 	newval = strtonum(val, 0, 1000000, &errmsg);
813 	if (errmsg)
814 		errx(1, "invalid %s %s: %s", cmd, val, errmsg);
815 
816 	t = time(NULL);
817 
818 	if (afp->af_af != AF_INET6)
819 		errx(1, "%s not allowed for this address family", cmd);
820 	if (strcmp(cmd, "vltime") == 0) {
821 		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
822 		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
823 	} else if (strcmp(cmd, "pltime") == 0) {
824 		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
825 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
826 	}
827 }
828 
829 void
setia6eui64(const char * cmd,int val)830 setia6eui64(const char *cmd, int val)
831 {
832 	struct ifaddrs *ifap, *ifa;
833 	const struct sockaddr_in6 *sin6 = NULL;
834 	const struct in6_addr *lladdr = NULL;
835 	struct in6_addr *in6;
836 
837 	if (afp->af_af != AF_INET6)
838 		errx(1, "%s not allowed for this address family", cmd);
839 
840 	addaf(ifname, AF_INET6);
841 
842 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
843 	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
844 		errx(1, "interface index is already filled");
845 	if (getifaddrs(&ifap) != 0)
846 		err(1, "getifaddrs");
847 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
848 		if (ifa->ifa_addr->sa_family == AF_INET6 &&
849 		    strcmp(ifa->ifa_name, ifname) == 0) {
850 			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
851 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
852 				lladdr = &sin6->sin6_addr;
853 				break;
854 			}
855 		}
856 	}
857 	if (!lladdr)
858 		errx(1, "could not determine link local address");
859 
860 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
861 
862 	freeifaddrs(ifap);
863 }
864 
865 const char *
get_string(const char * val,const char * sep,u_int8_t * buf,int * lenp)866 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
867 {
868 	int len = *lenp, hexstr;
869 	u_int8_t *p = buf;
870 
871 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
872 	if (hexstr)
873 		val += 2;
874 	for (;;) {
875 		if (*val == '\0')
876 			break;
877 		if (sep != NULL && strchr(sep, *val) != NULL) {
878 			val++;
879 			break;
880 		}
881 		if (hexstr) {
882 			if (!isxdigit((u_char)val[0]) ||
883 			    !isxdigit((u_char)val[1])) {
884 				warnx("bad hexadecimal digits");
885 				return NULL;
886 			}
887 		}
888 		if (p > buf + len) {
889 			if (hexstr)
890 				warnx("hexadecimal digits too long");
891 			else
892 				warnx("strings too long");
893 			return NULL;
894 		}
895 		if (hexstr) {
896 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
897 			*p++ = (tohex((u_char)val[0]) << 4) |
898 			    tohex((u_char)val[1]);
899 #undef tohex
900 			val += 2;
901 		} else {
902 			if (*val == '\\' &&
903 			    sep != NULL && strchr(sep, *(val + 1)) != NULL)
904 				val++;
905 			*p++ = *val++;
906 		}
907 	}
908 	len = p - buf;
909 	if (len < *lenp)
910 		memset(p, 0, *lenp - len);
911 	*lenp = len;
912 	return val;
913 }
914 
915 int
len_string(const u_int8_t * buf,int len)916 len_string(const u_int8_t *buf, int len)
917 {
918 	int i = 0, hasspc = 0;
919 
920 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
921 		for (; i < len; i++) {
922 			/* Only print 7-bit ASCII keys */
923 			if (buf[i] & 0x80 || !isprint(buf[i]))
924 				break;
925 			if (isspace(buf[i]))
926 				hasspc++;
927 		}
928 	}
929 	if (i == len) {
930 		if (hasspc || len == 0)
931 			return len + 2;
932 		else
933 			return len;
934 	} else
935 		return (len * 2) + 2;
936 }
937 
938 int
print_string(const u_int8_t * buf,int len)939 print_string(const u_int8_t *buf, int len)
940 {
941 	int i = 0, hasspc = 0;
942 
943 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
944 		for (; i < len; i++) {
945 			/* Only print 7-bit ASCII keys */
946 			if (buf[i] & 0x80 || !isprint(buf[i]))
947 				break;
948 			if (isspace(buf[i]))
949 				hasspc++;
950 		}
951 	}
952 	if (i == len) {
953 		if (hasspc || len == 0) {
954 			printf("\"%.*s\"", len, buf);
955 			return len + 2;
956 		} else {
957 			printf("%.*s", len, buf);
958 			return len;
959 		}
960 	} else {
961 		printf("0x");
962 		for (i = 0; i < len; i++)
963 			printf("%02x", buf[i]);
964 		return (len * 2) + 2;
965 	}
966 }
967 
968 static void
print_tunnel(const struct if_laddrreq * req)969 print_tunnel(const struct if_laddrreq *req)
970 {
971 	char psrcaddr[NI_MAXHOST];
972 	char pdstaddr[NI_MAXHOST];
973 	const char *ver = "";
974 	const int niflag = NI_NUMERICHOST;
975 
976 	if (req == NULL) {
977 		printf("(unset)");
978 		return;
979 	}
980 
981 	psrcaddr[0] = pdstaddr[0] = '\0';
982 
983 	if (getnameinfo((struct sockaddr *)&req->addr, req->addr.ss_len,
984 	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0)
985 		strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
986 	if (req->addr.ss_family == AF_INET6)
987 		ver = "6";
988 
989 	printf("inet%s %s", ver, psrcaddr);
990 
991 	if (req->dstaddr.ss_family != AF_UNSPEC) {
992 		in_port_t dstport = 0;
993 		const struct sockaddr_in *sin;
994 		const struct sockaddr_in6 *sin6;
995 
996 		if (getnameinfo((struct sockaddr *)&req->dstaddr,
997 		    req->dstaddr.ss_len, pdstaddr, sizeof(pdstaddr),
998 		    0, 0, niflag) != 0)
999 			strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
1000 
1001 		printf(" -> %s", pdstaddr);
1002 
1003 		switch (req->dstaddr.ss_family) {
1004 		case AF_INET:
1005 			sin = (const struct sockaddr_in *)&req->dstaddr;
1006 			dstport = sin->sin_port;
1007 			break;
1008 		case AF_INET6:
1009 			sin6 = (const struct sockaddr_in6 *)&req->dstaddr;
1010 			dstport = sin6->sin6_port;
1011 			break;
1012 		}
1013 
1014 		if (dstport)
1015 			printf(":%u", ntohs(dstport));
1016 	}
1017 }
1018 
1019 static void
phys_status(int force)1020 phys_status(int force)
1021 {
1022 	struct if_laddrreq req;
1023 	struct if_laddrreq *r = &req;
1024 
1025 	memset(&req, 0, sizeof(req));
1026 	(void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
1027 	if (ioctl(sock, SIOCGLIFPHYADDR, (caddr_t)&req) == -1) {
1028 		if (errno != EADDRNOTAVAIL)
1029 			return;
1030 
1031 		r = NULL;
1032 	}
1033 
1034 	printf("\ttunnel: ");
1035 	print_tunnel(r);
1036 
1037 	if (ioctl(sock, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0) {
1038 		if (ifr.ifr_ttl == -1)
1039 			printf(" ttl copy");
1040 		else if (ifr.ifr_ttl > 0)
1041 			printf(" ttl %d", ifr.ifr_ttl);
1042 	}
1043 
1044 	if (ioctl(sock, SIOCGLIFPHYDF, (caddr_t)&ifr) == 0)
1045 		printf(" %s", ifr.ifr_df ? "df" : "nodf");
1046 
1047 #ifndef SMALL
1048 	if (ioctl(sock, SIOCGLIFPHYECN, (caddr_t)&ifr) == 0)
1049 		printf(" %s", ifr.ifr_metric ? "ecn" : "noecn");
1050 
1051 	if (ioctl(sock, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 &&
1052 	    (rdomainid != 0 || ifr.ifr_rdomainid != 0))
1053 		printf(" rdomain %d", ifr.ifr_rdomainid);
1054 #endif
1055 	printf("\n");
1056 }
1057 
1058 #ifndef SMALL
1059 const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1060 
1061 const struct ifmedia_status_description ifm_status_descriptions[] =
1062 	IFM_STATUS_DESCRIPTIONS;
1063 #endif
1064 
1065 const struct if_status_description if_status_descriptions[] =
1066 	LINK_STATE_DESCRIPTIONS;
1067 
1068 const char *
get_linkstate(int mt,int link_state)1069 get_linkstate(int mt, int link_state)
1070 {
1071 	const struct if_status_description *p;
1072 	static char buf[8];
1073 
1074 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1075 		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
1076 			return (p->ifs_string);
1077 	}
1078 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1079 	return buf;
1080 }
1081 
1082 /*
1083  * Print the status of the interface.  If an address family was
1084  * specified, show it and it only; otherwise, show them all.
1085  */
1086 void
status(int link,struct sockaddr_dl * sdl,int ls)1087 status(int link, struct sockaddr_dl *sdl, int ls)
1088 {
1089 	const struct afswtch *p = afp;
1090 	struct ifmediareq ifmr;
1091 #ifndef SMALL
1092 	struct ifreq ifrdesc;
1093 	char ifdescr[IFDESCRSIZE];
1094 #endif
1095 	uint64_t *media_list;
1096 	char sep;
1097 
1098 
1099 	printf("%s: ", ifname);
1100 	printb("flags", flags | (xflags << 16), IFFBITS);
1101 	if (rdomainid)
1102 		printf(" rdomain %d", rdomainid);
1103 	if (metric)
1104 		printf(" metric %lu", metric);
1105 	if (mtu)
1106 		printf(" mtu %lu", mtu);
1107 	putchar('\n');
1108 	if (sdl != NULL && sdl->sdl_alen &&
1109 	    (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
1110 		(void)printf("\tlladdr %s\n", ether_ntoa(
1111 		    (struct ether_addr *)LLADDR(sdl)));
1112 
1113 	sep = '\t';
1114 #ifndef SMALL
1115 	(void) memset(&ifrdesc, 0, sizeof(ifrdesc));
1116 	(void) strlcpy(ifrdesc.ifr_name, ifname, sizeof(ifrdesc.ifr_name));
1117 	ifrdesc.ifr_data = (caddr_t)&ifdescr;
1118 	if (ioctl(sock, SIOCGIFDESCR, &ifrdesc) == 0 &&
1119 	    strlen(ifrdesc.ifr_data))
1120 		printf("\tdescription: %s\n", ifrdesc.ifr_data);
1121 
1122 	if (sdl != NULL) {
1123 		printf("%cindex %u", sep, sdl->sdl_index);
1124 		sep = ' ';
1125 	}
1126 	if (ioctl(sock, SIOCGIFPRIORITY, &ifrdesc) == 0) {
1127 		printf("%cpriority %d", sep, ifrdesc.ifr_metric);
1128 		sep = ' ';
1129 	}
1130 #endif
1131 	printf("%cllprio %d\n", sep, llprio);
1132 
1133 	(void) memset(&ifmr, 0, sizeof(ifmr));
1134 	(void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
1135 
1136 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
1137 		/*
1138 		 * Interface doesn't support SIOC{G,S}IFMEDIA.
1139 		 */
1140 		if (ls != LINK_STATE_UNKNOWN)
1141 			printf("\tstatus: %s\n",
1142 			    get_linkstate(sdl->sdl_type, ls));
1143 		goto proto_status;
1144 	}
1145 
1146 	if (ifmr.ifm_count == 0) {
1147 		warnx("%s: no media types?", ifname);
1148 		goto proto_status;
1149 	}
1150 
1151 	media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
1152 	if (media_list == NULL)
1153 		err(1, "calloc");
1154 	ifmr.ifm_ulist = media_list;
1155 
1156 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1)
1157 		err(1, "SIOCGIFMEDIA");
1158 
1159 #ifdef SMALL
1160 	printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls));
1161 #else
1162 	if (ifmr.ifm_status & IFM_AVALID) {
1163 		const struct ifmedia_status_description *ifms;
1164 		int bitno, found = 0;
1165 
1166 		printf("\tstatus: ");
1167 		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1168 			for (ifms = ifm_status_descriptions;
1169 			    ifms->ifms_valid != 0; ifms++) {
1170 				if (ifms->ifms_type !=
1171 				    IFM_TYPE(ifmr.ifm_current) ||
1172 				    ifms->ifms_valid !=
1173 				    ifm_status_valid_list[bitno])
1174 					continue;
1175 				printf("%s%s", found ? ", " : "",
1176 				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1177 				found = 1;
1178 
1179 				/*
1180 				 * For each valid indicator bit, there's
1181 				 * only one entry for each media type, so
1182 				 * terminate the inner loop now.
1183 				 */
1184 				break;
1185 			}
1186 		}
1187 
1188 		if (found == 0)
1189 			printf("unknown");
1190 		putchar('\n');
1191 	}
1192 
1193 #endif
1194 	free(media_list);
1195 
1196  proto_status:
1197 	if (link == 0) {
1198 		if ((p = afp) != NULL) {
1199 			p->af_status(1);
1200 		} else for (p = afs; p->af_name; p++) {
1201 			ifr.ifr_addr.sa_family = p->af_af;
1202 			p->af_status(0);
1203 		}
1204 	}
1205 
1206 	phys_status(0);
1207 }
1208 
1209 void
in_status(int force)1210 in_status(int force)
1211 {
1212 	struct sockaddr_in *sin, sin2;
1213 
1214 	getsock(AF_INET);
1215 	if (sock == -1) {
1216 		if (errno == EPROTONOSUPPORT)
1217 			return;
1218 		err(1, "socket");
1219 	}
1220 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1221 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1222 
1223 	/*
1224 	 * We keep the interface address and reset it before each
1225 	 * ioctl() so we can get ifaliases information (as opposed
1226 	 * to the primary interface netmask/dstaddr/broadaddr, if
1227 	 * the ifr_addr field is zero).
1228 	 */
1229 	memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
1230 
1231 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1232 	if (ioctl(sock, SIOCGIFADDR, (caddr_t)&ifr) == -1) {
1233 		warn("SIOCGIFADDR");
1234 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1235 	}
1236 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1237 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1238 	printf("\tinet %s", inet_ntoa(sin->sin_addr));
1239 	memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1240 	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t)&ifr) == -1) {
1241 		if (errno != EADDRNOTAVAIL)
1242 			warn("SIOCGIFNETMASK");
1243 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1244 	} else
1245 		netmask.sin_addr =
1246 		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1247 	if (flags & IFF_POINTOPOINT) {
1248 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1249 		if (ioctl(sock, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) {
1250 			if (errno == EADDRNOTAVAIL)
1251 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1252 			else
1253 			    warn("SIOCGIFDSTADDR");
1254 		}
1255 		(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1256 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1257 		printf(" --> %s", inet_ntoa(sin->sin_addr));
1258 	}
1259 	printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr));
1260 	if (flags & IFF_BROADCAST) {
1261 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1262 		if (ioctl(sock, SIOCGIFBRDADDR, (caddr_t)&ifr) == -1) {
1263 			if (errno == EADDRNOTAVAIL)
1264 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1265 			else
1266 			    warn("SIOCGIFBRDADDR");
1267 		}
1268 		(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1269 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
1270 		if (sin->sin_addr.s_addr != 0)
1271 			printf(" broadcast %s", inet_ntoa(sin->sin_addr));
1272 	}
1273 	putchar('\n');
1274 }
1275 
1276 void
setifprefixlen(const char * addr,int d)1277 setifprefixlen(const char *addr, int d)
1278 {
1279 	setmask++;
1280 	if (afp->af_getprefix)
1281 		afp->af_getprefix(addr, MASK);
1282 	explicit_prefix = 1;
1283 }
1284 
1285 void
in6_fillscopeid(struct sockaddr_in6 * sin6)1286 in6_fillscopeid(struct sockaddr_in6 *sin6)
1287 {
1288 #ifdef __KAME__
1289 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1290 		sin6->sin6_scope_id =
1291 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
1292 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
1293 	}
1294 #endif /* __KAME__ */
1295 }
1296 
1297 /* XXX not really an alias */
1298 void
in6_alias(struct in6_ifreq * creq)1299 in6_alias(struct in6_ifreq *creq)
1300 {
1301 	struct sockaddr_in6 *sin6;
1302 	struct	in6_ifreq ifr6;		/* shadows file static variable */
1303 	u_int32_t scopeid;
1304 	char hbuf[NI_MAXHOST];
1305 	const int niflag = NI_NUMERICHOST;
1306 
1307 	/* Get the non-alias address for this interface. */
1308 	getsock(AF_INET6);
1309 	if (sock == -1) {
1310 		if (errno == EPROTONOSUPPORT)
1311 			return;
1312 		err(1, "socket");
1313 	}
1314 
1315 	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
1316 
1317 	in6_fillscopeid(sin6);
1318 	scopeid = sin6->sin6_scope_id;
1319 	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1320 	    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1321 		strlcpy(hbuf, "", sizeof hbuf);
1322 	printf("\tinet6 %s", hbuf);
1323 
1324 	if (flags & IFF_POINTOPOINT) {
1325 		(void) memset(&ifr6, 0, sizeof(ifr6));
1326 		(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1327 		ifr6.ifr_addr = creq->ifr_addr;
1328 		if (ioctl(sock, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) == -1) {
1329 			if (errno != EADDRNOTAVAIL)
1330 				warn("SIOCGIFDSTADDR_IN6");
1331 			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
1332 			ifr6.ifr_addr.sin6_family = AF_INET6;
1333 			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
1334 		}
1335 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1336 		in6_fillscopeid(sin6);
1337 		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1338 		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1339 			strlcpy(hbuf, "", sizeof hbuf);
1340 		printf(" -> %s", hbuf);
1341 	}
1342 
1343 	(void) memset(&ifr6, 0, sizeof(ifr6));
1344 	(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1345 	ifr6.ifr_addr = creq->ifr_addr;
1346 	if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) {
1347 		if (errno != EADDRNOTAVAIL)
1348 			warn("SIOCGIFNETMASK_IN6");
1349 	} else {
1350 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1351 		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
1352 		    sizeof(struct in6_addr)));
1353 	}
1354 
1355 	(void) memset(&ifr6, 0, sizeof(ifr6));
1356 	(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1357 	ifr6.ifr_addr = creq->ifr_addr;
1358 	if (ioctl(sock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) {
1359 		if (errno != EADDRNOTAVAIL)
1360 			warn("SIOCGIFAFLAG_IN6");
1361 	} else {
1362 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
1363 			printf(" anycast");
1364 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
1365 			printf(" tentative");
1366 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
1367 			printf(" duplicated");
1368 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
1369 			printf(" detached");
1370 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
1371 			printf(" deprecated");
1372 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
1373 			printf(" autoconf");
1374 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TEMPORARY)
1375 			printf(" autoconfprivacy");
1376 	}
1377 
1378 	if (scopeid)
1379 		printf(" scopeid 0x%x", scopeid);
1380 
1381 	if (Lflag) {
1382 		struct in6_addrlifetime *lifetime;
1383 
1384 		(void) memset(&ifr6, 0, sizeof(ifr6));
1385 		(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1386 		ifr6.ifr_addr = creq->ifr_addr;
1387 		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
1388 		if (ioctl(sock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) {
1389 			if (errno != EADDRNOTAVAIL)
1390 				warn("SIOCGIFALIFETIME_IN6");
1391 		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
1392 			time_t t = time(NULL);
1393 
1394 			printf(" pltime ");
1395 			if (lifetime->ia6t_preferred) {
1396 				printf("%s", lifetime->ia6t_preferred < t
1397 				    ? "0" :
1398 				    sec2str(lifetime->ia6t_preferred - t));
1399 			} else
1400 				printf("infty");
1401 
1402 			printf(" vltime ");
1403 			if (lifetime->ia6t_expire) {
1404 				printf("%s", lifetime->ia6t_expire < t
1405 				    ? "0"
1406 				    : sec2str(lifetime->ia6t_expire - t));
1407 			} else
1408 				printf("infty");
1409 		}
1410 	}
1411 
1412 	printf("\n");
1413 }
1414 
1415 void
in6_status(int force)1416 in6_status(int force)
1417 {
1418 	in6_alias((struct in6_ifreq *)&ifr6);
1419 }
1420 
1421 #ifndef SMALL
1422 void
settunnel(const char * src,const char * dst)1423 settunnel(const char *src, const char *dst)
1424 {
1425 	char buf[HOST_NAME_MAX+1 + sizeof (":65535")], *dstport;
1426 	const char *dstip;
1427 	struct addrinfo *srcres, *dstres;
1428 	int ecode;
1429 	struct if_laddrreq req;
1430 
1431 	if (strchr(dst, ':') == NULL || strchr(dst, ':') != strrchr(dst, ':')) {
1432 		/* no port or IPv6 */
1433 		dstip = dst;
1434 		dstport = NULL;
1435 	} else {
1436 		if (strlcpy(buf, dst, sizeof(buf)) >= sizeof(buf))
1437 			errx(1, "%s bad value", dst);
1438 		dstport = strchr(buf, ':');
1439 		*dstport++ = '\0';
1440 		dstip = buf;
1441 	}
1442 
1443 	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
1444 		errx(1, "error in parsing address string: %s",
1445 		    gai_strerror(ecode));
1446 
1447 	if ((ecode = getaddrinfo(dstip, dstport, NULL, &dstres)) != 0)
1448 		errx(1, "error in parsing address string: %s",
1449 		    gai_strerror(ecode));
1450 
1451 	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
1452 		errx(1,
1453 		    "source and destination address families do not match");
1454 
1455 	memset(&req, 0, sizeof(req));
1456 	(void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
1457 	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
1458 	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
1459 	if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
1460 		warn("SIOCSLIFPHYADDR");
1461 
1462 	freeaddrinfo(srcres);
1463 	freeaddrinfo(dstres);
1464 }
1465 
1466 void
settunneladdr(const char * addr,int ignored)1467 settunneladdr(const char *addr, int ignored)
1468 {
1469 	struct addrinfo hints, *res;
1470 	struct if_laddrreq req;
1471 	ssize_t len;
1472 	int rv;
1473 
1474 	memset(&hints, 0, sizeof(hints));
1475 	hints.ai_family = AF_UNSPEC;
1476 	hints.ai_socktype = SOCK_DGRAM;
1477 	hints.ai_protocol = 0;
1478 	hints.ai_flags = AI_PASSIVE;
1479 
1480 	rv = getaddrinfo(addr, NULL, &hints, &res);
1481 	if (rv != 0)
1482 		errx(1, "tunneladdr %s: %s", addr, gai_strerror(rv));
1483 
1484 	memset(&req, 0, sizeof(req));
1485 	len = strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
1486 	if (len >= sizeof(req.iflr_name))
1487 		errx(1, "%s: Interface name too long", ifname);
1488 
1489 	memcpy(&req.addr, res->ai_addr, res->ai_addrlen);
1490 
1491 	req.dstaddr.ss_len = 2;
1492 	req.dstaddr.ss_family = AF_UNSPEC;
1493 
1494 	if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
1495 		warn("tunneladdr %s", addr);
1496 
1497 	freeaddrinfo(res);
1498 }
1499 
1500 void
deletetunnel(const char * ignored,int alsoignored)1501 deletetunnel(const char *ignored, int alsoignored)
1502 {
1503 	if (ioctl(sock, SIOCDIFPHYADDR, &ifr) == -1)
1504 		warn("SIOCDIFPHYADDR");
1505 }
1506 
1507 void
settunnelinst(const char * id,int param)1508 settunnelinst(const char *id, int param)
1509 {
1510 	const char *errmsg = NULL;
1511 	int rdomainid;
1512 
1513 	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
1514 	if (errmsg)
1515 		errx(1, "rdomain %s: %s", id, errmsg);
1516 
1517 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1518 	ifr.ifr_rdomainid = rdomainid;
1519 	if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
1520 		warn("SIOCSLIFPHYRTABLE");
1521 }
1522 
1523 void
unsettunnelinst(const char * ignored,int alsoignored)1524 unsettunnelinst(const char *ignored, int alsoignored)
1525 {
1526 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1527 	ifr.ifr_rdomainid = 0;
1528 	if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
1529 		warn("SIOCSLIFPHYRTABLE");
1530 }
1531 
1532 void
settunnelttl(const char * id,int param)1533 settunnelttl(const char *id, int param)
1534 {
1535 	const char *errmsg = NULL;
1536 	int ttl;
1537 
1538 	if (strcmp(id, "copy") == 0)
1539 		ttl = -1;
1540 	else {
1541 		ttl = strtonum(id, 0, 0xff, &errmsg);
1542 		if (errmsg)
1543 			errx(1, "tunnelttl %s: %s", id, errmsg);
1544 	}
1545 
1546 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1547 	ifr.ifr_ttl = ttl;
1548 	if (ioctl(sock, SIOCSLIFPHYTTL, (caddr_t)&ifr) == -1)
1549 		warn("SIOCSLIFPHYTTL");
1550 }
1551 
1552 void
utf16_to_char(uint16_t * in,int inlen,char * out,size_t outlen)1553 utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
1554 {
1555 	uint16_t c;
1556 
1557 	while (outlen > 0) {
1558 		c = inlen > 0 ? letoh16(*in) : 0;
1559 		if (c == 0 || --outlen == 0) {
1560 			/* always NUL terminate result */
1561 			*out = '\0';
1562 			break;
1563 		}
1564 		*out++ = isascii(c) ? (char)c : '?';
1565 		in++;
1566 		inlen--;
1567 	}
1568 }
1569 
1570 int
char_to_utf16(const char * in,uint16_t * out,size_t outlen)1571 char_to_utf16(const char *in, uint16_t *out, size_t outlen)
1572 {
1573 	int	 n = 0;
1574 	uint16_t c;
1575 
1576 	for (;;) {
1577 		c = *in++;
1578 
1579 		if (c == '\0') {
1580 			/*
1581 			 * NUL termination is not required, but zero out the
1582 			 * residual buffer
1583 			 */
1584 			memset(out, 0, outlen);
1585 			return n;
1586 		}
1587 		if (outlen < sizeof (*out))
1588 			return -1;
1589 
1590 		*out++ = htole16(c);
1591 		n += sizeof (*out);
1592 		outlen -= sizeof (*out);
1593 	}
1594 }
1595 
1596 #endif
1597 
1598 #define SIN(x) ((struct sockaddr_in *) &(x))
1599 struct sockaddr_in *sintab[] = {
1600 SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
1601 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
1602 
1603 void
in_getaddr(const char * s,int which)1604 in_getaddr(const char *s, int which)
1605 {
1606 	struct sockaddr_in *sin = sintab[which], tsin;
1607 	struct hostent *hp;
1608 	int bits, l;
1609 	char p[3];
1610 
1611 	bzero(&tsin, sizeof(tsin));
1612 	sin->sin_len = sizeof(*sin);
1613 	if (which != MASK)
1614 		sin->sin_family = AF_INET;
1615 
1616 	if (which == ADDR && strrchr(s, '/') != NULL &&
1617 	    (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr,
1618 	    sizeof(tsin.sin_addr))) != -1) {
1619 		l = snprintf(p, sizeof(p), "%d", bits);
1620 		if (l < 0 || l >= sizeof(p))
1621 			errx(1, "%d: bad prefixlen", bits);
1622 		setmask++;
1623 		in_getprefix(p, MASK);
1624 		memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr));
1625 	} else if (inet_aton(s, &sin->sin_addr) == 0) {
1626 		if ((hp = gethostbyname(s)))
1627 			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1628 		else
1629 			errx(1, "%s: bad value", s);
1630 	}
1631 }
1632 
1633 void
in_getprefix(const char * plen,int which)1634 in_getprefix(const char *plen, int which)
1635 {
1636 	struct sockaddr_in *sin = sintab[which];
1637 	const char *errmsg = NULL;
1638 	u_char *cp;
1639 	int len;
1640 
1641 	len = strtonum(plen, 0, 32, &errmsg);
1642 	if (errmsg)
1643 		errx(1, "prefix %s: %s", plen, errmsg);
1644 
1645 	sin->sin_len = sizeof(*sin);
1646 	if (which != MASK)
1647 		sin->sin_family = AF_INET;
1648 	if ((len == 0) || (len == 32)) {
1649 		memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
1650 		return;
1651 	}
1652 	memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
1653 	for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
1654 		*cp++ = 0xff;
1655 	if (len)
1656 		*cp = 0xff << (8 - len);
1657 }
1658 
1659 /*
1660  * Print a value a la the %b format of the kernel's printf
1661  */
1662 void
printb(char * s,unsigned int v,unsigned char * bits)1663 printb(char *s, unsigned int v, unsigned char *bits)
1664 {
1665 	int i, any = 0;
1666 	unsigned char c;
1667 
1668 	if (bits && *bits == 8)
1669 		printf("%s=%o", s, v);
1670 	else
1671 		printf("%s=%x", s, v);
1672 
1673 	if (bits) {
1674 		bits++;
1675 		putchar('<');
1676 		while ((i = *bits++)) {
1677 			if (v & (1 << (i-1))) {
1678 				if (any)
1679 					putchar(',');
1680 				any = 1;
1681 				for (; (c = *bits) > 32; bits++)
1682 					putchar(c);
1683 			} else
1684 				for (; *bits > 32; bits++)
1685 					;
1686 		}
1687 		putchar('>');
1688 	}
1689 }
1690 
1691 /*
1692  * A simple version of printb for status output
1693  */
1694 void
printb_status(unsigned short v,unsigned char * bits)1695 printb_status(unsigned short v, unsigned char *bits)
1696 {
1697 	int i, any = 0;
1698 	unsigned char c;
1699 
1700 	if (bits) {
1701 		bits++;
1702 		while ((i = *bits++)) {
1703 			if (v & (1 << (i-1))) {
1704 				if (any)
1705 					putchar(',');
1706 				any = 1;
1707 				for (; (c = *bits) > 32; bits++)
1708 					putchar(tolower(c));
1709 			} else
1710 				for (; *bits > 32; bits++)
1711 					;
1712 		}
1713 	}
1714 }
1715 
1716 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
1717 struct sockaddr_in6 *sin6tab[] = {
1718 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
1719 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
1720 
1721 void
in6_getaddr(const char * s,int which)1722 in6_getaddr(const char *s, int which)
1723 {
1724 	struct sockaddr_in6 *sin6 = sin6tab[which];
1725 	struct addrinfo hints, *res;
1726 	char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen;
1727 	int error;
1728 
1729 	memset(&hints, 0, sizeof(hints));
1730 	hints.ai_family = AF_INET6;
1731 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
1732 
1733 	if (which == ADDR && strchr(s, '/') != NULL) {
1734 		if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
1735 			errx(1, "%s: bad value", s);
1736 		pfxlen = strchr(buf, '/');
1737 		*pfxlen++ = '\0';
1738 		s = buf;
1739 		setmask++;
1740 		in6_getprefix(pfxlen, MASK);
1741 		explicit_prefix = 1;
1742 	}
1743 
1744 	error = getaddrinfo(s, "0", &hints, &res);
1745 	if (error)
1746 		errx(1, "%s: %s", s, gai_strerror(error));
1747 	memcpy(sin6, res->ai_addr, res->ai_addrlen);
1748 #ifdef __KAME__
1749 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
1750 	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
1751 	    sin6->sin6_scope_id) {
1752 		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
1753 		    htons(sin6->sin6_scope_id & 0xffff);
1754 		sin6->sin6_scope_id = 0;
1755 	}
1756 #endif /* __KAME__ */
1757 	freeaddrinfo(res);
1758 }
1759 
1760 void
in6_getprefix(const char * plen,int which)1761 in6_getprefix(const char *plen, int which)
1762 {
1763 	struct sockaddr_in6 *sin6 = sin6tab[which];
1764 	const char *errmsg = NULL;
1765 	u_char *cp;
1766 	int len;
1767 
1768 	len = strtonum(plen, 0, 128, &errmsg);
1769 	if (errmsg)
1770 		errx(1, "prefix %s: %s", plen, errmsg);
1771 
1772 	sin6->sin6_len = sizeof(*sin6);
1773 	if (which != MASK)
1774 		sin6->sin6_family = AF_INET6;
1775 	if ((len == 0) || (len == 128)) {
1776 		memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
1777 		return;
1778 	}
1779 	memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
1780 	for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
1781 		*cp++ = 0xff;
1782 	if (len)
1783 		*cp = 0xff << (8 - len);
1784 }
1785 
1786 int
prefix(void * val,int size)1787 prefix(void *val, int size)
1788 {
1789 	u_char *nam = (u_char *)val;
1790 	int byte, bit, plen = 0;
1791 
1792 	for (byte = 0; byte < size; byte++, plen += 8)
1793 		if (nam[byte] != 0xff)
1794 			break;
1795 	if (byte == size)
1796 		return (plen);
1797 	for (bit = 7; bit != 0; bit--, plen++)
1798 		if (!(nam[byte] & (1 << bit)))
1799 			break;
1800 	for (; bit != 0; bit--)
1801 		if (nam[byte] & (1 << bit))
1802 			return (0);
1803 	byte++;
1804 	for (; byte < size; byte++)
1805 		if (nam[byte])
1806 			return (0);
1807 	return (plen);
1808 }
1809 
1810 /* Print usage and exit  */
1811 __dead void
usage(void)1812 usage(void)
1813 {
1814 	fprintf(stderr,
1815 	    "usage: ifaddr interface [address_family] "
1816 	    "[address [dest_address]]\n"
1817 	    "\t\t[parameters]\n");
1818 	exit(1);
1819 }
1820 
1821 #ifndef SMALL
1822 void
printifhwfeatures(const char * unused,int show)1823 printifhwfeatures(const char *unused, int show)
1824 {
1825 	struct if_data ifrdat;
1826 
1827 	if (!show) {
1828 		if (showcapsflag)
1829 			usage();
1830 		showcapsflag = 1;
1831 		return;
1832 	}
1833 	bzero(&ifrdat, sizeof(ifrdat));
1834 	ifr.ifr_data = (caddr_t)&ifrdat;
1835 	if (ioctl(sock, SIOCGIFDATA, (caddr_t)&ifr) == -1)
1836 		err(1, "SIOCGIFDATA");
1837 	printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
1838 
1839 	if (ioctl(sock, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
1840 		if (ifr.ifr_hardmtu)
1841 			printf(" hardmtu %u", ifr.ifr_hardmtu);
1842 	}
1843 	putchar('\n');
1844 }
1845 #endif
1846 
1847 char *
sec2str(time_t total)1848 sec2str(time_t total)
1849 {
1850 	static char result[256];
1851 	char *p = result;
1852 	char *end = &result[sizeof(result)];
1853 
1854 	snprintf(p, end - p, "%lld", (long long)total);
1855 	return (result);
1856 }
1857 
1858 #ifndef SMALL
1859 void
setrdomain(const char * id,int param)1860 setrdomain(const char *id, int param)
1861 {
1862 	const char *errmsg = NULL;
1863 	int rdomainid;
1864 
1865 	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
1866 	if (errmsg)
1867 		errx(1, "rdomain %s: %s", id, errmsg);
1868 
1869 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1870 	ifr.ifr_rdomainid = rdomainid;
1871 	if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
1872 		warn("SIOCSIFRDOMAIN");
1873 }
1874 
1875 void
unsetrdomain(const char * ignored,int alsoignored)1876 unsetrdomain(const char *ignored, int alsoignored)
1877 {
1878 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1879 	ifr.ifr_rdomainid = 0;
1880 	if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
1881 		warn("SIOCSIFRDOMAIN");
1882 }
1883 #endif
1884 
1885 #ifdef SMALL
1886 void
setignore(const char * id,int param)1887 setignore(const char *id, int param)
1888 {
1889 	/* just digest the command */
1890 }
1891 #endif
1892