xref: /freebsd/sbin/ipfw/tables.c (revision 720ee730c602e624022fa74b9fd61604318a6d41)
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);
57adf3b2b9SAlexander V. Chernikov static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i);
5846d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second);
59adf3b2b9SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
60adf3b2b9SAlexander V. Chernikov static void table_modify(ipfw_obj_header *oh, int ac, char *av[]);
61adf3b2b9SAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
6246d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second);
63ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
64f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
65ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
66ac35ff17SAlexander V. Chernikov     uint16_t uidx);
67f1220db8SAlexander V. Chernikov 
68f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
69f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
70*720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh);
71f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
7281d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
73f1220db8SAlexander V. Chernikov 
74ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7581d3153dSAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
76ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
77ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
78ac35ff17SAlexander V. Chernikov 
79f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
80f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
81f1220db8SAlexander V. Chernikov 
82f1220db8SAlexander V. Chernikov #ifndef s6_addr32
83f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
84f1220db8SAlexander V. Chernikov #endif
85f1220db8SAlexander V. Chernikov 
86ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
87ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
88ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
89b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
90914bffb6SAlexander V. Chernikov       { "flow",		IPFW_TABLE_FLOW },
91ac35ff17SAlexander V. Chernikov       { NULL, 0 }
92ac35ff17SAlexander V. Chernikov };
93ac35ff17SAlexander V. Chernikov 
94ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
95ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
96ac35ff17SAlexander V. Chernikov       { NULL, 0 }
97ac35ff17SAlexander V. Chernikov };
98ac35ff17SAlexander V. Chernikov 
99adf3b2b9SAlexander V. Chernikov static struct _s_x tablefvaltypes[] = {
100adf3b2b9SAlexander V. Chernikov       { "ip",		IPFW_VFTYPE_IP },
101adf3b2b9SAlexander V. Chernikov       { "number",	IPFW_VFTYPE_U32 },
102adf3b2b9SAlexander V. Chernikov       { NULL, 0 }
103adf3b2b9SAlexander V. Chernikov };
104adf3b2b9SAlexander V. Chernikov 
105ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
106ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
107ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
10846d52008SAlexander V. Chernikov       { "create",	TOK_CREATE },
109ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
110ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
111adf3b2b9SAlexander V. Chernikov       { "modify",	TOK_MODIFY },
11246d52008SAlexander V. Chernikov       { "swap",		TOK_SWAP },
113ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
114358b9d09SAlexander V. Chernikov       { "detail",	TOK_DETAIL },
115ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
11681d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
117ac35ff17SAlexander V. Chernikov       { NULL, 0 }
118ac35ff17SAlexander V. Chernikov };
119ac35ff17SAlexander V. Chernikov 
120f1220db8SAlexander V. Chernikov static int
121f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
122f1220db8SAlexander V. Chernikov {
123f1220db8SAlexander V. Chernikov 	struct hostent *he;
124f1220db8SAlexander V. Chernikov 
125f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
126f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
127f1220db8SAlexander V. Chernikov 			return(-1);
128f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
129f1220db8SAlexander V. Chernikov 	}
130f1220db8SAlexander V. Chernikov 	return(0);
131f1220db8SAlexander V. Chernikov }
132f1220db8SAlexander V. Chernikov 
133f1220db8SAlexander V. Chernikov /*
134f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
135ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
136ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
137ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
138ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
139ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
140ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
141ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
142f1220db8SAlexander V. Chernikov  */
143f1220db8SAlexander V. Chernikov void
144f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
145f1220db8SAlexander V. Chernikov {
146ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
147ac35ff17SAlexander V. Chernikov 	int error, tcmd;
148ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
149ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
150f1220db8SAlexander V. Chernikov 	char *tablename;
151ac35ff17SAlexander V. Chernikov 	uint32_t set;
152358b9d09SAlexander V. Chernikov 	void *arg;
153f1220db8SAlexander V. Chernikov 
154ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
155ac35ff17SAlexander V. Chernikov 	is_all = 0;
156ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
157ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
158ac35ff17SAlexander V. Chernikov 	else
159ac35ff17SAlexander V. Chernikov 		set = 0;
160f1220db8SAlexander V. Chernikov 
161f1220db8SAlexander V. Chernikov 	ac--; av++;
1629d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
163f1220db8SAlexander V. Chernikov 	tablename = *av;
164f1220db8SAlexander V. Chernikov 
165ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
166ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
167ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
168ac35ff17SAlexander V. Chernikov 	} else {
169ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
170ac35ff17SAlexander V. Chernikov 			is_all = 1;
171ac35ff17SAlexander V. Chernikov 		else
172ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
173ac35ff17SAlexander V. Chernikov 	}
174ac35ff17SAlexander V. Chernikov 	ac--; av++;
1759d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
176ac35ff17SAlexander V. Chernikov 
177ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
178ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
179ac35ff17SAlexander V. Chernikov 
180ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
181ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
182ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
183358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
184ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
185ac35ff17SAlexander V. Chernikov 		break;
186ac35ff17SAlexander V. Chernikov 	default:
187ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
188ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
189ac35ff17SAlexander V. Chernikov 	}
190ac35ff17SAlexander V. Chernikov 
191ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
192ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
193ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
194f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
195f1220db8SAlexander V. Chernikov 		ac--; av++;
196ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
197ac35ff17SAlexander V. Chernikov 		break;
198ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
199f1220db8SAlexander V. Chernikov 		ac--; av++;
200ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
201ac35ff17SAlexander V. Chernikov 		break;
202adf3b2b9SAlexander V. Chernikov 	case TOK_MODIFY:
203adf3b2b9SAlexander V. Chernikov 		ac--; av++;
204adf3b2b9SAlexander V. Chernikov 		table_modify(&oh, ac, av);
205adf3b2b9SAlexander V. Chernikov 		break;
206ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
207ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
208ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
209ac35ff17SAlexander V. Chernikov 		break;
210ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
211f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
212ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
213f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
214f1220db8SAlexander V. Chernikov 				    tablename);
215f1220db8SAlexander V. Chernikov 		} else {
216ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
217f1220db8SAlexander V. Chernikov 			if (error != 0)
218f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
219f1220db8SAlexander V. Chernikov 		}
220ac35ff17SAlexander V. Chernikov 		break;
22146d52008SAlexander V. Chernikov 	case TOK_SWAP:
22246d52008SAlexander V. Chernikov 		ac--; av++;
22346d52008SAlexander V. Chernikov 		NEED1("second table name required");
22446d52008SAlexander V. Chernikov 		table_swap(&oh, *av);
22546d52008SAlexander V. Chernikov 		break;
226358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
227ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
228358b9d09SAlexander V. Chernikov 		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
229f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
230ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
231f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
232358b9d09SAlexander V. Chernikov 			table_show_info(&i, arg);
233f1220db8SAlexander V. Chernikov 		} else {
234358b9d09SAlexander V. Chernikov 			error = tables_foreach(table_show_info, arg, 1);
235f1220db8SAlexander V. Chernikov 			if (error != 0)
236f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
237f1220db8SAlexander V. Chernikov 		}
238ac35ff17SAlexander V. Chernikov 		break;
239ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
240ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
241ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
242ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
243ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
244ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
245f1220db8SAlexander V. Chernikov 		} else {
246ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
247ac35ff17SAlexander V. Chernikov 			if (error != 0)
248ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
249f1220db8SAlexander V. Chernikov 		}
250ac35ff17SAlexander V. Chernikov 		break;
25181d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
25281d3153dSAlexander V. Chernikov 		ac--; av++;
25381d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
25481d3153dSAlexander V. Chernikov 		break;
255f1220db8SAlexander V. Chernikov 	}
256f1220db8SAlexander V. Chernikov }
257f1220db8SAlexander V. Chernikov 
258f1220db8SAlexander V. Chernikov static void
259ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
260f1220db8SAlexander V. Chernikov {
261f1220db8SAlexander V. Chernikov 
262563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
263f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
264f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
265ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
266f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
267f1220db8SAlexander V. Chernikov }
268f1220db8SAlexander V. Chernikov 
269f1220db8SAlexander V. Chernikov static void
270f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
271f1220db8SAlexander V. Chernikov {
272f1220db8SAlexander V. Chernikov 
273f1220db8SAlexander V. Chernikov 	oh->idx = 1;
27481d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
275ac35ff17SAlexander V. Chernikov }
276ac35ff17SAlexander V. Chernikov 
277ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
278ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE },
279adf3b2b9SAlexander V. Chernikov       { "ftype",	TOK_FTYPE },
280ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
281ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
2824c0c07a5SAlexander V. Chernikov       { "limit",	TOK_LIMIT },
283ac35ff17SAlexander V. Chernikov       { NULL, 0 }
284ac35ff17SAlexander V. Chernikov };
285ac35ff17SAlexander V. Chernikov 
286914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
287914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
288914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
289914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
290914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
291914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
292914bffb6SAlexander V. Chernikov       { NULL, 0 }
293914bffb6SAlexander V. Chernikov };
294914bffb6SAlexander V. Chernikov 
295914bffb6SAlexander V. Chernikov int
296914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
297914bffb6SAlexander V. Chernikov {
298914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
299914bffb6SAlexander V. Chernikov 
300914bffb6SAlexander V. Chernikov 	/* Parse type options */
301914bffb6SAlexander V. Chernikov 	switch(ttype) {
302914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
303914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
304914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
305914bffb6SAlexander V. Chernikov 		    &fclear);
306914bffb6SAlexander V. Chernikov 		*tflags = fset;
307914bffb6SAlexander V. Chernikov 		break;
308914bffb6SAlexander V. Chernikov 	default:
309914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
310914bffb6SAlexander V. Chernikov 	}
311914bffb6SAlexander V. Chernikov 
312914bffb6SAlexander V. Chernikov 	return (0);
313914bffb6SAlexander V. Chernikov }
314914bffb6SAlexander V. Chernikov 
315914bffb6SAlexander V. Chernikov void
316914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
317914bffb6SAlexander V. Chernikov {
318914bffb6SAlexander V. Chernikov 	const char *tname;
319914bffb6SAlexander V. Chernikov 	int l;
320914bffb6SAlexander V. Chernikov 
321914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
322914bffb6SAlexander V. Chernikov 		tname = "unknown";
323914bffb6SAlexander V. Chernikov 
324914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
325914bffb6SAlexander V. Chernikov 	tbuf += l;
326914bffb6SAlexander V. Chernikov 	size -= l;
327914bffb6SAlexander V. Chernikov 
328914bffb6SAlexander V. Chernikov 	switch(type) {
329914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
330914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
331914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
332914bffb6SAlexander V. Chernikov 			l--;
333914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
334914bffb6SAlexander V. Chernikov 		}
335914bffb6SAlexander V. Chernikov 		break;
336914bffb6SAlexander V. Chernikov 	}
337914bffb6SAlexander V. Chernikov }
338914bffb6SAlexander V. Chernikov 
339ac35ff17SAlexander V. Chernikov /*
340ac35ff17SAlexander V. Chernikov  * Creates new table
341ac35ff17SAlexander V. Chernikov  *
342ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
343ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
344ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
345ac35ff17SAlexander V. Chernikov  */
346ac35ff17SAlexander V. Chernikov static void
347ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
348ac35ff17SAlexander V. Chernikov {
349ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
350ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
351ac35ff17SAlexander V. Chernikov 	size_t sz;
352914bffb6SAlexander V. Chernikov 	char *p;
353ac35ff17SAlexander V. Chernikov 	char tbuf[128];
354ac35ff17SAlexander V. Chernikov 
355ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
356ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
357ac35ff17SAlexander V. Chernikov 
358ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
359ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
360ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
361ac35ff17SAlexander V. Chernikov 
362ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
363ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
364ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
365ac35ff17SAlexander V. Chernikov 		ac--; av++;
366ac35ff17SAlexander V. Chernikov 
367ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
3684c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
3694c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
3704c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
3714c0c07a5SAlexander V. Chernikov 			ac--; av++;
3724c0c07a5SAlexander V. Chernikov 			break;
373ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
374ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
375914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
376914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
377914bffb6SAlexander V. Chernikov 				*p++ = '\0';
378ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
379914bffb6SAlexander V. Chernikov 			if (val == -1) {
380914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
381914bffb6SAlexander V. Chernikov 				    ", ");
382914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
383914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
384ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
385914bffb6SAlexander V. Chernikov 			}
386914bffb6SAlexander V. Chernikov 			xi.type = val;
387914bffb6SAlexander V. Chernikov 			if (p != NULL) {
388914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
389914bffb6SAlexander V. Chernikov 				if (error != 0)
390914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
391914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
392914bffb6SAlexander V. Chernikov 			}
393914bffb6SAlexander V. Chernikov 			ac--; av++;
394ac35ff17SAlexander V. Chernikov 			break;
395ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
396ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
397ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
398ac35ff17SAlexander V. Chernikov 			if (val != -1) {
399ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
400ac35ff17SAlexander V. Chernikov 				ac--; av++;
401ac35ff17SAlexander V. Chernikov 				break;
402ac35ff17SAlexander V. Chernikov 			}
403ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
404ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
405ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
406ac35ff17SAlexander V. Chernikov 			break;
407adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
408adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
409adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
410adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
411adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
412adf3b2b9SAlexander V. Chernikov 				ac--; av++;
413adf3b2b9SAlexander V. Chernikov 				break;
414adf3b2b9SAlexander V. Chernikov 			}
415adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
416adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown format type: %s. Supported: %s",
417adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
418adf3b2b9SAlexander V. Chernikov 			break;
419ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
420ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
421ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
422ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
423ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
424ac35ff17SAlexander V. Chernikov 			ac--; av++;
425ac35ff17SAlexander V. Chernikov 			break;
426ac35ff17SAlexander V. Chernikov 		}
427ac35ff17SAlexander V. Chernikov 	}
428ac35ff17SAlexander V. Chernikov 
429ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
430ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
431f1220db8SAlexander V. Chernikov }
432f1220db8SAlexander V. Chernikov 
433f1220db8SAlexander V. Chernikov /*
434ac35ff17SAlexander V. Chernikov  * Creates new table
435ac35ff17SAlexander V. Chernikov  *
436ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
437ac35ff17SAlexander V. Chernikov  *
438f1220db8SAlexander V. Chernikov  * Returns 0 on success.
439f1220db8SAlexander V. Chernikov  */
440f1220db8SAlexander V. Chernikov static int
441ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
442f1220db8SAlexander V. Chernikov {
443ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
444ac35ff17SAlexander V. Chernikov 	int error;
445f1220db8SAlexander V. Chernikov 
446ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
447ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
448ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
449ac35ff17SAlexander V. Chernikov 
450ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
451ac35ff17SAlexander V. Chernikov 
452ac35ff17SAlexander V. Chernikov 	return (error);
453ac35ff17SAlexander V. Chernikov }
454ac35ff17SAlexander V. Chernikov 
455ac35ff17SAlexander V. Chernikov /*
456adf3b2b9SAlexander V. Chernikov  * Modifies existing table
457adf3b2b9SAlexander V. Chernikov  *
458adf3b2b9SAlexander V. Chernikov  * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
459adf3b2b9SAlexander V. Chernikov  */
460adf3b2b9SAlexander V. Chernikov static void
461adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[])
462adf3b2b9SAlexander V. Chernikov {
463adf3b2b9SAlexander V. Chernikov 	ipfw_xtable_info xi;
464adf3b2b9SAlexander V. Chernikov 	int error, tcmd, val;
465adf3b2b9SAlexander V. Chernikov 	size_t sz;
466adf3b2b9SAlexander V. Chernikov 	char tbuf[128];
467adf3b2b9SAlexander V. Chernikov 
468adf3b2b9SAlexander V. Chernikov 	sz = sizeof(tbuf);
469adf3b2b9SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
470adf3b2b9SAlexander V. Chernikov 
471adf3b2b9SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
472adf3b2b9SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
473adf3b2b9SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
474adf3b2b9SAlexander V. Chernikov 
475adf3b2b9SAlexander V. Chernikov 	while (ac > 0) {
476adf3b2b9SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
477adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
478adf3b2b9SAlexander V. Chernikov 		ac--; av++;
479adf3b2b9SAlexander V. Chernikov 
480adf3b2b9SAlexander V. Chernikov 		switch (tcmd) {
481adf3b2b9SAlexander V. Chernikov 		case TOK_LIMIT:
482adf3b2b9SAlexander V. Chernikov 			NEED1("limit value required");
483adf3b2b9SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
484adf3b2b9SAlexander V. Chernikov 			xi.mflags |= IPFW_TMFLAGS_LIMIT;
485adf3b2b9SAlexander V. Chernikov 			ac--; av++;
486adf3b2b9SAlexander V. Chernikov 			break;
487adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
488adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
489adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
490adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
491adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
492adf3b2b9SAlexander V. Chernikov 				xi.mflags |= IPFW_TMFLAGS_FTYPE;
493adf3b2b9SAlexander V. Chernikov 				ac--; av++;
494adf3b2b9SAlexander V. Chernikov 				break;
495adf3b2b9SAlexander V. Chernikov 			}
496adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
497adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
498adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
499adf3b2b9SAlexander V. Chernikov 			break;
500adf3b2b9SAlexander V. Chernikov 		}
501adf3b2b9SAlexander V. Chernikov 	}
502adf3b2b9SAlexander V. Chernikov 
503adf3b2b9SAlexander V. Chernikov 	if ((error = table_do_modify(oh, &xi)) != 0)
504adf3b2b9SAlexander V. Chernikov 		err(EX_OSERR, "Table modification failed");
505adf3b2b9SAlexander V. Chernikov }
506adf3b2b9SAlexander V. Chernikov 
507adf3b2b9SAlexander V. Chernikov /*
508adf3b2b9SAlexander V. Chernikov  * Modifies existing table.
509adf3b2b9SAlexander V. Chernikov  *
510adf3b2b9SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
511adf3b2b9SAlexander V. Chernikov  *
512adf3b2b9SAlexander V. Chernikov  * Returns 0 on success.
513adf3b2b9SAlexander V. Chernikov  */
514adf3b2b9SAlexander V. Chernikov static int
515adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
516adf3b2b9SAlexander V. Chernikov {
517adf3b2b9SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
518adf3b2b9SAlexander V. Chernikov 	int error;
519adf3b2b9SAlexander V. Chernikov 
520adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
521adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
522adf3b2b9SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
523adf3b2b9SAlexander V. Chernikov 
524adf3b2b9SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
525adf3b2b9SAlexander V. Chernikov 
526adf3b2b9SAlexander V. Chernikov 	return (error);
527adf3b2b9SAlexander V. Chernikov }
528adf3b2b9SAlexander V. Chernikov /*
529ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
530ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
531ac35ff17SAlexander V. Chernikov  */
532ac35ff17SAlexander V. Chernikov static int
533ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
534ac35ff17SAlexander V. Chernikov {
535ac35ff17SAlexander V. Chernikov 
536ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
537f1220db8SAlexander V. Chernikov 		return (-1);
538f1220db8SAlexander V. Chernikov 
539f1220db8SAlexander V. Chernikov 	return (0);
540f1220db8SAlexander V. Chernikov }
541f1220db8SAlexander V. Chernikov 
542f1220db8SAlexander V. Chernikov /*
543ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
544f1220db8SAlexander V. Chernikov  * Returns 0 on success.
545f1220db8SAlexander V. Chernikov  */
546f1220db8SAlexander V. Chernikov static int
547ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
548f1220db8SAlexander V. Chernikov {
549f1220db8SAlexander V. Chernikov 
550ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
551f1220db8SAlexander V. Chernikov 		return (-1);
552f1220db8SAlexander V. Chernikov 
553f1220db8SAlexander V. Chernikov 	return (0);
554f1220db8SAlexander V. Chernikov }
555f1220db8SAlexander V. Chernikov 
55646d52008SAlexander V. Chernikov static int
55746d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second)
55846d52008SAlexander V. Chernikov {
55946d52008SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
56046d52008SAlexander V. Chernikov 	int error;
56146d52008SAlexander V. Chernikov 
56246d52008SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
56346d52008SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
56446d52008SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
56546d52008SAlexander V. Chernikov 	table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
56646d52008SAlexander V. Chernikov 
56746d52008SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
56846d52008SAlexander V. Chernikov 
56946d52008SAlexander V. Chernikov 	return (error);
57046d52008SAlexander V. Chernikov }
57146d52008SAlexander V. Chernikov 
57246d52008SAlexander V. Chernikov /*
57346d52008SAlexander V. Chernikov  * Swaps given table with @second one.
57446d52008SAlexander V. Chernikov  */
57546d52008SAlexander V. Chernikov static int
57646d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second)
57746d52008SAlexander V. Chernikov {
57846d52008SAlexander V. Chernikov 	int error;
57946d52008SAlexander V. Chernikov 
58046d52008SAlexander V. Chernikov 	if (table_check_name(second) != 0)
58146d52008SAlexander V. Chernikov 		errx(EX_USAGE, "table name %s is invalid", second);
58246d52008SAlexander V. Chernikov 
58346d52008SAlexander V. Chernikov 	error = table_do_swap(oh, second);
58446d52008SAlexander V. Chernikov 
58546d52008SAlexander V. Chernikov 	switch (error) {
58646d52008SAlexander V. Chernikov 	case EINVAL:
58746d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check types");
58846d52008SAlexander V. Chernikov 	case EFBIG:
58946d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check limits");
59046d52008SAlexander V. Chernikov 	}
59146d52008SAlexander V. Chernikov 
59246d52008SAlexander V. Chernikov 	return (0);
59346d52008SAlexander V. Chernikov }
59446d52008SAlexander V. Chernikov 
59546d52008SAlexander V. Chernikov 
596f1220db8SAlexander V. Chernikov /*
597ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
598f1220db8SAlexander V. Chernikov  * it inside @i.
599f1220db8SAlexander V. Chernikov  * Returns 0 on success.
600f1220db8SAlexander V. Chernikov  */
601f1220db8SAlexander V. Chernikov static int
602ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
603f1220db8SAlexander V. Chernikov {
604f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
605ac35ff17SAlexander V. Chernikov 	int error;
606f1220db8SAlexander V. Chernikov 	size_t sz;
607f1220db8SAlexander V. Chernikov 
608f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
609f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
610ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
611f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
612f1220db8SAlexander V. Chernikov 
613ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
614ac35ff17SAlexander V. Chernikov 		return (error);
615f1220db8SAlexander V. Chernikov 
616f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
617ac35ff17SAlexander V. Chernikov 		return (EINVAL);
618f1220db8SAlexander V. Chernikov 
619f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
620f1220db8SAlexander V. Chernikov 
621f1220db8SAlexander V. Chernikov 	return (0);
622f1220db8SAlexander V. Chernikov }
623f1220db8SAlexander V. Chernikov 
6245f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
6255f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
6265f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
6275f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
6285f379342SAlexander V. Chernikov       { NULL, 0 }
6295f379342SAlexander V. Chernikov };
6305f379342SAlexander V. Chernikov 
6315f379342SAlexander V. Chernikov struct ta_cldata {
6325f379342SAlexander V. Chernikov 	uint8_t		taclass;
6335f379342SAlexander V. Chernikov 	uint8_t		spare4;
6345f379342SAlexander V. Chernikov 	uint16_t	itemsize;
6355f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
6365f379342SAlexander V. Chernikov 	uint32_t	size;
6375f379342SAlexander V. Chernikov 	uint32_t	count;
6385f379342SAlexander V. Chernikov };
6395f379342SAlexander V. Chernikov 
6405f379342SAlexander V. Chernikov /*
6415f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
6425f379342SAlexander V. Chernikov  */
6435f379342SAlexander V. Chernikov static void
6445f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
6455f379342SAlexander V. Chernikov     const char *af, const char *taclass)
6465f379342SAlexander V. Chernikov {
6475f379342SAlexander V. Chernikov 
6485f379342SAlexander V. Chernikov 	switch (d->taclass) {
6495f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
6505f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
6515f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
6525f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
6535f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
6545f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
6555f379342SAlexander V. Chernikov 		else
6565f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
6575f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
6585f379342SAlexander V. Chernikov 			    d->size, d->count,
6595f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
6605f379342SAlexander V. Chernikov 		break;
6615f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
6625f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
6635f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
6645f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
6655f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
6665f379342SAlexander V. Chernikov 		else
6675f379342SAlexander V. Chernikov 			printf("  items: %u "
6685f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
6695f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
6705f379342SAlexander V. Chernikov 		break;
6715f379342SAlexander V. Chernikov 	default:
6725f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
6735f379342SAlexander V. Chernikov 	}
6745f379342SAlexander V. Chernikov }
6755f379342SAlexander V. Chernikov 
676f1220db8SAlexander V. Chernikov /*
677f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
678f1220db8SAlexander V. Chernikov  */
679f1220db8SAlexander V. Chernikov static int
680f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
681f1220db8SAlexander V. Chernikov {
682adf3b2b9SAlexander V. Chernikov 	const char *vtype, *vftype;
6835f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
6845f379342SAlexander V. Chernikov 	int afdata, afitem;
6855f379342SAlexander V. Chernikov 	struct ta_cldata d;
686adf3b2b9SAlexander V. Chernikov 	char ttype[64], tvtype[64];
687f1220db8SAlexander V. Chernikov 
688914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
689ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
690ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
691adf3b2b9SAlexander V. Chernikov 	if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL)
692adf3b2b9SAlexander V. Chernikov 		vftype = "unknown";
693adf3b2b9SAlexander V. Chernikov 	if (strcmp(vtype, vftype) != 0)
694adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype);
695adf3b2b9SAlexander V. Chernikov 	else
696adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s", vtype);
697ac35ff17SAlexander V. Chernikov 
698914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
699914bffb6SAlexander V. Chernikov 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
700adf3b2b9SAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
7019d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
702f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
7034c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
7044c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
705f1220db8SAlexander V. Chernikov 
706358b9d09SAlexander V. Chernikov 	/* Print algo-specific info if requested & set  */
707358b9d09SAlexander V. Chernikov 	if (arg == NULL)
708358b9d09SAlexander V. Chernikov 		return (0);
709358b9d09SAlexander V. Chernikov 
7105f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
7115f379342SAlexander V. Chernikov 		return (0);
7125f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
7135f379342SAlexander V. Chernikov 
7145f379342SAlexander V. Chernikov 	afdata = 0;
7155f379342SAlexander V. Chernikov 	afitem = 0;
7165f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
7175f379342SAlexander V. Chernikov 		afdata = 1;
7185f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
7195f379342SAlexander V. Chernikov 		afitem = 1;
7205f379342SAlexander V. Chernikov 
7215f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
7225f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
7235f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
7245f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
7255f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
7265f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
7275f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
7285f379342SAlexander V. Chernikov 	else
7295f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
7305f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7315f379342SAlexander V. Chernikov 		vtype = "unknown";
7325f379342SAlexander V. Chernikov 
7335f379342SAlexander V. Chernikov 	if (afdata == 0) {
7345f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
7355f379342SAlexander V. Chernikov 	} else {
7365f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
7375f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
7385f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
7395f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7405f379342SAlexander V. Chernikov 			vtype = "unknown";
7415f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
7425f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
7435f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
7445f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
7455f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
7465f379342SAlexander V. Chernikov 	}
7475f379342SAlexander V. Chernikov 
748f1220db8SAlexander V. Chernikov 	return (0);
749f1220db8SAlexander V. Chernikov }
750f1220db8SAlexander V. Chernikov 
751f1220db8SAlexander V. Chernikov 
752f1220db8SAlexander V. Chernikov /*
753f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
754f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
755f1220db8SAlexander V. Chernikov  */
756f1220db8SAlexander V. Chernikov 
757f1220db8SAlexander V. Chernikov static int
758f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
759f1220db8SAlexander V. Chernikov {
760f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
76181d3153dSAlexander V. Chernikov 	int error;
762f1220db8SAlexander V. Chernikov 
763*720ee730SAlexander V. Chernikov 	if ((error = table_do_get_list(i, &oh)) != 0) {
76481d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
76581d3153dSAlexander V. Chernikov 		return (error);
76681d3153dSAlexander V. Chernikov 	}
76781d3153dSAlexander V. Chernikov 
768f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
769f1220db8SAlexander V. Chernikov 
770f1220db8SAlexander V. Chernikov 	free(oh);
771f1220db8SAlexander V. Chernikov 	return (0);
772f1220db8SAlexander V. Chernikov }
773f1220db8SAlexander V. Chernikov 
774f1220db8SAlexander V. Chernikov static int
775f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
776f1220db8SAlexander V. Chernikov {
777ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
778f1220db8SAlexander V. Chernikov 
779ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
780ac35ff17SAlexander V. Chernikov 
781ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
782ac35ff17SAlexander V. Chernikov 
783ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
784f1220db8SAlexander V. Chernikov }
785f1220db8SAlexander V. Chernikov 
786ac35ff17SAlexander V. Chernikov static int
787ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
788ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
789ac35ff17SAlexander V. Chernikov {
790db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
791db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
792ac35ff17SAlexander V. Chernikov 	int error;
793ac35ff17SAlexander V. Chernikov 
794ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
795ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
796ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
797ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
798ac35ff17SAlexander V. Chernikov 
799db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
800db785d31SAlexander V. Chernikov 	ctlv->count = 1;
801db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
802db785d31SAlexander V. Chernikov 
803db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
804db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
805ac35ff17SAlexander V. Chernikov 	if (update != 0)
80681d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
807ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
808ac35ff17SAlexander V. Chernikov 
809ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
810ac35ff17SAlexander V. Chernikov 
811ac35ff17SAlexander V. Chernikov 	return (error);
812ac35ff17SAlexander V. Chernikov }
813ac35ff17SAlexander V. Chernikov 
814ac35ff17SAlexander V. Chernikov static void
815ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
816ac35ff17SAlexander V. Chernikov {
817ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
81881d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
819ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
8204c0c07a5SAlexander V. Chernikov 	int cmd, error;
8214c0c07a5SAlexander V. Chernikov 	char *texterr, *etxt;
822ac35ff17SAlexander V. Chernikov 
823ac35ff17SAlexander V. Chernikov 	if (ac == 0)
824ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
825ac35ff17SAlexander V. Chernikov 
826ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
827ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
828ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
829ac35ff17SAlexander V. Chernikov 
83081d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
831db785d31SAlexander V. Chernikov 
832db785d31SAlexander V. Chernikov 	/*
833db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
834db785d31SAlexander V. Chernikov 	 */
835db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
836db785d31SAlexander V. Chernikov 		xi.type = type;
837db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
838db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
839db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
840db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
841db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
842db785d31SAlexander V. Chernikov 	}
843db785d31SAlexander V. Chernikov 
844ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
845ac35ff17SAlexander V. Chernikov 	ac--; av++;
846ac35ff17SAlexander V. Chernikov 
847ac35ff17SAlexander V. Chernikov 	if (add != 0) {
848ac35ff17SAlexander V. Chernikov 		if (ac > 0)
849ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
850ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
8514c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
852ac35ff17SAlexander V. Chernikov 	} else {
853ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
8544c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
855ac35ff17SAlexander V. Chernikov 	}
856ac35ff17SAlexander V. Chernikov 
8574c0c07a5SAlexander V. Chernikov 	if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0)
8584c0c07a5SAlexander V. Chernikov 		return;
8594c0c07a5SAlexander V. Chernikov 
8604c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
8614c0c07a5SAlexander V. Chernikov 	switch (error) {
8624c0c07a5SAlexander V. Chernikov 	case EEXIST:
8634c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
8644c0c07a5SAlexander V. Chernikov 		break;
8654c0c07a5SAlexander V. Chernikov 	case EFBIG:
8664c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
8674c0c07a5SAlexander V. Chernikov 		break;
8684c0c07a5SAlexander V. Chernikov 	case ESRCH:
8694c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
8704c0c07a5SAlexander V. Chernikov 		break;
8714c0c07a5SAlexander V. Chernikov 	case ENOENT:
8724c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
8734c0c07a5SAlexander V. Chernikov 		break;
8744c0c07a5SAlexander V. Chernikov 	default:
8754c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
8764c0c07a5SAlexander V. Chernikov 	}
8774c0c07a5SAlexander V. Chernikov 
8784c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
879ac35ff17SAlexander V. Chernikov }
880ac35ff17SAlexander V. Chernikov 
88181d3153dSAlexander V. Chernikov static int
88281d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
88381d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
88481d3153dSAlexander V. Chernikov {
88581d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
88681d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
88781d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
88881d3153dSAlexander V. Chernikov 	int error;
88981d3153dSAlexander V. Chernikov 	size_t sz;
89081d3153dSAlexander V. Chernikov 
89181d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
89281d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
89381d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
89481d3153dSAlexander V. Chernikov 
89581d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
89681d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
89781d3153dSAlexander V. Chernikov 	tent->idx = 1;
89881d3153dSAlexander V. Chernikov 
89981d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
90081d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
90181d3153dSAlexander V. Chernikov 
90281d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
90381d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
90481d3153dSAlexander V. Chernikov 		return (error);
90581d3153dSAlexander V. Chernikov 
90681d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
90781d3153dSAlexander V. Chernikov 		return (EINVAL);
90881d3153dSAlexander V. Chernikov 
90981d3153dSAlexander V. Chernikov 	*xtent = *tent;
91081d3153dSAlexander V. Chernikov 
91181d3153dSAlexander V. Chernikov 	return (0);
91281d3153dSAlexander V. Chernikov }
91381d3153dSAlexander V. Chernikov 
91481d3153dSAlexander V. Chernikov static void
91581d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
91681d3153dSAlexander V. Chernikov {
91781d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
91881d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
919914bffb6SAlexander V. Chernikov 	char key[64];
92081d3153dSAlexander V. Chernikov 	int error;
92181d3153dSAlexander V. Chernikov 
92281d3153dSAlexander V. Chernikov 	if (ac == 0)
92381d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
92481d3153dSAlexander V. Chernikov 
925914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
926914bffb6SAlexander V. Chernikov 
927914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
92881d3153dSAlexander V. Chernikov 
92981d3153dSAlexander V. Chernikov 	switch (error) {
93081d3153dSAlexander V. Chernikov 	case 0:
93181d3153dSAlexander V. Chernikov 		break;
93281d3153dSAlexander V. Chernikov 	case ESRCH:
93381d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
93481d3153dSAlexander V. Chernikov 	case ENOENT:
93581d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
93681d3153dSAlexander V. Chernikov 	case ENOTSUP:
93781d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
93881d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
93981d3153dSAlexander V. Chernikov 	default:
94081d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
94181d3153dSAlexander V. Chernikov 	}
94281d3153dSAlexander V. Chernikov 
94381d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
94481d3153dSAlexander V. Chernikov }
945ac35ff17SAlexander V. Chernikov 
946ac35ff17SAlexander V. Chernikov static void
947914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
948914bffb6SAlexander V. Chernikov     uint8_t tflags)
949ac35ff17SAlexander V. Chernikov {
950914bffb6SAlexander V. Chernikov 	char *p, *pp;
951ac35ff17SAlexander V. Chernikov 	int mask, af;
952914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
953914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
954ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
955914bffb6SAlexander V. Chernikov 	uint16_t port;
956914bffb6SAlexander V. Chernikov 	struct protoent *pent;
957914bffb6SAlexander V. Chernikov 	struct servent *sent;
958ac35ff17SAlexander V. Chernikov 	int masklen;
959ac35ff17SAlexander V. Chernikov 
960ac35ff17SAlexander V. Chernikov 	masklen = 0;
961ac35ff17SAlexander V. Chernikov 	af = 0;
962ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
963ac35ff17SAlexander V. Chernikov 
964ac35ff17SAlexander V. Chernikov 	switch (type) {
965ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
966ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
967ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
968ac35ff17SAlexander V. Chernikov 			*p = '\0';
969ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
970ac35ff17SAlexander V. Chernikov 		}
971ac35ff17SAlexander V. Chernikov 
972ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
973ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
974ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
975ac35ff17SAlexander V. Chernikov 				    p + 1);
976ac35ff17SAlexander V. Chernikov 
977ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
978ac35ff17SAlexander V. Chernikov 			af = AF_INET;
979ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
980ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
981ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
982ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
983ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
984ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
985ac35ff17SAlexander V. Chernikov 				    p + 1);
986ac35ff17SAlexander V. Chernikov 
987ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
988ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
989ac35ff17SAlexander V. Chernikov 		} else {
990ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
991ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
992ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
993ac35ff17SAlexander V. Chernikov 
994ac35ff17SAlexander V. Chernikov 			masklen = 32;
995ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
996ac35ff17SAlexander V. Chernikov 			af = AF_INET;
997ac35ff17SAlexander V. Chernikov 		}
998ac35ff17SAlexander V. Chernikov 		break;
999ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1000ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
1001ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
1002ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
1003ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
1004ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
1005ac35ff17SAlexander V. Chernikov 		break;
1006b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1007ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
1008ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
1009ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1010ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
1011ac35ff17SAlexander V. Chernikov 
1012ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
1013ac35ff17SAlexander V. Chernikov 		*pkey = key;
1014ac35ff17SAlexander V. Chernikov 		masklen = 32;
1015ac35ff17SAlexander V. Chernikov 		break;
1016914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1017914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1018914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
1019914bffb6SAlexander V. Chernikov 		af = 0;
1020914bffb6SAlexander V. Chernikov 
1021914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1022914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
1023914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1024914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1025914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1026914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1027914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1028914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1029914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1030914bffb6SAlexander V. Chernikov 				af = AF_INET;
1031914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
1032914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1033914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1034914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1035914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1036914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1037914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
1038914bffb6SAlexander V. Chernikov 			}
1039914bffb6SAlexander V. Chernikov 
1040914bffb6SAlexander V. Chernikov 			arg = p;
1041914bffb6SAlexander V. Chernikov 		}
1042914bffb6SAlexander V. Chernikov 
1043914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
1044914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
1045914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1046914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1047914bffb6SAlexander V. Chernikov 
1048914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
1049914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
1050914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
1051914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
1052914bffb6SAlexander V. Chernikov 					    arg);
1053914bffb6SAlexander V. Chernikov 				else
1054914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
1055914bffb6SAlexander V. Chernikov 			}
1056914bffb6SAlexander V. Chernikov 
1057914bffb6SAlexander V. Chernikov 			if (key > 255)
1058914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
1059914bffb6SAlexander V. Chernikov 
1060914bffb6SAlexander V. Chernikov 			tfe->proto = key;
1061914bffb6SAlexander V. Chernikov 
1062914bffb6SAlexander V. Chernikov 			arg = p;
1063914bffb6SAlexander V. Chernikov 		}
1064914bffb6SAlexander V. Chernikov 
1065914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1066914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1067914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1068914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1069914bffb6SAlexander V. Chernikov 
1070914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1071914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1072914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1073914bffb6SAlexander V. Chernikov 					    arg);
1074914bffb6SAlexander V. Chernikov 				else
1075914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1076914bffb6SAlexander V. Chernikov 			}
1077914bffb6SAlexander V. Chernikov 
1078914bffb6SAlexander V. Chernikov 			tfe->sport = port;
1079914bffb6SAlexander V. Chernikov 
1080914bffb6SAlexander V. Chernikov 			arg = p;
1081914bffb6SAlexander V. Chernikov 		}
1082914bffb6SAlexander V. Chernikov 
1083914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1084914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
1085914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1086914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1087914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1088914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1089914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1090914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1091914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1092914bffb6SAlexander V. Chernikov 				af = AF_INET;
1093914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
1094914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1095914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1096914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1097914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1098914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1099914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
1100914bffb6SAlexander V. Chernikov 			}
1101914bffb6SAlexander V. Chernikov 
1102914bffb6SAlexander V. Chernikov 			arg = p;
1103914bffb6SAlexander V. Chernikov 		}
1104914bffb6SAlexander V. Chernikov 
1105914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1106914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1107914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1108914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1109914bffb6SAlexander V. Chernikov 
1110914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1111914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1112914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1113914bffb6SAlexander V. Chernikov 					    arg);
1114914bffb6SAlexander V. Chernikov 				else
1115914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1116914bffb6SAlexander V. Chernikov 			}
1117914bffb6SAlexander V. Chernikov 
1118914bffb6SAlexander V. Chernikov 			tfe->dport = port;
1119914bffb6SAlexander V. Chernikov 
1120914bffb6SAlexander V. Chernikov 			arg = p;
1121914bffb6SAlexander V. Chernikov 		}
1122914bffb6SAlexander V. Chernikov 
1123914bffb6SAlexander V. Chernikov 		tfe->af = af;
1124914bffb6SAlexander V. Chernikov 
1125914bffb6SAlexander V. Chernikov 		break;
1126914bffb6SAlexander V. Chernikov 
1127ac35ff17SAlexander V. Chernikov 	default:
1128ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
1129ac35ff17SAlexander V. Chernikov 	}
1130ac35ff17SAlexander V. Chernikov 
1131ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
1132ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
1133ac35ff17SAlexander V. Chernikov }
1134ac35ff17SAlexander V. Chernikov 
1135ac35ff17SAlexander V. Chernikov static void
1136ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
113781d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
1138ac35ff17SAlexander V. Chernikov {
1139914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
1140ac35ff17SAlexander V. Chernikov 	int error;
1141db785d31SAlexander V. Chernikov 	char *del;
1142ac35ff17SAlexander V. Chernikov 
1143ac35ff17SAlexander V. Chernikov 	type = 0;
1144914bffb6SAlexander V. Chernikov 	tflags = 0;
1145ac35ff17SAlexander V. Chernikov 	vtype = 0;
1146ac35ff17SAlexander V. Chernikov 
114781d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
114881d3153dSAlexander V. Chernikov 
114981d3153dSAlexander V. Chernikov 	if (error == 0) {
115081d3153dSAlexander V. Chernikov 		/* Table found. */
115181d3153dSAlexander V. Chernikov 		type = xi->type;
1152914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
115381d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
115481d3153dSAlexander V. Chernikov 	} else {
115581d3153dSAlexander V. Chernikov 		if (error != ESRCH)
115681d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
115781d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
1158ac35ff17SAlexander V. Chernikov 		/*
115981d3153dSAlexander V. Chernikov 		 * Table does not exist.
116081d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
116181d3153dSAlexander V. Chernikov 		 * before failing.
1162ac35ff17SAlexander V. Chernikov 		 */
1163db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1164db785d31SAlexander V. Chernikov 			*del = '\0';
1165ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1166ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1167ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1168ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1169ac35ff17SAlexander V. Chernikov 			/*
117081d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
117181d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1172ac35ff17SAlexander V. Chernikov 			 */
117381d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
117481d3153dSAlexander V. Chernikov 		} else {
117581d3153dSAlexander V. Chernikov 			/* Inknown key */
117681d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1177db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
117881d3153dSAlexander V. Chernikov 		}
1179db785d31SAlexander V. Chernikov 		if (del != NULL)
1180db785d31SAlexander V. Chernikov 			*del = '/';
1181ac35ff17SAlexander V. Chernikov 	}
1182ac35ff17SAlexander V. Chernikov 
1183914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1184ac35ff17SAlexander V. Chernikov 
1185ac35ff17SAlexander V. Chernikov 	*ptype = type;
1186ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1187ac35ff17SAlexander V. Chernikov }
1188ac35ff17SAlexander V. Chernikov 
1189ac35ff17SAlexander V. Chernikov static void
1190ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1191ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1192ac35ff17SAlexander V. Chernikov {
1193adf3b2b9SAlexander V. Chernikov 	uint32_t val;
1194ac35ff17SAlexander V. Chernikov 	char *p;
1195ac35ff17SAlexander V. Chernikov 
1196adf3b2b9SAlexander V. Chernikov 	/* Try to interpret as number first */
1197adf3b2b9SAlexander V. Chernikov 	tent->value = strtoul(arg, &p, 0);
1198adf3b2b9SAlexander V. Chernikov 	if (*p == '\0')
1199adf3b2b9SAlexander V. Chernikov 		return;
1200adf3b2b9SAlexander V. Chernikov 	if (inet_pton(AF_INET, arg, &val) == 1) {
1201adf3b2b9SAlexander V. Chernikov 		tent->value = ntohl(val);
1202adf3b2b9SAlexander V. Chernikov 		return;
1203adf3b2b9SAlexander V. Chernikov 	}
1204adf3b2b9SAlexander V. Chernikov 	/* Try hostname */
1205adf3b2b9SAlexander V. Chernikov 	if (lookup_host(arg, (struct in_addr *)&tent->value) == 0)
1206adf3b2b9SAlexander V. Chernikov 		return;
1207adf3b2b9SAlexander V. Chernikov 	errx(EX_OSERR, "Unable to parse value %s", arg);
1208adf3b2b9SAlexander V. Chernikov #if 0
1209ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1210ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1211ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1212ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1213ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1214ac35ff17SAlexander V. Chernikov 		break;
1215ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1216ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1217ac35ff17SAlexander V. Chernikov 			break;
1218ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1219ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1220ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1221ac35ff17SAlexander V. Chernikov 		break;
1222ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1223ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1224ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1225ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1226ac35ff17SAlexander V. Chernikov 		} else {
1227ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1228ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1229ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1230ac35ff17SAlexander V. Chernikov 		}
1231ac35ff17SAlexander V. Chernikov 		tent->value = code;
1232ac35ff17SAlexander V. Chernikov 		break;
1233ac35ff17SAlexander V. Chernikov 	default:
1234ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1235ac35ff17SAlexander V. Chernikov 	}
1236adf3b2b9SAlexander V. Chernikov #endif
1237ac35ff17SAlexander V. Chernikov }
1238f1220db8SAlexander V. Chernikov 
1239f1220db8SAlexander V. Chernikov /*
1240f1220db8SAlexander V. Chernikov  * Compare table names.
1241f1220db8SAlexander V. Chernikov  * Honor number comparison.
1242f1220db8SAlexander V. Chernikov  */
1243f1220db8SAlexander V. Chernikov static int
1244f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1245f1220db8SAlexander V. Chernikov {
1246f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1247f1220db8SAlexander V. Chernikov 
1248f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1249f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1250f1220db8SAlexander V. Chernikov 
125168394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1252f1220db8SAlexander V. Chernikov }
1253f1220db8SAlexander V. Chernikov 
1254f1220db8SAlexander V. Chernikov /*
1255f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1256f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1257f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1258f1220db8SAlexander V. Chernikov  */
1259f1220db8SAlexander V. Chernikov static int
1260f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1261f1220db8SAlexander V. Chernikov {
126228ea4fa3SAlexander V. Chernikov 	ipfw_obj_lheader *olh;
1263f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1264f1220db8SAlexander V. Chernikov 	size_t sz;
1265f1220db8SAlexander V. Chernikov 	int i, error;
1266f1220db8SAlexander V. Chernikov 
126728ea4fa3SAlexander V. Chernikov 	/* Start with reasonable default */
126828ea4fa3SAlexander V. Chernikov 	sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
1269f1220db8SAlexander V. Chernikov 
127028ea4fa3SAlexander V. Chernikov 	for (;;) {
1271f1220db8SAlexander V. Chernikov 		if ((olh = calloc(1, sz)) == NULL)
1272f1220db8SAlexander V. Chernikov 			return (ENOMEM);
1273f1220db8SAlexander V. Chernikov 
1274f1220db8SAlexander V. Chernikov 		olh->size = sz;
127528ea4fa3SAlexander V. Chernikov 		error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz);
127628ea4fa3SAlexander V. Chernikov 		if (error == ENOMEM) {
127728ea4fa3SAlexander V. Chernikov 			sz = olh->size;
1278f1220db8SAlexander V. Chernikov 			free(olh);
127928ea4fa3SAlexander V. Chernikov 			continue;
128028ea4fa3SAlexander V. Chernikov 		} else if (error != 0) {
128128ea4fa3SAlexander V. Chernikov 			free(olh);
128228ea4fa3SAlexander V. Chernikov 			return (error);
1283f1220db8SAlexander V. Chernikov 		}
1284f1220db8SAlexander V. Chernikov 
1285f1220db8SAlexander V. Chernikov 		if (sort != 0)
1286f1220db8SAlexander V. Chernikov 			qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1287f1220db8SAlexander V. Chernikov 
1288f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)(olh + 1);
1289f1220db8SAlexander V. Chernikov 		for (i = 0; i < olh->count; i++) {
1290f1220db8SAlexander V. Chernikov 			error = f(info, arg); /* Ignore errors for now */
1291f1220db8SAlexander V. Chernikov 			info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1292f1220db8SAlexander V. Chernikov 		}
1293f1220db8SAlexander V. Chernikov 
1294f1220db8SAlexander V. Chernikov 		free(olh);
129528ea4fa3SAlexander V. Chernikov 		break;
129628ea4fa3SAlexander V. Chernikov 	}
1297f1220db8SAlexander V. Chernikov 
1298f1220db8SAlexander V. Chernikov 	return (0);
1299f1220db8SAlexander V. Chernikov }
1300f1220db8SAlexander V. Chernikov 
130128ea4fa3SAlexander V. Chernikov 
1302f1220db8SAlexander V. Chernikov /*
1303f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1304*720ee730SAlexander V. Chernikov  * eXtended format. Allocate buffer large enough
1305*720ee730SAlexander V. Chernikov  * to store result. Called needs to free it later.
1306f1220db8SAlexander V. Chernikov  *
1307f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1308f1220db8SAlexander V. Chernikov  */
1309f1220db8SAlexander V. Chernikov static int
1310*720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
1311f1220db8SAlexander V. Chernikov {
1312*720ee730SAlexander V. Chernikov 	ipfw_obj_header *oh;
1313f1220db8SAlexander V. Chernikov 	size_t sz;
131481d3153dSAlexander V. Chernikov 	int error, c;
1315f1220db8SAlexander V. Chernikov 
131681d3153dSAlexander V. Chernikov 	sz = 0;
1317*720ee730SAlexander V. Chernikov 	oh = NULL;
1318*720ee730SAlexander V. Chernikov 	error = 0;
1319*720ee730SAlexander V. Chernikov 	for (c = 0; c < 8; c++) {
132081d3153dSAlexander V. Chernikov 		if (sz < i->size)
1321*720ee730SAlexander V. Chernikov 			sz = i->size + 44;
1322*720ee730SAlexander V. Chernikov 		if (oh != NULL)
1323*720ee730SAlexander V. Chernikov 			free(oh);
1324*720ee730SAlexander V. Chernikov 		if ((oh = calloc(1, sz)) == NULL)
1325*720ee730SAlexander V. Chernikov 			continue;
1326*720ee730SAlexander V. Chernikov 		table_fill_objheader(oh, i);
1327d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
132881d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1329d3a4f924SAlexander V. Chernikov 
1330*720ee730SAlexander V. Chernikov 		if (error == 0) {
1331*720ee730SAlexander V. Chernikov 			*poh = oh;
1332*720ee730SAlexander V. Chernikov 			return (0);
133381d3153dSAlexander V. Chernikov 		}
1334f1220db8SAlexander V. Chernikov 
1335*720ee730SAlexander V. Chernikov 		if (error != ENOMEM)
1336*720ee730SAlexander V. Chernikov 			break;
1337*720ee730SAlexander V. Chernikov 	}
1338*720ee730SAlexander V. Chernikov 	free(oh);
1339*720ee730SAlexander V. Chernikov 
1340*720ee730SAlexander V. Chernikov 	return (error);
1341f1220db8SAlexander V. Chernikov }
1342f1220db8SAlexander V. Chernikov 
1343f1220db8SAlexander V. Chernikov /*
1344f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1345f1220db8SAlexander V. Chernikov  */
1346f1220db8SAlexander V. Chernikov static void
1347f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1348f1220db8SAlexander V. Chernikov {
134981d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
135081d3153dSAlexander V. Chernikov 	uint32_t count;
1351f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1352f1220db8SAlexander V. Chernikov 
1353f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
135481d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1355f1220db8SAlexander V. Chernikov 
1356f1220db8SAlexander V. Chernikov 	if (need_header)
1357f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1358f1220db8SAlexander V. Chernikov 
1359f1220db8SAlexander V. Chernikov 	count = i->count;
1360f1220db8SAlexander V. Chernikov 	while (count > 0) {
136181d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
136281d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
136381d3153dSAlexander V. Chernikov 		count--;
136481d3153dSAlexander V. Chernikov 	}
136581d3153dSAlexander V. Chernikov }
136681d3153dSAlexander V. Chernikov 
136781d3153dSAlexander V. Chernikov static void
136881d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
136981d3153dSAlexander V. Chernikov {
1370914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1371914bffb6SAlexander V. Chernikov 	void *paddr;
137281d3153dSAlexander V. Chernikov 	uint32_t tval;
1373914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
137481d3153dSAlexander V. Chernikov 
137581d3153dSAlexander V. Chernikov 	tval = tent->value;
137681d3153dSAlexander V. Chernikov 
1377adf3b2b9SAlexander V. Chernikov 	if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
1378914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1379914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1380914bffb6SAlexander V. Chernikov 	} else
1381914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1382914bffb6SAlexander V. Chernikov 
1383f1220db8SAlexander V. Chernikov 	switch (i->type) {
1384f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1385f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
138681d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1387914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1388f1220db8SAlexander V. Chernikov 		break;
1389f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1390f1220db8SAlexander V. Chernikov 		/* Interface names */
1391914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1392b23d5de9SAlexander V. Chernikov 		break;
1393b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1394b23d5de9SAlexander V. Chernikov 		/* numbers */
1395914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1396b23d5de9SAlexander V. Chernikov 		break;
1397914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1398914bffb6SAlexander V. Chernikov 		/* flows */
1399914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1400914bffb6SAlexander V. Chernikov 		comma = "";
1401914bffb6SAlexander V. Chernikov 
1402914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1403914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1404914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1405914bffb6SAlexander V. Chernikov 			else
1406914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1407914bffb6SAlexander V. Chernikov 
1408914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1409914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1410914bffb6SAlexander V. Chernikov 			comma = ",";
1411914bffb6SAlexander V. Chernikov 		}
1412914bffb6SAlexander V. Chernikov 
1413914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1414914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1415914bffb6SAlexander V. Chernikov 			comma = ",";
1416914bffb6SAlexander V. Chernikov 		}
1417914bffb6SAlexander V. Chernikov 
1418914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1419914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1420914bffb6SAlexander V. Chernikov 			comma = ",";
1421914bffb6SAlexander V. Chernikov 		}
1422914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1423914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1424914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1425914bffb6SAlexander V. Chernikov 			else
1426914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1427914bffb6SAlexander V. Chernikov 
1428914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1429914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1430914bffb6SAlexander V. Chernikov 			comma = ",";
1431914bffb6SAlexander V. Chernikov 		}
1432914bffb6SAlexander V. Chernikov 
1433914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1434914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1435914bffb6SAlexander V. Chernikov 			comma = ",";
1436914bffb6SAlexander V. Chernikov 		}
1437914bffb6SAlexander V. Chernikov 
1438914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1439f1220db8SAlexander V. Chernikov 	}
1440f1220db8SAlexander V. Chernikov }
1441f1220db8SAlexander V. Chernikov 
14429d099b4fSAlexander V. Chernikov static int
14439d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
14449d099b4fSAlexander V. Chernikov {
14459d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
14469d099b4fSAlexander V. Chernikov 	size_t sz;
14479d099b4fSAlexander V. Chernikov 	int error;
14489d099b4fSAlexander V. Chernikov 
14499d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
14509d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
14519d099b4fSAlexander V. Chernikov 
14529d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
14539d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
14549d099b4fSAlexander V. Chernikov 		return (error);
14559d099b4fSAlexander V. Chernikov 
14569d099b4fSAlexander V. Chernikov 	sz = req.size;
14579d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
14589d099b4fSAlexander V. Chernikov 		return (ENOMEM);
14599d099b4fSAlexander V. Chernikov 
14609d099b4fSAlexander V. Chernikov 	olh->size = sz;
14619d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
14629d099b4fSAlexander V. Chernikov 		free(olh);
14639d099b4fSAlexander V. Chernikov 		return (error);
14649d099b4fSAlexander V. Chernikov 	}
14659d099b4fSAlexander V. Chernikov 
14669d099b4fSAlexander V. Chernikov 	*polh = olh;
14679d099b4fSAlexander V. Chernikov 	return (0);
14689d099b4fSAlexander V. Chernikov }
14699d099b4fSAlexander V. Chernikov 
14709d099b4fSAlexander V. Chernikov void
14719d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
14729d099b4fSAlexander V. Chernikov {
14739d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
14749d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
14759d099b4fSAlexander V. Chernikov 	int error, i;
14769d099b4fSAlexander V. Chernikov 	const char *atype;
14779d099b4fSAlexander V. Chernikov 
14789d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
14799d099b4fSAlexander V. Chernikov 	if (error != 0)
14809d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
14819d099b4fSAlexander V. Chernikov 
14829d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
14839d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
14849d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
14859d099b4fSAlexander V. Chernikov 			atype = "unknown";
14868ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
14878ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
14889d099b4fSAlexander V. Chernikov 
14899d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
14909d099b4fSAlexander V. Chernikov 	}
14919d099b4fSAlexander V. Chernikov 
14929d099b4fSAlexander V. Chernikov 	free(olh);
14939d099b4fSAlexander V. Chernikov }
14949d099b4fSAlexander V. Chernikov 
14956c2997ffSAlexander V. Chernikov int
14966c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
14976c2997ffSAlexander V. Chernikov {
14986c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
14996c2997ffSAlexander V. Chernikov 
15006c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
15016c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
15026c2997ffSAlexander V. Chernikov 
15036c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
15046c2997ffSAlexander V. Chernikov 		return (-1);
15056c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
15066c2997ffSAlexander V. Chernikov 		return (1);
15076c2997ffSAlexander V. Chernikov 
15086c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
15096c2997ffSAlexander V. Chernikov 		return (-1);
15106c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
15116c2997ffSAlexander V. Chernikov 		return (1);
15126c2997ffSAlexander V. Chernikov 
15136c2997ffSAlexander V. Chernikov 	return (0);
15146c2997ffSAlexander V. Chernikov }
1515563b5ab1SAlexander V. Chernikov 
1516563b5ab1SAlexander V. Chernikov int
15176c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1518563b5ab1SAlexander V. Chernikov {
1519563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1520563b5ab1SAlexander V. Chernikov 	uint16_t key;
1521563b5ab1SAlexander V. Chernikov 
1522563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1523563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1524563b5ab1SAlexander V. Chernikov 
1525563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1526563b5ab1SAlexander V. Chernikov 		return (-1);
1527563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1528563b5ab1SAlexander V. Chernikov 		return (1);
1529563b5ab1SAlexander V. Chernikov 
1530563b5ab1SAlexander V. Chernikov 	return (0);
1531563b5ab1SAlexander V. Chernikov }
1532563b5ab1SAlexander V. Chernikov 
1533563b5ab1SAlexander V. Chernikov /*
1534563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1535563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1536563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1537563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1538563b5ab1SAlexander V. Chernikov  *
1539563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1540563b5ab1SAlexander V. Chernikov  */
1541563b5ab1SAlexander V. Chernikov char *
1542563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1543563b5ab1SAlexander V. Chernikov {
1544563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1545563b5ab1SAlexander V. Chernikov 
1546563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
15476c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1548563b5ab1SAlexander V. Chernikov 
1549563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1550563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1551563b5ab1SAlexander V. Chernikov 
1552563b5ab1SAlexander V. Chernikov 	return (NULL);
1553563b5ab1SAlexander V. Chernikov }
1554563b5ab1SAlexander V. Chernikov 
15556c2997ffSAlexander V. Chernikov void
15566c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
15576c2997ffSAlexander V. Chernikov {
15586c2997ffSAlexander V. Chernikov 
15596c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
15606c2997ffSAlexander V. Chernikov }
15616c2997ffSAlexander V. Chernikov 
15626c2997ffSAlexander V. Chernikov int
15636c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
15646c2997ffSAlexander V. Chernikov {
15656c2997ffSAlexander V. Chernikov 	int c, i, l;
15666c2997ffSAlexander V. Chernikov 
15676c2997ffSAlexander V. Chernikov 	/*
15686c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
15696c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1570ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
15716c2997ffSAlexander V. Chernikov 	 */
15726c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
15736c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
15746c2997ffSAlexander V. Chernikov 		return (EINVAL);
15756c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
15766c2997ffSAlexander V. Chernikov 		c = tablename[i];
15776c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
15786c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
15796c2997ffSAlexander V. Chernikov 			continue;
15806c2997ffSAlexander V. Chernikov 		return (EINVAL);
15816c2997ffSAlexander V. Chernikov 	}
15826c2997ffSAlexander V. Chernikov 
1583ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1584ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1585ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1586ac35ff17SAlexander V. Chernikov 
15876c2997ffSAlexander V. Chernikov 	return (0);
15886c2997ffSAlexander V. Chernikov }
15896c2997ffSAlexander V. Chernikov 
1590