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
126struct	ifreq		ifr, ridreq;
127struct	in_aliasreq	in_addreq;
128struct	in6_ifreq	ifr6;
129struct	in6_ifreq	in6_ridreq;
130struct	in6_aliasreq	in6_addreq;
131struct	sockaddr_in	netmask;
132
133char	ifname[IFNAMSIZ];
134int	flags, xflags, setaddr, setmask, setipdst, setbroad, doalias;
135u_long	metric, mtu;
136int	rdomainid;
137int	llprio;
138int	clearaddr, sock;
139int	newaddr = 0;
140int	af = AF_INET;
141int	explicit_prefix = 0;
142int	Lflag = 1;
143
144int	showcapsflag;
145
146void	notealias(const char *, int);
147void	setifaddr(const char *, int);
148void	setifrtlabel(const char *, int);
149void	setifdstaddr(const char *, int);
150void	addaf(const char *, int);
151void	removeaf(const char *, int);
152void	setifbroadaddr(const char *, int);
153void	setifnetmask(const char *, int);
154void	setifprefixlen(const char *, int);
155void	settunnel(const char *, const char *);
156void	settunneladdr(const char *, int);
157void	deletetunnel(const char *, int);
158void	settunnelinst(const char *, int);
159void	unsettunnelinst(const char *, int);
160void	settunnelttl(const char *, int);
161void	setia6flags(const char *, int);
162void	setia6pltime(const char *, int);
163void	setia6vltime(const char *, int);
164void	setia6lifetime(const char *, const char *);
165void	setia6eui64(const char *, int);
166void	setrdomain(const char *, int);
167void	unsetrdomain(const char *, int);
168int	prefix(void *val, int);
169int	printgroup(char *, int);
170void	setifipdst(const char *, int);
171void	setignore(const char *, int);
172
173int	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
181const 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
228int	getinfo(struct ifreq *, int);
229void	getsock(int);
230void	printif(char *, int);
231void	printb(char *, unsigned int, unsigned char *);
232void	printb_status(unsigned short, unsigned char *);
233const char *get_linkstate(int, int);
234void	status(int, struct sockaddr_dl *, int);
235__dead void	usage(void);
236const char *get_string(const char *, const char *, u_int8_t *, int *);
237int	len_string(const u_int8_t *, int);
238int	print_string(const u_int8_t *, int);
239char	*sec2str(time_t);
240
241unsigned long get_ts_map(int, int, int);
242
243void	in_status(int);
244void	in_getaddr(const char *, int);
245void	in_getprefix(const char *, int);
246void	in6_fillscopeid(struct sockaddr_in6 *);
247void	in6_alias(struct in6_ifreq *);
248void	in6_status(int);
249void	in6_getaddr(const char *, int);
250void	in6_getprefix(const char *, int);
251
252/* Known address families */
253const 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
272const struct afswtch *afp;	/*the address family being set or asked about*/
273
274int ifaliases = 0;
275int aflag = 0;
276
277int
278main(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) {
392nextarg:
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
481void
482getsock(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
497int
498getinfo(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
544int
545printgroup(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
579void
580printif(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
683void
684setifaddr(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
700void
701setifrtlabel(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
712void
713setifnetmask(const char *addr, int ignored)
714{
715	setmask++;
716	afp->af_getaddr(addr, MASK);
717	explicit_prefix = 1;
718}
719
720void
721setifbroadaddr(const char *addr, int ignored)
722{
723	setbroad++;
724	afp->af_getaddr(addr, DSTADDR);
725}
726
727void
728setifipdst(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))
737void
738notealias(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
751void
752setifdstaddr(const char *addr, int param)
753{
754	setaddr++;
755	setipdst++;
756	afp->af_getaddr(addr, DSTADDR);
757}
758
759void
760addaf(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
770void
771removeaf(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
781void
782setia6flags(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
792void
793setia6pltime(const char *val, int d)
794{
795
796	setia6lifetime("pltime", val);
797}
798
799void
800setia6vltime(const char *val, int d)
801{
802
803	setia6lifetime("vltime", val);
804}
805
806void
807setia6lifetime(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
829void
830setia6eui64(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
865const char *
866get_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
915int
916len_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
938int
939print_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
968static void
969print_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
1019static void
1020phys_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
1059const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1060
1061const struct ifmedia_status_description ifm_status_descriptions[] =
1062	IFM_STATUS_DESCRIPTIONS;
1063#endif
1064
1065const struct if_status_description if_status_descriptions[] =
1066	LINK_STATE_DESCRIPTIONS;
1067
1068const char *
1069get_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 */
1086void
1087status(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
1209void
1210in_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
1276void
1277setifprefixlen(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
1285void
1286in6_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 */
1298void
1299in6_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
1415void
1416in6_status(int force)
1417{
1418	in6_alias((struct in6_ifreq *)&ifr6);
1419}
1420
1421#ifndef SMALL
1422void
1423settunnel(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
1466void
1467settunneladdr(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
1500void
1501deletetunnel(const char *ignored, int alsoignored)
1502{
1503	if (ioctl(sock, SIOCDIFPHYADDR, &ifr) == -1)
1504		warn("SIOCDIFPHYADDR");
1505}
1506
1507void
1508settunnelinst(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
1523void
1524unsettunnelinst(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
1532void
1533settunnelttl(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
1552void
1553utf16_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
1570int
1571char_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))
1599struct sockaddr_in *sintab[] = {
1600SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
1601SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
1602
1603void
1604in_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
1633void
1634in_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 */
1662void
1663printb(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 */
1694void
1695printb_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))
1717struct sockaddr_in6 *sin6tab[] = {
1718SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
1719SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
1720
1721void
1722in6_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
1760void
1761in6_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
1786int
1787prefix(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
1812usage(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
1822void
1823printifhwfeatures(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
1847char *
1848sec2str(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
1859void
1860setrdomain(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
1875void
1876unsetrdomain(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
1886void
1887setignore(const char *id, int param)
1888{
1889	/* just digest the command */
1890}
1891#endif
1892