xref: /freebsd/sbin/ipfw/tables.c (revision 358b9d09)
1f1220db8SAlexander V. Chernikov /*
2f1220db8SAlexander V. Chernikov  * Copyright (c) 2002-2003 Luigi Rizzo
3f1220db8SAlexander V. Chernikov  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4f1220db8SAlexander V. Chernikov  * Copyright (c) 1994 Ugen J.S.Antsilevich
5f1220db8SAlexander V. Chernikov  *
6f1220db8SAlexander V. Chernikov  * Idea and grammar partially left from:
7f1220db8SAlexander V. Chernikov  * Copyright (c) 1993 Daniel Boulet
8f1220db8SAlexander V. Chernikov  *
9f1220db8SAlexander V. Chernikov  * Redistribution and use in source forms, with and without modification,
10f1220db8SAlexander V. Chernikov  * are permitted provided that this entire comment appears intact.
11f1220db8SAlexander V. Chernikov  *
12f1220db8SAlexander V. Chernikov  * Redistribution in binary form may occur without any restrictions.
13f1220db8SAlexander V. Chernikov  * Obviously, it would be nice if you gave credit where credit is due
14f1220db8SAlexander V. Chernikov  * but requiring it would be too onerous.
15f1220db8SAlexander V. Chernikov  *
16f1220db8SAlexander V. Chernikov  * This software is provided ``AS IS'' without any warranties of any kind.
17f1220db8SAlexander V. Chernikov  *
18f1220db8SAlexander V. Chernikov  * in-kernel tables support
19f1220db8SAlexander V. Chernikov  *
20f1220db8SAlexander V. Chernikov  * $FreeBSD: projects/ipfw/sbin/ipfw/ipfw2.c 267467 2014-06-14 10:58:39Z melifaro $
21f1220db8SAlexander V. Chernikov  */
22f1220db8SAlexander V. Chernikov 
23f1220db8SAlexander V. Chernikov 
24f1220db8SAlexander V. Chernikov #include <sys/types.h>
25f1220db8SAlexander V. Chernikov #include <sys/param.h>
26f1220db8SAlexander V. Chernikov #include <sys/socket.h>
27f1220db8SAlexander V. Chernikov #include <sys/sysctl.h>
28f1220db8SAlexander V. Chernikov 
29f1220db8SAlexander V. Chernikov #include <ctype.h>
30f1220db8SAlexander V. Chernikov #include <err.h>
31f1220db8SAlexander V. Chernikov #include <errno.h>
32f1220db8SAlexander V. Chernikov #include <netdb.h>
33f1220db8SAlexander V. Chernikov #include <stddef.h>	/* offsetof */
34f1220db8SAlexander V. Chernikov #include <stdio.h>
35f1220db8SAlexander V. Chernikov #include <stdlib.h>
36f1220db8SAlexander V. Chernikov #include <string.h>
37f1220db8SAlexander V. Chernikov #include <sysexits.h>
38f1220db8SAlexander V. Chernikov 
39f1220db8SAlexander V. Chernikov #define IPFW_INTERNAL	/* Access to protected structures in ip_fw.h. */
40f1220db8SAlexander V. Chernikov 
41f1220db8SAlexander V. Chernikov #include <net/if.h>
42f1220db8SAlexander V. Chernikov #include <net/if_dl.h>
43f1220db8SAlexander V. Chernikov #include <net/route.h> /* def. of struct route */
44f1220db8SAlexander V. Chernikov #include <netinet/in.h>
45f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h>
46f1220db8SAlexander V. Chernikov #include <arpa/inet.h>
47f1220db8SAlexander V. Chernikov #include <alias.h>
48f1220db8SAlexander V. Chernikov 
49f1220db8SAlexander V. Chernikov #include "ipfw2.h"
50f1220db8SAlexander V. Chernikov 
51f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header);
52ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
53ac35ff17SAlexander V. Chernikov     int add, int update);
54ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh);
55ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh);
56ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
57ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
5881d3153dSAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
59ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
60f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
61ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
62ac35ff17SAlexander V. Chernikov     uint16_t uidx);
63f1220db8SAlexander V. Chernikov 
64f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
65f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
66f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
67f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
6881d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
69f1220db8SAlexander V. Chernikov 
70ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7181d3153dSAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
72ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
73ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
74ac35ff17SAlexander V. Chernikov 
75f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
76f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
77f1220db8SAlexander V. Chernikov 
78f1220db8SAlexander V. Chernikov #ifndef s6_addr32
79f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
80f1220db8SAlexander V. Chernikov #endif
81f1220db8SAlexander V. Chernikov 
82ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
83ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
84ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
85b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
86914bffb6SAlexander V. Chernikov       { "flow",		IPFW_TABLE_FLOW },
87ac35ff17SAlexander V. Chernikov       { NULL, 0 }
88ac35ff17SAlexander V. Chernikov };
89ac35ff17SAlexander V. Chernikov 
90ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
91ac35ff17SAlexander V. Chernikov       { "dscp",		IPFW_VTYPE_DSCP },
92ac35ff17SAlexander V. Chernikov       { "ip",		IPFW_VTYPE_IP },
93ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
94ac35ff17SAlexander V. Chernikov       { NULL, 0 }
95ac35ff17SAlexander V. Chernikov };
96ac35ff17SAlexander V. Chernikov 
97ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
98ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
99ac35ff17SAlexander V. Chernikov       { "create",	TOK_CREATE },
100ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
101ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
102ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
103ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
104358b9d09SAlexander V. Chernikov       { "detail",	TOK_DETAIL },
105ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
10681d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
107ac35ff17SAlexander V. Chernikov       { NULL, 0 }
108ac35ff17SAlexander V. Chernikov };
109ac35ff17SAlexander V. Chernikov 
110f1220db8SAlexander V. Chernikov static int
111f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
112f1220db8SAlexander V. Chernikov {
113f1220db8SAlexander V. Chernikov 	struct hostent *he;
114f1220db8SAlexander V. Chernikov 
115f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
116f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
117f1220db8SAlexander V. Chernikov 			return(-1);
118f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
119f1220db8SAlexander V. Chernikov 	}
120f1220db8SAlexander V. Chernikov 	return(0);
121f1220db8SAlexander V. Chernikov }
122f1220db8SAlexander V. Chernikov 
123f1220db8SAlexander V. Chernikov /*
124f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
125ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
126ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
127ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
128ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
129ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
130ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
131ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
132f1220db8SAlexander V. Chernikov  */
133f1220db8SAlexander V. Chernikov void
134f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
135f1220db8SAlexander V. Chernikov {
136ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
137ac35ff17SAlexander V. Chernikov 	int error, tcmd;
138ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
139ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
140f1220db8SAlexander V. Chernikov 	char *tablename;
141ac35ff17SAlexander V. Chernikov 	uint32_t set;
142358b9d09SAlexander V. Chernikov 	void *arg;
143f1220db8SAlexander V. Chernikov 
144ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
145ac35ff17SAlexander V. Chernikov 	is_all = 0;
146ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
147ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
148ac35ff17SAlexander V. Chernikov 	else
149ac35ff17SAlexander V. Chernikov 		set = 0;
150f1220db8SAlexander V. Chernikov 
151f1220db8SAlexander V. Chernikov 	ac--; av++;
1529d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
153f1220db8SAlexander V. Chernikov 	tablename = *av;
154f1220db8SAlexander V. Chernikov 
155ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
156ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
157ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
158ac35ff17SAlexander V. Chernikov 	} else {
159ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
160ac35ff17SAlexander V. Chernikov 			is_all = 1;
161ac35ff17SAlexander V. Chernikov 		else
162ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
163ac35ff17SAlexander V. Chernikov 	}
164ac35ff17SAlexander V. Chernikov 	ac--; av++;
1659d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
166ac35ff17SAlexander V. Chernikov 
167ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
168ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
169ac35ff17SAlexander V. Chernikov 
170ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
171ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
172ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
173358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
174ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
175ac35ff17SAlexander V. Chernikov 		break;
176ac35ff17SAlexander V. Chernikov 	default:
177ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
178ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
179ac35ff17SAlexander V. Chernikov 	}
180ac35ff17SAlexander V. Chernikov 
181ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
182ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
183ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
184f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
185f1220db8SAlexander V. Chernikov 		ac--; av++;
186ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
187ac35ff17SAlexander V. Chernikov 		break;
188ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
189f1220db8SAlexander V. Chernikov 		ac--; av++;
190ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
191ac35ff17SAlexander V. Chernikov 		break;
192ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
193ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
194ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
195ac35ff17SAlexander V. Chernikov 		break;
196ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
197f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
198ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
199f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
200f1220db8SAlexander V. Chernikov 				    tablename);
201f1220db8SAlexander V. Chernikov 		} else {
202ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
203f1220db8SAlexander V. Chernikov 			if (error != 0)
204f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
205f1220db8SAlexander V. Chernikov 		}
206ac35ff17SAlexander V. Chernikov 		break;
207358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
208ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
209358b9d09SAlexander V. Chernikov 		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
210f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
211ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
212f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
213358b9d09SAlexander V. Chernikov 			table_show_info(&i, arg);
214f1220db8SAlexander V. Chernikov 		} else {
215358b9d09SAlexander V. Chernikov 			error = tables_foreach(table_show_info, arg, 1);
216f1220db8SAlexander V. Chernikov 			if (error != 0)
217f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
218f1220db8SAlexander V. Chernikov 		}
219ac35ff17SAlexander V. Chernikov 		break;
220ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
221ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
222ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
223ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
224ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
225ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
226f1220db8SAlexander V. Chernikov 		} else {
227ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
228ac35ff17SAlexander V. Chernikov 			if (error != 0)
229ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
230f1220db8SAlexander V. Chernikov 		}
231ac35ff17SAlexander V. Chernikov 		break;
23281d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
23381d3153dSAlexander V. Chernikov 		ac--; av++;
23481d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
23581d3153dSAlexander V. Chernikov 		break;
236f1220db8SAlexander V. Chernikov 	}
237f1220db8SAlexander V. Chernikov }
238f1220db8SAlexander V. Chernikov 
239f1220db8SAlexander V. Chernikov static void
240ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
241f1220db8SAlexander V. Chernikov {
242f1220db8SAlexander V. Chernikov 
243563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
244f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
245f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
246ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
247f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
248f1220db8SAlexander V. Chernikov }
249f1220db8SAlexander V. Chernikov 
250f1220db8SAlexander V. Chernikov static void
251f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
252f1220db8SAlexander V. Chernikov {
253f1220db8SAlexander V. Chernikov 
254f1220db8SAlexander V. Chernikov 	oh->idx = 1;
25581d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
256ac35ff17SAlexander V. Chernikov }
257ac35ff17SAlexander V. Chernikov 
258ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
259ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE },
260ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
261ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
2624c0c07a5SAlexander V. Chernikov       { "limit",	TOK_LIMIT },
263ac35ff17SAlexander V. Chernikov       { NULL, 0 }
264ac35ff17SAlexander V. Chernikov };
265ac35ff17SAlexander V. Chernikov 
266914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
267914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
268914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
269914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
270914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
271914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
272914bffb6SAlexander V. Chernikov       { NULL, 0 }
273914bffb6SAlexander V. Chernikov };
274914bffb6SAlexander V. Chernikov 
275914bffb6SAlexander V. Chernikov int
276914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
277914bffb6SAlexander V. Chernikov {
278914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
279914bffb6SAlexander V. Chernikov 
280914bffb6SAlexander V. Chernikov 	/* Parse type options */
281914bffb6SAlexander V. Chernikov 	switch(ttype) {
282914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
283914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
284914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
285914bffb6SAlexander V. Chernikov 		    &fclear);
286914bffb6SAlexander V. Chernikov 		*tflags = fset;
287914bffb6SAlexander V. Chernikov 		break;
288914bffb6SAlexander V. Chernikov 	default:
289914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
290914bffb6SAlexander V. Chernikov 	}
291914bffb6SAlexander V. Chernikov 
292914bffb6SAlexander V. Chernikov 	return (0);
293914bffb6SAlexander V. Chernikov }
294914bffb6SAlexander V. Chernikov 
295914bffb6SAlexander V. Chernikov void
296914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
297914bffb6SAlexander V. Chernikov {
298914bffb6SAlexander V. Chernikov 	const char *tname;
299914bffb6SAlexander V. Chernikov 	int l;
300914bffb6SAlexander V. Chernikov 
301914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
302914bffb6SAlexander V. Chernikov 		tname = "unknown";
303914bffb6SAlexander V. Chernikov 
304914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
305914bffb6SAlexander V. Chernikov 	tbuf += l;
306914bffb6SAlexander V. Chernikov 	size -= l;
307914bffb6SAlexander V. Chernikov 
308914bffb6SAlexander V. Chernikov 	switch(type) {
309914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
310914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
311914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
312914bffb6SAlexander V. Chernikov 			l--;
313914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
314914bffb6SAlexander V. Chernikov 		}
315914bffb6SAlexander V. Chernikov 		break;
316914bffb6SAlexander V. Chernikov 	}
317914bffb6SAlexander V. Chernikov }
318914bffb6SAlexander V. Chernikov 
319ac35ff17SAlexander V. Chernikov /*
320ac35ff17SAlexander V. Chernikov  * Creates new table
321ac35ff17SAlexander V. Chernikov  *
322ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
323ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
324ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
325ac35ff17SAlexander V. Chernikov  *
326ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
327ac35ff17SAlexander V. Chernikov  */
328ac35ff17SAlexander V. Chernikov static void
329ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
330ac35ff17SAlexander V. Chernikov {
331ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
332ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
333ac35ff17SAlexander V. Chernikov 	size_t sz;
334914bffb6SAlexander V. Chernikov 	char *p;
335ac35ff17SAlexander V. Chernikov 	char tbuf[128];
336ac35ff17SAlexander V. Chernikov 
337ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
338ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
339ac35ff17SAlexander V. Chernikov 
340ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
341ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
342ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
343ac35ff17SAlexander V. Chernikov 
344ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
345ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
346ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
347ac35ff17SAlexander V. Chernikov 		ac--; av++;
348ac35ff17SAlexander V. Chernikov 
349ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
3504c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
3514c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
3524c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
3534c0c07a5SAlexander V. Chernikov 			ac--; av++;
3544c0c07a5SAlexander V. Chernikov 			break;
355ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
356ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
357914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
358914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
359914bffb6SAlexander V. Chernikov 				*p++ = '\0';
360ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
361914bffb6SAlexander V. Chernikov 			if (val == -1) {
362914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
363914bffb6SAlexander V. Chernikov 				    ", ");
364914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
365914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
366ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
367914bffb6SAlexander V. Chernikov 			}
368914bffb6SAlexander V. Chernikov 			xi.type = val;
369914bffb6SAlexander V. Chernikov 			if (p != NULL) {
370914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
371914bffb6SAlexander V. Chernikov 				if (error != 0)
372914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
373914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
374914bffb6SAlexander V. Chernikov 			}
375914bffb6SAlexander V. Chernikov 			ac--; av++;
376ac35ff17SAlexander V. Chernikov 			break;
377ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
378ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
379ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
380ac35ff17SAlexander V. Chernikov 			if (val != -1) {
381ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
382ac35ff17SAlexander V. Chernikov 				ac--; av++;
383ac35ff17SAlexander V. Chernikov 				break;
384ac35ff17SAlexander V. Chernikov 			}
385ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
386ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
387ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
388ac35ff17SAlexander V. Chernikov 			break;
389ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
390ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
391ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
392ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
393ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
394ac35ff17SAlexander V. Chernikov 			ac--; av++;
395ac35ff17SAlexander V. Chernikov 			break;
396ac35ff17SAlexander V. Chernikov 		}
397ac35ff17SAlexander V. Chernikov 	}
398ac35ff17SAlexander V. Chernikov 
399ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
400ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
401f1220db8SAlexander V. Chernikov }
402f1220db8SAlexander V. Chernikov 
403f1220db8SAlexander V. Chernikov /*
404ac35ff17SAlexander V. Chernikov  * Creates new table
405ac35ff17SAlexander V. Chernikov  *
406ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
407ac35ff17SAlexander V. Chernikov  *
408f1220db8SAlexander V. Chernikov  * Returns 0 on success.
409f1220db8SAlexander V. Chernikov  */
410f1220db8SAlexander V. Chernikov static int
411ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
412f1220db8SAlexander V. Chernikov {
413ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
414ac35ff17SAlexander V. Chernikov 	int error;
415f1220db8SAlexander V. Chernikov 
416ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
417ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
418ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
419ac35ff17SAlexander V. Chernikov 
420ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
421ac35ff17SAlexander V. Chernikov 
422ac35ff17SAlexander V. Chernikov 	return (error);
423ac35ff17SAlexander V. Chernikov }
424ac35ff17SAlexander V. Chernikov 
425ac35ff17SAlexander V. Chernikov /*
426ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
427ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
428ac35ff17SAlexander V. Chernikov  */
429ac35ff17SAlexander V. Chernikov static int
430ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
431ac35ff17SAlexander V. Chernikov {
432ac35ff17SAlexander V. Chernikov 
433ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
434f1220db8SAlexander V. Chernikov 		return (-1);
435f1220db8SAlexander V. Chernikov 
436f1220db8SAlexander V. Chernikov 	return (0);
437f1220db8SAlexander V. Chernikov }
438f1220db8SAlexander V. Chernikov 
439f1220db8SAlexander V. Chernikov /*
440ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
441f1220db8SAlexander V. Chernikov  * Returns 0 on success.
442f1220db8SAlexander V. Chernikov  */
443f1220db8SAlexander V. Chernikov static int
444ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
445f1220db8SAlexander V. Chernikov {
446f1220db8SAlexander V. Chernikov 
447ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
448f1220db8SAlexander V. Chernikov 		return (-1);
449f1220db8SAlexander V. Chernikov 
450f1220db8SAlexander V. Chernikov 	return (0);
451f1220db8SAlexander V. Chernikov }
452f1220db8SAlexander V. Chernikov 
453f1220db8SAlexander V. Chernikov /*
454ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
455f1220db8SAlexander V. Chernikov  * it inside @i.
456f1220db8SAlexander V. Chernikov  * Returns 0 on success.
457f1220db8SAlexander V. Chernikov  */
458f1220db8SAlexander V. Chernikov static int
459ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
460f1220db8SAlexander V. Chernikov {
461f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
462ac35ff17SAlexander V. Chernikov 	int error;
463f1220db8SAlexander V. Chernikov 	size_t sz;
464f1220db8SAlexander V. Chernikov 
465f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
466f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
467ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
468f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
469f1220db8SAlexander V. Chernikov 
470ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
471ac35ff17SAlexander V. Chernikov 		return (error);
472f1220db8SAlexander V. Chernikov 
473f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
474ac35ff17SAlexander V. Chernikov 		return (EINVAL);
475f1220db8SAlexander V. Chernikov 
476f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
477f1220db8SAlexander V. Chernikov 
478f1220db8SAlexander V. Chernikov 	return (0);
479f1220db8SAlexander V. Chernikov }
480f1220db8SAlexander V. Chernikov 
4815f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
4825f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
4835f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
4845f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
4855f379342SAlexander V. Chernikov       { NULL, 0 }
4865f379342SAlexander V. Chernikov };
4875f379342SAlexander V. Chernikov 
4885f379342SAlexander V. Chernikov struct ta_cldata {
4895f379342SAlexander V. Chernikov 	uint8_t		taclass;
4905f379342SAlexander V. Chernikov 	uint8_t		spare4;
4915f379342SAlexander V. Chernikov 	uint16_t	itemsize;
4925f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
4935f379342SAlexander V. Chernikov 	uint32_t	size;
4945f379342SAlexander V. Chernikov 	uint32_t	count;
4955f379342SAlexander V. Chernikov };
4965f379342SAlexander V. Chernikov 
4975f379342SAlexander V. Chernikov /*
4985f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
4995f379342SAlexander V. Chernikov  */
5005f379342SAlexander V. Chernikov static void
5015f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
5025f379342SAlexander V. Chernikov     const char *af, const char *taclass)
5035f379342SAlexander V. Chernikov {
5045f379342SAlexander V. Chernikov 
5055f379342SAlexander V. Chernikov 	switch (d->taclass) {
5065f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
5075f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
5085f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
5095f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
5105f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
5115f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
5125f379342SAlexander V. Chernikov 		else
5135f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
5145f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
5155f379342SAlexander V. Chernikov 			    d->size, d->count,
5165f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
5175f379342SAlexander V. Chernikov 		break;
5185f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
5195f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
5205f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
5215f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
5225f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
5235f379342SAlexander V. Chernikov 		else
5245f379342SAlexander V. Chernikov 			printf("  items: %u "
5255f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
5265f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
5275f379342SAlexander V. Chernikov 		break;
5285f379342SAlexander V. Chernikov 	default:
5295f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
5305f379342SAlexander V. Chernikov 	}
5315f379342SAlexander V. Chernikov }
5325f379342SAlexander V. Chernikov 
533f1220db8SAlexander V. Chernikov /*
534f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
535f1220db8SAlexander V. Chernikov  */
536f1220db8SAlexander V. Chernikov static int
537f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
538f1220db8SAlexander V. Chernikov {
539914bffb6SAlexander V. Chernikov 	const char *vtype;
5405f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
5415f379342SAlexander V. Chernikov 	int afdata, afitem;
5425f379342SAlexander V. Chernikov 	struct ta_cldata d;
543914bffb6SAlexander V. Chernikov 	char ttype[64];
544f1220db8SAlexander V. Chernikov 
545914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
546ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
547ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
548ac35ff17SAlexander V. Chernikov 
549914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
550914bffb6SAlexander V. Chernikov 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
5519d099b4fSAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
5529d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
553f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
5544c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
5554c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
556f1220db8SAlexander V. Chernikov 
557358b9d09SAlexander V. Chernikov 	/* Print algo-specific info if requested & set  */
558358b9d09SAlexander V. Chernikov 	if (arg == NULL)
559358b9d09SAlexander V. Chernikov 		return (0);
560358b9d09SAlexander V. Chernikov 
5615f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
5625f379342SAlexander V. Chernikov 		return (0);
5635f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
5645f379342SAlexander V. Chernikov 
5655f379342SAlexander V. Chernikov 	afdata = 0;
5665f379342SAlexander V. Chernikov 	afitem = 0;
5675f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
5685f379342SAlexander V. Chernikov 		afdata = 1;
5695f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
5705f379342SAlexander V. Chernikov 		afitem = 1;
5715f379342SAlexander V. Chernikov 
5725f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
5735f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
5745f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
5755f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
5765f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
5775f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
5785f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
5795f379342SAlexander V. Chernikov 	else
5805f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
5815f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
5825f379342SAlexander V. Chernikov 		vtype = "unknown";
5835f379342SAlexander V. Chernikov 
5845f379342SAlexander V. Chernikov 	if (afdata == 0) {
5855f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
5865f379342SAlexander V. Chernikov 	} else {
5875f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
5885f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
5895f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
5905f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
5915f379342SAlexander V. Chernikov 			vtype = "unknown";
5925f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
5935f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
5945f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
5955f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
5965f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
5975f379342SAlexander V. Chernikov 	}
5985f379342SAlexander V. Chernikov 
599f1220db8SAlexander V. Chernikov 	return (0);
600f1220db8SAlexander V. Chernikov }
601f1220db8SAlexander V. Chernikov 
602f1220db8SAlexander V. Chernikov 
603f1220db8SAlexander V. Chernikov /*
604f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
605f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
606f1220db8SAlexander V. Chernikov  */
607f1220db8SAlexander V. Chernikov 
608f1220db8SAlexander V. Chernikov static int
609f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
610f1220db8SAlexander V. Chernikov {
611f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
61281d3153dSAlexander V. Chernikov 	int error;
613f1220db8SAlexander V. Chernikov 
614ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
615f1220db8SAlexander V. Chernikov 		return (ENOMEM);
616f1220db8SAlexander V. Chernikov 
61781d3153dSAlexander V. Chernikov 	if ((error = table_get_list(i, oh)) != 0) {
61881d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
61981d3153dSAlexander V. Chernikov 		return (error);
62081d3153dSAlexander V. Chernikov 	}
62181d3153dSAlexander V. Chernikov 
622f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
623f1220db8SAlexander V. Chernikov 
624f1220db8SAlexander V. Chernikov 	free(oh);
625f1220db8SAlexander V. Chernikov 	return (0);
626f1220db8SAlexander V. Chernikov }
627f1220db8SAlexander V. Chernikov 
628f1220db8SAlexander V. Chernikov static int
629f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
630f1220db8SAlexander V. Chernikov {
631ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
632f1220db8SAlexander V. Chernikov 
633ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
634ac35ff17SAlexander V. Chernikov 
635ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
636ac35ff17SAlexander V. Chernikov 
637ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
638f1220db8SAlexander V. Chernikov }
639f1220db8SAlexander V. Chernikov 
640ac35ff17SAlexander V. Chernikov static int
641ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
642ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
643ac35ff17SAlexander V. Chernikov {
644db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
645db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
646ac35ff17SAlexander V. Chernikov 	int error;
647ac35ff17SAlexander V. Chernikov 
648ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
649ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
650ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
651ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
652ac35ff17SAlexander V. Chernikov 
653db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
654db785d31SAlexander V. Chernikov 	ctlv->count = 1;
655db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
656db785d31SAlexander V. Chernikov 
657db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
658db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
659ac35ff17SAlexander V. Chernikov 	if (update != 0)
66081d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
661ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
662ac35ff17SAlexander V. Chernikov 
663ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
664ac35ff17SAlexander V. Chernikov 
665ac35ff17SAlexander V. Chernikov 	return (error);
666ac35ff17SAlexander V. Chernikov }
667ac35ff17SAlexander V. Chernikov 
668ac35ff17SAlexander V. Chernikov static void
669ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
670ac35ff17SAlexander V. Chernikov {
671ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
67281d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
673ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
6744c0c07a5SAlexander V. Chernikov 	int cmd, error;
6754c0c07a5SAlexander V. Chernikov 	char *texterr, *etxt;
676ac35ff17SAlexander V. Chernikov 
677ac35ff17SAlexander V. Chernikov 	if (ac == 0)
678ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
679ac35ff17SAlexander V. Chernikov 
680ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
681ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
682ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
683ac35ff17SAlexander V. Chernikov 
68481d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
685db785d31SAlexander V. Chernikov 
686db785d31SAlexander V. Chernikov 	/*
687db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
688db785d31SAlexander V. Chernikov 	 */
689db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
690db785d31SAlexander V. Chernikov 		xi.type = type;
691db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
692db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
693db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
694db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
695db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
696db785d31SAlexander V. Chernikov 	}
697db785d31SAlexander V. Chernikov 
698ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
699ac35ff17SAlexander V. Chernikov 	ac--; av++;
700ac35ff17SAlexander V. Chernikov 
701ac35ff17SAlexander V. Chernikov 	if (add != 0) {
702ac35ff17SAlexander V. Chernikov 		if (ac > 0)
703ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
704ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
7054c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
706ac35ff17SAlexander V. Chernikov 	} else {
707ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
7084c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
709ac35ff17SAlexander V. Chernikov 	}
710ac35ff17SAlexander V. Chernikov 
7114c0c07a5SAlexander V. Chernikov 	if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0)
7124c0c07a5SAlexander V. Chernikov 		return;
7134c0c07a5SAlexander V. Chernikov 
7144c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
7154c0c07a5SAlexander V. Chernikov 	switch (error) {
7164c0c07a5SAlexander V. Chernikov 	case EEXIST:
7174c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
7184c0c07a5SAlexander V. Chernikov 		break;
7194c0c07a5SAlexander V. Chernikov 	case EFBIG:
7204c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
7214c0c07a5SAlexander V. Chernikov 		break;
7224c0c07a5SAlexander V. Chernikov 	case ESRCH:
7234c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
7244c0c07a5SAlexander V. Chernikov 		break;
7254c0c07a5SAlexander V. Chernikov 	case ENOENT:
7264c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
7274c0c07a5SAlexander V. Chernikov 		break;
7284c0c07a5SAlexander V. Chernikov 	default:
7294c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
7304c0c07a5SAlexander V. Chernikov 	}
7314c0c07a5SAlexander V. Chernikov 
7324c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
733ac35ff17SAlexander V. Chernikov }
734ac35ff17SAlexander V. Chernikov 
73581d3153dSAlexander V. Chernikov static int
73681d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
73781d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
73881d3153dSAlexander V. Chernikov {
73981d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
74081d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
74181d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
74281d3153dSAlexander V. Chernikov 	int error;
74381d3153dSAlexander V. Chernikov 	size_t sz;
74481d3153dSAlexander V. Chernikov 
74581d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
74681d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
74781d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
74881d3153dSAlexander V. Chernikov 
74981d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
75081d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
75181d3153dSAlexander V. Chernikov 	tent->idx = 1;
75281d3153dSAlexander V. Chernikov 
75381d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
75481d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
75581d3153dSAlexander V. Chernikov 
75681d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
75781d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
75881d3153dSAlexander V. Chernikov 		return (error);
75981d3153dSAlexander V. Chernikov 
76081d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
76181d3153dSAlexander V. Chernikov 		return (EINVAL);
76281d3153dSAlexander V. Chernikov 
76381d3153dSAlexander V. Chernikov 	*xtent = *tent;
76481d3153dSAlexander V. Chernikov 
76581d3153dSAlexander V. Chernikov 	return (0);
76681d3153dSAlexander V. Chernikov }
76781d3153dSAlexander V. Chernikov 
76881d3153dSAlexander V. Chernikov static void
76981d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
77081d3153dSAlexander V. Chernikov {
77181d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
77281d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
773914bffb6SAlexander V. Chernikov 	char key[64];
77481d3153dSAlexander V. Chernikov 	int error;
77581d3153dSAlexander V. Chernikov 
77681d3153dSAlexander V. Chernikov 	if (ac == 0)
77781d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
77881d3153dSAlexander V. Chernikov 
779914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
780914bffb6SAlexander V. Chernikov 
781914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
78281d3153dSAlexander V. Chernikov 
78381d3153dSAlexander V. Chernikov 	switch (error) {
78481d3153dSAlexander V. Chernikov 	case 0:
78581d3153dSAlexander V. Chernikov 		break;
78681d3153dSAlexander V. Chernikov 	case ESRCH:
78781d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
78881d3153dSAlexander V. Chernikov 	case ENOENT:
78981d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
79081d3153dSAlexander V. Chernikov 	case ENOTSUP:
79181d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
79281d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
79381d3153dSAlexander V. Chernikov 	default:
79481d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
79581d3153dSAlexander V. Chernikov 	}
79681d3153dSAlexander V. Chernikov 
79781d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
79881d3153dSAlexander V. Chernikov }
799ac35ff17SAlexander V. Chernikov 
800ac35ff17SAlexander V. Chernikov static void
801914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
802914bffb6SAlexander V. Chernikov     uint8_t tflags)
803ac35ff17SAlexander V. Chernikov {
804914bffb6SAlexander V. Chernikov 	char *p, *pp;
805ac35ff17SAlexander V. Chernikov 	int mask, af;
806914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
807914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
808ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
809914bffb6SAlexander V. Chernikov 	uint16_t port;
810914bffb6SAlexander V. Chernikov 	struct protoent *pent;
811914bffb6SAlexander V. Chernikov 	struct servent *sent;
812ac35ff17SAlexander V. Chernikov 	int masklen;
813ac35ff17SAlexander V. Chernikov 
814ac35ff17SAlexander V. Chernikov 	masklen = 0;
815ac35ff17SAlexander V. Chernikov 	af = 0;
816ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
817ac35ff17SAlexander V. Chernikov 
818ac35ff17SAlexander V. Chernikov 	switch (type) {
819ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
820ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
821ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
822ac35ff17SAlexander V. Chernikov 			*p = '\0';
823ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
824ac35ff17SAlexander V. Chernikov 		}
825ac35ff17SAlexander V. Chernikov 
826ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
827ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
828ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
829ac35ff17SAlexander V. Chernikov 				    p + 1);
830ac35ff17SAlexander V. Chernikov 
831ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
832ac35ff17SAlexander V. Chernikov 			af = AF_INET;
833ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
834ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
835ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
836ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
837ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
838ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
839ac35ff17SAlexander V. Chernikov 				    p + 1);
840ac35ff17SAlexander V. Chernikov 
841ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
842ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
843ac35ff17SAlexander V. Chernikov 		} else {
844ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
845ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
846ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
847ac35ff17SAlexander V. Chernikov 
848ac35ff17SAlexander V. Chernikov 			masklen = 32;
849ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
850ac35ff17SAlexander V. Chernikov 			af = AF_INET;
851ac35ff17SAlexander V. Chernikov 		}
852ac35ff17SAlexander V. Chernikov 		break;
853ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
854ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
855ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
856ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
857ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
858ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
859ac35ff17SAlexander V. Chernikov 		break;
860b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
861ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
862ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
863ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
864ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
865ac35ff17SAlexander V. Chernikov 
866ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
867ac35ff17SAlexander V. Chernikov 		*pkey = key;
868ac35ff17SAlexander V. Chernikov 		masklen = 32;
869ac35ff17SAlexander V. Chernikov 		break;
870914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
871914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
872914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
873914bffb6SAlexander V. Chernikov 		af = 0;
874914bffb6SAlexander V. Chernikov 
875914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
876914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
877914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
878914bffb6SAlexander V. Chernikov 				*p++ = '\0';
879914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
880914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
881914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
882914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
883914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
884914bffb6SAlexander V. Chernikov 				af = AF_INET;
885914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
886914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
887914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
888914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
889914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
890914bffb6SAlexander V. Chernikov 				af = AF_INET6;
891914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
892914bffb6SAlexander V. Chernikov 			}
893914bffb6SAlexander V. Chernikov 
894914bffb6SAlexander V. Chernikov 			arg = p;
895914bffb6SAlexander V. Chernikov 		}
896914bffb6SAlexander V. Chernikov 
897914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
898914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
899914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
900914bffb6SAlexander V. Chernikov 				*p++ = '\0';
901914bffb6SAlexander V. Chernikov 
902914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
903914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
904914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
905914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
906914bffb6SAlexander V. Chernikov 					    arg);
907914bffb6SAlexander V. Chernikov 				else
908914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
909914bffb6SAlexander V. Chernikov 			}
910914bffb6SAlexander V. Chernikov 
911914bffb6SAlexander V. Chernikov 			if (key > 255)
912914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
913914bffb6SAlexander V. Chernikov 
914914bffb6SAlexander V. Chernikov 			tfe->proto = key;
915914bffb6SAlexander V. Chernikov 
916914bffb6SAlexander V. Chernikov 			arg = p;
917914bffb6SAlexander V. Chernikov 		}
918914bffb6SAlexander V. Chernikov 
919914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
920914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
921914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
922914bffb6SAlexander V. Chernikov 				*p++ = '\0';
923914bffb6SAlexander V. Chernikov 
924914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
925914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
926914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
927914bffb6SAlexander V. Chernikov 					    arg);
928914bffb6SAlexander V. Chernikov 				else
929914bffb6SAlexander V. Chernikov 					key = sent->s_port;
930914bffb6SAlexander V. Chernikov 			}
931914bffb6SAlexander V. Chernikov 
932914bffb6SAlexander V. Chernikov 			tfe->sport = port;
933914bffb6SAlexander V. Chernikov 
934914bffb6SAlexander V. Chernikov 			arg = p;
935914bffb6SAlexander V. Chernikov 		}
936914bffb6SAlexander V. Chernikov 
937914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
938914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
939914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
940914bffb6SAlexander V. Chernikov 				*p++ = '\0';
941914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
942914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
943914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
944914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
945914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
946914bffb6SAlexander V. Chernikov 				af = AF_INET;
947914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
948914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
949914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
950914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
951914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
952914bffb6SAlexander V. Chernikov 				af = AF_INET6;
953914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
954914bffb6SAlexander V. Chernikov 			}
955914bffb6SAlexander V. Chernikov 
956914bffb6SAlexander V. Chernikov 			arg = p;
957914bffb6SAlexander V. Chernikov 		}
958914bffb6SAlexander V. Chernikov 
959914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
960914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
961914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
962914bffb6SAlexander V. Chernikov 				*p++ = '\0';
963914bffb6SAlexander V. Chernikov 
964914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
965914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
966914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
967914bffb6SAlexander V. Chernikov 					    arg);
968914bffb6SAlexander V. Chernikov 				else
969914bffb6SAlexander V. Chernikov 					key = sent->s_port;
970914bffb6SAlexander V. Chernikov 			}
971914bffb6SAlexander V. Chernikov 
972914bffb6SAlexander V. Chernikov 			tfe->dport = port;
973914bffb6SAlexander V. Chernikov 
974914bffb6SAlexander V. Chernikov 			arg = p;
975914bffb6SAlexander V. Chernikov 		}
976914bffb6SAlexander V. Chernikov 
977914bffb6SAlexander V. Chernikov 		tfe->af = af;
978914bffb6SAlexander V. Chernikov 
979914bffb6SAlexander V. Chernikov 		break;
980914bffb6SAlexander V. Chernikov 
981ac35ff17SAlexander V. Chernikov 	default:
982ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
983ac35ff17SAlexander V. Chernikov 	}
984ac35ff17SAlexander V. Chernikov 
985ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
986ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
987ac35ff17SAlexander V. Chernikov }
988ac35ff17SAlexander V. Chernikov 
989ac35ff17SAlexander V. Chernikov static void
990ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
99181d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
992ac35ff17SAlexander V. Chernikov {
993914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
994ac35ff17SAlexander V. Chernikov 	int error;
995db785d31SAlexander V. Chernikov 	char *del;
996ac35ff17SAlexander V. Chernikov 
997ac35ff17SAlexander V. Chernikov 	type = 0;
998914bffb6SAlexander V. Chernikov 	tflags = 0;
999ac35ff17SAlexander V. Chernikov 	vtype = 0;
1000ac35ff17SAlexander V. Chernikov 
100181d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
100281d3153dSAlexander V. Chernikov 
100381d3153dSAlexander V. Chernikov 	if (error == 0) {
100481d3153dSAlexander V. Chernikov 		/* Table found. */
100581d3153dSAlexander V. Chernikov 		type = xi->type;
1006914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
100781d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
100881d3153dSAlexander V. Chernikov 	} else {
100981d3153dSAlexander V. Chernikov 		if (error != ESRCH)
101081d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
101181d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
1012ac35ff17SAlexander V. Chernikov 		/*
101381d3153dSAlexander V. Chernikov 		 * Table does not exist.
101481d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
101581d3153dSAlexander V. Chernikov 		 * before failing.
1016ac35ff17SAlexander V. Chernikov 		 */
1017db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1018db785d31SAlexander V. Chernikov 			*del = '\0';
1019ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1020ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1021ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1022ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1023ac35ff17SAlexander V. Chernikov 			/*
102481d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
102581d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1026ac35ff17SAlexander V. Chernikov 			 */
102781d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
102881d3153dSAlexander V. Chernikov 		} else {
102981d3153dSAlexander V. Chernikov 			/* Inknown key */
103081d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1031db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
103281d3153dSAlexander V. Chernikov 		}
1033db785d31SAlexander V. Chernikov 		if (del != NULL)
1034db785d31SAlexander V. Chernikov 			*del = '/';
1035ac35ff17SAlexander V. Chernikov 	}
1036ac35ff17SAlexander V. Chernikov 
1037914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1038ac35ff17SAlexander V. Chernikov 
1039ac35ff17SAlexander V. Chernikov 	*ptype = type;
1040ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1041ac35ff17SAlexander V. Chernikov }
1042ac35ff17SAlexander V. Chernikov 
1043ac35ff17SAlexander V. Chernikov static void
1044ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1045ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1046ac35ff17SAlexander V. Chernikov {
1047ac35ff17SAlexander V. Chernikov 	int code;
1048ac35ff17SAlexander V. Chernikov 	char *p;
1049ac35ff17SAlexander V. Chernikov 
1050ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1051ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1052ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1053ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1054ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1055ac35ff17SAlexander V. Chernikov 		break;
1056ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1057ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1058ac35ff17SAlexander V. Chernikov 			break;
1059ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1060ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1061ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1062ac35ff17SAlexander V. Chernikov 		break;
1063ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1064ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1065ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1066ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1067ac35ff17SAlexander V. Chernikov 		} else {
1068ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1069ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1070ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1071ac35ff17SAlexander V. Chernikov 		}
1072ac35ff17SAlexander V. Chernikov 		tent->value = code;
1073ac35ff17SAlexander V. Chernikov 		break;
1074ac35ff17SAlexander V. Chernikov 	default:
1075ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1076ac35ff17SAlexander V. Chernikov 	}
1077ac35ff17SAlexander V. Chernikov }
1078f1220db8SAlexander V. Chernikov 
1079f1220db8SAlexander V. Chernikov /*
1080f1220db8SAlexander V. Chernikov  * Compare table names.
1081f1220db8SAlexander V. Chernikov  * Honor number comparison.
1082f1220db8SAlexander V. Chernikov  */
1083f1220db8SAlexander V. Chernikov static int
1084f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1085f1220db8SAlexander V. Chernikov {
1086f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1087f1220db8SAlexander V. Chernikov 
1088f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1089f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1090f1220db8SAlexander V. Chernikov 
109168394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1092f1220db8SAlexander V. Chernikov }
1093f1220db8SAlexander V. Chernikov 
1094f1220db8SAlexander V. Chernikov /*
1095f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1096f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1097f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1098f1220db8SAlexander V. Chernikov  */
1099f1220db8SAlexander V. Chernikov static int
1100f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1101f1220db8SAlexander V. Chernikov {
1102f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
1103f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1104f1220db8SAlexander V. Chernikov 	size_t sz;
1105f1220db8SAlexander V. Chernikov 	int i, error;
1106f1220db8SAlexander V. Chernikov 
1107f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
1108f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
1109f1220db8SAlexander V. Chernikov 
1110d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
1111f1220db8SAlexander V. Chernikov 		return (errno);
1112f1220db8SAlexander V. Chernikov 
1113f1220db8SAlexander V. Chernikov 	sz = req.size;
1114f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
1115f1220db8SAlexander V. Chernikov 		return (ENOMEM);
1116f1220db8SAlexander V. Chernikov 
1117f1220db8SAlexander V. Chernikov 	olh->size = sz;
1118d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
1119f1220db8SAlexander V. Chernikov 		free(olh);
1120f1220db8SAlexander V. Chernikov 		return (errno);
1121f1220db8SAlexander V. Chernikov 	}
1122f1220db8SAlexander V. Chernikov 
1123f1220db8SAlexander V. Chernikov 	if (sort != 0)
1124f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1125f1220db8SAlexander V. Chernikov 
1126f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
1127f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
1128f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
1129f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1130f1220db8SAlexander V. Chernikov 	}
1131f1220db8SAlexander V. Chernikov 
1132f1220db8SAlexander V. Chernikov 	free(olh);
1133f1220db8SAlexander V. Chernikov 
1134f1220db8SAlexander V. Chernikov 	return (0);
1135f1220db8SAlexander V. Chernikov }
1136f1220db8SAlexander V. Chernikov 
1137f1220db8SAlexander V. Chernikov /*
1138f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1139d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
1140d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
1141f1220db8SAlexander V. Chernikov  *
1142f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1143f1220db8SAlexander V. Chernikov  */
1144f1220db8SAlexander V. Chernikov static int
1145f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
1146f1220db8SAlexander V. Chernikov {
1147f1220db8SAlexander V. Chernikov 	size_t sz;
114881d3153dSAlexander V. Chernikov 	int error, c;
1149f1220db8SAlexander V. Chernikov 
115081d3153dSAlexander V. Chernikov 	sz = 0;
115181d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
1152f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
115381d3153dSAlexander V. Chernikov 		if (sz < i->size)
1154f1220db8SAlexander V. Chernikov 			sz = i->size;
1155f1220db8SAlexander V. Chernikov 
1156d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
115781d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1158d3a4f924SAlexander V. Chernikov 
115981d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
1160f1220db8SAlexander V. Chernikov 			return (errno);
116181d3153dSAlexander V. Chernikov 	}
1162f1220db8SAlexander V. Chernikov 
116381d3153dSAlexander V. Chernikov 	return (ENOMEM);
1164f1220db8SAlexander V. Chernikov }
1165f1220db8SAlexander V. Chernikov 
1166f1220db8SAlexander V. Chernikov /*
1167f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1168f1220db8SAlexander V. Chernikov  */
1169f1220db8SAlexander V. Chernikov static void
1170f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1171f1220db8SAlexander V. Chernikov {
117281d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
117381d3153dSAlexander V. Chernikov 	uint32_t count;
1174f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1175f1220db8SAlexander V. Chernikov 
1176f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
117781d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1178f1220db8SAlexander V. Chernikov 
1179f1220db8SAlexander V. Chernikov 	if (need_header)
1180f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1181f1220db8SAlexander V. Chernikov 
1182f1220db8SAlexander V. Chernikov 	count = i->count;
1183f1220db8SAlexander V. Chernikov 	while (count > 0) {
118481d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
118581d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
118681d3153dSAlexander V. Chernikov 		count--;
118781d3153dSAlexander V. Chernikov 	}
118881d3153dSAlexander V. Chernikov }
118981d3153dSAlexander V. Chernikov 
119081d3153dSAlexander V. Chernikov static void
119181d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
119281d3153dSAlexander V. Chernikov {
1193914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1194914bffb6SAlexander V. Chernikov 	void *paddr;
119581d3153dSAlexander V. Chernikov 	uint32_t tval;
1196914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
119781d3153dSAlexander V. Chernikov 
119881d3153dSAlexander V. Chernikov 	tval = tent->value;
119981d3153dSAlexander V. Chernikov 
1200914bffb6SAlexander V. Chernikov 	if (co.do_value_as_ip) {
1201914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1202914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1203914bffb6SAlexander V. Chernikov 	} else
1204914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1205914bffb6SAlexander V. Chernikov 
1206f1220db8SAlexander V. Chernikov 	switch (i->type) {
1207f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1208f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
120981d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1210914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1211f1220db8SAlexander V. Chernikov 		break;
1212f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1213f1220db8SAlexander V. Chernikov 		/* Interface names */
1214914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1215b23d5de9SAlexander V. Chernikov 		break;
1216b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1217b23d5de9SAlexander V. Chernikov 		/* numbers */
1218914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1219b23d5de9SAlexander V. Chernikov 		break;
1220914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1221914bffb6SAlexander V. Chernikov 		/* flows */
1222914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1223914bffb6SAlexander V. Chernikov 		comma = "";
1224914bffb6SAlexander V. Chernikov 
1225914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1226914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1227914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1228914bffb6SAlexander V. Chernikov 			else
1229914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1230914bffb6SAlexander V. Chernikov 
1231914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1232914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1233914bffb6SAlexander V. Chernikov 			comma = ",";
1234914bffb6SAlexander V. Chernikov 		}
1235914bffb6SAlexander V. Chernikov 
1236914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1237914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1238914bffb6SAlexander V. Chernikov 			comma = ",";
1239914bffb6SAlexander V. Chernikov 		}
1240914bffb6SAlexander V. Chernikov 
1241914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1242914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1243914bffb6SAlexander V. Chernikov 			comma = ",";
1244914bffb6SAlexander V. Chernikov 		}
1245914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1246914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1247914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1248914bffb6SAlexander V. Chernikov 			else
1249914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1250914bffb6SAlexander V. Chernikov 
1251914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1252914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1253914bffb6SAlexander V. Chernikov 			comma = ",";
1254914bffb6SAlexander V. Chernikov 		}
1255914bffb6SAlexander V. Chernikov 
1256914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1257914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1258914bffb6SAlexander V. Chernikov 			comma = ",";
1259914bffb6SAlexander V. Chernikov 		}
1260914bffb6SAlexander V. Chernikov 
1261914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1262f1220db8SAlexander V. Chernikov 	}
1263f1220db8SAlexander V. Chernikov }
1264f1220db8SAlexander V. Chernikov 
12659d099b4fSAlexander V. Chernikov static int
12669d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
12679d099b4fSAlexander V. Chernikov {
12689d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
12699d099b4fSAlexander V. Chernikov 	size_t sz;
12709d099b4fSAlexander V. Chernikov 	int error;
12719d099b4fSAlexander V. Chernikov 
12729d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
12739d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
12749d099b4fSAlexander V. Chernikov 
12759d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
12769d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
12779d099b4fSAlexander V. Chernikov 		return (error);
12789d099b4fSAlexander V. Chernikov 
12799d099b4fSAlexander V. Chernikov 	sz = req.size;
12809d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
12819d099b4fSAlexander V. Chernikov 		return (ENOMEM);
12829d099b4fSAlexander V. Chernikov 
12839d099b4fSAlexander V. Chernikov 	olh->size = sz;
12849d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
12859d099b4fSAlexander V. Chernikov 		free(olh);
12869d099b4fSAlexander V. Chernikov 		return (error);
12879d099b4fSAlexander V. Chernikov 	}
12889d099b4fSAlexander V. Chernikov 
12899d099b4fSAlexander V. Chernikov 	*polh = olh;
12909d099b4fSAlexander V. Chernikov 	return (0);
12919d099b4fSAlexander V. Chernikov }
12929d099b4fSAlexander V. Chernikov 
12939d099b4fSAlexander V. Chernikov void
12949d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
12959d099b4fSAlexander V. Chernikov {
12969d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
12979d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
12989d099b4fSAlexander V. Chernikov 	int error, i;
12999d099b4fSAlexander V. Chernikov 	const char *atype;
13009d099b4fSAlexander V. Chernikov 
13019d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
13029d099b4fSAlexander V. Chernikov 	if (error != 0)
13039d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
13049d099b4fSAlexander V. Chernikov 
13059d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
13069d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
13079d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
13089d099b4fSAlexander V. Chernikov 			atype = "unknown";
13098ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
13108ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
13119d099b4fSAlexander V. Chernikov 
13129d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
13139d099b4fSAlexander V. Chernikov 	}
13149d099b4fSAlexander V. Chernikov 
13159d099b4fSAlexander V. Chernikov 	free(olh);
13169d099b4fSAlexander V. Chernikov }
13179d099b4fSAlexander V. Chernikov 
13186c2997ffSAlexander V. Chernikov int
13196c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
13206c2997ffSAlexander V. Chernikov {
13216c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
13226c2997ffSAlexander V. Chernikov 
13236c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
13246c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
13256c2997ffSAlexander V. Chernikov 
13266c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
13276c2997ffSAlexander V. Chernikov 		return (-1);
13286c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
13296c2997ffSAlexander V. Chernikov 		return (1);
13306c2997ffSAlexander V. Chernikov 
13316c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
13326c2997ffSAlexander V. Chernikov 		return (-1);
13336c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
13346c2997ffSAlexander V. Chernikov 		return (1);
13356c2997ffSAlexander V. Chernikov 
13366c2997ffSAlexander V. Chernikov 	return (0);
13376c2997ffSAlexander V. Chernikov }
1338563b5ab1SAlexander V. Chernikov 
1339563b5ab1SAlexander V. Chernikov int
13406c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1341563b5ab1SAlexander V. Chernikov {
1342563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1343563b5ab1SAlexander V. Chernikov 	uint16_t key;
1344563b5ab1SAlexander V. Chernikov 
1345563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1346563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1347563b5ab1SAlexander V. Chernikov 
1348563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1349563b5ab1SAlexander V. Chernikov 		return (-1);
1350563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1351563b5ab1SAlexander V. Chernikov 		return (1);
1352563b5ab1SAlexander V. Chernikov 
1353563b5ab1SAlexander V. Chernikov 	return (0);
1354563b5ab1SAlexander V. Chernikov }
1355563b5ab1SAlexander V. Chernikov 
1356563b5ab1SAlexander V. Chernikov /*
1357563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1358563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1359563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1360563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1361563b5ab1SAlexander V. Chernikov  *
1362563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1363563b5ab1SAlexander V. Chernikov  */
1364563b5ab1SAlexander V. Chernikov char *
1365563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1366563b5ab1SAlexander V. Chernikov {
1367563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1368563b5ab1SAlexander V. Chernikov 
1369563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
13706c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1371563b5ab1SAlexander V. Chernikov 
1372563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1373563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1374563b5ab1SAlexander V. Chernikov 
1375563b5ab1SAlexander V. Chernikov 	return (NULL);
1376563b5ab1SAlexander V. Chernikov }
1377563b5ab1SAlexander V. Chernikov 
13786c2997ffSAlexander V. Chernikov void
13796c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
13806c2997ffSAlexander V. Chernikov {
13816c2997ffSAlexander V. Chernikov 
13826c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
13836c2997ffSAlexander V. Chernikov }
13846c2997ffSAlexander V. Chernikov 
13856c2997ffSAlexander V. Chernikov int
13866c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
13876c2997ffSAlexander V. Chernikov {
13886c2997ffSAlexander V. Chernikov 	int c, i, l;
13896c2997ffSAlexander V. Chernikov 
13906c2997ffSAlexander V. Chernikov 	/*
13916c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
13926c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1393ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
13946c2997ffSAlexander V. Chernikov 	 */
13956c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
13966c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
13976c2997ffSAlexander V. Chernikov 		return (EINVAL);
13986c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
13996c2997ffSAlexander V. Chernikov 		c = tablename[i];
14006c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
14016c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
14026c2997ffSAlexander V. Chernikov 			continue;
14036c2997ffSAlexander V. Chernikov 		return (EINVAL);
14046c2997ffSAlexander V. Chernikov 	}
14056c2997ffSAlexander V. Chernikov 
1406ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1407ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1408ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1409ac35ff17SAlexander V. Chernikov 
14106c2997ffSAlexander V. Chernikov 	return (0);
14116c2997ffSAlexander V. Chernikov }
14126c2997ffSAlexander V. Chernikov 
1413