GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ipsecctl/ipsecctl.c Lines: 0 360 0.0 %
Date: 2016-12-06 Branches: 0 259 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ipsecctl.c,v 1.80 2015/12/10 17:27:00 mmcc 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_sagroup(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.group_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.group_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_sagroup(struct ipsec_rule *r, int opts)
386
{
387
	if (!(opts & IPSECCTL_OPT_VERBOSE2))
388
		return;
389
390
	printf("[group %s to ", satype[r->proto]);
391
	ipsecctl_print_addr(r->dst);
392
	printf(" spi 0x%08x with %s to ", r->spi, satype[r->proto2]);
393
	ipsecctl_print_addr(r->dst2);
394
	printf(" spi 0x%08x", r->spi2);
395
396
	printf("]\n");
397
}
398
399
void
400
ipsecctl_print_rule(struct ipsec_rule *r, int opts)
401
{
402
	if (opts & IPSECCTL_OPT_VERBOSE2)
403
		printf("@%d ", r->nr);
404
405
	if (r->type & RULE_FLOW)
406
		ipsecctl_print_flow(r, opts);
407
	if (r->type & RULE_SA)
408
		ipsecctl_print_sa(r, opts);
409
	if (r->type & RULE_IKE)
410
		ike_print_config(r, opts);
411
	if (r->type & RULE_GROUP)
412
		ipsecctl_print_sagroup(r, opts);
413
}
414
415
int
416
ipsecctl_flush(int opts)
417
{
418
	if (opts & IPSECCTL_OPT_NOACTION)
419
		return (0);
420
421
	if (pfkey_init() == -1)
422
		errx(1, "ipsecctl_flush: failed to open PF_KEY socket");
423
424
	if (pfkey_ipsec_flush() == -1)
425
		errx(1, "ipsecctl_flush: failed to flush");
426
427
	return (0);
428
}
429
430
void
431
ipsecctl_get_rules(struct ipsecctl *ipsec)
432
{
433
	struct sadb_msg *msg;
434
	struct ipsec_rule *rule;
435
	int		 mib[4];
436
	size_t		 need;
437
	char		*buf, *lim, *next;
438
439
	mib[0] = CTL_NET;
440
	mib[1] = PF_KEY;
441
	mib[2] = PF_KEY_V2;
442
	mib[3] = NET_KEY_SPD_DUMP;
443
444
	if (sysctl(mib, 4, NULL, &need, NULL, 0) == -1)
445
		err(1, "ipsecctl_get_rules: sysctl");
446
	if (need == 0)
447
		return;
448
	if ((buf = malloc(need)) == NULL)
449
		err(1, "ipsecctl_get_rules: malloc");
450
	if (sysctl(mib, 4, buf, &need, NULL, 0) == -1)
451
		err(1, "ipsecctl_get_rules: sysctl");
452
	lim = buf + need;
453
454
	for (next = buf; next < lim; next += msg->sadb_msg_len *
455
	    PFKEYV2_CHUNK) {
456
		msg = (struct sadb_msg *)next;
457
		if (msg->sadb_msg_len == 0)
458
			break;
459
460
		rule = calloc(1, sizeof(struct ipsec_rule));
461
		if (rule == NULL)
462
			err(1, "ipsecctl_get_rules: calloc");
463
		rule->nr = ipsec->rule_nr++;
464
		rule->type |= RULE_FLOW;
465
466
		if (pfkey_parse(msg, rule))
467
			errx(1, "ipsecctl_get_rules: "
468
			    "failed to parse PF_KEY message");
469
470
		ipsecctl_add_rule(ipsec, rule);
471
	}
472
473
	free(buf);
474
}
475
476
void
477
ipsecctl_print_title(char *title)
478
{
479
	if (!first_title)
480
		printf("\n");
481
	first_title = 0;
482
	printf("%s\n", title);
483
}
484
485
void
486
ipsecctl_show_flows(int opts)
487
{
488
	struct ipsecctl ipsec;
489
	struct ipsec_rule *rp;
490
491
	bzero(&ipsec, sizeof(ipsec));
492
	ipsec.opts = opts;
493
	TAILQ_INIT(&ipsec.rule_queue);
494
495
	ipsecctl_get_rules(&ipsec);
496
497
	if (opts & IPSECCTL_OPT_SHOWALL)
498
		ipsecctl_print_title("FLOWS:");
499
500
	if (TAILQ_FIRST(&ipsec.rule_queue) == 0) {
501
		if (opts & IPSECCTL_OPT_SHOWALL)
502
			printf("No flows\n");
503
		return;
504
	}
505
506
	while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
507
		TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
508
509
		ipsecctl_print_rule(rp, ipsec.opts);
510
511
		free(rp->src->name);
512
		free(rp->src);
513
		free(rp->dst->name);
514
		free(rp->dst);
515
		if (rp->local) {
516
			free(rp->local->name);
517
			free(rp->local);
518
		}
519
		if (rp->peer) {
520
			free(rp->peer->name);
521
			free(rp->peer);
522
		}
523
		if (rp->auth) {
524
			free(rp->auth->srcid);
525
			free(rp->auth->dstid);
526
			free(rp->auth);
527
		}
528
		free(rp);
529
	}
530
}
531
532
void
533
ipsecctl_show_sas(int opts)
534
{
535
	struct sadb_msg *msg;
536
	struct sad	*sad;
537
	int		 mib[5], sacount, i;
538
	size_t		 need = 0;
539
	char		*buf, *lim, *next;
540
541
	mib[0] = CTL_NET;
542
	mib[1] = PF_KEY;
543
	mib[2] = PF_KEY_V2;
544
	mib[3] = NET_KEY_SADB_DUMP;
545
	mib[4] = SADB_SATYPE_UNSPEC;
546
547
	if (opts & IPSECCTL_OPT_SHOWALL)
548
		ipsecctl_print_title("SAD:");
549
550
	/* When the SAD is empty we get ENOENT, no need to err(). */
551
	if (sysctl(mib, 5, NULL, &need, NULL, 0) == -1 && errno != ENOENT)
552
		err(1, "ipsecctl_show_sas: sysctl");
553
	if (need == 0) {
554
		if (opts & IPSECCTL_OPT_SHOWALL)
555
			printf("No entries\n");
556
		return;
557
	}
558
	if ((buf = malloc(need)) == NULL)
559
		err(1, "ipsecctl_show_sas: malloc");
560
	if (sysctl(mib, 5, buf, &need, NULL, 0) == -1)
561
		err(1, "ipsecctl_show_sas: sysctl");
562
	sacount = 0;
563
	lim = buf + need;
564
	for (next = buf; next < lim;
565
	    next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
566
		msg = (struct sadb_msg *)next;
567
		if (msg->sadb_msg_len == 0)
568
			break;
569
		sacount++;
570
	}
571
	if ((sad = calloc(sacount, sizeof(*sad))) == NULL)
572
		err(1, "ipsecctl_show_sas: calloc");
573
	i = 0;
574
	for (next = buf; next < lim;
575
	    next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
576
		msg = (struct sadb_msg *)next;
577
		if (msg->sadb_msg_len == 0)
578
			break;
579
		sad[i].sad_spi = pfkey_get_spi(msg);
580
		sad[i].sad_msg = msg;
581
		i++;
582
	}
583
	qsort(sad, sacount, sizeof(*sad), sacompare);
584
	for (i = 0; i < sacount; i++)
585
		pfkey_print_sa(sad[i].sad_msg, opts);
586
	free(sad);
587
	free(buf);
588
}
589
590
int
591
ipsecctl_monitor(int opts)
592
{
593
	return (pfkey_monitor(opts));
594
}
595
596
__dead void
597
usage(void)
598
{
599
	extern char	*__progname;
600
601
	fprintf(stderr, "usage: %s [-dFkmnv] [-D macro=value] [-f file]"
602
	    " [-i fifo] [-s modifier]\n", __progname);
603
	exit(1);
604
}
605
606
const char *
607
ipsecctl_lookup_option(char *cmd, const char **list)
608
{
609
	if (cmd != NULL && *cmd)
610
		for (; *list; list++)
611
			if (!strncmp(cmd, *list, strlen(cmd)))
612
				return (*list);
613
	return (NULL);
614
}
615
616
int
617
main(int argc, char *argv[])
618
{
619
	int		 error = 0;
620
	int		 ch;
621
	int		 opts = 0;
622
	char		*rulesopt = NULL;
623
624
	if (argc < 2)
625
		usage();
626
627
	while ((ch = getopt(argc, argv, "D:df:Fi:kmnvs:")) != -1) {
628
		switch (ch) {
629
		case 'D':
630
			if (cmdline_symset(optarg) < 0)
631
				warnx("could not parse macro definition %s",
632
				    optarg);
633
			break;
634
635
		case 'd':
636
			opts |= IPSECCTL_OPT_DELETE;
637
			break;
638
639
		case 'f':
640
			rulesopt = optarg;
641
			break;
642
643
		case 'F':
644
			opts |= IPSECCTL_OPT_FLUSH;
645
			break;
646
647
		case 'i':
648
			isakmpd_fifo = optarg;
649
			break;
650
651
		case 'k':
652
			opts |= IPSECCTL_OPT_SHOWKEY;
653
			break;
654
655
		case 'm':
656
			opts |= IPSECCTL_OPT_MONITOR;
657
			break;
658
659
		case 'n':
660
			opts |= IPSECCTL_OPT_NOACTION;
661
			break;
662
663
		case 'v':
664
			if (opts & IPSECCTL_OPT_VERBOSE)
665
				opts |= IPSECCTL_OPT_VERBOSE2;
666
			opts |= IPSECCTL_OPT_VERBOSE;
667
			break;
668
669
		case 's':
670
			showopt = ipsecctl_lookup_option(optarg, showopt_list);
671
			if (showopt == NULL) {
672
				warnx("Unknown show modifier '%s'", optarg);
673
				usage();
674
				/* NOTREACHED */
675
			}
676
			opts |= IPSECCTL_OPT_SHOW;
677
			break;
678
679
		default:
680
			usage();
681
			/* NOTREACHED */
682
		}
683
	}
684
685
	if (argc != optind) {
686
		warnx("unknown command line argument: %s ...", argv[optind]);
687
		usage();
688
		/* NOTREACHED */
689
	}
690
	if (opts & IPSECCTL_OPT_FLUSH)
691
		if (ipsecctl_flush(opts))
692
			error = 1;
693
694
	if (rulesopt != NULL)
695
		if (ipsecctl_rules(rulesopt, opts))
696
			error = 1;
697
698
	if (showopt != NULL) {
699
		switch (*showopt) {
700
		case 'f':
701
			ipsecctl_show_flows(opts);
702
			break;
703
		case 's':
704
			ipsecctl_show_sas(opts);
705
			break;
706
		case 'a':
707
			opts |= IPSECCTL_OPT_SHOWALL;
708
			ipsecctl_show_flows(opts);
709
			ipsecctl_show_sas(opts);
710
		}
711
	}
712
713
	if (opts & IPSECCTL_OPT_MONITOR)
714
		if (ipsecctl_monitor(opts))
715
			error = 1;
716
717
	exit(error);
718
}
719
720
/* ARGSUSED1 */
721
static int
722
unmask(struct ipsec_addr *ipa, sa_family_t af)
723
{
724
	int		i = 31, j = 0, b = 0;
725
	u_int32_t	tmp;
726
727
	while (j < 4 && ipa->addr32[j] == 0xffffffff) {
728
		b += 32;
729
		j++;
730
	}
731
	if (j < 4) {
732
		tmp = ntohl(ipa->addr32[j]);
733
		for (i = 31; tmp & (1 << i); --i)
734
			b++;
735
	}
736
	return (b);
737
}