1*b899bfd9Srmind /*-
2*b899bfd9Srmind * Copyright (c) 2009-2020 The NetBSD Foundation, Inc.
3*b899bfd9Srmind * All rights reserved.
4*b899bfd9Srmind *
5*b899bfd9Srmind * This material is based upon work partially supported by The
6*b899bfd9Srmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
7*b899bfd9Srmind *
8*b899bfd9Srmind * Redistribution and use in source and binary forms, with or without
9*b899bfd9Srmind * modification, are permitted provided that the following conditions
10*b899bfd9Srmind * are met:
11*b899bfd9Srmind * 1. Redistributions of source code must retain the above copyright
12*b899bfd9Srmind * notice, this list of conditions and the following disclaimer.
13*b899bfd9Srmind * 2. Redistributions in binary form must reproduce the above copyright
14*b899bfd9Srmind * notice, this list of conditions and the following disclaimer in the
15*b899bfd9Srmind * documentation and/or other materials provided with the distribution.
16*b899bfd9Srmind *
17*b899bfd9Srmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18*b899bfd9Srmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19*b899bfd9Srmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20*b899bfd9Srmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21*b899bfd9Srmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*b899bfd9Srmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*b899bfd9Srmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*b899bfd9Srmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*b899bfd9Srmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*b899bfd9Srmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*b899bfd9Srmind * POSSIBILITY OF SUCH DAMAGE.
28*b899bfd9Srmind */
29*b899bfd9Srmind
30*b899bfd9Srmind #include <sys/cdefs.h>
31*b899bfd9Srmind __RCSID("$NetBSD: npf_cmd.c,v 1.1 2020/05/30 14:16:56 rmind Exp $");
32*b899bfd9Srmind
33*b899bfd9Srmind #include <stdio.h>
34*b899bfd9Srmind #include <string.h>
35*b899bfd9Srmind #include <stdlib.h>
36*b899bfd9Srmind #include <unistd.h>
37*b899bfd9Srmind #include <errno.h>
38*b899bfd9Srmind #include <err.h>
39*b899bfd9Srmind
40*b899bfd9Srmind #ifdef __NetBSD__
41*b899bfd9Srmind #include <sha1.h>
42*b899bfd9Srmind #define SHA_DIGEST_LENGTH SHA1_DIGEST_LENGTH
43*b899bfd9Srmind #else
44*b899bfd9Srmind #include <openssl/sha.h>
45*b899bfd9Srmind #endif
46*b899bfd9Srmind
47*b899bfd9Srmind #include "npfctl.h"
48*b899bfd9Srmind
49*b899bfd9Srmind ////////////////////////////////////////////////////////////////////////////
50*b899bfd9Srmind //
51*b899bfd9Srmind // NPFCTL RULE COMMANDS
52*b899bfd9Srmind //
53*b899bfd9Srmind
54*b899bfd9Srmind #ifdef __NetBSD__
55*b899bfd9Srmind static unsigned char *
SHA1(const unsigned char * d,size_t l,unsigned char * md)56*b899bfd9Srmind SHA1(const unsigned char *d, size_t l, unsigned char *md)
57*b899bfd9Srmind {
58*b899bfd9Srmind SHA1_CTX c;
59*b899bfd9Srmind
60*b899bfd9Srmind SHA1Init(&c);
61*b899bfd9Srmind SHA1Update(&c, d, l);
62*b899bfd9Srmind SHA1Final(md, &c);
63*b899bfd9Srmind return md;
64*b899bfd9Srmind }
65*b899bfd9Srmind #endif
66*b899bfd9Srmind
67*b899bfd9Srmind static void
npfctl_generate_key(nl_rule_t * rl,void * key)68*b899bfd9Srmind npfctl_generate_key(nl_rule_t *rl, void *key)
69*b899bfd9Srmind {
70*b899bfd9Srmind void *meta;
71*b899bfd9Srmind size_t len;
72*b899bfd9Srmind
73*b899bfd9Srmind if ((meta = npf_rule_export(rl, &len)) == NULL) {
74*b899bfd9Srmind errx(EXIT_FAILURE, "error generating rule key");
75*b899bfd9Srmind }
76*b899bfd9Srmind __CTASSERT(NPF_RULE_MAXKEYLEN >= SHA_DIGEST_LENGTH);
77*b899bfd9Srmind memset(key, 0, NPF_RULE_MAXKEYLEN);
78*b899bfd9Srmind SHA1(meta, len, key);
79*b899bfd9Srmind free(meta);
80*b899bfd9Srmind }
81*b899bfd9Srmind
82*b899bfd9Srmind int
npfctl_nat_ruleset_p(const char * name,bool * natset)83*b899bfd9Srmind npfctl_nat_ruleset_p(const char *name, bool *natset)
84*b899bfd9Srmind {
85*b899bfd9Srmind const size_t preflen = sizeof(NPF_RULESET_MAP_PREF) - 1;
86*b899bfd9Srmind *natset = strncmp(name, NPF_RULESET_MAP_PREF, preflen) == 0;
87*b899bfd9Srmind return (*natset && strlen(name) <= preflen) ? -1 : 0;
88*b899bfd9Srmind }
89*b899bfd9Srmind
90*b899bfd9Srmind static nl_rule_t *
npfctl_parse_rule(int argc,char ** argv,parse_entry_t entry)91*b899bfd9Srmind npfctl_parse_rule(int argc, char **argv, parse_entry_t entry)
92*b899bfd9Srmind {
93*b899bfd9Srmind char rule_string[1024];
94*b899bfd9Srmind nl_rule_t *rl;
95*b899bfd9Srmind
96*b899bfd9Srmind /* Get the rule string and parse it. */
97*b899bfd9Srmind if (!join(rule_string, sizeof(rule_string), argc, argv, " ")) {
98*b899bfd9Srmind errx(EXIT_FAILURE, "command too long");
99*b899bfd9Srmind }
100*b899bfd9Srmind npfctl_parse_string(rule_string, entry);
101*b899bfd9Srmind if ((rl = npfctl_rule_ref()) == NULL) {
102*b899bfd9Srmind errx(EXIT_FAILURE, "could not parse the rule");
103*b899bfd9Srmind }
104*b899bfd9Srmind return rl;
105*b899bfd9Srmind }
106*b899bfd9Srmind
107*b899bfd9Srmind void
npfctl_rule(int fd,int argc,char ** argv)108*b899bfd9Srmind npfctl_rule(int fd, int argc, char **argv)
109*b899bfd9Srmind {
110*b899bfd9Srmind static const struct ruleops_s {
111*b899bfd9Srmind const char * cmd;
112*b899bfd9Srmind int action;
113*b899bfd9Srmind bool extra_arg;
114*b899bfd9Srmind } ruleops[] = {
115*b899bfd9Srmind { "add", NPF_CMD_RULE_ADD, true },
116*b899bfd9Srmind { "rem", NPF_CMD_RULE_REMKEY, true },
117*b899bfd9Srmind { "del", NPF_CMD_RULE_REMKEY, true },
118*b899bfd9Srmind { "rem-id", NPF_CMD_RULE_REMOVE, true },
119*b899bfd9Srmind { "list", NPF_CMD_RULE_LIST, false },
120*b899bfd9Srmind { "flush", NPF_CMD_RULE_FLUSH, false },
121*b899bfd9Srmind { NULL, 0, 0 }
122*b899bfd9Srmind };
123*b899bfd9Srmind uint8_t key[NPF_RULE_MAXKEYLEN];
124*b899bfd9Srmind const char *ruleset_name = argv[0];
125*b899bfd9Srmind const char *cmd = argv[1];
126*b899bfd9Srmind int error, action = 0;
127*b899bfd9Srmind bool extra_arg, natset;
128*b899bfd9Srmind parse_entry_t entry;
129*b899bfd9Srmind uint64_t rule_id;
130*b899bfd9Srmind nl_rule_t *rl;
131*b899bfd9Srmind
132*b899bfd9Srmind for (unsigned n = 0; ruleops[n].cmd != NULL; n++) {
133*b899bfd9Srmind if (strcmp(cmd, ruleops[n].cmd) == 0) {
134*b899bfd9Srmind action = ruleops[n].action;
135*b899bfd9Srmind extra_arg = ruleops[n].extra_arg;
136*b899bfd9Srmind break;
137*b899bfd9Srmind }
138*b899bfd9Srmind }
139*b899bfd9Srmind argc -= 2;
140*b899bfd9Srmind argv += 2;
141*b899bfd9Srmind
142*b899bfd9Srmind if (!action || (extra_arg && argc == 0)) {
143*b899bfd9Srmind usage();
144*b899bfd9Srmind }
145*b899bfd9Srmind
146*b899bfd9Srmind if (npfctl_nat_ruleset_p(ruleset_name, &natset) != 0) {
147*b899bfd9Srmind errx(EXIT_FAILURE,
148*b899bfd9Srmind "invalid NAT ruleset name (note: the name must be "
149*b899bfd9Srmind "prefixed with `" NPF_RULESET_MAP_PREF "`)");
150*b899bfd9Srmind }
151*b899bfd9Srmind entry = natset ? NPFCTL_PARSE_MAP : NPFCTL_PARSE_RULE;
152*b899bfd9Srmind
153*b899bfd9Srmind switch (action) {
154*b899bfd9Srmind case NPF_CMD_RULE_ADD:
155*b899bfd9Srmind rl = npfctl_parse_rule(argc, argv, entry);
156*b899bfd9Srmind npfctl_generate_key(rl, key);
157*b899bfd9Srmind npf_rule_setkey(rl, key, sizeof(key));
158*b899bfd9Srmind error = npf_ruleset_add(fd, ruleset_name, rl, &rule_id);
159*b899bfd9Srmind break;
160*b899bfd9Srmind case NPF_CMD_RULE_REMKEY:
161*b899bfd9Srmind rl = npfctl_parse_rule(argc, argv, entry);
162*b899bfd9Srmind npfctl_generate_key(rl, key);
163*b899bfd9Srmind error = npf_ruleset_remkey(fd, ruleset_name, key, sizeof(key));
164*b899bfd9Srmind break;
165*b899bfd9Srmind case NPF_CMD_RULE_REMOVE:
166*b899bfd9Srmind rule_id = strtoull(argv[0], NULL, 16);
167*b899bfd9Srmind error = npf_ruleset_remove(fd, ruleset_name, rule_id);
168*b899bfd9Srmind break;
169*b899bfd9Srmind case NPF_CMD_RULE_LIST:
170*b899bfd9Srmind error = npfctl_ruleset_show(fd, ruleset_name);
171*b899bfd9Srmind break;
172*b899bfd9Srmind case NPF_CMD_RULE_FLUSH:
173*b899bfd9Srmind error = npf_ruleset_flush(fd, ruleset_name);
174*b899bfd9Srmind break;
175*b899bfd9Srmind default:
176*b899bfd9Srmind abort();
177*b899bfd9Srmind }
178*b899bfd9Srmind
179*b899bfd9Srmind switch (error) {
180*b899bfd9Srmind case 0:
181*b899bfd9Srmind /* Success. */
182*b899bfd9Srmind break;
183*b899bfd9Srmind case ESRCH:
184*b899bfd9Srmind errx(EXIT_FAILURE, "ruleset \"%s\" not found", ruleset_name);
185*b899bfd9Srmind case ENOENT:
186*b899bfd9Srmind errx(EXIT_FAILURE, "rule was not found");
187*b899bfd9Srmind default:
188*b899bfd9Srmind errx(EXIT_FAILURE, "rule operation: %s", strerror(error));
189*b899bfd9Srmind }
190*b899bfd9Srmind if (action == NPF_CMD_RULE_ADD) {
191*b899bfd9Srmind printf("OK %" PRIx64 "\n", rule_id);
192*b899bfd9Srmind }
193*b899bfd9Srmind }
194*b899bfd9Srmind
195*b899bfd9Srmind ////////////////////////////////////////////////////////////////////////////
196*b899bfd9Srmind //
197*b899bfd9Srmind // NPFCTL TABLE COMMANDS
198*b899bfd9Srmind //
199*b899bfd9Srmind
200*b899bfd9Srmind static int
npfctl_table_type(const char * typename)201*b899bfd9Srmind npfctl_table_type(const char *typename)
202*b899bfd9Srmind {
203*b899bfd9Srmind static const struct tbltype_s {
204*b899bfd9Srmind const char * name;
205*b899bfd9Srmind unsigned type;
206*b899bfd9Srmind } tbltypes[] = {
207*b899bfd9Srmind { "ipset", NPF_TABLE_IPSET },
208*b899bfd9Srmind { "lpm", NPF_TABLE_LPM },
209*b899bfd9Srmind { "const", NPF_TABLE_CONST },
210*b899bfd9Srmind { NULL, 0 }
211*b899bfd9Srmind };
212*b899bfd9Srmind
213*b899bfd9Srmind for (unsigned i = 0; tbltypes[i].name != NULL; i++) {
214*b899bfd9Srmind if (strcmp(typename, tbltypes[i].name) == 0) {
215*b899bfd9Srmind return tbltypes[i].type;
216*b899bfd9Srmind }
217*b899bfd9Srmind }
218*b899bfd9Srmind return 0;
219*b899bfd9Srmind }
220*b899bfd9Srmind
221*b899bfd9Srmind void
npfctl_table_replace(int fd,int argc,char ** argv)222*b899bfd9Srmind npfctl_table_replace(int fd, int argc, char **argv)
223*b899bfd9Srmind {
224*b899bfd9Srmind const char *name, *newname, *path, *typename = NULL;
225*b899bfd9Srmind nl_config_t *ncf;
226*b899bfd9Srmind nl_table_t *t;
227*b899bfd9Srmind unsigned type = 0;
228*b899bfd9Srmind int c, tid = -1;
229*b899bfd9Srmind FILE *fp;
230*b899bfd9Srmind
231*b899bfd9Srmind name = newname = argv[0];
232*b899bfd9Srmind optind = 2;
233*b899bfd9Srmind while ((c = getopt(argc, argv, "n:t:")) != -1) {
234*b899bfd9Srmind switch (c) {
235*b899bfd9Srmind case 't':
236*b899bfd9Srmind typename = optarg;
237*b899bfd9Srmind break;
238*b899bfd9Srmind case 'n':
239*b899bfd9Srmind newname = optarg;
240*b899bfd9Srmind break;
241*b899bfd9Srmind default:
242*b899bfd9Srmind errx(EXIT_FAILURE,
243*b899bfd9Srmind "Usage: %s table \"table-name\" replace "
244*b899bfd9Srmind "[-n \"name\"] [-t <type>] <table-file>\n",
245*b899bfd9Srmind getprogname());
246*b899bfd9Srmind }
247*b899bfd9Srmind }
248*b899bfd9Srmind argc -= optind;
249*b899bfd9Srmind argv += optind;
250*b899bfd9Srmind
251*b899bfd9Srmind if (typename && (type = npfctl_table_type(typename)) == 0) {
252*b899bfd9Srmind errx(EXIT_FAILURE, "unsupported table type '%s'", typename);
253*b899bfd9Srmind }
254*b899bfd9Srmind
255*b899bfd9Srmind if (argc != 1) {
256*b899bfd9Srmind usage();
257*b899bfd9Srmind }
258*b899bfd9Srmind
259*b899bfd9Srmind path = argv[0];
260*b899bfd9Srmind if (strcmp(path, "-") == 0) {
261*b899bfd9Srmind path = "stdin";
262*b899bfd9Srmind fp = stdin;
263*b899bfd9Srmind } else if ((fp = fopen(path, "r")) == NULL) {
264*b899bfd9Srmind err(EXIT_FAILURE, "open '%s'", path);
265*b899bfd9Srmind }
266*b899bfd9Srmind
267*b899bfd9Srmind /* Get existing config to lookup ID of existing table */
268*b899bfd9Srmind if ((ncf = npf_config_retrieve(fd)) == NULL) {
269*b899bfd9Srmind err(EXIT_FAILURE, "npf_config_retrieve()");
270*b899bfd9Srmind }
271*b899bfd9Srmind if ((t = npfctl_table_getbyname(ncf, name)) == NULL) {
272*b899bfd9Srmind errx(EXIT_FAILURE,
273*b899bfd9Srmind "table '%s' not found in the active configuration", name);
274*b899bfd9Srmind }
275*b899bfd9Srmind tid = npf_table_getid(t);
276*b899bfd9Srmind if (!type) {
277*b899bfd9Srmind type = npf_table_gettype(t);
278*b899bfd9Srmind }
279*b899bfd9Srmind npf_config_destroy(ncf);
280*b899bfd9Srmind
281*b899bfd9Srmind if ((t = npfctl_load_table(newname, tid, type, path, fp)) == NULL) {
282*b899bfd9Srmind err(EXIT_FAILURE, "table load failed");
283*b899bfd9Srmind }
284*b899bfd9Srmind
285*b899bfd9Srmind if (npf_table_replace(fd, t, NULL)) {
286*b899bfd9Srmind err(EXIT_FAILURE, "npf_table_replace(<%s>)", name);
287*b899bfd9Srmind }
288*b899bfd9Srmind }
289*b899bfd9Srmind
290*b899bfd9Srmind void
npfctl_table(int fd,int argc,char ** argv)291*b899bfd9Srmind npfctl_table(int fd, int argc, char **argv)
292*b899bfd9Srmind {
293*b899bfd9Srmind static const struct tblops_s {
294*b899bfd9Srmind const char * cmd;
295*b899bfd9Srmind int action;
296*b899bfd9Srmind } tblops[] = {
297*b899bfd9Srmind { "add", NPF_CMD_TABLE_ADD },
298*b899bfd9Srmind { "rem", NPF_CMD_TABLE_REMOVE },
299*b899bfd9Srmind { "del", NPF_CMD_TABLE_REMOVE },
300*b899bfd9Srmind { "test", NPF_CMD_TABLE_LOOKUP },
301*b899bfd9Srmind { "list", NPF_CMD_TABLE_LIST },
302*b899bfd9Srmind { "flush", NPF_CMD_TABLE_FLUSH },
303*b899bfd9Srmind { NULL, 0 }
304*b899bfd9Srmind };
305*b899bfd9Srmind npf_ioctl_table_t nct;
306*b899bfd9Srmind fam_addr_mask_t fam;
307*b899bfd9Srmind size_t buflen = 512;
308*b899bfd9Srmind char *cmd, *arg;
309*b899bfd9Srmind int n, alen;
310*b899bfd9Srmind
311*b899bfd9Srmind /* Default action is list. */
312*b899bfd9Srmind memset(&nct, 0, sizeof(npf_ioctl_table_t));
313*b899bfd9Srmind nct.nct_name = argv[0];
314*b899bfd9Srmind cmd = argv[1];
315*b899bfd9Srmind
316*b899bfd9Srmind for (n = 0; tblops[n].cmd != NULL; n++) {
317*b899bfd9Srmind if (strcmp(cmd, tblops[n].cmd) != 0) {
318*b899bfd9Srmind continue;
319*b899bfd9Srmind }
320*b899bfd9Srmind nct.nct_cmd = tblops[n].action;
321*b899bfd9Srmind break;
322*b899bfd9Srmind }
323*b899bfd9Srmind if (tblops[n].cmd == NULL) {
324*b899bfd9Srmind errx(EXIT_FAILURE, "invalid command '%s'", cmd);
325*b899bfd9Srmind }
326*b899bfd9Srmind
327*b899bfd9Srmind switch (nct.nct_cmd) {
328*b899bfd9Srmind case NPF_CMD_TABLE_LIST:
329*b899bfd9Srmind case NPF_CMD_TABLE_FLUSH:
330*b899bfd9Srmind arg = NULL;
331*b899bfd9Srmind break;
332*b899bfd9Srmind default:
333*b899bfd9Srmind if (argc < 3) {
334*b899bfd9Srmind usage();
335*b899bfd9Srmind }
336*b899bfd9Srmind arg = argv[2];
337*b899bfd9Srmind }
338*b899bfd9Srmind
339*b899bfd9Srmind again:
340*b899bfd9Srmind switch (nct.nct_cmd) {
341*b899bfd9Srmind case NPF_CMD_TABLE_LIST:
342*b899bfd9Srmind nct.nct_data.buf.buf = ecalloc(1, buflen);
343*b899bfd9Srmind nct.nct_data.buf.len = buflen;
344*b899bfd9Srmind break;
345*b899bfd9Srmind case NPF_CMD_TABLE_FLUSH:
346*b899bfd9Srmind break;
347*b899bfd9Srmind default:
348*b899bfd9Srmind if (!npfctl_parse_cidr(arg, &fam, &alen)) {
349*b899bfd9Srmind errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
350*b899bfd9Srmind }
351*b899bfd9Srmind nct.nct_data.ent.alen = alen;
352*b899bfd9Srmind memcpy(&nct.nct_data.ent.addr, &fam.fam_addr, alen);
353*b899bfd9Srmind nct.nct_data.ent.mask = fam.fam_mask;
354*b899bfd9Srmind }
355*b899bfd9Srmind
356*b899bfd9Srmind if (ioctl(fd, IOC_NPF_TABLE, &nct) != -1) {
357*b899bfd9Srmind errno = 0;
358*b899bfd9Srmind }
359*b899bfd9Srmind switch (errno) {
360*b899bfd9Srmind case 0:
361*b899bfd9Srmind break;
362*b899bfd9Srmind case EEXIST:
363*b899bfd9Srmind errx(EXIT_FAILURE, "entry already exists or is conflicting");
364*b899bfd9Srmind case ENOENT:
365*b899bfd9Srmind errx(EXIT_FAILURE, "not found");
366*b899bfd9Srmind case EINVAL:
367*b899bfd9Srmind errx(EXIT_FAILURE, "invalid address, mask or table ID");
368*b899bfd9Srmind case ENOMEM:
369*b899bfd9Srmind if (nct.nct_cmd == NPF_CMD_TABLE_LIST) {
370*b899bfd9Srmind /* XXX */
371*b899bfd9Srmind free(nct.nct_data.buf.buf);
372*b899bfd9Srmind buflen <<= 1;
373*b899bfd9Srmind goto again;
374*b899bfd9Srmind }
375*b899bfd9Srmind /* FALLTHROUGH */
376*b899bfd9Srmind default:
377*b899bfd9Srmind err(EXIT_FAILURE, "ioctl(IOC_NPF_TABLE)");
378*b899bfd9Srmind }
379*b899bfd9Srmind
380*b899bfd9Srmind if (nct.nct_cmd == NPF_CMD_TABLE_LIST) {
381*b899bfd9Srmind npf_ioctl_ent_t *ent = nct.nct_data.buf.buf;
382*b899bfd9Srmind char *buf;
383*b899bfd9Srmind
384*b899bfd9Srmind while (nct.nct_data.buf.len--) {
385*b899bfd9Srmind if (!ent->alen)
386*b899bfd9Srmind break;
387*b899bfd9Srmind buf = npfctl_print_addrmask(ent->alen, "%a",
388*b899bfd9Srmind &ent->addr, ent->mask);
389*b899bfd9Srmind puts(buf);
390*b899bfd9Srmind ent++;
391*b899bfd9Srmind }
392*b899bfd9Srmind free(nct.nct_data.buf.buf);
393*b899bfd9Srmind } else {
394*b899bfd9Srmind printf("%s: %s\n", getprogname(),
395*b899bfd9Srmind nct.nct_cmd == NPF_CMD_TABLE_LOOKUP ?
396*b899bfd9Srmind "match" : "success");
397*b899bfd9Srmind }
398*b899bfd9Srmind }
399*b899bfd9Srmind
400*b899bfd9Srmind ////////////////////////////////////////////////////////////////////////////
401*b899bfd9Srmind //
402*b899bfd9Srmind // NPFCTL CONNECTION COMMANDS
403*b899bfd9Srmind //
404*b899bfd9Srmind
405*b899bfd9Srmind typedef struct {
406*b899bfd9Srmind FILE * fp;
407*b899bfd9Srmind unsigned alen;
408*b899bfd9Srmind const char * ifname;
409*b899bfd9Srmind bool nat;
410*b899bfd9Srmind bool nowide;
411*b899bfd9Srmind bool name;
412*b899bfd9Srmind
413*b899bfd9Srmind bool v4;
414*b899bfd9Srmind unsigned pwidth;
415*b899bfd9Srmind } npf_conn_filter_t;
416*b899bfd9Srmind
417*b899bfd9Srmind static int
npfctl_conn_print(unsigned alen,const npf_addr_t * a,const in_port_t * p,const char * ifname,void * arg)418*b899bfd9Srmind npfctl_conn_print(unsigned alen, const npf_addr_t *a, const in_port_t *p,
419*b899bfd9Srmind const char *ifname, void *arg)
420*b899bfd9Srmind {
421*b899bfd9Srmind const npf_conn_filter_t *fil = arg;
422*b899bfd9Srmind char *addrstr, *src, *dst;
423*b899bfd9Srmind const char *fmt;
424*b899bfd9Srmind FILE *fp = fil->fp;
425*b899bfd9Srmind bool nat_conn;
426*b899bfd9Srmind
427*b899bfd9Srmind /*
428*b899bfd9Srmind * Filter connection entries by IP version, interface and/or
429*b899bfd9Srmind * applicability of NAT.
430*b899bfd9Srmind */
431*b899bfd9Srmind if (alen != fil->alen) {
432*b899bfd9Srmind return 0;
433*b899bfd9Srmind }
434*b899bfd9Srmind if (fil->ifname && (!ifname || strcmp(ifname, fil->ifname) != 0)) {
435*b899bfd9Srmind return 0;
436*b899bfd9Srmind }
437*b899bfd9Srmind nat_conn = !npfctl_addr_iszero(&a[2]) || p[2] != 0;
438*b899bfd9Srmind if (fil->nat && !nat_conn) {
439*b899bfd9Srmind return 0;
440*b899bfd9Srmind }
441*b899bfd9Srmind
442*b899bfd9Srmind fmt = fil->name ? "%A" : (fil->v4 ? "%a" : "[%a]");
443*b899bfd9Srmind
444*b899bfd9Srmind addrstr = npfctl_print_addrmask(alen, fmt, &a[0], NPF_NO_NETMASK);
445*b899bfd9Srmind easprintf(&src, "%s:%d", addrstr, p[0]);
446*b899bfd9Srmind free(addrstr);
447*b899bfd9Srmind
448*b899bfd9Srmind addrstr = npfctl_print_addrmask(alen, fmt, &a[1], NPF_NO_NETMASK);
449*b899bfd9Srmind easprintf(&dst, "%s:%d", addrstr, p[1]);
450*b899bfd9Srmind free(addrstr);
451*b899bfd9Srmind
452*b899bfd9Srmind fprintf(fp, "%-*s %-*s ", fil->pwidth, src, fil->pwidth, dst);
453*b899bfd9Srmind free(src);
454*b899bfd9Srmind free(dst);
455*b899bfd9Srmind
456*b899bfd9Srmind fprintf(fp, "%-10s ", ifname ? ifname : "-");
457*b899bfd9Srmind if (nat_conn) {
458*b899bfd9Srmind addrstr = npfctl_print_addrmask(alen, fmt, &a[2], NPF_NO_NETMASK);
459*b899bfd9Srmind fprintf(fp, "%s", addrstr);
460*b899bfd9Srmind free(addrstr);
461*b899bfd9Srmind if (p[2]) {
462*b899bfd9Srmind fprintf(fp, ":%d", p[2]);
463*b899bfd9Srmind }
464*b899bfd9Srmind }
465*b899bfd9Srmind fputc('\n', fp);
466*b899bfd9Srmind return 1;
467*b899bfd9Srmind }
468*b899bfd9Srmind
469*b899bfd9Srmind static void
npf_conn_list_v(int fd,unsigned alen,npf_conn_filter_t * f)470*b899bfd9Srmind npf_conn_list_v(int fd, unsigned alen, npf_conn_filter_t *f)
471*b899bfd9Srmind {
472*b899bfd9Srmind f->alen = alen;
473*b899bfd9Srmind f->v4 = alen == sizeof(struct in_addr);
474*b899bfd9Srmind f->pwidth = f->nowide ? 0 : ((f->v4 ? 15 : 40) + 1 + 5);
475*b899bfd9Srmind if (npf_conn_list(fd, npfctl_conn_print, f) != 0) {
476*b899bfd9Srmind err(EXIT_FAILURE, "npf_conn_list");
477*b899bfd9Srmind }
478*b899bfd9Srmind }
479*b899bfd9Srmind
480*b899bfd9Srmind int
npfctl_conn_list(int fd,int argc,char ** argv)481*b899bfd9Srmind npfctl_conn_list(int fd, int argc, char **argv)
482*b899bfd9Srmind {
483*b899bfd9Srmind npf_conn_filter_t f;
484*b899bfd9Srmind bool header = true;
485*b899bfd9Srmind unsigned alen = 0;
486*b899bfd9Srmind int c;
487*b899bfd9Srmind
488*b899bfd9Srmind argc--;
489*b899bfd9Srmind argv++;
490*b899bfd9Srmind
491*b899bfd9Srmind memset(&f, 0, sizeof(f));
492*b899bfd9Srmind f.fp = stdout;
493*b899bfd9Srmind
494*b899bfd9Srmind while ((c = getopt(argc, argv, "46hi:nNW")) != -1) {
495*b899bfd9Srmind switch (c) {
496*b899bfd9Srmind case '4':
497*b899bfd9Srmind alen = sizeof(struct in_addr);
498*b899bfd9Srmind break;
499*b899bfd9Srmind case '6':
500*b899bfd9Srmind alen = sizeof(struct in6_addr);
501*b899bfd9Srmind break;
502*b899bfd9Srmind case 'h':
503*b899bfd9Srmind header = false;
504*b899bfd9Srmind break;
505*b899bfd9Srmind case 'i':
506*b899bfd9Srmind f.ifname = optarg;
507*b899bfd9Srmind break;
508*b899bfd9Srmind case 'n':
509*b899bfd9Srmind f.nat = true;
510*b899bfd9Srmind break;
511*b899bfd9Srmind case 'N':
512*b899bfd9Srmind f.name = true;
513*b899bfd9Srmind break;
514*b899bfd9Srmind case 'W':
515*b899bfd9Srmind f.nowide = true;
516*b899bfd9Srmind break;
517*b899bfd9Srmind default:
518*b899bfd9Srmind errx(EXIT_FAILURE,
519*b899bfd9Srmind "Usage: %s list [-46hnNW] [-i <ifname>]\n",
520*b899bfd9Srmind getprogname());
521*b899bfd9Srmind }
522*b899bfd9Srmind }
523*b899bfd9Srmind
524*b899bfd9Srmind if (header) {
525*b899bfd9Srmind fprintf(f.fp, "# %-*s %-*s %-*s %s\n",
526*b899bfd9Srmind 21 - 2, "src-addr:port",
527*b899bfd9Srmind 21, "dst-addr:port",
528*b899bfd9Srmind 10, "interface",
529*b899bfd9Srmind "nat-addr:port");
530*b899bfd9Srmind }
531*b899bfd9Srmind
532*b899bfd9Srmind if (!alen || alen == sizeof(struct in_addr)) {
533*b899bfd9Srmind npf_conn_list_v(fd, sizeof(struct in_addr), &f);
534*b899bfd9Srmind }
535*b899bfd9Srmind if (!alen || alen == sizeof(struct in6_addr)) {
536*b899bfd9Srmind npf_conn_list_v(fd, sizeof(struct in6_addr), &f);
537*b899bfd9Srmind }
538*b899bfd9Srmind
539*b899bfd9Srmind return 0;
540*b899bfd9Srmind }
541