xref: /freebsd/sbin/ipfw/tables.c (revision 81d3153d)
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 {
468ac35ff17SAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
469ac35ff17SAlexander V. Chernikov 	int error;
470ac35ff17SAlexander V. Chernikov 
471ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
472ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
473ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
474ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
475ac35ff17SAlexander V. Chernikov 
476ac35ff17SAlexander V. Chernikov 	memcpy(oh + 1, tent, sizeof(*tent));
477ac35ff17SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
478ac35ff17SAlexander V. Chernikov 	if (update != 0)
47981d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
480ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
481ac35ff17SAlexander V. Chernikov 
482ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
483ac35ff17SAlexander V. Chernikov 
484ac35ff17SAlexander V. Chernikov 	return (error);
485ac35ff17SAlexander V. Chernikov }
486ac35ff17SAlexander V. Chernikov 
487ac35ff17SAlexander V. Chernikov static void
488ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
489ac35ff17SAlexander V. Chernikov {
490ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
49181d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
492ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
493ac35ff17SAlexander V. Chernikov 	int cmd;
494ac35ff17SAlexander V. Chernikov 	char *texterr;
495ac35ff17SAlexander V. Chernikov 
496ac35ff17SAlexander V. Chernikov 	if (ac == 0)
497ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
498ac35ff17SAlexander V. Chernikov 
499ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
500ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
501ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
502ac35ff17SAlexander V. Chernikov 
50381d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
504ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
505ac35ff17SAlexander V. Chernikov 	ac--; av++;
506ac35ff17SAlexander V. Chernikov 
507ac35ff17SAlexander V. Chernikov 	if (add != 0) {
508ac35ff17SAlexander V. Chernikov 		if (ac > 0)
509ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
510ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
511ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XADD)";
512ac35ff17SAlexander V. Chernikov 	} else {
513ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
514ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XDEL)";
515ac35ff17SAlexander V. Chernikov 	}
516ac35ff17SAlexander V. Chernikov 
517ac35ff17SAlexander V. Chernikov 	if (table_do_modify_record(cmd, oh, &tent, update) != 0)
518ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "%s", texterr);
519ac35ff17SAlexander V. Chernikov }
520ac35ff17SAlexander V. Chernikov 
52181d3153dSAlexander V. Chernikov static int
52281d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
52381d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
52481d3153dSAlexander V. Chernikov {
52581d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
52681d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
52781d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
52881d3153dSAlexander V. Chernikov 	int error;
52981d3153dSAlexander V. Chernikov 	size_t sz;
53081d3153dSAlexander V. Chernikov 
53181d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
53281d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
53381d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
53481d3153dSAlexander V. Chernikov 
53581d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
53681d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
53781d3153dSAlexander V. Chernikov 	tent->idx = 1;
53881d3153dSAlexander V. Chernikov 
53981d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
54081d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
54181d3153dSAlexander V. Chernikov 
54281d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
54381d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
54481d3153dSAlexander V. Chernikov 		return (error);
54581d3153dSAlexander V. Chernikov 
54681d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
54781d3153dSAlexander V. Chernikov 		return (EINVAL);
54881d3153dSAlexander V. Chernikov 
54981d3153dSAlexander V. Chernikov 	*xtent = *tent;
55081d3153dSAlexander V. Chernikov 
55181d3153dSAlexander V. Chernikov 	return (0);
55281d3153dSAlexander V. Chernikov }
55381d3153dSAlexander V. Chernikov 
55481d3153dSAlexander V. Chernikov static void
55581d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
55681d3153dSAlexander V. Chernikov {
55781d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
55881d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
55981d3153dSAlexander V. Chernikov 	int error;
56081d3153dSAlexander V. Chernikov 
56181d3153dSAlexander V. Chernikov 	if (ac == 0)
56281d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
56381d3153dSAlexander V. Chernikov 
56481d3153dSAlexander V. Chernikov 	error = table_do_lookup(oh, *av, &xi, &xtent);
56581d3153dSAlexander V. Chernikov 
56681d3153dSAlexander V. Chernikov 	switch (error) {
56781d3153dSAlexander V. Chernikov 	case 0:
56881d3153dSAlexander V. Chernikov 		break;
56981d3153dSAlexander V. Chernikov 	case ESRCH:
57081d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
57181d3153dSAlexander V. Chernikov 	case ENOENT:
57281d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
57381d3153dSAlexander V. Chernikov 	case ENOTSUP:
57481d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
57581d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
57681d3153dSAlexander V. Chernikov 	default:
57781d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
57881d3153dSAlexander V. Chernikov 	}
57981d3153dSAlexander V. Chernikov 
58081d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
58181d3153dSAlexander V. Chernikov }
582ac35ff17SAlexander V. Chernikov 
583ac35ff17SAlexander V. Chernikov static void
584ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
585ac35ff17SAlexander V. Chernikov {
586ac35ff17SAlexander V. Chernikov 	char *p;
587ac35ff17SAlexander V. Chernikov 	int mask, af;
588ac35ff17SAlexander V. Chernikov 	struct in6_addr *paddr;
589ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
590ac35ff17SAlexander V. Chernikov 	int masklen;
591ac35ff17SAlexander V. Chernikov 
592ac35ff17SAlexander V. Chernikov 	masklen = 0;
593ac35ff17SAlexander V. Chernikov 	af = 0;
594ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
595ac35ff17SAlexander V. Chernikov 
596ac35ff17SAlexander V. Chernikov 	switch (type) {
597ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
598ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
599ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
600ac35ff17SAlexander V. Chernikov 			*p = '\0';
601ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
602ac35ff17SAlexander V. Chernikov 		}
603ac35ff17SAlexander V. Chernikov 
604ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
605ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
606ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
607ac35ff17SAlexander V. Chernikov 				    p + 1);
608ac35ff17SAlexander V. Chernikov 
609ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
610ac35ff17SAlexander V. Chernikov 			af = AF_INET;
611ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
612ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
613ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
614ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
615ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
616ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
617ac35ff17SAlexander V. Chernikov 				    p + 1);
618ac35ff17SAlexander V. Chernikov 
619ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
620ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
621ac35ff17SAlexander V. Chernikov 		} else {
622ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
623ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
624ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
625ac35ff17SAlexander V. Chernikov 
626ac35ff17SAlexander V. Chernikov 			masklen = 32;
627ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
628ac35ff17SAlexander V. Chernikov 			af = AF_INET;
629ac35ff17SAlexander V. Chernikov 		}
630ac35ff17SAlexander V. Chernikov 		break;
631ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
632ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
633ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
634ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
635ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
636ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
637ac35ff17SAlexander V. Chernikov 		break;
638ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_U32:
639ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
640ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
641ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
642ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
643ac35ff17SAlexander V. Chernikov 
644ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
645ac35ff17SAlexander V. Chernikov 		*pkey = key;
646ac35ff17SAlexander V. Chernikov 		masklen = 32;
647ac35ff17SAlexander V. Chernikov 		break;
648ac35ff17SAlexander V. Chernikov 	default:
649ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
650ac35ff17SAlexander V. Chernikov 	}
651ac35ff17SAlexander V. Chernikov 
652ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
653ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
654ac35ff17SAlexander V. Chernikov }
655ac35ff17SAlexander V. Chernikov 
656ac35ff17SAlexander V. Chernikov static void
657ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
65881d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
659ac35ff17SAlexander V. Chernikov {
660ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
661ac35ff17SAlexander V. Chernikov 	int error;
662ac35ff17SAlexander V. Chernikov 
663ac35ff17SAlexander V. Chernikov 	type = 0;
664ac35ff17SAlexander V. Chernikov 	vtype = 0;
665ac35ff17SAlexander V. Chernikov 
66681d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
66781d3153dSAlexander V. Chernikov 
66881d3153dSAlexander V. Chernikov 	if (error == 0) {
66981d3153dSAlexander V. Chernikov 		/* Table found. */
67081d3153dSAlexander V. Chernikov 		type = xi->type;
67181d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
67281d3153dSAlexander V. Chernikov 	} else {
67381d3153dSAlexander V. Chernikov 		if (error != ESRCH)
67481d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
67581d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
676ac35ff17SAlexander V. Chernikov 		/*
67781d3153dSAlexander V. Chernikov 		 * Table does not exist.
67881d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
67981d3153dSAlexander V. Chernikov 		 * before failing.
680ac35ff17SAlexander V. Chernikov 		 */
681ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
682ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
683ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
684ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
685ac35ff17SAlexander V. Chernikov 			/*
68681d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
68781d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
688ac35ff17SAlexander V. Chernikov 			 */
68981d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
69081d3153dSAlexander V. Chernikov 		} else {
69181d3153dSAlexander V. Chernikov 			/* Inknown key */
69281d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
693ac35ff17SAlexander V. Chernikov 			    "key type", oh->ntlv.name);
69481d3153dSAlexander V. Chernikov 		}
695ac35ff17SAlexander V. Chernikov 	}
696ac35ff17SAlexander V. Chernikov 
697ac35ff17SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type);
698ac35ff17SAlexander V. Chernikov 
699ac35ff17SAlexander V. Chernikov 	*ptype = type;
700ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
701ac35ff17SAlexander V. Chernikov }
702ac35ff17SAlexander V. Chernikov 
703ac35ff17SAlexander V. Chernikov static void
704ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
705ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
706ac35ff17SAlexander V. Chernikov {
707ac35ff17SAlexander V. Chernikov 	int code;
708ac35ff17SAlexander V. Chernikov 	char *p;
709ac35ff17SAlexander V. Chernikov 
710ac35ff17SAlexander V. Chernikov 	switch (vtype) {
711ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
712ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
713ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
714ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
715ac35ff17SAlexander V. Chernikov 		break;
716ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
717ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
718ac35ff17SAlexander V. Chernikov 			break;
719ac35ff17SAlexander V. Chernikov 		/* Try hostname */
720ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
721ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
722ac35ff17SAlexander V. Chernikov 		break;
723ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
724ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
725ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
726ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
727ac35ff17SAlexander V. Chernikov 		} else {
728ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
729ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
730ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
731ac35ff17SAlexander V. Chernikov 		}
732ac35ff17SAlexander V. Chernikov 		tent->value = code;
733ac35ff17SAlexander V. Chernikov 		break;
734ac35ff17SAlexander V. Chernikov 	default:
735ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
736ac35ff17SAlexander V. Chernikov 	}
737ac35ff17SAlexander V. Chernikov }
738f1220db8SAlexander V. Chernikov 
739f1220db8SAlexander V. Chernikov /*
740f1220db8SAlexander V. Chernikov  * Compare table names.
741f1220db8SAlexander V. Chernikov  * Honor number comparison.
742f1220db8SAlexander V. Chernikov  */
743f1220db8SAlexander V. Chernikov static int
744f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
745f1220db8SAlexander V. Chernikov {
746f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
747f1220db8SAlexander V. Chernikov 	int la, lb;
748f1220db8SAlexander V. Chernikov 
749f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
750f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
751f1220db8SAlexander V. Chernikov 	la = strlen(ia->tablename);
752f1220db8SAlexander V. Chernikov 	lb = strlen(ib->tablename);
753f1220db8SAlexander V. Chernikov 
754f1220db8SAlexander V. Chernikov 	if (la > lb)
755f1220db8SAlexander V. Chernikov 		return (1);
756f1220db8SAlexander V. Chernikov 	else if (la < lb)
757f1220db8SAlexander V. Chernikov 		return (-01);
758f1220db8SAlexander V. Chernikov 
759f1220db8SAlexander V. Chernikov 	return (strcmp(ia->tablename, ib->tablename));
760f1220db8SAlexander V. Chernikov }
761f1220db8SAlexander V. Chernikov 
762f1220db8SAlexander V. Chernikov /*
763f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
764f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
765f1220db8SAlexander V. Chernikov  * Returns 0 on success.
766f1220db8SAlexander V. Chernikov  */
767f1220db8SAlexander V. Chernikov static int
768f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
769f1220db8SAlexander V. Chernikov {
770f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
771f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
772f1220db8SAlexander V. Chernikov 	size_t sz;
773f1220db8SAlexander V. Chernikov 	int i, error;
774f1220db8SAlexander V. Chernikov 
775f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
776f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
777f1220db8SAlexander V. Chernikov 
778d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
779f1220db8SAlexander V. Chernikov 		return (errno);
780f1220db8SAlexander V. Chernikov 
781f1220db8SAlexander V. Chernikov 	sz = req.size;
782f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
783f1220db8SAlexander V. Chernikov 		return (ENOMEM);
784f1220db8SAlexander V. Chernikov 
785f1220db8SAlexander V. Chernikov 	olh->size = sz;
786d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
787f1220db8SAlexander V. Chernikov 		free(olh);
788f1220db8SAlexander V. Chernikov 		return (errno);
789f1220db8SAlexander V. Chernikov 	}
790f1220db8SAlexander V. Chernikov 
791f1220db8SAlexander V. Chernikov 	if (sort != 0)
792f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
793f1220db8SAlexander V. Chernikov 
794f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
795f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
796f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
797f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
798f1220db8SAlexander V. Chernikov 	}
799f1220db8SAlexander V. Chernikov 
800f1220db8SAlexander V. Chernikov 	free(olh);
801f1220db8SAlexander V. Chernikov 
802f1220db8SAlexander V. Chernikov 	return (0);
803f1220db8SAlexander V. Chernikov }
804f1220db8SAlexander V. Chernikov 
805f1220db8SAlexander V. Chernikov /*
806f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
807d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
808d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
809f1220db8SAlexander V. Chernikov  *
810f1220db8SAlexander V. Chernikov  * Returns 0 on success.
811f1220db8SAlexander V. Chernikov  */
812f1220db8SAlexander V. Chernikov static int
813f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
814f1220db8SAlexander V. Chernikov {
815f1220db8SAlexander V. Chernikov 	size_t sz;
81681d3153dSAlexander V. Chernikov 	int error, c;
817f1220db8SAlexander V. Chernikov 
81881d3153dSAlexander V. Chernikov 	sz = 0;
81981d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
820f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
82181d3153dSAlexander V. Chernikov 		if (sz < i->size)
822f1220db8SAlexander V. Chernikov 			sz = i->size;
823f1220db8SAlexander V. Chernikov 
824d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
82581d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
826d3a4f924SAlexander V. Chernikov 
82781d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
828f1220db8SAlexander V. Chernikov 			return (errno);
82981d3153dSAlexander V. Chernikov 	}
830f1220db8SAlexander V. Chernikov 
83181d3153dSAlexander V. Chernikov 	return (ENOMEM);
832f1220db8SAlexander V. Chernikov }
833f1220db8SAlexander V. Chernikov 
834f1220db8SAlexander V. Chernikov /*
835f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
836f1220db8SAlexander V. Chernikov  */
837f1220db8SAlexander V. Chernikov static void
838f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
839f1220db8SAlexander V. Chernikov {
84081d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
84181d3153dSAlexander V. Chernikov 	uint32_t count;
842f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
843f1220db8SAlexander V. Chernikov 
844f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
84581d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
846f1220db8SAlexander V. Chernikov 
847f1220db8SAlexander V. Chernikov 	if (need_header)
848f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
849f1220db8SAlexander V. Chernikov 
850f1220db8SAlexander V. Chernikov 	count = i->count;
851f1220db8SAlexander V. Chernikov 	while (count > 0) {
85281d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
85381d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
85481d3153dSAlexander V. Chernikov 		count--;
85581d3153dSAlexander V. Chernikov 	}
85681d3153dSAlexander V. Chernikov }
85781d3153dSAlexander V. Chernikov 
85881d3153dSAlexander V. Chernikov static void
85981d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
86081d3153dSAlexander V. Chernikov {
86181d3153dSAlexander V. Chernikov 	char tbuf[128];
86281d3153dSAlexander V. Chernikov 	uint32_t tval;
86381d3153dSAlexander V. Chernikov 
86481d3153dSAlexander V. Chernikov 	tval = tent->value;
86581d3153dSAlexander V. Chernikov 
866f1220db8SAlexander V. Chernikov 	switch (i->type) {
867f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
868f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
86981d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
870f1220db8SAlexander V. Chernikov 
871f1220db8SAlexander V. Chernikov 		if (co.do_value_as_ip) {
872f1220db8SAlexander V. Chernikov 			tval = htonl(tval);
87381d3153dSAlexander V. Chernikov 			printf("%s/%u %s\n", tbuf, tent->masklen,
874f1220db8SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
875f1220db8SAlexander V. Chernikov 		} else
87681d3153dSAlexander V. Chernikov 			printf("%s/%u %u\n", tbuf, tent->masklen, tval);
877f1220db8SAlexander V. Chernikov 		break;
878f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
879f1220db8SAlexander V. Chernikov 		/* Interface names */
880f1220db8SAlexander V. Chernikov 		if (co.do_value_as_ip) {
881f1220db8SAlexander V. Chernikov 			tval = htonl(tval);
88281d3153dSAlexander V. Chernikov 			printf("%s %s\n", tent->k.iface,
883f1220db8SAlexander V. Chernikov 			    inet_ntoa(*(struct in_addr *)&tval));
884f1220db8SAlexander V. Chernikov 		} else
88581d3153dSAlexander V. Chernikov 			printf("%s %u\n", tent->k.iface, tval);
886f1220db8SAlexander V. Chernikov 	}
887f1220db8SAlexander V. Chernikov }
888f1220db8SAlexander V. Chernikov 
8896c2997ffSAlexander V. Chernikov int
8906c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
8916c2997ffSAlexander V. Chernikov {
8926c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
8936c2997ffSAlexander V. Chernikov 
8946c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
8956c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
8966c2997ffSAlexander V. Chernikov 
8976c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
8986c2997ffSAlexander V. Chernikov 		return (-1);
8996c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
9006c2997ffSAlexander V. Chernikov 		return (1);
9016c2997ffSAlexander V. Chernikov 
9026c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
9036c2997ffSAlexander V. Chernikov 		return (-1);
9046c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
9056c2997ffSAlexander V. Chernikov 		return (1);
9066c2997ffSAlexander V. Chernikov 
9076c2997ffSAlexander V. Chernikov 	return (0);
9086c2997ffSAlexander V. Chernikov }
909563b5ab1SAlexander V. Chernikov 
910563b5ab1SAlexander V. Chernikov int
9116c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
912563b5ab1SAlexander V. Chernikov {
913563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
914563b5ab1SAlexander V. Chernikov 	uint16_t key;
915563b5ab1SAlexander V. Chernikov 
916563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
917563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
918563b5ab1SAlexander V. Chernikov 
919563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
920563b5ab1SAlexander V. Chernikov 		return (-1);
921563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
922563b5ab1SAlexander V. Chernikov 		return (1);
923563b5ab1SAlexander V. Chernikov 
924563b5ab1SAlexander V. Chernikov 	return (0);
925563b5ab1SAlexander V. Chernikov }
926563b5ab1SAlexander V. Chernikov 
927563b5ab1SAlexander V. Chernikov /*
928563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
929563b5ab1SAlexander V. Chernikov  * Uses the following facts:
930563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
931563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
932563b5ab1SAlexander V. Chernikov  *
933563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
934563b5ab1SAlexander V. Chernikov  */
935563b5ab1SAlexander V. Chernikov char *
936563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
937563b5ab1SAlexander V. Chernikov {
938563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
939563b5ab1SAlexander V. Chernikov 
940563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
9416c2997ffSAlexander V. Chernikov 	    compare_kntlv);
942563b5ab1SAlexander V. Chernikov 
943563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
944563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
945563b5ab1SAlexander V. Chernikov 
946563b5ab1SAlexander V. Chernikov 	return (NULL);
947563b5ab1SAlexander V. Chernikov }
948563b5ab1SAlexander V. Chernikov 
9496c2997ffSAlexander V. Chernikov void
9506c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
9516c2997ffSAlexander V. Chernikov {
9526c2997ffSAlexander V. Chernikov 
9536c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
9546c2997ffSAlexander V. Chernikov }
9556c2997ffSAlexander V. Chernikov 
9566c2997ffSAlexander V. Chernikov int
9576c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
9586c2997ffSAlexander V. Chernikov {
9596c2997ffSAlexander V. Chernikov 	int c, i, l;
9606c2997ffSAlexander V. Chernikov 
9616c2997ffSAlexander V. Chernikov 	/*
9626c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
9636c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
964ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
9656c2997ffSAlexander V. Chernikov 	 */
9666c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
9676c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
9686c2997ffSAlexander V. Chernikov 		return (EINVAL);
9696c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
9706c2997ffSAlexander V. Chernikov 		c = tablename[i];
9716c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
9726c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
9736c2997ffSAlexander V. Chernikov 			continue;
9746c2997ffSAlexander V. Chernikov 		return (EINVAL);
9756c2997ffSAlexander V. Chernikov 	}
9766c2997ffSAlexander V. Chernikov 
977ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
978ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
979ac35ff17SAlexander V. Chernikov 		return (EINVAL);
980ac35ff17SAlexander V. Chernikov 
9816c2997ffSAlexander V. Chernikov 	return (0);
9826c2997ffSAlexander V. Chernikov }
9836c2997ffSAlexander V. Chernikov 
984