xref: /freebsd/usr.sbin/ip6addrctl/ip6addrctl.c (revision 6dcdd79a251b5e62ff9ce562ad451e92dec39408)
12df34251SHajimu UMEMOTO /*	$KAME: ip6addrctl.c,v 1.3 2003/12/16 08:14:28 suz Exp $	*/
2f71d0e11SHajimu UMEMOTO 
38a16b7a1SPedro F. Giffuni /*-
48a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
58a16b7a1SPedro F. Giffuni  *
6f71d0e11SHajimu UMEMOTO  * Copyright (C) 2001 WIDE Project.
7f71d0e11SHajimu UMEMOTO  * All rights reserved.
8f71d0e11SHajimu UMEMOTO  *
9f71d0e11SHajimu UMEMOTO  * Redistribution and use in source and binary forms, with or without
10f71d0e11SHajimu UMEMOTO  * modification, are permitted provided that the following conditions
11f71d0e11SHajimu UMEMOTO  * are met:
12f71d0e11SHajimu UMEMOTO  * 1. Redistributions of source code must retain the above copyright
13f71d0e11SHajimu UMEMOTO  *    notice, this list of conditions and the following disclaimer.
14f71d0e11SHajimu UMEMOTO  * 2. Redistributions in binary form must reproduce the above copyright
15f71d0e11SHajimu UMEMOTO  *    notice, this list of conditions and the following disclaimer in the
16f71d0e11SHajimu UMEMOTO  *    documentation and/or other materials provided with the distribution.
17f71d0e11SHajimu UMEMOTO  * 3. Neither the name of the project nor the names of its contributors
18f71d0e11SHajimu UMEMOTO  *    may be used to endorse or promote products derived from this software
19f71d0e11SHajimu UMEMOTO  *    without specific prior written permission.
20f71d0e11SHajimu UMEMOTO  *
21f71d0e11SHajimu UMEMOTO  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22f71d0e11SHajimu UMEMOTO  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23f71d0e11SHajimu UMEMOTO  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24f71d0e11SHajimu UMEMOTO  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25f71d0e11SHajimu UMEMOTO  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26f71d0e11SHajimu UMEMOTO  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27f71d0e11SHajimu UMEMOTO  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28f71d0e11SHajimu UMEMOTO  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29f71d0e11SHajimu UMEMOTO  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30f71d0e11SHajimu UMEMOTO  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31f71d0e11SHajimu UMEMOTO  * SUCH DAMAGE.
32f71d0e11SHajimu UMEMOTO  */
33f71d0e11SHajimu UMEMOTO 
34f71d0e11SHajimu UMEMOTO #include <sys/types.h>
35f71d0e11SHajimu UMEMOTO #include <sys/socket.h>
36f71d0e11SHajimu UMEMOTO #include <sys/queue.h>
37f71d0e11SHajimu UMEMOTO #include <sys/param.h>
38f71d0e11SHajimu UMEMOTO #include <sys/ioctl.h>
39*6dcdd79aSZhenlei Huang #ifdef JAIL
40*6dcdd79aSZhenlei Huang #include <sys/jail.h>
41*6dcdd79aSZhenlei Huang #endif
42f71d0e11SHajimu UMEMOTO #include <sys/sysctl.h>
43f71d0e11SHajimu UMEMOTO 
44f71d0e11SHajimu UMEMOTO #include <net/if.h>
45f71d0e11SHajimu UMEMOTO 
46f71d0e11SHajimu UMEMOTO #include <netinet/in.h>
47f71d0e11SHajimu UMEMOTO #include <netinet6/in6_var.h>
48f71d0e11SHajimu UMEMOTO 
49f71d0e11SHajimu UMEMOTO #include <stdlib.h>
50f71d0e11SHajimu UMEMOTO #include <netdb.h>
51*6dcdd79aSZhenlei Huang #ifdef JAIL
52*6dcdd79aSZhenlei Huang #include <jail.h>
53*6dcdd79aSZhenlei Huang #endif
54f71d0e11SHajimu UMEMOTO #include <stdio.h>
55f71d0e11SHajimu UMEMOTO #include <unistd.h>
56f71d0e11SHajimu UMEMOTO #include <limits.h>
57f71d0e11SHajimu UMEMOTO #include <string.h>
58f71d0e11SHajimu UMEMOTO #include <err.h>
59f71d0e11SHajimu UMEMOTO 
60*6dcdd79aSZhenlei Huang #ifdef JAIL
61*6dcdd79aSZhenlei Huang static char *jailname;
62*6dcdd79aSZhenlei Huang #endif
63f71d0e11SHajimu UMEMOTO static char *configfile;
64f71d0e11SHajimu UMEMOTO 
65f71d0e11SHajimu UMEMOTO struct policyqueue {
66f71d0e11SHajimu UMEMOTO 	TAILQ_ENTRY(policyqueue) pc_entry;
67f71d0e11SHajimu UMEMOTO 	struct in6_addrpolicy pc_policy;
68f71d0e11SHajimu UMEMOTO };
69f71d0e11SHajimu UMEMOTO TAILQ_HEAD(policyhead, policyqueue);
707bb9ba61SZhenlei Huang static struct policyhead policyhead = TAILQ_HEAD_INITIALIZER(policyhead);
71f71d0e11SHajimu UMEMOTO 
72a9cce232SAlfonso Gregory static void usage(void) __dead2;
73*6dcdd79aSZhenlei Huang static void attach_jail(void);
74784bddbcSKevin Lo static void get_policy(void);
75784bddbcSKevin Lo static void dump_policy(void);
76784bddbcSKevin Lo static int mask2plen(struct sockaddr_in6 *);
77784bddbcSKevin Lo static int parse_prefix(const char *, struct in6_addrpolicy *);
78784bddbcSKevin Lo static void make_policy_fromfile(char *);
79784bddbcSKevin Lo static void plen2mask(struct sockaddr_in6 *, int);
80784bddbcSKevin Lo static void set_policy(void);
81784bddbcSKevin Lo static void add_policy(char *, char *, char *);
82784bddbcSKevin Lo static void delete_policy(char *);
8345442869SEitan Adler static void flush_policy(void);
84f71d0e11SHajimu UMEMOTO 
85f71d0e11SHajimu UMEMOTO int
8645442869SEitan Adler main(int argc, char *argv[])
87f71d0e11SHajimu UMEMOTO {
88*6dcdd79aSZhenlei Huang 	int ch;
89*6dcdd79aSZhenlei Huang 
90*6dcdd79aSZhenlei Huang 	while ((ch = getopt(argc, argv, "j:")) != -1) {
91*6dcdd79aSZhenlei Huang 		switch (ch) {
92*6dcdd79aSZhenlei Huang 		case 'j':
93*6dcdd79aSZhenlei Huang #ifdef JAIL
94*6dcdd79aSZhenlei Huang 			if ((jailname = optarg) == NULL)
95*6dcdd79aSZhenlei Huang 				usage();
96*6dcdd79aSZhenlei Huang #else
97*6dcdd79aSZhenlei Huang 			errx(1, "not built with jail support");
98*6dcdd79aSZhenlei Huang #endif
99*6dcdd79aSZhenlei Huang 			break;
100*6dcdd79aSZhenlei Huang 		default:
101*6dcdd79aSZhenlei Huang 			usage();
102*6dcdd79aSZhenlei Huang 		}
103*6dcdd79aSZhenlei Huang 	}
104*6dcdd79aSZhenlei Huang 	argc -= optind;
105*6dcdd79aSZhenlei Huang 	argv += optind;
106*6dcdd79aSZhenlei Huang 
107*6dcdd79aSZhenlei Huang 	if (argc == 0 || (argc == 1 && strcasecmp(argv[0], "show") == 0)) {
108*6dcdd79aSZhenlei Huang 		attach_jail();
109f71d0e11SHajimu UMEMOTO 		get_policy();
110f71d0e11SHajimu UMEMOTO 		dump_policy();
111*6dcdd79aSZhenlei Huang 	} else if (strcasecmp(argv[0], "add") == 0) {
112*6dcdd79aSZhenlei Huang 		if (argc != 4)
113f71d0e11SHajimu UMEMOTO 			usage();
114*6dcdd79aSZhenlei Huang 		attach_jail();
115*6dcdd79aSZhenlei Huang 		add_policy(argv[1], argv[2], argv[3]);
116*6dcdd79aSZhenlei Huang 	} else if (strcasecmp(argv[0], "delete") == 0) {
11713ce55b6SZhenlei Huang 		if (argc != 2)
11813ce55b6SZhenlei Huang 			usage();
119*6dcdd79aSZhenlei Huang 		attach_jail();
120*6dcdd79aSZhenlei Huang 		delete_policy(argv[1]);
121*6dcdd79aSZhenlei Huang 	} else if (strcasecmp(argv[0], "flush") == 0) {
122*6dcdd79aSZhenlei Huang 		if (argc != 1)
123*6dcdd79aSZhenlei Huang 			usage();
124*6dcdd79aSZhenlei Huang 		attach_jail();
125f71d0e11SHajimu UMEMOTO 		get_policy();
126f71d0e11SHajimu UMEMOTO 		flush_policy();
127*6dcdd79aSZhenlei Huang 	} else if (strcasecmp(argv[0], "install") == 0) {
128*6dcdd79aSZhenlei Huang 		if (argc != 2)
129f71d0e11SHajimu UMEMOTO 			usage();
130*6dcdd79aSZhenlei Huang 		configfile = argv[1];
131f71d0e11SHajimu UMEMOTO 		make_policy_fromfile(configfile);
132*6dcdd79aSZhenlei Huang 		attach_jail();
133f71d0e11SHajimu UMEMOTO 		set_policy();
134f71d0e11SHajimu UMEMOTO 	} else
135f71d0e11SHajimu UMEMOTO 		usage();
136f71d0e11SHajimu UMEMOTO 
137f71d0e11SHajimu UMEMOTO 	exit(0);
138f71d0e11SHajimu UMEMOTO }
139f71d0e11SHajimu UMEMOTO 
140f71d0e11SHajimu UMEMOTO static void
141*6dcdd79aSZhenlei Huang attach_jail(void)
142*6dcdd79aSZhenlei Huang {
143*6dcdd79aSZhenlei Huang #ifdef JAIL
144*6dcdd79aSZhenlei Huang 	int jid;
145*6dcdd79aSZhenlei Huang 
146*6dcdd79aSZhenlei Huang 	if (jailname == NULL)
147*6dcdd79aSZhenlei Huang 		return;
148*6dcdd79aSZhenlei Huang 
149*6dcdd79aSZhenlei Huang 	jid = jail_getid(jailname);
150*6dcdd79aSZhenlei Huang 	if (jid == -1)
151*6dcdd79aSZhenlei Huang 		errx(1, "jail not found");
152*6dcdd79aSZhenlei Huang 	if (jail_attach(jid) != 0)
153*6dcdd79aSZhenlei Huang 		errx(1, "cannot attach to jail");
154*6dcdd79aSZhenlei Huang #endif
155*6dcdd79aSZhenlei Huang }
156*6dcdd79aSZhenlei Huang 
157*6dcdd79aSZhenlei Huang static void
15845442869SEitan Adler get_policy(void)
159f71d0e11SHajimu UMEMOTO {
160f71d0e11SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
161f71d0e11SHajimu UMEMOTO 	size_t l;
16245442869SEitan Adler 	struct in6_addrpolicy *buf;
163f71d0e11SHajimu UMEMOTO 	struct in6_addrpolicy *pol, *ep;
164f71d0e11SHajimu UMEMOTO 
165d42456e1SMarcelo Araujo 	if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0) {
166f71d0e11SHajimu UMEMOTO 		err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
167f71d0e11SHajimu UMEMOTO 		/* NOTREACHED */
168f71d0e11SHajimu UMEMOTO 	}
1692df34251SHajimu UMEMOTO 	if (l == 0) {
1702df34251SHajimu UMEMOTO 		printf("no source-address-selection policy is installed\n");
1712df34251SHajimu UMEMOTO 		return;
1722df34251SHajimu UMEMOTO 	}
173f71d0e11SHajimu UMEMOTO 	if ((buf = malloc(l)) == NULL) {
174f71d0e11SHajimu UMEMOTO 		errx(1, "malloc failed");
175f71d0e11SHajimu UMEMOTO 		/* NOTREACHED */
176f71d0e11SHajimu UMEMOTO 	}
177d42456e1SMarcelo Araujo 	if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
178f71d0e11SHajimu UMEMOTO 		err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
179f71d0e11SHajimu UMEMOTO 		/* NOTREACHED */
180f71d0e11SHajimu UMEMOTO 	}
181f71d0e11SHajimu UMEMOTO 
18245442869SEitan Adler 	ep = buf + l/sizeof(*buf);
18345442869SEitan Adler 	for (pol = buf; pol + 1 <= ep; pol++) {
184f71d0e11SHajimu UMEMOTO 		struct policyqueue *new;
185f71d0e11SHajimu UMEMOTO 
186f71d0e11SHajimu UMEMOTO 		if ((new = malloc(sizeof(*new))) == NULL)
187f71d0e11SHajimu UMEMOTO 			errx(1, "malloc failed\n");
188f71d0e11SHajimu UMEMOTO 		new->pc_policy = *pol;
189f71d0e11SHajimu UMEMOTO 		TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
190f71d0e11SHajimu UMEMOTO 	}
191f71d0e11SHajimu UMEMOTO 
192f71d0e11SHajimu UMEMOTO 	free(buf);
193f71d0e11SHajimu UMEMOTO }
194f71d0e11SHajimu UMEMOTO 
195f71d0e11SHajimu UMEMOTO static void
19645442869SEitan Adler dump_policy(void)
197f71d0e11SHajimu UMEMOTO {
198f71d0e11SHajimu UMEMOTO 	size_t addrlen;
199f71d0e11SHajimu UMEMOTO 	char addrbuf[NI_MAXHOST];
200f71d0e11SHajimu UMEMOTO 	struct in6_addrpolicy *pol;
201f71d0e11SHajimu UMEMOTO 	struct policyqueue *ent;
202f71d0e11SHajimu UMEMOTO 	int plen, first = 1;
203f71d0e11SHajimu UMEMOTO 
204f71d0e11SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(&policyhead); ent;
205f71d0e11SHajimu UMEMOTO 	     ent = TAILQ_NEXT(ent, pc_entry)) {
206f71d0e11SHajimu UMEMOTO 		pol = &ent->pc_policy;
207f71d0e11SHajimu UMEMOTO 		if (first) {
208f71d0e11SHajimu UMEMOTO 			printf("%-30s %5s %5s %8s\n",
209f71d0e11SHajimu UMEMOTO 			       "Prefix", "Prec", "Label", "Use");
210f71d0e11SHajimu UMEMOTO 			first = 0;
211f71d0e11SHajimu UMEMOTO 		}
212f71d0e11SHajimu UMEMOTO 
213f71d0e11SHajimu UMEMOTO 		if ((getnameinfo((struct sockaddr *)&pol->addr,
214f71d0e11SHajimu UMEMOTO 				 sizeof(pol->addr), addrbuf, sizeof(addrbuf),
215f71d0e11SHajimu UMEMOTO 				 NULL, 0, NI_NUMERICHOST))) {
216f71d0e11SHajimu UMEMOTO 			warnx("getnameinfo for prefix address failed");
217f71d0e11SHajimu UMEMOTO 			continue;
218f71d0e11SHajimu UMEMOTO 		}
219f71d0e11SHajimu UMEMOTO 		if ((plen = mask2plen(&pol->addrmask)) < 0) {
220f71d0e11SHajimu UMEMOTO 			warnx("invalid address mask");
221f71d0e11SHajimu UMEMOTO 			continue;
222f71d0e11SHajimu UMEMOTO 		}
223f71d0e11SHajimu UMEMOTO 		addrlen = strlen(addrbuf);
224f71d0e11SHajimu UMEMOTO 		if (addrlen + sizeof("/128") < sizeof(addrbuf)) {
225f71d0e11SHajimu UMEMOTO 			snprintf(&addrbuf[addrlen],
226f71d0e11SHajimu UMEMOTO 				 sizeof(addrbuf) - addrlen - 1,
227f71d0e11SHajimu UMEMOTO 				 "/%d", plen);
228f71d0e11SHajimu UMEMOTO 			printf("%-30s", addrbuf);
229f71d0e11SHajimu UMEMOTO 		} else		/* XXX */
230f71d0e11SHajimu UMEMOTO 			printf("%s/%d", addrbuf, plen);
231f71d0e11SHajimu UMEMOTO 		printf(" %5d %5d %8llu\n", pol->preced, pol->label,
232f71d0e11SHajimu UMEMOTO 		    (unsigned long long)pol->use);
233f71d0e11SHajimu UMEMOTO 	}
234f71d0e11SHajimu UMEMOTO }
235f71d0e11SHajimu UMEMOTO 
236f71d0e11SHajimu UMEMOTO #define SKIP_WHITE(p, emptyok) \
237f71d0e11SHajimu UMEMOTO 	do { \
238f71d0e11SHajimu UMEMOTO 		while((*(p) == ' ' || *(p) == '\t')) \
239f71d0e11SHajimu UMEMOTO 			(p)++; \
240f71d0e11SHajimu UMEMOTO  		if ((*(p) == '\0' || (*(p) == '\n')) && !(emptyok)) \
241f71d0e11SHajimu UMEMOTO 			goto bad; \
242f71d0e11SHajimu UMEMOTO 	} while (0);
243f71d0e11SHajimu UMEMOTO #define SKIP_WORD(p) \
244f71d0e11SHajimu UMEMOTO 	do { \
245f71d0e11SHajimu UMEMOTO 		while(*(p) != ' ' && *(p) != '\t') \
246f71d0e11SHajimu UMEMOTO 			(p)++; \
247f71d0e11SHajimu UMEMOTO  		if (*(p) == '\0' || *(p) == '\n') \
248f71d0e11SHajimu UMEMOTO 			goto bad; \
249f71d0e11SHajimu UMEMOTO 	} while (0);
250f71d0e11SHajimu UMEMOTO 
251f71d0e11SHajimu UMEMOTO static void
25245442869SEitan Adler make_policy_fromfile(char *conf)
253f71d0e11SHajimu UMEMOTO {
254f71d0e11SHajimu UMEMOTO 	char line[_POSIX2_LINE_MAX], *cp;
255f71d0e11SHajimu UMEMOTO 	char *addrstr;
256f71d0e11SHajimu UMEMOTO 	FILE *fp;
257f71d0e11SHajimu UMEMOTO 	int count = 0;
258f71d0e11SHajimu UMEMOTO 	struct in6_addrpolicy pol0;
259f71d0e11SHajimu UMEMOTO 	struct policyqueue *new;
260f71d0e11SHajimu UMEMOTO 
261f71d0e11SHajimu UMEMOTO 	if ((fp = fopen(conf, "r")) == NULL)
262f71d0e11SHajimu UMEMOTO 		err(1, "fopen: %s", conf);
263f71d0e11SHajimu UMEMOTO 
264f71d0e11SHajimu UMEMOTO 	while(fgets(line, sizeof(line), fp)) {
265f71d0e11SHajimu UMEMOTO 		count++;
266f71d0e11SHajimu UMEMOTO 		cp = line;
267f71d0e11SHajimu UMEMOTO 
268f71d0e11SHajimu UMEMOTO 		memset(&pol0, 0, sizeof(pol0));
269f71d0e11SHajimu UMEMOTO 
270f71d0e11SHajimu UMEMOTO 		/* get prefix */
271f71d0e11SHajimu UMEMOTO 		SKIP_WHITE(cp, 1);
272f71d0e11SHajimu UMEMOTO 		if (*cp == '\n') /* empty line */
273f71d0e11SHajimu UMEMOTO 			continue;
274f71d0e11SHajimu UMEMOTO 		if (*cp == '#')
275f71d0e11SHajimu UMEMOTO 			continue;
276f71d0e11SHajimu UMEMOTO 		addrstr = cp;
277f71d0e11SHajimu UMEMOTO 		if (parse_prefix((const char *)addrstr, &pol0))
278f71d0e11SHajimu UMEMOTO 			goto bad;
279f71d0e11SHajimu UMEMOTO 
280f71d0e11SHajimu UMEMOTO 		/* get precedence value */
281f71d0e11SHajimu UMEMOTO 		SKIP_WORD(cp);
282f71d0e11SHajimu UMEMOTO 		SKIP_WHITE(cp, 0);
283f71d0e11SHajimu UMEMOTO 		pol0.preced = atoi(cp);
284f71d0e11SHajimu UMEMOTO 
285f71d0e11SHajimu UMEMOTO 		/* get label */
286f71d0e11SHajimu UMEMOTO 		SKIP_WORD(cp);
287f71d0e11SHajimu UMEMOTO 		SKIP_WHITE(cp, 0);
288f71d0e11SHajimu UMEMOTO 		pol0.label = atoi(cp);
289f71d0e11SHajimu UMEMOTO 
290f71d0e11SHajimu UMEMOTO 		/* parse succeeded.  make a control buffer entry. */
291f71d0e11SHajimu UMEMOTO 		if ((new = malloc(sizeof(*new))) == NULL)
292f71d0e11SHajimu UMEMOTO 			errx(1, "malloc failed\n");
293f71d0e11SHajimu UMEMOTO 		memset(new, 0, sizeof(*new));
294f71d0e11SHajimu UMEMOTO 		new->pc_policy = pol0;
295f71d0e11SHajimu UMEMOTO 		TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
296f71d0e11SHajimu UMEMOTO 	}
297f71d0e11SHajimu UMEMOTO 
298f71d0e11SHajimu UMEMOTO 	fclose(fp);
299f71d0e11SHajimu UMEMOTO 	return;
300f71d0e11SHajimu UMEMOTO 
301f71d0e11SHajimu UMEMOTO   bad:
302f71d0e11SHajimu UMEMOTO 	errx(1, "parse failed at line %d", count);
303f71d0e11SHajimu UMEMOTO 	/* NOTREACHED */
304f71d0e11SHajimu UMEMOTO }
305f71d0e11SHajimu UMEMOTO 
306f71d0e11SHajimu UMEMOTO static int
30745442869SEitan Adler parse_prefix(const char *prefix0, struct in6_addrpolicy *pol)
308f71d0e11SHajimu UMEMOTO {
309f71d0e11SHajimu UMEMOTO 	int e = 0, plen;
310f71d0e11SHajimu UMEMOTO 	char *prefix, *plenstr;
311f71d0e11SHajimu UMEMOTO 	struct addrinfo hints, *res;
312f71d0e11SHajimu UMEMOTO 
313f71d0e11SHajimu UMEMOTO 	if ((prefix = strdup(prefix0)) == NULL)
314f71d0e11SHajimu UMEMOTO 		errx(1, "strdup failed");
315f71d0e11SHajimu UMEMOTO 
316f71d0e11SHajimu UMEMOTO 	if ((plenstr = strchr(prefix, '/')) == NULL) {
317f71d0e11SHajimu UMEMOTO 		e = -1;
318f71d0e11SHajimu UMEMOTO 		goto end;
319f71d0e11SHajimu UMEMOTO 	}
320f71d0e11SHajimu UMEMOTO 	*plenstr = '\0';
321f71d0e11SHajimu UMEMOTO 
322f71d0e11SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
323f71d0e11SHajimu UMEMOTO 	hints.ai_flags = AI_NUMERICHOST;
324f71d0e11SHajimu UMEMOTO 	hints.ai_family = AF_INET6;
325f71d0e11SHajimu UMEMOTO 
326f71d0e11SHajimu UMEMOTO 	if ((e = getaddrinfo(prefix, NULL, &hints, &res)) != 0) {
327f71d0e11SHajimu UMEMOTO 		warnx("getaddrinfo failed for %s: %s", prefix,
328f71d0e11SHajimu UMEMOTO 		      gai_strerror(e));
329f71d0e11SHajimu UMEMOTO 		goto end;
330f71d0e11SHajimu UMEMOTO 	}
331f71d0e11SHajimu UMEMOTO 	memcpy(&pol->addr, res->ai_addr, res->ai_addrlen);
332f71d0e11SHajimu UMEMOTO 	freeaddrinfo(res);
333f71d0e11SHajimu UMEMOTO 	plen = atoi(plenstr + 1);
334f71d0e11SHajimu UMEMOTO 	if (plen < 0 || plen > 128) {
335f71d0e11SHajimu UMEMOTO 		warnx("invalid prefix length: %d", plen);
336f71d0e11SHajimu UMEMOTO 		e = -1;
337f71d0e11SHajimu UMEMOTO 		goto end;
338f71d0e11SHajimu UMEMOTO 	}
339f71d0e11SHajimu UMEMOTO 	plen2mask(&pol->addrmask, plen);
340f71d0e11SHajimu UMEMOTO 
341f71d0e11SHajimu UMEMOTO   end:
342f71d0e11SHajimu UMEMOTO 	free(prefix);
343f71d0e11SHajimu UMEMOTO 	return(e);
344f71d0e11SHajimu UMEMOTO }
345f71d0e11SHajimu UMEMOTO 
346f71d0e11SHajimu UMEMOTO static void
34745442869SEitan Adler plen2mask(struct sockaddr_in6 *mask, int plen)
348f71d0e11SHajimu UMEMOTO {
34945442869SEitan Adler 	u_char *cp = (unsigned char *)&mask->sin6_addr;
350f71d0e11SHajimu UMEMOTO 
351f71d0e11SHajimu UMEMOTO 	memset(mask, 0, sizeof(*mask));
352f71d0e11SHajimu UMEMOTO 	mask->sin6_family = AF_INET6; /* just in case */
353f71d0e11SHajimu UMEMOTO 	mask->sin6_len = sizeof(*mask);
354f71d0e11SHajimu UMEMOTO 
355f71d0e11SHajimu UMEMOTO 	for(; plen >= 8; plen -= 8)
356f71d0e11SHajimu UMEMOTO 		*cp++ = 0xff;
357f71d0e11SHajimu UMEMOTO 	if (plen > 0)
358f71d0e11SHajimu UMEMOTO 		*cp = (0xff << (8 - plen));
359f71d0e11SHajimu UMEMOTO }
360f71d0e11SHajimu UMEMOTO 
361f71d0e11SHajimu UMEMOTO static void
36245442869SEitan Adler set_policy(void)
363f71d0e11SHajimu UMEMOTO {
364f71d0e11SHajimu UMEMOTO 	struct policyqueue *ent;
365f71d0e11SHajimu UMEMOTO 	int s;
366f71d0e11SHajimu UMEMOTO 
367f71d0e11SHajimu UMEMOTO 	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
368f71d0e11SHajimu UMEMOTO 		err(1, "socket(UDP)");
369f71d0e11SHajimu UMEMOTO 
370f71d0e11SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(&policyhead); ent;
371f71d0e11SHajimu UMEMOTO 	     ent = TAILQ_NEXT(ent, pc_entry)) {
372f71d0e11SHajimu UMEMOTO 		if (ioctl(s, SIOCAADDRCTL_POLICY, &ent->pc_policy))
373f71d0e11SHajimu UMEMOTO 			warn("ioctl(SIOCAADDRCTL_POLICY)");
374f71d0e11SHajimu UMEMOTO 	}
375f71d0e11SHajimu UMEMOTO 
376f71d0e11SHajimu UMEMOTO 	close(s);
377f71d0e11SHajimu UMEMOTO }
378f71d0e11SHajimu UMEMOTO 
379f71d0e11SHajimu UMEMOTO static int
38045442869SEitan Adler mask2plen(struct sockaddr_in6 *mask)
381f71d0e11SHajimu UMEMOTO {
382f71d0e11SHajimu UMEMOTO 	int masklen, final = 0;
383f71d0e11SHajimu UMEMOTO 	u_char *p, *lim;
384f71d0e11SHajimu UMEMOTO 
385f71d0e11SHajimu UMEMOTO 	masklen = 0;
386f71d0e11SHajimu UMEMOTO 	lim = (u_char *)(mask + 1);
387f71d0e11SHajimu UMEMOTO 	for (p = (u_char *)(&mask->sin6_addr); p < lim; p++) {
388f71d0e11SHajimu UMEMOTO 		if (final && *p) {
389f71d0e11SHajimu UMEMOTO 			goto bad;
390f71d0e11SHajimu UMEMOTO 		}
391f71d0e11SHajimu UMEMOTO 
392f71d0e11SHajimu UMEMOTO 		switch (*p & 0xff) {
393f71d0e11SHajimu UMEMOTO 		case 0xff:
394f71d0e11SHajimu UMEMOTO 			masklen += 8;
395f71d0e11SHajimu UMEMOTO 			break;
396f71d0e11SHajimu UMEMOTO 		case 0xfe:
397f71d0e11SHajimu UMEMOTO 			masklen += 7;
398f71d0e11SHajimu UMEMOTO 			final++;
399f71d0e11SHajimu UMEMOTO 			break;
400f71d0e11SHajimu UMEMOTO 		case 0xfc:
401f71d0e11SHajimu UMEMOTO 			masklen += 6;
402f71d0e11SHajimu UMEMOTO 			final++;
403f71d0e11SHajimu UMEMOTO 			break;
404f71d0e11SHajimu UMEMOTO 		case 0xf8:
405f71d0e11SHajimu UMEMOTO 			masklen += 5;
406f71d0e11SHajimu UMEMOTO 			final++;
407f71d0e11SHajimu UMEMOTO 			break;
408f71d0e11SHajimu UMEMOTO 		case 0xf0:
409f71d0e11SHajimu UMEMOTO 			masklen += 4;
410f71d0e11SHajimu UMEMOTO 			final++;
411f71d0e11SHajimu UMEMOTO 			break;
412f71d0e11SHajimu UMEMOTO 		case 0xe0:
413f71d0e11SHajimu UMEMOTO 			masklen += 3;
414f71d0e11SHajimu UMEMOTO 			final++;
415f71d0e11SHajimu UMEMOTO 			break;
416f71d0e11SHajimu UMEMOTO 		case 0xc0:
417f71d0e11SHajimu UMEMOTO 			masklen += 2;
418f71d0e11SHajimu UMEMOTO 			final++;
419f71d0e11SHajimu UMEMOTO 			break;
420f71d0e11SHajimu UMEMOTO 		case 0x80:
421f71d0e11SHajimu UMEMOTO 			masklen += 1;
422f71d0e11SHajimu UMEMOTO 			final++;
423f71d0e11SHajimu UMEMOTO 			break;
424f71d0e11SHajimu UMEMOTO 		case 0x00:
425f71d0e11SHajimu UMEMOTO 			final++;
426f71d0e11SHajimu UMEMOTO 			break;
427f71d0e11SHajimu UMEMOTO 		default:
428f71d0e11SHajimu UMEMOTO 			goto bad;
429f71d0e11SHajimu UMEMOTO 			break;
430f71d0e11SHajimu UMEMOTO 		}
431f71d0e11SHajimu UMEMOTO 	}
432f71d0e11SHajimu UMEMOTO 	return(masklen);
433f71d0e11SHajimu UMEMOTO 
434f71d0e11SHajimu UMEMOTO   bad:
435f71d0e11SHajimu UMEMOTO 	return(-1);
436f71d0e11SHajimu UMEMOTO }
437f71d0e11SHajimu UMEMOTO 
438f71d0e11SHajimu UMEMOTO static void
43945442869SEitan Adler add_policy(char *prefix, char *prec, char *label)
440f71d0e11SHajimu UMEMOTO {
441f71d0e11SHajimu UMEMOTO 	struct in6_addrpolicy p;
442f71d0e11SHajimu UMEMOTO 	int s;
443f71d0e11SHajimu UMEMOTO 
444f71d0e11SHajimu UMEMOTO 	memset(&p, 0, sizeof(p));
445f71d0e11SHajimu UMEMOTO 
446f71d0e11SHajimu UMEMOTO 	if (parse_prefix((const char *)prefix, &p))
447f71d0e11SHajimu UMEMOTO 		errx(1, "bad prefix: %s", prefix);
448f71d0e11SHajimu UMEMOTO 	p.preced = atoi(prec);
449f71d0e11SHajimu UMEMOTO 	p.label = atoi(label);
450f71d0e11SHajimu UMEMOTO 
451f71d0e11SHajimu UMEMOTO 	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
452f71d0e11SHajimu UMEMOTO 		err(1, "socket(UDP)");
453f71d0e11SHajimu UMEMOTO 	if (ioctl(s, SIOCAADDRCTL_POLICY, &p))
454f71d0e11SHajimu UMEMOTO 		err(1, "ioctl(SIOCAADDRCTL_POLICY)");
455f71d0e11SHajimu UMEMOTO 
456f71d0e11SHajimu UMEMOTO 	close(s);
457f71d0e11SHajimu UMEMOTO }
458f71d0e11SHajimu UMEMOTO 
459f71d0e11SHajimu UMEMOTO static void
46045442869SEitan Adler delete_policy(char *prefix)
461f71d0e11SHajimu UMEMOTO {
462f71d0e11SHajimu UMEMOTO 	struct in6_addrpolicy p;
463f71d0e11SHajimu UMEMOTO 	int s;
464f71d0e11SHajimu UMEMOTO 
465f71d0e11SHajimu UMEMOTO 	memset(&p, 0, sizeof(p));
466f71d0e11SHajimu UMEMOTO 
467f71d0e11SHajimu UMEMOTO 	if (parse_prefix((const char *)prefix, &p))
468f71d0e11SHajimu UMEMOTO 		errx(1, "bad prefix: %s", prefix);
469f71d0e11SHajimu UMEMOTO 
470f71d0e11SHajimu UMEMOTO 	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
471f71d0e11SHajimu UMEMOTO 		err(1, "socket(UDP)");
472f71d0e11SHajimu UMEMOTO 	if (ioctl(s, SIOCDADDRCTL_POLICY, &p))
473f71d0e11SHajimu UMEMOTO 		err(1, "ioctl(SIOCDADDRCTL_POLICY)");
474f71d0e11SHajimu UMEMOTO 
475f71d0e11SHajimu UMEMOTO 	close(s);
476f71d0e11SHajimu UMEMOTO }
477f71d0e11SHajimu UMEMOTO 
478f71d0e11SHajimu UMEMOTO static void
47945442869SEitan Adler flush_policy(void)
480f71d0e11SHajimu UMEMOTO {
481f71d0e11SHajimu UMEMOTO 	struct policyqueue *ent;
482f71d0e11SHajimu UMEMOTO 	int s;
483f71d0e11SHajimu UMEMOTO 
484f71d0e11SHajimu UMEMOTO 	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
485f71d0e11SHajimu UMEMOTO 		err(1, "socket(UDP)");
486f71d0e11SHajimu UMEMOTO 
487f71d0e11SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(&policyhead); ent;
488f71d0e11SHajimu UMEMOTO 	     ent = TAILQ_NEXT(ent, pc_entry)) {
489f71d0e11SHajimu UMEMOTO 		if (ioctl(s, SIOCDADDRCTL_POLICY, &ent->pc_policy))
490f71d0e11SHajimu UMEMOTO 			warn("ioctl(SIOCDADDRCTL_POLICY)");
491f71d0e11SHajimu UMEMOTO 	}
492f71d0e11SHajimu UMEMOTO 
493f71d0e11SHajimu UMEMOTO 	close(s);
494f71d0e11SHajimu UMEMOTO }
495f71d0e11SHajimu UMEMOTO 
496f71d0e11SHajimu UMEMOTO static void
49745442869SEitan Adler usage(void)
498f71d0e11SHajimu UMEMOTO {
499*6dcdd79aSZhenlei Huang 	fprintf(stderr, "usage: ip6addrctl [-j jail] [show]\n");
500*6dcdd79aSZhenlei Huang 	fprintf(stderr, "       ip6addrctl [-j jail] add "
501f71d0e11SHajimu UMEMOTO 		"<prefix> <precedence> <label>\n");
502*6dcdd79aSZhenlei Huang 	fprintf(stderr, "       ip6addrctl [-j jail] delete <prefix>\n");
503*6dcdd79aSZhenlei Huang 	fprintf(stderr, "       ip6addrctl [-j jail] flush\n");
504*6dcdd79aSZhenlei Huang 	fprintf(stderr, "       ip6addrctl [-j jail] install <configfile>\n");
505f71d0e11SHajimu UMEMOTO 
506f71d0e11SHajimu UMEMOTO 	exit(1);
507f71d0e11SHajimu UMEMOTO }
508