xref: /freebsd/sbin/ipfw/tables.c (revision 3a845e1076df15bad3cd681d5b92225833b7ad25)
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[],
53*3a845e10SAlexander V. Chernikov     int add, int quiet, int update, int atomic);
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);
70720ee730SAlexander 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 },
117*3a845e10SAlexander V. Chernikov       { "atomic",	TOK_ATOMIC },
118ac35ff17SAlexander V. Chernikov       { NULL, 0 }
119ac35ff17SAlexander V. Chernikov };
120ac35ff17SAlexander V. Chernikov 
121f1220db8SAlexander V. Chernikov static int
122f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
123f1220db8SAlexander V. Chernikov {
124f1220db8SAlexander V. Chernikov 	struct hostent *he;
125f1220db8SAlexander V. Chernikov 
126f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
127f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
128f1220db8SAlexander V. Chernikov 			return(-1);
129f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
130f1220db8SAlexander V. Chernikov 	}
131f1220db8SAlexander V. Chernikov 	return(0);
132f1220db8SAlexander V. Chernikov }
133f1220db8SAlexander V. Chernikov 
134f1220db8SAlexander V. Chernikov /*
135f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
136ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
137ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
138ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
139ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
140ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
141ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
142ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
143f1220db8SAlexander V. Chernikov  */
144f1220db8SAlexander V. Chernikov void
145f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
146f1220db8SAlexander V. Chernikov {
147ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
148*3a845e10SAlexander V. Chernikov 	int atomic, error, tcmd;
149ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
150ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
151f1220db8SAlexander V. Chernikov 	char *tablename;
152ac35ff17SAlexander V. Chernikov 	uint32_t set;
153358b9d09SAlexander V. Chernikov 	void *arg;
154f1220db8SAlexander V. Chernikov 
155ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
156ac35ff17SAlexander V. Chernikov 	is_all = 0;
157ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
158ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
159ac35ff17SAlexander V. Chernikov 	else
160ac35ff17SAlexander V. Chernikov 		set = 0;
161f1220db8SAlexander V. Chernikov 
162f1220db8SAlexander V. Chernikov 	ac--; av++;
1639d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
164f1220db8SAlexander V. Chernikov 	tablename = *av;
165f1220db8SAlexander V. Chernikov 
166ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
167ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
168ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
169ac35ff17SAlexander V. Chernikov 	} else {
170ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
171ac35ff17SAlexander V. Chernikov 			is_all = 1;
172ac35ff17SAlexander V. Chernikov 		else
173ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
174ac35ff17SAlexander V. Chernikov 	}
175ac35ff17SAlexander V. Chernikov 	ac--; av++;
1769d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
177ac35ff17SAlexander V. Chernikov 
178ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
179ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
180*3a845e10SAlexander V. Chernikov 	/* Check if atomic operation was requested */
181*3a845e10SAlexander V. Chernikov 	atomic = 0;
182*3a845e10SAlexander V. Chernikov 	if (tcmd == TOK_ATOMIC) {
183*3a845e10SAlexander V. Chernikov 		ac--; av++;
184*3a845e10SAlexander V. Chernikov 		NEED1("atomic needs command");
185*3a845e10SAlexander V. Chernikov 		if ((tcmd = match_token(tablecmds, *av)) == -1)
186*3a845e10SAlexander V. Chernikov 			errx(EX_USAGE, "invalid table command %s", *av);
187*3a845e10SAlexander V. Chernikov 		switch (tcmd) {
188*3a845e10SAlexander V. Chernikov 		case TOK_ADD:
189*3a845e10SAlexander V. Chernikov 			break;
190*3a845e10SAlexander V. Chernikov 		default:
191*3a845e10SAlexander V. Chernikov 			errx(EX_USAGE, "atomic is not compatible with %s", *av);
192*3a845e10SAlexander V. Chernikov 		}
193*3a845e10SAlexander V. Chernikov 		atomic = 1;
194*3a845e10SAlexander V. Chernikov 	}
195ac35ff17SAlexander V. Chernikov 
196ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
197ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
198ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
199358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
200ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
201ac35ff17SAlexander V. Chernikov 		break;
202ac35ff17SAlexander V. Chernikov 	default:
203ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
204ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
205ac35ff17SAlexander V. Chernikov 	}
206ac35ff17SAlexander V. Chernikov 
207ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
208ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
209ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
210f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
211f1220db8SAlexander V. Chernikov 		ac--; av++;
212*3a845e10SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet,
213*3a845e10SAlexander V. Chernikov 		    co.do_quiet, atomic);
214ac35ff17SAlexander V. Chernikov 		break;
215ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
216f1220db8SAlexander V. Chernikov 		ac--; av++;
217ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
218ac35ff17SAlexander V. Chernikov 		break;
219adf3b2b9SAlexander V. Chernikov 	case TOK_MODIFY:
220adf3b2b9SAlexander V. Chernikov 		ac--; av++;
221adf3b2b9SAlexander V. Chernikov 		table_modify(&oh, ac, av);
222adf3b2b9SAlexander V. Chernikov 		break;
223ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
224ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
225ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
226ac35ff17SAlexander V. Chernikov 		break;
227ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
228f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
229ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
230f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
231f1220db8SAlexander V. Chernikov 				    tablename);
232f1220db8SAlexander V. Chernikov 		} else {
233ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
234f1220db8SAlexander V. Chernikov 			if (error != 0)
235f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
236f1220db8SAlexander V. Chernikov 		}
237ac35ff17SAlexander V. Chernikov 		break;
23846d52008SAlexander V. Chernikov 	case TOK_SWAP:
23946d52008SAlexander V. Chernikov 		ac--; av++;
24046d52008SAlexander V. Chernikov 		NEED1("second table name required");
24146d52008SAlexander V. Chernikov 		table_swap(&oh, *av);
24246d52008SAlexander V. Chernikov 		break;
243358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
244ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
245358b9d09SAlexander V. Chernikov 		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
246f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
247ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
248f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
249358b9d09SAlexander V. Chernikov 			table_show_info(&i, arg);
250f1220db8SAlexander V. Chernikov 		} else {
251358b9d09SAlexander V. Chernikov 			error = tables_foreach(table_show_info, arg, 1);
252f1220db8SAlexander V. Chernikov 			if (error != 0)
253f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
254f1220db8SAlexander V. Chernikov 		}
255ac35ff17SAlexander V. Chernikov 		break;
256ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
257ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
258ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
259ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
260ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
261ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
262f1220db8SAlexander V. Chernikov 		} else {
263ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
264ac35ff17SAlexander V. Chernikov 			if (error != 0)
265ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
266f1220db8SAlexander V. Chernikov 		}
267ac35ff17SAlexander V. Chernikov 		break;
26881d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
26981d3153dSAlexander V. Chernikov 		ac--; av++;
27081d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
27181d3153dSAlexander V. Chernikov 		break;
272f1220db8SAlexander V. Chernikov 	}
273f1220db8SAlexander V. Chernikov }
274f1220db8SAlexander V. Chernikov 
275f1220db8SAlexander V. Chernikov static void
276ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
277f1220db8SAlexander V. Chernikov {
278f1220db8SAlexander V. Chernikov 
279563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
280f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
281f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
282ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
283f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
284f1220db8SAlexander V. Chernikov }
285f1220db8SAlexander V. Chernikov 
286f1220db8SAlexander V. Chernikov static void
287f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
288f1220db8SAlexander V. Chernikov {
289f1220db8SAlexander V. Chernikov 
290f1220db8SAlexander V. Chernikov 	oh->idx = 1;
29181d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
292ac35ff17SAlexander V. Chernikov }
293ac35ff17SAlexander V. Chernikov 
294ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
295ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE },
296adf3b2b9SAlexander V. Chernikov       { "ftype",	TOK_FTYPE },
297ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
298ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
2994c0c07a5SAlexander V. Chernikov       { "limit",	TOK_LIMIT },
300ac35ff17SAlexander V. Chernikov       { NULL, 0 }
301ac35ff17SAlexander V. Chernikov };
302ac35ff17SAlexander V. Chernikov 
303914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
304914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
305914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
306914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
307914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
308914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
309914bffb6SAlexander V. Chernikov       { NULL, 0 }
310914bffb6SAlexander V. Chernikov };
311914bffb6SAlexander V. Chernikov 
312914bffb6SAlexander V. Chernikov int
313914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
314914bffb6SAlexander V. Chernikov {
315914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
316914bffb6SAlexander V. Chernikov 
317914bffb6SAlexander V. Chernikov 	/* Parse type options */
318914bffb6SAlexander V. Chernikov 	switch(ttype) {
319914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
320914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
321914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
322914bffb6SAlexander V. Chernikov 		    &fclear);
323914bffb6SAlexander V. Chernikov 		*tflags = fset;
324914bffb6SAlexander V. Chernikov 		break;
325914bffb6SAlexander V. Chernikov 	default:
326914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
327914bffb6SAlexander V. Chernikov 	}
328914bffb6SAlexander V. Chernikov 
329914bffb6SAlexander V. Chernikov 	return (0);
330914bffb6SAlexander V. Chernikov }
331914bffb6SAlexander V. Chernikov 
332914bffb6SAlexander V. Chernikov void
333914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
334914bffb6SAlexander V. Chernikov {
335914bffb6SAlexander V. Chernikov 	const char *tname;
336914bffb6SAlexander V. Chernikov 	int l;
337914bffb6SAlexander V. Chernikov 
338914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
339914bffb6SAlexander V. Chernikov 		tname = "unknown";
340914bffb6SAlexander V. Chernikov 
341914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
342914bffb6SAlexander V. Chernikov 	tbuf += l;
343914bffb6SAlexander V. Chernikov 	size -= l;
344914bffb6SAlexander V. Chernikov 
345914bffb6SAlexander V. Chernikov 	switch(type) {
346914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
347914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
348914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
349914bffb6SAlexander V. Chernikov 			l--;
350914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
351914bffb6SAlexander V. Chernikov 		}
352914bffb6SAlexander V. Chernikov 		break;
353914bffb6SAlexander V. Chernikov 	}
354914bffb6SAlexander V. Chernikov }
355914bffb6SAlexander V. Chernikov 
356ac35ff17SAlexander V. Chernikov /*
357ac35ff17SAlexander V. Chernikov  * Creates new table
358ac35ff17SAlexander V. Chernikov  *
359ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
360ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
361ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
362ac35ff17SAlexander V. Chernikov  */
363ac35ff17SAlexander V. Chernikov static void
364ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
365ac35ff17SAlexander V. Chernikov {
366ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
367ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
368ac35ff17SAlexander V. Chernikov 	size_t sz;
369914bffb6SAlexander V. Chernikov 	char *p;
370ac35ff17SAlexander V. Chernikov 	char tbuf[128];
371ac35ff17SAlexander V. Chernikov 
372ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
373ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
374ac35ff17SAlexander V. Chernikov 
375ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
376ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
377ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
378ac35ff17SAlexander V. Chernikov 
379ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
380ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
381ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
382ac35ff17SAlexander V. Chernikov 		ac--; av++;
383ac35ff17SAlexander V. Chernikov 
384ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
3854c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
3864c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
3874c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
3884c0c07a5SAlexander V. Chernikov 			ac--; av++;
3894c0c07a5SAlexander V. Chernikov 			break;
390ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
391ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
392914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
393914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
394914bffb6SAlexander V. Chernikov 				*p++ = '\0';
395ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
396914bffb6SAlexander V. Chernikov 			if (val == -1) {
397914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
398914bffb6SAlexander V. Chernikov 				    ", ");
399914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
400914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
401ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
402914bffb6SAlexander V. Chernikov 			}
403914bffb6SAlexander V. Chernikov 			xi.type = val;
404914bffb6SAlexander V. Chernikov 			if (p != NULL) {
405914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
406914bffb6SAlexander V. Chernikov 				if (error != 0)
407914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
408914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
409914bffb6SAlexander V. Chernikov 			}
410914bffb6SAlexander V. Chernikov 			ac--; av++;
411ac35ff17SAlexander V. Chernikov 			break;
412ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
413ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
414ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
415ac35ff17SAlexander V. Chernikov 			if (val != -1) {
416ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
417ac35ff17SAlexander V. Chernikov 				ac--; av++;
418ac35ff17SAlexander V. Chernikov 				break;
419ac35ff17SAlexander V. Chernikov 			}
420ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
421ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
422ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
423ac35ff17SAlexander V. Chernikov 			break;
424adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
425adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
426adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
427adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
428adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
429adf3b2b9SAlexander V. Chernikov 				ac--; av++;
430adf3b2b9SAlexander V. Chernikov 				break;
431adf3b2b9SAlexander V. Chernikov 			}
432adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
433adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown format type: %s. Supported: %s",
434adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
435adf3b2b9SAlexander V. Chernikov 			break;
436ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
437ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
438ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
439ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
440ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
441ac35ff17SAlexander V. Chernikov 			ac--; av++;
442ac35ff17SAlexander V. Chernikov 			break;
443ac35ff17SAlexander V. Chernikov 		}
444ac35ff17SAlexander V. Chernikov 	}
445ac35ff17SAlexander V. Chernikov 
446ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
447ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
448f1220db8SAlexander V. Chernikov }
449f1220db8SAlexander V. Chernikov 
450f1220db8SAlexander V. Chernikov /*
451ac35ff17SAlexander V. Chernikov  * Creates new table
452ac35ff17SAlexander V. Chernikov  *
453ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
454ac35ff17SAlexander V. Chernikov  *
455f1220db8SAlexander V. Chernikov  * Returns 0 on success.
456f1220db8SAlexander V. Chernikov  */
457f1220db8SAlexander V. Chernikov static int
458ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
459f1220db8SAlexander V. Chernikov {
460ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
461ac35ff17SAlexander V. Chernikov 	int error;
462f1220db8SAlexander V. Chernikov 
463ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
464ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
465ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
466ac35ff17SAlexander V. Chernikov 
467ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
468ac35ff17SAlexander V. Chernikov 
469ac35ff17SAlexander V. Chernikov 	return (error);
470ac35ff17SAlexander V. Chernikov }
471ac35ff17SAlexander V. Chernikov 
472ac35ff17SAlexander V. Chernikov /*
473adf3b2b9SAlexander V. Chernikov  * Modifies existing table
474adf3b2b9SAlexander V. Chernikov  *
475adf3b2b9SAlexander V. Chernikov  * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
476adf3b2b9SAlexander V. Chernikov  */
477adf3b2b9SAlexander V. Chernikov static void
478adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[])
479adf3b2b9SAlexander V. Chernikov {
480adf3b2b9SAlexander V. Chernikov 	ipfw_xtable_info xi;
481adf3b2b9SAlexander V. Chernikov 	int error, tcmd, val;
482adf3b2b9SAlexander V. Chernikov 	size_t sz;
483adf3b2b9SAlexander V. Chernikov 	char tbuf[128];
484adf3b2b9SAlexander V. Chernikov 
485adf3b2b9SAlexander V. Chernikov 	sz = sizeof(tbuf);
486adf3b2b9SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
487adf3b2b9SAlexander V. Chernikov 
488adf3b2b9SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
489adf3b2b9SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
490adf3b2b9SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
491adf3b2b9SAlexander V. Chernikov 
492adf3b2b9SAlexander V. Chernikov 	while (ac > 0) {
493adf3b2b9SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
494adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
495adf3b2b9SAlexander V. Chernikov 		ac--; av++;
496adf3b2b9SAlexander V. Chernikov 
497adf3b2b9SAlexander V. Chernikov 		switch (tcmd) {
498adf3b2b9SAlexander V. Chernikov 		case TOK_LIMIT:
499adf3b2b9SAlexander V. Chernikov 			NEED1("limit value required");
500adf3b2b9SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
501adf3b2b9SAlexander V. Chernikov 			xi.mflags |= IPFW_TMFLAGS_LIMIT;
502adf3b2b9SAlexander V. Chernikov 			ac--; av++;
503adf3b2b9SAlexander V. Chernikov 			break;
504adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
505adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
506adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
507adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
508adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
509adf3b2b9SAlexander V. Chernikov 				xi.mflags |= IPFW_TMFLAGS_FTYPE;
510adf3b2b9SAlexander V. Chernikov 				ac--; av++;
511adf3b2b9SAlexander V. Chernikov 				break;
512adf3b2b9SAlexander V. Chernikov 			}
513adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
514adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
515adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
516adf3b2b9SAlexander V. Chernikov 			break;
517adf3b2b9SAlexander V. Chernikov 		}
518adf3b2b9SAlexander V. Chernikov 	}
519adf3b2b9SAlexander V. Chernikov 
520adf3b2b9SAlexander V. Chernikov 	if ((error = table_do_modify(oh, &xi)) != 0)
521adf3b2b9SAlexander V. Chernikov 		err(EX_OSERR, "Table modification failed");
522adf3b2b9SAlexander V. Chernikov }
523adf3b2b9SAlexander V. Chernikov 
524adf3b2b9SAlexander V. Chernikov /*
525adf3b2b9SAlexander V. Chernikov  * Modifies existing table.
526adf3b2b9SAlexander V. Chernikov  *
527adf3b2b9SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
528adf3b2b9SAlexander V. Chernikov  *
529adf3b2b9SAlexander V. Chernikov  * Returns 0 on success.
530adf3b2b9SAlexander V. Chernikov  */
531adf3b2b9SAlexander V. Chernikov static int
532adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
533adf3b2b9SAlexander V. Chernikov {
534adf3b2b9SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
535adf3b2b9SAlexander V. Chernikov 	int error;
536adf3b2b9SAlexander V. Chernikov 
537adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
538adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
539adf3b2b9SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
540adf3b2b9SAlexander V. Chernikov 
541adf3b2b9SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
542adf3b2b9SAlexander V. Chernikov 
543adf3b2b9SAlexander V. Chernikov 	return (error);
544adf3b2b9SAlexander V. Chernikov }
545adf3b2b9SAlexander V. Chernikov /*
546ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
547ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
548ac35ff17SAlexander V. Chernikov  */
549ac35ff17SAlexander V. Chernikov static int
550ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
551ac35ff17SAlexander V. Chernikov {
552ac35ff17SAlexander V. Chernikov 
553ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
554f1220db8SAlexander V. Chernikov 		return (-1);
555f1220db8SAlexander V. Chernikov 
556f1220db8SAlexander V. Chernikov 	return (0);
557f1220db8SAlexander V. Chernikov }
558f1220db8SAlexander V. Chernikov 
559f1220db8SAlexander V. Chernikov /*
560ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
561f1220db8SAlexander V. Chernikov  * Returns 0 on success.
562f1220db8SAlexander V. Chernikov  */
563f1220db8SAlexander V. Chernikov static int
564ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
565f1220db8SAlexander V. Chernikov {
566f1220db8SAlexander V. Chernikov 
567ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
568f1220db8SAlexander V. Chernikov 		return (-1);
569f1220db8SAlexander V. Chernikov 
570f1220db8SAlexander V. Chernikov 	return (0);
571f1220db8SAlexander V. Chernikov }
572f1220db8SAlexander V. Chernikov 
57346d52008SAlexander V. Chernikov static int
57446d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second)
57546d52008SAlexander V. Chernikov {
57646d52008SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
57746d52008SAlexander V. Chernikov 	int error;
57846d52008SAlexander V. Chernikov 
57946d52008SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
58046d52008SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
58146d52008SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
58246d52008SAlexander V. Chernikov 	table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
58346d52008SAlexander V. Chernikov 
58446d52008SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
58546d52008SAlexander V. Chernikov 
58646d52008SAlexander V. Chernikov 	return (error);
58746d52008SAlexander V. Chernikov }
58846d52008SAlexander V. Chernikov 
58946d52008SAlexander V. Chernikov /*
59046d52008SAlexander V. Chernikov  * Swaps given table with @second one.
59146d52008SAlexander V. Chernikov  */
59246d52008SAlexander V. Chernikov static int
59346d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second)
59446d52008SAlexander V. Chernikov {
59546d52008SAlexander V. Chernikov 	int error;
59646d52008SAlexander V. Chernikov 
59746d52008SAlexander V. Chernikov 	if (table_check_name(second) != 0)
59846d52008SAlexander V. Chernikov 		errx(EX_USAGE, "table name %s is invalid", second);
59946d52008SAlexander V. Chernikov 
60046d52008SAlexander V. Chernikov 	error = table_do_swap(oh, second);
60146d52008SAlexander V. Chernikov 
60246d52008SAlexander V. Chernikov 	switch (error) {
60346d52008SAlexander V. Chernikov 	case EINVAL:
60446d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check types");
60546d52008SAlexander V. Chernikov 	case EFBIG:
60646d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check limits");
60746d52008SAlexander V. Chernikov 	}
60846d52008SAlexander V. Chernikov 
60946d52008SAlexander V. Chernikov 	return (0);
61046d52008SAlexander V. Chernikov }
61146d52008SAlexander V. Chernikov 
61246d52008SAlexander V. Chernikov 
613f1220db8SAlexander V. Chernikov /*
614ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
615f1220db8SAlexander V. Chernikov  * it inside @i.
616f1220db8SAlexander V. Chernikov  * Returns 0 on success.
617f1220db8SAlexander V. Chernikov  */
618f1220db8SAlexander V. Chernikov static int
619ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
620f1220db8SAlexander V. Chernikov {
621f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
622ac35ff17SAlexander V. Chernikov 	int error;
623f1220db8SAlexander V. Chernikov 	size_t sz;
624f1220db8SAlexander V. Chernikov 
625f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
626f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
627ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
628f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
629f1220db8SAlexander V. Chernikov 
630ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
631ac35ff17SAlexander V. Chernikov 		return (error);
632f1220db8SAlexander V. Chernikov 
633f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
634ac35ff17SAlexander V. Chernikov 		return (EINVAL);
635f1220db8SAlexander V. Chernikov 
636f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
637f1220db8SAlexander V. Chernikov 
638f1220db8SAlexander V. Chernikov 	return (0);
639f1220db8SAlexander V. Chernikov }
640f1220db8SAlexander V. Chernikov 
6415f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
6425f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
6435f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
6445f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
6455f379342SAlexander V. Chernikov       { NULL, 0 }
6465f379342SAlexander V. Chernikov };
6475f379342SAlexander V. Chernikov 
6485f379342SAlexander V. Chernikov struct ta_cldata {
6495f379342SAlexander V. Chernikov 	uint8_t		taclass;
6505f379342SAlexander V. Chernikov 	uint8_t		spare4;
6515f379342SAlexander V. Chernikov 	uint16_t	itemsize;
6525f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
6535f379342SAlexander V. Chernikov 	uint32_t	size;
6545f379342SAlexander V. Chernikov 	uint32_t	count;
6555f379342SAlexander V. Chernikov };
6565f379342SAlexander V. Chernikov 
6575f379342SAlexander V. Chernikov /*
6585f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
6595f379342SAlexander V. Chernikov  */
6605f379342SAlexander V. Chernikov static void
6615f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
6625f379342SAlexander V. Chernikov     const char *af, const char *taclass)
6635f379342SAlexander V. Chernikov {
6645f379342SAlexander V. Chernikov 
6655f379342SAlexander V. Chernikov 	switch (d->taclass) {
6665f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
6675f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
6685f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
6695f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
6705f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
6715f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
6725f379342SAlexander V. Chernikov 		else
6735f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
6745f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
6755f379342SAlexander V. Chernikov 			    d->size, d->count,
6765f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
6775f379342SAlexander V. Chernikov 		break;
6785f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
6795f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
6805f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
6815f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
6825f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
6835f379342SAlexander V. Chernikov 		else
6845f379342SAlexander V. Chernikov 			printf("  items: %u "
6855f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
6865f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
6875f379342SAlexander V. Chernikov 		break;
6885f379342SAlexander V. Chernikov 	default:
6895f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
6905f379342SAlexander V. Chernikov 	}
6915f379342SAlexander V. Chernikov }
6925f379342SAlexander V. Chernikov 
693f1220db8SAlexander V. Chernikov /*
694f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
695f1220db8SAlexander V. Chernikov  */
696f1220db8SAlexander V. Chernikov static int
697f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
698f1220db8SAlexander V. Chernikov {
699adf3b2b9SAlexander V. Chernikov 	const char *vtype, *vftype;
7005f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
7015f379342SAlexander V. Chernikov 	int afdata, afitem;
7025f379342SAlexander V. Chernikov 	struct ta_cldata d;
703adf3b2b9SAlexander V. Chernikov 	char ttype[64], tvtype[64];
704f1220db8SAlexander V. Chernikov 
705914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
706ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
707ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
708adf3b2b9SAlexander V. Chernikov 	if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL)
709adf3b2b9SAlexander V. Chernikov 		vftype = "unknown";
710adf3b2b9SAlexander V. Chernikov 	if (strcmp(vtype, vftype) != 0)
711adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype);
712adf3b2b9SAlexander V. Chernikov 	else
713adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s", vtype);
714ac35ff17SAlexander V. Chernikov 
715914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
716914bffb6SAlexander V. Chernikov 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
717adf3b2b9SAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
7189d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
719f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
7204c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
7214c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
722f1220db8SAlexander V. Chernikov 
723358b9d09SAlexander V. Chernikov 	/* Print algo-specific info if requested & set  */
724358b9d09SAlexander V. Chernikov 	if (arg == NULL)
725358b9d09SAlexander V. Chernikov 		return (0);
726358b9d09SAlexander V. Chernikov 
7275f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
7285f379342SAlexander V. Chernikov 		return (0);
7295f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
7305f379342SAlexander V. Chernikov 
7315f379342SAlexander V. Chernikov 	afdata = 0;
7325f379342SAlexander V. Chernikov 	afitem = 0;
7335f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
7345f379342SAlexander V. Chernikov 		afdata = 1;
7355f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
7365f379342SAlexander V. Chernikov 		afitem = 1;
7375f379342SAlexander V. Chernikov 
7385f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
7395f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
7405f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
7415f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
7425f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
7435f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
7445f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
7455f379342SAlexander V. Chernikov 	else
7465f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
7475f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7485f379342SAlexander V. Chernikov 		vtype = "unknown";
7495f379342SAlexander V. Chernikov 
7505f379342SAlexander V. Chernikov 	if (afdata == 0) {
7515f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
7525f379342SAlexander V. Chernikov 	} else {
7535f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
7545f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
7555f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
7565f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7575f379342SAlexander V. Chernikov 			vtype = "unknown";
7585f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
7595f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
7605f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
7615f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
7625f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
7635f379342SAlexander V. Chernikov 	}
7645f379342SAlexander V. Chernikov 
765f1220db8SAlexander V. Chernikov 	return (0);
766f1220db8SAlexander V. Chernikov }
767f1220db8SAlexander V. Chernikov 
768f1220db8SAlexander V. Chernikov 
769f1220db8SAlexander V. Chernikov /*
770f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
771f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
772f1220db8SAlexander V. Chernikov  */
773f1220db8SAlexander V. Chernikov 
774f1220db8SAlexander V. Chernikov static int
775f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
776f1220db8SAlexander V. Chernikov {
777f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
77881d3153dSAlexander V. Chernikov 	int error;
779f1220db8SAlexander V. Chernikov 
780720ee730SAlexander V. Chernikov 	if ((error = table_do_get_list(i, &oh)) != 0) {
78181d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
78281d3153dSAlexander V. Chernikov 		return (error);
78381d3153dSAlexander V. Chernikov 	}
78481d3153dSAlexander V. Chernikov 
785f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
786f1220db8SAlexander V. Chernikov 
787f1220db8SAlexander V. Chernikov 	free(oh);
788f1220db8SAlexander V. Chernikov 	return (0);
789f1220db8SAlexander V. Chernikov }
790f1220db8SAlexander V. Chernikov 
791f1220db8SAlexander V. Chernikov static int
792f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
793f1220db8SAlexander V. Chernikov {
794ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
795f1220db8SAlexander V. Chernikov 
796ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
797ac35ff17SAlexander V. Chernikov 
798ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
799ac35ff17SAlexander V. Chernikov 
800ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
801f1220db8SAlexander V. Chernikov }
802f1220db8SAlexander V. Chernikov 
803ac35ff17SAlexander V. Chernikov static int
804ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
805*3a845e10SAlexander V. Chernikov     ipfw_obj_tentry *tent, int count, int atomic)
806ac35ff17SAlexander V. Chernikov {
807db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
808*3a845e10SAlexander V. Chernikov 	ipfw_obj_tentry *tent_base;
809*3a845e10SAlexander V. Chernikov 	caddr_t pbuf;
810db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
811*3a845e10SAlexander V. Chernikov 	int error, i;
812*3a845e10SAlexander V. Chernikov 	size_t sz;
813ac35ff17SAlexander V. Chernikov 
814*3a845e10SAlexander V. Chernikov 	sz = sizeof(*ctlv) + sizeof(*tent) * count;
815*3a845e10SAlexander V. Chernikov 	if (count == 1) {
816ac35ff17SAlexander V. Chernikov 		memset(xbuf, 0, sizeof(xbuf));
817*3a845e10SAlexander V. Chernikov 		pbuf = xbuf;
818*3a845e10SAlexander V. Chernikov 	} else {
819*3a845e10SAlexander V. Chernikov 		if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL)
820*3a845e10SAlexander V. Chernikov 			return (ENOMEM);
821*3a845e10SAlexander V. Chernikov 	}
822*3a845e10SAlexander V. Chernikov 
823*3a845e10SAlexander V. Chernikov 	memcpy(pbuf, oh, sizeof(*oh));
824*3a845e10SAlexander V. Chernikov 	oh = (ipfw_obj_header *)pbuf;
825ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
826ac35ff17SAlexander V. Chernikov 
827db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
828*3a845e10SAlexander V. Chernikov 	ctlv->count = count;
829*3a845e10SAlexander V. Chernikov 	ctlv->head.length = sz;
830*3a845e10SAlexander V. Chernikov 	if (atomic != 0)
831*3a845e10SAlexander V. Chernikov 		ctlv->flags |= IPFW_CTF_ATOMIC;
832db785d31SAlexander V. Chernikov 
833*3a845e10SAlexander V. Chernikov 	tent_base = tent;
834*3a845e10SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent) * count);
835db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
836*3a845e10SAlexander V. Chernikov 	for (i = 0; i < count; i++, tent++) {
837ac35ff17SAlexander V. Chernikov 		tent->head.length = sizeof(ipfw_obj_tentry);
838*3a845e10SAlexander V. Chernikov 		tent->idx = oh->idx;
839*3a845e10SAlexander V. Chernikov 	}
840ac35ff17SAlexander V. Chernikov 
841*3a845e10SAlexander V. Chernikov 	sz += sizeof(*oh);
842*3a845e10SAlexander V. Chernikov 	error = do_get3(cmd, &oh->opheader, &sz);
843*3a845e10SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
844*3a845e10SAlexander V. Chernikov 	/* Copy result back to provided buffer */
845*3a845e10SAlexander V. Chernikov 	memcpy(tent_base, ctlv + 1, sizeof(*tent) * count);
846*3a845e10SAlexander V. Chernikov 
847*3a845e10SAlexander V. Chernikov 	if (pbuf != xbuf)
848*3a845e10SAlexander V. Chernikov 		free(pbuf);
849ac35ff17SAlexander V. Chernikov 
850ac35ff17SAlexander V. Chernikov 	return (error);
851ac35ff17SAlexander V. Chernikov }
852ac35ff17SAlexander V. Chernikov 
853ac35ff17SAlexander V. Chernikov static void
854*3a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add,
855*3a845e10SAlexander V. Chernikov     int quiet, int update, int atomic)
856ac35ff17SAlexander V. Chernikov {
857*3a845e10SAlexander V. Chernikov 	ipfw_obj_tentry *ptent, tent, *tent_buf;
85881d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
859ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
860*3a845e10SAlexander V. Chernikov 	int cmd, count, error, i, ignored;
861*3a845e10SAlexander V. Chernikov 	char *texterr, *etxt, *px;
862ac35ff17SAlexander V. Chernikov 
863ac35ff17SAlexander V. Chernikov 	if (ac == 0)
864ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
865ac35ff17SAlexander V. Chernikov 
866ac35ff17SAlexander V. Chernikov 	if (add != 0) {
867ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
8684c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
869ac35ff17SAlexander V. Chernikov 	} else {
870ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
8714c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
872ac35ff17SAlexander V. Chernikov 	}
873ac35ff17SAlexander V. Chernikov 
874*3a845e10SAlexander V. Chernikov 	/*
875*3a845e10SAlexander V. Chernikov 	 * Calculate number of entries:
876*3a845e10SAlexander V. Chernikov 	 * Assume [key val] x N for add
877*3a845e10SAlexander V. Chernikov 	 * and
878*3a845e10SAlexander V. Chernikov 	 * key x N for delete
879*3a845e10SAlexander V. Chernikov 	 */
880*3a845e10SAlexander V. Chernikov 	count = (add != 0) ? ac / 2 + 1 : ac;
881*3a845e10SAlexander V. Chernikov 
882*3a845e10SAlexander V. Chernikov 	if (count <= 1) {
883*3a845e10SAlexander V. Chernikov 		/* Adding single entry with/without value */
884*3a845e10SAlexander V. Chernikov 		memset(&tent, 0, sizeof(tent));
885*3a845e10SAlexander V. Chernikov 		tent_buf = &tent;
886*3a845e10SAlexander V. Chernikov 	} else {
887*3a845e10SAlexander V. Chernikov 
888*3a845e10SAlexander V. Chernikov 		if ((tent_buf = calloc(count, sizeof(tent))) == NULL)
889*3a845e10SAlexander V. Chernikov 			errx(EX_OSERR,
890*3a845e10SAlexander V. Chernikov 			    "Unable to allocate memory for all entries");
891*3a845e10SAlexander V. Chernikov 	}
892*3a845e10SAlexander V. Chernikov 	ptent = tent_buf;
893*3a845e10SAlexander V. Chernikov 
894*3a845e10SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
895*3a845e10SAlexander V. Chernikov 	count = 0;
896*3a845e10SAlexander V. Chernikov 	while (ac > 0) {
897*3a845e10SAlexander V. Chernikov 		tentry_fill_key(oh, ptent, *av, &type, &vtype, &xi);
898*3a845e10SAlexander V. Chernikov 
899*3a845e10SAlexander V. Chernikov 		/*
900*3a845e10SAlexander V. Chernikov 		 * compability layer: auto-create table if not exists
901*3a845e10SAlexander V. Chernikov 		 */
902*3a845e10SAlexander V. Chernikov 		if (xi.tablename[0] == '\0') {
903*3a845e10SAlexander V. Chernikov 			xi.type = type;
904*3a845e10SAlexander V. Chernikov 			xi.vtype = vtype;
905*3a845e10SAlexander V. Chernikov 			strlcpy(xi.tablename, oh->ntlv.name,
906*3a845e10SAlexander V. Chernikov 			    sizeof(xi.tablename));
907*3a845e10SAlexander V. Chernikov 			fprintf(stderr, "DEPRECATED: inserting data info "
908*3a845e10SAlexander V. Chernikov 			    "non-existent table %s. (auto-created)\n",
909*3a845e10SAlexander V. Chernikov 			    xi.tablename);
910*3a845e10SAlexander V. Chernikov 			table_do_create(oh, &xi);
911*3a845e10SAlexander V. Chernikov 		}
912*3a845e10SAlexander V. Chernikov 
913*3a845e10SAlexander V. Chernikov 		oh->ntlv.type = type;
914*3a845e10SAlexander V. Chernikov 		ac--; av++;
915*3a845e10SAlexander V. Chernikov 
916*3a845e10SAlexander V. Chernikov 		if (add != 0 && ac > 0) {
917*3a845e10SAlexander V. Chernikov 			tentry_fill_value(oh, ptent, *av, type, vtype);
918*3a845e10SAlexander V. Chernikov 			ac--; av++;
919*3a845e10SAlexander V. Chernikov 		}
920*3a845e10SAlexander V. Chernikov 
921*3a845e10SAlexander V. Chernikov 		if (update != 0)
922*3a845e10SAlexander V. Chernikov 			ptent->head.flags |= IPFW_TF_UPDATE;
923*3a845e10SAlexander V. Chernikov 
924*3a845e10SAlexander V. Chernikov 		count++;
925*3a845e10SAlexander V. Chernikov 		ptent++;
926*3a845e10SAlexander V. Chernikov 	}
927*3a845e10SAlexander V. Chernikov 
928*3a845e10SAlexander V. Chernikov 	error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
929*3a845e10SAlexander V. Chernikov 
930*3a845e10SAlexander V. Chernikov 	/*
931*3a845e10SAlexander V. Chernikov 	 * Compatibility stuff: do not yell on duplicate keys or
932*3a845e10SAlexander V. Chernikov 	 * failed deletions.
933*3a845e10SAlexander V. Chernikov 	 */
934*3a845e10SAlexander V. Chernikov 	if (error == 0 || (error == EEXIST && add != 0) ||
935*3a845e10SAlexander V. Chernikov 	    (error == ENOENT && add == 0)) {
936*3a845e10SAlexander V. Chernikov 		if (quiet != 0) {
937*3a845e10SAlexander V. Chernikov 			if (tent_buf != &tent)
938*3a845e10SAlexander V. Chernikov 				free(tent_buf);
939*3a845e10SAlexander V. Chernikov 			return;
940*3a845e10SAlexander V. Chernikov 		}
941*3a845e10SAlexander V. Chernikov 	}
942*3a845e10SAlexander V. Chernikov 
943*3a845e10SAlexander V. Chernikov 	/* Report results back */
944*3a845e10SAlexander V. Chernikov 	ptent = tent_buf;
945*3a845e10SAlexander V. Chernikov 	for (i = 0; i < count; ptent++, i++) {
946*3a845e10SAlexander V. Chernikov 		ignored = 0;
947*3a845e10SAlexander V. Chernikov 		switch (ptent->result) {
948*3a845e10SAlexander V. Chernikov 		case IPFW_TR_ADDED:
949*3a845e10SAlexander V. Chernikov 			px = "added";
950*3a845e10SAlexander V. Chernikov 			break;
951*3a845e10SAlexander V. Chernikov 		case IPFW_TR_DELETED:
952*3a845e10SAlexander V. Chernikov 			px = "deleted";
953*3a845e10SAlexander V. Chernikov 			break;
954*3a845e10SAlexander V. Chernikov 		case IPFW_TR_UPDATED:
955*3a845e10SAlexander V. Chernikov 			px = "updated";
956*3a845e10SAlexander V. Chernikov 			break;
957*3a845e10SAlexander V. Chernikov 		case IPFW_TR_LIMIT:
958*3a845e10SAlexander V. Chernikov 			px = "limit";
959*3a845e10SAlexander V. Chernikov 			ignored = 1;
960*3a845e10SAlexander V. Chernikov 			break;
961*3a845e10SAlexander V. Chernikov 		case IPFW_TR_ERROR:
962*3a845e10SAlexander V. Chernikov 			px = "error";
963*3a845e10SAlexander V. Chernikov 			ignored = 1;
964*3a845e10SAlexander V. Chernikov 			break;
965*3a845e10SAlexander V. Chernikov 		case IPFW_TR_NOTFOUND:
966*3a845e10SAlexander V. Chernikov 			px = "notfound";
967*3a845e10SAlexander V. Chernikov 			ignored = 1;
968*3a845e10SAlexander V. Chernikov 			break;
969*3a845e10SAlexander V. Chernikov 		case IPFW_TR_EXISTS:
970*3a845e10SAlexander V. Chernikov 			px = "exists";
971*3a845e10SAlexander V. Chernikov 			ignored = 1;
972*3a845e10SAlexander V. Chernikov 			break;
973*3a845e10SAlexander V. Chernikov 		case IPFW_TR_IGNORED:
974*3a845e10SAlexander V. Chernikov 			px = "ignored";
975*3a845e10SAlexander V. Chernikov 			ignored = 1;
976*3a845e10SAlexander V. Chernikov 			break;
977*3a845e10SAlexander V. Chernikov 		default:
978*3a845e10SAlexander V. Chernikov 			px = "unknown";
979*3a845e10SAlexander V. Chernikov 			ignored = 1;
980*3a845e10SAlexander V. Chernikov 		}
981*3a845e10SAlexander V. Chernikov 
982*3a845e10SAlexander V. Chernikov 		if (error != 0 && atomic != 0 && ignored == 0)
983*3a845e10SAlexander V. Chernikov 			printf("%s(reverted): ", px);
984*3a845e10SAlexander V. Chernikov 		else
985*3a845e10SAlexander V. Chernikov 			printf("%s: ", px);
986*3a845e10SAlexander V. Chernikov 
987*3a845e10SAlexander V. Chernikov 		table_show_entry(&xi, ptent);
988*3a845e10SAlexander V. Chernikov 	}
989*3a845e10SAlexander V. Chernikov 
990*3a845e10SAlexander V. Chernikov 	if (tent_buf != &tent)
991*3a845e10SAlexander V. Chernikov 		free(tent_buf);
992*3a845e10SAlexander V. Chernikov 
993*3a845e10SAlexander V. Chernikov 	if (error == 0)
9944c0c07a5SAlexander V. Chernikov 		return;
9954c0c07a5SAlexander V. Chernikov 
9964c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
9974c0c07a5SAlexander V. Chernikov 	switch (error) {
9984c0c07a5SAlexander V. Chernikov 	case EEXIST:
9994c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
10004c0c07a5SAlexander V. Chernikov 		break;
10014c0c07a5SAlexander V. Chernikov 	case EFBIG:
10024c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
10034c0c07a5SAlexander V. Chernikov 		break;
10044c0c07a5SAlexander V. Chernikov 	case ESRCH:
10054c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
10064c0c07a5SAlexander V. Chernikov 		break;
10074c0c07a5SAlexander V. Chernikov 	case ENOENT:
10084c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
10094c0c07a5SAlexander V. Chernikov 		break;
10104c0c07a5SAlexander V. Chernikov 	default:
10114c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
10124c0c07a5SAlexander V. Chernikov 	}
10134c0c07a5SAlexander V. Chernikov 
10144c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
1015ac35ff17SAlexander V. Chernikov }
1016ac35ff17SAlexander V. Chernikov 
101781d3153dSAlexander V. Chernikov static int
101881d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
101981d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
102081d3153dSAlexander V. Chernikov {
102181d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
102281d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
102381d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
102481d3153dSAlexander V. Chernikov 	int error;
102581d3153dSAlexander V. Chernikov 	size_t sz;
102681d3153dSAlexander V. Chernikov 
102781d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
102881d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
102981d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
103081d3153dSAlexander V. Chernikov 
103181d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
103281d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
103381d3153dSAlexander V. Chernikov 	tent->idx = 1;
103481d3153dSAlexander V. Chernikov 
103581d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
103681d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
103781d3153dSAlexander V. Chernikov 
103881d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
103981d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
104081d3153dSAlexander V. Chernikov 		return (error);
104181d3153dSAlexander V. Chernikov 
104281d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
104381d3153dSAlexander V. Chernikov 		return (EINVAL);
104481d3153dSAlexander V. Chernikov 
104581d3153dSAlexander V. Chernikov 	*xtent = *tent;
104681d3153dSAlexander V. Chernikov 
104781d3153dSAlexander V. Chernikov 	return (0);
104881d3153dSAlexander V. Chernikov }
104981d3153dSAlexander V. Chernikov 
105081d3153dSAlexander V. Chernikov static void
105181d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
105281d3153dSAlexander V. Chernikov {
105381d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
105481d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
1055914bffb6SAlexander V. Chernikov 	char key[64];
105681d3153dSAlexander V. Chernikov 	int error;
105781d3153dSAlexander V. Chernikov 
105881d3153dSAlexander V. Chernikov 	if (ac == 0)
105981d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
106081d3153dSAlexander V. Chernikov 
1061914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
1062914bffb6SAlexander V. Chernikov 
1063*3a845e10SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
1064914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
106581d3153dSAlexander V. Chernikov 
106681d3153dSAlexander V. Chernikov 	switch (error) {
106781d3153dSAlexander V. Chernikov 	case 0:
106881d3153dSAlexander V. Chernikov 		break;
106981d3153dSAlexander V. Chernikov 	case ESRCH:
107081d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
107181d3153dSAlexander V. Chernikov 	case ENOENT:
107281d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
107381d3153dSAlexander V. Chernikov 	case ENOTSUP:
107481d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
107581d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
107681d3153dSAlexander V. Chernikov 	default:
107781d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
107881d3153dSAlexander V. Chernikov 	}
107981d3153dSAlexander V. Chernikov 
108081d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
108181d3153dSAlexander V. Chernikov }
1082ac35ff17SAlexander V. Chernikov 
1083ac35ff17SAlexander V. Chernikov static void
1084914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
1085914bffb6SAlexander V. Chernikov     uint8_t tflags)
1086ac35ff17SAlexander V. Chernikov {
1087914bffb6SAlexander V. Chernikov 	char *p, *pp;
1088ac35ff17SAlexander V. Chernikov 	int mask, af;
1089914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
1090914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
1091ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
1092914bffb6SAlexander V. Chernikov 	uint16_t port;
1093914bffb6SAlexander V. Chernikov 	struct protoent *pent;
1094914bffb6SAlexander V. Chernikov 	struct servent *sent;
1095ac35ff17SAlexander V. Chernikov 	int masklen;
1096ac35ff17SAlexander V. Chernikov 
1097ac35ff17SAlexander V. Chernikov 	masklen = 0;
1098ac35ff17SAlexander V. Chernikov 	af = 0;
1099ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
1100ac35ff17SAlexander V. Chernikov 
1101ac35ff17SAlexander V. Chernikov 	switch (type) {
1102ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1103ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
1104ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
1105ac35ff17SAlexander V. Chernikov 			*p = '\0';
1106ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
1107ac35ff17SAlexander V. Chernikov 		}
1108ac35ff17SAlexander V. Chernikov 
1109ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
1110ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
1111ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
1112ac35ff17SAlexander V. Chernikov 				    p + 1);
1113ac35ff17SAlexander V. Chernikov 
1114ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
1115ac35ff17SAlexander V. Chernikov 			af = AF_INET;
1116ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
1117ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
1118ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
1119ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
1120ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
1121ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
1122ac35ff17SAlexander V. Chernikov 				    p + 1);
1123ac35ff17SAlexander V. Chernikov 
1124ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
1125ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
1126ac35ff17SAlexander V. Chernikov 		} else {
1127ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
1128ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
1129ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
1130ac35ff17SAlexander V. Chernikov 
1131ac35ff17SAlexander V. Chernikov 			masklen = 32;
1132ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1133ac35ff17SAlexander V. Chernikov 			af = AF_INET;
1134ac35ff17SAlexander V. Chernikov 		}
1135ac35ff17SAlexander V. Chernikov 		break;
1136ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1137ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
1138ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
1139ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
1140ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
1141ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
1142ac35ff17SAlexander V. Chernikov 		break;
1143b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1144ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
1145ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
1146ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1147ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
1148ac35ff17SAlexander V. Chernikov 
1149ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
1150ac35ff17SAlexander V. Chernikov 		*pkey = key;
1151ac35ff17SAlexander V. Chernikov 		masklen = 32;
1152ac35ff17SAlexander V. Chernikov 		break;
1153914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1154914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1155914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
1156914bffb6SAlexander V. Chernikov 		af = 0;
1157914bffb6SAlexander V. Chernikov 
1158914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1159914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
1160914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1161914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1162914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1163914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1164914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1165914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1166914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1167914bffb6SAlexander V. Chernikov 				af = AF_INET;
1168914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
1169914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1170914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1171914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1172914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1173914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1174914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
1175914bffb6SAlexander V. Chernikov 			}
1176914bffb6SAlexander V. Chernikov 
1177914bffb6SAlexander V. Chernikov 			arg = p;
1178914bffb6SAlexander V. Chernikov 		}
1179914bffb6SAlexander V. Chernikov 
1180914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
1181914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
1182914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1183914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1184914bffb6SAlexander V. Chernikov 
1185914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
1186914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
1187914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
1188914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
1189914bffb6SAlexander V. Chernikov 					    arg);
1190914bffb6SAlexander V. Chernikov 				else
1191914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
1192914bffb6SAlexander V. Chernikov 			}
1193914bffb6SAlexander V. Chernikov 
1194914bffb6SAlexander V. Chernikov 			if (key > 255)
1195914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
1196914bffb6SAlexander V. Chernikov 
1197914bffb6SAlexander V. Chernikov 			tfe->proto = key;
1198914bffb6SAlexander V. Chernikov 
1199914bffb6SAlexander V. Chernikov 			arg = p;
1200914bffb6SAlexander V. Chernikov 		}
1201914bffb6SAlexander V. Chernikov 
1202914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1203914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1204914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1205914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1206914bffb6SAlexander V. Chernikov 
1207914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1208914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1209914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1210914bffb6SAlexander V. Chernikov 					    arg);
1211914bffb6SAlexander V. Chernikov 				else
1212914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1213914bffb6SAlexander V. Chernikov 			}
1214914bffb6SAlexander V. Chernikov 
1215914bffb6SAlexander V. Chernikov 			tfe->sport = port;
1216914bffb6SAlexander V. Chernikov 
1217914bffb6SAlexander V. Chernikov 			arg = p;
1218914bffb6SAlexander V. Chernikov 		}
1219914bffb6SAlexander V. Chernikov 
1220914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1221914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
1222914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1223914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1224914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1225914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1226914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1227914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1228914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1229914bffb6SAlexander V. Chernikov 				af = AF_INET;
1230914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
1231914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1232914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1233914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1234914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1235914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1236914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
1237914bffb6SAlexander V. Chernikov 			}
1238914bffb6SAlexander V. Chernikov 
1239914bffb6SAlexander V. Chernikov 			arg = p;
1240914bffb6SAlexander V. Chernikov 		}
1241914bffb6SAlexander V. Chernikov 
1242914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1243914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1244914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1245914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1246914bffb6SAlexander V. Chernikov 
1247914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1248914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1249914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1250914bffb6SAlexander V. Chernikov 					    arg);
1251914bffb6SAlexander V. Chernikov 				else
1252914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1253914bffb6SAlexander V. Chernikov 			}
1254914bffb6SAlexander V. Chernikov 
1255914bffb6SAlexander V. Chernikov 			tfe->dport = port;
1256914bffb6SAlexander V. Chernikov 
1257914bffb6SAlexander V. Chernikov 			arg = p;
1258914bffb6SAlexander V. Chernikov 		}
1259914bffb6SAlexander V. Chernikov 
1260914bffb6SAlexander V. Chernikov 		tfe->af = af;
1261914bffb6SAlexander V. Chernikov 
1262914bffb6SAlexander V. Chernikov 		break;
1263914bffb6SAlexander V. Chernikov 
1264ac35ff17SAlexander V. Chernikov 	default:
1265ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
1266ac35ff17SAlexander V. Chernikov 	}
1267ac35ff17SAlexander V. Chernikov 
1268ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
1269ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
1270ac35ff17SAlexander V. Chernikov }
1271ac35ff17SAlexander V. Chernikov 
1272ac35ff17SAlexander V. Chernikov static void
1273ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
127481d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
1275ac35ff17SAlexander V. Chernikov {
1276914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
1277ac35ff17SAlexander V. Chernikov 	int error;
1278db785d31SAlexander V. Chernikov 	char *del;
1279ac35ff17SAlexander V. Chernikov 
1280ac35ff17SAlexander V. Chernikov 	type = 0;
1281914bffb6SAlexander V. Chernikov 	tflags = 0;
1282ac35ff17SAlexander V. Chernikov 	vtype = 0;
1283ac35ff17SAlexander V. Chernikov 
1284*3a845e10SAlexander V. Chernikov 	if (xi->tablename[0] == '\0')
128581d3153dSAlexander V. Chernikov 		error = table_get_info(oh, xi);
1286*3a845e10SAlexander V. Chernikov 	else
1287*3a845e10SAlexander V. Chernikov 		error = 0;
128881d3153dSAlexander V. Chernikov 
128981d3153dSAlexander V. Chernikov 	if (error == 0) {
129081d3153dSAlexander V. Chernikov 		/* Table found. */
129181d3153dSAlexander V. Chernikov 		type = xi->type;
1292914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
129381d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
129481d3153dSAlexander V. Chernikov 	} else {
129581d3153dSAlexander V. Chernikov 		if (error != ESRCH)
129681d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
129781d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
1298ac35ff17SAlexander V. Chernikov 		/*
129981d3153dSAlexander V. Chernikov 		 * Table does not exist.
130081d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
130181d3153dSAlexander V. Chernikov 		 * before failing.
1302ac35ff17SAlexander V. Chernikov 		 */
1303db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1304db785d31SAlexander V. Chernikov 			*del = '\0';
1305ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1306ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1307ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1308ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1309ac35ff17SAlexander V. Chernikov 			/*
131081d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
131181d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1312ac35ff17SAlexander V. Chernikov 			 */
131381d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
131481d3153dSAlexander V. Chernikov 		} else {
131581d3153dSAlexander V. Chernikov 			/* Inknown key */
131681d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1317db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
131881d3153dSAlexander V. Chernikov 		}
1319db785d31SAlexander V. Chernikov 		if (del != NULL)
1320db785d31SAlexander V. Chernikov 			*del = '/';
1321ac35ff17SAlexander V. Chernikov 	}
1322ac35ff17SAlexander V. Chernikov 
1323914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1324ac35ff17SAlexander V. Chernikov 
1325ac35ff17SAlexander V. Chernikov 	*ptype = type;
1326ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1327ac35ff17SAlexander V. Chernikov }
1328ac35ff17SAlexander V. Chernikov 
1329ac35ff17SAlexander V. Chernikov static void
1330ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1331ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1332ac35ff17SAlexander V. Chernikov {
1333adf3b2b9SAlexander V. Chernikov 	uint32_t val;
1334ac35ff17SAlexander V. Chernikov 	char *p;
1335ac35ff17SAlexander V. Chernikov 
1336adf3b2b9SAlexander V. Chernikov 	/* Try to interpret as number first */
1337adf3b2b9SAlexander V. Chernikov 	tent->value = strtoul(arg, &p, 0);
1338adf3b2b9SAlexander V. Chernikov 	if (*p == '\0')
1339adf3b2b9SAlexander V. Chernikov 		return;
1340adf3b2b9SAlexander V. Chernikov 	if (inet_pton(AF_INET, arg, &val) == 1) {
1341adf3b2b9SAlexander V. Chernikov 		tent->value = ntohl(val);
1342adf3b2b9SAlexander V. Chernikov 		return;
1343adf3b2b9SAlexander V. Chernikov 	}
1344adf3b2b9SAlexander V. Chernikov 	/* Try hostname */
1345adf3b2b9SAlexander V. Chernikov 	if (lookup_host(arg, (struct in_addr *)&tent->value) == 0)
1346adf3b2b9SAlexander V. Chernikov 		return;
1347adf3b2b9SAlexander V. Chernikov 	errx(EX_OSERR, "Unable to parse value %s", arg);
1348adf3b2b9SAlexander V. Chernikov #if 0
1349ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1350ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1351ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1352ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1353ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1354ac35ff17SAlexander V. Chernikov 		break;
1355ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1356ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1357ac35ff17SAlexander V. Chernikov 			break;
1358ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1359ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1360ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1361ac35ff17SAlexander V. Chernikov 		break;
1362ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1363ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1364ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1365ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1366ac35ff17SAlexander V. Chernikov 		} else {
1367ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1368ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1369ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1370ac35ff17SAlexander V. Chernikov 		}
1371ac35ff17SAlexander V. Chernikov 		tent->value = code;
1372ac35ff17SAlexander V. Chernikov 		break;
1373ac35ff17SAlexander V. Chernikov 	default:
1374ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1375ac35ff17SAlexander V. Chernikov 	}
1376adf3b2b9SAlexander V. Chernikov #endif
1377ac35ff17SAlexander V. Chernikov }
1378f1220db8SAlexander V. Chernikov 
1379f1220db8SAlexander V. Chernikov /*
1380f1220db8SAlexander V. Chernikov  * Compare table names.
1381f1220db8SAlexander V. Chernikov  * Honor number comparison.
1382f1220db8SAlexander V. Chernikov  */
1383f1220db8SAlexander V. Chernikov static int
1384f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1385f1220db8SAlexander V. Chernikov {
1386f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1387f1220db8SAlexander V. Chernikov 
1388f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1389f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1390f1220db8SAlexander V. Chernikov 
139168394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1392f1220db8SAlexander V. Chernikov }
1393f1220db8SAlexander V. Chernikov 
1394f1220db8SAlexander V. Chernikov /*
1395f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1396f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1397f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1398f1220db8SAlexander V. Chernikov  */
1399f1220db8SAlexander V. Chernikov static int
1400f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1401f1220db8SAlexander V. Chernikov {
140228ea4fa3SAlexander V. Chernikov 	ipfw_obj_lheader *olh;
1403f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1404f1220db8SAlexander V. Chernikov 	size_t sz;
1405f1220db8SAlexander V. Chernikov 	int i, error;
1406f1220db8SAlexander V. Chernikov 
140728ea4fa3SAlexander V. Chernikov 	/* Start with reasonable default */
140828ea4fa3SAlexander V. Chernikov 	sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
1409f1220db8SAlexander V. Chernikov 
141028ea4fa3SAlexander V. Chernikov 	for (;;) {
1411f1220db8SAlexander V. Chernikov 		if ((olh = calloc(1, sz)) == NULL)
1412f1220db8SAlexander V. Chernikov 			return (ENOMEM);
1413f1220db8SAlexander V. Chernikov 
1414f1220db8SAlexander V. Chernikov 		olh->size = sz;
141528ea4fa3SAlexander V. Chernikov 		error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz);
141628ea4fa3SAlexander V. Chernikov 		if (error == ENOMEM) {
141728ea4fa3SAlexander V. Chernikov 			sz = olh->size;
1418f1220db8SAlexander V. Chernikov 			free(olh);
141928ea4fa3SAlexander V. Chernikov 			continue;
142028ea4fa3SAlexander V. Chernikov 		} else if (error != 0) {
142128ea4fa3SAlexander V. Chernikov 			free(olh);
142228ea4fa3SAlexander V. Chernikov 			return (error);
1423f1220db8SAlexander V. Chernikov 		}
1424f1220db8SAlexander V. Chernikov 
1425f1220db8SAlexander V. Chernikov 		if (sort != 0)
1426f1220db8SAlexander V. Chernikov 			qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1427f1220db8SAlexander V. Chernikov 
1428f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)(olh + 1);
1429f1220db8SAlexander V. Chernikov 		for (i = 0; i < olh->count; i++) {
1430f1220db8SAlexander V. Chernikov 			error = f(info, arg); /* Ignore errors for now */
1431f1220db8SAlexander V. Chernikov 			info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1432f1220db8SAlexander V. Chernikov 		}
1433f1220db8SAlexander V. Chernikov 
1434f1220db8SAlexander V. Chernikov 		free(olh);
143528ea4fa3SAlexander V. Chernikov 		break;
143628ea4fa3SAlexander V. Chernikov 	}
1437f1220db8SAlexander V. Chernikov 
1438f1220db8SAlexander V. Chernikov 	return (0);
1439f1220db8SAlexander V. Chernikov }
1440f1220db8SAlexander V. Chernikov 
144128ea4fa3SAlexander V. Chernikov 
1442f1220db8SAlexander V. Chernikov /*
1443f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1444720ee730SAlexander V. Chernikov  * eXtended format. Allocate buffer large enough
1445720ee730SAlexander V. Chernikov  * to store result. Called needs to free it later.
1446f1220db8SAlexander V. Chernikov  *
1447f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1448f1220db8SAlexander V. Chernikov  */
1449f1220db8SAlexander V. Chernikov static int
1450720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
1451f1220db8SAlexander V. Chernikov {
1452720ee730SAlexander V. Chernikov 	ipfw_obj_header *oh;
1453f1220db8SAlexander V. Chernikov 	size_t sz;
145481d3153dSAlexander V. Chernikov 	int error, c;
1455f1220db8SAlexander V. Chernikov 
145681d3153dSAlexander V. Chernikov 	sz = 0;
1457720ee730SAlexander V. Chernikov 	oh = NULL;
1458720ee730SAlexander V. Chernikov 	error = 0;
1459720ee730SAlexander V. Chernikov 	for (c = 0; c < 8; c++) {
146081d3153dSAlexander V. Chernikov 		if (sz < i->size)
1461720ee730SAlexander V. Chernikov 			sz = i->size + 44;
1462720ee730SAlexander V. Chernikov 		if (oh != NULL)
1463720ee730SAlexander V. Chernikov 			free(oh);
1464720ee730SAlexander V. Chernikov 		if ((oh = calloc(1, sz)) == NULL)
1465720ee730SAlexander V. Chernikov 			continue;
1466720ee730SAlexander V. Chernikov 		table_fill_objheader(oh, i);
1467d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
146881d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1469d3a4f924SAlexander V. Chernikov 
1470720ee730SAlexander V. Chernikov 		if (error == 0) {
1471720ee730SAlexander V. Chernikov 			*poh = oh;
1472720ee730SAlexander V. Chernikov 			return (0);
147381d3153dSAlexander V. Chernikov 		}
1474f1220db8SAlexander V. Chernikov 
1475720ee730SAlexander V. Chernikov 		if (error != ENOMEM)
1476720ee730SAlexander V. Chernikov 			break;
1477720ee730SAlexander V. Chernikov 	}
1478720ee730SAlexander V. Chernikov 	free(oh);
1479720ee730SAlexander V. Chernikov 
1480720ee730SAlexander V. Chernikov 	return (error);
1481f1220db8SAlexander V. Chernikov }
1482f1220db8SAlexander V. Chernikov 
1483f1220db8SAlexander V. Chernikov /*
1484f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1485f1220db8SAlexander V. Chernikov  */
1486f1220db8SAlexander V. Chernikov static void
1487f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1488f1220db8SAlexander V. Chernikov {
148981d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
149081d3153dSAlexander V. Chernikov 	uint32_t count;
1491f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1492f1220db8SAlexander V. Chernikov 
1493f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
149481d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1495f1220db8SAlexander V. Chernikov 
1496f1220db8SAlexander V. Chernikov 	if (need_header)
1497f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1498f1220db8SAlexander V. Chernikov 
1499f1220db8SAlexander V. Chernikov 	count = i->count;
1500f1220db8SAlexander V. Chernikov 	while (count > 0) {
150181d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
150281d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
150381d3153dSAlexander V. Chernikov 		count--;
150481d3153dSAlexander V. Chernikov 	}
150581d3153dSAlexander V. Chernikov }
150681d3153dSAlexander V. Chernikov 
150781d3153dSAlexander V. Chernikov static void
150881d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
150981d3153dSAlexander V. Chernikov {
1510914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1511914bffb6SAlexander V. Chernikov 	void *paddr;
151281d3153dSAlexander V. Chernikov 	uint32_t tval;
1513914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
151481d3153dSAlexander V. Chernikov 
151581d3153dSAlexander V. Chernikov 	tval = tent->value;
151681d3153dSAlexander V. Chernikov 
1517adf3b2b9SAlexander V. Chernikov 	if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
1518914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1519914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1520914bffb6SAlexander V. Chernikov 	} else
1521914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1522914bffb6SAlexander V. Chernikov 
1523f1220db8SAlexander V. Chernikov 	switch (i->type) {
1524f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1525f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
152681d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1527914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1528f1220db8SAlexander V. Chernikov 		break;
1529f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1530f1220db8SAlexander V. Chernikov 		/* Interface names */
1531914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1532b23d5de9SAlexander V. Chernikov 		break;
1533b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1534b23d5de9SAlexander V. Chernikov 		/* numbers */
1535914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1536b23d5de9SAlexander V. Chernikov 		break;
1537914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1538914bffb6SAlexander V. Chernikov 		/* flows */
1539914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1540914bffb6SAlexander V. Chernikov 		comma = "";
1541914bffb6SAlexander V. Chernikov 
1542914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1543914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1544914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1545914bffb6SAlexander V. Chernikov 			else
1546914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1547914bffb6SAlexander V. Chernikov 
1548914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1549914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1550914bffb6SAlexander V. Chernikov 			comma = ",";
1551914bffb6SAlexander V. Chernikov 		}
1552914bffb6SAlexander V. Chernikov 
1553914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1554914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1555914bffb6SAlexander V. Chernikov 			comma = ",";
1556914bffb6SAlexander V. Chernikov 		}
1557914bffb6SAlexander V. Chernikov 
1558914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1559914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1560914bffb6SAlexander V. Chernikov 			comma = ",";
1561914bffb6SAlexander V. Chernikov 		}
1562914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1563914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1564914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1565914bffb6SAlexander V. Chernikov 			else
1566914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1567914bffb6SAlexander V. Chernikov 
1568914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1569914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1570914bffb6SAlexander V. Chernikov 			comma = ",";
1571914bffb6SAlexander V. Chernikov 		}
1572914bffb6SAlexander V. Chernikov 
1573914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1574914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1575914bffb6SAlexander V. Chernikov 			comma = ",";
1576914bffb6SAlexander V. Chernikov 		}
1577914bffb6SAlexander V. Chernikov 
1578914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1579f1220db8SAlexander V. Chernikov 	}
1580f1220db8SAlexander V. Chernikov }
1581f1220db8SAlexander V. Chernikov 
15829d099b4fSAlexander V. Chernikov static int
15839d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
15849d099b4fSAlexander V. Chernikov {
15859d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
15869d099b4fSAlexander V. Chernikov 	size_t sz;
15879d099b4fSAlexander V. Chernikov 	int error;
15889d099b4fSAlexander V. Chernikov 
15899d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
15909d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
15919d099b4fSAlexander V. Chernikov 
15929d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
15939d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
15949d099b4fSAlexander V. Chernikov 		return (error);
15959d099b4fSAlexander V. Chernikov 
15969d099b4fSAlexander V. Chernikov 	sz = req.size;
15979d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
15989d099b4fSAlexander V. Chernikov 		return (ENOMEM);
15999d099b4fSAlexander V. Chernikov 
16009d099b4fSAlexander V. Chernikov 	olh->size = sz;
16019d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
16029d099b4fSAlexander V. Chernikov 		free(olh);
16039d099b4fSAlexander V. Chernikov 		return (error);
16049d099b4fSAlexander V. Chernikov 	}
16059d099b4fSAlexander V. Chernikov 
16069d099b4fSAlexander V. Chernikov 	*polh = olh;
16079d099b4fSAlexander V. Chernikov 	return (0);
16089d099b4fSAlexander V. Chernikov }
16099d099b4fSAlexander V. Chernikov 
16109d099b4fSAlexander V. Chernikov void
16119d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
16129d099b4fSAlexander V. Chernikov {
16139d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
16149d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
16159d099b4fSAlexander V. Chernikov 	int error, i;
16169d099b4fSAlexander V. Chernikov 	const char *atype;
16179d099b4fSAlexander V. Chernikov 
16189d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
16199d099b4fSAlexander V. Chernikov 	if (error != 0)
16209d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
16219d099b4fSAlexander V. Chernikov 
16229d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
16239d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
16249d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
16259d099b4fSAlexander V. Chernikov 			atype = "unknown";
16268ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
16278ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
16289d099b4fSAlexander V. Chernikov 
16299d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
16309d099b4fSAlexander V. Chernikov 	}
16319d099b4fSAlexander V. Chernikov 
16329d099b4fSAlexander V. Chernikov 	free(olh);
16339d099b4fSAlexander V. Chernikov }
16349d099b4fSAlexander V. Chernikov 
16356c2997ffSAlexander V. Chernikov int
16366c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
16376c2997ffSAlexander V. Chernikov {
16386c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
16396c2997ffSAlexander V. Chernikov 
16406c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
16416c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
16426c2997ffSAlexander V. Chernikov 
16436c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
16446c2997ffSAlexander V. Chernikov 		return (-1);
16456c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
16466c2997ffSAlexander V. Chernikov 		return (1);
16476c2997ffSAlexander V. Chernikov 
16486c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
16496c2997ffSAlexander V. Chernikov 		return (-1);
16506c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
16516c2997ffSAlexander V. Chernikov 		return (1);
16526c2997ffSAlexander V. Chernikov 
16536c2997ffSAlexander V. Chernikov 	return (0);
16546c2997ffSAlexander V. Chernikov }
1655563b5ab1SAlexander V. Chernikov 
1656563b5ab1SAlexander V. Chernikov int
16576c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1658563b5ab1SAlexander V. Chernikov {
1659563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1660563b5ab1SAlexander V. Chernikov 	uint16_t key;
1661563b5ab1SAlexander V. Chernikov 
1662563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1663563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1664563b5ab1SAlexander V. Chernikov 
1665563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1666563b5ab1SAlexander V. Chernikov 		return (-1);
1667563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1668563b5ab1SAlexander V. Chernikov 		return (1);
1669563b5ab1SAlexander V. Chernikov 
1670563b5ab1SAlexander V. Chernikov 	return (0);
1671563b5ab1SAlexander V. Chernikov }
1672563b5ab1SAlexander V. Chernikov 
1673563b5ab1SAlexander V. Chernikov /*
1674563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1675563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1676563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1677563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1678563b5ab1SAlexander V. Chernikov  *
1679563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1680563b5ab1SAlexander V. Chernikov  */
1681563b5ab1SAlexander V. Chernikov char *
1682563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1683563b5ab1SAlexander V. Chernikov {
1684563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1685563b5ab1SAlexander V. Chernikov 
1686563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
16876c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1688563b5ab1SAlexander V. Chernikov 
1689563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1690563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1691563b5ab1SAlexander V. Chernikov 
1692563b5ab1SAlexander V. Chernikov 	return (NULL);
1693563b5ab1SAlexander V. Chernikov }
1694563b5ab1SAlexander V. Chernikov 
16956c2997ffSAlexander V. Chernikov void
16966c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
16976c2997ffSAlexander V. Chernikov {
16986c2997ffSAlexander V. Chernikov 
16996c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
17006c2997ffSAlexander V. Chernikov }
17016c2997ffSAlexander V. Chernikov 
17026c2997ffSAlexander V. Chernikov int
17036c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
17046c2997ffSAlexander V. Chernikov {
17056c2997ffSAlexander V. Chernikov 	int c, i, l;
17066c2997ffSAlexander V. Chernikov 
17076c2997ffSAlexander V. Chernikov 	/*
17086c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
17096c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1710ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
17116c2997ffSAlexander V. Chernikov 	 */
17126c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
17136c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
17146c2997ffSAlexander V. Chernikov 		return (EINVAL);
17156c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
17166c2997ffSAlexander V. Chernikov 		c = tablename[i];
17176c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
17186c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
17196c2997ffSAlexander V. Chernikov 			continue;
17206c2997ffSAlexander V. Chernikov 		return (EINVAL);
17216c2997ffSAlexander V. Chernikov 	}
17226c2997ffSAlexander V. Chernikov 
1723ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1724ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1725ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1726ac35ff17SAlexander V. Chernikov 
17276c2997ffSAlexander V. Chernikov 	return (0);
17286c2997ffSAlexander V. Chernikov }
17296c2997ffSAlexander V. Chernikov 
1730