xref: /openbsd/sbin/ipsecctl/ipsecctl.c (revision 6f40fd34)
1 /*	$OpenBSD: ipsecctl.c,v 1.82 2017/04/19 15:59:38 bluhm Exp $	*/
2 /*
3  * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/socket.h>
19 #include <sys/sysctl.h>
20 #include <sys/queue.h>
21 #include <sys/stat.h>
22 #include <net/pfkeyv2.h>
23 #include <net/route.h>
24 #include <netinet/in.h>
25 #include <netinet/ip_ipsp.h>
26 #include <arpa/inet.h>
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <netdb.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include "ipsecctl.h"
38 #include "pfkey.h"
39 
40 int		 ipsecctl_rules(char *, int);
41 FILE		*ipsecctl_fopen(const char *, const char *);
42 int		 ipsecctl_commit(int, struct ipsecctl *);
43 int		 ipsecctl_add_rule(struct ipsecctl *, struct ipsec_rule *);
44 void		 ipsecctl_free_rule(struct ipsec_rule *);
45 void		 ipsecctl_print_addr(struct ipsec_addr_wrap *);
46 void		 ipsecctl_print_proto(u_int8_t);
47 void		 ipsecctl_print_port(u_int16_t, const char *);
48 void		 ipsecctl_print_key(struct ipsec_key *);
49 void		 ipsecctl_print_flow(struct ipsec_rule *, int);
50 void		 ipsecctl_print_sa(struct ipsec_rule *, int);
51 void		 ipsecctl_print_sabundle(struct ipsec_rule *, int);
52 int		 ipsecctl_flush(int);
53 void		 ipsecctl_get_rules(struct ipsecctl *);
54 void		 ipsecctl_print_title(char *);
55 void		 ipsecctl_show_flows(int);
56 void		 ipsecctl_show_sas(int);
57 int		 ipsecctl_monitor(int);
58 void		 usage(void);
59 const char	*ipsecctl_lookup_option(char *, const char **);
60 static int	 unmask(struct ipsec_addr *, sa_family_t);
61 int		 sacompare(const void *, const void *);
62 
63 const char	*showopt;
64 char		*isakmpd_fifo = "/var/run/isakmpd.fifo";
65 
66 int		 first_title = 1;
67 
68 static const char *showopt_list[] = {
69 	"flow", "sa", "all", NULL
70 };
71 
72 static const char *direction[] = {"?", "in", "out"};
73 static const char *flowtype[] = {"?", "use", "acquire", "require", "deny",
74     "bypass", "dontacq"};
75 static const char *satype[] = {"?", "esp", "ah", "ipcomp", "tcpmd5", "ipip"};
76 static const char *tmode[] = {"?", "transport", "tunnel"};
77 static const char *auth[] = {"?", "psk", "rsa"};
78 
79 struct sad {
80 	struct sadb_msg	*sad_msg;
81 	u_int32_t	 sad_spi;
82 };
83 
84 int
85 sacompare(const void *va, const void *vb)
86 {
87 	const struct sad *a = va, *b = vb;
88 
89 	if (a->sad_spi < b->sad_spi)
90 		return (-1);
91 	if (a->sad_spi > b->sad_spi)
92 		return (1);
93 	return (0);
94 }
95 
96 int
97 ipsecctl_rules(char *filename, int opts)
98 {
99 	struct ipsecctl		 ipsec;
100 	struct ipsec_rule	*rp;
101 	int			 action, error = 0;
102 
103 	bzero(&ipsec, sizeof(ipsec));
104 	ipsec.opts = opts;
105 	TAILQ_INIT(&ipsec.rule_queue);
106 	TAILQ_INIT(&ipsec.bundle_queue);
107 
108 	if (parse_rules(filename, &ipsec) < 0) {
109 		warnx("Syntax error in config file: ipsec rules not loaded");
110 		error = 1;
111 	} else {
112 		if (opts & IPSECCTL_OPT_DELETE)
113 			action = ACTION_DELETE;
114 		else
115 			action = ACTION_ADD;
116 
117 		if ((opts & IPSECCTL_OPT_NOACTION) == 0)
118 			error = ipsecctl_commit(action, &ipsec);
119 
120 	}
121 
122 	/* This also frees the rules in ipsec.bundle_queue. */
123 	while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
124 		TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
125 		ipsecctl_free_rule(rp);
126 	}
127 
128 	return (error);
129 }
130 
131 FILE *
132 ipsecctl_fopen(const char *name, const char *mode)
133 {
134 	struct stat	 st;
135 	FILE		*fp;
136 
137 	fp = fopen(name, mode);
138 	if (fp == NULL)
139 		return (NULL);
140 
141 	if (fstat(fileno(fp), &st)) {
142 		fclose(fp);
143 		return (NULL);
144 	}
145 	if (S_ISDIR(st.st_mode)) {
146 		fclose(fp);
147 		errno = EISDIR;
148 		return (NULL);
149 	}
150 	return (fp);
151 }
152 
153 int
154 ipsecctl_commit(int action, struct ipsecctl *ipsec)
155 {
156 	struct ipsec_rule	*rp;
157 	int			 ret = 0;
158 
159 	if (pfkey_init() == -1)
160 		errx(1, "ipsecctl_commit: failed to open PF_KEY socket");
161 
162 	TAILQ_FOREACH(rp, &ipsec->rule_queue, rule_entry) {
163 		if (rp->type & RULE_IKE) {
164 			if (ike_ipsec_establish(action, rp, isakmpd_fifo) ==
165 			    -1) {
166 				warnx("failed to %s ike rule %d",
167 				    action == ACTION_DELETE ? "delete" : "add",
168 				    rp->nr);
169 				ret = 2;
170 			}
171 		} else {
172 			if (pfkey_ipsec_establish(action, rp) == -1) {
173 				warnx("failed to %s rule %d",
174 				    action == ACTION_DELETE ? "delete" : "add",
175 				    rp->nr);
176 				ret = 2;
177 			}
178 		}
179 	}
180 
181 	return (ret);
182 }
183 
184 int
185 ipsecctl_add_rule(struct ipsecctl *ipsec, struct ipsec_rule *r)
186 {
187 	TAILQ_INSERT_TAIL(&ipsec->rule_queue, r, rule_entry);
188 
189 	if ((ipsec->opts & IPSECCTL_OPT_VERBOSE) && !(ipsec->opts &
190 	    IPSECCTL_OPT_SHOW))
191 		ipsecctl_print_rule(r, ipsec->opts);
192 
193 	return (0);
194 }
195 
196 void
197 ipsecctl_free_rule(struct ipsec_rule *rp)
198 {
199 	if (rp->src) {
200 		free(rp->src->name);
201 		free(rp->src);
202 	}
203 	if (rp->dst) {
204 		free(rp->dst->name);
205 		free(rp->dst);
206 	}
207 	if (rp->dst2) {
208 		free(rp->dst2->name);
209 		free(rp->dst2);
210 	}
211 	if (rp->local) {
212 		free(rp->local->name);
213 		free(rp->local);
214 	}
215 	if (rp->peer) {
216 		free(rp->peer->name);
217 		free(rp->peer);
218 	}
219 	if (rp->auth) {
220 		free(rp->auth->srcid);
221 		free(rp->auth->dstid);
222 		free(rp->auth);
223 	}
224 	if (rp->ikeauth) {
225 		free(rp->ikeauth->string);
226 		free(rp->ikeauth);
227 	}
228 	free(rp->xfs);
229 	free(rp->p1xfs);
230 	free(rp->p2xfs);
231 	free(rp->p1life);
232 	free(rp->p2life);
233 	if (rp->authkey) {
234 		free(rp->authkey->data);
235 		free(rp->authkey);
236 	}
237 	if (rp->enckey) {
238 		free(rp->enckey->data);
239 		free(rp->enckey);
240 	}
241 	free(rp->p1name);
242 	free(rp->p2name);
243 	free(rp->p2lid);
244 	free(rp->p2nid);
245 	free(rp->p2rid);
246 	free(rp);
247 }
248 
249 void
250 ipsecctl_print_addr(struct ipsec_addr_wrap *ipa)
251 {
252 	int		bits;
253 	char		buf[NI_MAXHOST];
254 
255 	if (ipa == NULL) {
256 		printf("?");
257 		return;
258 	}
259 	if (inet_ntop(ipa->af, &ipa->address, buf, sizeof(buf)) == NULL)
260 		printf("?");
261 	else
262 		printf("%s", buf);
263 
264 	bits = unmask(&ipa->mask, ipa->af);
265 	if (bits != (ipa->af == AF_INET ? 32 : 128))
266 		printf("/%d", bits);
267 }
268 
269 void
270 ipsecctl_print_proto(u_int8_t proto)
271 {
272 	struct protoent *p;
273 
274 	if ((p = getprotobynumber(proto)) != NULL)
275 		printf("%s", p->p_name);
276 	else
277 		printf("%u", proto);
278 }
279 
280 void
281 ipsecctl_print_port(u_int16_t port, const char *proto)
282 {
283 	struct servent *s;
284 
285 	if ((s = getservbyport(port, proto)) != NULL)
286 		printf("%s", s->s_name);
287 	else
288 		printf("%u", ntohs(port));
289 }
290 
291 void
292 ipsecctl_print_key(struct ipsec_key *key)
293 {
294 	int	i;
295 
296 	for (i = 0; i < (int)key->len; i++)
297 		printf("%02x", key->data[i]);
298 }
299 
300 void
301 ipsecctl_print_flow(struct ipsec_rule *r, int opts)
302 {
303 	printf("flow %s %s", satype[r->satype], direction[r->direction]);
304 
305 	if (r->proto) {
306 		printf(" proto ");
307 		ipsecctl_print_proto(r->proto);
308 	}
309 	printf(" from ");
310 	ipsecctl_print_addr(r->src);
311 	if (r->sport) {
312 		printf(" port ");
313 		ipsecctl_print_port(r->sport,
314 		    r->proto == IPPROTO_TCP ? "tcp" : "udp");
315 	}
316 	printf(" to ");
317 	ipsecctl_print_addr(r->dst);
318 	if (r->dport) {
319 		printf(" port ");
320 		ipsecctl_print_port(r->dport,
321 		    r->proto == IPPROTO_TCP ? "tcp" : "udp");
322 	}
323 	if (r->local) {
324 		printf(" local ");
325 		ipsecctl_print_addr(r->local);
326 	}
327 	if (r->peer) {
328 		printf(" peer ");
329 		ipsecctl_print_addr(r->peer);
330 	}
331 	if (r->auth) {
332 		if (r->auth->srcid)
333 			printf(" srcid %s", r->auth->srcid);
334 		if (r->auth->dstid)
335 			printf(" dstid %s", r->auth->dstid);
336 		if (r->auth->type > 0)
337 			printf(" %s", auth[r->auth->type]);
338 	}
339 	printf(" type %s", flowtype[r->flowtype]);
340 	printf("\n");
341 }
342 
343 /* ARGSUSED1 */
344 void
345 ipsecctl_print_sa(struct ipsec_rule *r, int opts)
346 {
347 	printf("%s ", satype[r->satype]);
348 	/* tunnel/transport is only meaningful for esp/ah/ipcomp */
349 	if (r->satype != IPSEC_TCPMD5 && r->satype != IPSEC_IPIP)
350 		printf("%s ", tmode[r->tmode]);
351 	printf("from ");
352 	ipsecctl_print_addr(r->src);
353 	printf(" to ");
354 	ipsecctl_print_addr(r->dst);
355 	printf(" spi 0x%08x", r->spi);
356 
357 	if (r->satype != IPSEC_TCPMD5) {
358 		if (r->xfs && r->xfs->authxf)
359 			printf(" auth %s", r->xfs->authxf->name);
360 		if (r->xfs && r->xfs->encxf)
361 			printf(" enc %s", r->xfs->encxf->name);
362 		if (r->xfs && r->xfs->compxf)
363 			printf(" comp %s", r->xfs->compxf->name);
364 	}
365 	if (r->authkey && (opts & IPSECCTL_OPT_SHOWKEY)) {
366 		if (r->satype == IPSEC_TCPMD5)
367 			printf(" ");
368 		else
369 			printf(" \\\n\t");
370 		printf("authkey 0x");
371 		ipsecctl_print_key(r->authkey);
372 	}
373 	if (r->enckey && (opts & IPSECCTL_OPT_SHOWKEY)) {
374 		if (r->satype == IPSEC_TCPMD5)
375 			printf(" ");
376 		else
377 			printf(" \\\n\t");
378 		printf("enckey 0x");
379 		ipsecctl_print_key(r->enckey);
380 	}
381 	printf("\n");
382 }
383 
384 void
385 ipsecctl_print_sabundle(struct ipsec_rule *r, int opts)
386 {
387 	printf("[bundle %s to ", satype[r->proto]);
388 	ipsecctl_print_addr(r->dst);
389 	printf(" spi 0x%08x with %s to ", r->spi, satype[r->proto2]);
390 	ipsecctl_print_addr(r->dst2);
391 	printf(" spi 0x%08x", r->spi2);
392 
393 	printf("]\n");
394 }
395 
396 void
397 ipsecctl_print_rule(struct ipsec_rule *r, int opts)
398 {
399 	if (opts & IPSECCTL_OPT_VERBOSE2)
400 		printf("@%d ", r->nr);
401 
402 	if (r->type & RULE_FLOW)
403 		ipsecctl_print_flow(r, opts);
404 	if (r->type & RULE_SA)
405 		ipsecctl_print_sa(r, opts);
406 	if (r->type & RULE_IKE)
407 		ike_print_config(r, opts);
408 	if (r->type & RULE_BUNDLE)
409 		ipsecctl_print_sabundle(r, opts);
410 }
411 
412 int
413 ipsecctl_flush(int opts)
414 {
415 	if (opts & IPSECCTL_OPT_NOACTION)
416 		return (0);
417 
418 	if (pfkey_init() == -1)
419 		errx(1, "ipsecctl_flush: failed to open PF_KEY socket");
420 
421 	if (pfkey_ipsec_flush() == -1)
422 		errx(1, "ipsecctl_flush: failed to flush");
423 
424 	return (0);
425 }
426 
427 void
428 ipsecctl_get_rules(struct ipsecctl *ipsec)
429 {
430 	struct sadb_msg *msg;
431 	struct ipsec_rule *rule;
432 	int		 mib[4];
433 	size_t		 need;
434 	char		*buf, *lim, *next;
435 
436 	mib[0] = CTL_NET;
437 	mib[1] = PF_KEY;
438 	mib[2] = PF_KEY_V2;
439 	mib[3] = NET_KEY_SPD_DUMP;
440 
441 	if (sysctl(mib, 4, NULL, &need, NULL, 0) == -1)
442 		err(1, "ipsecctl_get_rules: sysctl");
443 	if (need == 0)
444 		return;
445 	if ((buf = malloc(need)) == NULL)
446 		err(1, "ipsecctl_get_rules: malloc");
447 	if (sysctl(mib, 4, buf, &need, NULL, 0) == -1)
448 		err(1, "ipsecctl_get_rules: sysctl");
449 	lim = buf + need;
450 
451 	for (next = buf; next < lim; next += msg->sadb_msg_len *
452 	    PFKEYV2_CHUNK) {
453 		msg = (struct sadb_msg *)next;
454 		if (msg->sadb_msg_len == 0)
455 			break;
456 
457 		rule = calloc(1, sizeof(struct ipsec_rule));
458 		if (rule == NULL)
459 			err(1, "ipsecctl_get_rules: calloc");
460 		rule->nr = ipsec->rule_nr++;
461 		rule->type |= RULE_FLOW;
462 
463 		if (pfkey_parse(msg, rule))
464 			errx(1, "ipsecctl_get_rules: "
465 			    "failed to parse PF_KEY message");
466 
467 		ipsecctl_add_rule(ipsec, rule);
468 	}
469 
470 	free(buf);
471 }
472 
473 void
474 ipsecctl_print_title(char *title)
475 {
476 	if (!first_title)
477 		printf("\n");
478 	first_title = 0;
479 	printf("%s\n", title);
480 }
481 
482 void
483 ipsecctl_show_flows(int opts)
484 {
485 	struct ipsecctl ipsec;
486 	struct ipsec_rule *rp;
487 
488 	bzero(&ipsec, sizeof(ipsec));
489 	ipsec.opts = opts;
490 	TAILQ_INIT(&ipsec.rule_queue);
491 
492 	ipsecctl_get_rules(&ipsec);
493 
494 	if (opts & IPSECCTL_OPT_SHOWALL)
495 		ipsecctl_print_title("FLOWS:");
496 
497 	if (TAILQ_FIRST(&ipsec.rule_queue) == 0) {
498 		if (opts & IPSECCTL_OPT_SHOWALL)
499 			printf("No flows\n");
500 		return;
501 	}
502 
503 	while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
504 		TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
505 
506 		ipsecctl_print_rule(rp, ipsec.opts);
507 
508 		free(rp->src->name);
509 		free(rp->src);
510 		free(rp->dst->name);
511 		free(rp->dst);
512 		if (rp->local) {
513 			free(rp->local->name);
514 			free(rp->local);
515 		}
516 		if (rp->peer) {
517 			free(rp->peer->name);
518 			free(rp->peer);
519 		}
520 		if (rp->auth) {
521 			free(rp->auth->srcid);
522 			free(rp->auth->dstid);
523 			free(rp->auth);
524 		}
525 		free(rp);
526 	}
527 }
528 
529 void
530 ipsecctl_show_sas(int opts)
531 {
532 	struct sadb_msg *msg;
533 	struct sad	*sad;
534 	int		 mib[5], sacount, i;
535 	size_t		 need = 0;
536 	char		*buf, *lim, *next;
537 
538 	mib[0] = CTL_NET;
539 	mib[1] = PF_KEY;
540 	mib[2] = PF_KEY_V2;
541 	mib[3] = NET_KEY_SADB_DUMP;
542 	mib[4] = SADB_SATYPE_UNSPEC;
543 
544 	if (opts & IPSECCTL_OPT_SHOWALL)
545 		ipsecctl_print_title("SAD:");
546 
547 	/* When the SAD is empty we get ENOENT, no need to err(). */
548 	if (sysctl(mib, 5, NULL, &need, NULL, 0) == -1 && errno != ENOENT)
549 		err(1, "ipsecctl_show_sas: sysctl");
550 	if (need == 0) {
551 		if (opts & IPSECCTL_OPT_SHOWALL)
552 			printf("No entries\n");
553 		return;
554 	}
555 	if ((buf = malloc(need)) == NULL)
556 		err(1, "ipsecctl_show_sas: malloc");
557 	if (sysctl(mib, 5, buf, &need, NULL, 0) == -1)
558 		err(1, "ipsecctl_show_sas: sysctl");
559 	sacount = 0;
560 	lim = buf + need;
561 	for (next = buf; next < lim;
562 	    next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
563 		msg = (struct sadb_msg *)next;
564 		if (msg->sadb_msg_len == 0)
565 			break;
566 		sacount++;
567 	}
568 	if ((sad = calloc(sacount, sizeof(*sad))) == NULL)
569 		err(1, "ipsecctl_show_sas: calloc");
570 	i = 0;
571 	for (next = buf; next < lim;
572 	    next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
573 		msg = (struct sadb_msg *)next;
574 		if (msg->sadb_msg_len == 0)
575 			break;
576 		sad[i].sad_spi = pfkey_get_spi(msg);
577 		sad[i].sad_msg = msg;
578 		i++;
579 	}
580 	qsort(sad, sacount, sizeof(*sad), sacompare);
581 	for (i = 0; i < sacount; i++)
582 		pfkey_print_sa(sad[i].sad_msg, opts);
583 	free(sad);
584 	free(buf);
585 }
586 
587 int
588 ipsecctl_monitor(int opts)
589 {
590 	return (pfkey_monitor(opts));
591 }
592 
593 __dead void
594 usage(void)
595 {
596 	extern char	*__progname;
597 
598 	fprintf(stderr, "usage: %s [-dFkmnv] [-D macro=value] [-f file]"
599 	    " [-i fifo] [-s modifier]\n", __progname);
600 	exit(1);
601 }
602 
603 const char *
604 ipsecctl_lookup_option(char *cmd, const char **list)
605 {
606 	if (cmd != NULL && *cmd)
607 		for (; *list; list++)
608 			if (!strncmp(cmd, *list, strlen(cmd)))
609 				return (*list);
610 	return (NULL);
611 }
612 
613 int
614 main(int argc, char *argv[])
615 {
616 	int		 error = 0;
617 	int		 ch;
618 	int		 opts = 0;
619 	char		*rulesopt = NULL;
620 
621 	if (argc < 2)
622 		usage();
623 
624 	while ((ch = getopt(argc, argv, "D:df:Fi:kmnvs:")) != -1) {
625 		switch (ch) {
626 		case 'D':
627 			if (cmdline_symset(optarg) < 0)
628 				warnx("could not parse macro definition %s",
629 				    optarg);
630 			break;
631 
632 		case 'd':
633 			opts |= IPSECCTL_OPT_DELETE;
634 			break;
635 
636 		case 'f':
637 			rulesopt = optarg;
638 			break;
639 
640 		case 'F':
641 			opts |= IPSECCTL_OPT_FLUSH;
642 			break;
643 
644 		case 'i':
645 			isakmpd_fifo = optarg;
646 			break;
647 
648 		case 'k':
649 			opts |= IPSECCTL_OPT_SHOWKEY;
650 			break;
651 
652 		case 'm':
653 			opts |= IPSECCTL_OPT_MONITOR;
654 			break;
655 
656 		case 'n':
657 			opts |= IPSECCTL_OPT_NOACTION;
658 			break;
659 
660 		case 'v':
661 			if (opts & IPSECCTL_OPT_VERBOSE)
662 				opts |= IPSECCTL_OPT_VERBOSE2;
663 			opts |= IPSECCTL_OPT_VERBOSE;
664 			break;
665 
666 		case 's':
667 			showopt = ipsecctl_lookup_option(optarg, showopt_list);
668 			if (showopt == NULL) {
669 				warnx("Unknown show modifier '%s'", optarg);
670 				usage();
671 				/* NOTREACHED */
672 			}
673 			opts |= IPSECCTL_OPT_SHOW;
674 			break;
675 
676 		default:
677 			usage();
678 			/* NOTREACHED */
679 		}
680 	}
681 
682 	if (argc != optind) {
683 		warnx("unknown command line argument: %s ...", argv[optind]);
684 		usage();
685 		/* NOTREACHED */
686 	}
687 	if (opts & IPSECCTL_OPT_FLUSH)
688 		if (ipsecctl_flush(opts))
689 			error = 1;
690 
691 	if (rulesopt != NULL)
692 		if (ipsecctl_rules(rulesopt, opts))
693 			error = 1;
694 
695 	if (showopt != NULL) {
696 		switch (*showopt) {
697 		case 'f':
698 			ipsecctl_show_flows(opts);
699 			break;
700 		case 's':
701 			ipsecctl_show_sas(opts);
702 			break;
703 		case 'a':
704 			opts |= IPSECCTL_OPT_SHOWALL;
705 			ipsecctl_show_flows(opts);
706 			ipsecctl_show_sas(opts);
707 		}
708 	}
709 
710 	if (opts & IPSECCTL_OPT_MONITOR)
711 		if (ipsecctl_monitor(opts))
712 			error = 1;
713 
714 	exit(error);
715 }
716 
717 /* ARGSUSED1 */
718 static int
719 unmask(struct ipsec_addr *ipa, sa_family_t af)
720 {
721 	int		i = 31, j = 0, b = 0;
722 	u_int32_t	tmp;
723 
724 	while (j < 4 && ipa->addr32[j] == 0xffffffff) {
725 		b += 32;
726 		j++;
727 	}
728 	if (j < 4) {
729 		tmp = ntohl(ipa->addr32[j]);
730 		for (i = 31; tmp & (1 << i); --i)
731 			b++;
732 	}
733 	return (b);
734 }
735