xref: /netbsd-src/usr.sbin/npf/npfctl/npf_cmd.c (revision b899bfd96fd2cbaf2befc9ce4aaed9b9c230837a)
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