1 /* $OpenBSD: ipsecctl.c,v 1.88 2024/02/06 05:39:28 yasuoka 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 <assert.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <netdb.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "ipsecctl.h"
39 #include "pfkey.h"
40
41 int ipsecctl_rules(char *, int);
42 FILE *ipsecctl_fopen(const char *, const char *);
43 int ipsecctl_commit(int, struct ipsecctl *);
44 int ipsecctl_add_rule(struct ipsecctl *, struct ipsec_rule *);
45 void ipsecctl_free_rule(struct ipsec_rule *);
46 int ipsecctl_merge_rules(struct ipsec_rule *, struct ipsec_rule *);
47 int ipsecctl_cmp_ident(struct ipsec_rule *, struct ipsec_rule *);
48 int ipsecctl_rule_matchsrc(struct ipsec_rule *,
49 struct ipsec_addr_wrap *);
50 int ipsecctl_rule_matchdst(struct ipsec_rule *,
51 struct ipsec_addr_wrap *);
52 void ipsecctl_print_addr(struct ipsec_addr_wrap *);
53 void ipsecctl_print_proto(u_int8_t);
54 void ipsecctl_print_port(u_int16_t, const char *);
55 void ipsecctl_print_key(struct ipsec_key *);
56 void ipsecctl_print_flow(struct ipsec_rule *, int);
57 void ipsecctl_print_sa(struct ipsec_rule *, int);
58 void ipsecctl_print_sabundle(struct ipsec_rule *, int);
59 int ipsecctl_flush(int);
60 char *ipsecctl_get_rules(struct ipsecctl *, size_t *);
61 void ipsecctl_parse_rules(struct ipsecctl *, char *, size_t);
62 void ipsecctl_print_title(char *);
63 void ipsecctl_show(int);
64 int ipsecctl_monitor(int);
65 void usage(void);
66 const char *ipsecctl_lookup_option(char *, const char **);
67 static int unmask(struct ipsec_addr *);
68 int sacompare(const void *, const void *);
69
70 const char *showopt;
71 char *isakmpd_fifo = "/var/run/isakmpd.fifo";
72
73 int first_title = 1;
74
75 static const char *showopt_list[] = {
76 "flow", "sa", "all", NULL
77 };
78
79 static const char *direction[] = {"?", "in", "out"};
80 static const char *flowtype[] = {"?", "use", "acquire", "require", "deny",
81 "bypass", "dontacq"};
82 static const char *satype[] = {"?", "esp", "ah", "ipcomp", "tcpmd5", "ipip"};
83 static const char *tmode[] = {"?", "transport", "tunnel"};
84 static const char *auth[] = {"?", "psk", "rsa"};
85
86 struct sad {
87 struct sadb_msg *sad_msg;
88 u_int32_t sad_spi;
89 };
90
91 int
sacompare(const void * va,const void * vb)92 sacompare(const void *va, const void *vb)
93 {
94 const struct sad *a = va, *b = vb;
95
96 if (a->sad_spi < b->sad_spi)
97 return (-1);
98 if (a->sad_spi > b->sad_spi)
99 return (1);
100 return (0);
101 }
102
103 int
ipsecctl_rules(char * filename,int opts)104 ipsecctl_rules(char *filename, int opts)
105 {
106 struct ipsecctl ipsec;
107 struct ipsec_rule *rp;
108 int action, error = 0;
109
110 bzero(&ipsec, sizeof(ipsec));
111 ipsec.opts = opts;
112 TAILQ_INIT(&ipsec.rule_queue);
113 TAILQ_INIT(&ipsec.bundle_queue);
114
115 if (parse_rules(filename, &ipsec) < 0) {
116 warnx("Syntax error in config file: ipsec rules not loaded");
117 error = 1;
118 } else {
119 if (opts & IPSECCTL_OPT_DELETE)
120 action = ACTION_DELETE;
121 else
122 action = ACTION_ADD;
123
124 if ((opts & IPSECCTL_OPT_NOACTION) == 0)
125 error = ipsecctl_commit(action, &ipsec);
126
127 }
128
129 /* This also frees the rules in ipsec.bundle_queue. */
130 while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
131 TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
132 ipsecctl_free_rule(rp);
133 }
134
135 return (error);
136 }
137
138 FILE *
ipsecctl_fopen(const char * name,const char * mode)139 ipsecctl_fopen(const char *name, const char *mode)
140 {
141 struct stat st;
142 FILE *fp;
143
144 fp = fopen(name, mode);
145 if (fp == NULL)
146 return (NULL);
147
148 if (fstat(fileno(fp), &st)) {
149 fclose(fp);
150 return (NULL);
151 }
152 if (S_ISDIR(st.st_mode)) {
153 fclose(fp);
154 errno = EISDIR;
155 return (NULL);
156 }
157 return (fp);
158 }
159
160 int
ipsecctl_commit(int action,struct ipsecctl * ipsec)161 ipsecctl_commit(int action, struct ipsecctl *ipsec)
162 {
163 struct ipsec_rule *rp;
164 int ret = 0;
165
166 if (pfkey_init() == -1)
167 errx(1, "ipsecctl_commit: failed to open PF_KEY socket");
168
169 TAILQ_FOREACH(rp, &ipsec->rule_queue, rule_entry) {
170 if (rp->type & RULE_IKE) {
171 if (ike_ipsec_establish(action, rp, isakmpd_fifo) ==
172 -1) {
173 warnx("failed to %s ike rule %d",
174 action == ACTION_DELETE ? "delete" : "add",
175 rp->nr);
176 ret = 2;
177 }
178 } else {
179 if (pfkey_ipsec_establish(action, rp) == -1) {
180 warnx("failed to %s rule %d",
181 action == ACTION_DELETE ? "delete" : "add",
182 rp->nr);
183 ret = 2;
184 }
185 }
186 }
187
188 return (ret);
189 }
190
191 int
ipsecctl_add_rule(struct ipsecctl * ipsec,struct ipsec_rule * r)192 ipsecctl_add_rule(struct ipsecctl *ipsec, struct ipsec_rule *r)
193 {
194 TAILQ_INSERT_TAIL(&ipsec->rule_queue, r, rule_entry);
195
196 if ((ipsec->opts & IPSECCTL_OPT_VERBOSE) && !(ipsec->opts &
197 IPSECCTL_OPT_SHOW))
198 ipsecctl_print_rule(r, ipsec->opts);
199
200 return (0);
201 }
202
203 void
ipsecctl_free_rule(struct ipsec_rule * rp)204 ipsecctl_free_rule(struct ipsec_rule *rp)
205 {
206 if (rp->src) {
207 free(rp->src->name);
208 free(rp->src);
209 }
210 if (rp->dst) {
211 free(rp->dst->name);
212 free(rp->dst);
213 }
214 if (rp->dst2) {
215 free(rp->dst2->name);
216 free(rp->dst2);
217 }
218 if (rp->local) {
219 free(rp->local->name);
220 free(rp->local);
221 }
222 if (rp->peer) {
223 free(rp->peer->name);
224 free(rp->peer);
225 }
226 if (rp->auth) {
227 free(rp->auth->srcid);
228 free(rp->auth->dstid);
229 free(rp->auth);
230 }
231 if (rp->ikeauth) {
232 free(rp->ikeauth->string);
233 free(rp->ikeauth);
234 }
235 free(rp->xfs);
236 free(rp->p1xfs);
237 free(rp->p2xfs);
238 free(rp->p1life);
239 free(rp->p2life);
240 if (rp->authkey) {
241 free(rp->authkey->data);
242 free(rp->authkey);
243 }
244 if (rp->enckey) {
245 free(rp->enckey->data);
246 free(rp->enckey);
247 }
248 free(rp->p1name);
249 free(rp->p2name);
250 free(rp->p2lid);
251 free(rp->p2nid);
252 free(rp->p2rid);
253 free(rp);
254 }
255
256 /*
257 * Merge two flow rules if they match.
258 *
259 * Return 0 if ``from'' has been merged into ``to'', -1 otherwise.
260 */
261 int
ipsecctl_merge_rules(struct ipsec_rule * to,struct ipsec_rule * from)262 ipsecctl_merge_rules(struct ipsec_rule *to, struct ipsec_rule *from)
263 {
264 int match = 0;
265
266 assert((to->type & RULE_FLOW) && (from->type & RULE_FLOW));
267
268 if ((to->satype != from->satype) ||
269 (to->direction != from->direction) ||
270 (to->sport != from->sport) ||
271 (to->dport != from->dport) ||
272 (to->proto != from->proto))
273 return (-1);
274
275 if (to->local != NULL || from->local != NULL) {
276 if ((to->local == NULL) || (from->local == NULL) ||
277 memcmp(to->local, from->local, sizeof(*to->local)))
278 return (-1);
279 }
280
281 if (to->peer != NULL || from->peer != NULL) {
282 if ((to->peer == NULL) || (from->peer == NULL) ||
283 memcmp(to->peer, from->peer, sizeof(*to->peer)))
284 return (-1);
285 }
286
287 if (ipsecctl_cmp_ident(to, from))
288 return (-1);
289
290 if (ipsecctl_rule_matchsrc(to, from->src)) {
291 free(from->src->name);
292 free(from->src);
293 from->src = NULL;
294 match = 1;
295 }
296 if (ipsecctl_rule_matchdst(to, from->dst)) {
297 free(from->dst->name);
298 free(from->dst);
299 from->dst = NULL;
300 match = 1;
301 }
302
303 if (!match)
304 return (-1);
305
306 TAILQ_INSERT_TAIL(&to->collapsed_rules, from, bundle_entry);
307
308 return (0);
309 }
310
311 /*
312 * Return 0 if ``r1'' and ``r2'' IDENTITY match, -1 otherwise.
313 */
314 int
ipsecctl_cmp_ident(struct ipsec_rule * r1,struct ipsec_rule * r2)315 ipsecctl_cmp_ident(struct ipsec_rule *r1, struct ipsec_rule *r2)
316 {
317 if ((r1->auth == NULL) && (r2->auth == NULL))
318 return (0) ;
319
320 if ((r1->auth == NULL) || (r2->auth == NULL))
321 return (-1);
322
323 if (r1->auth->type != r2->auth->type)
324 return (-1);
325
326 if (r1->auth->srcid != NULL) {
327 if (r2->auth->srcid == NULL)
328 return (-1);
329
330 if (strcmp(r1->auth->srcid, r2->auth->srcid))
331 return (-1);
332 }
333
334 if (r1->auth->dstid) {
335 if (r2->auth->dstid == NULL)
336 return (-1);
337
338 if (strcmp(r1->auth->dstid, r2->auth->dstid))
339 return (-1);
340 }
341
342 return (0);
343 }
344
345
346 /*
347 * Return 0 if ``r'' or its merged entries contain ``src'', -1 otherwise.
348 */
349 int
ipsecctl_rule_matchsrc(struct ipsec_rule * r,struct ipsec_addr_wrap * src)350 ipsecctl_rule_matchsrc(struct ipsec_rule *r, struct ipsec_addr_wrap *src)
351 {
352 struct ipsec_rule *r2;
353
354 if (memcmp(r->src, src, sizeof(*r->src)) == 0)
355 return (-1);
356
357 TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
358 if (r2->src == NULL)
359 continue;
360 if (memcmp(r2->src, src, sizeof(*r->src)) == 0)
361 return (-1);
362 }
363
364 return (0);
365 }
366
367 /*
368 * Return 0 if ``r'' or its merged entries contain ``dst'', -1 otherwise.
369 */
370 int
ipsecctl_rule_matchdst(struct ipsec_rule * r,struct ipsec_addr_wrap * dst)371 ipsecctl_rule_matchdst(struct ipsec_rule *r, struct ipsec_addr_wrap *dst)
372 {
373 struct ipsec_rule *r2;
374
375 if (memcmp(r->dst, dst, sizeof(*r->dst)) == 0)
376 return (-1);
377
378 TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
379 if (r2->dst == NULL)
380 continue;
381 if (memcmp(r2->dst, dst, sizeof(*r->dst)) == 0)
382 return (-1);
383 }
384
385 return (0);
386 }
387
388 void
ipsecctl_print_addr(struct ipsec_addr_wrap * ipa)389 ipsecctl_print_addr(struct ipsec_addr_wrap *ipa)
390 {
391 int bits;
392 char buf[NI_MAXHOST];
393
394 if (ipa == NULL) {
395 printf("?");
396 return;
397 }
398 if (inet_ntop(ipa->af, &ipa->address, buf, sizeof(buf)) == NULL)
399 printf("?");
400 else
401 printf("%s", buf);
402
403 bits = unmask(&ipa->mask);
404 if (bits != (ipa->af == AF_INET ? 32 : 128))
405 printf("/%d", bits);
406 }
407
408 void
ipsecctl_print_proto(u_int8_t proto)409 ipsecctl_print_proto(u_int8_t proto)
410 {
411 struct protoent *p;
412
413 if ((p = getprotobynumber(proto)) != NULL)
414 printf("%s", p->p_name);
415 else
416 printf("%u", proto);
417 }
418
419 void
ipsecctl_print_port(u_int16_t port,const char * proto)420 ipsecctl_print_port(u_int16_t port, const char *proto)
421 {
422 struct servent *s;
423
424 if ((s = getservbyport(port, proto)) != NULL)
425 printf("%s", s->s_name);
426 else
427 printf("%u", ntohs(port));
428 }
429
430 void
ipsecctl_print_key(struct ipsec_key * key)431 ipsecctl_print_key(struct ipsec_key *key)
432 {
433 int i;
434
435 for (i = 0; i < (int)key->len; i++)
436 printf("%02x", key->data[i]);
437 }
438
439 void
ipsecctl_print_flow(struct ipsec_rule * r,int opts)440 ipsecctl_print_flow(struct ipsec_rule *r, int opts)
441 {
442 struct ipsec_rule *r2;
443
444 printf("flow %s %s", satype[r->satype], direction[r->direction]);
445
446 if (r->proto) {
447 printf(" proto ");
448 ipsecctl_print_proto(r->proto);
449 }
450 printf(" from ");
451 if (opts & IPSECCTL_OPT_COLLAPSE) {
452 printf("{ ");
453 ipsecctl_print_addr(r->src);
454 TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
455 if (r2->src == NULL)
456 continue;
457 printf(", ");
458 ipsecctl_print_addr(r2->src);
459 }
460 printf(" }");
461 } else
462 ipsecctl_print_addr(r->src);
463 if (r->sport) {
464 printf(" port ");
465 ipsecctl_print_port(r->sport,
466 r->proto == IPPROTO_TCP ? "tcp" : "udp");
467 }
468 printf(" to ");
469 if (opts & IPSECCTL_OPT_COLLAPSE) {
470 printf("{ ");
471 ipsecctl_print_addr(r->dst);
472 TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
473 if (r2->dst == NULL)
474 continue;
475 printf(", ");
476 ipsecctl_print_addr(r2->dst);
477 }
478 printf(" }");
479 } else
480 ipsecctl_print_addr(r->dst);
481 if (r->dport) {
482 printf(" port ");
483 ipsecctl_print_port(r->dport,
484 r->proto == IPPROTO_TCP ? "tcp" : "udp");
485 }
486 if (r->local) {
487 printf(" local ");
488 ipsecctl_print_addr(r->local);
489 }
490 if (r->peer) {
491 printf(" peer ");
492 ipsecctl_print_addr(r->peer);
493 }
494 if (r->auth) {
495 if (r->auth->srcid)
496 printf(" srcid %s", r->auth->srcid);
497 if (r->auth->dstid)
498 printf(" dstid %s", r->auth->dstid);
499 if (r->auth->type > 0)
500 printf(" %s", auth[r->auth->type]);
501 }
502 printf(" type %s", flowtype[r->flowtype]);
503 printf("\n");
504 }
505
506 void
ipsecctl_print_sa(struct ipsec_rule * r,int opts)507 ipsecctl_print_sa(struct ipsec_rule *r, int opts)
508 {
509 printf("%s ", satype[r->satype]);
510 /* tunnel/transport is only meaningful for esp/ah/ipcomp */
511 if (r->satype != IPSEC_TCPMD5 && r->satype != IPSEC_IPIP)
512 printf("%s ", tmode[r->tmode]);
513 printf("from ");
514 ipsecctl_print_addr(r->src);
515 printf(" to ");
516 ipsecctl_print_addr(r->dst);
517 printf(" spi 0x%08x", r->spi);
518
519 if (r->satype != IPSEC_TCPMD5) {
520 if (r->xfs && r->xfs->authxf)
521 printf(" auth %s", r->xfs->authxf->name);
522 if (r->xfs && r->xfs->encxf)
523 printf(" enc %s", r->xfs->encxf->name);
524 if (r->xfs && r->xfs->compxf)
525 printf(" comp %s", r->xfs->compxf->name);
526 }
527 if (r->authkey && (opts & IPSECCTL_OPT_SHOWKEY)) {
528 if (r->satype == IPSEC_TCPMD5)
529 printf(" ");
530 else
531 printf(" \\\n\t");
532 printf("authkey 0x");
533 ipsecctl_print_key(r->authkey);
534 }
535 if (r->enckey && (opts & IPSECCTL_OPT_SHOWKEY)) {
536 if (r->satype == IPSEC_TCPMD5)
537 printf(" ");
538 else
539 printf(" \\\n\t");
540 printf("enckey 0x");
541 ipsecctl_print_key(r->enckey);
542 }
543 printf("\n");
544 }
545
546 void
ipsecctl_print_sabundle(struct ipsec_rule * r,int opts)547 ipsecctl_print_sabundle(struct ipsec_rule *r, int opts)
548 {
549 printf("[bundle %s to ", satype[r->proto]);
550 ipsecctl_print_addr(r->dst);
551 printf(" spi 0x%08x with %s to ", r->spi, satype[r->proto2]);
552 ipsecctl_print_addr(r->dst2);
553 printf(" spi 0x%08x", r->spi2);
554
555 printf("]\n");
556 }
557
558 void
ipsecctl_print_rule(struct ipsec_rule * r,int opts)559 ipsecctl_print_rule(struct ipsec_rule *r, int opts)
560 {
561 struct ipsec_rule *r2;
562
563 if (opts & IPSECCTL_OPT_VERBOSE2) {
564 printf("@%d", r->nr);
565 if (opts & IPSECCTL_OPT_COLLAPSE) {
566 TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
567 printf(",%d", r2->nr);
568 }
569 }
570 printf(" ");
571 }
572
573 if (r->type & RULE_FLOW)
574 ipsecctl_print_flow(r, opts);
575 if (r->type & RULE_SA)
576 ipsecctl_print_sa(r, opts);
577 if (r->type & RULE_IKE)
578 ike_print_config(r, opts);
579 if (r->type & RULE_BUNDLE)
580 ipsecctl_print_sabundle(r, opts);
581 }
582
583 int
ipsecctl_flush(int opts)584 ipsecctl_flush(int opts)
585 {
586 if (opts & IPSECCTL_OPT_NOACTION)
587 return (0);
588
589 if (pfkey_init() == -1)
590 errx(1, "ipsecctl_flush: failed to open PF_KEY socket");
591
592 if (pfkey_ipsec_flush() == -1)
593 errx(1, "ipsecctl_flush: failed to flush");
594
595 return (0);
596 }
597
598 char *
ipsecctl_get_rules(struct ipsecctl * ipsec,size_t * need)599 ipsecctl_get_rules(struct ipsecctl *ipsec, size_t *need)
600 {
601 int mib[4];
602 char *buf;
603
604 mib[0] = CTL_NET;
605 mib[1] = PF_KEY;
606 mib[2] = PF_KEY_V2;
607 mib[3] = NET_KEY_SPD_DUMP;
608
609 if (sysctl(mib, 4, NULL, need, NULL, 0) == -1)
610 err(1, "ipsecctl_get_rules: sysctl");
611 if (*need == 0)
612 return NULL;
613 if ((buf = malloc(*need)) == NULL)
614 err(1, "ipsecctl_get_rules: malloc");
615 if (sysctl(mib, 4, buf, need, NULL, 0) == -1)
616 err(1, "ipsecctl_get_rules: sysctl");
617
618 return buf;
619 }
620
621 void
ipsecctl_parse_rules(struct ipsecctl * ipsec,char * buf,size_t need)622 ipsecctl_parse_rules(struct ipsecctl *ipsec, char *buf, size_t need)
623 {
624 struct sadb_msg *msg;
625 struct ipsec_rule *rule, *last = NULL;
626 char *lim, *next;
627
628 lim = buf + need;
629 for (next = buf; next < lim; next += msg->sadb_msg_len *
630 PFKEYV2_CHUNK) {
631 msg = (struct sadb_msg *)next;
632 if (msg->sadb_msg_len == 0)
633 break;
634
635 rule = calloc(1, sizeof(struct ipsec_rule));
636 if (rule == NULL)
637 err(1, "ipsecctl_parse_rules: calloc");
638 rule->nr = ipsec->rule_nr++;
639 rule->type |= RULE_FLOW;
640 TAILQ_INIT(&rule->collapsed_rules);
641
642 if (pfkey_parse(msg, rule))
643 errx(1, "ipsecctl_parse_rules: "
644 "failed to parse PF_KEY message");
645
646 /*
647 * Try to collapse ``rule'' with the last enqueued rule.
648 *
649 * Note that comparing only the last entry works only if
650 * the dump is sorted.
651 */
652 if ((ipsec->opts & IPSECCTL_OPT_COLLAPSE) && (last != NULL) &&
653 (ipsecctl_merge_rules(last, rule) == 0))
654 continue;
655
656 ipsecctl_add_rule(ipsec, rule);
657 last = rule;
658 }
659
660 free(buf);
661 }
662
663 void
ipsecctl_print_title(char * title)664 ipsecctl_print_title(char *title)
665 {
666 if (!first_title)
667 printf("\n");
668 first_title = 0;
669 printf("%s\n", title);
670 }
671
672 void
ipsecctl_show(int opts)673 ipsecctl_show(int opts)
674 {
675 struct ipsecctl ipsec;
676 struct ipsec_rule *rp;
677 struct sadb_msg *msg;
678 struct sad *sad;
679 int mib[5], sacount, i;
680 size_t need = 0, rlen;
681 char *sbuf = NULL, *rbuf = NULL, *lim, *next;
682
683 if (opts & IPSECCTL_OPT_SHOWFLOWS) {
684 bzero(&ipsec, sizeof(ipsec));
685 ipsec.opts = opts;
686 TAILQ_INIT(&ipsec.rule_queue);
687 rbuf = ipsecctl_get_rules(&ipsec, &rlen);
688 }
689
690 if (opts & IPSECCTL_OPT_SHOWSAS) {
691 mib[0] = CTL_NET;
692 mib[1] = PF_KEY;
693 mib[2] = PF_KEY_V2;
694 mib[3] = NET_KEY_SADB_DUMP;
695 mib[4] = SADB_SATYPE_UNSPEC;
696
697 /* When the SAD is empty we get ENOENT, no need to err(). */
698 if (sysctl(mib, 5, NULL, &need, NULL, 0) == -1 &&
699 errno != ENOENT)
700 err(1, "ipsecctl_show: sysctl");
701 if (need > 0) {
702 if ((sbuf = malloc(need)) == NULL)
703 err(1, "ipsecctl_show: malloc");
704 if (sysctl(mib, 5, sbuf, &need, NULL, 0) == -1)
705 err(1, "ipsecctl_show: sysctl");
706 }
707 }
708
709 if (pledge("stdio dns", NULL) == -1)
710 err(1, "pledge");
711
712 if (rbuf != NULL) {
713 ipsecctl_parse_rules(&ipsec, rbuf, rlen);
714
715 if (opts & IPSECCTL_OPT_SHOWALL)
716 ipsecctl_print_title("FLOWS:");
717
718 if (TAILQ_FIRST(&ipsec.rule_queue) != NULL) {
719 while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
720 TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
721
722 ipsecctl_print_rule(rp, ipsec.opts);
723
724 free(rp->src->name);
725 free(rp->src);
726 free(rp->dst->name);
727 free(rp->dst);
728 if (rp->local) {
729 free(rp->local->name);
730 free(rp->local);
731 }
732 if (rp->peer) {
733 free(rp->peer->name);
734 free(rp->peer);
735 }
736 if (rp->auth) {
737 free(rp->auth->srcid);
738 free(rp->auth->dstid);
739 free(rp->auth);
740 }
741 free(rp);
742 }
743 }
744 } else if (opts & IPSECCTL_OPT_SHOWALL) {
745 ipsecctl_print_title("FLOWS:");
746 if (opts & IPSECCTL_OPT_SHOWALL)
747 printf("No flows\n");
748 }
749
750 if (pledge("stdio", NULL) == -1)
751 err(1, "pledge");
752
753 if (sbuf != NULL) {
754 if (opts & IPSECCTL_OPT_SHOWALL)
755 ipsecctl_print_title("SAD:");
756
757 sacount = 0;
758 lim = sbuf + need;
759 for (next = sbuf; next < lim;
760 next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
761 msg = (struct sadb_msg *)next;
762 if (msg->sadb_msg_len == 0)
763 break;
764 sacount++;
765 }
766 if ((sad = calloc(sacount, sizeof(*sad))) == NULL)
767 err(1, "ipsecctl_show: calloc");
768 i = 0;
769 for (next = sbuf; next < lim;
770 next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
771 msg = (struct sadb_msg *)next;
772 if (msg->sadb_msg_len == 0)
773 break;
774 sad[i].sad_spi = pfkey_get_spi(msg);
775 sad[i].sad_msg = msg;
776 i++;
777 }
778 qsort(sad, sacount, sizeof(*sad), sacompare);
779 for (i = 0; i < sacount; i++)
780 pfkey_print_sa(sad[i].sad_msg, opts);
781 free(sad);
782 free(sbuf);
783 } else if (opts & IPSECCTL_OPT_SHOWALL) {
784 ipsecctl_print_title("SAD:");
785 printf("No entries\n");
786 }
787 }
788
789 int
ipsecctl_monitor(int opts)790 ipsecctl_monitor(int opts)
791 {
792 return (pfkey_monitor(opts));
793 }
794
795 __dead void
usage(void)796 usage(void)
797 {
798 extern char *__progname;
799
800 fprintf(stderr, "usage: %s [-cdFkmnv] [-D macro=value] [-f file]"
801 " [-i fifo] [-s modifier]\n", __progname);
802 exit(1);
803 }
804
805 const char *
ipsecctl_lookup_option(char * cmd,const char ** list)806 ipsecctl_lookup_option(char *cmd, const char **list)
807 {
808 if (cmd != NULL && *cmd)
809 for (; *list; list++)
810 if (!strncmp(cmd, *list, strlen(cmd)))
811 return (*list);
812 return (NULL);
813 }
814
815 int
main(int argc,char * argv[])816 main(int argc, char *argv[])
817 {
818 int error = 0;
819 int ch;
820 int opts = 0;
821 char *rulesopt = NULL;
822
823 if (argc < 2)
824 usage();
825
826 while ((ch = getopt(argc, argv, "cD:df:Fi:kmnvs:")) != -1) {
827 switch (ch) {
828 case 'c':
829 opts |= IPSECCTL_OPT_COLLAPSE;
830 break;
831
832 case 'D':
833 if (cmdline_symset(optarg) < 0)
834 warnx("could not parse macro definition %s",
835 optarg);
836 break;
837
838 case 'd':
839 opts |= IPSECCTL_OPT_DELETE;
840 break;
841
842 case 'f':
843 rulesopt = optarg;
844 break;
845
846 case 'F':
847 opts |= IPSECCTL_OPT_FLUSH;
848 break;
849
850 case 'i':
851 isakmpd_fifo = optarg;
852 break;
853
854 case 'k':
855 opts |= IPSECCTL_OPT_SHOWKEY;
856 break;
857
858 case 'm':
859 opts |= IPSECCTL_OPT_MONITOR;
860 break;
861
862 case 'n':
863 opts |= IPSECCTL_OPT_NOACTION;
864 break;
865
866 case 'v':
867 if (opts & IPSECCTL_OPT_VERBOSE)
868 opts |= IPSECCTL_OPT_VERBOSE2;
869 opts |= IPSECCTL_OPT_VERBOSE;
870 break;
871
872 case 's':
873 showopt = ipsecctl_lookup_option(optarg, showopt_list);
874 if (showopt == NULL) {
875 warnx("Unknown show modifier '%s'", optarg);
876 usage();
877 /* NOTREACHED */
878 }
879 opts |= IPSECCTL_OPT_SHOW;
880 break;
881
882 default:
883 usage();
884 /* NOTREACHED */
885 }
886 }
887
888 if (argc != optind) {
889 warnx("unknown command line argument: %s ...", argv[optind]);
890 usage();
891 /* NOTREACHED */
892 }
893 if (opts & IPSECCTL_OPT_FLUSH)
894 if (ipsecctl_flush(opts))
895 error = 1;
896
897 if (rulesopt != NULL)
898 if (ipsecctl_rules(rulesopt, opts))
899 error = 1;
900
901 if (showopt != NULL) {
902 switch (*showopt) {
903 case 'f':
904 opts |= IPSECCTL_OPT_SHOWFLOWS;
905 break;
906 case 's':
907 opts |= IPSECCTL_OPT_SHOWSAS;
908 break;
909 case 'a':
910 opts |= IPSECCTL_OPT_SHOWFLOWS;
911 opts |= IPSECCTL_OPT_SHOWSAS;
912 opts |= IPSECCTL_OPT_SHOWALL;
913 break;
914 }
915 ipsecctl_show(opts);
916 }
917
918 if (opts & IPSECCTL_OPT_MONITOR)
919 if (ipsecctl_monitor(opts))
920 error = 1;
921
922 exit(error);
923 }
924
925 static int
unmask(struct ipsec_addr * ipa)926 unmask(struct ipsec_addr *ipa)
927 {
928 int i = 31, j = 0, b = 0;
929 u_int32_t tmp;
930
931 while (j < 4 && ipa->addr32[j] == 0xffffffff) {
932 b += 32;
933 j++;
934 }
935 if (j < 4) {
936 tmp = ntohl(ipa->addr32[j]);
937 for (i = 31; tmp & (1 << i); --i)
938 b++;
939 }
940 return (b);
941 }
942