xref: /freebsd/sbin/ipfw/tables.c (revision db785d319954371674fbb18f6cbc46d9c8bb0c63)
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 },
85ac35ff17SAlexander V. Chernikov       { "u32",		IPFW_TABLE_U32 },
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++;
149f1220db8SAlexander V. Chernikov 	tablename = *av;
150f1220db8SAlexander V. Chernikov 
151ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
152ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
153ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
154ac35ff17SAlexander V. Chernikov 	} else {
155ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
156ac35ff17SAlexander V. Chernikov 			is_all = 1;
157ac35ff17SAlexander V. Chernikov 		else
158ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
159ac35ff17SAlexander V. Chernikov 	}
160ac35ff17SAlexander V. Chernikov 	ac--; av++;
161ac35ff17SAlexander V. Chernikov 
162ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
163ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
164ac35ff17SAlexander V. Chernikov 
165ac35ff17SAlexander V. Chernikov 	NEED1("table needs command");
166ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
167ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
168ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
169ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
170ac35ff17SAlexander V. Chernikov 		break;
171ac35ff17SAlexander V. Chernikov 	default:
172ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
173ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
174ac35ff17SAlexander V. Chernikov 	}
175ac35ff17SAlexander V. Chernikov 
176ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
177ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
178ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
179f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
180f1220db8SAlexander V. Chernikov 		ac--; av++;
181ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
182ac35ff17SAlexander V. Chernikov 		break;
183ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
184f1220db8SAlexander V. Chernikov 		ac--; av++;
185ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
186ac35ff17SAlexander V. Chernikov 		break;
187ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
188ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
189ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
190ac35ff17SAlexander V. Chernikov 		break;
191ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
192f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
193ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
194f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
195f1220db8SAlexander V. Chernikov 				    tablename);
196f1220db8SAlexander V. Chernikov 		} else {
197ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
198f1220db8SAlexander V. Chernikov 			if (error != 0)
199f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
200f1220db8SAlexander V. Chernikov 		}
201ac35ff17SAlexander V. Chernikov 		break;
202ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
203f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
204ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
205f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
206f1220db8SAlexander V. Chernikov 			table_show_info(&i, NULL);
207f1220db8SAlexander V. Chernikov 		} else {
208f1220db8SAlexander V. Chernikov 			error = tables_foreach(table_show_info, NULL, 1);
209f1220db8SAlexander V. Chernikov 			if (error != 0)
210f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
211f1220db8SAlexander V. Chernikov 		}
212ac35ff17SAlexander V. Chernikov 		break;
213ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
214ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
215ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
216ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
217ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
218ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
219f1220db8SAlexander V. Chernikov 		} else {
220ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
221ac35ff17SAlexander V. Chernikov 			if (error != 0)
222ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
223f1220db8SAlexander V. Chernikov 		}
224ac35ff17SAlexander V. Chernikov 		break;
22581d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
22681d3153dSAlexander V. Chernikov 		ac--; av++;
22781d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
22881d3153dSAlexander V. Chernikov 		break;
229f1220db8SAlexander V. Chernikov 	}
230f1220db8SAlexander V. Chernikov }
231f1220db8SAlexander V. Chernikov 
232f1220db8SAlexander V. Chernikov static void
233ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
234f1220db8SAlexander V. Chernikov {
235f1220db8SAlexander V. Chernikov 
236563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
237f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
238f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
239ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
240f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
241f1220db8SAlexander V. Chernikov }
242f1220db8SAlexander V. Chernikov 
243f1220db8SAlexander V. Chernikov static void
244f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
245f1220db8SAlexander V. Chernikov {
246f1220db8SAlexander V. Chernikov 
247f1220db8SAlexander V. Chernikov 	oh->idx = 1;
24881d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
249ac35ff17SAlexander V. Chernikov }
250ac35ff17SAlexander V. Chernikov 
251ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
252ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE},
253ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
254ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
255ac35ff17SAlexander V. Chernikov       { NULL, 0 }
256ac35ff17SAlexander V. Chernikov };
257ac35ff17SAlexander V. Chernikov 
258ac35ff17SAlexander V. Chernikov /*
259ac35ff17SAlexander V. Chernikov  * Creates new table
260ac35ff17SAlexander V. Chernikov  *
261ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
262ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
263ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
264ac35ff17SAlexander V. Chernikov  *
265ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
266ac35ff17SAlexander V. Chernikov  */
267ac35ff17SAlexander V. Chernikov static void
268ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
269ac35ff17SAlexander V. Chernikov {
270ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
271ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
272ac35ff17SAlexander V. Chernikov 	size_t sz;
273ac35ff17SAlexander V. Chernikov 	char tbuf[128];
274ac35ff17SAlexander V. Chernikov 
275ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
276ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
277ac35ff17SAlexander V. Chernikov 
278ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
279ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
280ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
281ac35ff17SAlexander V. Chernikov 
282ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
283ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
284ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
285ac35ff17SAlexander V. Chernikov 		ac--; av++;
286ac35ff17SAlexander V. Chernikov 
287ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
288ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
289ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
290ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
291ac35ff17SAlexander V. Chernikov 			if (val != -1) {
292ac35ff17SAlexander V. Chernikov 				xi.type = val;
293ac35ff17SAlexander V. Chernikov 				ac--; av++;
294ac35ff17SAlexander V. Chernikov 				break;
295ac35ff17SAlexander V. Chernikov 			}
296ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", ");
297ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s",
298ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
299ac35ff17SAlexander V. Chernikov 			break;
300ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
301ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
302ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
303ac35ff17SAlexander V. Chernikov 			if (val != -1) {
304ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
305ac35ff17SAlexander V. Chernikov 				ac--; av++;
306ac35ff17SAlexander V. Chernikov 				break;
307ac35ff17SAlexander V. Chernikov 			}
308ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
309ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
310ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
311ac35ff17SAlexander V. Chernikov 			break;
312ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
313ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
314ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
315ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
316ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
317ac35ff17SAlexander V. Chernikov 			ac--; av++;
318ac35ff17SAlexander V. Chernikov 			break;
319ac35ff17SAlexander V. Chernikov 		}
320ac35ff17SAlexander V. Chernikov 	}
321ac35ff17SAlexander V. Chernikov 
322ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
323ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
324f1220db8SAlexander V. Chernikov }
325f1220db8SAlexander V. Chernikov 
326f1220db8SAlexander V. Chernikov /*
327ac35ff17SAlexander V. Chernikov  * Creates new table
328ac35ff17SAlexander V. Chernikov  *
329ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
330ac35ff17SAlexander V. Chernikov  *
331f1220db8SAlexander V. Chernikov  * Returns 0 on success.
332f1220db8SAlexander V. Chernikov  */
333f1220db8SAlexander V. Chernikov static int
334ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
335f1220db8SAlexander V. Chernikov {
336ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
337ac35ff17SAlexander V. Chernikov 	int error;
338f1220db8SAlexander V. Chernikov 
339ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
340ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
341ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
342ac35ff17SAlexander V. Chernikov 
343ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
344ac35ff17SAlexander V. Chernikov 
345ac35ff17SAlexander V. Chernikov 	return (error);
346ac35ff17SAlexander V. Chernikov }
347ac35ff17SAlexander V. Chernikov 
348ac35ff17SAlexander V. Chernikov /*
349ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
350ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
351ac35ff17SAlexander V. Chernikov  */
352ac35ff17SAlexander V. Chernikov static int
353ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
354ac35ff17SAlexander V. Chernikov {
355ac35ff17SAlexander V. Chernikov 
356ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
357f1220db8SAlexander V. Chernikov 		return (-1);
358f1220db8SAlexander V. Chernikov 
359f1220db8SAlexander V. Chernikov 	return (0);
360f1220db8SAlexander V. Chernikov }
361f1220db8SAlexander V. Chernikov 
362f1220db8SAlexander V. Chernikov /*
363ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
364f1220db8SAlexander V. Chernikov  * Returns 0 on success.
365f1220db8SAlexander V. Chernikov  */
366f1220db8SAlexander V. Chernikov static int
367ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
368f1220db8SAlexander V. Chernikov {
369f1220db8SAlexander V. Chernikov 
370ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
371f1220db8SAlexander V. Chernikov 		return (-1);
372f1220db8SAlexander V. Chernikov 
373f1220db8SAlexander V. Chernikov 	return (0);
374f1220db8SAlexander V. Chernikov }
375f1220db8SAlexander V. Chernikov 
376f1220db8SAlexander V. Chernikov /*
377ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
378f1220db8SAlexander V. Chernikov  * it inside @i.
379f1220db8SAlexander V. Chernikov  * Returns 0 on success.
380f1220db8SAlexander V. Chernikov  */
381f1220db8SAlexander V. Chernikov static int
382ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
383f1220db8SAlexander V. Chernikov {
384f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
385ac35ff17SAlexander V. Chernikov 	int error;
386f1220db8SAlexander V. Chernikov 	size_t sz;
387f1220db8SAlexander V. Chernikov 
388f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
389f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
390ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
391f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
392f1220db8SAlexander V. Chernikov 
393ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
394ac35ff17SAlexander V. Chernikov 		return (error);
395f1220db8SAlexander V. Chernikov 
396f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
397ac35ff17SAlexander V. Chernikov 		return (EINVAL);
398f1220db8SAlexander V. Chernikov 
399f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
400f1220db8SAlexander V. Chernikov 
401f1220db8SAlexander V. Chernikov 	return (0);
402f1220db8SAlexander V. Chernikov }
403f1220db8SAlexander V. Chernikov 
404f1220db8SAlexander V. Chernikov /*
405f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
406f1220db8SAlexander V. Chernikov  */
407f1220db8SAlexander V. Chernikov static int
408f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
409f1220db8SAlexander V. Chernikov {
410ac35ff17SAlexander V. Chernikov 	const char *ttype, *vtype;
411f1220db8SAlexander V. Chernikov 
412f1220db8SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
413ac35ff17SAlexander V. Chernikov 	if ((ttype = match_value(tabletypes, i->type)) == NULL)
414ac35ff17SAlexander V. Chernikov 		ttype = "unknown";
415ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
416ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
417ac35ff17SAlexander V. Chernikov 
418ac35ff17SAlexander V. Chernikov 	printf(" type: %s, kindex: %d\n", ttype, i->kidx);
419ac35ff17SAlexander V. Chernikov 	printf(" valtype: %s, algorithm: %s\n", vtype, i->algoname);
420f1220db8SAlexander V. Chernikov 	printf(" references: %u\n", i->refcnt);
421f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
422f1220db8SAlexander V. Chernikov 
423f1220db8SAlexander V. Chernikov 	return (0);
424f1220db8SAlexander V. Chernikov }
425f1220db8SAlexander V. Chernikov 
426f1220db8SAlexander V. Chernikov 
427f1220db8SAlexander V. Chernikov /*
428f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
429f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
430f1220db8SAlexander V. Chernikov  */
431f1220db8SAlexander V. Chernikov 
432f1220db8SAlexander V. Chernikov static int
433f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
434f1220db8SAlexander V. Chernikov {
435f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
43681d3153dSAlexander V. Chernikov 	int error;
437f1220db8SAlexander V. Chernikov 
438ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
439f1220db8SAlexander V. Chernikov 		return (ENOMEM);
440f1220db8SAlexander V. Chernikov 
44181d3153dSAlexander V. Chernikov 	if ((error = table_get_list(i, oh)) != 0) {
44281d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
44381d3153dSAlexander V. Chernikov 		return (error);
44481d3153dSAlexander V. Chernikov 	}
44581d3153dSAlexander V. Chernikov 
446f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
447f1220db8SAlexander V. Chernikov 
448f1220db8SAlexander V. Chernikov 	free(oh);
449f1220db8SAlexander V. Chernikov 	return (0);
450f1220db8SAlexander V. Chernikov }
451f1220db8SAlexander V. Chernikov 
452f1220db8SAlexander V. Chernikov static int
453f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
454f1220db8SAlexander V. Chernikov {
455ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
456f1220db8SAlexander V. Chernikov 
457ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
458ac35ff17SAlexander V. Chernikov 
459ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
460ac35ff17SAlexander V. Chernikov 
461ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
462f1220db8SAlexander V. Chernikov }
463f1220db8SAlexander V. Chernikov 
464ac35ff17SAlexander V. Chernikov static int
465ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
466ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
467ac35ff17SAlexander V. Chernikov {
468*db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
469*db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
470ac35ff17SAlexander V. Chernikov 	int error;
471ac35ff17SAlexander V. Chernikov 
472ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
473ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
474ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
475ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
476ac35ff17SAlexander V. Chernikov 
477*db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
478*db785d31SAlexander V. Chernikov 	ctlv->count = 1;
479*db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
480*db785d31SAlexander V. Chernikov 
481*db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
482*db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
483ac35ff17SAlexander V. Chernikov 	if (update != 0)
48481d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
485ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
486ac35ff17SAlexander V. Chernikov 
487ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
488ac35ff17SAlexander V. Chernikov 
489ac35ff17SAlexander V. Chernikov 	return (error);
490ac35ff17SAlexander V. Chernikov }
491ac35ff17SAlexander V. Chernikov 
492ac35ff17SAlexander V. Chernikov static void
493ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
494ac35ff17SAlexander V. Chernikov {
495ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
49681d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
497ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
498ac35ff17SAlexander V. Chernikov 	int cmd;
499ac35ff17SAlexander V. Chernikov 	char *texterr;
500ac35ff17SAlexander V. Chernikov 
501ac35ff17SAlexander V. Chernikov 	if (ac == 0)
502ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
503ac35ff17SAlexander V. Chernikov 
504ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
505ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
506ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
507ac35ff17SAlexander V. Chernikov 
50881d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
509*db785d31SAlexander V. Chernikov 
510*db785d31SAlexander V. Chernikov 	/*
511*db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
512*db785d31SAlexander V. Chernikov 	 */
513*db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
514*db785d31SAlexander V. Chernikov 		xi.type = type;
515*db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
516*db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
517*db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
518*db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
519*db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
520*db785d31SAlexander V. Chernikov 	}
521*db785d31SAlexander V. Chernikov 
522ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
523ac35ff17SAlexander V. Chernikov 	ac--; av++;
524ac35ff17SAlexander V. Chernikov 
525ac35ff17SAlexander V. Chernikov 	if (add != 0) {
526ac35ff17SAlexander V. Chernikov 		if (ac > 0)
527ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
528ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
529ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XADD)";
530ac35ff17SAlexander V. Chernikov 	} else {
531ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
532ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XDEL)";
533ac35ff17SAlexander V. Chernikov 	}
534ac35ff17SAlexander V. Chernikov 
535ac35ff17SAlexander V. Chernikov 	if (table_do_modify_record(cmd, oh, &tent, update) != 0)
536ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "%s", texterr);
537ac35ff17SAlexander V. Chernikov }
538ac35ff17SAlexander V. Chernikov 
53981d3153dSAlexander V. Chernikov static int
54081d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
54181d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
54281d3153dSAlexander V. Chernikov {
54381d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
54481d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
54581d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
54681d3153dSAlexander V. Chernikov 	int error;
54781d3153dSAlexander V. Chernikov 	size_t sz;
54881d3153dSAlexander V. Chernikov 
54981d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
55081d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
55181d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
55281d3153dSAlexander V. Chernikov 
55381d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
55481d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
55581d3153dSAlexander V. Chernikov 	tent->idx = 1;
55681d3153dSAlexander V. Chernikov 
55781d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
55881d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
55981d3153dSAlexander V. Chernikov 
56081d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
56181d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
56281d3153dSAlexander V. Chernikov 		return (error);
56381d3153dSAlexander V. Chernikov 
56481d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
56581d3153dSAlexander V. Chernikov 		return (EINVAL);
56681d3153dSAlexander V. Chernikov 
56781d3153dSAlexander V. Chernikov 	*xtent = *tent;
56881d3153dSAlexander V. Chernikov 
56981d3153dSAlexander V. Chernikov 	return (0);
57081d3153dSAlexander V. Chernikov }
57181d3153dSAlexander V. Chernikov 
57281d3153dSAlexander V. Chernikov static void
57381d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
57481d3153dSAlexander V. Chernikov {
57581d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
57681d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
57781d3153dSAlexander V. Chernikov 	int error;
57881d3153dSAlexander V. Chernikov 
57981d3153dSAlexander V. Chernikov 	if (ac == 0)
58081d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
58181d3153dSAlexander V. Chernikov 
58281d3153dSAlexander V. Chernikov 	error = table_do_lookup(oh, *av, &xi, &xtent);
58381d3153dSAlexander V. Chernikov 
58481d3153dSAlexander V. Chernikov 	switch (error) {
58581d3153dSAlexander V. Chernikov 	case 0:
58681d3153dSAlexander V. Chernikov 		break;
58781d3153dSAlexander V. Chernikov 	case ESRCH:
58881d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
58981d3153dSAlexander V. Chernikov 	case ENOENT:
59081d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
59181d3153dSAlexander V. Chernikov 	case ENOTSUP:
59281d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
59381d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
59481d3153dSAlexander V. Chernikov 	default:
59581d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
59681d3153dSAlexander V. Chernikov 	}
59781d3153dSAlexander V. Chernikov 
59881d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
59981d3153dSAlexander V. Chernikov }
600ac35ff17SAlexander V. Chernikov 
601ac35ff17SAlexander V. Chernikov static void
602ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
603ac35ff17SAlexander V. Chernikov {
604ac35ff17SAlexander V. Chernikov 	char *p;
605ac35ff17SAlexander V. Chernikov 	int mask, af;
606ac35ff17SAlexander V. Chernikov 	struct in6_addr *paddr;
607ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
608ac35ff17SAlexander V. Chernikov 	int masklen;
609ac35ff17SAlexander V. Chernikov 
610ac35ff17SAlexander V. Chernikov 	masklen = 0;
611ac35ff17SAlexander V. Chernikov 	af = 0;
612ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
613ac35ff17SAlexander V. Chernikov 
614ac35ff17SAlexander V. Chernikov 	switch (type) {
615ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
616ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
617ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
618ac35ff17SAlexander V. Chernikov 			*p = '\0';
619ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
620ac35ff17SAlexander V. Chernikov 		}
621ac35ff17SAlexander V. Chernikov 
622ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
623ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
624ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
625ac35ff17SAlexander V. Chernikov 				    p + 1);
626ac35ff17SAlexander V. Chernikov 
627ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
628ac35ff17SAlexander V. Chernikov 			af = AF_INET;
629ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
630ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
631ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
632ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
633ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
634ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
635ac35ff17SAlexander V. Chernikov 				    p + 1);
636ac35ff17SAlexander V. Chernikov 
637ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
638ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
639ac35ff17SAlexander V. Chernikov 		} else {
640ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
641ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
642ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
643ac35ff17SAlexander V. Chernikov 
644ac35ff17SAlexander V. Chernikov 			masklen = 32;
645ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
646ac35ff17SAlexander V. Chernikov 			af = AF_INET;
647ac35ff17SAlexander V. Chernikov 		}
648ac35ff17SAlexander V. Chernikov 		break;
649ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
650ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
651ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
652ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
653ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
654ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
655ac35ff17SAlexander V. Chernikov 		break;
656ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_U32:
657ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
658ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
659ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
660ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
661ac35ff17SAlexander V. Chernikov 
662ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
663ac35ff17SAlexander V. Chernikov 		*pkey = key;
664ac35ff17SAlexander V. Chernikov 		masklen = 32;
665ac35ff17SAlexander V. Chernikov 		break;
666ac35ff17SAlexander V. Chernikov 	default:
667ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
668ac35ff17SAlexander V. Chernikov 	}
669ac35ff17SAlexander V. Chernikov 
670ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
671ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
672ac35ff17SAlexander V. Chernikov }
673ac35ff17SAlexander V. Chernikov 
674ac35ff17SAlexander V. Chernikov static void
675ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
67681d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
677ac35ff17SAlexander V. Chernikov {
678ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
679ac35ff17SAlexander V. Chernikov 	int error;
680*db785d31SAlexander V. Chernikov 	char *del;
681ac35ff17SAlexander V. Chernikov 
682ac35ff17SAlexander V. Chernikov 	type = 0;
683ac35ff17SAlexander V. Chernikov 	vtype = 0;
684ac35ff17SAlexander V. Chernikov 
68581d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
68681d3153dSAlexander V. Chernikov 
68781d3153dSAlexander V. Chernikov 	if (error == 0) {
68881d3153dSAlexander V. Chernikov 		/* Table found. */
68981d3153dSAlexander V. Chernikov 		type = xi->type;
69081d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
69181d3153dSAlexander V. Chernikov 	} else {
69281d3153dSAlexander V. Chernikov 		if (error != ESRCH)
69381d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
69481d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
695ac35ff17SAlexander V. Chernikov 		/*
69681d3153dSAlexander V. Chernikov 		 * Table does not exist.
69781d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
69881d3153dSAlexander V. Chernikov 		 * before failing.
699ac35ff17SAlexander V. Chernikov 		 */
700*db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
701*db785d31SAlexander V. Chernikov 			*del = '\0';
702ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
703ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
704ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
705ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
706ac35ff17SAlexander V. Chernikov 			/*
70781d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
70881d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
709ac35ff17SAlexander V. Chernikov 			 */
71081d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
71181d3153dSAlexander V. Chernikov 		} else {
71281d3153dSAlexander V. Chernikov 			/* Inknown key */
71381d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
714*db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
71581d3153dSAlexander V. Chernikov 		}
716*db785d31SAlexander V. Chernikov 		if (del != NULL)
717*db785d31SAlexander V. Chernikov 			*del = '/';
718ac35ff17SAlexander V. Chernikov 	}
719ac35ff17SAlexander V. Chernikov 
720ac35ff17SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type);
721ac35ff17SAlexander V. Chernikov 
722ac35ff17SAlexander V. Chernikov 	*ptype = type;
723ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
724ac35ff17SAlexander V. Chernikov }
725ac35ff17SAlexander V. Chernikov 
726ac35ff17SAlexander V. Chernikov static void
727ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
728ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
729ac35ff17SAlexander V. Chernikov {
730ac35ff17SAlexander V. Chernikov 	int code;
731ac35ff17SAlexander V. Chernikov 	char *p;
732ac35ff17SAlexander V. Chernikov 
733ac35ff17SAlexander V. Chernikov 	switch (vtype) {
734ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
735ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
736ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
737ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
738ac35ff17SAlexander V. Chernikov 		break;
739ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
740ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
741ac35ff17SAlexander V. Chernikov 			break;
742ac35ff17SAlexander V. Chernikov 		/* Try hostname */
743ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
744ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
745ac35ff17SAlexander V. Chernikov 		break;
746ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
747ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
748ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
749ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
750ac35ff17SAlexander V. Chernikov 		} else {
751ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
752ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
753ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
754ac35ff17SAlexander V. Chernikov 		}
755ac35ff17SAlexander V. Chernikov 		tent->value = code;
756ac35ff17SAlexander V. Chernikov 		break;
757ac35ff17SAlexander V. Chernikov 	default:
758ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
759ac35ff17SAlexander V. Chernikov 	}
760ac35ff17SAlexander V. Chernikov }
761f1220db8SAlexander V. Chernikov 
762f1220db8SAlexander V. Chernikov /*
763f1220db8SAlexander V. Chernikov  * Compare table names.
764f1220db8SAlexander V. Chernikov  * Honor number comparison.
765f1220db8SAlexander V. Chernikov  */
766f1220db8SAlexander V. Chernikov static int
767f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
768f1220db8SAlexander V. Chernikov {
769f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
770f1220db8SAlexander V. Chernikov 	int la, lb;
771f1220db8SAlexander V. Chernikov 
772f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
773f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
774f1220db8SAlexander V. Chernikov 	la = strlen(ia->tablename);
775f1220db8SAlexander V. Chernikov 	lb = strlen(ib->tablename);
776f1220db8SAlexander V. Chernikov 
777f1220db8SAlexander V. Chernikov 	if (la > lb)
778f1220db8SAlexander V. Chernikov 		return (1);
779f1220db8SAlexander V. Chernikov 	else if (la < lb)
780f1220db8SAlexander V. Chernikov 		return (-01);
781f1220db8SAlexander V. Chernikov 
782f1220db8SAlexander V. Chernikov 	return (strcmp(ia->tablename, ib->tablename));
783f1220db8SAlexander V. Chernikov }
784f1220db8SAlexander V. Chernikov 
785f1220db8SAlexander V. Chernikov /*
786f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
787f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
788f1220db8SAlexander V. Chernikov  * Returns 0 on success.
789f1220db8SAlexander V. Chernikov  */
790f1220db8SAlexander V. Chernikov static int
791f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
792f1220db8SAlexander V. Chernikov {
793f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
794f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
795f1220db8SAlexander V. Chernikov 	size_t sz;
796f1220db8SAlexander V. Chernikov 	int i, error;
797f1220db8SAlexander V. Chernikov 
798f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
799f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
800f1220db8SAlexander V. Chernikov 
801d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
802f1220db8SAlexander V. Chernikov 		return (errno);
803f1220db8SAlexander V. Chernikov 
804f1220db8SAlexander V. Chernikov 	sz = req.size;
805f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
806f1220db8SAlexander V. Chernikov 		return (ENOMEM);
807f1220db8SAlexander V. Chernikov 
808f1220db8SAlexander V. Chernikov 	olh->size = sz;
809d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
810f1220db8SAlexander V. Chernikov 		free(olh);
811f1220db8SAlexander V. Chernikov 		return (errno);
812f1220db8SAlexander V. Chernikov 	}
813f1220db8SAlexander V. Chernikov 
814f1220db8SAlexander V. Chernikov 	if (sort != 0)
815f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
816f1220db8SAlexander V. Chernikov 
817f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
818f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
819f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
820f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
821f1220db8SAlexander V. Chernikov 	}
822f1220db8SAlexander V. Chernikov 
823f1220db8SAlexander V. Chernikov 	free(olh);
824f1220db8SAlexander V. Chernikov 
825f1220db8SAlexander V. Chernikov 	return (0);
826f1220db8SAlexander V. Chernikov }
827f1220db8SAlexander V. Chernikov 
828f1220db8SAlexander V. Chernikov /*
829f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
830d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
831d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
832f1220db8SAlexander V. Chernikov  *
833f1220db8SAlexander V. Chernikov  * Returns 0 on success.
834f1220db8SAlexander V. Chernikov  */
835f1220db8SAlexander V. Chernikov static int
836f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
837f1220db8SAlexander V. Chernikov {
838f1220db8SAlexander V. Chernikov 	size_t sz;
83981d3153dSAlexander V. Chernikov 	int error, c;
840f1220db8SAlexander V. Chernikov 
84181d3153dSAlexander V. Chernikov 	sz = 0;
84281d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
843f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
84481d3153dSAlexander V. Chernikov 		if (sz < i->size)
845f1220db8SAlexander V. Chernikov 			sz = i->size;
846f1220db8SAlexander V. Chernikov 
847d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
84881d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
849d3a4f924SAlexander V. Chernikov 
85081d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
851f1220db8SAlexander V. Chernikov 			return (errno);
85281d3153dSAlexander V. Chernikov 	}
853f1220db8SAlexander V. Chernikov 
85481d3153dSAlexander V. Chernikov 	return (ENOMEM);
855f1220db8SAlexander V. Chernikov }
856f1220db8SAlexander V. Chernikov 
857f1220db8SAlexander V. Chernikov /*
858f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
859f1220db8SAlexander V. Chernikov  */
860f1220db8SAlexander V. Chernikov static void
861f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
862f1220db8SAlexander V. Chernikov {
86381d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
86481d3153dSAlexander V. Chernikov 	uint32_t count;
865f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
866f1220db8SAlexander V. Chernikov 
867f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
86881d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
869f1220db8SAlexander V. Chernikov 
870f1220db8SAlexander V. Chernikov 	if (need_header)
871f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
872f1220db8SAlexander V. Chernikov 
873f1220db8SAlexander V. Chernikov 	count = i->count;
874f1220db8SAlexander V. Chernikov 	while (count > 0) {
87581d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
87681d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
87781d3153dSAlexander V. Chernikov 		count--;
87881d3153dSAlexander V. Chernikov 	}
87981d3153dSAlexander V. Chernikov }
88081d3153dSAlexander V. Chernikov 
88181d3153dSAlexander V. Chernikov static void
88281d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
88381d3153dSAlexander V. Chernikov {
88481d3153dSAlexander V. Chernikov 	char tbuf[128];
88581d3153dSAlexander V. Chernikov 	uint32_t tval;
88681d3153dSAlexander V. Chernikov 
88781d3153dSAlexander V. Chernikov 	tval = tent->value;
88881d3153dSAlexander V. Chernikov 
889f1220db8SAlexander V. Chernikov 	switch (i->type) {
890f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
891f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
89281d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
893f1220db8SAlexander V. Chernikov 
894f1220db8SAlexander V. Chernikov 		if (co.do_value_as_ip) {
895f1220db8SAlexander V. Chernikov 			tval = htonl(tval);
89681d3153dSAlexander V. Chernikov 			printf("%s/%u %s\n", tbuf, tent->masklen,
897f1220db8SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
898f1220db8SAlexander V. Chernikov 		} else
89981d3153dSAlexander V. Chernikov 			printf("%s/%u %u\n", tbuf, tent->masklen, tval);
900f1220db8SAlexander V. Chernikov 		break;
901f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
902f1220db8SAlexander V. Chernikov 		/* Interface names */
903f1220db8SAlexander V. Chernikov 		if (co.do_value_as_ip) {
904f1220db8SAlexander V. Chernikov 			tval = htonl(tval);
90581d3153dSAlexander V. Chernikov 			printf("%s %s\n", tent->k.iface,
906f1220db8SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
907f1220db8SAlexander V. Chernikov 		} else
90881d3153dSAlexander V. Chernikov 			printf("%s %u\n", tent->k.iface, tval);
909f1220db8SAlexander V. Chernikov 	}
910f1220db8SAlexander V. Chernikov }
911f1220db8SAlexander V. Chernikov 
9126c2997ffSAlexander V. Chernikov int
9136c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
9146c2997ffSAlexander V. Chernikov {
9156c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
9166c2997ffSAlexander V. Chernikov 
9176c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
9186c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
9196c2997ffSAlexander V. Chernikov 
9206c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
9216c2997ffSAlexander V. Chernikov 		return (-1);
9226c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
9236c2997ffSAlexander V. Chernikov 		return (1);
9246c2997ffSAlexander V. Chernikov 
9256c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
9266c2997ffSAlexander V. Chernikov 		return (-1);
9276c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
9286c2997ffSAlexander V. Chernikov 		return (1);
9296c2997ffSAlexander V. Chernikov 
9306c2997ffSAlexander V. Chernikov 	return (0);
9316c2997ffSAlexander V. Chernikov }
932563b5ab1SAlexander V. Chernikov 
933563b5ab1SAlexander V. Chernikov int
9346c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
935563b5ab1SAlexander V. Chernikov {
936563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
937563b5ab1SAlexander V. Chernikov 	uint16_t key;
938563b5ab1SAlexander V. Chernikov 
939563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
940563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
941563b5ab1SAlexander V. Chernikov 
942563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
943563b5ab1SAlexander V. Chernikov 		return (-1);
944563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
945563b5ab1SAlexander V. Chernikov 		return (1);
946563b5ab1SAlexander V. Chernikov 
947563b5ab1SAlexander V. Chernikov 	return (0);
948563b5ab1SAlexander V. Chernikov }
949563b5ab1SAlexander V. Chernikov 
950563b5ab1SAlexander V. Chernikov /*
951563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
952563b5ab1SAlexander V. Chernikov  * Uses the following facts:
953563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
954563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
955563b5ab1SAlexander V. Chernikov  *
956563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
957563b5ab1SAlexander V. Chernikov  */
958563b5ab1SAlexander V. Chernikov char *
959563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
960563b5ab1SAlexander V. Chernikov {
961563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
962563b5ab1SAlexander V. Chernikov 
963563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
9646c2997ffSAlexander V. Chernikov 	    compare_kntlv);
965563b5ab1SAlexander V. Chernikov 
966563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
967563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
968563b5ab1SAlexander V. Chernikov 
969563b5ab1SAlexander V. Chernikov 	return (NULL);
970563b5ab1SAlexander V. Chernikov }
971563b5ab1SAlexander V. Chernikov 
9726c2997ffSAlexander V. Chernikov void
9736c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
9746c2997ffSAlexander V. Chernikov {
9756c2997ffSAlexander V. Chernikov 
9766c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
9776c2997ffSAlexander V. Chernikov }
9786c2997ffSAlexander V. Chernikov 
9796c2997ffSAlexander V. Chernikov int
9806c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
9816c2997ffSAlexander V. Chernikov {
9826c2997ffSAlexander V. Chernikov 	int c, i, l;
9836c2997ffSAlexander V. Chernikov 
9846c2997ffSAlexander V. Chernikov 	/*
9856c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
9866c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
987ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
9886c2997ffSAlexander V. Chernikov 	 */
9896c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
9906c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
9916c2997ffSAlexander V. Chernikov 		return (EINVAL);
9926c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
9936c2997ffSAlexander V. Chernikov 		c = tablename[i];
9946c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
9956c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
9966c2997ffSAlexander V. Chernikov 			continue;
9976c2997ffSAlexander V. Chernikov 		return (EINVAL);
9986c2997ffSAlexander V. Chernikov 	}
9996c2997ffSAlexander V. Chernikov 
1000ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1001ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1002ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1003ac35ff17SAlexander V. Chernikov 
10046c2997ffSAlexander V. Chernikov 	return (0);
10056c2997ffSAlexander V. Chernikov }
10066c2997ffSAlexander V. Chernikov 
1007