xref: /freebsd/sbin/ipfw/tables.c (revision 8ce7a2bc03a8e1d3a579fecc4960b610de50cbbb)
1f1220db8SAlexander V. Chernikov /*
2f1220db8SAlexander V. Chernikov  * Copyright (c) 2002-2003 Luigi Rizzo
3f1220db8SAlexander V. Chernikov  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4f1220db8SAlexander V. Chernikov  * Copyright (c) 1994 Ugen J.S.Antsilevich
5f1220db8SAlexander V. Chernikov  *
6f1220db8SAlexander V. Chernikov  * Idea and grammar partially left from:
7f1220db8SAlexander V. Chernikov  * Copyright (c) 1993 Daniel Boulet
8f1220db8SAlexander V. Chernikov  *
9f1220db8SAlexander V. Chernikov  * Redistribution and use in source forms, with and without modification,
10f1220db8SAlexander V. Chernikov  * are permitted provided that this entire comment appears intact.
11f1220db8SAlexander V. Chernikov  *
12f1220db8SAlexander V. Chernikov  * Redistribution in binary form may occur without any restrictions.
13f1220db8SAlexander V. Chernikov  * Obviously, it would be nice if you gave credit where credit is due
14f1220db8SAlexander V. Chernikov  * but requiring it would be too onerous.
15f1220db8SAlexander V. Chernikov  *
16f1220db8SAlexander V. Chernikov  * This software is provided ``AS IS'' without any warranties of any kind.
17f1220db8SAlexander V. Chernikov  *
18f1220db8SAlexander V. Chernikov  * in-kernel tables support
19f1220db8SAlexander V. Chernikov  *
20f1220db8SAlexander V. Chernikov  * $FreeBSD: projects/ipfw/sbin/ipfw/ipfw2.c 267467 2014-06-14 10:58:39Z melifaro $
21f1220db8SAlexander V. Chernikov  */
22f1220db8SAlexander V. Chernikov 
23f1220db8SAlexander V. Chernikov 
24f1220db8SAlexander V. Chernikov #include <sys/types.h>
25f1220db8SAlexander V. Chernikov #include <sys/param.h>
26f1220db8SAlexander V. Chernikov #include <sys/socket.h>
27f1220db8SAlexander V. Chernikov #include <sys/sysctl.h>
28f1220db8SAlexander V. Chernikov 
29f1220db8SAlexander V. Chernikov #include <ctype.h>
30f1220db8SAlexander V. Chernikov #include <err.h>
31f1220db8SAlexander V. Chernikov #include <errno.h>
32f1220db8SAlexander V. Chernikov #include <netdb.h>
33f1220db8SAlexander V. Chernikov #include <stddef.h>	/* offsetof */
34f1220db8SAlexander V. Chernikov #include <stdio.h>
35f1220db8SAlexander V. Chernikov #include <stdlib.h>
36f1220db8SAlexander V. Chernikov #include <string.h>
37f1220db8SAlexander V. Chernikov #include <sysexits.h>
38f1220db8SAlexander V. Chernikov 
39f1220db8SAlexander V. Chernikov #define IPFW_INTERNAL	/* Access to protected structures in ip_fw.h. */
40f1220db8SAlexander V. Chernikov 
41f1220db8SAlexander V. Chernikov #include <net/if.h>
42f1220db8SAlexander V. Chernikov #include <net/if_dl.h>
43f1220db8SAlexander V. Chernikov #include <net/route.h> /* def. of struct route */
44f1220db8SAlexander V. Chernikov #include <netinet/in.h>
45f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h>
46f1220db8SAlexander V. Chernikov #include <arpa/inet.h>
47f1220db8SAlexander V. Chernikov #include <alias.h>
48f1220db8SAlexander V. Chernikov 
49f1220db8SAlexander V. Chernikov #include "ipfw2.h"
50f1220db8SAlexander V. Chernikov 
51f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header);
52ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
53ac35ff17SAlexander V. Chernikov     int add, int update);
54ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh);
55ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh);
56ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
57ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
5881d3153dSAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
59ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
60f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
61ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
62ac35ff17SAlexander V. Chernikov     uint16_t uidx);
63f1220db8SAlexander V. Chernikov 
64f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
65f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
66f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
67f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
6881d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
69f1220db8SAlexander V. Chernikov 
70ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7181d3153dSAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
72ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
73ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
74ac35ff17SAlexander V. Chernikov 
75f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
76f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
77f1220db8SAlexander V. Chernikov 
78f1220db8SAlexander V. Chernikov #ifndef s6_addr32
79f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
80f1220db8SAlexander V. Chernikov #endif
81f1220db8SAlexander V. Chernikov 
82ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
83ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
84ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
85b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
86ac35ff17SAlexander V. Chernikov       { NULL, 0 }
87ac35ff17SAlexander V. Chernikov };
88ac35ff17SAlexander V. Chernikov 
89ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
90ac35ff17SAlexander V. Chernikov       { "dscp",		IPFW_VTYPE_DSCP },
91ac35ff17SAlexander V. Chernikov       { "ip",		IPFW_VTYPE_IP },
92ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
93ac35ff17SAlexander V. Chernikov       { NULL, 0 }
94ac35ff17SAlexander V. Chernikov };
95ac35ff17SAlexander V. Chernikov 
96ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
97ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
98ac35ff17SAlexander V. Chernikov       { "create",	TOK_CREATE },
99ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
100ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
101ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
102ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
103ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
10481d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
105ac35ff17SAlexander V. Chernikov       { NULL, 0 }
106ac35ff17SAlexander V. Chernikov };
107ac35ff17SAlexander V. Chernikov 
108f1220db8SAlexander V. Chernikov static int
109f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
110f1220db8SAlexander V. Chernikov {
111f1220db8SAlexander V. Chernikov 	struct hostent *he;
112f1220db8SAlexander V. Chernikov 
113f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
114f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
115f1220db8SAlexander V. Chernikov 			return(-1);
116f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
117f1220db8SAlexander V. Chernikov 	}
118f1220db8SAlexander V. Chernikov 	return(0);
119f1220db8SAlexander V. Chernikov }
120f1220db8SAlexander V. Chernikov 
121f1220db8SAlexander V. Chernikov /*
122f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
123ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
124ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
125ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
126ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
127ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
128ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
129ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
130f1220db8SAlexander V. Chernikov  */
131f1220db8SAlexander V. Chernikov void
132f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
133f1220db8SAlexander V. Chernikov {
134ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
135ac35ff17SAlexander V. Chernikov 	int error, tcmd;
136ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
137ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
138f1220db8SAlexander V. Chernikov 	char *tablename;
139ac35ff17SAlexander V. Chernikov 	uint32_t set;
140f1220db8SAlexander V. Chernikov 
141ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
142ac35ff17SAlexander V. Chernikov 	is_all = 0;
143ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
144ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
145ac35ff17SAlexander V. Chernikov 	else
146ac35ff17SAlexander V. Chernikov 		set = 0;
147f1220db8SAlexander V. Chernikov 
148f1220db8SAlexander V. Chernikov 	ac--; av++;
1499d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
150f1220db8SAlexander V. Chernikov 	tablename = *av;
151f1220db8SAlexander V. Chernikov 
152ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
153ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
154ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
155ac35ff17SAlexander V. Chernikov 	} else {
156ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
157ac35ff17SAlexander V. Chernikov 			is_all = 1;
158ac35ff17SAlexander V. Chernikov 		else
159ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
160ac35ff17SAlexander V. Chernikov 	}
161ac35ff17SAlexander V. Chernikov 	ac--; av++;
1629d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
163ac35ff17SAlexander V. Chernikov 
164ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
165ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
166ac35ff17SAlexander V. Chernikov 
167ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
168ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
169ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
170ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
171ac35ff17SAlexander V. Chernikov 		break;
172ac35ff17SAlexander V. Chernikov 	default:
173ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
174ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
175ac35ff17SAlexander V. Chernikov 	}
176ac35ff17SAlexander V. Chernikov 
177ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
178ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
179ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
180f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
181f1220db8SAlexander V. Chernikov 		ac--; av++;
182ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
183ac35ff17SAlexander V. Chernikov 		break;
184ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
185f1220db8SAlexander V. Chernikov 		ac--; av++;
186ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
187ac35ff17SAlexander V. Chernikov 		break;
188ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
189ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
190ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
191ac35ff17SAlexander V. Chernikov 		break;
192ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
193f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
194ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
195f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
196f1220db8SAlexander V. Chernikov 				    tablename);
197f1220db8SAlexander V. Chernikov 		} else {
198ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
199f1220db8SAlexander V. Chernikov 			if (error != 0)
200f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
201f1220db8SAlexander V. Chernikov 		}
202ac35ff17SAlexander V. Chernikov 		break;
203ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
204f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
205ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
206f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
207f1220db8SAlexander V. Chernikov 			table_show_info(&i, NULL);
208f1220db8SAlexander V. Chernikov 		} else {
209f1220db8SAlexander V. Chernikov 			error = tables_foreach(table_show_info, NULL, 1);
210f1220db8SAlexander V. Chernikov 			if (error != 0)
211f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
212f1220db8SAlexander V. Chernikov 		}
213ac35ff17SAlexander V. Chernikov 		break;
214ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
215ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
216ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
217ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
218ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
219ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
220f1220db8SAlexander V. Chernikov 		} else {
221ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
222ac35ff17SAlexander V. Chernikov 			if (error != 0)
223ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
224f1220db8SAlexander V. Chernikov 		}
225ac35ff17SAlexander V. Chernikov 		break;
22681d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
22781d3153dSAlexander V. Chernikov 		ac--; av++;
22881d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
22981d3153dSAlexander V. Chernikov 		break;
230f1220db8SAlexander V. Chernikov 	}
231f1220db8SAlexander V. Chernikov }
232f1220db8SAlexander V. Chernikov 
233f1220db8SAlexander V. Chernikov static void
234ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
235f1220db8SAlexander V. Chernikov {
236f1220db8SAlexander V. Chernikov 
237563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
238f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
239f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
240ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
241f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
242f1220db8SAlexander V. Chernikov }
243f1220db8SAlexander V. Chernikov 
244f1220db8SAlexander V. Chernikov static void
245f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
246f1220db8SAlexander V. Chernikov {
247f1220db8SAlexander V. Chernikov 
248f1220db8SAlexander V. Chernikov 	oh->idx = 1;
24981d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
250ac35ff17SAlexander V. Chernikov }
251ac35ff17SAlexander V. Chernikov 
252ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
253ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE},
254ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
255ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
256ac35ff17SAlexander V. Chernikov       { NULL, 0 }
257ac35ff17SAlexander V. Chernikov };
258ac35ff17SAlexander V. Chernikov 
259ac35ff17SAlexander V. Chernikov /*
260ac35ff17SAlexander V. Chernikov  * Creates new table
261ac35ff17SAlexander V. Chernikov  *
262ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
263ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
264ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
265ac35ff17SAlexander V. Chernikov  *
266ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
267ac35ff17SAlexander V. Chernikov  */
268ac35ff17SAlexander V. Chernikov static void
269ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
270ac35ff17SAlexander V. Chernikov {
271ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
272ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
273ac35ff17SAlexander V. Chernikov 	size_t sz;
274ac35ff17SAlexander V. Chernikov 	char tbuf[128];
275ac35ff17SAlexander V. Chernikov 
276ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
277ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
278ac35ff17SAlexander V. Chernikov 
279ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
280ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
281ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
282ac35ff17SAlexander V. Chernikov 
283ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
284ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
285ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
286ac35ff17SAlexander V. Chernikov 		ac--; av++;
287ac35ff17SAlexander V. Chernikov 
288ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
289ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
290ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
291ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
292ac35ff17SAlexander V. Chernikov 			if (val != -1) {
293ac35ff17SAlexander V. Chernikov 				xi.type = val;
294ac35ff17SAlexander V. Chernikov 				ac--; av++;
295ac35ff17SAlexander V. Chernikov 				break;
296ac35ff17SAlexander V. Chernikov 			}
297ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", ");
298ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s",
299ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
300ac35ff17SAlexander V. Chernikov 			break;
301ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
302ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
303ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
304ac35ff17SAlexander V. Chernikov 			if (val != -1) {
305ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
306ac35ff17SAlexander V. Chernikov 				ac--; av++;
307ac35ff17SAlexander V. Chernikov 				break;
308ac35ff17SAlexander V. Chernikov 			}
309ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
310ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
311ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
312ac35ff17SAlexander V. Chernikov 			break;
313ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
314ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
315ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
316ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
317ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
318ac35ff17SAlexander V. Chernikov 			ac--; av++;
319ac35ff17SAlexander V. Chernikov 			break;
320ac35ff17SAlexander V. Chernikov 		}
321ac35ff17SAlexander V. Chernikov 	}
322ac35ff17SAlexander V. Chernikov 
323ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
324ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
325f1220db8SAlexander V. Chernikov }
326f1220db8SAlexander V. Chernikov 
327f1220db8SAlexander V. Chernikov /*
328ac35ff17SAlexander V. Chernikov  * Creates new table
329ac35ff17SAlexander V. Chernikov  *
330ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
331ac35ff17SAlexander V. Chernikov  *
332f1220db8SAlexander V. Chernikov  * Returns 0 on success.
333f1220db8SAlexander V. Chernikov  */
334f1220db8SAlexander V. Chernikov static int
335ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
336f1220db8SAlexander V. Chernikov {
337ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
338ac35ff17SAlexander V. Chernikov 	int error;
339f1220db8SAlexander V. Chernikov 
340ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
341ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
342ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
343ac35ff17SAlexander V. Chernikov 
344ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
345ac35ff17SAlexander V. Chernikov 
346ac35ff17SAlexander V. Chernikov 	return (error);
347ac35ff17SAlexander V. Chernikov }
348ac35ff17SAlexander V. Chernikov 
349ac35ff17SAlexander V. Chernikov /*
350ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
351ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
352ac35ff17SAlexander V. Chernikov  */
353ac35ff17SAlexander V. Chernikov static int
354ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
355ac35ff17SAlexander V. Chernikov {
356ac35ff17SAlexander V. Chernikov 
357ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
358f1220db8SAlexander V. Chernikov 		return (-1);
359f1220db8SAlexander V. Chernikov 
360f1220db8SAlexander V. Chernikov 	return (0);
361f1220db8SAlexander V. Chernikov }
362f1220db8SAlexander V. Chernikov 
363f1220db8SAlexander V. Chernikov /*
364ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
365f1220db8SAlexander V. Chernikov  * Returns 0 on success.
366f1220db8SAlexander V. Chernikov  */
367f1220db8SAlexander V. Chernikov static int
368ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
369f1220db8SAlexander V. Chernikov {
370f1220db8SAlexander V. Chernikov 
371ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
372f1220db8SAlexander V. Chernikov 		return (-1);
373f1220db8SAlexander V. Chernikov 
374f1220db8SAlexander V. Chernikov 	return (0);
375f1220db8SAlexander V. Chernikov }
376f1220db8SAlexander V. Chernikov 
377f1220db8SAlexander V. Chernikov /*
378ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
379f1220db8SAlexander V. Chernikov  * it inside @i.
380f1220db8SAlexander V. Chernikov  * Returns 0 on success.
381f1220db8SAlexander V. Chernikov  */
382f1220db8SAlexander V. Chernikov static int
383ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
384f1220db8SAlexander V. Chernikov {
385f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
386ac35ff17SAlexander V. Chernikov 	int error;
387f1220db8SAlexander V. Chernikov 	size_t sz;
388f1220db8SAlexander V. Chernikov 
389f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
390f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
391ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
392f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
393f1220db8SAlexander V. Chernikov 
394ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
395ac35ff17SAlexander V. Chernikov 		return (error);
396f1220db8SAlexander V. Chernikov 
397f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
398ac35ff17SAlexander V. Chernikov 		return (EINVAL);
399f1220db8SAlexander V. Chernikov 
400f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
401f1220db8SAlexander V. Chernikov 
402f1220db8SAlexander V. Chernikov 	return (0);
403f1220db8SAlexander V. Chernikov }
404f1220db8SAlexander V. Chernikov 
405f1220db8SAlexander V. Chernikov /*
406f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
407f1220db8SAlexander V. Chernikov  */
408f1220db8SAlexander V. Chernikov static int
409f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
410f1220db8SAlexander V. Chernikov {
411ac35ff17SAlexander V. Chernikov 	const char *ttype, *vtype;
412f1220db8SAlexander V. Chernikov 
413f1220db8SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
414ac35ff17SAlexander V. Chernikov 	if ((ttype = match_value(tabletypes, i->type)) == NULL)
415ac35ff17SAlexander V. Chernikov 		ttype = "unknown";
416ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
417ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
418ac35ff17SAlexander V. Chernikov 
419ac35ff17SAlexander V. Chernikov 	printf(" type: %s, kindex: %d\n", ttype, i->kidx);
4209d099b4fSAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
4219d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
422f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
423f1220db8SAlexander V. Chernikov 
424f1220db8SAlexander V. Chernikov 	return (0);
425f1220db8SAlexander V. Chernikov }
426f1220db8SAlexander V. Chernikov 
427f1220db8SAlexander V. Chernikov 
428f1220db8SAlexander V. Chernikov /*
429f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
430f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
431f1220db8SAlexander V. Chernikov  */
432f1220db8SAlexander V. Chernikov 
433f1220db8SAlexander V. Chernikov static int
434f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
435f1220db8SAlexander V. Chernikov {
436f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
43781d3153dSAlexander V. Chernikov 	int error;
438f1220db8SAlexander V. Chernikov 
439ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
440f1220db8SAlexander V. Chernikov 		return (ENOMEM);
441f1220db8SAlexander V. Chernikov 
44281d3153dSAlexander V. Chernikov 	if ((error = table_get_list(i, oh)) != 0) {
44381d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
44481d3153dSAlexander V. Chernikov 		return (error);
44581d3153dSAlexander V. Chernikov 	}
44681d3153dSAlexander V. Chernikov 
447f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
448f1220db8SAlexander V. Chernikov 
449f1220db8SAlexander V. Chernikov 	free(oh);
450f1220db8SAlexander V. Chernikov 	return (0);
451f1220db8SAlexander V. Chernikov }
452f1220db8SAlexander V. Chernikov 
453f1220db8SAlexander V. Chernikov static int
454f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
455f1220db8SAlexander V. Chernikov {
456ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
457f1220db8SAlexander V. Chernikov 
458ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
459ac35ff17SAlexander V. Chernikov 
460ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
461ac35ff17SAlexander V. Chernikov 
462ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
463f1220db8SAlexander V. Chernikov }
464f1220db8SAlexander V. Chernikov 
465ac35ff17SAlexander V. Chernikov static int
466ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
467ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
468ac35ff17SAlexander V. Chernikov {
469db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
470db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
471ac35ff17SAlexander V. Chernikov 	int error;
472ac35ff17SAlexander V. Chernikov 
473ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
474ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
475ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
476ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
477ac35ff17SAlexander V. Chernikov 
478db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
479db785d31SAlexander V. Chernikov 	ctlv->count = 1;
480db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
481db785d31SAlexander V. Chernikov 
482db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
483db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
484ac35ff17SAlexander V. Chernikov 	if (update != 0)
48581d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
486ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
487ac35ff17SAlexander V. Chernikov 
488ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
489ac35ff17SAlexander V. Chernikov 
490ac35ff17SAlexander V. Chernikov 	return (error);
491ac35ff17SAlexander V. Chernikov }
492ac35ff17SAlexander V. Chernikov 
493ac35ff17SAlexander V. Chernikov static void
494ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
495ac35ff17SAlexander V. Chernikov {
496ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
49781d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
498ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
499ac35ff17SAlexander V. Chernikov 	int cmd;
500ac35ff17SAlexander V. Chernikov 	char *texterr;
501ac35ff17SAlexander V. Chernikov 
502ac35ff17SAlexander V. Chernikov 	if (ac == 0)
503ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
504ac35ff17SAlexander V. Chernikov 
505ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
506ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
507ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
508ac35ff17SAlexander V. Chernikov 
50981d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
510db785d31SAlexander V. Chernikov 
511db785d31SAlexander V. Chernikov 	/*
512db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
513db785d31SAlexander V. Chernikov 	 */
514db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
515db785d31SAlexander V. Chernikov 		xi.type = type;
516db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
517db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
518db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
519db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
520db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
521db785d31SAlexander V. Chernikov 	}
522db785d31SAlexander V. Chernikov 
523ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
524ac35ff17SAlexander V. Chernikov 	ac--; av++;
525ac35ff17SAlexander V. Chernikov 
526ac35ff17SAlexander V. Chernikov 	if (add != 0) {
527ac35ff17SAlexander V. Chernikov 		if (ac > 0)
528ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
529ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
530ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XADD)";
531ac35ff17SAlexander V. Chernikov 	} else {
532ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
533ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XDEL)";
534ac35ff17SAlexander V. Chernikov 	}
535ac35ff17SAlexander V. Chernikov 
536ac35ff17SAlexander V. Chernikov 	if (table_do_modify_record(cmd, oh, &tent, update) != 0)
537ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "%s", texterr);
538ac35ff17SAlexander V. Chernikov }
539ac35ff17SAlexander V. Chernikov 
54081d3153dSAlexander V. Chernikov static int
54181d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
54281d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
54381d3153dSAlexander V. Chernikov {
54481d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
54581d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
54681d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
54781d3153dSAlexander V. Chernikov 	int error;
54881d3153dSAlexander V. Chernikov 	size_t sz;
54981d3153dSAlexander V. Chernikov 
55081d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
55181d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
55281d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
55381d3153dSAlexander V. Chernikov 
55481d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
55581d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
55681d3153dSAlexander V. Chernikov 	tent->idx = 1;
55781d3153dSAlexander V. Chernikov 
55881d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
55981d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
56081d3153dSAlexander V. Chernikov 
56181d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
56281d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
56381d3153dSAlexander V. Chernikov 		return (error);
56481d3153dSAlexander V. Chernikov 
56581d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
56681d3153dSAlexander V. Chernikov 		return (EINVAL);
56781d3153dSAlexander V. Chernikov 
56881d3153dSAlexander V. Chernikov 	*xtent = *tent;
56981d3153dSAlexander V. Chernikov 
57081d3153dSAlexander V. Chernikov 	return (0);
57181d3153dSAlexander V. Chernikov }
57281d3153dSAlexander V. Chernikov 
57381d3153dSAlexander V. Chernikov static void
57481d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
57581d3153dSAlexander V. Chernikov {
57681d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
57781d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
57881d3153dSAlexander V. Chernikov 	int error;
57981d3153dSAlexander V. Chernikov 
58081d3153dSAlexander V. Chernikov 	if (ac == 0)
58181d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
58281d3153dSAlexander V. Chernikov 
58381d3153dSAlexander V. Chernikov 	error = table_do_lookup(oh, *av, &xi, &xtent);
58481d3153dSAlexander V. Chernikov 
58581d3153dSAlexander V. Chernikov 	switch (error) {
58681d3153dSAlexander V. Chernikov 	case 0:
58781d3153dSAlexander V. Chernikov 		break;
58881d3153dSAlexander V. Chernikov 	case ESRCH:
58981d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
59081d3153dSAlexander V. Chernikov 	case ENOENT:
59181d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
59281d3153dSAlexander V. Chernikov 	case ENOTSUP:
59381d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
59481d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
59581d3153dSAlexander V. Chernikov 	default:
59681d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
59781d3153dSAlexander V. Chernikov 	}
59881d3153dSAlexander V. Chernikov 
59981d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
60081d3153dSAlexander V. Chernikov }
601ac35ff17SAlexander V. Chernikov 
602ac35ff17SAlexander V. Chernikov static void
603ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
604ac35ff17SAlexander V. Chernikov {
605ac35ff17SAlexander V. Chernikov 	char *p;
606ac35ff17SAlexander V. Chernikov 	int mask, af;
607ac35ff17SAlexander V. Chernikov 	struct in6_addr *paddr;
608ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
609ac35ff17SAlexander V. Chernikov 	int masklen;
610ac35ff17SAlexander V. Chernikov 
611ac35ff17SAlexander V. Chernikov 	masklen = 0;
612ac35ff17SAlexander V. Chernikov 	af = 0;
613ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
614ac35ff17SAlexander V. Chernikov 
615ac35ff17SAlexander V. Chernikov 	switch (type) {
616ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
617ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
618ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
619ac35ff17SAlexander V. Chernikov 			*p = '\0';
620ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
621ac35ff17SAlexander V. Chernikov 		}
622ac35ff17SAlexander V. Chernikov 
623ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
624ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
625ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
626ac35ff17SAlexander V. Chernikov 				    p + 1);
627ac35ff17SAlexander V. Chernikov 
628ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
629ac35ff17SAlexander V. Chernikov 			af = AF_INET;
630ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
631ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
632ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
633ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
634ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
635ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
636ac35ff17SAlexander V. Chernikov 				    p + 1);
637ac35ff17SAlexander V. Chernikov 
638ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
639ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
640ac35ff17SAlexander V. Chernikov 		} else {
641ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
642ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
643ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
644ac35ff17SAlexander V. Chernikov 
645ac35ff17SAlexander V. Chernikov 			masklen = 32;
646ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
647ac35ff17SAlexander V. Chernikov 			af = AF_INET;
648ac35ff17SAlexander V. Chernikov 		}
649ac35ff17SAlexander V. Chernikov 		break;
650ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
651ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
652ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
653ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
654ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
655ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
656ac35ff17SAlexander V. Chernikov 		break;
657b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
658ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
659ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
660ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
661ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
662ac35ff17SAlexander V. Chernikov 
663ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
664ac35ff17SAlexander V. Chernikov 		*pkey = key;
665ac35ff17SAlexander V. Chernikov 		masklen = 32;
666ac35ff17SAlexander V. Chernikov 		break;
667ac35ff17SAlexander V. Chernikov 	default:
668ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
669ac35ff17SAlexander V. Chernikov 	}
670ac35ff17SAlexander V. Chernikov 
671ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
672ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
673ac35ff17SAlexander V. Chernikov }
674ac35ff17SAlexander V. Chernikov 
675ac35ff17SAlexander V. Chernikov static void
676ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
67781d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
678ac35ff17SAlexander V. Chernikov {
679ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
680ac35ff17SAlexander V. Chernikov 	int error;
681db785d31SAlexander V. Chernikov 	char *del;
682ac35ff17SAlexander V. Chernikov 
683ac35ff17SAlexander V. Chernikov 	type = 0;
684ac35ff17SAlexander V. Chernikov 	vtype = 0;
685ac35ff17SAlexander V. Chernikov 
68681d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
68781d3153dSAlexander V. Chernikov 
68881d3153dSAlexander V. Chernikov 	if (error == 0) {
68981d3153dSAlexander V. Chernikov 		/* Table found. */
69081d3153dSAlexander V. Chernikov 		type = xi->type;
69181d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
69281d3153dSAlexander V. Chernikov 	} else {
69381d3153dSAlexander V. Chernikov 		if (error != ESRCH)
69481d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
69581d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
696ac35ff17SAlexander V. Chernikov 		/*
69781d3153dSAlexander V. Chernikov 		 * Table does not exist.
69881d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
69981d3153dSAlexander V. Chernikov 		 * before failing.
700ac35ff17SAlexander V. Chernikov 		 */
701db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
702db785d31SAlexander V. Chernikov 			*del = '\0';
703ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
704ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
705ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
706ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
707ac35ff17SAlexander V. Chernikov 			/*
70881d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
70981d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
710ac35ff17SAlexander V. Chernikov 			 */
71181d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
71281d3153dSAlexander V. Chernikov 		} else {
71381d3153dSAlexander V. Chernikov 			/* Inknown key */
71481d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
715db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
71681d3153dSAlexander V. Chernikov 		}
717db785d31SAlexander V. Chernikov 		if (del != NULL)
718db785d31SAlexander V. Chernikov 			*del = '/';
719ac35ff17SAlexander V. Chernikov 	}
720ac35ff17SAlexander V. Chernikov 
721ac35ff17SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type);
722ac35ff17SAlexander V. Chernikov 
723ac35ff17SAlexander V. Chernikov 	*ptype = type;
724ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
725ac35ff17SAlexander V. Chernikov }
726ac35ff17SAlexander V. Chernikov 
727ac35ff17SAlexander V. Chernikov static void
728ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
729ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
730ac35ff17SAlexander V. Chernikov {
731ac35ff17SAlexander V. Chernikov 	int code;
732ac35ff17SAlexander V. Chernikov 	char *p;
733ac35ff17SAlexander V. Chernikov 
734ac35ff17SAlexander V. Chernikov 	switch (vtype) {
735ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
736ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
737ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
738ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
739ac35ff17SAlexander V. Chernikov 		break;
740ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
741ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
742ac35ff17SAlexander V. Chernikov 			break;
743ac35ff17SAlexander V. Chernikov 		/* Try hostname */
744ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
745ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
746ac35ff17SAlexander V. Chernikov 		break;
747ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
748ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
749ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
750ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
751ac35ff17SAlexander V. Chernikov 		} else {
752ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
753ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
754ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
755ac35ff17SAlexander V. Chernikov 		}
756ac35ff17SAlexander V. Chernikov 		tent->value = code;
757ac35ff17SAlexander V. Chernikov 		break;
758ac35ff17SAlexander V. Chernikov 	default:
759ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
760ac35ff17SAlexander V. Chernikov 	}
761ac35ff17SAlexander V. Chernikov }
762f1220db8SAlexander V. Chernikov 
763f1220db8SAlexander V. Chernikov /*
764f1220db8SAlexander V. Chernikov  * Compare table names.
765f1220db8SAlexander V. Chernikov  * Honor number comparison.
766f1220db8SAlexander V. Chernikov  */
767f1220db8SAlexander V. Chernikov static int
768f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
769f1220db8SAlexander V. Chernikov {
770f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
771f1220db8SAlexander V. Chernikov 
772f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
773f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
774f1220db8SAlexander V. Chernikov 
77568394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
776f1220db8SAlexander V. Chernikov }
777f1220db8SAlexander V. Chernikov 
778f1220db8SAlexander V. Chernikov /*
779f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
780f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
781f1220db8SAlexander V. Chernikov  * Returns 0 on success.
782f1220db8SAlexander V. Chernikov  */
783f1220db8SAlexander V. Chernikov static int
784f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
785f1220db8SAlexander V. Chernikov {
786f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
787f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
788f1220db8SAlexander V. Chernikov 	size_t sz;
789f1220db8SAlexander V. Chernikov 	int i, error;
790f1220db8SAlexander V. Chernikov 
791f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
792f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
793f1220db8SAlexander V. Chernikov 
794d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
795f1220db8SAlexander V. Chernikov 		return (errno);
796f1220db8SAlexander V. Chernikov 
797f1220db8SAlexander V. Chernikov 	sz = req.size;
798f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
799f1220db8SAlexander V. Chernikov 		return (ENOMEM);
800f1220db8SAlexander V. Chernikov 
801f1220db8SAlexander V. Chernikov 	olh->size = sz;
802d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
803f1220db8SAlexander V. Chernikov 		free(olh);
804f1220db8SAlexander V. Chernikov 		return (errno);
805f1220db8SAlexander V. Chernikov 	}
806f1220db8SAlexander V. Chernikov 
807f1220db8SAlexander V. Chernikov 	if (sort != 0)
808f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
809f1220db8SAlexander V. Chernikov 
810f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
811f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
812f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
813f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
814f1220db8SAlexander V. Chernikov 	}
815f1220db8SAlexander V. Chernikov 
816f1220db8SAlexander V. Chernikov 	free(olh);
817f1220db8SAlexander V. Chernikov 
818f1220db8SAlexander V. Chernikov 	return (0);
819f1220db8SAlexander V. Chernikov }
820f1220db8SAlexander V. Chernikov 
821f1220db8SAlexander V. Chernikov /*
822f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
823d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
824d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
825f1220db8SAlexander V. Chernikov  *
826f1220db8SAlexander V. Chernikov  * Returns 0 on success.
827f1220db8SAlexander V. Chernikov  */
828f1220db8SAlexander V. Chernikov static int
829f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
830f1220db8SAlexander V. Chernikov {
831f1220db8SAlexander V. Chernikov 	size_t sz;
83281d3153dSAlexander V. Chernikov 	int error, c;
833f1220db8SAlexander V. Chernikov 
83481d3153dSAlexander V. Chernikov 	sz = 0;
83581d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
836f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
83781d3153dSAlexander V. Chernikov 		if (sz < i->size)
838f1220db8SAlexander V. Chernikov 			sz = i->size;
839f1220db8SAlexander V. Chernikov 
840d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
84181d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
842d3a4f924SAlexander V. Chernikov 
84381d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
844f1220db8SAlexander V. Chernikov 			return (errno);
84581d3153dSAlexander V. Chernikov 	}
846f1220db8SAlexander V. Chernikov 
84781d3153dSAlexander V. Chernikov 	return (ENOMEM);
848f1220db8SAlexander V. Chernikov }
849f1220db8SAlexander V. Chernikov 
850f1220db8SAlexander V. Chernikov /*
851f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
852f1220db8SAlexander V. Chernikov  */
853f1220db8SAlexander V. Chernikov static void
854f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
855f1220db8SAlexander V. Chernikov {
85681d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
85781d3153dSAlexander V. Chernikov 	uint32_t count;
858f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
859f1220db8SAlexander V. Chernikov 
860f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
86181d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
862f1220db8SAlexander V. Chernikov 
863f1220db8SAlexander V. Chernikov 	if (need_header)
864f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
865f1220db8SAlexander V. Chernikov 
866f1220db8SAlexander V. Chernikov 	count = i->count;
867f1220db8SAlexander V. Chernikov 	while (count > 0) {
86881d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
86981d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
87081d3153dSAlexander V. Chernikov 		count--;
87181d3153dSAlexander V. Chernikov 	}
87281d3153dSAlexander V. Chernikov }
87381d3153dSAlexander V. Chernikov 
87481d3153dSAlexander V. Chernikov static void
87581d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
87681d3153dSAlexander V. Chernikov {
87781d3153dSAlexander V. Chernikov 	char tbuf[128];
87881d3153dSAlexander V. Chernikov 	uint32_t tval;
87981d3153dSAlexander V. Chernikov 
88081d3153dSAlexander V. Chernikov 	tval = tent->value;
88181d3153dSAlexander V. Chernikov 
882f1220db8SAlexander V. Chernikov 	switch (i->type) {
883f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
884f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
88581d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
886f1220db8SAlexander V. Chernikov 
887f1220db8SAlexander V. Chernikov 		if (co.do_value_as_ip) {
888f1220db8SAlexander V. Chernikov 			tval = htonl(tval);
88981d3153dSAlexander V. Chernikov 			printf("%s/%u %s\n", tbuf, tent->masklen,
890f1220db8SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
891f1220db8SAlexander V. Chernikov 		} else
89281d3153dSAlexander V. Chernikov 			printf("%s/%u %u\n", tbuf, tent->masklen, tval);
893f1220db8SAlexander V. Chernikov 		break;
894f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
895f1220db8SAlexander V. Chernikov 		/* Interface names */
896f1220db8SAlexander V. Chernikov 		if (co.do_value_as_ip) {
897f1220db8SAlexander V. Chernikov 			tval = htonl(tval);
89881d3153dSAlexander V. Chernikov 			printf("%s %s\n", tent->k.iface,
899f1220db8SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
900f1220db8SAlexander V. Chernikov 		} else
90181d3153dSAlexander V. Chernikov 			printf("%s %u\n", tent->k.iface, tval);
902b23d5de9SAlexander V. Chernikov 		break;
903b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
904b23d5de9SAlexander V. Chernikov 		/* numbers */
905b23d5de9SAlexander V. Chernikov 		if (co.do_value_as_ip) {
906b23d5de9SAlexander V. Chernikov 			tval = htonl(tval);
907b23d5de9SAlexander V. Chernikov 			printf("%u %s\n", tent->k.key,
908b23d5de9SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
909b23d5de9SAlexander V. Chernikov 		} else
910b23d5de9SAlexander V. Chernikov 			printf("%u %u\n", tent->k.key, tval);
911b23d5de9SAlexander V. Chernikov 		break;
912f1220db8SAlexander V. Chernikov 	}
913f1220db8SAlexander V. Chernikov }
914f1220db8SAlexander V. Chernikov 
9159d099b4fSAlexander V. Chernikov static int
9169d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
9179d099b4fSAlexander V. Chernikov {
9189d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
9199d099b4fSAlexander V. Chernikov 	size_t sz;
9209d099b4fSAlexander V. Chernikov 	int error;
9219d099b4fSAlexander V. Chernikov 
9229d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
9239d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
9249d099b4fSAlexander V. Chernikov 
9259d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
9269d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
9279d099b4fSAlexander V. Chernikov 		return (error);
9289d099b4fSAlexander V. Chernikov 
9299d099b4fSAlexander V. Chernikov 	sz = req.size;
9309d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
9319d099b4fSAlexander V. Chernikov 		return (ENOMEM);
9329d099b4fSAlexander V. Chernikov 
9339d099b4fSAlexander V. Chernikov 	olh->size = sz;
9349d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
9359d099b4fSAlexander V. Chernikov 		free(olh);
9369d099b4fSAlexander V. Chernikov 		return (error);
9379d099b4fSAlexander V. Chernikov 	}
9389d099b4fSAlexander V. Chernikov 
9399d099b4fSAlexander V. Chernikov 	*polh = olh;
9409d099b4fSAlexander V. Chernikov 	return (0);
9419d099b4fSAlexander V. Chernikov }
9429d099b4fSAlexander V. Chernikov 
9439d099b4fSAlexander V. Chernikov void
9449d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
9459d099b4fSAlexander V. Chernikov {
9469d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
9479d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
9489d099b4fSAlexander V. Chernikov 	int error, i;
9499d099b4fSAlexander V. Chernikov 	const char *atype;
9509d099b4fSAlexander V. Chernikov 
9519d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
9529d099b4fSAlexander V. Chernikov 	if (error != 0)
9539d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
9549d099b4fSAlexander V. Chernikov 
9559d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
9569d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
9579d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
9589d099b4fSAlexander V. Chernikov 			atype = "unknown";
959*8ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
960*8ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
9619d099b4fSAlexander V. Chernikov 
9629d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
9639d099b4fSAlexander V. Chernikov 	}
9649d099b4fSAlexander V. Chernikov 
9659d099b4fSAlexander V. Chernikov 	free(olh);
9669d099b4fSAlexander V. Chernikov }
9679d099b4fSAlexander V. Chernikov 
9686c2997ffSAlexander V. Chernikov int
9696c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
9706c2997ffSAlexander V. Chernikov {
9716c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
9726c2997ffSAlexander V. Chernikov 
9736c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
9746c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
9756c2997ffSAlexander V. Chernikov 
9766c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
9776c2997ffSAlexander V. Chernikov 		return (-1);
9786c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
9796c2997ffSAlexander V. Chernikov 		return (1);
9806c2997ffSAlexander V. Chernikov 
9816c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
9826c2997ffSAlexander V. Chernikov 		return (-1);
9836c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
9846c2997ffSAlexander V. Chernikov 		return (1);
9856c2997ffSAlexander V. Chernikov 
9866c2997ffSAlexander V. Chernikov 	return (0);
9876c2997ffSAlexander V. Chernikov }
988563b5ab1SAlexander V. Chernikov 
989563b5ab1SAlexander V. Chernikov int
9906c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
991563b5ab1SAlexander V. Chernikov {
992563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
993563b5ab1SAlexander V. Chernikov 	uint16_t key;
994563b5ab1SAlexander V. Chernikov 
995563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
996563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
997563b5ab1SAlexander V. Chernikov 
998563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
999563b5ab1SAlexander V. Chernikov 		return (-1);
1000563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1001563b5ab1SAlexander V. Chernikov 		return (1);
1002563b5ab1SAlexander V. Chernikov 
1003563b5ab1SAlexander V. Chernikov 	return (0);
1004563b5ab1SAlexander V. Chernikov }
1005563b5ab1SAlexander V. Chernikov 
1006563b5ab1SAlexander V. Chernikov /*
1007563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1008563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1009563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1010563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1011563b5ab1SAlexander V. Chernikov  *
1012563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1013563b5ab1SAlexander V. Chernikov  */
1014563b5ab1SAlexander V. Chernikov char *
1015563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1016563b5ab1SAlexander V. Chernikov {
1017563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1018563b5ab1SAlexander V. Chernikov 
1019563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
10206c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1021563b5ab1SAlexander V. Chernikov 
1022563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1023563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1024563b5ab1SAlexander V. Chernikov 
1025563b5ab1SAlexander V. Chernikov 	return (NULL);
1026563b5ab1SAlexander V. Chernikov }
1027563b5ab1SAlexander V. Chernikov 
10286c2997ffSAlexander V. Chernikov void
10296c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
10306c2997ffSAlexander V. Chernikov {
10316c2997ffSAlexander V. Chernikov 
10326c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
10336c2997ffSAlexander V. Chernikov }
10346c2997ffSAlexander V. Chernikov 
10356c2997ffSAlexander V. Chernikov int
10366c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
10376c2997ffSAlexander V. Chernikov {
10386c2997ffSAlexander V. Chernikov 	int c, i, l;
10396c2997ffSAlexander V. Chernikov 
10406c2997ffSAlexander V. Chernikov 	/*
10416c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
10426c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1043ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
10446c2997ffSAlexander V. Chernikov 	 */
10456c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
10466c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
10476c2997ffSAlexander V. Chernikov 		return (EINVAL);
10486c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
10496c2997ffSAlexander V. Chernikov 		c = tablename[i];
10506c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
10516c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
10526c2997ffSAlexander V. Chernikov 			continue;
10536c2997ffSAlexander V. Chernikov 		return (EINVAL);
10546c2997ffSAlexander V. Chernikov 	}
10556c2997ffSAlexander V. Chernikov 
1056ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1057ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1058ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1059ac35ff17SAlexander V. Chernikov 
10606c2997ffSAlexander V. Chernikov 	return (0);
10616c2997ffSAlexander V. Chernikov }
10626c2997ffSAlexander V. Chernikov 
1063