xref: /freebsd/sbin/ipfw/tables.c (revision fd0869d54785422f077f7daa9c3e1838b215343f)
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 <stdio.h>
34f1220db8SAlexander V. Chernikov #include <stdlib.h>
35f1220db8SAlexander V. Chernikov #include <string.h>
36f1220db8SAlexander V. Chernikov #include <sysexits.h>
37f1220db8SAlexander V. Chernikov 
38f1220db8SAlexander V. Chernikov #include <net/if.h>
39f1220db8SAlexander V. Chernikov #include <netinet/in.h>
40f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h>
41f1220db8SAlexander V. Chernikov #include <arpa/inet.h>
42f1220db8SAlexander V. Chernikov 
43f1220db8SAlexander V. Chernikov #include "ipfw2.h"
44f1220db8SAlexander V. Chernikov 
45f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header);
46ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
473a845e10SAlexander V. Chernikov     int add, int quiet, int update, int atomic);
48ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh);
49ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh);
50ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
51adf3b2b9SAlexander V. Chernikov static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i);
5246d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second);
53adf3b2b9SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
54adf3b2b9SAlexander V. Chernikov static void table_modify(ipfw_obj_header *oh, int ac, char *av[]);
55adf3b2b9SAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
564f43138aSAlexander V. Chernikov static void table_lock(ipfw_obj_header *oh, int lock);
5746d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second);
58ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
59f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
60ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
61ac35ff17SAlexander V. Chernikov     uint16_t uidx);
62f1220db8SAlexander V. Chernikov 
63f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
64f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
65720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh);
66f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
6781d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
68f1220db8SAlexander V. Chernikov 
69ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7035df97d0SAlexander V. Chernikov     char *key, int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
71ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
72ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
73ac35ff17SAlexander V. Chernikov 
74f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
75f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
76f1220db8SAlexander V. Chernikov 
77f1220db8SAlexander V. Chernikov #ifndef s6_addr32
78f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
79f1220db8SAlexander V. Chernikov #endif
80f1220db8SAlexander V. Chernikov 
81ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
82ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
83ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
84b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
85914bffb6SAlexander V. Chernikov       { "flow",		IPFW_TABLE_FLOW },
86ac35ff17SAlexander V. Chernikov       { NULL, 0 }
87ac35ff17SAlexander V. Chernikov };
88ac35ff17SAlexander V. Chernikov 
89ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
90ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
91ac35ff17SAlexander V. Chernikov       { NULL, 0 }
92ac35ff17SAlexander V. Chernikov };
93ac35ff17SAlexander V. Chernikov 
94adf3b2b9SAlexander V. Chernikov static struct _s_x tablefvaltypes[] = {
95adf3b2b9SAlexander V. Chernikov       { "ip",		IPFW_VFTYPE_IP },
96adf3b2b9SAlexander V. Chernikov       { "number",	IPFW_VFTYPE_U32 },
97adf3b2b9SAlexander V. Chernikov       { NULL, 0 }
98adf3b2b9SAlexander V. Chernikov };
99adf3b2b9SAlexander V. Chernikov 
100ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
101ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
102ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
10346d52008SAlexander V. Chernikov       { "create",	TOK_CREATE },
104ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
105ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
106adf3b2b9SAlexander V. Chernikov       { "modify",	TOK_MODIFY },
10746d52008SAlexander V. Chernikov       { "swap",		TOK_SWAP },
108ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
109358b9d09SAlexander V. Chernikov       { "detail",	TOK_DETAIL },
110ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
11181d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
1123a845e10SAlexander V. Chernikov       { "atomic",	TOK_ATOMIC },
1134f43138aSAlexander V. Chernikov       { "lock",		TOK_LOCK },
1144f43138aSAlexander V. Chernikov       { "unlock",	TOK_UNLOCK },
115ac35ff17SAlexander V. Chernikov       { NULL, 0 }
116ac35ff17SAlexander V. Chernikov };
117ac35ff17SAlexander V. Chernikov 
118f1220db8SAlexander V. Chernikov static int
119f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
120f1220db8SAlexander V. Chernikov {
121f1220db8SAlexander V. Chernikov 	struct hostent *he;
122f1220db8SAlexander V. Chernikov 
123f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
124f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
125f1220db8SAlexander V. Chernikov 			return(-1);
126f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
127f1220db8SAlexander V. Chernikov 	}
128f1220db8SAlexander V. Chernikov 	return(0);
129f1220db8SAlexander V. Chernikov }
130f1220db8SAlexander V. Chernikov 
131be695df9SAlexander V. Chernikov static int
132be695df9SAlexander V. Chernikov get_token(struct _s_x *table, char *string, char *errbase)
133be695df9SAlexander V. Chernikov {
134be695df9SAlexander V. Chernikov 	int tcmd;
135be695df9SAlexander V. Chernikov 
136be695df9SAlexander V. Chernikov 	if ((tcmd = match_token_relaxed(table, string)) < 0)
137be695df9SAlexander V. Chernikov 		errx(EX_USAGE, "%s %s %s",
138be695df9SAlexander V. Chernikov 		    (tcmd == 0) ? "invalid" : "ambiguous", errbase, string);
139be695df9SAlexander V. Chernikov 
140be695df9SAlexander V. Chernikov 	return (tcmd);
141be695df9SAlexander V. Chernikov }
142be695df9SAlexander V. Chernikov 
143f1220db8SAlexander V. Chernikov /*
144f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
145ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
146be695df9SAlexander V. Chernikov  * 	ipfw table NAME modify ...
147ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
148be695df9SAlexander V. Chernikov  * 	ipfw table NAME swap NAME
149be695df9SAlexander V. Chernikov  * 	ipfw table NAME lock
150be695df9SAlexander V. Chernikov  * 	ipfw table NAME unlock
151ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
152be695df9SAlexander V. Chernikov  * 	ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] ..
153be695df9SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen] [addr[/masklen]] ..
154be695df9SAlexander V. Chernikov  * 	ipfw table NAME lookup addr
155ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
156ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
157ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
158be695df9SAlexander V. Chernikov  * 	ipfw table {NAME | all} detail
159f1220db8SAlexander V. Chernikov  */
160f1220db8SAlexander V. Chernikov void
161f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
162f1220db8SAlexander V. Chernikov {
163ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
1643a845e10SAlexander V. Chernikov 	int atomic, error, tcmd;
165ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
166ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
167f1220db8SAlexander V. Chernikov 	char *tablename;
168ac35ff17SAlexander V. Chernikov 	uint32_t set;
169358b9d09SAlexander V. Chernikov 	void *arg;
170f1220db8SAlexander V. Chernikov 
171ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
172ac35ff17SAlexander V. Chernikov 	is_all = 0;
173ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
174ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
175ac35ff17SAlexander V. Chernikov 	else
176ac35ff17SAlexander V. Chernikov 		set = 0;
177f1220db8SAlexander V. Chernikov 
178f1220db8SAlexander V. Chernikov 	ac--; av++;
1799d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
180f1220db8SAlexander V. Chernikov 	tablename = *av;
181f1220db8SAlexander V. Chernikov 
182ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
183ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
184ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
185ac35ff17SAlexander V. Chernikov 	} else {
186ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
187ac35ff17SAlexander V. Chernikov 			is_all = 1;
188ac35ff17SAlexander V. Chernikov 		else
189ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
190ac35ff17SAlexander V. Chernikov 	}
191ac35ff17SAlexander V. Chernikov 	ac--; av++;
1929d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
193ac35ff17SAlexander V. Chernikov 
194be695df9SAlexander V. Chernikov 	tcmd = get_token(tablecmds, *av, "table command");
1953a845e10SAlexander V. Chernikov 	/* Check if atomic operation was requested */
1963a845e10SAlexander V. Chernikov 	atomic = 0;
1973a845e10SAlexander V. Chernikov 	if (tcmd == TOK_ATOMIC) {
1983a845e10SAlexander V. Chernikov 		ac--; av++;
1993a845e10SAlexander V. Chernikov 		NEED1("atomic needs command");
200be695df9SAlexander V. Chernikov 		tcmd = get_token(tablecmds, *av, "table command");
2013a845e10SAlexander V. Chernikov 		switch (tcmd) {
2023a845e10SAlexander V. Chernikov 		case TOK_ADD:
2033a845e10SAlexander V. Chernikov 			break;
2043a845e10SAlexander V. Chernikov 		default:
2053a845e10SAlexander V. Chernikov 			errx(EX_USAGE, "atomic is not compatible with %s", *av);
2063a845e10SAlexander V. Chernikov 		}
2073a845e10SAlexander V. Chernikov 		atomic = 1;
2083a845e10SAlexander V. Chernikov 	}
209ac35ff17SAlexander V. Chernikov 
210ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
211ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
212ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
213358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
214ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
215ac35ff17SAlexander V. Chernikov 		break;
216ac35ff17SAlexander V. Chernikov 	default:
217ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
218ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
219ac35ff17SAlexander V. Chernikov 	}
220ac35ff17SAlexander V. Chernikov 
221ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
222ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
223ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
224f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
225f1220db8SAlexander V. Chernikov 		ac--; av++;
2263a845e10SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet,
2273a845e10SAlexander V. Chernikov 		    co.do_quiet, atomic);
228ac35ff17SAlexander V. Chernikov 		break;
229ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
230f1220db8SAlexander V. Chernikov 		ac--; av++;
231ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
232ac35ff17SAlexander V. Chernikov 		break;
233adf3b2b9SAlexander V. Chernikov 	case TOK_MODIFY:
234adf3b2b9SAlexander V. Chernikov 		ac--; av++;
235adf3b2b9SAlexander V. Chernikov 		table_modify(&oh, ac, av);
236adf3b2b9SAlexander V. Chernikov 		break;
237ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
238ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
239ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
240ac35ff17SAlexander V. Chernikov 		break;
241ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
242f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
243ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
244f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
245f1220db8SAlexander V. Chernikov 				    tablename);
246f1220db8SAlexander V. Chernikov 		} else {
247ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
248f1220db8SAlexander V. Chernikov 			if (error != 0)
249f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
250f1220db8SAlexander V. Chernikov 		}
251ac35ff17SAlexander V. Chernikov 		break;
25246d52008SAlexander V. Chernikov 	case TOK_SWAP:
25346d52008SAlexander V. Chernikov 		ac--; av++;
25446d52008SAlexander V. Chernikov 		NEED1("second table name required");
25546d52008SAlexander V. Chernikov 		table_swap(&oh, *av);
25646d52008SAlexander V. Chernikov 		break;
2574f43138aSAlexander V. Chernikov 	case TOK_LOCK:
2584f43138aSAlexander V. Chernikov 	case TOK_UNLOCK:
2594f43138aSAlexander V. Chernikov 		table_lock(&oh, (tcmd == TOK_LOCK));
2604f43138aSAlexander V. Chernikov 		break;
261358b9d09SAlexander V. Chernikov 	case TOK_DETAIL:
262ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
263358b9d09SAlexander V. Chernikov 		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
264f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
265ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
266f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
267358b9d09SAlexander V. Chernikov 			table_show_info(&i, arg);
268f1220db8SAlexander V. Chernikov 		} else {
269358b9d09SAlexander V. Chernikov 			error = tables_foreach(table_show_info, arg, 1);
270f1220db8SAlexander V. Chernikov 			if (error != 0)
271f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
272f1220db8SAlexander V. Chernikov 		}
273ac35ff17SAlexander V. Chernikov 		break;
274ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
275ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
276ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
277ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
278ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
279ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
280f1220db8SAlexander V. Chernikov 		} else {
281ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
282ac35ff17SAlexander V. Chernikov 			if (error != 0)
283ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
284f1220db8SAlexander V. Chernikov 		}
285ac35ff17SAlexander V. Chernikov 		break;
28681d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
28781d3153dSAlexander V. Chernikov 		ac--; av++;
28881d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
28981d3153dSAlexander V. Chernikov 		break;
290f1220db8SAlexander V. Chernikov 	}
291f1220db8SAlexander V. Chernikov }
292f1220db8SAlexander V. Chernikov 
293f1220db8SAlexander V. Chernikov static void
294ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
295f1220db8SAlexander V. Chernikov {
296f1220db8SAlexander V. Chernikov 
297563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
298f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
299f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
300ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
301f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
302f1220db8SAlexander V. Chernikov }
303f1220db8SAlexander V. Chernikov 
304f1220db8SAlexander V. Chernikov static void
305f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
306f1220db8SAlexander V. Chernikov {
307f1220db8SAlexander V. Chernikov 
308f1220db8SAlexander V. Chernikov 	oh->idx = 1;
30981d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
310ac35ff17SAlexander V. Chernikov }
311ac35ff17SAlexander V. Chernikov 
312ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
313ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE },
314adf3b2b9SAlexander V. Chernikov       { "ftype",	TOK_FTYPE },
315ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
316ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
3174c0c07a5SAlexander V. Chernikov       { "limit",	TOK_LIMIT },
3184f43138aSAlexander V. Chernikov       { "locked",	TOK_LOCK },
319ac35ff17SAlexander V. Chernikov       { NULL, 0 }
320ac35ff17SAlexander V. Chernikov };
321ac35ff17SAlexander V. Chernikov 
322914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
323914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
324914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
325914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
326914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
327914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
328914bffb6SAlexander V. Chernikov       { NULL, 0 }
329914bffb6SAlexander V. Chernikov };
330914bffb6SAlexander V. Chernikov 
331914bffb6SAlexander V. Chernikov int
332914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
333914bffb6SAlexander V. Chernikov {
334914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
335914bffb6SAlexander V. Chernikov 
336914bffb6SAlexander V. Chernikov 	/* Parse type options */
337914bffb6SAlexander V. Chernikov 	switch(ttype) {
338914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
339914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
340914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
341914bffb6SAlexander V. Chernikov 		    &fclear);
342914bffb6SAlexander V. Chernikov 		*tflags = fset;
343914bffb6SAlexander V. Chernikov 		break;
344914bffb6SAlexander V. Chernikov 	default:
345914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
346914bffb6SAlexander V. Chernikov 	}
347914bffb6SAlexander V. Chernikov 
348914bffb6SAlexander V. Chernikov 	return (0);
349914bffb6SAlexander V. Chernikov }
350914bffb6SAlexander V. Chernikov 
351914bffb6SAlexander V. Chernikov void
352914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
353914bffb6SAlexander V. Chernikov {
354914bffb6SAlexander V. Chernikov 	const char *tname;
355914bffb6SAlexander V. Chernikov 	int l;
356914bffb6SAlexander V. Chernikov 
357914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
358914bffb6SAlexander V. Chernikov 		tname = "unknown";
359914bffb6SAlexander V. Chernikov 
360914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
361914bffb6SAlexander V. Chernikov 	tbuf += l;
362914bffb6SAlexander V. Chernikov 	size -= l;
363914bffb6SAlexander V. Chernikov 
364914bffb6SAlexander V. Chernikov 	switch(type) {
365914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
366914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
367914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
368914bffb6SAlexander V. Chernikov 			l--;
369914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
370914bffb6SAlexander V. Chernikov 		}
371914bffb6SAlexander V. Chernikov 		break;
372914bffb6SAlexander V. Chernikov 	}
373914bffb6SAlexander V. Chernikov }
374914bffb6SAlexander V. Chernikov 
375ac35ff17SAlexander V. Chernikov /*
376ac35ff17SAlexander V. Chernikov  * Creates new table
377ac35ff17SAlexander V. Chernikov  *
378ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
379ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
380ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
381ac35ff17SAlexander V. Chernikov  */
382ac35ff17SAlexander V. Chernikov static void
383ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
384ac35ff17SAlexander V. Chernikov {
385ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
386ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
387ac35ff17SAlexander V. Chernikov 	size_t sz;
388914bffb6SAlexander V. Chernikov 	char *p;
389ac35ff17SAlexander V. Chernikov 	char tbuf[128];
390ac35ff17SAlexander V. Chernikov 
391ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
392ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
393ac35ff17SAlexander V. Chernikov 
394ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
395be695df9SAlexander V. Chernikov 		tcmd = get_token(tablenewcmds, *av, "option");
396ac35ff17SAlexander V. Chernikov 		ac--; av++;
397ac35ff17SAlexander V. Chernikov 
398ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
3994c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
4004c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
4014c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
4024c0c07a5SAlexander V. Chernikov 			ac--; av++;
4034c0c07a5SAlexander V. Chernikov 			break;
404ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
405ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
406914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
407914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
408914bffb6SAlexander V. Chernikov 				*p++ = '\0';
409ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
410914bffb6SAlexander V. Chernikov 			if (val == -1) {
411914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
412914bffb6SAlexander V. Chernikov 				    ", ");
413914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
414914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
415ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
416914bffb6SAlexander V. Chernikov 			}
417914bffb6SAlexander V. Chernikov 			xi.type = val;
418914bffb6SAlexander V. Chernikov 			if (p != NULL) {
419914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
420914bffb6SAlexander V. Chernikov 				if (error != 0)
421914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
422914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
423914bffb6SAlexander V. Chernikov 			}
424914bffb6SAlexander V. Chernikov 			ac--; av++;
425ac35ff17SAlexander V. Chernikov 			break;
426ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
427ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
428ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
429ac35ff17SAlexander V. Chernikov 			if (val != -1) {
430ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
431ac35ff17SAlexander V. Chernikov 				ac--; av++;
432ac35ff17SAlexander V. Chernikov 				break;
433ac35ff17SAlexander V. Chernikov 			}
434ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
435ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
436ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
437ac35ff17SAlexander V. Chernikov 			break;
438adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
439adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
440adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
441adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
442adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
443adf3b2b9SAlexander V. Chernikov 				ac--; av++;
444adf3b2b9SAlexander V. Chernikov 				break;
445adf3b2b9SAlexander V. Chernikov 			}
446adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
447adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown format type: %s. Supported: %s",
448adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
449adf3b2b9SAlexander V. Chernikov 			break;
450ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
451ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
452ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
453ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
454ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
455ac35ff17SAlexander V. Chernikov 			ac--; av++;
456ac35ff17SAlexander V. Chernikov 			break;
4574f43138aSAlexander V. Chernikov 		case TOK_LOCK:
4584f43138aSAlexander V. Chernikov 			xi.flags |= IPFW_TGFLAGS_LOCKED;
4594f43138aSAlexander V. Chernikov 			break;
460ac35ff17SAlexander V. Chernikov 		}
461ac35ff17SAlexander V. Chernikov 	}
462ac35ff17SAlexander V. Chernikov 
463*fd0869d5SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
464*fd0869d5SAlexander V. Chernikov 	if (xi.algoname[0] == '\0' && xi.type == 0)
465*fd0869d5SAlexander V. Chernikov 		xi.type = IPFW_TABLE_CIDR;
466*fd0869d5SAlexander V. Chernikov 	if (xi.vtype == 0)
467*fd0869d5SAlexander V. Chernikov 		xi.vtype = IPFW_VTYPE_U32;
468*fd0869d5SAlexander V. Chernikov 
469ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
470ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
471f1220db8SAlexander V. Chernikov }
472f1220db8SAlexander V. Chernikov 
473f1220db8SAlexander V. Chernikov /*
474ac35ff17SAlexander V. Chernikov  * Creates new table
475ac35ff17SAlexander V. Chernikov  *
476ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
477ac35ff17SAlexander V. Chernikov  *
478f1220db8SAlexander V. Chernikov  * Returns 0 on success.
479f1220db8SAlexander V. Chernikov  */
480f1220db8SAlexander V. Chernikov static int
481ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
482f1220db8SAlexander V. Chernikov {
483ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
484ac35ff17SAlexander V. Chernikov 	int error;
485f1220db8SAlexander V. Chernikov 
486ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
487ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
488ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
489ac35ff17SAlexander V. Chernikov 
490ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
491ac35ff17SAlexander V. Chernikov 
492ac35ff17SAlexander V. Chernikov 	return (error);
493ac35ff17SAlexander V. Chernikov }
494ac35ff17SAlexander V. Chernikov 
495ac35ff17SAlexander V. Chernikov /*
496adf3b2b9SAlexander V. Chernikov  * Modifies existing table
497adf3b2b9SAlexander V. Chernikov  *
498adf3b2b9SAlexander V. Chernikov  * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
499adf3b2b9SAlexander V. Chernikov  */
500adf3b2b9SAlexander V. Chernikov static void
501adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[])
502adf3b2b9SAlexander V. Chernikov {
503adf3b2b9SAlexander V. Chernikov 	ipfw_xtable_info xi;
504adf3b2b9SAlexander V. Chernikov 	int error, tcmd, val;
505adf3b2b9SAlexander V. Chernikov 	size_t sz;
506adf3b2b9SAlexander V. Chernikov 	char tbuf[128];
507adf3b2b9SAlexander V. Chernikov 
508adf3b2b9SAlexander V. Chernikov 	sz = sizeof(tbuf);
509adf3b2b9SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
510adf3b2b9SAlexander V. Chernikov 
511adf3b2b9SAlexander V. Chernikov 	while (ac > 0) {
512be695df9SAlexander V. Chernikov 		tcmd = get_token(tablenewcmds, *av, "option");
513adf3b2b9SAlexander V. Chernikov 		ac--; av++;
514adf3b2b9SAlexander V. Chernikov 
515adf3b2b9SAlexander V. Chernikov 		switch (tcmd) {
516adf3b2b9SAlexander V. Chernikov 		case TOK_LIMIT:
517adf3b2b9SAlexander V. Chernikov 			NEED1("limit value required");
518adf3b2b9SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
519adf3b2b9SAlexander V. Chernikov 			xi.mflags |= IPFW_TMFLAGS_LIMIT;
520adf3b2b9SAlexander V. Chernikov 			ac--; av++;
521adf3b2b9SAlexander V. Chernikov 			break;
522adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
523adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
524adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
525adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
526adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
527adf3b2b9SAlexander V. Chernikov 				xi.mflags |= IPFW_TMFLAGS_FTYPE;
528adf3b2b9SAlexander V. Chernikov 				ac--; av++;
529adf3b2b9SAlexander V. Chernikov 				break;
530adf3b2b9SAlexander V. Chernikov 			}
531adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
532adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
533adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
534adf3b2b9SAlexander V. Chernikov 			break;
535adf3b2b9SAlexander V. Chernikov 		}
536adf3b2b9SAlexander V. Chernikov 	}
537adf3b2b9SAlexander V. Chernikov 
538adf3b2b9SAlexander V. Chernikov 	if ((error = table_do_modify(oh, &xi)) != 0)
539adf3b2b9SAlexander V. Chernikov 		err(EX_OSERR, "Table modification failed");
540adf3b2b9SAlexander V. Chernikov }
541adf3b2b9SAlexander V. Chernikov 
542adf3b2b9SAlexander V. Chernikov /*
543adf3b2b9SAlexander V. Chernikov  * Modifies existing table.
544adf3b2b9SAlexander V. Chernikov  *
545adf3b2b9SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
546adf3b2b9SAlexander V. Chernikov  *
547adf3b2b9SAlexander V. Chernikov  * Returns 0 on success.
548adf3b2b9SAlexander V. Chernikov  */
549adf3b2b9SAlexander V. Chernikov static int
550adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
551adf3b2b9SAlexander V. Chernikov {
552adf3b2b9SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
553adf3b2b9SAlexander V. Chernikov 	int error;
554adf3b2b9SAlexander V. Chernikov 
555adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
556adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
557adf3b2b9SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
558adf3b2b9SAlexander V. Chernikov 
559adf3b2b9SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
560adf3b2b9SAlexander V. Chernikov 
561adf3b2b9SAlexander V. Chernikov 	return (error);
562adf3b2b9SAlexander V. Chernikov }
5634f43138aSAlexander V. Chernikov 
5644f43138aSAlexander V. Chernikov /*
5654f43138aSAlexander V. Chernikov  * Locks or unlocks given table
5664f43138aSAlexander V. Chernikov  */
5674f43138aSAlexander V. Chernikov static void
5684f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock)
5694f43138aSAlexander V. Chernikov {
5704f43138aSAlexander V. Chernikov 	ipfw_xtable_info xi;
5714f43138aSAlexander V. Chernikov 	int error;
5724f43138aSAlexander V. Chernikov 
5734f43138aSAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
5744f43138aSAlexander V. Chernikov 
5754f43138aSAlexander V. Chernikov 	xi.mflags |= IPFW_TMFLAGS_LOCK;
5764f43138aSAlexander V. Chernikov 	xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0;
5774f43138aSAlexander V. Chernikov 
5784f43138aSAlexander V. Chernikov 	if ((error = table_do_modify(oh, &xi)) != 0)
5794f43138aSAlexander V. Chernikov 		err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock");
5804f43138aSAlexander V. Chernikov }
5814f43138aSAlexander V. Chernikov 
582adf3b2b9SAlexander V. Chernikov /*
583ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
584ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
585ac35ff17SAlexander V. Chernikov  */
586ac35ff17SAlexander V. Chernikov static int
587ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
588ac35ff17SAlexander V. Chernikov {
589ac35ff17SAlexander V. Chernikov 
590ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
591f1220db8SAlexander V. Chernikov 		return (-1);
592f1220db8SAlexander V. Chernikov 
593f1220db8SAlexander V. Chernikov 	return (0);
594f1220db8SAlexander V. Chernikov }
595f1220db8SAlexander V. Chernikov 
596f1220db8SAlexander V. Chernikov /*
597ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
598f1220db8SAlexander V. Chernikov  * Returns 0 on success.
599f1220db8SAlexander V. Chernikov  */
600f1220db8SAlexander V. Chernikov static int
601ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
602f1220db8SAlexander V. Chernikov {
603f1220db8SAlexander V. Chernikov 
604ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
605f1220db8SAlexander V. Chernikov 		return (-1);
606f1220db8SAlexander V. Chernikov 
607f1220db8SAlexander V. Chernikov 	return (0);
608f1220db8SAlexander V. Chernikov }
609f1220db8SAlexander V. Chernikov 
61046d52008SAlexander V. Chernikov static int
61146d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second)
61246d52008SAlexander V. Chernikov {
61346d52008SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
61446d52008SAlexander V. Chernikov 	int error;
61546d52008SAlexander V. Chernikov 
61646d52008SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
61746d52008SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
61846d52008SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
61946d52008SAlexander V. Chernikov 	table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
62046d52008SAlexander V. Chernikov 
62146d52008SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
62246d52008SAlexander V. Chernikov 
62346d52008SAlexander V. Chernikov 	return (error);
62446d52008SAlexander V. Chernikov }
62546d52008SAlexander V. Chernikov 
62646d52008SAlexander V. Chernikov /*
62746d52008SAlexander V. Chernikov  * Swaps given table with @second one.
62846d52008SAlexander V. Chernikov  */
62946d52008SAlexander V. Chernikov static int
63046d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second)
63146d52008SAlexander V. Chernikov {
63246d52008SAlexander V. Chernikov 	int error;
63346d52008SAlexander V. Chernikov 
63446d52008SAlexander V. Chernikov 	if (table_check_name(second) != 0)
63546d52008SAlexander V. Chernikov 		errx(EX_USAGE, "table name %s is invalid", second);
63646d52008SAlexander V. Chernikov 
63746d52008SAlexander V. Chernikov 	error = table_do_swap(oh, second);
63846d52008SAlexander V. Chernikov 
63946d52008SAlexander V. Chernikov 	switch (error) {
64046d52008SAlexander V. Chernikov 	case EINVAL:
64146d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check types");
64246d52008SAlexander V. Chernikov 	case EFBIG:
64346d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check limits");
64446d52008SAlexander V. Chernikov 	}
64546d52008SAlexander V. Chernikov 
64646d52008SAlexander V. Chernikov 	return (0);
64746d52008SAlexander V. Chernikov }
64846d52008SAlexander V. Chernikov 
64946d52008SAlexander V. Chernikov 
650f1220db8SAlexander V. Chernikov /*
651ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
652f1220db8SAlexander V. Chernikov  * it inside @i.
653f1220db8SAlexander V. Chernikov  * Returns 0 on success.
654f1220db8SAlexander V. Chernikov  */
655f1220db8SAlexander V. Chernikov static int
656ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
657f1220db8SAlexander V. Chernikov {
658f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
659ac35ff17SAlexander V. Chernikov 	int error;
660f1220db8SAlexander V. Chernikov 	size_t sz;
661f1220db8SAlexander V. Chernikov 
662f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
663f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
664ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
665f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
666f1220db8SAlexander V. Chernikov 
667ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
668ac35ff17SAlexander V. Chernikov 		return (error);
669f1220db8SAlexander V. Chernikov 
670f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
671ac35ff17SAlexander V. Chernikov 		return (EINVAL);
672f1220db8SAlexander V. Chernikov 
673f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
674f1220db8SAlexander V. Chernikov 
675f1220db8SAlexander V. Chernikov 	return (0);
676f1220db8SAlexander V. Chernikov }
677f1220db8SAlexander V. Chernikov 
6785f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
6795f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
6805f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
6815f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
6825f379342SAlexander V. Chernikov       { NULL, 0 }
6835f379342SAlexander V. Chernikov };
6845f379342SAlexander V. Chernikov 
6855f379342SAlexander V. Chernikov struct ta_cldata {
6865f379342SAlexander V. Chernikov 	uint8_t		taclass;
6875f379342SAlexander V. Chernikov 	uint8_t		spare4;
6885f379342SAlexander V. Chernikov 	uint16_t	itemsize;
6895f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
6905f379342SAlexander V. Chernikov 	uint32_t	size;
6915f379342SAlexander V. Chernikov 	uint32_t	count;
6925f379342SAlexander V. Chernikov };
6935f379342SAlexander V. Chernikov 
6945f379342SAlexander V. Chernikov /*
6955f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
6965f379342SAlexander V. Chernikov  */
6975f379342SAlexander V. Chernikov static void
6985f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
6995f379342SAlexander V. Chernikov     const char *af, const char *taclass)
7005f379342SAlexander V. Chernikov {
7015f379342SAlexander V. Chernikov 
7025f379342SAlexander V. Chernikov 	switch (d->taclass) {
7035f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
7045f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
7055f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
7065f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
7075f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
7085f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
7095f379342SAlexander V. Chernikov 		else
7105f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
7115f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
7125f379342SAlexander V. Chernikov 			    d->size, d->count,
7135f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
7145f379342SAlexander V. Chernikov 		break;
7155f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
7165f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
7175f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
7185f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
7195f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
7205f379342SAlexander V. Chernikov 		else
7215f379342SAlexander V. Chernikov 			printf("  items: %u "
7225f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
7235f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
7245f379342SAlexander V. Chernikov 		break;
7255f379342SAlexander V. Chernikov 	default:
7265f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
7275f379342SAlexander V. Chernikov 	}
7285f379342SAlexander V. Chernikov }
7295f379342SAlexander V. Chernikov 
730f1220db8SAlexander V. Chernikov /*
731f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
732f1220db8SAlexander V. Chernikov  */
733f1220db8SAlexander V. Chernikov static int
734f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
735f1220db8SAlexander V. Chernikov {
736adf3b2b9SAlexander V. Chernikov 	const char *vtype, *vftype;
7375f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
7385f379342SAlexander V. Chernikov 	int afdata, afitem;
7395f379342SAlexander V. Chernikov 	struct ta_cldata d;
740adf3b2b9SAlexander V. Chernikov 	char ttype[64], tvtype[64];
741f1220db8SAlexander V. Chernikov 
742914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
743ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
744ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
745adf3b2b9SAlexander V. Chernikov 	if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL)
746adf3b2b9SAlexander V. Chernikov 		vftype = "unknown";
747adf3b2b9SAlexander V. Chernikov 	if (strcmp(vtype, vftype) != 0)
748adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype);
749adf3b2b9SAlexander V. Chernikov 	else
750adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s", vtype);
751ac35ff17SAlexander V. Chernikov 
752914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
7534f43138aSAlexander V. Chernikov 	if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
7544f43138aSAlexander V. Chernikov 		printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
7554f43138aSAlexander V. Chernikov 	else
756914bffb6SAlexander V. Chernikov 		printf(" kindex: %d, type: %s\n", i->kidx, ttype);
757adf3b2b9SAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
7589d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
759f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
7604c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
7614c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
762f1220db8SAlexander V. Chernikov 
763358b9d09SAlexander V. Chernikov 	/* Print algo-specific info if requested & set  */
764358b9d09SAlexander V. Chernikov 	if (arg == NULL)
765358b9d09SAlexander V. Chernikov 		return (0);
766358b9d09SAlexander V. Chernikov 
7675f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
7685f379342SAlexander V. Chernikov 		return (0);
7695f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
7705f379342SAlexander V. Chernikov 
7715f379342SAlexander V. Chernikov 	afdata = 0;
7725f379342SAlexander V. Chernikov 	afitem = 0;
7735f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
7745f379342SAlexander V. Chernikov 		afdata = 1;
7755f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
7765f379342SAlexander V. Chernikov 		afitem = 1;
7775f379342SAlexander V. Chernikov 
7785f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
7795f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
7805f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
7815f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
7825f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
7835f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
7845f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
7855f379342SAlexander V. Chernikov 	else
7865f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
7875f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7885f379342SAlexander V. Chernikov 		vtype = "unknown";
7895f379342SAlexander V. Chernikov 
7905f379342SAlexander V. Chernikov 	if (afdata == 0) {
7915f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
7925f379342SAlexander V. Chernikov 	} else {
7935f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
7945f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
7955f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
7965f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7975f379342SAlexander V. Chernikov 			vtype = "unknown";
7985f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
7995f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
8005f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
8015f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
8025f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
8035f379342SAlexander V. Chernikov 	}
8045f379342SAlexander V. Chernikov 
805f1220db8SAlexander V. Chernikov 	return (0);
806f1220db8SAlexander V. Chernikov }
807f1220db8SAlexander V. Chernikov 
808f1220db8SAlexander V. Chernikov 
809f1220db8SAlexander V. Chernikov /*
810f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
811f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
812f1220db8SAlexander V. Chernikov  */
813f1220db8SAlexander V. Chernikov 
814f1220db8SAlexander V. Chernikov static int
815f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
816f1220db8SAlexander V. Chernikov {
817f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
81881d3153dSAlexander V. Chernikov 	int error;
819f1220db8SAlexander V. Chernikov 
820720ee730SAlexander V. Chernikov 	if ((error = table_do_get_list(i, &oh)) != 0) {
82181d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
82281d3153dSAlexander V. Chernikov 		return (error);
82381d3153dSAlexander V. Chernikov 	}
82481d3153dSAlexander V. Chernikov 
825f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
826f1220db8SAlexander V. Chernikov 
827f1220db8SAlexander V. Chernikov 	free(oh);
828f1220db8SAlexander V. Chernikov 	return (0);
829f1220db8SAlexander V. Chernikov }
830f1220db8SAlexander V. Chernikov 
831f1220db8SAlexander V. Chernikov static int
832f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
833f1220db8SAlexander V. Chernikov {
834ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
835f1220db8SAlexander V. Chernikov 
836ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
837ac35ff17SAlexander V. Chernikov 
838ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
839ac35ff17SAlexander V. Chernikov 
840ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
841f1220db8SAlexander V. Chernikov }
842f1220db8SAlexander V. Chernikov 
843ac35ff17SAlexander V. Chernikov static int
844ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
8453a845e10SAlexander V. Chernikov     ipfw_obj_tentry *tent, int count, int atomic)
846ac35ff17SAlexander V. Chernikov {
847db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
8483a845e10SAlexander V. Chernikov 	ipfw_obj_tentry *tent_base;
8493a845e10SAlexander V. Chernikov 	caddr_t pbuf;
850db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
8513a845e10SAlexander V. Chernikov 	int error, i;
8523a845e10SAlexander V. Chernikov 	size_t sz;
853ac35ff17SAlexander V. Chernikov 
8543a845e10SAlexander V. Chernikov 	sz = sizeof(*ctlv) + sizeof(*tent) * count;
8553a845e10SAlexander V. Chernikov 	if (count == 1) {
856ac35ff17SAlexander V. Chernikov 		memset(xbuf, 0, sizeof(xbuf));
8573a845e10SAlexander V. Chernikov 		pbuf = xbuf;
8583a845e10SAlexander V. Chernikov 	} else {
8593a845e10SAlexander V. Chernikov 		if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL)
8603a845e10SAlexander V. Chernikov 			return (ENOMEM);
8613a845e10SAlexander V. Chernikov 	}
8623a845e10SAlexander V. Chernikov 
8633a845e10SAlexander V. Chernikov 	memcpy(pbuf, oh, sizeof(*oh));
8643a845e10SAlexander V. Chernikov 	oh = (ipfw_obj_header *)pbuf;
865ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
866ac35ff17SAlexander V. Chernikov 
867db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
8683a845e10SAlexander V. Chernikov 	ctlv->count = count;
8693a845e10SAlexander V. Chernikov 	ctlv->head.length = sz;
8703a845e10SAlexander V. Chernikov 	if (atomic != 0)
8713a845e10SAlexander V. Chernikov 		ctlv->flags |= IPFW_CTF_ATOMIC;
872db785d31SAlexander V. Chernikov 
8733a845e10SAlexander V. Chernikov 	tent_base = tent;
8743a845e10SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent) * count);
875db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
8763a845e10SAlexander V. Chernikov 	for (i = 0; i < count; i++, tent++) {
877ac35ff17SAlexander V. Chernikov 		tent->head.length = sizeof(ipfw_obj_tentry);
8783a845e10SAlexander V. Chernikov 		tent->idx = oh->idx;
8793a845e10SAlexander V. Chernikov 	}
880ac35ff17SAlexander V. Chernikov 
8813a845e10SAlexander V. Chernikov 	sz += sizeof(*oh);
8823a845e10SAlexander V. Chernikov 	error = do_get3(cmd, &oh->opheader, &sz);
8833a845e10SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
8843a845e10SAlexander V. Chernikov 	/* Copy result back to provided buffer */
8853a845e10SAlexander V. Chernikov 	memcpy(tent_base, ctlv + 1, sizeof(*tent) * count);
8863a845e10SAlexander V. Chernikov 
8873a845e10SAlexander V. Chernikov 	if (pbuf != xbuf)
8883a845e10SAlexander V. Chernikov 		free(pbuf);
889ac35ff17SAlexander V. Chernikov 
890ac35ff17SAlexander V. Chernikov 	return (error);
891ac35ff17SAlexander V. Chernikov }
892ac35ff17SAlexander V. Chernikov 
893ac35ff17SAlexander V. Chernikov static void
8943a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add,
8953a845e10SAlexander V. Chernikov     int quiet, int update, int atomic)
896ac35ff17SAlexander V. Chernikov {
8973a845e10SAlexander V. Chernikov 	ipfw_obj_tentry *ptent, tent, *tent_buf;
89881d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
899ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
9003a845e10SAlexander V. Chernikov 	int cmd, count, error, i, ignored;
9013a845e10SAlexander V. Chernikov 	char *texterr, *etxt, *px;
902ac35ff17SAlexander V. Chernikov 
903ac35ff17SAlexander V. Chernikov 	if (ac == 0)
904ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
905ac35ff17SAlexander V. Chernikov 
906ac35ff17SAlexander V. Chernikov 	if (add != 0) {
907ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
9084c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
909ac35ff17SAlexander V. Chernikov 	} else {
910ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
9114c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
912ac35ff17SAlexander V. Chernikov 	}
913ac35ff17SAlexander V. Chernikov 
9143a845e10SAlexander V. Chernikov 	/*
9153a845e10SAlexander V. Chernikov 	 * Calculate number of entries:
9163a845e10SAlexander V. Chernikov 	 * Assume [key val] x N for add
9173a845e10SAlexander V. Chernikov 	 * and
9183a845e10SAlexander V. Chernikov 	 * key x N for delete
9193a845e10SAlexander V. Chernikov 	 */
9203a845e10SAlexander V. Chernikov 	count = (add != 0) ? ac / 2 + 1 : ac;
9213a845e10SAlexander V. Chernikov 
9223a845e10SAlexander V. Chernikov 	if (count <= 1) {
9233a845e10SAlexander V. Chernikov 		/* Adding single entry with/without value */
9243a845e10SAlexander V. Chernikov 		memset(&tent, 0, sizeof(tent));
9253a845e10SAlexander V. Chernikov 		tent_buf = &tent;
9263a845e10SAlexander V. Chernikov 	} else {
9273a845e10SAlexander V. Chernikov 
9283a845e10SAlexander V. Chernikov 		if ((tent_buf = calloc(count, sizeof(tent))) == NULL)
9293a845e10SAlexander V. Chernikov 			errx(EX_OSERR,
9303a845e10SAlexander V. Chernikov 			    "Unable to allocate memory for all entries");
9313a845e10SAlexander V. Chernikov 	}
9323a845e10SAlexander V. Chernikov 	ptent = tent_buf;
9333a845e10SAlexander V. Chernikov 
9343a845e10SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
9353a845e10SAlexander V. Chernikov 	count = 0;
9363a845e10SAlexander V. Chernikov 	while (ac > 0) {
93735df97d0SAlexander V. Chernikov 		tentry_fill_key(oh, ptent, *av, add, &type, &vtype, &xi);
9383a845e10SAlexander V. Chernikov 
9393a845e10SAlexander V. Chernikov 		/*
9403a845e10SAlexander V. Chernikov 		 * compability layer: auto-create table if not exists
9413a845e10SAlexander V. Chernikov 		 */
9423a845e10SAlexander V. Chernikov 		if (xi.tablename[0] == '\0') {
9433a845e10SAlexander V. Chernikov 			xi.type = type;
9443a845e10SAlexander V. Chernikov 			xi.vtype = vtype;
9453a845e10SAlexander V. Chernikov 			strlcpy(xi.tablename, oh->ntlv.name,
9463a845e10SAlexander V. Chernikov 			    sizeof(xi.tablename));
9473a845e10SAlexander V. Chernikov 			fprintf(stderr, "DEPRECATED: inserting data info "
9483a845e10SAlexander V. Chernikov 			    "non-existent table %s. (auto-created)\n",
9493a845e10SAlexander V. Chernikov 			    xi.tablename);
9503a845e10SAlexander V. Chernikov 			table_do_create(oh, &xi);
9513a845e10SAlexander V. Chernikov 		}
9523a845e10SAlexander V. Chernikov 
9533a845e10SAlexander V. Chernikov 		oh->ntlv.type = type;
9543a845e10SAlexander V. Chernikov 		ac--; av++;
9553a845e10SAlexander V. Chernikov 
9563a845e10SAlexander V. Chernikov 		if (add != 0 && ac > 0) {
9573a845e10SAlexander V. Chernikov 			tentry_fill_value(oh, ptent, *av, type, vtype);
9583a845e10SAlexander V. Chernikov 			ac--; av++;
9593a845e10SAlexander V. Chernikov 		}
9603a845e10SAlexander V. Chernikov 
9613a845e10SAlexander V. Chernikov 		if (update != 0)
9623a845e10SAlexander V. Chernikov 			ptent->head.flags |= IPFW_TF_UPDATE;
9633a845e10SAlexander V. Chernikov 
9643a845e10SAlexander V. Chernikov 		count++;
9653a845e10SAlexander V. Chernikov 		ptent++;
9663a845e10SAlexander V. Chernikov 	}
9673a845e10SAlexander V. Chernikov 
9683a845e10SAlexander V. Chernikov 	error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
9693a845e10SAlexander V. Chernikov 
9703a845e10SAlexander V. Chernikov 	/*
9713a845e10SAlexander V. Chernikov 	 * Compatibility stuff: do not yell on duplicate keys or
9723a845e10SAlexander V. Chernikov 	 * failed deletions.
9733a845e10SAlexander V. Chernikov 	 */
9743a845e10SAlexander V. Chernikov 	if (error == 0 || (error == EEXIST && add != 0) ||
9753a845e10SAlexander V. Chernikov 	    (error == ENOENT && add == 0)) {
9763a845e10SAlexander V. Chernikov 		if (quiet != 0) {
9773a845e10SAlexander V. Chernikov 			if (tent_buf != &tent)
9783a845e10SAlexander V. Chernikov 				free(tent_buf);
9793a845e10SAlexander V. Chernikov 			return;
9803a845e10SAlexander V. Chernikov 		}
9813a845e10SAlexander V. Chernikov 	}
9823a845e10SAlexander V. Chernikov 
9833a845e10SAlexander V. Chernikov 	/* Report results back */
9843a845e10SAlexander V. Chernikov 	ptent = tent_buf;
9853a845e10SAlexander V. Chernikov 	for (i = 0; i < count; ptent++, i++) {
9863a845e10SAlexander V. Chernikov 		ignored = 0;
9873a845e10SAlexander V. Chernikov 		switch (ptent->result) {
9883a845e10SAlexander V. Chernikov 		case IPFW_TR_ADDED:
9893a845e10SAlexander V. Chernikov 			px = "added";
9903a845e10SAlexander V. Chernikov 			break;
9913a845e10SAlexander V. Chernikov 		case IPFW_TR_DELETED:
9923a845e10SAlexander V. Chernikov 			px = "deleted";
9933a845e10SAlexander V. Chernikov 			break;
9943a845e10SAlexander V. Chernikov 		case IPFW_TR_UPDATED:
9953a845e10SAlexander V. Chernikov 			px = "updated";
9963a845e10SAlexander V. Chernikov 			break;
9973a845e10SAlexander V. Chernikov 		case IPFW_TR_LIMIT:
9983a845e10SAlexander V. Chernikov 			px = "limit";
9993a845e10SAlexander V. Chernikov 			ignored = 1;
10003a845e10SAlexander V. Chernikov 			break;
10013a845e10SAlexander V. Chernikov 		case IPFW_TR_ERROR:
10023a845e10SAlexander V. Chernikov 			px = "error";
10033a845e10SAlexander V. Chernikov 			ignored = 1;
10043a845e10SAlexander V. Chernikov 			break;
10053a845e10SAlexander V. Chernikov 		case IPFW_TR_NOTFOUND:
10063a845e10SAlexander V. Chernikov 			px = "notfound";
10073a845e10SAlexander V. Chernikov 			ignored = 1;
10083a845e10SAlexander V. Chernikov 			break;
10093a845e10SAlexander V. Chernikov 		case IPFW_TR_EXISTS:
10103a845e10SAlexander V. Chernikov 			px = "exists";
10113a845e10SAlexander V. Chernikov 			ignored = 1;
10123a845e10SAlexander V. Chernikov 			break;
10133a845e10SAlexander V. Chernikov 		case IPFW_TR_IGNORED:
10143a845e10SAlexander V. Chernikov 			px = "ignored";
10153a845e10SAlexander V. Chernikov 			ignored = 1;
10163a845e10SAlexander V. Chernikov 			break;
10173a845e10SAlexander V. Chernikov 		default:
10183a845e10SAlexander V. Chernikov 			px = "unknown";
10193a845e10SAlexander V. Chernikov 			ignored = 1;
10203a845e10SAlexander V. Chernikov 		}
10213a845e10SAlexander V. Chernikov 
10223a845e10SAlexander V. Chernikov 		if (error != 0 && atomic != 0 && ignored == 0)
10233a845e10SAlexander V. Chernikov 			printf("%s(reverted): ", px);
10243a845e10SAlexander V. Chernikov 		else
10253a845e10SAlexander V. Chernikov 			printf("%s: ", px);
10263a845e10SAlexander V. Chernikov 
10273a845e10SAlexander V. Chernikov 		table_show_entry(&xi, ptent);
10283a845e10SAlexander V. Chernikov 	}
10293a845e10SAlexander V. Chernikov 
10303a845e10SAlexander V. Chernikov 	if (tent_buf != &tent)
10313a845e10SAlexander V. Chernikov 		free(tent_buf);
10323a845e10SAlexander V. Chernikov 
10333a845e10SAlexander V. Chernikov 	if (error == 0)
10344c0c07a5SAlexander V. Chernikov 		return;
10354c0c07a5SAlexander V. Chernikov 
10364c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
10374c0c07a5SAlexander V. Chernikov 	switch (error) {
10384c0c07a5SAlexander V. Chernikov 	case EEXIST:
10394c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
10404c0c07a5SAlexander V. Chernikov 		break;
10414c0c07a5SAlexander V. Chernikov 	case EFBIG:
10424c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
10434c0c07a5SAlexander V. Chernikov 		break;
10444c0c07a5SAlexander V. Chernikov 	case ESRCH:
10454c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
10464c0c07a5SAlexander V. Chernikov 		break;
10474c0c07a5SAlexander V. Chernikov 	case ENOENT:
10484c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
10494c0c07a5SAlexander V. Chernikov 		break;
10504f43138aSAlexander V. Chernikov 	case EACCES:
10514f43138aSAlexander V. Chernikov 		etxt = "table is locked";
10524f43138aSAlexander V. Chernikov 		break;
10534c0c07a5SAlexander V. Chernikov 	default:
10544c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
10554c0c07a5SAlexander V. Chernikov 	}
10564c0c07a5SAlexander V. Chernikov 
10574c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
1058ac35ff17SAlexander V. Chernikov }
1059ac35ff17SAlexander V. Chernikov 
106081d3153dSAlexander V. Chernikov static int
106181d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
106281d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
106381d3153dSAlexander V. Chernikov {
106481d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
106581d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
106681d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
106781d3153dSAlexander V. Chernikov 	int error;
106881d3153dSAlexander V. Chernikov 	size_t sz;
106981d3153dSAlexander V. Chernikov 
107081d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
107181d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
107281d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
107381d3153dSAlexander V. Chernikov 
107481d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
107581d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
107681d3153dSAlexander V. Chernikov 	tent->idx = 1;
107781d3153dSAlexander V. Chernikov 
107835df97d0SAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, 0, &type, &vtype, xi);
107981d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
108081d3153dSAlexander V. Chernikov 
108181d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
108281d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
108381d3153dSAlexander V. Chernikov 		return (error);
108481d3153dSAlexander V. Chernikov 
108581d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
108681d3153dSAlexander V. Chernikov 		return (EINVAL);
108781d3153dSAlexander V. Chernikov 
108881d3153dSAlexander V. Chernikov 	*xtent = *tent;
108981d3153dSAlexander V. Chernikov 
109081d3153dSAlexander V. Chernikov 	return (0);
109181d3153dSAlexander V. Chernikov }
109281d3153dSAlexander V. Chernikov 
109381d3153dSAlexander V. Chernikov static void
109481d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
109581d3153dSAlexander V. Chernikov {
109681d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
109781d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
1098914bffb6SAlexander V. Chernikov 	char key[64];
109981d3153dSAlexander V. Chernikov 	int error;
110081d3153dSAlexander V. Chernikov 
110181d3153dSAlexander V. Chernikov 	if (ac == 0)
110281d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
110381d3153dSAlexander V. Chernikov 
1104914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
1105914bffb6SAlexander V. Chernikov 
11063a845e10SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
1107914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
110881d3153dSAlexander V. Chernikov 
110981d3153dSAlexander V. Chernikov 	switch (error) {
111081d3153dSAlexander V. Chernikov 	case 0:
111181d3153dSAlexander V. Chernikov 		break;
111281d3153dSAlexander V. Chernikov 	case ESRCH:
111381d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
111481d3153dSAlexander V. Chernikov 	case ENOENT:
111581d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
111681d3153dSAlexander V. Chernikov 	case ENOTSUP:
111781d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
111881d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
111981d3153dSAlexander V. Chernikov 	default:
112081d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
112181d3153dSAlexander V. Chernikov 	}
112281d3153dSAlexander V. Chernikov 
112381d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
112481d3153dSAlexander V. Chernikov }
1125ac35ff17SAlexander V. Chernikov 
1126ac35ff17SAlexander V. Chernikov static void
1127914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
1128914bffb6SAlexander V. Chernikov     uint8_t tflags)
1129ac35ff17SAlexander V. Chernikov {
1130914bffb6SAlexander V. Chernikov 	char *p, *pp;
1131ac35ff17SAlexander V. Chernikov 	int mask, af;
1132914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
1133914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
1134ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
1135914bffb6SAlexander V. Chernikov 	uint16_t port;
1136914bffb6SAlexander V. Chernikov 	struct protoent *pent;
1137914bffb6SAlexander V. Chernikov 	struct servent *sent;
1138ac35ff17SAlexander V. Chernikov 	int masklen;
1139ac35ff17SAlexander V. Chernikov 
1140ac35ff17SAlexander V. Chernikov 	masklen = 0;
1141ac35ff17SAlexander V. Chernikov 	af = 0;
1142ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
1143ac35ff17SAlexander V. Chernikov 
1144ac35ff17SAlexander V. Chernikov 	switch (type) {
1145ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1146ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
1147ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
1148ac35ff17SAlexander V. Chernikov 			*p = '\0';
1149ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
1150ac35ff17SAlexander V. Chernikov 		}
1151ac35ff17SAlexander V. Chernikov 
1152ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
1153ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
1154ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
1155ac35ff17SAlexander V. Chernikov 				    p + 1);
1156ac35ff17SAlexander V. Chernikov 
1157ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
1158ac35ff17SAlexander V. Chernikov 			af = AF_INET;
1159ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
1160ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
1161ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
1162ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
1163ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
1164ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
1165ac35ff17SAlexander V. Chernikov 				    p + 1);
1166ac35ff17SAlexander V. Chernikov 
1167ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
1168ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
1169ac35ff17SAlexander V. Chernikov 		} else {
1170ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
1171ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
1172ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
1173ac35ff17SAlexander V. Chernikov 
1174ac35ff17SAlexander V. Chernikov 			masklen = 32;
1175ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1176ac35ff17SAlexander V. Chernikov 			af = AF_INET;
1177ac35ff17SAlexander V. Chernikov 		}
1178ac35ff17SAlexander V. Chernikov 		break;
1179ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1180ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
1181ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
1182ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
1183ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
1184ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
1185ac35ff17SAlexander V. Chernikov 		break;
1186b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1187ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
1188ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
1189ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1190ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
1191ac35ff17SAlexander V. Chernikov 
1192ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
1193ac35ff17SAlexander V. Chernikov 		*pkey = key;
1194ac35ff17SAlexander V. Chernikov 		masklen = 32;
1195ac35ff17SAlexander V. Chernikov 		break;
1196914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1197914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1198914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
1199914bffb6SAlexander V. Chernikov 		af = 0;
1200914bffb6SAlexander V. Chernikov 
1201914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6> */
1202914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
1203914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1204914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1205914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1206914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1207914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1208914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1209914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1210914bffb6SAlexander V. Chernikov 				af = AF_INET;
1211914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
1212914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1213914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1214914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1215914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1216914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1217914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
1218914bffb6SAlexander V. Chernikov 			}
1219914bffb6SAlexander V. Chernikov 
1220914bffb6SAlexander V. Chernikov 			arg = p;
1221914bffb6SAlexander V. Chernikov 		}
1222914bffb6SAlexander V. Chernikov 
1223914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
1224914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
122535df97d0SAlexander V. Chernikov 			if (arg == NULL)
122635df97d0SAlexander V. Chernikov 				errx(EX_DATAERR, "invalid key: proto missing");
1227914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1228914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1229914bffb6SAlexander V. Chernikov 
1230914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
1231914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
1232914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
1233914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
1234914bffb6SAlexander V. Chernikov 					    arg);
1235914bffb6SAlexander V. Chernikov 				else
1236914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
1237914bffb6SAlexander V. Chernikov 			}
1238914bffb6SAlexander V. Chernikov 
1239914bffb6SAlexander V. Chernikov 			if (key > 255)
1240914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
1241914bffb6SAlexander V. Chernikov 
1242914bffb6SAlexander V. Chernikov 			tfe->proto = key;
1243914bffb6SAlexander V. Chernikov 
1244914bffb6SAlexander V. Chernikov 			arg = p;
1245914bffb6SAlexander V. Chernikov 		}
1246914bffb6SAlexander V. Chernikov 
1247914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1248914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
124935df97d0SAlexander V. Chernikov 			if (arg == NULL)
125035df97d0SAlexander V. Chernikov 				errx(EX_DATAERR, "invalid key: src port missing");
1251914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1252914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1253914bffb6SAlexander V. Chernikov 
1254914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1255914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1256914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1257914bffb6SAlexander V. Chernikov 					    arg);
1258914bffb6SAlexander V. Chernikov 				else
1259914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1260914bffb6SAlexander V. Chernikov 			}
1261914bffb6SAlexander V. Chernikov 
1262914bffb6SAlexander V. Chernikov 			tfe->sport = port;
1263914bffb6SAlexander V. Chernikov 
1264914bffb6SAlexander V. Chernikov 			arg = p;
1265914bffb6SAlexander V. Chernikov 		}
1266914bffb6SAlexander V. Chernikov 
1267914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1268914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
126935df97d0SAlexander V. Chernikov 			if (arg == NULL)
127035df97d0SAlexander V. Chernikov 				errx(EX_DATAERR, "invalid key: dst ip missing");
1271914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1272914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1273914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1274914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1275914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1276914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1277914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1278914bffb6SAlexander V. Chernikov 				af = AF_INET;
1279914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
1280914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1281914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1282914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1283914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1284914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1285914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
1286914bffb6SAlexander V. Chernikov 			}
1287914bffb6SAlexander V. Chernikov 
1288914bffb6SAlexander V. Chernikov 			arg = p;
1289914bffb6SAlexander V. Chernikov 		}
1290914bffb6SAlexander V. Chernikov 
1291914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1292914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
129335df97d0SAlexander V. Chernikov 			if (arg == NULL)
129435df97d0SAlexander V. Chernikov 				errx(EX_DATAERR, "invalid key: dst port missing");
1295914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1296914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1297914bffb6SAlexander V. Chernikov 
1298914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1299914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1300914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1301914bffb6SAlexander V. Chernikov 					    arg);
1302914bffb6SAlexander V. Chernikov 				else
1303914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1304914bffb6SAlexander V. Chernikov 			}
1305914bffb6SAlexander V. Chernikov 
1306914bffb6SAlexander V. Chernikov 			tfe->dport = port;
1307914bffb6SAlexander V. Chernikov 
1308914bffb6SAlexander V. Chernikov 			arg = p;
1309914bffb6SAlexander V. Chernikov 		}
1310914bffb6SAlexander V. Chernikov 
1311914bffb6SAlexander V. Chernikov 		tfe->af = af;
1312914bffb6SAlexander V. Chernikov 
1313914bffb6SAlexander V. Chernikov 		break;
1314914bffb6SAlexander V. Chernikov 
1315ac35ff17SAlexander V. Chernikov 	default:
1316ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
1317ac35ff17SAlexander V. Chernikov 	}
1318ac35ff17SAlexander V. Chernikov 
1319ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
1320ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
1321ac35ff17SAlexander V. Chernikov }
1322ac35ff17SAlexander V. Chernikov 
1323ac35ff17SAlexander V. Chernikov static void
1324ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
132535df97d0SAlexander V. Chernikov     int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
1326ac35ff17SAlexander V. Chernikov {
1327914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
1328ac35ff17SAlexander V. Chernikov 	int error;
1329db785d31SAlexander V. Chernikov 	char *del;
1330ac35ff17SAlexander V. Chernikov 
1331ac35ff17SAlexander V. Chernikov 	type = 0;
1332914bffb6SAlexander V. Chernikov 	tflags = 0;
1333ac35ff17SAlexander V. Chernikov 	vtype = 0;
1334ac35ff17SAlexander V. Chernikov 
13353a845e10SAlexander V. Chernikov 	if (xi->tablename[0] == '\0')
133681d3153dSAlexander V. Chernikov 		error = table_get_info(oh, xi);
13373a845e10SAlexander V. Chernikov 	else
13383a845e10SAlexander V. Chernikov 		error = 0;
133981d3153dSAlexander V. Chernikov 
134081d3153dSAlexander V. Chernikov 	if (error == 0) {
134181d3153dSAlexander V. Chernikov 		/* Table found. */
134281d3153dSAlexander V. Chernikov 		type = xi->type;
1343914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
134481d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
134581d3153dSAlexander V. Chernikov 	} else {
134681d3153dSAlexander V. Chernikov 		if (error != ESRCH)
134781d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
134881d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
134935df97d0SAlexander V. Chernikov 		if (add == 0)
135035df97d0SAlexander V. Chernikov 			errx(EX_DATAERR, "Table %s does not exist",
135135df97d0SAlexander V. Chernikov 			    oh->ntlv.name);
1352ac35ff17SAlexander V. Chernikov 		/*
135381d3153dSAlexander V. Chernikov 		 * Table does not exist.
135481d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
135581d3153dSAlexander V. Chernikov 		 * before failing.
1356ac35ff17SAlexander V. Chernikov 		 */
1357db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1358db785d31SAlexander V. Chernikov 			*del = '\0';
1359ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1360ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1361ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1362ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1363ac35ff17SAlexander V. Chernikov 			/*
136481d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
136581d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1366ac35ff17SAlexander V. Chernikov 			 */
136781d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
136881d3153dSAlexander V. Chernikov 		} else {
136981d3153dSAlexander V. Chernikov 			/* Inknown key */
137081d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1371db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
137281d3153dSAlexander V. Chernikov 		}
1373db785d31SAlexander V. Chernikov 		if (del != NULL)
1374db785d31SAlexander V. Chernikov 			*del = '/';
1375ac35ff17SAlexander V. Chernikov 	}
1376ac35ff17SAlexander V. Chernikov 
1377914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1378ac35ff17SAlexander V. Chernikov 
1379ac35ff17SAlexander V. Chernikov 	*ptype = type;
1380ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1381ac35ff17SAlexander V. Chernikov }
1382ac35ff17SAlexander V. Chernikov 
1383ac35ff17SAlexander V. Chernikov static void
1384ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1385ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1386ac35ff17SAlexander V. Chernikov {
1387adf3b2b9SAlexander V. Chernikov 	uint32_t val;
1388ac35ff17SAlexander V. Chernikov 	char *p;
1389ac35ff17SAlexander V. Chernikov 
1390adf3b2b9SAlexander V. Chernikov 	/* Try to interpret as number first */
1391adf3b2b9SAlexander V. Chernikov 	tent->value = strtoul(arg, &p, 0);
1392adf3b2b9SAlexander V. Chernikov 	if (*p == '\0')
1393adf3b2b9SAlexander V. Chernikov 		return;
1394adf3b2b9SAlexander V. Chernikov 	if (inet_pton(AF_INET, arg, &val) == 1) {
1395adf3b2b9SAlexander V. Chernikov 		tent->value = ntohl(val);
1396adf3b2b9SAlexander V. Chernikov 		return;
1397adf3b2b9SAlexander V. Chernikov 	}
1398adf3b2b9SAlexander V. Chernikov 	/* Try hostname */
1399adf3b2b9SAlexander V. Chernikov 	if (lookup_host(arg, (struct in_addr *)&tent->value) == 0)
1400adf3b2b9SAlexander V. Chernikov 		return;
1401adf3b2b9SAlexander V. Chernikov 	errx(EX_OSERR, "Unable to parse value %s", arg);
1402adf3b2b9SAlexander V. Chernikov #if 0
1403ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1404ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1405ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1406ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1407ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1408ac35ff17SAlexander V. Chernikov 		break;
1409ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1410ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1411ac35ff17SAlexander V. Chernikov 			break;
1412ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1413ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1414ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1415ac35ff17SAlexander V. Chernikov 		break;
1416ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1417ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1418ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1419ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1420ac35ff17SAlexander V. Chernikov 		} else {
1421ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1422ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1423ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1424ac35ff17SAlexander V. Chernikov 		}
1425ac35ff17SAlexander V. Chernikov 		tent->value = code;
1426ac35ff17SAlexander V. Chernikov 		break;
1427ac35ff17SAlexander V. Chernikov 	default:
1428ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1429ac35ff17SAlexander V. Chernikov 	}
1430adf3b2b9SAlexander V. Chernikov #endif
1431ac35ff17SAlexander V. Chernikov }
1432f1220db8SAlexander V. Chernikov 
1433f1220db8SAlexander V. Chernikov /*
1434f1220db8SAlexander V. Chernikov  * Compare table names.
1435f1220db8SAlexander V. Chernikov  * Honor number comparison.
1436f1220db8SAlexander V. Chernikov  */
1437f1220db8SAlexander V. Chernikov static int
1438f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1439f1220db8SAlexander V. Chernikov {
1440f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1441f1220db8SAlexander V. Chernikov 
1442f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1443f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1444f1220db8SAlexander V. Chernikov 
144568394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1446f1220db8SAlexander V. Chernikov }
1447f1220db8SAlexander V. Chernikov 
1448f1220db8SAlexander V. Chernikov /*
1449f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1450f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1451f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1452f1220db8SAlexander V. Chernikov  */
1453f1220db8SAlexander V. Chernikov static int
1454f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1455f1220db8SAlexander V. Chernikov {
145628ea4fa3SAlexander V. Chernikov 	ipfw_obj_lheader *olh;
1457f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1458f1220db8SAlexander V. Chernikov 	size_t sz;
1459f1220db8SAlexander V. Chernikov 	int i, error;
1460f1220db8SAlexander V. Chernikov 
146128ea4fa3SAlexander V. Chernikov 	/* Start with reasonable default */
146228ea4fa3SAlexander V. Chernikov 	sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
1463f1220db8SAlexander V. Chernikov 
146428ea4fa3SAlexander V. Chernikov 	for (;;) {
1465f1220db8SAlexander V. Chernikov 		if ((olh = calloc(1, sz)) == NULL)
1466f1220db8SAlexander V. Chernikov 			return (ENOMEM);
1467f1220db8SAlexander V. Chernikov 
1468f1220db8SAlexander V. Chernikov 		olh->size = sz;
146928ea4fa3SAlexander V. Chernikov 		error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz);
147028ea4fa3SAlexander V. Chernikov 		if (error == ENOMEM) {
147128ea4fa3SAlexander V. Chernikov 			sz = olh->size;
1472f1220db8SAlexander V. Chernikov 			free(olh);
147328ea4fa3SAlexander V. Chernikov 			continue;
147428ea4fa3SAlexander V. Chernikov 		} else if (error != 0) {
147528ea4fa3SAlexander V. Chernikov 			free(olh);
147628ea4fa3SAlexander V. Chernikov 			return (error);
1477f1220db8SAlexander V. Chernikov 		}
1478f1220db8SAlexander V. Chernikov 
1479f1220db8SAlexander V. Chernikov 		if (sort != 0)
1480f1220db8SAlexander V. Chernikov 			qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1481f1220db8SAlexander V. Chernikov 
1482f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)(olh + 1);
1483f1220db8SAlexander V. Chernikov 		for (i = 0; i < olh->count; i++) {
1484f1220db8SAlexander V. Chernikov 			error = f(info, arg); /* Ignore errors for now */
1485f1220db8SAlexander V. Chernikov 			info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1486f1220db8SAlexander V. Chernikov 		}
1487f1220db8SAlexander V. Chernikov 
1488f1220db8SAlexander V. Chernikov 		free(olh);
148928ea4fa3SAlexander V. Chernikov 		break;
149028ea4fa3SAlexander V. Chernikov 	}
1491f1220db8SAlexander V. Chernikov 
1492f1220db8SAlexander V. Chernikov 	return (0);
1493f1220db8SAlexander V. Chernikov }
1494f1220db8SAlexander V. Chernikov 
149528ea4fa3SAlexander V. Chernikov 
1496f1220db8SAlexander V. Chernikov /*
1497f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1498720ee730SAlexander V. Chernikov  * eXtended format. Allocate buffer large enough
1499720ee730SAlexander V. Chernikov  * to store result. Called needs to free it later.
1500f1220db8SAlexander V. Chernikov  *
1501f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1502f1220db8SAlexander V. Chernikov  */
1503f1220db8SAlexander V. Chernikov static int
1504720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
1505f1220db8SAlexander V. Chernikov {
1506720ee730SAlexander V. Chernikov 	ipfw_obj_header *oh;
1507f1220db8SAlexander V. Chernikov 	size_t sz;
150881d3153dSAlexander V. Chernikov 	int error, c;
1509f1220db8SAlexander V. Chernikov 
151081d3153dSAlexander V. Chernikov 	sz = 0;
1511720ee730SAlexander V. Chernikov 	oh = NULL;
1512720ee730SAlexander V. Chernikov 	error = 0;
1513720ee730SAlexander V. Chernikov 	for (c = 0; c < 8; c++) {
151481d3153dSAlexander V. Chernikov 		if (sz < i->size)
1515720ee730SAlexander V. Chernikov 			sz = i->size + 44;
1516720ee730SAlexander V. Chernikov 		if (oh != NULL)
1517720ee730SAlexander V. Chernikov 			free(oh);
1518720ee730SAlexander V. Chernikov 		if ((oh = calloc(1, sz)) == NULL)
1519720ee730SAlexander V. Chernikov 			continue;
1520720ee730SAlexander V. Chernikov 		table_fill_objheader(oh, i);
1521d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
152281d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1523d3a4f924SAlexander V. Chernikov 
1524720ee730SAlexander V. Chernikov 		if (error == 0) {
1525720ee730SAlexander V. Chernikov 			*poh = oh;
1526720ee730SAlexander V. Chernikov 			return (0);
152781d3153dSAlexander V. Chernikov 		}
1528f1220db8SAlexander V. Chernikov 
1529720ee730SAlexander V. Chernikov 		if (error != ENOMEM)
1530720ee730SAlexander V. Chernikov 			break;
1531720ee730SAlexander V. Chernikov 	}
1532720ee730SAlexander V. Chernikov 	free(oh);
1533720ee730SAlexander V. Chernikov 
1534720ee730SAlexander V. Chernikov 	return (error);
1535f1220db8SAlexander V. Chernikov }
1536f1220db8SAlexander V. Chernikov 
1537f1220db8SAlexander V. Chernikov /*
1538f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1539f1220db8SAlexander V. Chernikov  */
1540f1220db8SAlexander V. Chernikov static void
1541f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1542f1220db8SAlexander V. Chernikov {
154381d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
154481d3153dSAlexander V. Chernikov 	uint32_t count;
1545f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1546f1220db8SAlexander V. Chernikov 
1547f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
154881d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1549f1220db8SAlexander V. Chernikov 
1550f1220db8SAlexander V. Chernikov 	if (need_header)
1551f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1552f1220db8SAlexander V. Chernikov 
1553f1220db8SAlexander V. Chernikov 	count = i->count;
1554f1220db8SAlexander V. Chernikov 	while (count > 0) {
155581d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
155681d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
155781d3153dSAlexander V. Chernikov 		count--;
155881d3153dSAlexander V. Chernikov 	}
155981d3153dSAlexander V. Chernikov }
156081d3153dSAlexander V. Chernikov 
156181d3153dSAlexander V. Chernikov static void
156281d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
156381d3153dSAlexander V. Chernikov {
1564914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1565914bffb6SAlexander V. Chernikov 	void *paddr;
156681d3153dSAlexander V. Chernikov 	uint32_t tval;
1567914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
156881d3153dSAlexander V. Chernikov 
156981d3153dSAlexander V. Chernikov 	tval = tent->value;
157081d3153dSAlexander V. Chernikov 
1571adf3b2b9SAlexander V. Chernikov 	if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
1572914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1573914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1574914bffb6SAlexander V. Chernikov 	} else
1575914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1576914bffb6SAlexander V. Chernikov 
1577f1220db8SAlexander V. Chernikov 	switch (i->type) {
1578f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1579f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
158081d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1581914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1582f1220db8SAlexander V. Chernikov 		break;
1583f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1584f1220db8SAlexander V. Chernikov 		/* Interface names */
1585914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1586b23d5de9SAlexander V. Chernikov 		break;
1587b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1588b23d5de9SAlexander V. Chernikov 		/* numbers */
1589914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1590b23d5de9SAlexander V. Chernikov 		break;
1591914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1592914bffb6SAlexander V. Chernikov 		/* flows */
1593914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1594914bffb6SAlexander V. Chernikov 		comma = "";
1595914bffb6SAlexander V. Chernikov 
1596914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1597914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1598914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1599914bffb6SAlexander V. Chernikov 			else
1600914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1601914bffb6SAlexander V. Chernikov 
1602914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1603914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1604914bffb6SAlexander V. Chernikov 			comma = ",";
1605914bffb6SAlexander V. Chernikov 		}
1606914bffb6SAlexander V. Chernikov 
1607914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1608914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1609914bffb6SAlexander V. Chernikov 			comma = ",";
1610914bffb6SAlexander V. Chernikov 		}
1611914bffb6SAlexander V. Chernikov 
1612914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1613914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1614914bffb6SAlexander V. Chernikov 			comma = ",";
1615914bffb6SAlexander V. Chernikov 		}
1616914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1617914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1618914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1619914bffb6SAlexander V. Chernikov 			else
1620914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1621914bffb6SAlexander V. Chernikov 
1622914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1623914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1624914bffb6SAlexander V. Chernikov 			comma = ",";
1625914bffb6SAlexander V. Chernikov 		}
1626914bffb6SAlexander V. Chernikov 
1627914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1628914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1629914bffb6SAlexander V. Chernikov 			comma = ",";
1630914bffb6SAlexander V. Chernikov 		}
1631914bffb6SAlexander V. Chernikov 
1632914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1633f1220db8SAlexander V. Chernikov 	}
1634f1220db8SAlexander V. Chernikov }
1635f1220db8SAlexander V. Chernikov 
16369d099b4fSAlexander V. Chernikov static int
16379d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
16389d099b4fSAlexander V. Chernikov {
16399d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
16409d099b4fSAlexander V. Chernikov 	size_t sz;
16419d099b4fSAlexander V. Chernikov 	int error;
16429d099b4fSAlexander V. Chernikov 
16439d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
16449d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
16459d099b4fSAlexander V. Chernikov 
16469d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
16479d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
16489d099b4fSAlexander V. Chernikov 		return (error);
16499d099b4fSAlexander V. Chernikov 
16509d099b4fSAlexander V. Chernikov 	sz = req.size;
16519d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
16529d099b4fSAlexander V. Chernikov 		return (ENOMEM);
16539d099b4fSAlexander V. Chernikov 
16549d099b4fSAlexander V. Chernikov 	olh->size = sz;
16559d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
16569d099b4fSAlexander V. Chernikov 		free(olh);
16579d099b4fSAlexander V. Chernikov 		return (error);
16589d099b4fSAlexander V. Chernikov 	}
16599d099b4fSAlexander V. Chernikov 
16609d099b4fSAlexander V. Chernikov 	*polh = olh;
16619d099b4fSAlexander V. Chernikov 	return (0);
16629d099b4fSAlexander V. Chernikov }
16639d099b4fSAlexander V. Chernikov 
16649d099b4fSAlexander V. Chernikov void
16659d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
16669d099b4fSAlexander V. Chernikov {
16679d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
16689d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
16699d099b4fSAlexander V. Chernikov 	int error, i;
16709d099b4fSAlexander V. Chernikov 	const char *atype;
16719d099b4fSAlexander V. Chernikov 
16729d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
16739d099b4fSAlexander V. Chernikov 	if (error != 0)
16749d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
16759d099b4fSAlexander V. Chernikov 
16769d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
16779d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
16789d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
16799d099b4fSAlexander V. Chernikov 			atype = "unknown";
16808ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
16818ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
16829d099b4fSAlexander V. Chernikov 
16839d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
16849d099b4fSAlexander V. Chernikov 	}
16859d099b4fSAlexander V. Chernikov 
16869d099b4fSAlexander V. Chernikov 	free(olh);
16879d099b4fSAlexander V. Chernikov }
16889d099b4fSAlexander V. Chernikov 
16896c2997ffSAlexander V. Chernikov int
16906c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
16916c2997ffSAlexander V. Chernikov {
16926c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
16936c2997ffSAlexander V. Chernikov 
16946c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
16956c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
16966c2997ffSAlexander V. Chernikov 
16976c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
16986c2997ffSAlexander V. Chernikov 		return (-1);
16996c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
17006c2997ffSAlexander V. Chernikov 		return (1);
17016c2997ffSAlexander V. Chernikov 
17026c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
17036c2997ffSAlexander V. Chernikov 		return (-1);
17046c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
17056c2997ffSAlexander V. Chernikov 		return (1);
17066c2997ffSAlexander V. Chernikov 
17076c2997ffSAlexander V. Chernikov 	return (0);
17086c2997ffSAlexander V. Chernikov }
1709563b5ab1SAlexander V. Chernikov 
1710563b5ab1SAlexander V. Chernikov int
17116c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1712563b5ab1SAlexander V. Chernikov {
1713563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1714563b5ab1SAlexander V. Chernikov 	uint16_t key;
1715563b5ab1SAlexander V. Chernikov 
1716563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1717563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1718563b5ab1SAlexander V. Chernikov 
1719563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1720563b5ab1SAlexander V. Chernikov 		return (-1);
1721563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1722563b5ab1SAlexander V. Chernikov 		return (1);
1723563b5ab1SAlexander V. Chernikov 
1724563b5ab1SAlexander V. Chernikov 	return (0);
1725563b5ab1SAlexander V. Chernikov }
1726563b5ab1SAlexander V. Chernikov 
1727563b5ab1SAlexander V. Chernikov /*
1728563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1729563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1730563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1731563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1732563b5ab1SAlexander V. Chernikov  *
1733563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1734563b5ab1SAlexander V. Chernikov  */
1735563b5ab1SAlexander V. Chernikov char *
1736563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1737563b5ab1SAlexander V. Chernikov {
1738563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1739563b5ab1SAlexander V. Chernikov 
1740563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
17416c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1742563b5ab1SAlexander V. Chernikov 
1743563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1744563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1745563b5ab1SAlexander V. Chernikov 
1746563b5ab1SAlexander V. Chernikov 	return (NULL);
1747563b5ab1SAlexander V. Chernikov }
1748563b5ab1SAlexander V. Chernikov 
17496c2997ffSAlexander V. Chernikov void
17506c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
17516c2997ffSAlexander V. Chernikov {
17526c2997ffSAlexander V. Chernikov 
17536c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
17546c2997ffSAlexander V. Chernikov }
17556c2997ffSAlexander V. Chernikov 
17566c2997ffSAlexander V. Chernikov int
17576c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
17586c2997ffSAlexander V. Chernikov {
17596c2997ffSAlexander V. Chernikov 	int c, i, l;
17606c2997ffSAlexander V. Chernikov 
17616c2997ffSAlexander V. Chernikov 	/*
17626c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
17636c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1764ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
17656c2997ffSAlexander V. Chernikov 	 */
17666c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
17676c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
17686c2997ffSAlexander V. Chernikov 		return (EINVAL);
17696c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
17706c2997ffSAlexander V. Chernikov 		c = tablename[i];
17716c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
17726c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
17736c2997ffSAlexander V. Chernikov 			continue;
17746c2997ffSAlexander V. Chernikov 		return (EINVAL);
17756c2997ffSAlexander V. Chernikov 	}
17766c2997ffSAlexander V. Chernikov 
1777ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1778ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1779ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1780ac35ff17SAlexander V. Chernikov 
17816c2997ffSAlexander V. Chernikov 	return (0);
17826c2997ffSAlexander V. Chernikov }
17836c2997ffSAlexander V. Chernikov 
1784