xref: /freebsd/sbin/ipfw/tables.c (revision 5f379342d2f2605c46c2e9644e92113bde590df8)
1f1220db8SAlexander V. Chernikov /*
2f1220db8SAlexander V. Chernikov  * Copyright (c) 2002-2003 Luigi Rizzo
3f1220db8SAlexander V. Chernikov  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4f1220db8SAlexander V. Chernikov  * Copyright (c) 1994 Ugen J.S.Antsilevich
5f1220db8SAlexander V. Chernikov  *
6f1220db8SAlexander V. Chernikov  * Idea and grammar partially left from:
7f1220db8SAlexander V. Chernikov  * Copyright (c) 1993 Daniel Boulet
8f1220db8SAlexander V. Chernikov  *
9f1220db8SAlexander V. Chernikov  * Redistribution and use in source forms, with and without modification,
10f1220db8SAlexander V. Chernikov  * are permitted provided that this entire comment appears intact.
11f1220db8SAlexander V. Chernikov  *
12f1220db8SAlexander V. Chernikov  * Redistribution in binary form may occur without any restrictions.
13f1220db8SAlexander V. Chernikov  * Obviously, it would be nice if you gave credit where credit is due
14f1220db8SAlexander V. Chernikov  * but requiring it would be too onerous.
15f1220db8SAlexander V. Chernikov  *
16f1220db8SAlexander V. Chernikov  * This software is provided ``AS IS'' without any warranties of any kind.
17f1220db8SAlexander V. Chernikov  *
18f1220db8SAlexander V. Chernikov  * in-kernel tables support
19f1220db8SAlexander V. Chernikov  *
20f1220db8SAlexander V. Chernikov  * $FreeBSD: projects/ipfw/sbin/ipfw/ipfw2.c 267467 2014-06-14 10:58:39Z melifaro $
21f1220db8SAlexander V. Chernikov  */
22f1220db8SAlexander V. Chernikov 
23f1220db8SAlexander V. Chernikov 
24f1220db8SAlexander V. Chernikov #include <sys/types.h>
25f1220db8SAlexander V. Chernikov #include <sys/param.h>
26f1220db8SAlexander V. Chernikov #include <sys/socket.h>
27f1220db8SAlexander V. Chernikov #include <sys/sysctl.h>
28f1220db8SAlexander V. Chernikov 
29f1220db8SAlexander V. Chernikov #include <ctype.h>
30f1220db8SAlexander V. Chernikov #include <err.h>
31f1220db8SAlexander V. Chernikov #include <errno.h>
32f1220db8SAlexander V. Chernikov #include <netdb.h>
33f1220db8SAlexander V. Chernikov #include <stddef.h>	/* offsetof */
34f1220db8SAlexander V. Chernikov #include <stdio.h>
35f1220db8SAlexander V. Chernikov #include <stdlib.h>
36f1220db8SAlexander V. Chernikov #include <string.h>
37f1220db8SAlexander V. Chernikov #include <sysexits.h>
38f1220db8SAlexander V. Chernikov 
39f1220db8SAlexander V. Chernikov #define IPFW_INTERNAL	/* Access to protected structures in ip_fw.h. */
40f1220db8SAlexander V. Chernikov 
41f1220db8SAlexander V. Chernikov #include <net/if.h>
42f1220db8SAlexander V. Chernikov #include <net/if_dl.h>
43f1220db8SAlexander V. Chernikov #include <net/route.h> /* def. of struct route */
44f1220db8SAlexander V. Chernikov #include <netinet/in.h>
45f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h>
46f1220db8SAlexander V. Chernikov #include <arpa/inet.h>
47f1220db8SAlexander V. Chernikov #include <alias.h>
48f1220db8SAlexander V. Chernikov 
49f1220db8SAlexander V. Chernikov #include "ipfw2.h"
50f1220db8SAlexander V. Chernikov 
51f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header);
52ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
53ac35ff17SAlexander V. Chernikov     int add, int update);
54ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh);
55ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh);
56ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
57ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
5881d3153dSAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
59ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
60f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
61ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
62ac35ff17SAlexander V. Chernikov     uint16_t uidx);
63f1220db8SAlexander V. Chernikov 
64f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
65f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
66f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
67f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
6881d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
69f1220db8SAlexander V. Chernikov 
70ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7181d3153dSAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
72ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
73ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
74ac35ff17SAlexander V. Chernikov 
75f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
76f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
77f1220db8SAlexander V. Chernikov 
78f1220db8SAlexander V. Chernikov #ifndef s6_addr32
79f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
80f1220db8SAlexander V. Chernikov #endif
81f1220db8SAlexander V. Chernikov 
82ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
83ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
84ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
85b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
86914bffb6SAlexander V. Chernikov       { "flow",		IPFW_TABLE_FLOW },
87ac35ff17SAlexander V. Chernikov       { NULL, 0 }
88ac35ff17SAlexander V. Chernikov };
89ac35ff17SAlexander V. Chernikov 
90ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
91ac35ff17SAlexander V. Chernikov       { "dscp",		IPFW_VTYPE_DSCP },
92ac35ff17SAlexander V. Chernikov       { "ip",		IPFW_VTYPE_IP },
93ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
94ac35ff17SAlexander V. Chernikov       { NULL, 0 }
95ac35ff17SAlexander V. Chernikov };
96ac35ff17SAlexander V. Chernikov 
97ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
98ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
99ac35ff17SAlexander V. Chernikov       { "create",	TOK_CREATE },
100ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
101ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
102ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
103ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
104ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
10581d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
106ac35ff17SAlexander V. Chernikov       { NULL, 0 }
107ac35ff17SAlexander V. Chernikov };
108ac35ff17SAlexander V. Chernikov 
109f1220db8SAlexander V. Chernikov static int
110f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
111f1220db8SAlexander V. Chernikov {
112f1220db8SAlexander V. Chernikov 	struct hostent *he;
113f1220db8SAlexander V. Chernikov 
114f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
115f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
116f1220db8SAlexander V. Chernikov 			return(-1);
117f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
118f1220db8SAlexander V. Chernikov 	}
119f1220db8SAlexander V. Chernikov 	return(0);
120f1220db8SAlexander V. Chernikov }
121f1220db8SAlexander V. Chernikov 
122f1220db8SAlexander V. Chernikov /*
123f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
124ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
125ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
126ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
127ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
128ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
129ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
130ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
131f1220db8SAlexander V. Chernikov  */
132f1220db8SAlexander V. Chernikov void
133f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
134f1220db8SAlexander V. Chernikov {
135ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
136ac35ff17SAlexander V. Chernikov 	int error, tcmd;
137ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
138ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
139f1220db8SAlexander V. Chernikov 	char *tablename;
140ac35ff17SAlexander V. Chernikov 	uint32_t set;
141f1220db8SAlexander V. Chernikov 
142ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
143ac35ff17SAlexander V. Chernikov 	is_all = 0;
144ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
145ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
146ac35ff17SAlexander V. Chernikov 	else
147ac35ff17SAlexander V. Chernikov 		set = 0;
148f1220db8SAlexander V. Chernikov 
149f1220db8SAlexander V. Chernikov 	ac--; av++;
1509d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
151f1220db8SAlexander V. Chernikov 	tablename = *av;
152f1220db8SAlexander V. Chernikov 
153ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
154ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
155ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
156ac35ff17SAlexander V. Chernikov 	} else {
157ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
158ac35ff17SAlexander V. Chernikov 			is_all = 1;
159ac35ff17SAlexander V. Chernikov 		else
160ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
161ac35ff17SAlexander V. Chernikov 	}
162ac35ff17SAlexander V. Chernikov 	ac--; av++;
1639d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
164ac35ff17SAlexander V. Chernikov 
165ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
166ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
167ac35ff17SAlexander V. Chernikov 
168ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
169ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
170ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
171ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
172ac35ff17SAlexander V. Chernikov 		break;
173ac35ff17SAlexander V. Chernikov 	default:
174ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
175ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
176ac35ff17SAlexander V. Chernikov 	}
177ac35ff17SAlexander V. Chernikov 
178ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
179ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
180ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
181f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
182f1220db8SAlexander V. Chernikov 		ac--; av++;
183ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
184ac35ff17SAlexander V. Chernikov 		break;
185ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
186f1220db8SAlexander V. Chernikov 		ac--; av++;
187ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
188ac35ff17SAlexander V. Chernikov 		break;
189ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
190ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
191ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
192ac35ff17SAlexander V. Chernikov 		break;
193ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
194f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
195ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
196f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
197f1220db8SAlexander V. Chernikov 				    tablename);
198f1220db8SAlexander V. Chernikov 		} else {
199ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
200f1220db8SAlexander V. Chernikov 			if (error != 0)
201f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
202f1220db8SAlexander V. Chernikov 		}
203ac35ff17SAlexander V. Chernikov 		break;
204ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
205f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
206ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
207f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
208f1220db8SAlexander V. Chernikov 			table_show_info(&i, NULL);
209f1220db8SAlexander V. Chernikov 		} else {
210f1220db8SAlexander V. Chernikov 			error = tables_foreach(table_show_info, NULL, 1);
211f1220db8SAlexander V. Chernikov 			if (error != 0)
212f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
213f1220db8SAlexander V. Chernikov 		}
214ac35ff17SAlexander V. Chernikov 		break;
215ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
216ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
217ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
218ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
219ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
220ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
221f1220db8SAlexander V. Chernikov 		} else {
222ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
223ac35ff17SAlexander V. Chernikov 			if (error != 0)
224ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
225f1220db8SAlexander V. Chernikov 		}
226ac35ff17SAlexander V. Chernikov 		break;
22781d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
22881d3153dSAlexander V. Chernikov 		ac--; av++;
22981d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
23081d3153dSAlexander V. Chernikov 		break;
231f1220db8SAlexander V. Chernikov 	}
232f1220db8SAlexander V. Chernikov }
233f1220db8SAlexander V. Chernikov 
234f1220db8SAlexander V. Chernikov static void
235ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
236f1220db8SAlexander V. Chernikov {
237f1220db8SAlexander V. Chernikov 
238563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
239f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
240f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
241ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
242f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
243f1220db8SAlexander V. Chernikov }
244f1220db8SAlexander V. Chernikov 
245f1220db8SAlexander V. Chernikov static void
246f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
247f1220db8SAlexander V. Chernikov {
248f1220db8SAlexander V. Chernikov 
249f1220db8SAlexander V. Chernikov 	oh->idx = 1;
25081d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
251ac35ff17SAlexander V. Chernikov }
252ac35ff17SAlexander V. Chernikov 
253ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
254ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE },
255ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
256ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
2574c0c07a5SAlexander V. Chernikov       { "limit",	TOK_LIMIT },
258ac35ff17SAlexander V. Chernikov       { NULL, 0 }
259ac35ff17SAlexander V. Chernikov };
260ac35ff17SAlexander V. Chernikov 
261914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
262914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
263914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
264914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
265914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
266914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
267914bffb6SAlexander V. Chernikov       { NULL, 0 }
268914bffb6SAlexander V. Chernikov };
269914bffb6SAlexander V. Chernikov 
270914bffb6SAlexander V. Chernikov int
271914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
272914bffb6SAlexander V. Chernikov {
273914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
274914bffb6SAlexander V. Chernikov 
275914bffb6SAlexander V. Chernikov 	/* Parse type options */
276914bffb6SAlexander V. Chernikov 	switch(ttype) {
277914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
278914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
279914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
280914bffb6SAlexander V. Chernikov 		    &fclear);
281914bffb6SAlexander V. Chernikov 		*tflags = fset;
282914bffb6SAlexander V. Chernikov 		break;
283914bffb6SAlexander V. Chernikov 	default:
284914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
285914bffb6SAlexander V. Chernikov 	}
286914bffb6SAlexander V. Chernikov 
287914bffb6SAlexander V. Chernikov 	return (0);
288914bffb6SAlexander V. Chernikov }
289914bffb6SAlexander V. Chernikov 
290914bffb6SAlexander V. Chernikov void
291914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
292914bffb6SAlexander V. Chernikov {
293914bffb6SAlexander V. Chernikov 	const char *tname;
294914bffb6SAlexander V. Chernikov 	int l;
295914bffb6SAlexander V. Chernikov 
296914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
297914bffb6SAlexander V. Chernikov 		tname = "unknown";
298914bffb6SAlexander V. Chernikov 
299914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
300914bffb6SAlexander V. Chernikov 	tbuf += l;
301914bffb6SAlexander V. Chernikov 	size -= l;
302914bffb6SAlexander V. Chernikov 
303914bffb6SAlexander V. Chernikov 	switch(type) {
304914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
305914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
306914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
307914bffb6SAlexander V. Chernikov 			l--;
308914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
309914bffb6SAlexander V. Chernikov 		}
310914bffb6SAlexander V. Chernikov 		break;
311914bffb6SAlexander V. Chernikov 	}
312914bffb6SAlexander V. Chernikov }
313914bffb6SAlexander V. Chernikov 
314ac35ff17SAlexander V. Chernikov /*
315ac35ff17SAlexander V. Chernikov  * Creates new table
316ac35ff17SAlexander V. Chernikov  *
317ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
318ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
319ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
320ac35ff17SAlexander V. Chernikov  *
321ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
322ac35ff17SAlexander V. Chernikov  */
323ac35ff17SAlexander V. Chernikov static void
324ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
325ac35ff17SAlexander V. Chernikov {
326ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
327ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
328ac35ff17SAlexander V. Chernikov 	size_t sz;
329914bffb6SAlexander V. Chernikov 	char *p;
330ac35ff17SAlexander V. Chernikov 	char tbuf[128];
331ac35ff17SAlexander V. Chernikov 
332ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
333ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
334ac35ff17SAlexander V. Chernikov 
335ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
336ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
337ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
338ac35ff17SAlexander V. Chernikov 
339ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
340ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
341ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
342ac35ff17SAlexander V. Chernikov 		ac--; av++;
343ac35ff17SAlexander V. Chernikov 
344ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
3454c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
3464c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
3474c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
3484c0c07a5SAlexander V. Chernikov 			ac--; av++;
3494c0c07a5SAlexander V. Chernikov 			break;
350ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
351ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
352914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
353914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
354914bffb6SAlexander V. Chernikov 				*p++ = '\0';
355ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
356914bffb6SAlexander V. Chernikov 			if (val == -1) {
357914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
358914bffb6SAlexander V. Chernikov 				    ", ");
359914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
360914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
361ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
362914bffb6SAlexander V. Chernikov 			}
363914bffb6SAlexander V. Chernikov 			xi.type = val;
364914bffb6SAlexander V. Chernikov 			if (p != NULL) {
365914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
366914bffb6SAlexander V. Chernikov 				if (error != 0)
367914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
368914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
369914bffb6SAlexander V. Chernikov 			}
370914bffb6SAlexander V. Chernikov 			ac--; av++;
371ac35ff17SAlexander V. Chernikov 			break;
372ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
373ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
374ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
375ac35ff17SAlexander V. Chernikov 			if (val != -1) {
376ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
377ac35ff17SAlexander V. Chernikov 				ac--; av++;
378ac35ff17SAlexander V. Chernikov 				break;
379ac35ff17SAlexander V. Chernikov 			}
380ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
381ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
382ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
383ac35ff17SAlexander V. Chernikov 			break;
384ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
385ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
386ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
387ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
388ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
389ac35ff17SAlexander V. Chernikov 			ac--; av++;
390ac35ff17SAlexander V. Chernikov 			break;
391ac35ff17SAlexander V. Chernikov 		}
392ac35ff17SAlexander V. Chernikov 	}
393ac35ff17SAlexander V. Chernikov 
394ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
395ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
396f1220db8SAlexander V. Chernikov }
397f1220db8SAlexander V. Chernikov 
398f1220db8SAlexander V. Chernikov /*
399ac35ff17SAlexander V. Chernikov  * Creates new table
400ac35ff17SAlexander V. Chernikov  *
401ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
402ac35ff17SAlexander V. Chernikov  *
403f1220db8SAlexander V. Chernikov  * Returns 0 on success.
404f1220db8SAlexander V. Chernikov  */
405f1220db8SAlexander V. Chernikov static int
406ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
407f1220db8SAlexander V. Chernikov {
408ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
409ac35ff17SAlexander V. Chernikov 	int error;
410f1220db8SAlexander V. Chernikov 
411ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
412ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
413ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
414ac35ff17SAlexander V. Chernikov 
415ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
416ac35ff17SAlexander V. Chernikov 
417ac35ff17SAlexander V. Chernikov 	return (error);
418ac35ff17SAlexander V. Chernikov }
419ac35ff17SAlexander V. Chernikov 
420ac35ff17SAlexander V. Chernikov /*
421ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
422ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
423ac35ff17SAlexander V. Chernikov  */
424ac35ff17SAlexander V. Chernikov static int
425ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
426ac35ff17SAlexander V. Chernikov {
427ac35ff17SAlexander V. Chernikov 
428ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
429f1220db8SAlexander V. Chernikov 		return (-1);
430f1220db8SAlexander V. Chernikov 
431f1220db8SAlexander V. Chernikov 	return (0);
432f1220db8SAlexander V. Chernikov }
433f1220db8SAlexander V. Chernikov 
434f1220db8SAlexander V. Chernikov /*
435ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
436f1220db8SAlexander V. Chernikov  * Returns 0 on success.
437f1220db8SAlexander V. Chernikov  */
438f1220db8SAlexander V. Chernikov static int
439ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
440f1220db8SAlexander V. Chernikov {
441f1220db8SAlexander V. Chernikov 
442ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
443f1220db8SAlexander V. Chernikov 		return (-1);
444f1220db8SAlexander V. Chernikov 
445f1220db8SAlexander V. Chernikov 	return (0);
446f1220db8SAlexander V. Chernikov }
447f1220db8SAlexander V. Chernikov 
448f1220db8SAlexander V. Chernikov /*
449ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
450f1220db8SAlexander V. Chernikov  * it inside @i.
451f1220db8SAlexander V. Chernikov  * Returns 0 on success.
452f1220db8SAlexander V. Chernikov  */
453f1220db8SAlexander V. Chernikov static int
454ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
455f1220db8SAlexander V. Chernikov {
456f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
457ac35ff17SAlexander V. Chernikov 	int error;
458f1220db8SAlexander V. Chernikov 	size_t sz;
459f1220db8SAlexander V. Chernikov 
460f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
461f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
462ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
463f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
464f1220db8SAlexander V. Chernikov 
465ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
466ac35ff17SAlexander V. Chernikov 		return (error);
467f1220db8SAlexander V. Chernikov 
468f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
469ac35ff17SAlexander V. Chernikov 		return (EINVAL);
470f1220db8SAlexander V. Chernikov 
471f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
472f1220db8SAlexander V. Chernikov 
473f1220db8SAlexander V. Chernikov 	return (0);
474f1220db8SAlexander V. Chernikov }
475f1220db8SAlexander V. Chernikov 
476*5f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
477*5f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
478*5f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
479*5f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
480*5f379342SAlexander V. Chernikov       { NULL, 0 }
481*5f379342SAlexander V. Chernikov };
482*5f379342SAlexander V. Chernikov 
483*5f379342SAlexander V. Chernikov struct ta_cldata {
484*5f379342SAlexander V. Chernikov 	uint8_t		taclass;
485*5f379342SAlexander V. Chernikov 	uint8_t		spare4;
486*5f379342SAlexander V. Chernikov 	uint16_t	itemsize;
487*5f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
488*5f379342SAlexander V. Chernikov 	uint32_t	size;
489*5f379342SAlexander V. Chernikov 	uint32_t	count;
490*5f379342SAlexander V. Chernikov };
491*5f379342SAlexander V. Chernikov 
492*5f379342SAlexander V. Chernikov /*
493*5f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
494*5f379342SAlexander V. Chernikov  */
495*5f379342SAlexander V. Chernikov static void
496*5f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
497*5f379342SAlexander V. Chernikov     const char *af, const char *taclass)
498*5f379342SAlexander V. Chernikov {
499*5f379342SAlexander V. Chernikov 
500*5f379342SAlexander V. Chernikov 	switch (d->taclass) {
501*5f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
502*5f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
503*5f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
504*5f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
505*5f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
506*5f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
507*5f379342SAlexander V. Chernikov 		else
508*5f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
509*5f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
510*5f379342SAlexander V. Chernikov 			    d->size, d->count,
511*5f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
512*5f379342SAlexander V. Chernikov 		break;
513*5f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
514*5f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
515*5f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
516*5f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
517*5f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
518*5f379342SAlexander V. Chernikov 		else
519*5f379342SAlexander V. Chernikov 			printf("  items: %u "
520*5f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
521*5f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
522*5f379342SAlexander V. Chernikov 		break;
523*5f379342SAlexander V. Chernikov 	default:
524*5f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
525*5f379342SAlexander V. Chernikov 	}
526*5f379342SAlexander V. Chernikov }
527*5f379342SAlexander V. Chernikov 
528f1220db8SAlexander V. Chernikov /*
529f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
530f1220db8SAlexander V. Chernikov  */
531f1220db8SAlexander V. Chernikov static int
532f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
533f1220db8SAlexander V. Chernikov {
534914bffb6SAlexander V. Chernikov 	const char *vtype;
535*5f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
536*5f379342SAlexander V. Chernikov 	int afdata, afitem;
537*5f379342SAlexander V. Chernikov 	struct ta_cldata d;
538914bffb6SAlexander V. Chernikov 	char ttype[64];
539f1220db8SAlexander V. Chernikov 
540914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
541ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
542ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
543ac35ff17SAlexander V. Chernikov 
544914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
545914bffb6SAlexander V. Chernikov 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
5469d099b4fSAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
5479d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
548f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
5494c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
5504c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
551f1220db8SAlexander V. Chernikov 
552*5f379342SAlexander V. Chernikov 	/* Print algo-specific info if any */
553*5f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
554*5f379342SAlexander V. Chernikov 		return (0);
555*5f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
556*5f379342SAlexander V. Chernikov 
557*5f379342SAlexander V. Chernikov 	afdata = 0;
558*5f379342SAlexander V. Chernikov 	afitem = 0;
559*5f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
560*5f379342SAlexander V. Chernikov 		afdata = 1;
561*5f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
562*5f379342SAlexander V. Chernikov 		afitem = 1;
563*5f379342SAlexander V. Chernikov 
564*5f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
565*5f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
566*5f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
567*5f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
568*5f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
569*5f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
570*5f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
571*5f379342SAlexander V. Chernikov 	else
572*5f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
573*5f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
574*5f379342SAlexander V. Chernikov 		vtype = "unknown";
575*5f379342SAlexander V. Chernikov 
576*5f379342SAlexander V. Chernikov 	if (afdata == 0) {
577*5f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
578*5f379342SAlexander V. Chernikov 	} else {
579*5f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
580*5f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
581*5f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
582*5f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
583*5f379342SAlexander V. Chernikov 			vtype = "unknown";
584*5f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
585*5f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
586*5f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
587*5f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
588*5f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
589*5f379342SAlexander V. Chernikov 	}
590*5f379342SAlexander V. Chernikov 
591f1220db8SAlexander V. Chernikov 	return (0);
592f1220db8SAlexander V. Chernikov }
593f1220db8SAlexander V. Chernikov 
594f1220db8SAlexander V. Chernikov 
595f1220db8SAlexander V. Chernikov /*
596f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
597f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
598f1220db8SAlexander V. Chernikov  */
599f1220db8SAlexander V. Chernikov 
600f1220db8SAlexander V. Chernikov static int
601f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
602f1220db8SAlexander V. Chernikov {
603f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
60481d3153dSAlexander V. Chernikov 	int error;
605f1220db8SAlexander V. Chernikov 
606ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
607f1220db8SAlexander V. Chernikov 		return (ENOMEM);
608f1220db8SAlexander V. Chernikov 
60981d3153dSAlexander V. Chernikov 	if ((error = table_get_list(i, oh)) != 0) {
61081d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
61181d3153dSAlexander V. Chernikov 		return (error);
61281d3153dSAlexander V. Chernikov 	}
61381d3153dSAlexander V. Chernikov 
614f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
615f1220db8SAlexander V. Chernikov 
616f1220db8SAlexander V. Chernikov 	free(oh);
617f1220db8SAlexander V. Chernikov 	return (0);
618f1220db8SAlexander V. Chernikov }
619f1220db8SAlexander V. Chernikov 
620f1220db8SAlexander V. Chernikov static int
621f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
622f1220db8SAlexander V. Chernikov {
623ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
624f1220db8SAlexander V. Chernikov 
625ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
626ac35ff17SAlexander V. Chernikov 
627ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
628ac35ff17SAlexander V. Chernikov 
629ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
630f1220db8SAlexander V. Chernikov }
631f1220db8SAlexander V. Chernikov 
632ac35ff17SAlexander V. Chernikov static int
633ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
634ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
635ac35ff17SAlexander V. Chernikov {
636db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
637db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
638ac35ff17SAlexander V. Chernikov 	int error;
639ac35ff17SAlexander V. Chernikov 
640ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
641ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
642ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
643ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
644ac35ff17SAlexander V. Chernikov 
645db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
646db785d31SAlexander V. Chernikov 	ctlv->count = 1;
647db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
648db785d31SAlexander V. Chernikov 
649db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
650db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
651ac35ff17SAlexander V. Chernikov 	if (update != 0)
65281d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
653ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
654ac35ff17SAlexander V. Chernikov 
655ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
656ac35ff17SAlexander V. Chernikov 
657ac35ff17SAlexander V. Chernikov 	return (error);
658ac35ff17SAlexander V. Chernikov }
659ac35ff17SAlexander V. Chernikov 
660ac35ff17SAlexander V. Chernikov static void
661ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
662ac35ff17SAlexander V. Chernikov {
663ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
66481d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
665ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
6664c0c07a5SAlexander V. Chernikov 	int cmd, error;
6674c0c07a5SAlexander V. Chernikov 	char *texterr, *etxt;
668ac35ff17SAlexander V. Chernikov 
669ac35ff17SAlexander V. Chernikov 	if (ac == 0)
670ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
671ac35ff17SAlexander V. Chernikov 
672ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
673ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
674ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
675ac35ff17SAlexander V. Chernikov 
67681d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
677db785d31SAlexander V. Chernikov 
678db785d31SAlexander V. Chernikov 	/*
679db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
680db785d31SAlexander V. Chernikov 	 */
681db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
682db785d31SAlexander V. Chernikov 		xi.type = type;
683db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
684db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
685db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
686db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
687db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
688db785d31SAlexander V. Chernikov 	}
689db785d31SAlexander V. Chernikov 
690ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
691ac35ff17SAlexander V. Chernikov 	ac--; av++;
692ac35ff17SAlexander V. Chernikov 
693ac35ff17SAlexander V. Chernikov 	if (add != 0) {
694ac35ff17SAlexander V. Chernikov 		if (ac > 0)
695ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
696ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
6974c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
698ac35ff17SAlexander V. Chernikov 	} else {
699ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
7004c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
701ac35ff17SAlexander V. Chernikov 	}
702ac35ff17SAlexander V. Chernikov 
7034c0c07a5SAlexander V. Chernikov 	if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0)
7044c0c07a5SAlexander V. Chernikov 		return;
7054c0c07a5SAlexander V. Chernikov 
7064c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
7074c0c07a5SAlexander V. Chernikov 	switch (error) {
7084c0c07a5SAlexander V. Chernikov 	case EEXIST:
7094c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
7104c0c07a5SAlexander V. Chernikov 		break;
7114c0c07a5SAlexander V. Chernikov 	case EFBIG:
7124c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
7134c0c07a5SAlexander V. Chernikov 		break;
7144c0c07a5SAlexander V. Chernikov 	case ESRCH:
7154c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
7164c0c07a5SAlexander V. Chernikov 		break;
7174c0c07a5SAlexander V. Chernikov 	case ENOENT:
7184c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
7194c0c07a5SAlexander V. Chernikov 		break;
7204c0c07a5SAlexander V. Chernikov 	default:
7214c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
7224c0c07a5SAlexander V. Chernikov 	}
7234c0c07a5SAlexander V. Chernikov 
7244c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
725ac35ff17SAlexander V. Chernikov }
726ac35ff17SAlexander V. Chernikov 
72781d3153dSAlexander V. Chernikov static int
72881d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
72981d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
73081d3153dSAlexander V. Chernikov {
73181d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
73281d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
73381d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
73481d3153dSAlexander V. Chernikov 	int error;
73581d3153dSAlexander V. Chernikov 	size_t sz;
73681d3153dSAlexander V. Chernikov 
73781d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
73881d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
73981d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
74081d3153dSAlexander V. Chernikov 
74181d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
74281d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
74381d3153dSAlexander V. Chernikov 	tent->idx = 1;
74481d3153dSAlexander V. Chernikov 
74581d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
74681d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
74781d3153dSAlexander V. Chernikov 
74881d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
74981d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
75081d3153dSAlexander V. Chernikov 		return (error);
75181d3153dSAlexander V. Chernikov 
75281d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
75381d3153dSAlexander V. Chernikov 		return (EINVAL);
75481d3153dSAlexander V. Chernikov 
75581d3153dSAlexander V. Chernikov 	*xtent = *tent;
75681d3153dSAlexander V. Chernikov 
75781d3153dSAlexander V. Chernikov 	return (0);
75881d3153dSAlexander V. Chernikov }
75981d3153dSAlexander V. Chernikov 
76081d3153dSAlexander V. Chernikov static void
76181d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
76281d3153dSAlexander V. Chernikov {
76381d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
76481d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
765914bffb6SAlexander V. Chernikov 	char key[64];
76681d3153dSAlexander V. Chernikov 	int error;
76781d3153dSAlexander V. Chernikov 
76881d3153dSAlexander V. Chernikov 	if (ac == 0)
76981d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
77081d3153dSAlexander V. Chernikov 
771914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
772914bffb6SAlexander V. Chernikov 
773914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
77481d3153dSAlexander V. Chernikov 
77581d3153dSAlexander V. Chernikov 	switch (error) {
77681d3153dSAlexander V. Chernikov 	case 0:
77781d3153dSAlexander V. Chernikov 		break;
77881d3153dSAlexander V. Chernikov 	case ESRCH:
77981d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
78081d3153dSAlexander V. Chernikov 	case ENOENT:
78181d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
78281d3153dSAlexander V. Chernikov 	case ENOTSUP:
78381d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
78481d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
78581d3153dSAlexander V. Chernikov 	default:
78681d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
78781d3153dSAlexander V. Chernikov 	}
78881d3153dSAlexander V. Chernikov 
78981d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
79081d3153dSAlexander V. Chernikov }
791ac35ff17SAlexander V. Chernikov 
792ac35ff17SAlexander V. Chernikov static void
793914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
794914bffb6SAlexander V. Chernikov     uint8_t tflags)
795ac35ff17SAlexander V. Chernikov {
796914bffb6SAlexander V. Chernikov 	char *p, *pp;
797ac35ff17SAlexander V. Chernikov 	int mask, af;
798914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
799914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
800ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
801914bffb6SAlexander V. Chernikov 	uint16_t port;
802914bffb6SAlexander V. Chernikov 	struct protoent *pent;
803914bffb6SAlexander V. Chernikov 	struct servent *sent;
804ac35ff17SAlexander V. Chernikov 	int masklen;
805ac35ff17SAlexander V. Chernikov 
806ac35ff17SAlexander V. Chernikov 	masklen = 0;
807ac35ff17SAlexander V. Chernikov 	af = 0;
808ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
809ac35ff17SAlexander V. Chernikov 
810ac35ff17SAlexander V. Chernikov 	switch (type) {
811ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
812ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
813ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
814ac35ff17SAlexander V. Chernikov 			*p = '\0';
815ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
816ac35ff17SAlexander V. Chernikov 		}
817ac35ff17SAlexander V. Chernikov 
818ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
819ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
820ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
821ac35ff17SAlexander V. Chernikov 				    p + 1);
822ac35ff17SAlexander V. Chernikov 
823ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
824ac35ff17SAlexander V. Chernikov 			af = AF_INET;
825ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
826ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
827ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
828ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
829ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
830ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
831ac35ff17SAlexander V. Chernikov 				    p + 1);
832ac35ff17SAlexander V. Chernikov 
833ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
834ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
835ac35ff17SAlexander V. Chernikov 		} else {
836ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
837ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
838ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
839ac35ff17SAlexander V. Chernikov 
840ac35ff17SAlexander V. Chernikov 			masklen = 32;
841ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
842ac35ff17SAlexander V. Chernikov 			af = AF_INET;
843ac35ff17SAlexander V. Chernikov 		}
844ac35ff17SAlexander V. Chernikov 		break;
845ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
846ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
847ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
848ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
849ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
850ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
851ac35ff17SAlexander V. Chernikov 		break;
852b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
853ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
854ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
855ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
856ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
857ac35ff17SAlexander V. Chernikov 
858ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
859ac35ff17SAlexander V. Chernikov 		*pkey = key;
860ac35ff17SAlexander V. Chernikov 		masklen = 32;
861ac35ff17SAlexander V. Chernikov 		break;
862914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
863914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
864914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
865914bffb6SAlexander V. Chernikov 		af = 0;
866914bffb6SAlexander V. Chernikov 
867914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
868914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
869914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
870914bffb6SAlexander V. Chernikov 				*p++ = '\0';
871914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
872914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
873914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
874914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
875914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
876914bffb6SAlexander V. Chernikov 				af = AF_INET;
877914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
878914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
879914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
880914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
881914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
882914bffb6SAlexander V. Chernikov 				af = AF_INET6;
883914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
884914bffb6SAlexander V. Chernikov 			}
885914bffb6SAlexander V. Chernikov 
886914bffb6SAlexander V. Chernikov 			arg = p;
887914bffb6SAlexander V. Chernikov 		}
888914bffb6SAlexander V. Chernikov 
889914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
890914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
891914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
892914bffb6SAlexander V. Chernikov 				*p++ = '\0';
893914bffb6SAlexander V. Chernikov 
894914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
895914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
896914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
897914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
898914bffb6SAlexander V. Chernikov 					    arg);
899914bffb6SAlexander V. Chernikov 				else
900914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
901914bffb6SAlexander V. Chernikov 			}
902914bffb6SAlexander V. Chernikov 
903914bffb6SAlexander V. Chernikov 			if (key > 255)
904914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
905914bffb6SAlexander V. Chernikov 
906914bffb6SAlexander V. Chernikov 			tfe->proto = key;
907914bffb6SAlexander V. Chernikov 
908914bffb6SAlexander V. Chernikov 			arg = p;
909914bffb6SAlexander V. Chernikov 		}
910914bffb6SAlexander V. Chernikov 
911914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
912914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
913914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
914914bffb6SAlexander V. Chernikov 				*p++ = '\0';
915914bffb6SAlexander V. Chernikov 
916914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
917914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
918914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
919914bffb6SAlexander V. Chernikov 					    arg);
920914bffb6SAlexander V. Chernikov 				else
921914bffb6SAlexander V. Chernikov 					key = sent->s_port;
922914bffb6SAlexander V. Chernikov 			}
923914bffb6SAlexander V. Chernikov 
924914bffb6SAlexander V. Chernikov 			tfe->sport = port;
925914bffb6SAlexander V. Chernikov 
926914bffb6SAlexander V. Chernikov 			arg = p;
927914bffb6SAlexander V. Chernikov 		}
928914bffb6SAlexander V. Chernikov 
929914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
930914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
931914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
932914bffb6SAlexander V. Chernikov 				*p++ = '\0';
933914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
934914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
935914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
936914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
937914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
938914bffb6SAlexander V. Chernikov 				af = AF_INET;
939914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
940914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
941914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
942914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
943914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
944914bffb6SAlexander V. Chernikov 				af = AF_INET6;
945914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
946914bffb6SAlexander V. Chernikov 			}
947914bffb6SAlexander V. Chernikov 
948914bffb6SAlexander V. Chernikov 			arg = p;
949914bffb6SAlexander V. Chernikov 		}
950914bffb6SAlexander V. Chernikov 
951914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
952914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
953914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
954914bffb6SAlexander V. Chernikov 				*p++ = '\0';
955914bffb6SAlexander V. Chernikov 
956914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
957914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
958914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
959914bffb6SAlexander V. Chernikov 					    arg);
960914bffb6SAlexander V. Chernikov 				else
961914bffb6SAlexander V. Chernikov 					key = sent->s_port;
962914bffb6SAlexander V. Chernikov 			}
963914bffb6SAlexander V. Chernikov 
964914bffb6SAlexander V. Chernikov 			tfe->dport = port;
965914bffb6SAlexander V. Chernikov 
966914bffb6SAlexander V. Chernikov 			arg = p;
967914bffb6SAlexander V. Chernikov 		}
968914bffb6SAlexander V. Chernikov 
969914bffb6SAlexander V. Chernikov 		tfe->af = af;
970914bffb6SAlexander V. Chernikov 
971914bffb6SAlexander V. Chernikov 		break;
972914bffb6SAlexander V. Chernikov 
973ac35ff17SAlexander V. Chernikov 	default:
974ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
975ac35ff17SAlexander V. Chernikov 	}
976ac35ff17SAlexander V. Chernikov 
977ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
978ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
979ac35ff17SAlexander V. Chernikov }
980ac35ff17SAlexander V. Chernikov 
981ac35ff17SAlexander V. Chernikov static void
982ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
98381d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
984ac35ff17SAlexander V. Chernikov {
985914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
986ac35ff17SAlexander V. Chernikov 	int error;
987db785d31SAlexander V. Chernikov 	char *del;
988ac35ff17SAlexander V. Chernikov 
989ac35ff17SAlexander V. Chernikov 	type = 0;
990914bffb6SAlexander V. Chernikov 	tflags = 0;
991ac35ff17SAlexander V. Chernikov 	vtype = 0;
992ac35ff17SAlexander V. Chernikov 
99381d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
99481d3153dSAlexander V. Chernikov 
99581d3153dSAlexander V. Chernikov 	if (error == 0) {
99681d3153dSAlexander V. Chernikov 		/* Table found. */
99781d3153dSAlexander V. Chernikov 		type = xi->type;
998914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
99981d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
100081d3153dSAlexander V. Chernikov 	} else {
100181d3153dSAlexander V. Chernikov 		if (error != ESRCH)
100281d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
100381d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
1004ac35ff17SAlexander V. Chernikov 		/*
100581d3153dSAlexander V. Chernikov 		 * Table does not exist.
100681d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
100781d3153dSAlexander V. Chernikov 		 * before failing.
1008ac35ff17SAlexander V. Chernikov 		 */
1009db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1010db785d31SAlexander V. Chernikov 			*del = '\0';
1011ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1012ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1013ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1014ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1015ac35ff17SAlexander V. Chernikov 			/*
101681d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
101781d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1018ac35ff17SAlexander V. Chernikov 			 */
101981d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
102081d3153dSAlexander V. Chernikov 		} else {
102181d3153dSAlexander V. Chernikov 			/* Inknown key */
102281d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1023db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
102481d3153dSAlexander V. Chernikov 		}
1025db785d31SAlexander V. Chernikov 		if (del != NULL)
1026db785d31SAlexander V. Chernikov 			*del = '/';
1027ac35ff17SAlexander V. Chernikov 	}
1028ac35ff17SAlexander V. Chernikov 
1029914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1030ac35ff17SAlexander V. Chernikov 
1031ac35ff17SAlexander V. Chernikov 	*ptype = type;
1032ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1033ac35ff17SAlexander V. Chernikov }
1034ac35ff17SAlexander V. Chernikov 
1035ac35ff17SAlexander V. Chernikov static void
1036ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1037ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1038ac35ff17SAlexander V. Chernikov {
1039ac35ff17SAlexander V. Chernikov 	int code;
1040ac35ff17SAlexander V. Chernikov 	char *p;
1041ac35ff17SAlexander V. Chernikov 
1042ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1043ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1044ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1045ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1046ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1047ac35ff17SAlexander V. Chernikov 		break;
1048ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1049ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1050ac35ff17SAlexander V. Chernikov 			break;
1051ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1052ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1053ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1054ac35ff17SAlexander V. Chernikov 		break;
1055ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1056ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1057ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1058ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1059ac35ff17SAlexander V. Chernikov 		} else {
1060ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1061ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1062ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1063ac35ff17SAlexander V. Chernikov 		}
1064ac35ff17SAlexander V. Chernikov 		tent->value = code;
1065ac35ff17SAlexander V. Chernikov 		break;
1066ac35ff17SAlexander V. Chernikov 	default:
1067ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1068ac35ff17SAlexander V. Chernikov 	}
1069ac35ff17SAlexander V. Chernikov }
1070f1220db8SAlexander V. Chernikov 
1071f1220db8SAlexander V. Chernikov /*
1072f1220db8SAlexander V. Chernikov  * Compare table names.
1073f1220db8SAlexander V. Chernikov  * Honor number comparison.
1074f1220db8SAlexander V. Chernikov  */
1075f1220db8SAlexander V. Chernikov static int
1076f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1077f1220db8SAlexander V. Chernikov {
1078f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1079f1220db8SAlexander V. Chernikov 
1080f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1081f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1082f1220db8SAlexander V. Chernikov 
108368394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1084f1220db8SAlexander V. Chernikov }
1085f1220db8SAlexander V. Chernikov 
1086f1220db8SAlexander V. Chernikov /*
1087f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1088f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1089f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1090f1220db8SAlexander V. Chernikov  */
1091f1220db8SAlexander V. Chernikov static int
1092f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1093f1220db8SAlexander V. Chernikov {
1094f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
1095f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1096f1220db8SAlexander V. Chernikov 	size_t sz;
1097f1220db8SAlexander V. Chernikov 	int i, error;
1098f1220db8SAlexander V. Chernikov 
1099f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
1100f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
1101f1220db8SAlexander V. Chernikov 
1102d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
1103f1220db8SAlexander V. Chernikov 		return (errno);
1104f1220db8SAlexander V. Chernikov 
1105f1220db8SAlexander V. Chernikov 	sz = req.size;
1106f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
1107f1220db8SAlexander V. Chernikov 		return (ENOMEM);
1108f1220db8SAlexander V. Chernikov 
1109f1220db8SAlexander V. Chernikov 	olh->size = sz;
1110d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
1111f1220db8SAlexander V. Chernikov 		free(olh);
1112f1220db8SAlexander V. Chernikov 		return (errno);
1113f1220db8SAlexander V. Chernikov 	}
1114f1220db8SAlexander V. Chernikov 
1115f1220db8SAlexander V. Chernikov 	if (sort != 0)
1116f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1117f1220db8SAlexander V. Chernikov 
1118f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
1119f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
1120f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
1121f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1122f1220db8SAlexander V. Chernikov 	}
1123f1220db8SAlexander V. Chernikov 
1124f1220db8SAlexander V. Chernikov 	free(olh);
1125f1220db8SAlexander V. Chernikov 
1126f1220db8SAlexander V. Chernikov 	return (0);
1127f1220db8SAlexander V. Chernikov }
1128f1220db8SAlexander V. Chernikov 
1129f1220db8SAlexander V. Chernikov /*
1130f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1131d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
1132d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
1133f1220db8SAlexander V. Chernikov  *
1134f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1135f1220db8SAlexander V. Chernikov  */
1136f1220db8SAlexander V. Chernikov static int
1137f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
1138f1220db8SAlexander V. Chernikov {
1139f1220db8SAlexander V. Chernikov 	size_t sz;
114081d3153dSAlexander V. Chernikov 	int error, c;
1141f1220db8SAlexander V. Chernikov 
114281d3153dSAlexander V. Chernikov 	sz = 0;
114381d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
1144f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
114581d3153dSAlexander V. Chernikov 		if (sz < i->size)
1146f1220db8SAlexander V. Chernikov 			sz = i->size;
1147f1220db8SAlexander V. Chernikov 
1148d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
114981d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1150d3a4f924SAlexander V. Chernikov 
115181d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
1152f1220db8SAlexander V. Chernikov 			return (errno);
115381d3153dSAlexander V. Chernikov 	}
1154f1220db8SAlexander V. Chernikov 
115581d3153dSAlexander V. Chernikov 	return (ENOMEM);
1156f1220db8SAlexander V. Chernikov }
1157f1220db8SAlexander V. Chernikov 
1158f1220db8SAlexander V. Chernikov /*
1159f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1160f1220db8SAlexander V. Chernikov  */
1161f1220db8SAlexander V. Chernikov static void
1162f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1163f1220db8SAlexander V. Chernikov {
116481d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
116581d3153dSAlexander V. Chernikov 	uint32_t count;
1166f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1167f1220db8SAlexander V. Chernikov 
1168f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
116981d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1170f1220db8SAlexander V. Chernikov 
1171f1220db8SAlexander V. Chernikov 	if (need_header)
1172f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1173f1220db8SAlexander V. Chernikov 
1174f1220db8SAlexander V. Chernikov 	count = i->count;
1175f1220db8SAlexander V. Chernikov 	while (count > 0) {
117681d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
117781d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
117881d3153dSAlexander V. Chernikov 		count--;
117981d3153dSAlexander V. Chernikov 	}
118081d3153dSAlexander V. Chernikov }
118181d3153dSAlexander V. Chernikov 
118281d3153dSAlexander V. Chernikov static void
118381d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
118481d3153dSAlexander V. Chernikov {
1185914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1186914bffb6SAlexander V. Chernikov 	void *paddr;
118781d3153dSAlexander V. Chernikov 	uint32_t tval;
1188914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
118981d3153dSAlexander V. Chernikov 
119081d3153dSAlexander V. Chernikov 	tval = tent->value;
119181d3153dSAlexander V. Chernikov 
1192914bffb6SAlexander V. Chernikov 	if (co.do_value_as_ip) {
1193914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1194914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1195914bffb6SAlexander V. Chernikov 	} else
1196914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1197914bffb6SAlexander V. Chernikov 
1198f1220db8SAlexander V. Chernikov 	switch (i->type) {
1199f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1200f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
120181d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1202914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1203f1220db8SAlexander V. Chernikov 		break;
1204f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1205f1220db8SAlexander V. Chernikov 		/* Interface names */
1206914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1207b23d5de9SAlexander V. Chernikov 		break;
1208b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1209b23d5de9SAlexander V. Chernikov 		/* numbers */
1210914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1211b23d5de9SAlexander V. Chernikov 		break;
1212914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1213914bffb6SAlexander V. Chernikov 		/* flows */
1214914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1215914bffb6SAlexander V. Chernikov 		comma = "";
1216914bffb6SAlexander V. Chernikov 
1217914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1218914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1219914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1220914bffb6SAlexander V. Chernikov 			else
1221914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1222914bffb6SAlexander V. Chernikov 
1223914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1224914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1225914bffb6SAlexander V. Chernikov 			comma = ",";
1226914bffb6SAlexander V. Chernikov 		}
1227914bffb6SAlexander V. Chernikov 
1228914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1229914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1230914bffb6SAlexander V. Chernikov 			comma = ",";
1231914bffb6SAlexander V. Chernikov 		}
1232914bffb6SAlexander V. Chernikov 
1233914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1234914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1235914bffb6SAlexander V. Chernikov 			comma = ",";
1236914bffb6SAlexander V. Chernikov 		}
1237914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1238914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1239914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1240914bffb6SAlexander V. Chernikov 			else
1241914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1242914bffb6SAlexander V. Chernikov 
1243914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1244914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1245914bffb6SAlexander V. Chernikov 			comma = ",";
1246914bffb6SAlexander V. Chernikov 		}
1247914bffb6SAlexander V. Chernikov 
1248914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1249914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1250914bffb6SAlexander V. Chernikov 			comma = ",";
1251914bffb6SAlexander V. Chernikov 		}
1252914bffb6SAlexander V. Chernikov 
1253914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1254f1220db8SAlexander V. Chernikov 	}
1255f1220db8SAlexander V. Chernikov }
1256f1220db8SAlexander V. Chernikov 
12579d099b4fSAlexander V. Chernikov static int
12589d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
12599d099b4fSAlexander V. Chernikov {
12609d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
12619d099b4fSAlexander V. Chernikov 	size_t sz;
12629d099b4fSAlexander V. Chernikov 	int error;
12639d099b4fSAlexander V. Chernikov 
12649d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
12659d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
12669d099b4fSAlexander V. Chernikov 
12679d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
12689d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
12699d099b4fSAlexander V. Chernikov 		return (error);
12709d099b4fSAlexander V. Chernikov 
12719d099b4fSAlexander V. Chernikov 	sz = req.size;
12729d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
12739d099b4fSAlexander V. Chernikov 		return (ENOMEM);
12749d099b4fSAlexander V. Chernikov 
12759d099b4fSAlexander V. Chernikov 	olh->size = sz;
12769d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
12779d099b4fSAlexander V. Chernikov 		free(olh);
12789d099b4fSAlexander V. Chernikov 		return (error);
12799d099b4fSAlexander V. Chernikov 	}
12809d099b4fSAlexander V. Chernikov 
12819d099b4fSAlexander V. Chernikov 	*polh = olh;
12829d099b4fSAlexander V. Chernikov 	return (0);
12839d099b4fSAlexander V. Chernikov }
12849d099b4fSAlexander V. Chernikov 
12859d099b4fSAlexander V. Chernikov void
12869d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
12879d099b4fSAlexander V. Chernikov {
12889d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
12899d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
12909d099b4fSAlexander V. Chernikov 	int error, i;
12919d099b4fSAlexander V. Chernikov 	const char *atype;
12929d099b4fSAlexander V. Chernikov 
12939d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
12949d099b4fSAlexander V. Chernikov 	if (error != 0)
12959d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
12969d099b4fSAlexander V. Chernikov 
12979d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
12989d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
12999d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
13009d099b4fSAlexander V. Chernikov 			atype = "unknown";
13018ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
13028ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
13039d099b4fSAlexander V. Chernikov 
13049d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
13059d099b4fSAlexander V. Chernikov 	}
13069d099b4fSAlexander V. Chernikov 
13079d099b4fSAlexander V. Chernikov 	free(olh);
13089d099b4fSAlexander V. Chernikov }
13099d099b4fSAlexander V. Chernikov 
13106c2997ffSAlexander V. Chernikov int
13116c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
13126c2997ffSAlexander V. Chernikov {
13136c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
13146c2997ffSAlexander V. Chernikov 
13156c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
13166c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
13176c2997ffSAlexander V. Chernikov 
13186c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
13196c2997ffSAlexander V. Chernikov 		return (-1);
13206c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
13216c2997ffSAlexander V. Chernikov 		return (1);
13226c2997ffSAlexander V. Chernikov 
13236c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
13246c2997ffSAlexander V. Chernikov 		return (-1);
13256c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
13266c2997ffSAlexander V. Chernikov 		return (1);
13276c2997ffSAlexander V. Chernikov 
13286c2997ffSAlexander V. Chernikov 	return (0);
13296c2997ffSAlexander V. Chernikov }
1330563b5ab1SAlexander V. Chernikov 
1331563b5ab1SAlexander V. Chernikov int
13326c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1333563b5ab1SAlexander V. Chernikov {
1334563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1335563b5ab1SAlexander V. Chernikov 	uint16_t key;
1336563b5ab1SAlexander V. Chernikov 
1337563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1338563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1339563b5ab1SAlexander V. Chernikov 
1340563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1341563b5ab1SAlexander V. Chernikov 		return (-1);
1342563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1343563b5ab1SAlexander V. Chernikov 		return (1);
1344563b5ab1SAlexander V. Chernikov 
1345563b5ab1SAlexander V. Chernikov 	return (0);
1346563b5ab1SAlexander V. Chernikov }
1347563b5ab1SAlexander V. Chernikov 
1348563b5ab1SAlexander V. Chernikov /*
1349563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1350563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1351563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1352563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1353563b5ab1SAlexander V. Chernikov  *
1354563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1355563b5ab1SAlexander V. Chernikov  */
1356563b5ab1SAlexander V. Chernikov char *
1357563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1358563b5ab1SAlexander V. Chernikov {
1359563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1360563b5ab1SAlexander V. Chernikov 
1361563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
13626c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1363563b5ab1SAlexander V. Chernikov 
1364563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1365563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1366563b5ab1SAlexander V. Chernikov 
1367563b5ab1SAlexander V. Chernikov 	return (NULL);
1368563b5ab1SAlexander V. Chernikov }
1369563b5ab1SAlexander V. Chernikov 
13706c2997ffSAlexander V. Chernikov void
13716c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
13726c2997ffSAlexander V. Chernikov {
13736c2997ffSAlexander V. Chernikov 
13746c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
13756c2997ffSAlexander V. Chernikov }
13766c2997ffSAlexander V. Chernikov 
13776c2997ffSAlexander V. Chernikov int
13786c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
13796c2997ffSAlexander V. Chernikov {
13806c2997ffSAlexander V. Chernikov 	int c, i, l;
13816c2997ffSAlexander V. Chernikov 
13826c2997ffSAlexander V. Chernikov 	/*
13836c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
13846c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1385ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
13866c2997ffSAlexander V. Chernikov 	 */
13876c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
13886c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
13896c2997ffSAlexander V. Chernikov 		return (EINVAL);
13906c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
13916c2997ffSAlexander V. Chernikov 		c = tablename[i];
13926c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
13936c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
13946c2997ffSAlexander V. Chernikov 			continue;
13956c2997ffSAlexander V. Chernikov 		return (EINVAL);
13966c2997ffSAlexander V. Chernikov 	}
13976c2997ffSAlexander V. Chernikov 
1398ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1399ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1400ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1401ac35ff17SAlexander V. Chernikov 
14026c2997ffSAlexander V. Chernikov 	return (0);
14036c2997ffSAlexander V. Chernikov }
14046c2997ffSAlexander V. Chernikov 
1405