1*4ecd42c0Syasuoka /* $OpenBSD: ipsecctl.c,v 1.88 2024/02/06 05:39:28 yasuoka Exp $ */
2f484f2cfShshoexer /*
3f484f2cfShshoexer * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org>
4f484f2cfShshoexer *
5f484f2cfShshoexer * Permission to use, copy, modify, and distribute this software for any
6f484f2cfShshoexer * purpose with or without fee is hereby granted, provided that the above
7f484f2cfShshoexer * copyright notice and this permission notice appear in all copies.
8f484f2cfShshoexer *
9f484f2cfShshoexer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10f484f2cfShshoexer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11f484f2cfShshoexer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12f484f2cfShshoexer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13f484f2cfShshoexer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14f484f2cfShshoexer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15f484f2cfShshoexer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f484f2cfShshoexer */
17f484f2cfShshoexer
18f484f2cfShshoexer #include <sys/socket.h>
19f484f2cfShshoexer #include <sys/sysctl.h>
20f484f2cfShshoexer #include <sys/queue.h>
21f484f2cfShshoexer #include <sys/stat.h>
22f484f2cfShshoexer #include <net/pfkeyv2.h>
23f484f2cfShshoexer #include <net/route.h>
24f484f2cfShshoexer #include <netinet/in.h>
25f484f2cfShshoexer #include <netinet/ip_ipsp.h>
26f484f2cfShshoexer #include <arpa/inet.h>
27f484f2cfShshoexer
28aa9f7a4dSmpi #include <assert.h>
29f484f2cfShshoexer #include <err.h>
30f484f2cfShshoexer #include <errno.h>
31f484f2cfShshoexer #include <fcntl.h>
32712e78baShshoexer #include <netdb.h>
33f484f2cfShshoexer #include <stdio.h>
34f484f2cfShshoexer #include <stdlib.h>
354a9adf07Shshoexer #include <string.h>
36f484f2cfShshoexer #include <unistd.h>
37f484f2cfShshoexer
38f484f2cfShshoexer #include "ipsecctl.h"
391edc1b9aShshoexer #include "pfkey.h"
40f484f2cfShshoexer
41f484f2cfShshoexer int ipsecctl_rules(char *, int);
42f484f2cfShshoexer FILE *ipsecctl_fopen(const char *, const char *);
436d01698dShshoexer int ipsecctl_commit(int, struct ipsecctl *);
44f484f2cfShshoexer int ipsecctl_add_rule(struct ipsecctl *, struct ipsec_rule *);
4509203018Shshoexer void ipsecctl_free_rule(struct ipsec_rule *);
46aa9f7a4dSmpi int ipsecctl_merge_rules(struct ipsec_rule *, struct ipsec_rule *);
47aa9f7a4dSmpi int ipsecctl_cmp_ident(struct ipsec_rule *, struct ipsec_rule *);
48aa9f7a4dSmpi int ipsecctl_rule_matchsrc(struct ipsec_rule *,
49aa9f7a4dSmpi struct ipsec_addr_wrap *);
50aa9f7a4dSmpi int ipsecctl_rule_matchdst(struct ipsec_rule *,
51aa9f7a4dSmpi struct ipsec_addr_wrap *);
5291f765ddShshoexer void ipsecctl_print_addr(struct ipsec_addr_wrap *);
539182219dSmarkus void ipsecctl_print_proto(u_int8_t);
5457f58d0dSnaddy void ipsecctl_print_port(u_int16_t, const char *);
55110db5a9Shshoexer void ipsecctl_print_key(struct ipsec_key *);
56110db5a9Shshoexer void ipsecctl_print_flow(struct ipsec_rule *, int);
57110db5a9Shshoexer void ipsecctl_print_sa(struct ipsec_rule *, int);
58a6bcba92Sbluhm void ipsecctl_print_sabundle(struct ipsec_rule *, int);
59f484f2cfShshoexer int ipsecctl_flush(int);
60202aab43Stobhe char *ipsecctl_get_rules(struct ipsecctl *, size_t *);
61202aab43Stobhe void ipsecctl_parse_rules(struct ipsecctl *, char *, size_t);
623dd59ad2Shshoexer void ipsecctl_print_title(char *);
63202aab43Stobhe void ipsecctl_show(int);
648a87fca6Smsf int ipsecctl_monitor(int);
65f484f2cfShshoexer void usage(void);
663dd59ad2Shshoexer const char *ipsecctl_lookup_option(char *, const char **);
67eaa84e12Skn static int unmask(struct ipsec_addr *);
68895bd039Smarkus int sacompare(const void *, const void *);
69f484f2cfShshoexer
703dd59ad2Shshoexer const char *showopt;
71f8738d8bShenning char *isakmpd_fifo = "/var/run/isakmpd.fifo";
723dd59ad2Shshoexer
733dd59ad2Shshoexer int first_title = 1;
743dd59ad2Shshoexer
753dd59ad2Shshoexer static const char *showopt_list[] = {
763dd59ad2Shshoexer "flow", "sa", "all", NULL
773dd59ad2Shshoexer };
78f484f2cfShshoexer
79110db5a9Shshoexer static const char *direction[] = {"?", "in", "out"};
80110db5a9Shshoexer static const char *flowtype[] = {"?", "use", "acquire", "require", "deny",
81110db5a9Shshoexer "bypass", "dontacq"};
829182219dSmarkus static const char *satype[] = {"?", "esp", "ah", "ipcomp", "tcpmd5", "ipip"};
83a38d220fShshoexer static const char *tmode[] = {"?", "transport", "tunnel"};
84110db5a9Shshoexer static const char *auth[] = {"?", "psk", "rsa"};
85110db5a9Shshoexer
86895bd039Smarkus struct sad {
87895bd039Smarkus struct sadb_msg *sad_msg;
88895bd039Smarkus u_int32_t sad_spi;
89895bd039Smarkus };
90895bd039Smarkus
91895bd039Smarkus int
sacompare(const void * va,const void * vb)92895bd039Smarkus sacompare(const void *va, const void *vb)
93895bd039Smarkus {
94895bd039Smarkus const struct sad *a = va, *b = vb;
95895bd039Smarkus
96895bd039Smarkus if (a->sad_spi < b->sad_spi)
97895bd039Smarkus return (-1);
98895bd039Smarkus if (a->sad_spi > b->sad_spi)
99895bd039Smarkus return (1);
100895bd039Smarkus return (0);
101895bd039Smarkus }
102895bd039Smarkus
103f484f2cfShshoexer int
ipsecctl_rules(char * filename,int opts)104f484f2cfShshoexer ipsecctl_rules(char *filename, int opts)
105f484f2cfShshoexer {
106f484f2cfShshoexer struct ipsecctl ipsec;
107c272c54fSbluhm struct ipsec_rule *rp;
1086d01698dShshoexer int action, error = 0;
109f484f2cfShshoexer
110e7a09a9bSkjell bzero(&ipsec, sizeof(ipsec));
111f484f2cfShshoexer ipsec.opts = opts;
112f484f2cfShshoexer TAILQ_INIT(&ipsec.rule_queue);
113a6bcba92Sbluhm TAILQ_INIT(&ipsec.bundle_queue);
114f484f2cfShshoexer
11520741916Sderaadt if (parse_rules(filename, &ipsec) < 0) {
116f484f2cfShshoexer warnx("Syntax error in config file: ipsec rules not loaded");
117f484f2cfShshoexer error = 1;
118e7a09a9bSkjell } else {
1196d01698dShshoexer if (opts & IPSECCTL_OPT_DELETE)
12090bd57a7Shshoexer action = ACTION_DELETE;
1216d01698dShshoexer else
12290bd57a7Shshoexer action = ACTION_ADD;
1236d01698dShshoexer
124e7a09a9bSkjell if ((opts & IPSECCTL_OPT_NOACTION) == 0)
1252b6ecedeShshoexer error = ipsecctl_commit(action, &ipsec);
126c272c54fSbluhm
127e7a09a9bSkjell }
128c272c54fSbluhm
129a6bcba92Sbluhm /* This also frees the rules in ipsec.bundle_queue. */
130c272c54fSbluhm while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
131c272c54fSbluhm TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
132c272c54fSbluhm ipsecctl_free_rule(rp);
133c272c54fSbluhm }
134c272c54fSbluhm
135c3324a93Skjell return (error);
136f484f2cfShshoexer }
137f484f2cfShshoexer
138f484f2cfShshoexer FILE *
ipsecctl_fopen(const char * name,const char * mode)139f484f2cfShshoexer ipsecctl_fopen(const char *name, const char *mode)
140f484f2cfShshoexer {
141f484f2cfShshoexer struct stat st;
142f484f2cfShshoexer FILE *fp;
143f484f2cfShshoexer
144f484f2cfShshoexer fp = fopen(name, mode);
145f484f2cfShshoexer if (fp == NULL)
146c3324a93Skjell return (NULL);
147f484f2cfShshoexer
148f484f2cfShshoexer if (fstat(fileno(fp), &st)) {
149f484f2cfShshoexer fclose(fp);
150c3324a93Skjell return (NULL);
151f484f2cfShshoexer }
152f484f2cfShshoexer if (S_ISDIR(st.st_mode)) {
153f484f2cfShshoexer fclose(fp);
154f484f2cfShshoexer errno = EISDIR;
155c3324a93Skjell return (NULL);
156f484f2cfShshoexer }
157c3324a93Skjell return (fp);
158f484f2cfShshoexer }
159f484f2cfShshoexer
160f484f2cfShshoexer int
ipsecctl_commit(int action,struct ipsecctl * ipsec)1616d01698dShshoexer ipsecctl_commit(int action, struct ipsecctl *ipsec)
162f484f2cfShshoexer {
163f484f2cfShshoexer struct ipsec_rule *rp;
1642b6ecedeShshoexer int ret = 0;
165f484f2cfShshoexer
166f484f2cfShshoexer if (pfkey_init() == -1)
1670c7c92aeShshoexer errx(1, "ipsecctl_commit: failed to open PF_KEY socket");
168f484f2cfShshoexer
169c272c54fSbluhm TAILQ_FOREACH(rp, &ipsec->rule_queue, rule_entry) {
17090bd57a7Shshoexer if (rp->type & RULE_IKE) {
171f8738d8bShenning if (ike_ipsec_establish(action, rp, isakmpd_fifo) ==
172f8738d8bShenning -1) {
1734dfa5d1cSbluhm warnx("failed to %s ike rule %d",
174e0d21bd9Smarkus action == ACTION_DELETE ? "delete" : "add",
175e0d21bd9Smarkus rp->nr);
1762b6ecedeShshoexer ret = 2;
1772b6ecedeShshoexer }
17890bd57a7Shshoexer } else {
1792b6ecedeShshoexer if (pfkey_ipsec_establish(action, rp) == -1) {
180e0d21bd9Smarkus warnx("failed to %s rule %d",
181e0d21bd9Smarkus action == ACTION_DELETE ? "delete" : "add",
182e0d21bd9Smarkus rp->nr);
1832b6ecedeShshoexer ret = 2;
1842b6ecedeShshoexer }
18590bd57a7Shshoexer }
18609203018Shshoexer }
187f484f2cfShshoexer
1882b6ecedeShshoexer return (ret);
18909203018Shshoexer }
19009203018Shshoexer
19109203018Shshoexer int
ipsecctl_add_rule(struct ipsecctl * ipsec,struct ipsec_rule * r)19209203018Shshoexer ipsecctl_add_rule(struct ipsecctl *ipsec, struct ipsec_rule *r)
19309203018Shshoexer {
194e48766bcShshoexer TAILQ_INSERT_TAIL(&ipsec->rule_queue, r, rule_entry);
19509203018Shshoexer
19609203018Shshoexer if ((ipsec->opts & IPSECCTL_OPT_VERBOSE) && !(ipsec->opts &
19709203018Shshoexer IPSECCTL_OPT_SHOW))
19809203018Shshoexer ipsecctl_print_rule(r, ipsec->opts);
19909203018Shshoexer
20009203018Shshoexer return (0);
20109203018Shshoexer }
20209203018Shshoexer
20309203018Shshoexer void
ipsecctl_free_rule(struct ipsec_rule * rp)20409203018Shshoexer ipsecctl_free_rule(struct ipsec_rule *rp)
20509203018Shshoexer {
206bccfebbfShshoexer if (rp->src) {
20790bd57a7Shshoexer free(rp->src->name);
208f484f2cfShshoexer free(rp->src);
209bccfebbfShshoexer }
210bccfebbfShshoexer if (rp->dst) {
21190bd57a7Shshoexer free(rp->dst->name);
212f484f2cfShshoexer free(rp->dst);
213bccfebbfShshoexer }
214bccfebbfShshoexer if (rp->dst2) {
215bccfebbfShshoexer free(rp->dst2->name);
216bccfebbfShshoexer free(rp->dst2);
217bccfebbfShshoexer }
218435bb41eSmarkus if (rp->local) {
219435bb41eSmarkus free(rp->local->name);
220435bb41eSmarkus free(rp->local);
221435bb41eSmarkus }
22290bd57a7Shshoexer if (rp->peer) {
22390bd57a7Shshoexer free(rp->peer->name);
224f484f2cfShshoexer free(rp->peer);
22590bd57a7Shshoexer }
226abe65127Shshoexer if (rp->auth) {
227abe65127Shshoexer free(rp->auth->srcid);
228abe65127Shshoexer free(rp->auth->dstid);
229abe65127Shshoexer free(rp->auth);
23090bd57a7Shshoexer }
231aa4503c0Sreyk if (rp->ikeauth) {
232aa4503c0Sreyk free(rp->ikeauth->string);
233aa4503c0Sreyk free(rp->ikeauth);
234aa4503c0Sreyk }
235375db29dShshoexer free(rp->xfs);
236336f7f89Smcbride free(rp->p1xfs);
237336f7f89Smcbride free(rp->p2xfs);
238336f7f89Smcbride free(rp->p1life);
239336f7f89Smcbride free(rp->p2life);
240670bad1aShshoexer if (rp->authkey) {
241670bad1aShshoexer free(rp->authkey->data);
242670bad1aShshoexer free(rp->authkey);
243110db5a9Shshoexer }
244375db29dShshoexer if (rp->enckey) {
245375db29dShshoexer free(rp->enckey->data);
246375db29dShshoexer free(rp->enckey);
247375db29dShshoexer }
248befd40c8Sbluhm free(rp->p1name);
249e973ffa2Smarkus free(rp->p2name);
250e973ffa2Smarkus free(rp->p2lid);
251c471c043Smpf free(rp->p2nid);
252e973ffa2Smarkus free(rp->p2rid);
253f484f2cfShshoexer free(rp);
254f484f2cfShshoexer }
255f484f2cfShshoexer
256aa9f7a4dSmpi /*
257aa9f7a4dSmpi * Merge two flow rules if they match.
258aa9f7a4dSmpi *
259aa9f7a4dSmpi * Return 0 if ``from'' has been merged into ``to'', -1 otherwise.
260aa9f7a4dSmpi */
261aa9f7a4dSmpi int
ipsecctl_merge_rules(struct ipsec_rule * to,struct ipsec_rule * from)262aa9f7a4dSmpi ipsecctl_merge_rules(struct ipsec_rule *to, struct ipsec_rule *from)
263aa9f7a4dSmpi {
264aa9f7a4dSmpi int match = 0;
265aa9f7a4dSmpi
266aa9f7a4dSmpi assert((to->type & RULE_FLOW) && (from->type & RULE_FLOW));
267aa9f7a4dSmpi
268aa9f7a4dSmpi if ((to->satype != from->satype) ||
269aa9f7a4dSmpi (to->direction != from->direction) ||
270aa9f7a4dSmpi (to->sport != from->sport) ||
271aa9f7a4dSmpi (to->dport != from->dport) ||
272aa9f7a4dSmpi (to->proto != from->proto))
273aa9f7a4dSmpi return (-1);
274aa9f7a4dSmpi
275aa9f7a4dSmpi if (to->local != NULL || from->local != NULL) {
276aa9f7a4dSmpi if ((to->local == NULL) || (from->local == NULL) ||
277aa9f7a4dSmpi memcmp(to->local, from->local, sizeof(*to->local)))
278aa9f7a4dSmpi return (-1);
279aa9f7a4dSmpi }
280aa9f7a4dSmpi
281aa9f7a4dSmpi if (to->peer != NULL || from->peer != NULL) {
282aa9f7a4dSmpi if ((to->peer == NULL) || (from->peer == NULL) ||
283aa9f7a4dSmpi memcmp(to->peer, from->peer, sizeof(*to->peer)))
284aa9f7a4dSmpi return (-1);
285aa9f7a4dSmpi }
286aa9f7a4dSmpi
287aa9f7a4dSmpi if (ipsecctl_cmp_ident(to, from))
288aa9f7a4dSmpi return (-1);
289aa9f7a4dSmpi
290aa9f7a4dSmpi if (ipsecctl_rule_matchsrc(to, from->src)) {
291aa9f7a4dSmpi free(from->src->name);
292aa9f7a4dSmpi free(from->src);
293aa9f7a4dSmpi from->src = NULL;
294aa9f7a4dSmpi match = 1;
295aa9f7a4dSmpi }
296aa9f7a4dSmpi if (ipsecctl_rule_matchdst(to, from->dst)) {
297aa9f7a4dSmpi free(from->dst->name);
298aa9f7a4dSmpi free(from->dst);
299aa9f7a4dSmpi from->dst = NULL;
300aa9f7a4dSmpi match = 1;
301aa9f7a4dSmpi }
302aa9f7a4dSmpi
303aa9f7a4dSmpi if (!match)
304aa9f7a4dSmpi return (-1);
305aa9f7a4dSmpi
306aa9f7a4dSmpi TAILQ_INSERT_TAIL(&to->collapsed_rules, from, bundle_entry);
307aa9f7a4dSmpi
308aa9f7a4dSmpi return (0);
309aa9f7a4dSmpi }
310aa9f7a4dSmpi
311aa9f7a4dSmpi /*
312aa9f7a4dSmpi * Return 0 if ``r1'' and ``r2'' IDENTITY match, -1 otherwise.
313aa9f7a4dSmpi */
314aa9f7a4dSmpi int
ipsecctl_cmp_ident(struct ipsec_rule * r1,struct ipsec_rule * r2)315aa9f7a4dSmpi ipsecctl_cmp_ident(struct ipsec_rule *r1, struct ipsec_rule *r2)
316aa9f7a4dSmpi {
317aa9f7a4dSmpi if ((r1->auth == NULL) && (r2->auth == NULL))
318aa9f7a4dSmpi return (0) ;
319aa9f7a4dSmpi
320aa9f7a4dSmpi if ((r1->auth == NULL) || (r2->auth == NULL))
321aa9f7a4dSmpi return (-1);
322aa9f7a4dSmpi
323aa9f7a4dSmpi if (r1->auth->type != r2->auth->type)
324aa9f7a4dSmpi return (-1);
325aa9f7a4dSmpi
326aa9f7a4dSmpi if (r1->auth->srcid != NULL) {
327aa9f7a4dSmpi if (r2->auth->srcid == NULL)
328aa9f7a4dSmpi return (-1);
329aa9f7a4dSmpi
330aa9f7a4dSmpi if (strcmp(r1->auth->srcid, r2->auth->srcid))
331aa9f7a4dSmpi return (-1);
332aa9f7a4dSmpi }
333aa9f7a4dSmpi
334aa9f7a4dSmpi if (r1->auth->dstid) {
335aa9f7a4dSmpi if (r2->auth->dstid == NULL)
336aa9f7a4dSmpi return (-1);
337aa9f7a4dSmpi
338aa9f7a4dSmpi if (strcmp(r1->auth->dstid, r2->auth->dstid))
339aa9f7a4dSmpi return (-1);
340aa9f7a4dSmpi }
341aa9f7a4dSmpi
342aa9f7a4dSmpi return (0);
343aa9f7a4dSmpi }
344aa9f7a4dSmpi
345aa9f7a4dSmpi
346aa9f7a4dSmpi /*
347aa9f7a4dSmpi * Return 0 if ``r'' or its merged entries contain ``src'', -1 otherwise.
348aa9f7a4dSmpi */
349aa9f7a4dSmpi int
ipsecctl_rule_matchsrc(struct ipsec_rule * r,struct ipsec_addr_wrap * src)350aa9f7a4dSmpi ipsecctl_rule_matchsrc(struct ipsec_rule *r, struct ipsec_addr_wrap *src)
351aa9f7a4dSmpi {
352aa9f7a4dSmpi struct ipsec_rule *r2;
353aa9f7a4dSmpi
354aa9f7a4dSmpi if (memcmp(r->src, src, sizeof(*r->src)) == 0)
355aa9f7a4dSmpi return (-1);
356aa9f7a4dSmpi
357aa9f7a4dSmpi TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
358aa9f7a4dSmpi if (r2->src == NULL)
359aa9f7a4dSmpi continue;
360aa9f7a4dSmpi if (memcmp(r2->src, src, sizeof(*r->src)) == 0)
361aa9f7a4dSmpi return (-1);
362aa9f7a4dSmpi }
363aa9f7a4dSmpi
364aa9f7a4dSmpi return (0);
365aa9f7a4dSmpi }
366aa9f7a4dSmpi
367aa9f7a4dSmpi /*
368aa9f7a4dSmpi * Return 0 if ``r'' or its merged entries contain ``dst'', -1 otherwise.
369aa9f7a4dSmpi */
370aa9f7a4dSmpi int
ipsecctl_rule_matchdst(struct ipsec_rule * r,struct ipsec_addr_wrap * dst)371aa9f7a4dSmpi ipsecctl_rule_matchdst(struct ipsec_rule *r, struct ipsec_addr_wrap *dst)
372aa9f7a4dSmpi {
373aa9f7a4dSmpi struct ipsec_rule *r2;
374aa9f7a4dSmpi
375aa9f7a4dSmpi if (memcmp(r->dst, dst, sizeof(*r->dst)) == 0)
376aa9f7a4dSmpi return (-1);
377aa9f7a4dSmpi
378aa9f7a4dSmpi TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
379aa9f7a4dSmpi if (r2->dst == NULL)
380aa9f7a4dSmpi continue;
381aa9f7a4dSmpi if (memcmp(r2->dst, dst, sizeof(*r->dst)) == 0)
382aa9f7a4dSmpi return (-1);
383aa9f7a4dSmpi }
384aa9f7a4dSmpi
385aa9f7a4dSmpi return (0);
386aa9f7a4dSmpi }
387aa9f7a4dSmpi
388f484f2cfShshoexer void
ipsecctl_print_addr(struct ipsec_addr_wrap * ipa)38991f765ddShshoexer ipsecctl_print_addr(struct ipsec_addr_wrap *ipa)
390f484f2cfShshoexer {
39191f765ddShshoexer int bits;
392712e78baShshoexer char buf[NI_MAXHOST];
393f484f2cfShshoexer
394f484f2cfShshoexer if (ipa == NULL) {
395f484f2cfShshoexer printf("?");
396f484f2cfShshoexer return;
397f484f2cfShshoexer }
398712e78baShshoexer if (inet_ntop(ipa->af, &ipa->address, buf, sizeof(buf)) == NULL)
399f484f2cfShshoexer printf("?");
400f484f2cfShshoexer else
401f484f2cfShshoexer printf("%s", buf);
402f484f2cfShshoexer
403eaa84e12Skn bits = unmask(&ipa->mask);
40491f765ddShshoexer if (bits != (ipa->af == AF_INET ? 32 : 128))
40591f765ddShshoexer printf("/%d", bits);
406f484f2cfShshoexer }
407f484f2cfShshoexer
408f484f2cfShshoexer void
ipsecctl_print_proto(u_int8_t proto)4099182219dSmarkus ipsecctl_print_proto(u_int8_t proto)
4109182219dSmarkus {
4119182219dSmarkus struct protoent *p;
4129182219dSmarkus
4139182219dSmarkus if ((p = getprotobynumber(proto)) != NULL)
4149182219dSmarkus printf("%s", p->p_name);
4159182219dSmarkus else
4169182219dSmarkus printf("%u", proto);
4179182219dSmarkus }
4189182219dSmarkus
4199182219dSmarkus void
ipsecctl_print_port(u_int16_t port,const char * proto)42057f58d0dSnaddy ipsecctl_print_port(u_int16_t port, const char *proto)
42157f58d0dSnaddy {
42257f58d0dSnaddy struct servent *s;
42357f58d0dSnaddy
42457f58d0dSnaddy if ((s = getservbyport(port, proto)) != NULL)
42557f58d0dSnaddy printf("%s", s->s_name);
42657f58d0dSnaddy else
42757f58d0dSnaddy printf("%u", ntohs(port));
42857f58d0dSnaddy }
42957f58d0dSnaddy
43057f58d0dSnaddy void
ipsecctl_print_key(struct ipsec_key * key)431110db5a9Shshoexer ipsecctl_print_key(struct ipsec_key *key)
432f484f2cfShshoexer {
433110db5a9Shshoexer int i;
434f484f2cfShshoexer
435110db5a9Shshoexer for (i = 0; i < (int)key->len; i++)
436110db5a9Shshoexer printf("%02x", key->data[i]);
437110db5a9Shshoexer }
438f484f2cfShshoexer
439110db5a9Shshoexer void
ipsecctl_print_flow(struct ipsec_rule * r,int opts)440110db5a9Shshoexer ipsecctl_print_flow(struct ipsec_rule *r, int opts)
441110db5a9Shshoexer {
442aa9f7a4dSmpi struct ipsec_rule *r2;
443aa9f7a4dSmpi
4449182219dSmarkus printf("flow %s %s", satype[r->satype], direction[r->direction]);
445110db5a9Shshoexer
4469182219dSmarkus if (r->proto) {
4479182219dSmarkus printf(" proto ");
4489182219dSmarkus ipsecctl_print_proto(r->proto);
4499182219dSmarkus }
450f484f2cfShshoexer printf(" from ");
451aa9f7a4dSmpi if (opts & IPSECCTL_OPT_COLLAPSE) {
452aa9f7a4dSmpi printf("{ ");
453aa9f7a4dSmpi ipsecctl_print_addr(r->src);
454aa9f7a4dSmpi TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
455aa9f7a4dSmpi if (r2->src == NULL)
456aa9f7a4dSmpi continue;
457aa9f7a4dSmpi printf(", ");
458aa9f7a4dSmpi ipsecctl_print_addr(r2->src);
459aa9f7a4dSmpi }
460aa9f7a4dSmpi printf(" }");
461aa9f7a4dSmpi } else
462f484f2cfShshoexer ipsecctl_print_addr(r->src);
46357f58d0dSnaddy if (r->sport) {
46457f58d0dSnaddy printf(" port ");
46557f58d0dSnaddy ipsecctl_print_port(r->sport,
46657f58d0dSnaddy r->proto == IPPROTO_TCP ? "tcp" : "udp");
46757f58d0dSnaddy }
468f484f2cfShshoexer printf(" to ");
469aa9f7a4dSmpi if (opts & IPSECCTL_OPT_COLLAPSE) {
470aa9f7a4dSmpi printf("{ ");
471aa9f7a4dSmpi ipsecctl_print_addr(r->dst);
472aa9f7a4dSmpi TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
473aa9f7a4dSmpi if (r2->dst == NULL)
474aa9f7a4dSmpi continue;
475aa9f7a4dSmpi printf(", ");
476aa9f7a4dSmpi ipsecctl_print_addr(r2->dst);
477aa9f7a4dSmpi }
478aa9f7a4dSmpi printf(" }");
479aa9f7a4dSmpi } else
480f484f2cfShshoexer ipsecctl_print_addr(r->dst);
48157f58d0dSnaddy if (r->dport) {
48257f58d0dSnaddy printf(" port ");
48357f58d0dSnaddy ipsecctl_print_port(r->dport,
48457f58d0dSnaddy r->proto == IPPROTO_TCP ? "tcp" : "udp");
48557f58d0dSnaddy }
486435bb41eSmarkus if (r->local) {
487435bb41eSmarkus printf(" local ");
488435bb41eSmarkus ipsecctl_print_addr(r->local);
489435bb41eSmarkus }
4904c98b117Shshoexer if (r->peer) {
491f484f2cfShshoexer printf(" peer ");
492f484f2cfShshoexer ipsecctl_print_addr(r->peer);
4934c98b117Shshoexer }
4949382ed8fShshoexer if (r->auth) {
495abe65127Shshoexer if (r->auth->srcid)
496378cce75Shshoexer printf(" srcid %s", r->auth->srcid);
497abe65127Shshoexer if (r->auth->dstid)
498378cce75Shshoexer printf(" dstid %s", r->auth->dstid);
499abe65127Shshoexer if (r->auth->type > 0)
500378cce75Shshoexer printf(" %s", auth[r->auth->type]);
5019382ed8fShshoexer }
502378cce75Shshoexer printf(" type %s", flowtype[r->flowtype]);
50390bd57a7Shshoexer printf("\n");
504110db5a9Shshoexer }
505110db5a9Shshoexer
506110db5a9Shshoexer void
ipsecctl_print_sa(struct ipsec_rule * r,int opts)507110db5a9Shshoexer ipsecctl_print_sa(struct ipsec_rule *r, int opts)
508110db5a9Shshoexer {
5099182219dSmarkus printf("%s ", satype[r->satype]);
510ef9c0cabSmikeb /* tunnel/transport is only meaningful for esp/ah/ipcomp */
5119182219dSmarkus if (r->satype != IPSEC_TCPMD5 && r->satype != IPSEC_IPIP)
512a38d220fShshoexer printf("%s ", tmode[r->tmode]);
513110db5a9Shshoexer printf("from ");
514110db5a9Shshoexer ipsecctl_print_addr(r->src);
515110db5a9Shshoexer printf(" to ");
516110db5a9Shshoexer ipsecctl_print_addr(r->dst);
517110db5a9Shshoexer printf(" spi 0x%08x", r->spi);
5186525f06fShshoexer
5199182219dSmarkus if (r->satype != IPSEC_TCPMD5) {
520375db29dShshoexer if (r->xfs && r->xfs->authxf)
521375db29dShshoexer printf(" auth %s", r->xfs->authxf->name);
522375db29dShshoexer if (r->xfs && r->xfs->encxf)
523375db29dShshoexer printf(" enc %s", r->xfs->encxf->name);
52472e25333Shshoexer if (r->xfs && r->xfs->compxf)
52572e25333Shshoexer printf(" comp %s", r->xfs->compxf->name);
5266525f06fShshoexer }
5272cbe2c48Shshoexer if (r->authkey && (opts & IPSECCTL_OPT_SHOWKEY)) {
5289182219dSmarkus if (r->satype == IPSEC_TCPMD5)
5296525f06fShshoexer printf(" ");
5306525f06fShshoexer else
53163e1d805Smarkus printf(" \\\n\t");
532670bad1aShshoexer printf("authkey 0x");
533670bad1aShshoexer ipsecctl_print_key(r->authkey);
534110db5a9Shshoexer }
5352cbe2c48Shshoexer if (r->enckey && (opts & IPSECCTL_OPT_SHOWKEY)) {
5369182219dSmarkus if (r->satype == IPSEC_TCPMD5)
5376525f06fShshoexer printf(" ");
5386525f06fShshoexer else
53963e1d805Smarkus printf(" \\\n\t");
540381a2422Shshoexer printf("enckey 0x");
541381a2422Shshoexer ipsecctl_print_key(r->enckey);
542381a2422Shshoexer }
54390bd57a7Shshoexer printf("\n");
544c8602fa3Shshoexer }
545110db5a9Shshoexer
546110db5a9Shshoexer void
ipsecctl_print_sabundle(struct ipsec_rule * r,int opts)547a6bcba92Sbluhm ipsecctl_print_sabundle(struct ipsec_rule *r, int opts)
548b5f834c1Shshoexer {
549a6bcba92Sbluhm printf("[bundle %s to ", satype[r->proto]);
550b5f834c1Shshoexer ipsecctl_print_addr(r->dst);
551b5f834c1Shshoexer printf(" spi 0x%08x with %s to ", r->spi, satype[r->proto2]);
552b5f834c1Shshoexer ipsecctl_print_addr(r->dst2);
553b5f834c1Shshoexer printf(" spi 0x%08x", r->spi2);
554b5f834c1Shshoexer
555b5f834c1Shshoexer printf("]\n");
556b5f834c1Shshoexer }
557b5f834c1Shshoexer
558b5f834c1Shshoexer void
ipsecctl_print_rule(struct ipsec_rule * r,int opts)559110db5a9Shshoexer ipsecctl_print_rule(struct ipsec_rule *r, int opts)
560110db5a9Shshoexer {
561aa9f7a4dSmpi struct ipsec_rule *r2;
562aa9f7a4dSmpi
563aa9f7a4dSmpi if (opts & IPSECCTL_OPT_VERBOSE2) {
564110db5a9Shshoexer printf("@%d", r->nr);
565aa9f7a4dSmpi if (opts & IPSECCTL_OPT_COLLAPSE) {
566aa9f7a4dSmpi TAILQ_FOREACH(r2, &r->collapsed_rules, bundle_entry) {
567aa9f7a4dSmpi printf(",%d", r2->nr);
568aa9f7a4dSmpi }
569aa9f7a4dSmpi }
570aa9f7a4dSmpi printf(" ");
571aa9f7a4dSmpi }
572110db5a9Shshoexer
57316bc4fb7Shshoexer if (r->type & RULE_FLOW)
574110db5a9Shshoexer ipsecctl_print_flow(r, opts);
57516bc4fb7Shshoexer if (r->type & RULE_SA)
576110db5a9Shshoexer ipsecctl_print_sa(r, opts);
57790bd57a7Shshoexer if (r->type & RULE_IKE)
57890bd57a7Shshoexer ike_print_config(r, opts);
579a6bcba92Sbluhm if (r->type & RULE_BUNDLE)
580a6bcba92Sbluhm ipsecctl_print_sabundle(r, opts);
581f484f2cfShshoexer }
582f484f2cfShshoexer
583f484f2cfShshoexer int
ipsecctl_flush(int opts)584f484f2cfShshoexer ipsecctl_flush(int opts)
585f484f2cfShshoexer {
586f484f2cfShshoexer if (opts & IPSECCTL_OPT_NOACTION)
587c3324a93Skjell return (0);
588f484f2cfShshoexer
589f484f2cfShshoexer if (pfkey_init() == -1)
5900c7c92aeShshoexer errx(1, "ipsecctl_flush: failed to open PF_KEY socket");
591f484f2cfShshoexer
592b1bf2fcbShshoexer if (pfkey_ipsec_flush() == -1)
593b1bf2fcbShshoexer errx(1, "ipsecctl_flush: failed to flush");
594f484f2cfShshoexer
595c3324a93Skjell return (0);
596f484f2cfShshoexer }
597f484f2cfShshoexer
598202aab43Stobhe char *
ipsecctl_get_rules(struct ipsecctl * ipsec,size_t * need)599202aab43Stobhe ipsecctl_get_rules(struct ipsecctl *ipsec, size_t *need)
600f484f2cfShshoexer {
601f484f2cfShshoexer int mib[4];
602202aab43Stobhe char *buf;
603f484f2cfShshoexer
604f484f2cfShshoexer mib[0] = CTL_NET;
605f484f2cfShshoexer mib[1] = PF_KEY;
606f484f2cfShshoexer mib[2] = PF_KEY_V2;
607f484f2cfShshoexer mib[3] = NET_KEY_SPD_DUMP;
608f484f2cfShshoexer
609202aab43Stobhe if (sysctl(mib, 4, NULL, need, NULL, 0) == -1)
610bd828a90Shshoexer err(1, "ipsecctl_get_rules: sysctl");
611202aab43Stobhe if (*need == 0)
612202aab43Stobhe return NULL;
613202aab43Stobhe if ((buf = malloc(*need)) == NULL)
614bd828a90Shshoexer err(1, "ipsecctl_get_rules: malloc");
615202aab43Stobhe if (sysctl(mib, 4, buf, need, NULL, 0) == -1)
616bd828a90Shshoexer err(1, "ipsecctl_get_rules: sysctl");
617f484f2cfShshoexer
618202aab43Stobhe return buf;
619202aab43Stobhe }
620202aab43Stobhe
621202aab43Stobhe void
ipsecctl_parse_rules(struct ipsecctl * ipsec,char * buf,size_t need)622202aab43Stobhe ipsecctl_parse_rules(struct ipsecctl *ipsec, char *buf, size_t need)
623202aab43Stobhe {
624202aab43Stobhe struct sadb_msg *msg;
625202aab43Stobhe struct ipsec_rule *rule, *last = NULL;
626202aab43Stobhe char *lim, *next;
627202aab43Stobhe
628202aab43Stobhe lim = buf + need;
629a4e2382fShshoexer for (next = buf; next < lim; next += msg->sadb_msg_len *
630a4e2382fShshoexer PFKEYV2_CHUNK) {
631a4e2382fShshoexer msg = (struct sadb_msg *)next;
632a4e2382fShshoexer if (msg->sadb_msg_len == 0)
633a4e2382fShshoexer break;
634f484f2cfShshoexer
635f484f2cfShshoexer rule = calloc(1, sizeof(struct ipsec_rule));
636f484f2cfShshoexer if (rule == NULL)
637202aab43Stobhe err(1, "ipsecctl_parse_rules: calloc");
638f484f2cfShshoexer rule->nr = ipsec->rule_nr++;
63916bc4fb7Shshoexer rule->type |= RULE_FLOW;
640aa9f7a4dSmpi TAILQ_INIT(&rule->collapsed_rules);
641f484f2cfShshoexer
642a4e2382fShshoexer if (pfkey_parse(msg, rule))
643202aab43Stobhe errx(1, "ipsecctl_parse_rules: "
6448d007042Sreyk "failed to parse PF_KEY message");
645f484f2cfShshoexer
646aa9f7a4dSmpi /*
647aa9f7a4dSmpi * Try to collapse ``rule'' with the last enqueued rule.
648aa9f7a4dSmpi *
649aa9f7a4dSmpi * Note that comparing only the last entry works only if
650aa9f7a4dSmpi * the dump is sorted.
651aa9f7a4dSmpi */
652aa9f7a4dSmpi if ((ipsec->opts & IPSECCTL_OPT_COLLAPSE) && (last != NULL) &&
653aa9f7a4dSmpi (ipsecctl_merge_rules(last, rule) == 0))
654aa9f7a4dSmpi continue;
655aa9f7a4dSmpi
656f484f2cfShshoexer ipsecctl_add_rule(ipsec, rule);
657aa9f7a4dSmpi last = rule;
658f484f2cfShshoexer }
6598933a803Shshoexer
6608933a803Shshoexer free(buf);
661f484f2cfShshoexer }
662f484f2cfShshoexer
663f484f2cfShshoexer void
ipsecctl_print_title(char * title)6643dd59ad2Shshoexer ipsecctl_print_title(char *title)
6653dd59ad2Shshoexer {
6663dd59ad2Shshoexer if (!first_title)
6673dd59ad2Shshoexer printf("\n");
6683dd59ad2Shshoexer first_title = 0;
6693dd59ad2Shshoexer printf("%s\n", title);
6703dd59ad2Shshoexer }
6713dd59ad2Shshoexer
6723dd59ad2Shshoexer void
ipsecctl_show(int opts)673202aab43Stobhe ipsecctl_show(int opts)
674f484f2cfShshoexer {
675f484f2cfShshoexer struct ipsecctl ipsec;
676f484f2cfShshoexer struct ipsec_rule *rp;
677202aab43Stobhe struct sadb_msg *msg;
678202aab43Stobhe struct sad *sad;
679202aab43Stobhe int mib[5], sacount, i;
680202aab43Stobhe size_t need = 0, rlen;
681202aab43Stobhe char *sbuf = NULL, *rbuf = NULL, *lim, *next;
682f484f2cfShshoexer
683202aab43Stobhe if (opts & IPSECCTL_OPT_SHOWFLOWS) {
684e7a09a9bSkjell bzero(&ipsec, sizeof(ipsec));
685f484f2cfShshoexer ipsec.opts = opts;
686f484f2cfShshoexer TAILQ_INIT(&ipsec.rule_queue);
687202aab43Stobhe rbuf = ipsecctl_get_rules(&ipsec, &rlen);
688202aab43Stobhe }
689f484f2cfShshoexer
690202aab43Stobhe if (opts & IPSECCTL_OPT_SHOWSAS) {
691202aab43Stobhe mib[0] = CTL_NET;
692202aab43Stobhe mib[1] = PF_KEY;
693202aab43Stobhe mib[2] = PF_KEY_V2;
694202aab43Stobhe mib[3] = NET_KEY_SADB_DUMP;
695202aab43Stobhe mib[4] = SADB_SATYPE_UNSPEC;
696202aab43Stobhe
697202aab43Stobhe /* When the SAD is empty we get ENOENT, no need to err(). */
698202aab43Stobhe if (sysctl(mib, 5, NULL, &need, NULL, 0) == -1 &&
699202aab43Stobhe errno != ENOENT)
700202aab43Stobhe err(1, "ipsecctl_show: sysctl");
701202aab43Stobhe if (need > 0) {
702202aab43Stobhe if ((sbuf = malloc(need)) == NULL)
703202aab43Stobhe err(1, "ipsecctl_show: malloc");
704202aab43Stobhe if (sysctl(mib, 5, sbuf, &need, NULL, 0) == -1)
705202aab43Stobhe err(1, "ipsecctl_show: sysctl");
706202aab43Stobhe }
707202aab43Stobhe }
708202aab43Stobhe
709*4ecd42c0Syasuoka if (pledge("stdio dns", NULL) == -1)
710202aab43Stobhe err(1, "pledge");
711202aab43Stobhe
712202aab43Stobhe if (rbuf != NULL) {
713202aab43Stobhe ipsecctl_parse_rules(&ipsec, rbuf, rlen);
714f484f2cfShshoexer
7153dd59ad2Shshoexer if (opts & IPSECCTL_OPT_SHOWALL)
7163dd59ad2Shshoexer ipsecctl_print_title("FLOWS:");
7173dd59ad2Shshoexer
718202aab43Stobhe if (TAILQ_FIRST(&ipsec.rule_queue) != NULL) {
719f484f2cfShshoexer while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
720e48766bcShshoexer TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
721f484f2cfShshoexer
7223dd59ad2Shshoexer ipsecctl_print_rule(rp, ipsec.opts);
723f484f2cfShshoexer
72490bd57a7Shshoexer free(rp->src->name);
725f484f2cfShshoexer free(rp->src);
72690bd57a7Shshoexer free(rp->dst->name);
727f484f2cfShshoexer free(rp->dst);
728435bb41eSmarkus if (rp->local) {
729435bb41eSmarkus free(rp->local->name);
730435bb41eSmarkus free(rp->local);
731435bb41eSmarkus }
7324c98b117Shshoexer if (rp->peer) {
73390bd57a7Shshoexer free(rp->peer->name);
734f484f2cfShshoexer free(rp->peer);
7354c98b117Shshoexer }
736abe65127Shshoexer if (rp->auth) {
737abe65127Shshoexer free(rp->auth->srcid);
738abe65127Shshoexer free(rp->auth->dstid);
739abe65127Shshoexer free(rp->auth);
740abe65127Shshoexer }
741f484f2cfShshoexer free(rp);
742f484f2cfShshoexer }
743f484f2cfShshoexer }
744202aab43Stobhe } else if (opts & IPSECCTL_OPT_SHOWALL) {
745202aab43Stobhe ipsecctl_print_title("FLOWS:");
746202aab43Stobhe if (opts & IPSECCTL_OPT_SHOWALL)
747202aab43Stobhe printf("No flows\n");
748202aab43Stobhe }
749f484f2cfShshoexer
750*4ecd42c0Syasuoka if (pledge("stdio", NULL) == -1)
751*4ecd42c0Syasuoka err(1, "pledge");
752*4ecd42c0Syasuoka
753202aab43Stobhe if (sbuf != NULL) {
7543dd59ad2Shshoexer if (opts & IPSECCTL_OPT_SHOWALL)
7553044111dSho ipsecctl_print_title("SAD:");
7563dd59ad2Shshoexer
757895bd039Smarkus sacount = 0;
758202aab43Stobhe lim = sbuf + need;
759202aab43Stobhe for (next = sbuf; next < lim;
7603dd59ad2Shshoexer next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
7613dd59ad2Shshoexer msg = (struct sadb_msg *)next;
7623dd59ad2Shshoexer if (msg->sadb_msg_len == 0)
7633dd59ad2Shshoexer break;
764895bd039Smarkus sacount++;
7653dd59ad2Shshoexer }
766895bd039Smarkus if ((sad = calloc(sacount, sizeof(*sad))) == NULL)
767202aab43Stobhe err(1, "ipsecctl_show: calloc");
768895bd039Smarkus i = 0;
769202aab43Stobhe for (next = sbuf; next < lim;
770895bd039Smarkus next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
771895bd039Smarkus msg = (struct sadb_msg *)next;
772895bd039Smarkus if (msg->sadb_msg_len == 0)
773895bd039Smarkus break;
774895bd039Smarkus sad[i].sad_spi = pfkey_get_spi(msg);
775895bd039Smarkus sad[i].sad_msg = msg;
776895bd039Smarkus i++;
777895bd039Smarkus }
778895bd039Smarkus qsort(sad, sacount, sizeof(*sad), sacompare);
779895bd039Smarkus for (i = 0; i < sacount; i++)
780895bd039Smarkus pfkey_print_sa(sad[i].sad_msg, opts);
781895bd039Smarkus free(sad);
782202aab43Stobhe free(sbuf);
783202aab43Stobhe } else if (opts & IPSECCTL_OPT_SHOWALL) {
784202aab43Stobhe ipsecctl_print_title("SAD:");
785202aab43Stobhe printf("No entries\n");
786202aab43Stobhe }
7873dd59ad2Shshoexer }
7883dd59ad2Shshoexer
7898a87fca6Smsf int
ipsecctl_monitor(int opts)7908a87fca6Smsf ipsecctl_monitor(int opts)
7918a87fca6Smsf {
7928a87fca6Smsf return (pfkey_monitor(opts));
7938a87fca6Smsf }
7948a87fca6Smsf
795f484f2cfShshoexer __dead void
usage(void)796f484f2cfShshoexer usage(void)
797f484f2cfShshoexer {
798f484f2cfShshoexer extern char *__progname;
799f484f2cfShshoexer
800aa9f7a4dSmpi fprintf(stderr, "usage: %s [-cdFkmnv] [-D macro=value] [-f file]"
8013d7fea66Sjmc " [-i fifo] [-s modifier]\n", __progname);
802f484f2cfShshoexer exit(1);
803f484f2cfShshoexer }
804f484f2cfShshoexer
8053dd59ad2Shshoexer const char *
ipsecctl_lookup_option(char * cmd,const char ** list)8063dd59ad2Shshoexer ipsecctl_lookup_option(char *cmd, const char **list)
8073dd59ad2Shshoexer {
8083dd59ad2Shshoexer if (cmd != NULL && *cmd)
8093dd59ad2Shshoexer for (; *list; list++)
8103dd59ad2Shshoexer if (!strncmp(cmd, *list, strlen(cmd)))
8113dd59ad2Shshoexer return (*list);
8123dd59ad2Shshoexer return (NULL);
8133dd59ad2Shshoexer }
8143dd59ad2Shshoexer
815f484f2cfShshoexer int
main(int argc,char * argv[])816f484f2cfShshoexer main(int argc, char *argv[])
817f484f2cfShshoexer {
818f484f2cfShshoexer int error = 0;
819f484f2cfShshoexer int ch;
820f484f2cfShshoexer int opts = 0;
821f484f2cfShshoexer char *rulesopt = NULL;
822f484f2cfShshoexer
823f484f2cfShshoexer if (argc < 2)
824f484f2cfShshoexer usage();
825f484f2cfShshoexer
826aa9f7a4dSmpi while ((ch = getopt(argc, argv, "cD:df:Fi:kmnvs:")) != -1) {
827f484f2cfShshoexer switch (ch) {
828aa9f7a4dSmpi case 'c':
829aa9f7a4dSmpi opts |= IPSECCTL_OPT_COLLAPSE;
830aa9f7a4dSmpi break;
831aa9f7a4dSmpi
8323d351c90Sreyk case 'D':
8333d351c90Sreyk if (cmdline_symset(optarg) < 0)
8343d351c90Sreyk warnx("could not parse macro definition %s",
8353d351c90Sreyk optarg);
8363d351c90Sreyk break;
8373cb2a986Smarkus
8386d01698dShshoexer case 'd':
8396d01698dShshoexer opts |= IPSECCTL_OPT_DELETE;
8406d01698dShshoexer break;
8413cb2a986Smarkus
842f484f2cfShshoexer case 'f':
843f484f2cfShshoexer rulesopt = optarg;
844f484f2cfShshoexer break;
845f484f2cfShshoexer
846f484f2cfShshoexer case 'F':
847f484f2cfShshoexer opts |= IPSECCTL_OPT_FLUSH;
848f484f2cfShshoexer break;
849f484f2cfShshoexer
850f8738d8bShenning case 'i':
851f8738d8bShenning isakmpd_fifo = optarg;
852f8738d8bShenning break;
853f8738d8bShenning
8543cb2a986Smarkus case 'k':
8553cb2a986Smarkus opts |= IPSECCTL_OPT_SHOWKEY;
8563cb2a986Smarkus break;
8573cb2a986Smarkus
8588a87fca6Smsf case 'm':
8598a87fca6Smsf opts |= IPSECCTL_OPT_MONITOR;
8608a87fca6Smsf break;
8618a87fca6Smsf
862f484f2cfShshoexer case 'n':
863f484f2cfShshoexer opts |= IPSECCTL_OPT_NOACTION;
864f484f2cfShshoexer break;
865f484f2cfShshoexer
866f484f2cfShshoexer case 'v':
867f484f2cfShshoexer if (opts & IPSECCTL_OPT_VERBOSE)
868f484f2cfShshoexer opts |= IPSECCTL_OPT_VERBOSE2;
869f484f2cfShshoexer opts |= IPSECCTL_OPT_VERBOSE;
870f484f2cfShshoexer break;
871f484f2cfShshoexer
872f484f2cfShshoexer case 's':
8733dd59ad2Shshoexer showopt = ipsecctl_lookup_option(optarg, showopt_list);
8743dd59ad2Shshoexer if (showopt == NULL) {
8753dd59ad2Shshoexer warnx("Unknown show modifier '%s'", optarg);
8763dd59ad2Shshoexer usage();
8773dd59ad2Shshoexer /* NOTREACHED */
8783dd59ad2Shshoexer }
879f484f2cfShshoexer opts |= IPSECCTL_OPT_SHOW;
880f484f2cfShshoexer break;
881f484f2cfShshoexer
882f484f2cfShshoexer default:
883f484f2cfShshoexer usage();
884f484f2cfShshoexer /* NOTREACHED */
885f484f2cfShshoexer }
886f484f2cfShshoexer }
887f484f2cfShshoexer
888f484f2cfShshoexer if (argc != optind) {
889f484f2cfShshoexer warnx("unknown command line argument: %s ...", argv[optind]);
890f484f2cfShshoexer usage();
891f484f2cfShshoexer /* NOTREACHED */
892f484f2cfShshoexer }
893f484f2cfShshoexer if (opts & IPSECCTL_OPT_FLUSH)
894f484f2cfShshoexer if (ipsecctl_flush(opts))
895f484f2cfShshoexer error = 1;
896f484f2cfShshoexer
897f484f2cfShshoexer if (rulesopt != NULL)
898f484f2cfShshoexer if (ipsecctl_rules(rulesopt, opts))
899f484f2cfShshoexer error = 1;
900f484f2cfShshoexer
9013dd59ad2Shshoexer if (showopt != NULL) {
9023dd59ad2Shshoexer switch (*showopt) {
9033dd59ad2Shshoexer case 'f':
904202aab43Stobhe opts |= IPSECCTL_OPT_SHOWFLOWS;
9053dd59ad2Shshoexer break;
9063dd59ad2Shshoexer case 's':
907202aab43Stobhe opts |= IPSECCTL_OPT_SHOWSAS;
9083dd59ad2Shshoexer break;
9093dd59ad2Shshoexer case 'a':
910202aab43Stobhe opts |= IPSECCTL_OPT_SHOWFLOWS;
911202aab43Stobhe opts |= IPSECCTL_OPT_SHOWSAS;
9123dd59ad2Shshoexer opts |= IPSECCTL_OPT_SHOWALL;
913202aab43Stobhe break;
9143dd59ad2Shshoexer }
915202aab43Stobhe ipsecctl_show(opts);
9163dd59ad2Shshoexer }
917f484f2cfShshoexer
9188a87fca6Smsf if (opts & IPSECCTL_OPT_MONITOR)
9198a87fca6Smsf if (ipsecctl_monitor(opts))
9208a87fca6Smsf error = 1;
9218a87fca6Smsf
922f484f2cfShshoexer exit(error);
923f484f2cfShshoexer }
92491f765ddShshoexer
92591f765ddShshoexer static int
unmask(struct ipsec_addr * ipa)926eaa84e12Skn unmask(struct ipsec_addr *ipa)
92791f765ddShshoexer {
92891f765ddShshoexer int i = 31, j = 0, b = 0;
92991f765ddShshoexer u_int32_t tmp;
93091f765ddShshoexer
93191f765ddShshoexer while (j < 4 && ipa->addr32[j] == 0xffffffff) {
93291f765ddShshoexer b += 32;
93391f765ddShshoexer j++;
93491f765ddShshoexer }
93591f765ddShshoexer if (j < 4) {
93691f765ddShshoexer tmp = ntohl(ipa->addr32[j]);
93791f765ddShshoexer for (i = 31; tmp & (1 << i); --i)
93891f765ddShshoexer b++;
93991f765ddShshoexer }
94091f765ddShshoexer return (b);
94191f765ddShshoexer }
942