xref: /freebsd/sbin/ipfw/tables.c (revision be695df9)
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,
7081d3153dSAlexander V. Chernikov     char *key, 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 	/* Set some defaults to preserve compability */
395ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
396ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
397ac35ff17SAlexander V. Chernikov 
398ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
399be695df9SAlexander V. Chernikov 		tcmd = get_token(tablenewcmds, *av, "option");
400ac35ff17SAlexander V. Chernikov 		ac--; av++;
401ac35ff17SAlexander V. Chernikov 
402ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
4034c0c07a5SAlexander V. Chernikov 		case TOK_LIMIT:
4044c0c07a5SAlexander V. Chernikov 			NEED1("limit value required");
4054c0c07a5SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
4064c0c07a5SAlexander V. Chernikov 			ac--; av++;
4074c0c07a5SAlexander V. Chernikov 			break;
408ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
409ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
410914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
411914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
412914bffb6SAlexander V. Chernikov 				*p++ = '\0';
413ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
414914bffb6SAlexander V. Chernikov 			if (val == -1) {
415914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
416914bffb6SAlexander V. Chernikov 				    ", ");
417914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
418914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
419ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
420914bffb6SAlexander V. Chernikov 			}
421914bffb6SAlexander V. Chernikov 			xi.type = val;
422914bffb6SAlexander V. Chernikov 			if (p != NULL) {
423914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
424914bffb6SAlexander V. Chernikov 				if (error != 0)
425914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
426914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
427914bffb6SAlexander V. Chernikov 			}
428914bffb6SAlexander V. Chernikov 			ac--; av++;
429ac35ff17SAlexander V. Chernikov 			break;
430ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
431ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
432ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
433ac35ff17SAlexander V. Chernikov 			if (val != -1) {
434ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
435ac35ff17SAlexander V. Chernikov 				ac--; av++;
436ac35ff17SAlexander V. Chernikov 				break;
437ac35ff17SAlexander V. Chernikov 			}
438ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
439ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
440ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
441ac35ff17SAlexander V. Chernikov 			break;
442adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
443adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
444adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
445adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
446adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
447adf3b2b9SAlexander V. Chernikov 				ac--; av++;
448adf3b2b9SAlexander V. Chernikov 				break;
449adf3b2b9SAlexander V. Chernikov 			}
450adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
451adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown format type: %s. Supported: %s",
452adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
453adf3b2b9SAlexander V. Chernikov 			break;
454ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
455ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
456ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
457ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
458ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
459ac35ff17SAlexander V. Chernikov 			ac--; av++;
460ac35ff17SAlexander V. Chernikov 			break;
4614f43138aSAlexander V. Chernikov 		case TOK_LOCK:
4624f43138aSAlexander V. Chernikov 			xi.flags |= IPFW_TGFLAGS_LOCKED;
4634f43138aSAlexander V. Chernikov 			break;
464ac35ff17SAlexander V. Chernikov 		}
465ac35ff17SAlexander V. Chernikov 	}
466ac35ff17SAlexander V. Chernikov 
467ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
468ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
469f1220db8SAlexander V. Chernikov }
470f1220db8SAlexander V. Chernikov 
471f1220db8SAlexander V. Chernikov /*
472ac35ff17SAlexander V. Chernikov  * Creates new table
473ac35ff17SAlexander V. Chernikov  *
474ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
475ac35ff17SAlexander V. Chernikov  *
476f1220db8SAlexander V. Chernikov  * Returns 0 on success.
477f1220db8SAlexander V. Chernikov  */
478f1220db8SAlexander V. Chernikov static int
479ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
480f1220db8SAlexander V. Chernikov {
481ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
482ac35ff17SAlexander V. Chernikov 	int error;
483f1220db8SAlexander V. Chernikov 
484ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
485ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
486ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
487ac35ff17SAlexander V. Chernikov 
488ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
489ac35ff17SAlexander V. Chernikov 
490ac35ff17SAlexander V. Chernikov 	return (error);
491ac35ff17SAlexander V. Chernikov }
492ac35ff17SAlexander V. Chernikov 
493ac35ff17SAlexander V. Chernikov /*
494adf3b2b9SAlexander V. Chernikov  * Modifies existing table
495adf3b2b9SAlexander V. Chernikov  *
496adf3b2b9SAlexander V. Chernikov  * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
497adf3b2b9SAlexander V. Chernikov  */
498adf3b2b9SAlexander V. Chernikov static void
499adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[])
500adf3b2b9SAlexander V. Chernikov {
501adf3b2b9SAlexander V. Chernikov 	ipfw_xtable_info xi;
502adf3b2b9SAlexander V. Chernikov 	int error, tcmd, val;
503adf3b2b9SAlexander V. Chernikov 	size_t sz;
504adf3b2b9SAlexander V. Chernikov 	char tbuf[128];
505adf3b2b9SAlexander V. Chernikov 
506adf3b2b9SAlexander V. Chernikov 	sz = sizeof(tbuf);
507adf3b2b9SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
508adf3b2b9SAlexander V. Chernikov 
509adf3b2b9SAlexander V. Chernikov 	while (ac > 0) {
510be695df9SAlexander V. Chernikov 		tcmd = get_token(tablenewcmds, *av, "option");
511adf3b2b9SAlexander V. Chernikov 		ac--; av++;
512adf3b2b9SAlexander V. Chernikov 
513adf3b2b9SAlexander V. Chernikov 		switch (tcmd) {
514adf3b2b9SAlexander V. Chernikov 		case TOK_LIMIT:
515adf3b2b9SAlexander V. Chernikov 			NEED1("limit value required");
516adf3b2b9SAlexander V. Chernikov 			xi.limit = strtol(*av, NULL, 10);
517adf3b2b9SAlexander V. Chernikov 			xi.mflags |= IPFW_TMFLAGS_LIMIT;
518adf3b2b9SAlexander V. Chernikov 			ac--; av++;
519adf3b2b9SAlexander V. Chernikov 			break;
520adf3b2b9SAlexander V. Chernikov 		case TOK_FTYPE:
521adf3b2b9SAlexander V. Chernikov 			NEED1("table value format type required");
522adf3b2b9SAlexander V. Chernikov 			val = match_token(tablefvaltypes, *av);
523adf3b2b9SAlexander V. Chernikov 			if (val != -1) {
524adf3b2b9SAlexander V. Chernikov 				xi.vftype = val;
525adf3b2b9SAlexander V. Chernikov 				xi.mflags |= IPFW_TMFLAGS_FTYPE;
526adf3b2b9SAlexander V. Chernikov 				ac--; av++;
527adf3b2b9SAlexander V. Chernikov 				break;
528adf3b2b9SAlexander V. Chernikov 			}
529adf3b2b9SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
530adf3b2b9SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
531adf3b2b9SAlexander V. Chernikov 			    *av, tbuf);
532adf3b2b9SAlexander V. Chernikov 			break;
533adf3b2b9SAlexander V. Chernikov 		}
534adf3b2b9SAlexander V. Chernikov 	}
535adf3b2b9SAlexander V. Chernikov 
536adf3b2b9SAlexander V. Chernikov 	if ((error = table_do_modify(oh, &xi)) != 0)
537adf3b2b9SAlexander V. Chernikov 		err(EX_OSERR, "Table modification failed");
538adf3b2b9SAlexander V. Chernikov }
539adf3b2b9SAlexander V. Chernikov 
540adf3b2b9SAlexander V. Chernikov /*
541adf3b2b9SAlexander V. Chernikov  * Modifies existing table.
542adf3b2b9SAlexander V. Chernikov  *
543adf3b2b9SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
544adf3b2b9SAlexander V. Chernikov  *
545adf3b2b9SAlexander V. Chernikov  * Returns 0 on success.
546adf3b2b9SAlexander V. Chernikov  */
547adf3b2b9SAlexander V. Chernikov static int
548adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
549adf3b2b9SAlexander V. Chernikov {
550adf3b2b9SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
551adf3b2b9SAlexander V. Chernikov 	int error;
552adf3b2b9SAlexander V. Chernikov 
553adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
554adf3b2b9SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
555adf3b2b9SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
556adf3b2b9SAlexander V. Chernikov 
557adf3b2b9SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
558adf3b2b9SAlexander V. Chernikov 
559adf3b2b9SAlexander V. Chernikov 	return (error);
560adf3b2b9SAlexander V. Chernikov }
5614f43138aSAlexander V. Chernikov 
5624f43138aSAlexander V. Chernikov /*
5634f43138aSAlexander V. Chernikov  * Locks or unlocks given table
5644f43138aSAlexander V. Chernikov  */
5654f43138aSAlexander V. Chernikov static void
5664f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock)
5674f43138aSAlexander V. Chernikov {
5684f43138aSAlexander V. Chernikov 	ipfw_xtable_info xi;
5694f43138aSAlexander V. Chernikov 	int error;
5704f43138aSAlexander V. Chernikov 
5714f43138aSAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
5724f43138aSAlexander V. Chernikov 
5734f43138aSAlexander V. Chernikov 	xi.mflags |= IPFW_TMFLAGS_LOCK;
5744f43138aSAlexander V. Chernikov 	xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0;
5754f43138aSAlexander V. Chernikov 
5764f43138aSAlexander V. Chernikov 	if ((error = table_do_modify(oh, &xi)) != 0)
5774f43138aSAlexander V. Chernikov 		err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock");
5784f43138aSAlexander V. Chernikov }
5794f43138aSAlexander V. Chernikov 
580adf3b2b9SAlexander V. Chernikov /*
581ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
582ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
583ac35ff17SAlexander V. Chernikov  */
584ac35ff17SAlexander V. Chernikov static int
585ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
586ac35ff17SAlexander V. Chernikov {
587ac35ff17SAlexander V. Chernikov 
588ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
589f1220db8SAlexander V. Chernikov 		return (-1);
590f1220db8SAlexander V. Chernikov 
591f1220db8SAlexander V. Chernikov 	return (0);
592f1220db8SAlexander V. Chernikov }
593f1220db8SAlexander V. Chernikov 
594f1220db8SAlexander V. Chernikov /*
595ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
596f1220db8SAlexander V. Chernikov  * Returns 0 on success.
597f1220db8SAlexander V. Chernikov  */
598f1220db8SAlexander V. Chernikov static int
599ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
600f1220db8SAlexander V. Chernikov {
601f1220db8SAlexander V. Chernikov 
602ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
603f1220db8SAlexander V. Chernikov 		return (-1);
604f1220db8SAlexander V. Chernikov 
605f1220db8SAlexander V. Chernikov 	return (0);
606f1220db8SAlexander V. Chernikov }
607f1220db8SAlexander V. Chernikov 
60846d52008SAlexander V. Chernikov static int
60946d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second)
61046d52008SAlexander V. Chernikov {
61146d52008SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
61246d52008SAlexander V. Chernikov 	int error;
61346d52008SAlexander V. Chernikov 
61446d52008SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
61546d52008SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
61646d52008SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
61746d52008SAlexander V. Chernikov 	table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
61846d52008SAlexander V. Chernikov 
61946d52008SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
62046d52008SAlexander V. Chernikov 
62146d52008SAlexander V. Chernikov 	return (error);
62246d52008SAlexander V. Chernikov }
62346d52008SAlexander V. Chernikov 
62446d52008SAlexander V. Chernikov /*
62546d52008SAlexander V. Chernikov  * Swaps given table with @second one.
62646d52008SAlexander V. Chernikov  */
62746d52008SAlexander V. Chernikov static int
62846d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second)
62946d52008SAlexander V. Chernikov {
63046d52008SAlexander V. Chernikov 	int error;
63146d52008SAlexander V. Chernikov 
63246d52008SAlexander V. Chernikov 	if (table_check_name(second) != 0)
63346d52008SAlexander V. Chernikov 		errx(EX_USAGE, "table name %s is invalid", second);
63446d52008SAlexander V. Chernikov 
63546d52008SAlexander V. Chernikov 	error = table_do_swap(oh, second);
63646d52008SAlexander V. Chernikov 
63746d52008SAlexander V. Chernikov 	switch (error) {
63846d52008SAlexander V. Chernikov 	case EINVAL:
63946d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check types");
64046d52008SAlexander V. Chernikov 	case EFBIG:
64146d52008SAlexander V. Chernikov 		errx(EX_USAGE, "Unable to swap table: check limits");
64246d52008SAlexander V. Chernikov 	}
64346d52008SAlexander V. Chernikov 
64446d52008SAlexander V. Chernikov 	return (0);
64546d52008SAlexander V. Chernikov }
64646d52008SAlexander V. Chernikov 
64746d52008SAlexander V. Chernikov 
648f1220db8SAlexander V. Chernikov /*
649ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
650f1220db8SAlexander V. Chernikov  * it inside @i.
651f1220db8SAlexander V. Chernikov  * Returns 0 on success.
652f1220db8SAlexander V. Chernikov  */
653f1220db8SAlexander V. Chernikov static int
654ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
655f1220db8SAlexander V. Chernikov {
656f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
657ac35ff17SAlexander V. Chernikov 	int error;
658f1220db8SAlexander V. Chernikov 	size_t sz;
659f1220db8SAlexander V. Chernikov 
660f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
661f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
662ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
663f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
664f1220db8SAlexander V. Chernikov 
665ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
666ac35ff17SAlexander V. Chernikov 		return (error);
667f1220db8SAlexander V. Chernikov 
668f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
669ac35ff17SAlexander V. Chernikov 		return (EINVAL);
670f1220db8SAlexander V. Chernikov 
671f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
672f1220db8SAlexander V. Chernikov 
673f1220db8SAlexander V. Chernikov 	return (0);
674f1220db8SAlexander V. Chernikov }
675f1220db8SAlexander V. Chernikov 
6765f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = {
6775f379342SAlexander V. Chernikov       { "hash",		IPFW_TACLASS_HASH },
6785f379342SAlexander V. Chernikov       { "array",	IPFW_TACLASS_ARRAY },
6795f379342SAlexander V. Chernikov       { "radix",	IPFW_TACLASS_RADIX },
6805f379342SAlexander V. Chernikov       { NULL, 0 }
6815f379342SAlexander V. Chernikov };
6825f379342SAlexander V. Chernikov 
6835f379342SAlexander V. Chernikov struct ta_cldata {
6845f379342SAlexander V. Chernikov 	uint8_t		taclass;
6855f379342SAlexander V. Chernikov 	uint8_t		spare4;
6865f379342SAlexander V. Chernikov 	uint16_t	itemsize;
6875f379342SAlexander V. Chernikov 	uint16_t	itemsize6;
6885f379342SAlexander V. Chernikov 	uint32_t	size;
6895f379342SAlexander V. Chernikov 	uint32_t	count;
6905f379342SAlexander V. Chernikov };
6915f379342SAlexander V. Chernikov 
6925f379342SAlexander V. Chernikov /*
6935f379342SAlexander V. Chernikov  * Print global/per-AF table @i algorithm info.
6945f379342SAlexander V. Chernikov  */
6955f379342SAlexander V. Chernikov static void
6965f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
6975f379342SAlexander V. Chernikov     const char *af, const char *taclass)
6985f379342SAlexander V. Chernikov {
6995f379342SAlexander V. Chernikov 
7005f379342SAlexander V. Chernikov 	switch (d->taclass) {
7015f379342SAlexander V. Chernikov 	case IPFW_TACLASS_HASH:
7025f379342SAlexander V. Chernikov 	case IPFW_TACLASS_ARRAY:
7035f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
7045f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
7055f379342SAlexander V. Chernikov 			printf("  size: %u items: %u itemsize: %u\n",
7065f379342SAlexander V. Chernikov 			    d->size, d->count, d->itemsize);
7075f379342SAlexander V. Chernikov 		else
7085f379342SAlexander V. Chernikov 			printf("  size: %u items: %u "
7095f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
7105f379342SAlexander V. Chernikov 			    d->size, d->count,
7115f379342SAlexander V. Chernikov 			    d->itemsize, d->itemsize6);
7125f379342SAlexander V. Chernikov 		break;
7135f379342SAlexander V. Chernikov 	case IPFW_TACLASS_RADIX:
7145f379342SAlexander V. Chernikov 		printf(" %salgorithm %s info\n", af, taclass);
7155f379342SAlexander V. Chernikov 		if (d->itemsize == d->itemsize6)
7165f379342SAlexander V. Chernikov 			printf("  items: %u itemsize: %u\n",
7175f379342SAlexander V. Chernikov 			    d->count, d->itemsize);
7185f379342SAlexander V. Chernikov 		else
7195f379342SAlexander V. Chernikov 			printf("  items: %u "
7205f379342SAlexander V. Chernikov 			    "itemsize4: %u itemsize6: %u\n",
7215f379342SAlexander V. Chernikov 			    d->count, d->itemsize, d->itemsize6);
7225f379342SAlexander V. Chernikov 		break;
7235f379342SAlexander V. Chernikov 	default:
7245f379342SAlexander V. Chernikov 		printf(" algo class: %s\n", taclass);
7255f379342SAlexander V. Chernikov 	}
7265f379342SAlexander V. Chernikov }
7275f379342SAlexander V. Chernikov 
728f1220db8SAlexander V. Chernikov /*
729f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
730f1220db8SAlexander V. Chernikov  */
731f1220db8SAlexander V. Chernikov static int
732f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
733f1220db8SAlexander V. Chernikov {
734adf3b2b9SAlexander V. Chernikov 	const char *vtype, *vftype;
7355f379342SAlexander V. Chernikov 	ipfw_ta_tinfo *tainfo;
7365f379342SAlexander V. Chernikov 	int afdata, afitem;
7375f379342SAlexander V. Chernikov 	struct ta_cldata d;
738adf3b2b9SAlexander V. Chernikov 	char ttype[64], tvtype[64];
739f1220db8SAlexander V. Chernikov 
740914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
741ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
742ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
743adf3b2b9SAlexander V. Chernikov 	if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL)
744adf3b2b9SAlexander V. Chernikov 		vftype = "unknown";
745adf3b2b9SAlexander V. Chernikov 	if (strcmp(vtype, vftype) != 0)
746adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype);
747adf3b2b9SAlexander V. Chernikov 	else
748adf3b2b9SAlexander V. Chernikov 		snprintf(tvtype, sizeof(tvtype), "%s", vtype);
749ac35ff17SAlexander V. Chernikov 
750914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
7514f43138aSAlexander V. Chernikov 	if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
7524f43138aSAlexander V. Chernikov 		printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
7534f43138aSAlexander V. Chernikov 	else
754914bffb6SAlexander V. Chernikov 		printf(" kindex: %d, type: %s\n", i->kidx, ttype);
755adf3b2b9SAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
7569d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
757f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
7584c0c07a5SAlexander V. Chernikov 	if (i->limit > 0)
7594c0c07a5SAlexander V. Chernikov 		printf(" limit: %u\n", i->limit);
760f1220db8SAlexander V. Chernikov 
761358b9d09SAlexander V. Chernikov 	/* Print algo-specific info if requested & set  */
762358b9d09SAlexander V. Chernikov 	if (arg == NULL)
763358b9d09SAlexander V. Chernikov 		return (0);
764358b9d09SAlexander V. Chernikov 
7655f379342SAlexander V. Chernikov 	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
7665f379342SAlexander V. Chernikov 		return (0);
7675f379342SAlexander V. Chernikov 	tainfo = &i->ta_info;
7685f379342SAlexander V. Chernikov 
7695f379342SAlexander V. Chernikov 	afdata = 0;
7705f379342SAlexander V. Chernikov 	afitem = 0;
7715f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
7725f379342SAlexander V. Chernikov 		afdata = 1;
7735f379342SAlexander V. Chernikov 	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
7745f379342SAlexander V. Chernikov 		afitem = 1;
7755f379342SAlexander V. Chernikov 
7765f379342SAlexander V. Chernikov 	memset(&d, 0, sizeof(d));
7775f379342SAlexander V. Chernikov 	d.taclass = tainfo->taclass4;
7785f379342SAlexander V. Chernikov 	d.size = tainfo->size4;
7795f379342SAlexander V. Chernikov 	d.count = tainfo->count4;
7805f379342SAlexander V. Chernikov 	d.itemsize = tainfo->itemsize4;
7815f379342SAlexander V. Chernikov 	if (afdata == 0 && afitem != 0)
7825f379342SAlexander V. Chernikov 		d.itemsize6 = tainfo->itemsize6;
7835f379342SAlexander V. Chernikov 	else
7845f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
7855f379342SAlexander V. Chernikov 	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7865f379342SAlexander V. Chernikov 		vtype = "unknown";
7875f379342SAlexander V. Chernikov 
7885f379342SAlexander V. Chernikov 	if (afdata == 0) {
7895f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "", vtype);
7905f379342SAlexander V. Chernikov 	} else {
7915f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv4 ", vtype);
7925f379342SAlexander V. Chernikov 		memset(&d, 0, sizeof(d));
7935f379342SAlexander V. Chernikov 		d.taclass = tainfo->taclass6;
7945f379342SAlexander V. Chernikov 		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
7955f379342SAlexander V. Chernikov 			vtype = "unknown";
7965f379342SAlexander V. Chernikov 		d.size = tainfo->size6;
7975f379342SAlexander V. Chernikov 		d.count = tainfo->count6;
7985f379342SAlexander V. Chernikov 		d.itemsize = tainfo->itemsize6;
7995f379342SAlexander V. Chernikov 		d.itemsize6 = d.itemsize;
8005f379342SAlexander V. Chernikov 		table_show_tainfo(i, &d, "IPv6 ", vtype);
8015f379342SAlexander V. Chernikov 	}
8025f379342SAlexander V. Chernikov 
803f1220db8SAlexander V. Chernikov 	return (0);
804f1220db8SAlexander V. Chernikov }
805f1220db8SAlexander V. Chernikov 
806f1220db8SAlexander V. Chernikov 
807f1220db8SAlexander V. Chernikov /*
808f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
809f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
810f1220db8SAlexander V. Chernikov  */
811f1220db8SAlexander V. Chernikov 
812f1220db8SAlexander V. Chernikov static int
813f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
814f1220db8SAlexander V. Chernikov {
815f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
81681d3153dSAlexander V. Chernikov 	int error;
817f1220db8SAlexander V. Chernikov 
818720ee730SAlexander V. Chernikov 	if ((error = table_do_get_list(i, &oh)) != 0) {
81981d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
82081d3153dSAlexander V. Chernikov 		return (error);
82181d3153dSAlexander V. Chernikov 	}
82281d3153dSAlexander V. Chernikov 
823f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
824f1220db8SAlexander V. Chernikov 
825f1220db8SAlexander V. Chernikov 	free(oh);
826f1220db8SAlexander V. Chernikov 	return (0);
827f1220db8SAlexander V. Chernikov }
828f1220db8SAlexander V. Chernikov 
829f1220db8SAlexander V. Chernikov static int
830f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
831f1220db8SAlexander V. Chernikov {
832ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
833f1220db8SAlexander V. Chernikov 
834ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
835ac35ff17SAlexander V. Chernikov 
836ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
837ac35ff17SAlexander V. Chernikov 
838ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
839f1220db8SAlexander V. Chernikov }
840f1220db8SAlexander V. Chernikov 
841ac35ff17SAlexander V. Chernikov static int
842ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
8433a845e10SAlexander V. Chernikov     ipfw_obj_tentry *tent, int count, int atomic)
844ac35ff17SAlexander V. Chernikov {
845db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
8463a845e10SAlexander V. Chernikov 	ipfw_obj_tentry *tent_base;
8473a845e10SAlexander V. Chernikov 	caddr_t pbuf;
848db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
8493a845e10SAlexander V. Chernikov 	int error, i;
8503a845e10SAlexander V. Chernikov 	size_t sz;
851ac35ff17SAlexander V. Chernikov 
8523a845e10SAlexander V. Chernikov 	sz = sizeof(*ctlv) + sizeof(*tent) * count;
8533a845e10SAlexander V. Chernikov 	if (count == 1) {
854ac35ff17SAlexander V. Chernikov 		memset(xbuf, 0, sizeof(xbuf));
8553a845e10SAlexander V. Chernikov 		pbuf = xbuf;
8563a845e10SAlexander V. Chernikov 	} else {
8573a845e10SAlexander V. Chernikov 		if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL)
8583a845e10SAlexander V. Chernikov 			return (ENOMEM);
8593a845e10SAlexander V. Chernikov 	}
8603a845e10SAlexander V. Chernikov 
8613a845e10SAlexander V. Chernikov 	memcpy(pbuf, oh, sizeof(*oh));
8623a845e10SAlexander V. Chernikov 	oh = (ipfw_obj_header *)pbuf;
863ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
864ac35ff17SAlexander V. Chernikov 
865db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
8663a845e10SAlexander V. Chernikov 	ctlv->count = count;
8673a845e10SAlexander V. Chernikov 	ctlv->head.length = sz;
8683a845e10SAlexander V. Chernikov 	if (atomic != 0)
8693a845e10SAlexander V. Chernikov 		ctlv->flags |= IPFW_CTF_ATOMIC;
870db785d31SAlexander V. Chernikov 
8713a845e10SAlexander V. Chernikov 	tent_base = tent;
8723a845e10SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent) * count);
873db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
8743a845e10SAlexander V. Chernikov 	for (i = 0; i < count; i++, tent++) {
875ac35ff17SAlexander V. Chernikov 		tent->head.length = sizeof(ipfw_obj_tentry);
8763a845e10SAlexander V. Chernikov 		tent->idx = oh->idx;
8773a845e10SAlexander V. Chernikov 	}
878ac35ff17SAlexander V. Chernikov 
8793a845e10SAlexander V. Chernikov 	sz += sizeof(*oh);
8803a845e10SAlexander V. Chernikov 	error = do_get3(cmd, &oh->opheader, &sz);
8813a845e10SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
8823a845e10SAlexander V. Chernikov 	/* Copy result back to provided buffer */
8833a845e10SAlexander V. Chernikov 	memcpy(tent_base, ctlv + 1, sizeof(*tent) * count);
8843a845e10SAlexander V. Chernikov 
8853a845e10SAlexander V. Chernikov 	if (pbuf != xbuf)
8863a845e10SAlexander V. Chernikov 		free(pbuf);
887ac35ff17SAlexander V. Chernikov 
888ac35ff17SAlexander V. Chernikov 	return (error);
889ac35ff17SAlexander V. Chernikov }
890ac35ff17SAlexander V. Chernikov 
891ac35ff17SAlexander V. Chernikov static void
8923a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add,
8933a845e10SAlexander V. Chernikov     int quiet, int update, int atomic)
894ac35ff17SAlexander V. Chernikov {
8953a845e10SAlexander V. Chernikov 	ipfw_obj_tentry *ptent, tent, *tent_buf;
89681d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
897ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
8983a845e10SAlexander V. Chernikov 	int cmd, count, error, i, ignored;
8993a845e10SAlexander V. Chernikov 	char *texterr, *etxt, *px;
900ac35ff17SAlexander V. Chernikov 
901ac35ff17SAlexander V. Chernikov 	if (ac == 0)
902ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
903ac35ff17SAlexander V. Chernikov 
904ac35ff17SAlexander V. Chernikov 	if (add != 0) {
905ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
9064c0c07a5SAlexander V. Chernikov 		texterr = "Adding record failed";
907ac35ff17SAlexander V. Chernikov 	} else {
908ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
9094c0c07a5SAlexander V. Chernikov 		texterr = "Deleting record failed";
910ac35ff17SAlexander V. Chernikov 	}
911ac35ff17SAlexander V. Chernikov 
9123a845e10SAlexander V. Chernikov 	/*
9133a845e10SAlexander V. Chernikov 	 * Calculate number of entries:
9143a845e10SAlexander V. Chernikov 	 * Assume [key val] x N for add
9153a845e10SAlexander V. Chernikov 	 * and
9163a845e10SAlexander V. Chernikov 	 * key x N for delete
9173a845e10SAlexander V. Chernikov 	 */
9183a845e10SAlexander V. Chernikov 	count = (add != 0) ? ac / 2 + 1 : ac;
9193a845e10SAlexander V. Chernikov 
9203a845e10SAlexander V. Chernikov 	if (count <= 1) {
9213a845e10SAlexander V. Chernikov 		/* Adding single entry with/without value */
9223a845e10SAlexander V. Chernikov 		memset(&tent, 0, sizeof(tent));
9233a845e10SAlexander V. Chernikov 		tent_buf = &tent;
9243a845e10SAlexander V. Chernikov 	} else {
9253a845e10SAlexander V. Chernikov 
9263a845e10SAlexander V. Chernikov 		if ((tent_buf = calloc(count, sizeof(tent))) == NULL)
9273a845e10SAlexander V. Chernikov 			errx(EX_OSERR,
9283a845e10SAlexander V. Chernikov 			    "Unable to allocate memory for all entries");
9293a845e10SAlexander V. Chernikov 	}
9303a845e10SAlexander V. Chernikov 	ptent = tent_buf;
9313a845e10SAlexander V. Chernikov 
9323a845e10SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
9333a845e10SAlexander V. Chernikov 	count = 0;
9343a845e10SAlexander V. Chernikov 	while (ac > 0) {
9353a845e10SAlexander V. Chernikov 		tentry_fill_key(oh, ptent, *av, &type, &vtype, &xi);
9363a845e10SAlexander V. Chernikov 
9373a845e10SAlexander V. Chernikov 		/*
9383a845e10SAlexander V. Chernikov 		 * compability layer: auto-create table if not exists
9393a845e10SAlexander V. Chernikov 		 */
9403a845e10SAlexander V. Chernikov 		if (xi.tablename[0] == '\0') {
9413a845e10SAlexander V. Chernikov 			xi.type = type;
9423a845e10SAlexander V. Chernikov 			xi.vtype = vtype;
9433a845e10SAlexander V. Chernikov 			strlcpy(xi.tablename, oh->ntlv.name,
9443a845e10SAlexander V. Chernikov 			    sizeof(xi.tablename));
9453a845e10SAlexander V. Chernikov 			fprintf(stderr, "DEPRECATED: inserting data info "
9463a845e10SAlexander V. Chernikov 			    "non-existent table %s. (auto-created)\n",
9473a845e10SAlexander V. Chernikov 			    xi.tablename);
9483a845e10SAlexander V. Chernikov 			table_do_create(oh, &xi);
9493a845e10SAlexander V. Chernikov 		}
9503a845e10SAlexander V. Chernikov 
9513a845e10SAlexander V. Chernikov 		oh->ntlv.type = type;
9523a845e10SAlexander V. Chernikov 		ac--; av++;
9533a845e10SAlexander V. Chernikov 
9543a845e10SAlexander V. Chernikov 		if (add != 0 && ac > 0) {
9553a845e10SAlexander V. Chernikov 			tentry_fill_value(oh, ptent, *av, type, vtype);
9563a845e10SAlexander V. Chernikov 			ac--; av++;
9573a845e10SAlexander V. Chernikov 		}
9583a845e10SAlexander V. Chernikov 
9593a845e10SAlexander V. Chernikov 		if (update != 0)
9603a845e10SAlexander V. Chernikov 			ptent->head.flags |= IPFW_TF_UPDATE;
9613a845e10SAlexander V. Chernikov 
9623a845e10SAlexander V. Chernikov 		count++;
9633a845e10SAlexander V. Chernikov 		ptent++;
9643a845e10SAlexander V. Chernikov 	}
9653a845e10SAlexander V. Chernikov 
9663a845e10SAlexander V. Chernikov 	error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
9673a845e10SAlexander V. Chernikov 
9683a845e10SAlexander V. Chernikov 	/*
9693a845e10SAlexander V. Chernikov 	 * Compatibility stuff: do not yell on duplicate keys or
9703a845e10SAlexander V. Chernikov 	 * failed deletions.
9713a845e10SAlexander V. Chernikov 	 */
9723a845e10SAlexander V. Chernikov 	if (error == 0 || (error == EEXIST && add != 0) ||
9733a845e10SAlexander V. Chernikov 	    (error == ENOENT && add == 0)) {
9743a845e10SAlexander V. Chernikov 		if (quiet != 0) {
9753a845e10SAlexander V. Chernikov 			if (tent_buf != &tent)
9763a845e10SAlexander V. Chernikov 				free(tent_buf);
9773a845e10SAlexander V. Chernikov 			return;
9783a845e10SAlexander V. Chernikov 		}
9793a845e10SAlexander V. Chernikov 	}
9803a845e10SAlexander V. Chernikov 
9813a845e10SAlexander V. Chernikov 	/* Report results back */
9823a845e10SAlexander V. Chernikov 	ptent = tent_buf;
9833a845e10SAlexander V. Chernikov 	for (i = 0; i < count; ptent++, i++) {
9843a845e10SAlexander V. Chernikov 		ignored = 0;
9853a845e10SAlexander V. Chernikov 		switch (ptent->result) {
9863a845e10SAlexander V. Chernikov 		case IPFW_TR_ADDED:
9873a845e10SAlexander V. Chernikov 			px = "added";
9883a845e10SAlexander V. Chernikov 			break;
9893a845e10SAlexander V. Chernikov 		case IPFW_TR_DELETED:
9903a845e10SAlexander V. Chernikov 			px = "deleted";
9913a845e10SAlexander V. Chernikov 			break;
9923a845e10SAlexander V. Chernikov 		case IPFW_TR_UPDATED:
9933a845e10SAlexander V. Chernikov 			px = "updated";
9943a845e10SAlexander V. Chernikov 			break;
9953a845e10SAlexander V. Chernikov 		case IPFW_TR_LIMIT:
9963a845e10SAlexander V. Chernikov 			px = "limit";
9973a845e10SAlexander V. Chernikov 			ignored = 1;
9983a845e10SAlexander V. Chernikov 			break;
9993a845e10SAlexander V. Chernikov 		case IPFW_TR_ERROR:
10003a845e10SAlexander V. Chernikov 			px = "error";
10013a845e10SAlexander V. Chernikov 			ignored = 1;
10023a845e10SAlexander V. Chernikov 			break;
10033a845e10SAlexander V. Chernikov 		case IPFW_TR_NOTFOUND:
10043a845e10SAlexander V. Chernikov 			px = "notfound";
10053a845e10SAlexander V. Chernikov 			ignored = 1;
10063a845e10SAlexander V. Chernikov 			break;
10073a845e10SAlexander V. Chernikov 		case IPFW_TR_EXISTS:
10083a845e10SAlexander V. Chernikov 			px = "exists";
10093a845e10SAlexander V. Chernikov 			ignored = 1;
10103a845e10SAlexander V. Chernikov 			break;
10113a845e10SAlexander V. Chernikov 		case IPFW_TR_IGNORED:
10123a845e10SAlexander V. Chernikov 			px = "ignored";
10133a845e10SAlexander V. Chernikov 			ignored = 1;
10143a845e10SAlexander V. Chernikov 			break;
10153a845e10SAlexander V. Chernikov 		default:
10163a845e10SAlexander V. Chernikov 			px = "unknown";
10173a845e10SAlexander V. Chernikov 			ignored = 1;
10183a845e10SAlexander V. Chernikov 		}
10193a845e10SAlexander V. Chernikov 
10203a845e10SAlexander V. Chernikov 		if (error != 0 && atomic != 0 && ignored == 0)
10213a845e10SAlexander V. Chernikov 			printf("%s(reverted): ", px);
10223a845e10SAlexander V. Chernikov 		else
10233a845e10SAlexander V. Chernikov 			printf("%s: ", px);
10243a845e10SAlexander V. Chernikov 
10253a845e10SAlexander V. Chernikov 		table_show_entry(&xi, ptent);
10263a845e10SAlexander V. Chernikov 	}
10273a845e10SAlexander V. Chernikov 
10283a845e10SAlexander V. Chernikov 	if (tent_buf != &tent)
10293a845e10SAlexander V. Chernikov 		free(tent_buf);
10303a845e10SAlexander V. Chernikov 
10313a845e10SAlexander V. Chernikov 	if (error == 0)
10324c0c07a5SAlexander V. Chernikov 		return;
10334c0c07a5SAlexander V. Chernikov 
10344c0c07a5SAlexander V. Chernikov 	/* Try to provide more human-readable error */
10354c0c07a5SAlexander V. Chernikov 	switch (error) {
10364c0c07a5SAlexander V. Chernikov 	case EEXIST:
10374c0c07a5SAlexander V. Chernikov 		etxt = "record already exists";
10384c0c07a5SAlexander V. Chernikov 		break;
10394c0c07a5SAlexander V. Chernikov 	case EFBIG:
10404c0c07a5SAlexander V. Chernikov 		etxt = "limit hit";
10414c0c07a5SAlexander V. Chernikov 		break;
10424c0c07a5SAlexander V. Chernikov 	case ESRCH:
10434c0c07a5SAlexander V. Chernikov 		etxt = "table not found";
10444c0c07a5SAlexander V. Chernikov 		break;
10454c0c07a5SAlexander V. Chernikov 	case ENOENT:
10464c0c07a5SAlexander V. Chernikov 		etxt = "record not found";
10474c0c07a5SAlexander V. Chernikov 		break;
10484f43138aSAlexander V. Chernikov 	case EACCES:
10494f43138aSAlexander V. Chernikov 		etxt = "table is locked";
10504f43138aSAlexander V. Chernikov 		break;
10514c0c07a5SAlexander V. Chernikov 	default:
10524c0c07a5SAlexander V. Chernikov 		etxt = strerror(error);
10534c0c07a5SAlexander V. Chernikov 	}
10544c0c07a5SAlexander V. Chernikov 
10554c0c07a5SAlexander V. Chernikov 	errx(EX_OSERR, "%s: %s", texterr, etxt);
1056ac35ff17SAlexander V. Chernikov }
1057ac35ff17SAlexander V. Chernikov 
105881d3153dSAlexander V. Chernikov static int
105981d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
106081d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
106181d3153dSAlexander V. Chernikov {
106281d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
106381d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
106481d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
106581d3153dSAlexander V. Chernikov 	int error;
106681d3153dSAlexander V. Chernikov 	size_t sz;
106781d3153dSAlexander V. Chernikov 
106881d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
106981d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
107081d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
107181d3153dSAlexander V. Chernikov 
107281d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
107381d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
107481d3153dSAlexander V. Chernikov 	tent->idx = 1;
107581d3153dSAlexander V. Chernikov 
107681d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
107781d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
107881d3153dSAlexander V. Chernikov 
107981d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
108081d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
108181d3153dSAlexander V. Chernikov 		return (error);
108281d3153dSAlexander V. Chernikov 
108381d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
108481d3153dSAlexander V. Chernikov 		return (EINVAL);
108581d3153dSAlexander V. Chernikov 
108681d3153dSAlexander V. Chernikov 	*xtent = *tent;
108781d3153dSAlexander V. Chernikov 
108881d3153dSAlexander V. Chernikov 	return (0);
108981d3153dSAlexander V. Chernikov }
109081d3153dSAlexander V. Chernikov 
109181d3153dSAlexander V. Chernikov static void
109281d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
109381d3153dSAlexander V. Chernikov {
109481d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
109581d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
1096914bffb6SAlexander V. Chernikov 	char key[64];
109781d3153dSAlexander V. Chernikov 	int error;
109881d3153dSAlexander V. Chernikov 
109981d3153dSAlexander V. Chernikov 	if (ac == 0)
110081d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
110181d3153dSAlexander V. Chernikov 
1102914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
1103914bffb6SAlexander V. Chernikov 
11043a845e10SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
1105914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
110681d3153dSAlexander V. Chernikov 
110781d3153dSAlexander V. Chernikov 	switch (error) {
110881d3153dSAlexander V. Chernikov 	case 0:
110981d3153dSAlexander V. Chernikov 		break;
111081d3153dSAlexander V. Chernikov 	case ESRCH:
111181d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
111281d3153dSAlexander V. Chernikov 	case ENOENT:
111381d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
111481d3153dSAlexander V. Chernikov 	case ENOTSUP:
111581d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
111681d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
111781d3153dSAlexander V. Chernikov 	default:
111881d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
111981d3153dSAlexander V. Chernikov 	}
112081d3153dSAlexander V. Chernikov 
112181d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
112281d3153dSAlexander V. Chernikov }
1123ac35ff17SAlexander V. Chernikov 
1124ac35ff17SAlexander V. Chernikov static void
1125914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
1126914bffb6SAlexander V. Chernikov     uint8_t tflags)
1127ac35ff17SAlexander V. Chernikov {
1128914bffb6SAlexander V. Chernikov 	char *p, *pp;
1129ac35ff17SAlexander V. Chernikov 	int mask, af;
1130914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
1131914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
1132ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
1133914bffb6SAlexander V. Chernikov 	uint16_t port;
1134914bffb6SAlexander V. Chernikov 	struct protoent *pent;
1135914bffb6SAlexander V. Chernikov 	struct servent *sent;
1136ac35ff17SAlexander V. Chernikov 	int masklen;
1137ac35ff17SAlexander V. Chernikov 
1138ac35ff17SAlexander V. Chernikov 	masklen = 0;
1139ac35ff17SAlexander V. Chernikov 	af = 0;
1140ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
1141ac35ff17SAlexander V. Chernikov 
1142ac35ff17SAlexander V. Chernikov 	switch (type) {
1143ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1144ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
1145ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
1146ac35ff17SAlexander V. Chernikov 			*p = '\0';
1147ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
1148ac35ff17SAlexander V. Chernikov 		}
1149ac35ff17SAlexander V. Chernikov 
1150ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
1151ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
1152ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
1153ac35ff17SAlexander V. Chernikov 				    p + 1);
1154ac35ff17SAlexander V. Chernikov 
1155ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
1156ac35ff17SAlexander V. Chernikov 			af = AF_INET;
1157ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
1158ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
1159ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
1160ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
1161ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
1162ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
1163ac35ff17SAlexander V. Chernikov 				    p + 1);
1164ac35ff17SAlexander V. Chernikov 
1165ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
1166ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
1167ac35ff17SAlexander V. Chernikov 		} else {
1168ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
1169ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
1170ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
1171ac35ff17SAlexander V. Chernikov 
1172ac35ff17SAlexander V. Chernikov 			masklen = 32;
1173ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1174ac35ff17SAlexander V. Chernikov 			af = AF_INET;
1175ac35ff17SAlexander V. Chernikov 		}
1176ac35ff17SAlexander V. Chernikov 		break;
1177ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1178ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
1179ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
1180ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
1181ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
1182ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
1183ac35ff17SAlexander V. Chernikov 		break;
1184b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1185ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
1186ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
1187ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1188ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
1189ac35ff17SAlexander V. Chernikov 
1190ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
1191ac35ff17SAlexander V. Chernikov 		*pkey = key;
1192ac35ff17SAlexander V. Chernikov 		masklen = 32;
1193ac35ff17SAlexander V. Chernikov 		break;
1194914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1195914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1196914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
1197914bffb6SAlexander V. Chernikov 		af = 0;
1198914bffb6SAlexander V. Chernikov 
1199914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1200914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
1201914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1202914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1203914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1204914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1205914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1206914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1207914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1208914bffb6SAlexander V. Chernikov 				af = AF_INET;
1209914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
1210914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1211914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1212914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1213914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
1214914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1215914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
1216914bffb6SAlexander V. Chernikov 			}
1217914bffb6SAlexander V. Chernikov 
1218914bffb6SAlexander V. Chernikov 			arg = p;
1219914bffb6SAlexander V. Chernikov 		}
1220914bffb6SAlexander V. Chernikov 
1221914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
1222914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
1223914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1224914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1225914bffb6SAlexander V. Chernikov 
1226914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
1227914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
1228914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
1229914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
1230914bffb6SAlexander V. Chernikov 					    arg);
1231914bffb6SAlexander V. Chernikov 				else
1232914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
1233914bffb6SAlexander V. Chernikov 			}
1234914bffb6SAlexander V. Chernikov 
1235914bffb6SAlexander V. Chernikov 			if (key > 255)
1236914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
1237914bffb6SAlexander V. Chernikov 
1238914bffb6SAlexander V. Chernikov 			tfe->proto = key;
1239914bffb6SAlexander V. Chernikov 
1240914bffb6SAlexander V. Chernikov 			arg = p;
1241914bffb6SAlexander V. Chernikov 		}
1242914bffb6SAlexander V. Chernikov 
1243914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1244914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1245914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1246914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1247914bffb6SAlexander V. Chernikov 
1248914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1249914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1250914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1251914bffb6SAlexander V. Chernikov 					    arg);
1252914bffb6SAlexander V. Chernikov 				else
1253914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1254914bffb6SAlexander V. Chernikov 			}
1255914bffb6SAlexander V. Chernikov 
1256914bffb6SAlexander V. Chernikov 			tfe->sport = port;
1257914bffb6SAlexander V. Chernikov 
1258914bffb6SAlexander V. Chernikov 			arg = p;
1259914bffb6SAlexander V. Chernikov 		}
1260914bffb6SAlexander V. Chernikov 
1261914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
1262914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
1263914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1264914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1265914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
1266914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1267914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
1268914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1269914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1270914bffb6SAlexander V. Chernikov 				af = AF_INET;
1271914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
1272914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1273914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
1274914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
1275914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
1276914bffb6SAlexander V. Chernikov 				af = AF_INET6;
1277914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
1278914bffb6SAlexander V. Chernikov 			}
1279914bffb6SAlexander V. Chernikov 
1280914bffb6SAlexander V. Chernikov 			arg = p;
1281914bffb6SAlexander V. Chernikov 		}
1282914bffb6SAlexander V. Chernikov 
1283914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
1284914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1285914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
1286914bffb6SAlexander V. Chernikov 				*p++ = '\0';
1287914bffb6SAlexander V. Chernikov 
1288914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
1289914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
1290914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
1291914bffb6SAlexander V. Chernikov 					    arg);
1292914bffb6SAlexander V. Chernikov 				else
1293914bffb6SAlexander V. Chernikov 					key = sent->s_port;
1294914bffb6SAlexander V. Chernikov 			}
1295914bffb6SAlexander V. Chernikov 
1296914bffb6SAlexander V. Chernikov 			tfe->dport = port;
1297914bffb6SAlexander V. Chernikov 
1298914bffb6SAlexander V. Chernikov 			arg = p;
1299914bffb6SAlexander V. Chernikov 		}
1300914bffb6SAlexander V. Chernikov 
1301914bffb6SAlexander V. Chernikov 		tfe->af = af;
1302914bffb6SAlexander V. Chernikov 
1303914bffb6SAlexander V. Chernikov 		break;
1304914bffb6SAlexander V. Chernikov 
1305ac35ff17SAlexander V. Chernikov 	default:
1306ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
1307ac35ff17SAlexander V. Chernikov 	}
1308ac35ff17SAlexander V. Chernikov 
1309ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
1310ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
1311ac35ff17SAlexander V. Chernikov }
1312ac35ff17SAlexander V. Chernikov 
1313ac35ff17SAlexander V. Chernikov static void
1314ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
131581d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
1316ac35ff17SAlexander V. Chernikov {
1317914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
1318ac35ff17SAlexander V. Chernikov 	int error;
1319db785d31SAlexander V. Chernikov 	char *del;
1320ac35ff17SAlexander V. Chernikov 
1321ac35ff17SAlexander V. Chernikov 	type = 0;
1322914bffb6SAlexander V. Chernikov 	tflags = 0;
1323ac35ff17SAlexander V. Chernikov 	vtype = 0;
1324ac35ff17SAlexander V. Chernikov 
13253a845e10SAlexander V. Chernikov 	if (xi->tablename[0] == '\0')
132681d3153dSAlexander V. Chernikov 		error = table_get_info(oh, xi);
13273a845e10SAlexander V. Chernikov 	else
13283a845e10SAlexander V. Chernikov 		error = 0;
132981d3153dSAlexander V. Chernikov 
133081d3153dSAlexander V. Chernikov 	if (error == 0) {
133181d3153dSAlexander V. Chernikov 		/* Table found. */
133281d3153dSAlexander V. Chernikov 		type = xi->type;
1333914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
133481d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
133581d3153dSAlexander V. Chernikov 	} else {
133681d3153dSAlexander V. Chernikov 		if (error != ESRCH)
133781d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
133881d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
1339ac35ff17SAlexander V. Chernikov 		/*
134081d3153dSAlexander V. Chernikov 		 * Table does not exist.
134181d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
134281d3153dSAlexander V. Chernikov 		 * before failing.
1343ac35ff17SAlexander V. Chernikov 		 */
1344db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
1345db785d31SAlexander V. Chernikov 			*del = '\0';
1346ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
1347ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
1348ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
1349ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
1350ac35ff17SAlexander V. Chernikov 			/*
135181d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
135281d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
1353ac35ff17SAlexander V. Chernikov 			 */
135481d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
135581d3153dSAlexander V. Chernikov 		} else {
135681d3153dSAlexander V. Chernikov 			/* Inknown key */
135781d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1358db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
135981d3153dSAlexander V. Chernikov 		}
1360db785d31SAlexander V. Chernikov 		if (del != NULL)
1361db785d31SAlexander V. Chernikov 			*del = '/';
1362ac35ff17SAlexander V. Chernikov 	}
1363ac35ff17SAlexander V. Chernikov 
1364914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
1365ac35ff17SAlexander V. Chernikov 
1366ac35ff17SAlexander V. Chernikov 	*ptype = type;
1367ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
1368ac35ff17SAlexander V. Chernikov }
1369ac35ff17SAlexander V. Chernikov 
1370ac35ff17SAlexander V. Chernikov static void
1371ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1372ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
1373ac35ff17SAlexander V. Chernikov {
1374adf3b2b9SAlexander V. Chernikov 	uint32_t val;
1375ac35ff17SAlexander V. Chernikov 	char *p;
1376ac35ff17SAlexander V. Chernikov 
1377adf3b2b9SAlexander V. Chernikov 	/* Try to interpret as number first */
1378adf3b2b9SAlexander V. Chernikov 	tent->value = strtoul(arg, &p, 0);
1379adf3b2b9SAlexander V. Chernikov 	if (*p == '\0')
1380adf3b2b9SAlexander V. Chernikov 		return;
1381adf3b2b9SAlexander V. Chernikov 	if (inet_pton(AF_INET, arg, &val) == 1) {
1382adf3b2b9SAlexander V. Chernikov 		tent->value = ntohl(val);
1383adf3b2b9SAlexander V. Chernikov 		return;
1384adf3b2b9SAlexander V. Chernikov 	}
1385adf3b2b9SAlexander V. Chernikov 	/* Try hostname */
1386adf3b2b9SAlexander V. Chernikov 	if (lookup_host(arg, (struct in_addr *)&tent->value) == 0)
1387adf3b2b9SAlexander V. Chernikov 		return;
1388adf3b2b9SAlexander V. Chernikov 	errx(EX_OSERR, "Unable to parse value %s", arg);
1389adf3b2b9SAlexander V. Chernikov #if 0
1390ac35ff17SAlexander V. Chernikov 	switch (vtype) {
1391ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
1392ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
1393ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
1394ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
1395ac35ff17SAlexander V. Chernikov 		break;
1396ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
1397ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
1398ac35ff17SAlexander V. Chernikov 			break;
1399ac35ff17SAlexander V. Chernikov 		/* Try hostname */
1400ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
1401ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
1402ac35ff17SAlexander V. Chernikov 		break;
1403ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
1404ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
1405ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
1406ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
1407ac35ff17SAlexander V. Chernikov 		} else {
1408ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
1409ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
1410ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
1411ac35ff17SAlexander V. Chernikov 		}
1412ac35ff17SAlexander V. Chernikov 		tent->value = code;
1413ac35ff17SAlexander V. Chernikov 		break;
1414ac35ff17SAlexander V. Chernikov 	default:
1415ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
1416ac35ff17SAlexander V. Chernikov 	}
1417adf3b2b9SAlexander V. Chernikov #endif
1418ac35ff17SAlexander V. Chernikov }
1419f1220db8SAlexander V. Chernikov 
1420f1220db8SAlexander V. Chernikov /*
1421f1220db8SAlexander V. Chernikov  * Compare table names.
1422f1220db8SAlexander V. Chernikov  * Honor number comparison.
1423f1220db8SAlexander V. Chernikov  */
1424f1220db8SAlexander V. Chernikov static int
1425f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
1426f1220db8SAlexander V. Chernikov {
1427f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
1428f1220db8SAlexander V. Chernikov 
1429f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
1430f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
1431f1220db8SAlexander V. Chernikov 
143268394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
1433f1220db8SAlexander V. Chernikov }
1434f1220db8SAlexander V. Chernikov 
1435f1220db8SAlexander V. Chernikov /*
1436f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
1437f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
1438f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1439f1220db8SAlexander V. Chernikov  */
1440f1220db8SAlexander V. Chernikov static int
1441f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
1442f1220db8SAlexander V. Chernikov {
144328ea4fa3SAlexander V. Chernikov 	ipfw_obj_lheader *olh;
1444f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
1445f1220db8SAlexander V. Chernikov 	size_t sz;
1446f1220db8SAlexander V. Chernikov 	int i, error;
1447f1220db8SAlexander V. Chernikov 
144828ea4fa3SAlexander V. Chernikov 	/* Start with reasonable default */
144928ea4fa3SAlexander V. Chernikov 	sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
1450f1220db8SAlexander V. Chernikov 
145128ea4fa3SAlexander V. Chernikov 	for (;;) {
1452f1220db8SAlexander V. Chernikov 		if ((olh = calloc(1, sz)) == NULL)
1453f1220db8SAlexander V. Chernikov 			return (ENOMEM);
1454f1220db8SAlexander V. Chernikov 
1455f1220db8SAlexander V. Chernikov 		olh->size = sz;
145628ea4fa3SAlexander V. Chernikov 		error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz);
145728ea4fa3SAlexander V. Chernikov 		if (error == ENOMEM) {
145828ea4fa3SAlexander V. Chernikov 			sz = olh->size;
1459f1220db8SAlexander V. Chernikov 			free(olh);
146028ea4fa3SAlexander V. Chernikov 			continue;
146128ea4fa3SAlexander V. Chernikov 		} else if (error != 0) {
146228ea4fa3SAlexander V. Chernikov 			free(olh);
146328ea4fa3SAlexander V. Chernikov 			return (error);
1464f1220db8SAlexander V. Chernikov 		}
1465f1220db8SAlexander V. Chernikov 
1466f1220db8SAlexander V. Chernikov 		if (sort != 0)
1467f1220db8SAlexander V. Chernikov 			qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
1468f1220db8SAlexander V. Chernikov 
1469f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)(olh + 1);
1470f1220db8SAlexander V. Chernikov 		for (i = 0; i < olh->count; i++) {
1471f1220db8SAlexander V. Chernikov 			error = f(info, arg); /* Ignore errors for now */
1472f1220db8SAlexander V. Chernikov 			info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1473f1220db8SAlexander V. Chernikov 		}
1474f1220db8SAlexander V. Chernikov 
1475f1220db8SAlexander V. Chernikov 		free(olh);
147628ea4fa3SAlexander V. Chernikov 		break;
147728ea4fa3SAlexander V. Chernikov 	}
1478f1220db8SAlexander V. Chernikov 
1479f1220db8SAlexander V. Chernikov 	return (0);
1480f1220db8SAlexander V. Chernikov }
1481f1220db8SAlexander V. Chernikov 
148228ea4fa3SAlexander V. Chernikov 
1483f1220db8SAlexander V. Chernikov /*
1484f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1485720ee730SAlexander V. Chernikov  * eXtended format. Allocate buffer large enough
1486720ee730SAlexander V. Chernikov  * to store result. Called needs to free it later.
1487f1220db8SAlexander V. Chernikov  *
1488f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1489f1220db8SAlexander V. Chernikov  */
1490f1220db8SAlexander V. Chernikov static int
1491720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
1492f1220db8SAlexander V. Chernikov {
1493720ee730SAlexander V. Chernikov 	ipfw_obj_header *oh;
1494f1220db8SAlexander V. Chernikov 	size_t sz;
149581d3153dSAlexander V. Chernikov 	int error, c;
1496f1220db8SAlexander V. Chernikov 
149781d3153dSAlexander V. Chernikov 	sz = 0;
1498720ee730SAlexander V. Chernikov 	oh = NULL;
1499720ee730SAlexander V. Chernikov 	error = 0;
1500720ee730SAlexander V. Chernikov 	for (c = 0; c < 8; c++) {
150181d3153dSAlexander V. Chernikov 		if (sz < i->size)
1502720ee730SAlexander V. Chernikov 			sz = i->size + 44;
1503720ee730SAlexander V. Chernikov 		if (oh != NULL)
1504720ee730SAlexander V. Chernikov 			free(oh);
1505720ee730SAlexander V. Chernikov 		if ((oh = calloc(1, sz)) == NULL)
1506720ee730SAlexander V. Chernikov 			continue;
1507720ee730SAlexander V. Chernikov 		table_fill_objheader(oh, i);
1508d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
150981d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1510d3a4f924SAlexander V. Chernikov 
1511720ee730SAlexander V. Chernikov 		if (error == 0) {
1512720ee730SAlexander V. Chernikov 			*poh = oh;
1513720ee730SAlexander V. Chernikov 			return (0);
151481d3153dSAlexander V. Chernikov 		}
1515f1220db8SAlexander V. Chernikov 
1516720ee730SAlexander V. Chernikov 		if (error != ENOMEM)
1517720ee730SAlexander V. Chernikov 			break;
1518720ee730SAlexander V. Chernikov 	}
1519720ee730SAlexander V. Chernikov 	free(oh);
1520720ee730SAlexander V. Chernikov 
1521720ee730SAlexander V. Chernikov 	return (error);
1522f1220db8SAlexander V. Chernikov }
1523f1220db8SAlexander V. Chernikov 
1524f1220db8SAlexander V. Chernikov /*
1525f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1526f1220db8SAlexander V. Chernikov  */
1527f1220db8SAlexander V. Chernikov static void
1528f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1529f1220db8SAlexander V. Chernikov {
153081d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
153181d3153dSAlexander V. Chernikov 	uint32_t count;
1532f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1533f1220db8SAlexander V. Chernikov 
1534f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
153581d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1536f1220db8SAlexander V. Chernikov 
1537f1220db8SAlexander V. Chernikov 	if (need_header)
1538f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1539f1220db8SAlexander V. Chernikov 
1540f1220db8SAlexander V. Chernikov 	count = i->count;
1541f1220db8SAlexander V. Chernikov 	while (count > 0) {
154281d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
154381d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
154481d3153dSAlexander V. Chernikov 		count--;
154581d3153dSAlexander V. Chernikov 	}
154681d3153dSAlexander V. Chernikov }
154781d3153dSAlexander V. Chernikov 
154881d3153dSAlexander V. Chernikov static void
154981d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
155081d3153dSAlexander V. Chernikov {
1551914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1552914bffb6SAlexander V. Chernikov 	void *paddr;
155381d3153dSAlexander V. Chernikov 	uint32_t tval;
1554914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
155581d3153dSAlexander V. Chernikov 
155681d3153dSAlexander V. Chernikov 	tval = tent->value;
155781d3153dSAlexander V. Chernikov 
1558adf3b2b9SAlexander V. Chernikov 	if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
1559914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1560914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1561914bffb6SAlexander V. Chernikov 	} else
1562914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1563914bffb6SAlexander V. Chernikov 
1564f1220db8SAlexander V. Chernikov 	switch (i->type) {
1565f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1566f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
156781d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1568914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1569f1220db8SAlexander V. Chernikov 		break;
1570f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1571f1220db8SAlexander V. Chernikov 		/* Interface names */
1572914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1573b23d5de9SAlexander V. Chernikov 		break;
1574b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1575b23d5de9SAlexander V. Chernikov 		/* numbers */
1576914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1577b23d5de9SAlexander V. Chernikov 		break;
1578914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1579914bffb6SAlexander V. Chernikov 		/* flows */
1580914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1581914bffb6SAlexander V. Chernikov 		comma = "";
1582914bffb6SAlexander V. Chernikov 
1583914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1584914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1585914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1586914bffb6SAlexander V. Chernikov 			else
1587914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1588914bffb6SAlexander V. Chernikov 
1589914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1590914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1591914bffb6SAlexander V. Chernikov 			comma = ",";
1592914bffb6SAlexander V. Chernikov 		}
1593914bffb6SAlexander V. Chernikov 
1594914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1595914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1596914bffb6SAlexander V. Chernikov 			comma = ",";
1597914bffb6SAlexander V. Chernikov 		}
1598914bffb6SAlexander V. Chernikov 
1599914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1600914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1601914bffb6SAlexander V. Chernikov 			comma = ",";
1602914bffb6SAlexander V. Chernikov 		}
1603914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1604914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1605914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1606914bffb6SAlexander V. Chernikov 			else
1607914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1608914bffb6SAlexander V. Chernikov 
1609914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1610914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1611914bffb6SAlexander V. Chernikov 			comma = ",";
1612914bffb6SAlexander V. Chernikov 		}
1613914bffb6SAlexander V. Chernikov 
1614914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1615914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1616914bffb6SAlexander V. Chernikov 			comma = ",";
1617914bffb6SAlexander V. Chernikov 		}
1618914bffb6SAlexander V. Chernikov 
1619914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1620f1220db8SAlexander V. Chernikov 	}
1621f1220db8SAlexander V. Chernikov }
1622f1220db8SAlexander V. Chernikov 
16239d099b4fSAlexander V. Chernikov static int
16249d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
16259d099b4fSAlexander V. Chernikov {
16269d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
16279d099b4fSAlexander V. Chernikov 	size_t sz;
16289d099b4fSAlexander V. Chernikov 	int error;
16299d099b4fSAlexander V. Chernikov 
16309d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
16319d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
16329d099b4fSAlexander V. Chernikov 
16339d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
16349d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
16359d099b4fSAlexander V. Chernikov 		return (error);
16369d099b4fSAlexander V. Chernikov 
16379d099b4fSAlexander V. Chernikov 	sz = req.size;
16389d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
16399d099b4fSAlexander V. Chernikov 		return (ENOMEM);
16409d099b4fSAlexander V. Chernikov 
16419d099b4fSAlexander V. Chernikov 	olh->size = sz;
16429d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
16439d099b4fSAlexander V. Chernikov 		free(olh);
16449d099b4fSAlexander V. Chernikov 		return (error);
16459d099b4fSAlexander V. Chernikov 	}
16469d099b4fSAlexander V. Chernikov 
16479d099b4fSAlexander V. Chernikov 	*polh = olh;
16489d099b4fSAlexander V. Chernikov 	return (0);
16499d099b4fSAlexander V. Chernikov }
16509d099b4fSAlexander V. Chernikov 
16519d099b4fSAlexander V. Chernikov void
16529d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
16539d099b4fSAlexander V. Chernikov {
16549d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
16559d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
16569d099b4fSAlexander V. Chernikov 	int error, i;
16579d099b4fSAlexander V. Chernikov 	const char *atype;
16589d099b4fSAlexander V. Chernikov 
16599d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
16609d099b4fSAlexander V. Chernikov 	if (error != 0)
16619d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
16629d099b4fSAlexander V. Chernikov 
16639d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
16649d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
16659d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
16669d099b4fSAlexander V. Chernikov 			atype = "unknown";
16678ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
16688ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
16699d099b4fSAlexander V. Chernikov 
16709d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
16719d099b4fSAlexander V. Chernikov 	}
16729d099b4fSAlexander V. Chernikov 
16739d099b4fSAlexander V. Chernikov 	free(olh);
16749d099b4fSAlexander V. Chernikov }
16759d099b4fSAlexander V. Chernikov 
16766c2997ffSAlexander V. Chernikov int
16776c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
16786c2997ffSAlexander V. Chernikov {
16796c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
16806c2997ffSAlexander V. Chernikov 
16816c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
16826c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
16836c2997ffSAlexander V. Chernikov 
16846c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
16856c2997ffSAlexander V. Chernikov 		return (-1);
16866c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
16876c2997ffSAlexander V. Chernikov 		return (1);
16886c2997ffSAlexander V. Chernikov 
16896c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
16906c2997ffSAlexander V. Chernikov 		return (-1);
16916c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
16926c2997ffSAlexander V. Chernikov 		return (1);
16936c2997ffSAlexander V. Chernikov 
16946c2997ffSAlexander V. Chernikov 	return (0);
16956c2997ffSAlexander V. Chernikov }
1696563b5ab1SAlexander V. Chernikov 
1697563b5ab1SAlexander V. Chernikov int
16986c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1699563b5ab1SAlexander V. Chernikov {
1700563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1701563b5ab1SAlexander V. Chernikov 	uint16_t key;
1702563b5ab1SAlexander V. Chernikov 
1703563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1704563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1705563b5ab1SAlexander V. Chernikov 
1706563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1707563b5ab1SAlexander V. Chernikov 		return (-1);
1708563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1709563b5ab1SAlexander V. Chernikov 		return (1);
1710563b5ab1SAlexander V. Chernikov 
1711563b5ab1SAlexander V. Chernikov 	return (0);
1712563b5ab1SAlexander V. Chernikov }
1713563b5ab1SAlexander V. Chernikov 
1714563b5ab1SAlexander V. Chernikov /*
1715563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1716563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1717563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1718563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1719563b5ab1SAlexander V. Chernikov  *
1720563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1721563b5ab1SAlexander V. Chernikov  */
1722563b5ab1SAlexander V. Chernikov char *
1723563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1724563b5ab1SAlexander V. Chernikov {
1725563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1726563b5ab1SAlexander V. Chernikov 
1727563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
17286c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1729563b5ab1SAlexander V. Chernikov 
1730563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1731563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1732563b5ab1SAlexander V. Chernikov 
1733563b5ab1SAlexander V. Chernikov 	return (NULL);
1734563b5ab1SAlexander V. Chernikov }
1735563b5ab1SAlexander V. Chernikov 
17366c2997ffSAlexander V. Chernikov void
17376c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
17386c2997ffSAlexander V. Chernikov {
17396c2997ffSAlexander V. Chernikov 
17406c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
17416c2997ffSAlexander V. Chernikov }
17426c2997ffSAlexander V. Chernikov 
17436c2997ffSAlexander V. Chernikov int
17446c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
17456c2997ffSAlexander V. Chernikov {
17466c2997ffSAlexander V. Chernikov 	int c, i, l;
17476c2997ffSAlexander V. Chernikov 
17486c2997ffSAlexander V. Chernikov 	/*
17496c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
17506c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1751ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
17526c2997ffSAlexander V. Chernikov 	 */
17536c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
17546c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
17556c2997ffSAlexander V. Chernikov 		return (EINVAL);
17566c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
17576c2997ffSAlexander V. Chernikov 		c = tablename[i];
17586c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
17596c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
17606c2997ffSAlexander V. Chernikov 			continue;
17616c2997ffSAlexander V. Chernikov 		return (EINVAL);
17626c2997ffSAlexander V. Chernikov 	}
17636c2997ffSAlexander V. Chernikov 
1764ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1765ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1766ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1767ac35ff17SAlexander V. Chernikov 
17686c2997ffSAlexander V. Chernikov 	return (0);
17696c2997ffSAlexander V. Chernikov }
17706c2997ffSAlexander V. Chernikov 
1771