xref: /freebsd/sbin/ipfw/tables.c (revision 46d52008744fbe4de1b4cb285195005fc10807d3)
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[]);
59*46d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second);
60*46d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second);
61ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
62f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
63ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
64ac35ff17SAlexander V. Chernikov     uint16_t uidx);
65f1220db8SAlexander V. Chernikov 
66f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
67f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
68f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
69f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
7081d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
71f1220db8SAlexander V. Chernikov 
72ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7381d3153dSAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
74ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
75ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
76ac35ff17SAlexander V. Chernikov 
77f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
78f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
79f1220db8SAlexander V. Chernikov 
80f1220db8SAlexander V. Chernikov #ifndef s6_addr32
81f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
82f1220db8SAlexander V. Chernikov #endif
83f1220db8SAlexander V. Chernikov 
84ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
85ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
86ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
87b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
88914bffb6SAlexander V. Chernikov       { "flow",		IPFW_TABLE_FLOW },
89ac35ff17SAlexander V. Chernikov       { NULL, 0 }
90ac35ff17SAlexander V. Chernikov };
91ac35ff17SAlexander V. Chernikov 
92ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
93ac35ff17SAlexander V. Chernikov       { "dscp",		IPFW_VTYPE_DSCP },
94ac35ff17SAlexander V. Chernikov       { "ip",		IPFW_VTYPE_IP },
95ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
96ac35ff17SAlexander V. Chernikov       { NULL, 0 }
97ac35ff17SAlexander V. Chernikov };
98ac35ff17SAlexander V. Chernikov 
99ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
100ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
101ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
102*46d52008SAlexander V. Chernikov       { "create",	TOK_CREATE },
103ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
104ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
105*46d52008SAlexander V. Chernikov       { "swap",		TOK_SWAP },
106ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
107358b9d09SAlexander V. Chernikov       { "detail",	TOK_DETAIL },
108ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
10981d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
110ac35ff17SAlexander V. Chernikov       { NULL, 0 }
111ac35ff17SAlexander V. Chernikov };
112ac35ff17SAlexander V. Chernikov 
113f1220db8SAlexander V. Chernikov static int
114f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
115f1220db8SAlexander V. Chernikov {
116f1220db8SAlexander V. Chernikov 	struct hostent *he;
117f1220db8SAlexander V. Chernikov 
118f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
119f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
120f1220db8SAlexander V. Chernikov 			return(-1);
121f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
122f1220db8SAlexander V. Chernikov 	}
123f1220db8SAlexander V. Chernikov 	return(0);
124f1220db8SAlexander V. Chernikov }
125f1220db8SAlexander V. Chernikov 
126f1220db8SAlexander V. Chernikov /*
127f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
128ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
129ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
130ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
131ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
132ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
133ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
134ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
135f1220db8SAlexander V. Chernikov  */
136f1220db8SAlexander V. Chernikov void
137f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
138f1220db8SAlexander V. Chernikov {
139ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
140ac35ff17SAlexander V. Chernikov 	int error, tcmd;
141ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
142ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
143f1220db8SAlexander V. Chernikov 	char *tablename;
144ac35ff17SAlexander V. Chernikov 	uint32_t set;
145358b9d09SAlexander V. Chernikov 	void *arg;
146f1220db8SAlexander V. Chernikov 
147ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
148ac35ff17SAlexander V. Chernikov 	is_all = 0;
149ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
150ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
151ac35ff17SAlexander V. Chernikov 	else
152ac35ff17SAlexander V. Chernikov 		set = 0;
153f1220db8SAlexander V. Chernikov 
154f1220db8SAlexander V. Chernikov 	ac--; av++;
1559d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
156f1220db8SAlexander V. Chernikov 	tablename = *av;
157f1220db8SAlexander V. Chernikov 
158ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
159ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
160ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
161ac35ff17SAlexander V. Chernikov 	} else {
162ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
163ac35ff17SAlexander V. Chernikov 			is_all = 1;
164ac35ff17SAlexander V. Chernikov 		else
165ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
166ac35ff17SAlexander V. Chernikov 	}
167ac35ff17SAlexander V. Chernikov 	ac--; av++;
1689d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
169ac35ff17SAlexander V. Chernikov 
170ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
171ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
172ac35ff17SAlexander V. Chernikov 
173ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
174ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
175ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
176358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
177ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
178ac35ff17SAlexander V. Chernikov 		break;
179ac35ff17SAlexander V. Chernikov 	default:
180ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
181ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
182ac35ff17SAlexander V. Chernikov 	}
183ac35ff17SAlexander V. Chernikov 
184ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
185ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
186ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
187f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
188f1220db8SAlexander V. Chernikov 		ac--; av++;
189ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
190ac35ff17SAlexander V. Chernikov 		break;
191ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
192f1220db8SAlexander V. Chernikov 		ac--; av++;
193ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
194ac35ff17SAlexander V. Chernikov 		break;
195ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
196ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
197ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
198ac35ff17SAlexander V. Chernikov 		break;
199ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
200f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
201ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
202f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
203f1220db8SAlexander V. Chernikov 				    tablename);
204f1220db8SAlexander V. Chernikov 		} else {
205ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
206f1220db8SAlexander V. Chernikov 			if (error != 0)
207f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
208f1220db8SAlexander V. Chernikov 		}
209ac35ff17SAlexander V. Chernikov 		break;
210*46d52008SAlexander V. Chernikov 	case TOK_SWAP:
211*46d52008SAlexander V. Chernikov 		ac--; av++;
212*46d52008SAlexander V. Chernikov 		NEED1("second table name required");
213*46d52008SAlexander V. Chernikov 		table_swap(&oh, *av);
214*46d52008SAlexander V. Chernikov 		break;
215358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
216ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
217358b9d09SAlexander V. Chernikov 		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
218f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
219ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
220f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
221358b9d09SAlexander V. Chernikov 			table_show_info(&i, arg);
222f1220db8SAlexander V. Chernikov 		} else {
223358b9d09SAlexander V. Chernikov 			error = tables_foreach(table_show_info, arg, 1);
224f1220db8SAlexander V. Chernikov 			if (error != 0)
225f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
226f1220db8SAlexander V. Chernikov 		}
227ac35ff17SAlexander V. Chernikov 		break;
228ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
229ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
230ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
231ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
232ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
233ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
234f1220db8SAlexander V. Chernikov 		} else {
235ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
236ac35ff17SAlexander V. Chernikov 			if (error != 0)
237ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
238f1220db8SAlexander V. Chernikov 		}
239ac35ff17SAlexander V. Chernikov 		break;
24081d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
24181d3153dSAlexander V. Chernikov 		ac--; av++;
24281d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
24381d3153dSAlexander V. Chernikov 		break;
244f1220db8SAlexander V. Chernikov 	}
245f1220db8SAlexander V. Chernikov }
246f1220db8SAlexander V. Chernikov 
247f1220db8SAlexander V. Chernikov static void
248ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
249f1220db8SAlexander V. Chernikov {
250f1220db8SAlexander V. Chernikov 
251563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
252f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
253f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
254ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
255f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
256f1220db8SAlexander V. Chernikov }
257f1220db8SAlexander V. Chernikov 
258f1220db8SAlexander V. Chernikov static void
259f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
260f1220db8SAlexander V. Chernikov {
261f1220db8SAlexander V. Chernikov 
262f1220db8SAlexander V. Chernikov 	oh->idx = 1;
26381d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
264ac35ff17SAlexander V. Chernikov }
265ac35ff17SAlexander V. Chernikov 
266ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
267ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE },
268ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
269ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
2704c0c07a5SAlexander V. Chernikov       { "limit",	TOK_LIMIT },
271ac35ff17SAlexander V. Chernikov       { NULL, 0 }
272ac35ff17SAlexander V. Chernikov };
273ac35ff17SAlexander V. Chernikov 
274914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
275914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
276914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
277914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
278914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
279914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
280914bffb6SAlexander V. Chernikov       { NULL, 0 }
281914bffb6SAlexander V. Chernikov };
282914bffb6SAlexander V. Chernikov 
283914bffb6SAlexander V. Chernikov int
284914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
285914bffb6SAlexander V. Chernikov {
286914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
287914bffb6SAlexander V. Chernikov 
288914bffb6SAlexander V. Chernikov 	/* Parse type options */
289914bffb6SAlexander V. Chernikov 	switch(ttype) {
290914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
291914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
292914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
293914bffb6SAlexander V. Chernikov 		    &fclear);
294914bffb6SAlexander V. Chernikov 		*tflags = fset;
295914bffb6SAlexander V. Chernikov 		break;
296914bffb6SAlexander V. Chernikov 	default:
297914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
298914bffb6SAlexander V. Chernikov 	}
299914bffb6SAlexander V. Chernikov 
300914bffb6SAlexander V. Chernikov 	return (0);
301914bffb6SAlexander V. Chernikov }
302914bffb6SAlexander V. Chernikov 
303914bffb6SAlexander V. Chernikov void
304914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
305914bffb6SAlexander V. Chernikov {
306914bffb6SAlexander V. Chernikov 	const char *tname;
307914bffb6SAlexander V. Chernikov 	int l;
308914bffb6SAlexander V. Chernikov 
309914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
310914bffb6SAlexander V. Chernikov 		tname = "unknown";
311914bffb6SAlexander V. Chernikov 
312914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
313914bffb6SAlexander V. Chernikov 	tbuf += l;
314914bffb6SAlexander V. Chernikov 	size -= l;
315914bffb6SAlexander V. Chernikov 
316914bffb6SAlexander V. Chernikov 	switch(type) {
317914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
318914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
319914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
320914bffb6SAlexander V. Chernikov 			l--;
321914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
322914bffb6SAlexander V. Chernikov 		}
323914bffb6SAlexander V. Chernikov 		break;
324914bffb6SAlexander V. Chernikov 	}
325914bffb6SAlexander V. Chernikov }
326914bffb6SAlexander V. Chernikov 
327ac35ff17SAlexander V. Chernikov /*
328ac35ff17SAlexander V. Chernikov  * Creates new table
329ac35ff17SAlexander V. Chernikov  *
330ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
331ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
332ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
333ac35ff17SAlexander V. Chernikov  *
334ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
335ac35ff17SAlexander V. Chernikov  */
336ac35ff17SAlexander V. Chernikov static void
337ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
338ac35ff17SAlexander V. Chernikov {
339ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
340ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
341ac35ff17SAlexander V. Chernikov 	size_t sz;
342914bffb6SAlexander V. Chernikov 	char *p;
343ac35ff17SAlexander V. Chernikov 	char tbuf[128];
344ac35ff17SAlexander V. Chernikov 
345ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
346ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
347ac35ff17SAlexander V. Chernikov 
348ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
349ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
350ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
351ac35ff17SAlexander V. Chernikov 
352ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
353ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
354ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
355ac35ff17SAlexander V. Chernikov 		ac--; av++;
356ac35ff17SAlexander V. Chernikov 
357ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
3584c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
3594c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
3604c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
3614c0c07a5SAlexander V. Chernikov 			ac--; av++;
3624c0c07a5SAlexander V. Chernikov 			break;
363ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
364ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
365914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
366914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
367914bffb6SAlexander V. Chernikov 				*p++ = '\0';
368ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
369914bffb6SAlexander V. Chernikov 			if (val == -1) {
370914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
371914bffb6SAlexander V. Chernikov 				    ", ");
372914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
373914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
374ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
375914bffb6SAlexander V. Chernikov 			}
376914bffb6SAlexander V. Chernikov 			xi.type = val;
377914bffb6SAlexander V. Chernikov 			if (p != NULL) {
378914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
379914bffb6SAlexander V. Chernikov 				if (error != 0)
380914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
381914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
382914bffb6SAlexander V. Chernikov 			}
383914bffb6SAlexander V. Chernikov 			ac--; av++;
384ac35ff17SAlexander V. Chernikov 			break;
385ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
386ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
387ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
388ac35ff17SAlexander V. Chernikov 			if (val != -1) {
389ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
390ac35ff17SAlexander V. Chernikov 				ac--; av++;
391ac35ff17SAlexander V. Chernikov 				break;
392ac35ff17SAlexander V. Chernikov 			}
393ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
394ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
395ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
396ac35ff17SAlexander V. Chernikov 			break;
397ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
398ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
399ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
400ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
401ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
402ac35ff17SAlexander V. Chernikov 			ac--; av++;
403ac35ff17SAlexander V. Chernikov 			break;
404ac35ff17SAlexander V. Chernikov 		}
405ac35ff17SAlexander V. Chernikov 	}
406ac35ff17SAlexander V. Chernikov 
407ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
408ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
409f1220db8SAlexander V. Chernikov }
410f1220db8SAlexander V. Chernikov 
411f1220db8SAlexander V. Chernikov /*
412ac35ff17SAlexander V. Chernikov  * Creates new table
413ac35ff17SAlexander V. Chernikov  *
414ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
415ac35ff17SAlexander V. Chernikov  *
416f1220db8SAlexander V. Chernikov  * Returns 0 on success.
417f1220db8SAlexander V. Chernikov  */
418f1220db8SAlexander V. Chernikov static int
419ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
420f1220db8SAlexander V. Chernikov {
421ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
422ac35ff17SAlexander V. Chernikov 	int error;
423f1220db8SAlexander V. Chernikov 
424ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
425ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
426ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
427ac35ff17SAlexander V. Chernikov 
428ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
429ac35ff17SAlexander V. Chernikov 
430ac35ff17SAlexander V. Chernikov 	return (error);
431ac35ff17SAlexander V. Chernikov }
432ac35ff17SAlexander V. Chernikov 
433ac35ff17SAlexander V. Chernikov /*
434ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
435ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
436ac35ff17SAlexander V. Chernikov  */
437ac35ff17SAlexander V. Chernikov static int
438ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
439ac35ff17SAlexander V. Chernikov {
440ac35ff17SAlexander V. Chernikov 
441ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
442f1220db8SAlexander V. Chernikov 		return (-1);
443f1220db8SAlexander V. Chernikov 
444f1220db8SAlexander V. Chernikov 	return (0);
445f1220db8SAlexander V. Chernikov }
446f1220db8SAlexander V. Chernikov 
447f1220db8SAlexander V. Chernikov /*
448ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
449f1220db8SAlexander V. Chernikov  * Returns 0 on success.
450f1220db8SAlexander V. Chernikov  */
451f1220db8SAlexander V. Chernikov static int
452ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
453f1220db8SAlexander V. Chernikov {
454f1220db8SAlexander V. Chernikov 
455ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
456f1220db8SAlexander V. Chernikov 		return (-1);
457f1220db8SAlexander V. Chernikov 
458f1220db8SAlexander V. Chernikov 	return (0);
459f1220db8SAlexander V. Chernikov }
460f1220db8SAlexander V. Chernikov 
461*46d52008SAlexander V. Chernikov static int
462*46d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second)
463*46d52008SAlexander V. Chernikov {
464*46d52008SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
465*46d52008SAlexander V. Chernikov 	int error;
466*46d52008SAlexander V. Chernikov 
467*46d52008SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
468*46d52008SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
469*46d52008SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
470*46d52008SAlexander V. Chernikov 	table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
471*46d52008SAlexander V. Chernikov 
472*46d52008SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
473*46d52008SAlexander V. Chernikov 
474*46d52008SAlexander V. Chernikov 	return (error);
475*46d52008SAlexander V. Chernikov }
476*46d52008SAlexander V. Chernikov 
477*46d52008SAlexander V. Chernikov /*
478*46d52008SAlexander V. Chernikov  * Swaps given table with @second one.
479*46d52008SAlexander V. Chernikov  */
480*46d52008SAlexander V. Chernikov static int
481*46d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second)
482*46d52008SAlexander V. Chernikov {
483*46d52008SAlexander V. Chernikov 	int error;
484*46d52008SAlexander V. Chernikov 
485*46d52008SAlexander V. Chernikov 	if (table_check_name(second) != 0)
486*46d52008SAlexander V. Chernikov 		errx(EX_USAGE, "table name %s is invalid", second);
487*46d52008SAlexander V. Chernikov 
488*46d52008SAlexander V. Chernikov 	error = table_do_swap(oh, second);
489*46d52008SAlexander V. Chernikov 
490*46d52008SAlexander V. Chernikov 	switch (error) {
491*46d52008SAlexander V. Chernikov 	case EINVAL:
492*46d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check types");
493*46d52008SAlexander V. Chernikov 	case EFBIG:
494*46d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check limits");
495*46d52008SAlexander V. Chernikov 	}
496*46d52008SAlexander V. Chernikov 
497*46d52008SAlexander V. Chernikov 	return (0);
498*46d52008SAlexander V. Chernikov }
499*46d52008SAlexander V. Chernikov 
500*46d52008SAlexander V. Chernikov 
501f1220db8SAlexander V. Chernikov /*
502ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
503f1220db8SAlexander V. Chernikov  * it inside @i.
504f1220db8SAlexander V. Chernikov  * Returns 0 on success.
505f1220db8SAlexander V. Chernikov  */
506f1220db8SAlexander V. Chernikov static int
507ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
508f1220db8SAlexander V. Chernikov {
509f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
510ac35ff17SAlexander V. Chernikov 	int error;
511f1220db8SAlexander V. Chernikov 	size_t sz;
512f1220db8SAlexander V. Chernikov 
513f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
514f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
515ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
516f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
517f1220db8SAlexander V. Chernikov 
518ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
519ac35ff17SAlexander V. Chernikov 		return (error);
520f1220db8SAlexander V. Chernikov 
521f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
522ac35ff17SAlexander V. Chernikov 		return (EINVAL);
523f1220db8SAlexander V. Chernikov 
524f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
525f1220db8SAlexander V. Chernikov 
526f1220db8SAlexander V. Chernikov 	return (0);
527f1220db8SAlexander V. Chernikov }
528f1220db8SAlexander V. Chernikov 
5295f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
5305f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
5315f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
5325f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
5335f379342SAlexander V. Chernikov       { NULL, 0 }
5345f379342SAlexander V. Chernikov };
5355f379342SAlexander V. Chernikov 
5365f379342SAlexander V. Chernikov struct ta_cldata {
5375f379342SAlexander V. Chernikov 	uint8_t		taclass;
5385f379342SAlexander V. Chernikov 	uint8_t		spare4;
5395f379342SAlexander V. Chernikov 	uint16_t	itemsize;
5405f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
5415f379342SAlexander V. Chernikov 	uint32_t	size;
5425f379342SAlexander V. Chernikov 	uint32_t	count;
5435f379342SAlexander V. Chernikov };
5445f379342SAlexander V. Chernikov 
5455f379342SAlexander V. Chernikov /*
5465f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
5475f379342SAlexander V. Chernikov  */
5485f379342SAlexander V. Chernikov static void
5495f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
5505f379342SAlexander V. Chernikov     const char *af, const char *taclass)
5515f379342SAlexander V. Chernikov {
5525f379342SAlexander V. Chernikov 
5535f379342SAlexander V. Chernikov 	switch (d->taclass) {
5545f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
5555f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
5565f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
5575f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
5585f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
5595f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
5605f379342SAlexander V. Chernikov 		else
5615f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
5625f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
5635f379342SAlexander V. Chernikov 			    d->size, d->count,
5645f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
5655f379342SAlexander V. Chernikov 		break;
5665f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
5675f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
5685f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
5695f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
5705f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
5715f379342SAlexander V. Chernikov 		else
5725f379342SAlexander V. Chernikov 			printf("  items: %u "
5735f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
5745f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
5755f379342SAlexander V. Chernikov 		break;
5765f379342SAlexander V. Chernikov 	default:
5775f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
5785f379342SAlexander V. Chernikov 	}
5795f379342SAlexander V. Chernikov }
5805f379342SAlexander V. Chernikov 
581f1220db8SAlexander V. Chernikov /*
582f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
583f1220db8SAlexander V. Chernikov  */
584f1220db8SAlexander V. Chernikov static int
585f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
586f1220db8SAlexander V. Chernikov {
587914bffb6SAlexander V. Chernikov 	const char *vtype;
5885f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
5895f379342SAlexander V. Chernikov 	int afdata, afitem;
5905f379342SAlexander V. Chernikov 	struct ta_cldata d;
591914bffb6SAlexander V. Chernikov 	char ttype[64];
592f1220db8SAlexander V. Chernikov 
593914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
594ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
595ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
596ac35ff17SAlexander V. Chernikov 
597914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
598914bffb6SAlexander V. Chernikov 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
5999d099b4fSAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
6009d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
601f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
6024c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
6034c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
604f1220db8SAlexander V. Chernikov 
605358b9d09SAlexander V. Chernikov 	/* Print algo-specific info if requested & set  */
606358b9d09SAlexander V. Chernikov 	if (arg == NULL)
607358b9d09SAlexander V. Chernikov 		return (0);
608358b9d09SAlexander V. Chernikov 
6095f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
6105f379342SAlexander V. Chernikov 		return (0);
6115f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
6125f379342SAlexander V. Chernikov 
6135f379342SAlexander V. Chernikov 	afdata = 0;
6145f379342SAlexander V. Chernikov 	afitem = 0;
6155f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
6165f379342SAlexander V. Chernikov 		afdata = 1;
6175f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
6185f379342SAlexander V. Chernikov 		afitem = 1;
6195f379342SAlexander V. Chernikov 
6205f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
6215f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
6225f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
6235f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
6245f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
6255f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
6265f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
6275f379342SAlexander V. Chernikov 	else
6285f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
6295f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
6305f379342SAlexander V. Chernikov 		vtype = "unknown";
6315f379342SAlexander V. Chernikov 
6325f379342SAlexander V. Chernikov 	if (afdata == 0) {
6335f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
6345f379342SAlexander V. Chernikov 	} else {
6355f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
6365f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
6375f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
6385f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
6395f379342SAlexander V. Chernikov 			vtype = "unknown";
6405f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
6415f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
6425f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
6435f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
6445f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
6455f379342SAlexander V. Chernikov 	}
6465f379342SAlexander V. Chernikov 
647f1220db8SAlexander V. Chernikov 	return (0);
648f1220db8SAlexander V. Chernikov }
649f1220db8SAlexander V. Chernikov 
650f1220db8SAlexander V. Chernikov 
651f1220db8SAlexander V. Chernikov /*
652f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
653f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
654f1220db8SAlexander V. Chernikov  */
655f1220db8SAlexander V. Chernikov 
656f1220db8SAlexander V. Chernikov static int
657f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
658f1220db8SAlexander V. Chernikov {
659f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
66081d3153dSAlexander V. Chernikov 	int error;
661f1220db8SAlexander V. Chernikov 
662ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
663f1220db8SAlexander V. Chernikov 		return (ENOMEM);
664f1220db8SAlexander V. Chernikov 
66581d3153dSAlexander V. Chernikov 	if ((error = table_get_list(i, oh)) != 0) {
66681d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
66781d3153dSAlexander V. Chernikov 		return (error);
66881d3153dSAlexander V. Chernikov 	}
66981d3153dSAlexander V. Chernikov 
670f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
671f1220db8SAlexander V. Chernikov 
672f1220db8SAlexander V. Chernikov 	free(oh);
673f1220db8SAlexander V. Chernikov 	return (0);
674f1220db8SAlexander V. Chernikov }
675f1220db8SAlexander V. Chernikov 
676f1220db8SAlexander V. Chernikov static int
677f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
678f1220db8SAlexander V. Chernikov {
679ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
680f1220db8SAlexander V. Chernikov 
681ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
682ac35ff17SAlexander V. Chernikov 
683ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
684ac35ff17SAlexander V. Chernikov 
685ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
686f1220db8SAlexander V. Chernikov }
687f1220db8SAlexander V. Chernikov 
688ac35ff17SAlexander V. Chernikov static int
689ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
690ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
691ac35ff17SAlexander V. Chernikov {
692db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
693db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
694ac35ff17SAlexander V. Chernikov 	int error;
695ac35ff17SAlexander V. Chernikov 
696ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
697ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
698ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
699ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
700ac35ff17SAlexander V. Chernikov 
701db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
702db785d31SAlexander V. Chernikov 	ctlv->count = 1;
703db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
704db785d31SAlexander V. Chernikov 
705db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
706db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
707ac35ff17SAlexander V. Chernikov 	if (update != 0)
70881d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
709ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
710ac35ff17SAlexander V. Chernikov 
711ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
712ac35ff17SAlexander V. Chernikov 
713ac35ff17SAlexander V. Chernikov 	return (error);
714ac35ff17SAlexander V. Chernikov }
715ac35ff17SAlexander V. Chernikov 
716ac35ff17SAlexander V. Chernikov static void
717ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
718ac35ff17SAlexander V. Chernikov {
719ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
72081d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
721ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
7224c0c07a5SAlexander V. Chernikov 	int cmd, error;
7234c0c07a5SAlexander V. Chernikov 	char *texterr, *etxt;
724ac35ff17SAlexander V. Chernikov 
725ac35ff17SAlexander V. Chernikov 	if (ac == 0)
726ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
727ac35ff17SAlexander V. Chernikov 
728ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
729ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
730ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
731ac35ff17SAlexander V. Chernikov 
73281d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
733db785d31SAlexander V. Chernikov 
734db785d31SAlexander V. Chernikov 	/*
735db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
736db785d31SAlexander V. Chernikov 	 */
737db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
738db785d31SAlexander V. Chernikov 		xi.type = type;
739db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
740db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
741db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
742db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
743db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
744db785d31SAlexander V. Chernikov 	}
745db785d31SAlexander V. Chernikov 
746ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
747ac35ff17SAlexander V. Chernikov 	ac--; av++;
748ac35ff17SAlexander V. Chernikov 
749ac35ff17SAlexander V. Chernikov 	if (add != 0) {
750ac35ff17SAlexander V. Chernikov 		if (ac > 0)
751ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
752ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
7534c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
754ac35ff17SAlexander V. Chernikov 	} else {
755ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
7564c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
757ac35ff17SAlexander V. Chernikov 	}
758ac35ff17SAlexander V. Chernikov 
7594c0c07a5SAlexander V. Chernikov 	if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0)
7604c0c07a5SAlexander V. Chernikov 		return;
7614c0c07a5SAlexander V. Chernikov 
7624c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
7634c0c07a5SAlexander V. Chernikov 	switch (error) {
7644c0c07a5SAlexander V. Chernikov 	case EEXIST:
7654c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
7664c0c07a5SAlexander V. Chernikov 		break;
7674c0c07a5SAlexander V. Chernikov 	case EFBIG:
7684c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
7694c0c07a5SAlexander V. Chernikov 		break;
7704c0c07a5SAlexander V. Chernikov 	case ESRCH:
7714c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
7724c0c07a5SAlexander V. Chernikov 		break;
7734c0c07a5SAlexander V. Chernikov 	case ENOENT:
7744c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
7754c0c07a5SAlexander V. Chernikov 		break;
7764c0c07a5SAlexander V. Chernikov 	default:
7774c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
7784c0c07a5SAlexander V. Chernikov 	}
7794c0c07a5SAlexander V. Chernikov 
7804c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
781ac35ff17SAlexander V. Chernikov }
782ac35ff17SAlexander V. Chernikov 
78381d3153dSAlexander V. Chernikov static int
78481d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
78581d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
78681d3153dSAlexander V. Chernikov {
78781d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
78881d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
78981d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
79081d3153dSAlexander V. Chernikov 	int error;
79181d3153dSAlexander V. Chernikov 	size_t sz;
79281d3153dSAlexander V. Chernikov 
79381d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
79481d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
79581d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
79681d3153dSAlexander V. Chernikov 
79781d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
79881d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
79981d3153dSAlexander V. Chernikov 	tent->idx = 1;
80081d3153dSAlexander V. Chernikov 
80181d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
80281d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
80381d3153dSAlexander V. Chernikov 
80481d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
80581d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
80681d3153dSAlexander V. Chernikov 		return (error);
80781d3153dSAlexander V. Chernikov 
80881d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
80981d3153dSAlexander V. Chernikov 		return (EINVAL);
81081d3153dSAlexander V. Chernikov 
81181d3153dSAlexander V. Chernikov 	*xtent = *tent;
81281d3153dSAlexander V. Chernikov 
81381d3153dSAlexander V. Chernikov 	return (0);
81481d3153dSAlexander V. Chernikov }
81581d3153dSAlexander V. Chernikov 
81681d3153dSAlexander V. Chernikov static void
81781d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
81881d3153dSAlexander V. Chernikov {
81981d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
82081d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
821914bffb6SAlexander V. Chernikov 	char key[64];
82281d3153dSAlexander V. Chernikov 	int error;
82381d3153dSAlexander V. Chernikov 
82481d3153dSAlexander V. Chernikov 	if (ac == 0)
82581d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
82681d3153dSAlexander V. Chernikov 
827914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
828914bffb6SAlexander V. Chernikov 
829914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
83081d3153dSAlexander V. Chernikov 
83181d3153dSAlexander V. Chernikov 	switch (error) {
83281d3153dSAlexander V. Chernikov 	case 0:
83381d3153dSAlexander V. Chernikov 		break;
83481d3153dSAlexander V. Chernikov 	case ESRCH:
83581d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
83681d3153dSAlexander V. Chernikov 	case ENOENT:
83781d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
83881d3153dSAlexander V. Chernikov 	case ENOTSUP:
83981d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
84081d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
84181d3153dSAlexander V. Chernikov 	default:
84281d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
84381d3153dSAlexander V. Chernikov 	}
84481d3153dSAlexander V. Chernikov 
84581d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
84681d3153dSAlexander V. Chernikov }
847ac35ff17SAlexander V. Chernikov 
848ac35ff17SAlexander V. Chernikov static void
849914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
850914bffb6SAlexander V. Chernikov     uint8_t tflags)
851ac35ff17SAlexander V. Chernikov {
852914bffb6SAlexander V. Chernikov 	char *p, *pp;
853ac35ff17SAlexander V. Chernikov 	int mask, af;
854914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
855914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
856ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
857914bffb6SAlexander V. Chernikov 	uint16_t port;
858914bffb6SAlexander V. Chernikov 	struct protoent *pent;
859914bffb6SAlexander V. Chernikov 	struct servent *sent;
860ac35ff17SAlexander V. Chernikov 	int masklen;
861ac35ff17SAlexander V. Chernikov 
862ac35ff17SAlexander V. Chernikov 	masklen = 0;
863ac35ff17SAlexander V. Chernikov 	af = 0;
864ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
865ac35ff17SAlexander V. Chernikov 
866ac35ff17SAlexander V. Chernikov 	switch (type) {
867ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
868ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
869ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
870ac35ff17SAlexander V. Chernikov 			*p = '\0';
871ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
872ac35ff17SAlexander V. Chernikov 		}
873ac35ff17SAlexander V. Chernikov 
874ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
875ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
876ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
877ac35ff17SAlexander V. Chernikov 				    p + 1);
878ac35ff17SAlexander V. Chernikov 
879ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
880ac35ff17SAlexander V. Chernikov 			af = AF_INET;
881ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
882ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
883ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
884ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
885ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
886ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
887ac35ff17SAlexander V. Chernikov 				    p + 1);
888ac35ff17SAlexander V. Chernikov 
889ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
890ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
891ac35ff17SAlexander V. Chernikov 		} else {
892ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
893ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
894ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
895ac35ff17SAlexander V. Chernikov 
896ac35ff17SAlexander V. Chernikov 			masklen = 32;
897ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
898ac35ff17SAlexander V. Chernikov 			af = AF_INET;
899ac35ff17SAlexander V. Chernikov 		}
900ac35ff17SAlexander V. Chernikov 		break;
901ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
902ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
903ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
904ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
905ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
906ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
907ac35ff17SAlexander V. Chernikov 		break;
908b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
909ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
910ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
911ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
912ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
913ac35ff17SAlexander V. Chernikov 
914ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
915ac35ff17SAlexander V. Chernikov 		*pkey = key;
916ac35ff17SAlexander V. Chernikov 		masklen = 32;
917ac35ff17SAlexander V. Chernikov 		break;
918914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
919914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
920914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
921914bffb6SAlexander V. Chernikov 		af = 0;
922914bffb6SAlexander V. Chernikov 
923914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
924914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
925914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
926914bffb6SAlexander V. Chernikov 				*p++ = '\0';
927914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
928914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
929914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
930914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
931914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
932914bffb6SAlexander V. Chernikov 				af = AF_INET;
933914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
934914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
935914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
936914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
937914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
938914bffb6SAlexander V. Chernikov 				af = AF_INET6;
939914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
940914bffb6SAlexander V. Chernikov 			}
941914bffb6SAlexander V. Chernikov 
942914bffb6SAlexander V. Chernikov 			arg = p;
943914bffb6SAlexander V. Chernikov 		}
944914bffb6SAlexander V. Chernikov 
945914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
946914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
947914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
948914bffb6SAlexander V. Chernikov 				*p++ = '\0';
949914bffb6SAlexander V. Chernikov 
950914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
951914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
952914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
953914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
954914bffb6SAlexander V. Chernikov 					    arg);
955914bffb6SAlexander V. Chernikov 				else
956914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
957914bffb6SAlexander V. Chernikov 			}
958914bffb6SAlexander V. Chernikov 
959914bffb6SAlexander V. Chernikov 			if (key > 255)
960914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
961914bffb6SAlexander V. Chernikov 
962914bffb6SAlexander V. Chernikov 			tfe->proto = key;
963914bffb6SAlexander V. Chernikov 
964914bffb6SAlexander V. Chernikov 			arg = p;
965914bffb6SAlexander V. Chernikov 		}
966914bffb6SAlexander V. Chernikov 
967914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
968914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
969914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
970914bffb6SAlexander V. Chernikov 				*p++ = '\0';
971914bffb6SAlexander V. Chernikov 
972914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
973914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
974914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
975914bffb6SAlexander V. Chernikov 					    arg);
976914bffb6SAlexander V. Chernikov 				else
977914bffb6SAlexander V. Chernikov 					key = sent->s_port;
978914bffb6SAlexander V. Chernikov 			}
979914bffb6SAlexander V. Chernikov 
980914bffb6SAlexander V. Chernikov 			tfe->sport = port;
981914bffb6SAlexander V. Chernikov 
982914bffb6SAlexander V. Chernikov 			arg = p;
983914bffb6SAlexander V. Chernikov 		}
984914bffb6SAlexander V. Chernikov 
985914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
986914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
987914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
988914bffb6SAlexander V. Chernikov 				*p++ = '\0';
989914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
990914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
991914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
992914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
993914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
994914bffb6SAlexander V. Chernikov 				af = AF_INET;
995914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
996914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
997914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
998914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
999914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1000914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1001914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
1002914bffb6SAlexander V. Chernikov 			}
1003914bffb6SAlexander V. Chernikov 
1004914bffb6SAlexander V. Chernikov 			arg = p;
1005914bffb6SAlexander V. Chernikov 		}
1006914bffb6SAlexander V. Chernikov 
1007914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1008914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1009914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1010914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1011914bffb6SAlexander V. Chernikov 
1012914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1013914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1014914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1015914bffb6SAlexander V. Chernikov 					    arg);
1016914bffb6SAlexander V. Chernikov 				else
1017914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1018914bffb6SAlexander V. Chernikov 			}
1019914bffb6SAlexander V. Chernikov 
1020914bffb6SAlexander V. Chernikov 			tfe->dport = port;
1021914bffb6SAlexander V. Chernikov 
1022914bffb6SAlexander V. Chernikov 			arg = p;
1023914bffb6SAlexander V. Chernikov 		}
1024914bffb6SAlexander V. Chernikov 
1025914bffb6SAlexander V. Chernikov 		tfe->af = af;
1026914bffb6SAlexander V. Chernikov 
1027914bffb6SAlexander V. Chernikov 		break;
1028914bffb6SAlexander V. Chernikov 
1029ac35ff17SAlexander V. Chernikov 	default:
1030ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
1031ac35ff17SAlexander V. Chernikov 	}
1032ac35ff17SAlexander V. Chernikov 
1033ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
1034ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
1035ac35ff17SAlexander V. Chernikov }
1036ac35ff17SAlexander V. Chernikov 
1037ac35ff17SAlexander V. Chernikov static void
1038ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
103981d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
1040ac35ff17SAlexander V. Chernikov {
1041914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
1042ac35ff17SAlexander V. Chernikov 	int error;
1043db785d31SAlexander V. Chernikov 	char *del;
1044ac35ff17SAlexander V. Chernikov 
1045ac35ff17SAlexander V. Chernikov 	type = 0;
1046914bffb6SAlexander V. Chernikov 	tflags = 0;
1047ac35ff17SAlexander V. Chernikov 	vtype = 0;
1048ac35ff17SAlexander V. Chernikov 
104981d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
105081d3153dSAlexander V. Chernikov 
105181d3153dSAlexander V. Chernikov 	if (error == 0) {
105281d3153dSAlexander V. Chernikov 		/* Table found. */
105381d3153dSAlexander V. Chernikov 		type = xi->type;
1054914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
105581d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
105681d3153dSAlexander V. Chernikov 	} else {
105781d3153dSAlexander V. Chernikov 		if (error != ESRCH)
105881d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
105981d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
1060ac35ff17SAlexander V. Chernikov 		/*
106181d3153dSAlexander V. Chernikov 		 * Table does not exist.
106281d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
106381d3153dSAlexander V. Chernikov 		 * before failing.
1064ac35ff17SAlexander V. Chernikov 		 */
1065db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1066db785d31SAlexander V. Chernikov 			*del = '\0';
1067ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1068ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1069ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1070ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1071ac35ff17SAlexander V. Chernikov 			/*
107281d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
107381d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1074ac35ff17SAlexander V. Chernikov 			 */
107581d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
107681d3153dSAlexander V. Chernikov 		} else {
107781d3153dSAlexander V. Chernikov 			/* Inknown key */
107881d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1079db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
108081d3153dSAlexander V. Chernikov 		}
1081db785d31SAlexander V. Chernikov 		if (del != NULL)
1082db785d31SAlexander V. Chernikov 			*del = '/';
1083ac35ff17SAlexander V. Chernikov 	}
1084ac35ff17SAlexander V. Chernikov 
1085914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1086ac35ff17SAlexander V. Chernikov 
1087ac35ff17SAlexander V. Chernikov 	*ptype = type;
1088ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1089ac35ff17SAlexander V. Chernikov }
1090ac35ff17SAlexander V. Chernikov 
1091ac35ff17SAlexander V. Chernikov static void
1092ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1093ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1094ac35ff17SAlexander V. Chernikov {
1095ac35ff17SAlexander V. Chernikov 	int code;
1096ac35ff17SAlexander V. Chernikov 	char *p;
1097ac35ff17SAlexander V. Chernikov 
1098ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1099ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1100ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1101ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1102ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1103ac35ff17SAlexander V. Chernikov 		break;
1104ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1105ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1106ac35ff17SAlexander V. Chernikov 			break;
1107ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1108ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1109ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1110ac35ff17SAlexander V. Chernikov 		break;
1111ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1112ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1113ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1114ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1115ac35ff17SAlexander V. Chernikov 		} else {
1116ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1117ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1118ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1119ac35ff17SAlexander V. Chernikov 		}
1120ac35ff17SAlexander V. Chernikov 		tent->value = code;
1121ac35ff17SAlexander V. Chernikov 		break;
1122ac35ff17SAlexander V. Chernikov 	default:
1123ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1124ac35ff17SAlexander V. Chernikov 	}
1125ac35ff17SAlexander V. Chernikov }
1126f1220db8SAlexander V. Chernikov 
1127f1220db8SAlexander V. Chernikov /*
1128f1220db8SAlexander V. Chernikov  * Compare table names.
1129f1220db8SAlexander V. Chernikov  * Honor number comparison.
1130f1220db8SAlexander V. Chernikov  */
1131f1220db8SAlexander V. Chernikov static int
1132f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1133f1220db8SAlexander V. Chernikov {
1134f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1135f1220db8SAlexander V. Chernikov 
1136f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1137f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1138f1220db8SAlexander V. Chernikov 
113968394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1140f1220db8SAlexander V. Chernikov }
1141f1220db8SAlexander V. Chernikov 
1142f1220db8SAlexander V. Chernikov /*
1143f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1144f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1145f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1146f1220db8SAlexander V. Chernikov  */
1147f1220db8SAlexander V. Chernikov static int
1148f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1149f1220db8SAlexander V. Chernikov {
1150f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
1151f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1152f1220db8SAlexander V. Chernikov 	size_t sz;
1153f1220db8SAlexander V. Chernikov 	int i, error;
1154f1220db8SAlexander V. Chernikov 
1155f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
1156f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
1157f1220db8SAlexander V. Chernikov 
1158d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
1159f1220db8SAlexander V. Chernikov 		return (errno);
1160f1220db8SAlexander V. Chernikov 
1161f1220db8SAlexander V. Chernikov 	sz = req.size;
1162f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
1163f1220db8SAlexander V. Chernikov 		return (ENOMEM);
1164f1220db8SAlexander V. Chernikov 
1165f1220db8SAlexander V. Chernikov 	olh->size = sz;
1166d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
1167f1220db8SAlexander V. Chernikov 		free(olh);
1168f1220db8SAlexander V. Chernikov 		return (errno);
1169f1220db8SAlexander V. Chernikov 	}
1170f1220db8SAlexander V. Chernikov 
1171f1220db8SAlexander V. Chernikov 	if (sort != 0)
1172f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1173f1220db8SAlexander V. Chernikov 
1174f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
1175f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
1176f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
1177f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1178f1220db8SAlexander V. Chernikov 	}
1179f1220db8SAlexander V. Chernikov 
1180f1220db8SAlexander V. Chernikov 	free(olh);
1181f1220db8SAlexander V. Chernikov 
1182f1220db8SAlexander V. Chernikov 	return (0);
1183f1220db8SAlexander V. Chernikov }
1184f1220db8SAlexander V. Chernikov 
1185f1220db8SAlexander V. Chernikov /*
1186f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1187d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
1188d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
1189f1220db8SAlexander V. Chernikov  *
1190f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1191f1220db8SAlexander V. Chernikov  */
1192f1220db8SAlexander V. Chernikov static int
1193f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
1194f1220db8SAlexander V. Chernikov {
1195f1220db8SAlexander V. Chernikov 	size_t sz;
119681d3153dSAlexander V. Chernikov 	int error, c;
1197f1220db8SAlexander V. Chernikov 
119881d3153dSAlexander V. Chernikov 	sz = 0;
119981d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
1200f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
120181d3153dSAlexander V. Chernikov 		if (sz < i->size)
1202f1220db8SAlexander V. Chernikov 			sz = i->size;
1203f1220db8SAlexander V. Chernikov 
1204d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
120581d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1206d3a4f924SAlexander V. Chernikov 
120781d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
1208f1220db8SAlexander V. Chernikov 			return (errno);
120981d3153dSAlexander V. Chernikov 	}
1210f1220db8SAlexander V. Chernikov 
121181d3153dSAlexander V. Chernikov 	return (ENOMEM);
1212f1220db8SAlexander V. Chernikov }
1213f1220db8SAlexander V. Chernikov 
1214f1220db8SAlexander V. Chernikov /*
1215f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1216f1220db8SAlexander V. Chernikov  */
1217f1220db8SAlexander V. Chernikov static void
1218f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1219f1220db8SAlexander V. Chernikov {
122081d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
122181d3153dSAlexander V. Chernikov 	uint32_t count;
1222f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1223f1220db8SAlexander V. Chernikov 
1224f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
122581d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1226f1220db8SAlexander V. Chernikov 
1227f1220db8SAlexander V. Chernikov 	if (need_header)
1228f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1229f1220db8SAlexander V. Chernikov 
1230f1220db8SAlexander V. Chernikov 	count = i->count;
1231f1220db8SAlexander V. Chernikov 	while (count > 0) {
123281d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
123381d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
123481d3153dSAlexander V. Chernikov 		count--;
123581d3153dSAlexander V. Chernikov 	}
123681d3153dSAlexander V. Chernikov }
123781d3153dSAlexander V. Chernikov 
123881d3153dSAlexander V. Chernikov static void
123981d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
124081d3153dSAlexander V. Chernikov {
1241914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1242914bffb6SAlexander V. Chernikov 	void *paddr;
124381d3153dSAlexander V. Chernikov 	uint32_t tval;
1244914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
124581d3153dSAlexander V. Chernikov 
124681d3153dSAlexander V. Chernikov 	tval = tent->value;
124781d3153dSAlexander V. Chernikov 
1248914bffb6SAlexander V. Chernikov 	if (co.do_value_as_ip) {
1249914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1250914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1251914bffb6SAlexander V. Chernikov 	} else
1252914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1253914bffb6SAlexander V. Chernikov 
1254f1220db8SAlexander V. Chernikov 	switch (i->type) {
1255f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1256f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
125781d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1258914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1259f1220db8SAlexander V. Chernikov 		break;
1260f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1261f1220db8SAlexander V. Chernikov 		/* Interface names */
1262914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1263b23d5de9SAlexander V. Chernikov 		break;
1264b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1265b23d5de9SAlexander V. Chernikov 		/* numbers */
1266914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1267b23d5de9SAlexander V. Chernikov 		break;
1268914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1269914bffb6SAlexander V. Chernikov 		/* flows */
1270914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1271914bffb6SAlexander V. Chernikov 		comma = "";
1272914bffb6SAlexander V. Chernikov 
1273914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1274914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1275914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1276914bffb6SAlexander V. Chernikov 			else
1277914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1278914bffb6SAlexander V. Chernikov 
1279914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1280914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1281914bffb6SAlexander V. Chernikov 			comma = ",";
1282914bffb6SAlexander V. Chernikov 		}
1283914bffb6SAlexander V. Chernikov 
1284914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1285914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1286914bffb6SAlexander V. Chernikov 			comma = ",";
1287914bffb6SAlexander V. Chernikov 		}
1288914bffb6SAlexander V. Chernikov 
1289914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1290914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1291914bffb6SAlexander V. Chernikov 			comma = ",";
1292914bffb6SAlexander V. Chernikov 		}
1293914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1294914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1295914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1296914bffb6SAlexander V. Chernikov 			else
1297914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1298914bffb6SAlexander V. Chernikov 
1299914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1300914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1301914bffb6SAlexander V. Chernikov 			comma = ",";
1302914bffb6SAlexander V. Chernikov 		}
1303914bffb6SAlexander V. Chernikov 
1304914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1305914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1306914bffb6SAlexander V. Chernikov 			comma = ",";
1307914bffb6SAlexander V. Chernikov 		}
1308914bffb6SAlexander V. Chernikov 
1309914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1310f1220db8SAlexander V. Chernikov 	}
1311f1220db8SAlexander V. Chernikov }
1312f1220db8SAlexander V. Chernikov 
13139d099b4fSAlexander V. Chernikov static int
13149d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
13159d099b4fSAlexander V. Chernikov {
13169d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
13179d099b4fSAlexander V. Chernikov 	size_t sz;
13189d099b4fSAlexander V. Chernikov 	int error;
13199d099b4fSAlexander V. Chernikov 
13209d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
13219d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
13229d099b4fSAlexander V. Chernikov 
13239d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
13249d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
13259d099b4fSAlexander V. Chernikov 		return (error);
13269d099b4fSAlexander V. Chernikov 
13279d099b4fSAlexander V. Chernikov 	sz = req.size;
13289d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
13299d099b4fSAlexander V. Chernikov 		return (ENOMEM);
13309d099b4fSAlexander V. Chernikov 
13319d099b4fSAlexander V. Chernikov 	olh->size = sz;
13329d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
13339d099b4fSAlexander V. Chernikov 		free(olh);
13349d099b4fSAlexander V. Chernikov 		return (error);
13359d099b4fSAlexander V. Chernikov 	}
13369d099b4fSAlexander V. Chernikov 
13379d099b4fSAlexander V. Chernikov 	*polh = olh;
13389d099b4fSAlexander V. Chernikov 	return (0);
13399d099b4fSAlexander V. Chernikov }
13409d099b4fSAlexander V. Chernikov 
13419d099b4fSAlexander V. Chernikov void
13429d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
13439d099b4fSAlexander V. Chernikov {
13449d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
13459d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
13469d099b4fSAlexander V. Chernikov 	int error, i;
13479d099b4fSAlexander V. Chernikov 	const char *atype;
13489d099b4fSAlexander V. Chernikov 
13499d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
13509d099b4fSAlexander V. Chernikov 	if (error != 0)
13519d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
13529d099b4fSAlexander V. Chernikov 
13539d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
13549d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
13559d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
13569d099b4fSAlexander V. Chernikov 			atype = "unknown";
13578ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
13588ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
13599d099b4fSAlexander V. Chernikov 
13609d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
13619d099b4fSAlexander V. Chernikov 	}
13629d099b4fSAlexander V. Chernikov 
13639d099b4fSAlexander V. Chernikov 	free(olh);
13649d099b4fSAlexander V. Chernikov }
13659d099b4fSAlexander V. Chernikov 
13666c2997ffSAlexander V. Chernikov int
13676c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
13686c2997ffSAlexander V. Chernikov {
13696c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
13706c2997ffSAlexander V. Chernikov 
13716c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
13726c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
13736c2997ffSAlexander V. Chernikov 
13746c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
13756c2997ffSAlexander V. Chernikov 		return (-1);
13766c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
13776c2997ffSAlexander V. Chernikov 		return (1);
13786c2997ffSAlexander V. Chernikov 
13796c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
13806c2997ffSAlexander V. Chernikov 		return (-1);
13816c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
13826c2997ffSAlexander V. Chernikov 		return (1);
13836c2997ffSAlexander V. Chernikov 
13846c2997ffSAlexander V. Chernikov 	return (0);
13856c2997ffSAlexander V. Chernikov }
1386563b5ab1SAlexander V. Chernikov 
1387563b5ab1SAlexander V. Chernikov int
13886c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1389563b5ab1SAlexander V. Chernikov {
1390563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1391563b5ab1SAlexander V. Chernikov 	uint16_t key;
1392563b5ab1SAlexander V. Chernikov 
1393563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1394563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1395563b5ab1SAlexander V. Chernikov 
1396563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1397563b5ab1SAlexander V. Chernikov 		return (-1);
1398563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1399563b5ab1SAlexander V. Chernikov 		return (1);
1400563b5ab1SAlexander V. Chernikov 
1401563b5ab1SAlexander V. Chernikov 	return (0);
1402563b5ab1SAlexander V. Chernikov }
1403563b5ab1SAlexander V. Chernikov 
1404563b5ab1SAlexander V. Chernikov /*
1405563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1406563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1407563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1408563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1409563b5ab1SAlexander V. Chernikov  *
1410563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1411563b5ab1SAlexander V. Chernikov  */
1412563b5ab1SAlexander V. Chernikov char *
1413563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1414563b5ab1SAlexander V. Chernikov {
1415563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1416563b5ab1SAlexander V. Chernikov 
1417563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
14186c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1419563b5ab1SAlexander V. Chernikov 
1420563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1421563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1422563b5ab1SAlexander V. Chernikov 
1423563b5ab1SAlexander V. Chernikov 	return (NULL);
1424563b5ab1SAlexander V. Chernikov }
1425563b5ab1SAlexander V. Chernikov 
14266c2997ffSAlexander V. Chernikov void
14276c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
14286c2997ffSAlexander V. Chernikov {
14296c2997ffSAlexander V. Chernikov 
14306c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
14316c2997ffSAlexander V. Chernikov }
14326c2997ffSAlexander V. Chernikov 
14336c2997ffSAlexander V. Chernikov int
14346c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
14356c2997ffSAlexander V. Chernikov {
14366c2997ffSAlexander V. Chernikov 	int c, i, l;
14376c2997ffSAlexander V. Chernikov 
14386c2997ffSAlexander V. Chernikov 	/*
14396c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
14406c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1441ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
14426c2997ffSAlexander V. Chernikov 	 */
14436c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
14446c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
14456c2997ffSAlexander V. Chernikov 		return (EINVAL);
14466c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
14476c2997ffSAlexander V. Chernikov 		c = tablename[i];
14486c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
14496c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
14506c2997ffSAlexander V. Chernikov 			continue;
14516c2997ffSAlexander V. Chernikov 		return (EINVAL);
14526c2997ffSAlexander V. Chernikov 	}
14536c2997ffSAlexander V. Chernikov 
1454ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1455ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1456ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1457ac35ff17SAlexander V. Chernikov 
14586c2997ffSAlexander V. Chernikov 	return (0);
14596c2997ffSAlexander V. Chernikov }
14606c2997ffSAlexander V. Chernikov 
1461