xref: /freebsd/sbin/ipfw/tables.c (revision 914bffb6ab13f86826761d3b39d45d9996556e35)
1f1220db8SAlexander V. Chernikov /*
2f1220db8SAlexander V. Chernikov  * Copyright (c) 2002-2003 Luigi Rizzo
3f1220db8SAlexander V. Chernikov  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4f1220db8SAlexander V. Chernikov  * Copyright (c) 1994 Ugen J.S.Antsilevich
5f1220db8SAlexander V. Chernikov  *
6f1220db8SAlexander V. Chernikov  * Idea and grammar partially left from:
7f1220db8SAlexander V. Chernikov  * Copyright (c) 1993 Daniel Boulet
8f1220db8SAlexander V. Chernikov  *
9f1220db8SAlexander V. Chernikov  * Redistribution and use in source forms, with and without modification,
10f1220db8SAlexander V. Chernikov  * are permitted provided that this entire comment appears intact.
11f1220db8SAlexander V. Chernikov  *
12f1220db8SAlexander V. Chernikov  * Redistribution in binary form may occur without any restrictions.
13f1220db8SAlexander V. Chernikov  * Obviously, it would be nice if you gave credit where credit is due
14f1220db8SAlexander V. Chernikov  * but requiring it would be too onerous.
15f1220db8SAlexander V. Chernikov  *
16f1220db8SAlexander V. Chernikov  * This software is provided ``AS IS'' without any warranties of any kind.
17f1220db8SAlexander V. Chernikov  *
18f1220db8SAlexander V. Chernikov  * in-kernel tables support
19f1220db8SAlexander V. Chernikov  *
20f1220db8SAlexander V. Chernikov  * $FreeBSD: projects/ipfw/sbin/ipfw/ipfw2.c 267467 2014-06-14 10:58:39Z melifaro $
21f1220db8SAlexander V. Chernikov  */
22f1220db8SAlexander V. Chernikov 
23f1220db8SAlexander V. Chernikov 
24f1220db8SAlexander V. Chernikov #include <sys/types.h>
25f1220db8SAlexander V. Chernikov #include <sys/param.h>
26f1220db8SAlexander V. Chernikov #include <sys/socket.h>
27f1220db8SAlexander V. Chernikov #include <sys/sysctl.h>
28f1220db8SAlexander V. Chernikov 
29f1220db8SAlexander V. Chernikov #include <ctype.h>
30f1220db8SAlexander V. Chernikov #include <err.h>
31f1220db8SAlexander V. Chernikov #include <errno.h>
32f1220db8SAlexander V. Chernikov #include <netdb.h>
33f1220db8SAlexander V. Chernikov #include <stddef.h>	/* offsetof */
34f1220db8SAlexander V. Chernikov #include <stdio.h>
35f1220db8SAlexander V. Chernikov #include <stdlib.h>
36f1220db8SAlexander V. Chernikov #include <string.h>
37f1220db8SAlexander V. Chernikov #include <sysexits.h>
38f1220db8SAlexander V. Chernikov 
39f1220db8SAlexander V. Chernikov #define IPFW_INTERNAL	/* Access to protected structures in ip_fw.h. */
40f1220db8SAlexander V. Chernikov 
41f1220db8SAlexander V. Chernikov #include <net/if.h>
42f1220db8SAlexander V. Chernikov #include <net/if_dl.h>
43f1220db8SAlexander V. Chernikov #include <net/route.h> /* def. of struct route */
44f1220db8SAlexander V. Chernikov #include <netinet/in.h>
45f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h>
46f1220db8SAlexander V. Chernikov #include <arpa/inet.h>
47f1220db8SAlexander V. Chernikov #include <alias.h>
48f1220db8SAlexander V. Chernikov 
49f1220db8SAlexander V. Chernikov #include "ipfw2.h"
50f1220db8SAlexander V. Chernikov 
51f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header);
52ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
53ac35ff17SAlexander V. Chernikov     int add, int update);
54ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh);
55ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh);
56ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
57ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
5881d3153dSAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
59ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
60f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg);
61ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
62ac35ff17SAlexander V. Chernikov     uint16_t uidx);
63f1220db8SAlexander V. Chernikov 
64f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg);
65f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg);
66f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
67f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
6881d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
69f1220db8SAlexander V. Chernikov 
70ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
7181d3153dSAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
72ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
73ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
74ac35ff17SAlexander V. Chernikov 
75f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
76f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
77f1220db8SAlexander V. Chernikov 
78f1220db8SAlexander V. Chernikov #ifndef s6_addr32
79f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
80f1220db8SAlexander V. Chernikov #endif
81f1220db8SAlexander V. Chernikov 
82ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
83ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
84ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
85b23d5de9SAlexander V. Chernikov       { "number",	IPFW_TABLE_NUMBER },
86*914bffb6SAlexander V. Chernikov       { "flow",		IPFW_TABLE_FLOW },
87ac35ff17SAlexander V. Chernikov       { NULL, 0 }
88ac35ff17SAlexander V. Chernikov };
89ac35ff17SAlexander V. Chernikov 
90ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
91ac35ff17SAlexander V. Chernikov       { "dscp",		IPFW_VTYPE_DSCP },
92ac35ff17SAlexander V. Chernikov       { "ip",		IPFW_VTYPE_IP },
93ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
94ac35ff17SAlexander V. Chernikov       { NULL, 0 }
95ac35ff17SAlexander V. Chernikov };
96ac35ff17SAlexander V. Chernikov 
97ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
98ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
99ac35ff17SAlexander V. Chernikov       { "create",	TOK_CREATE },
100ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
101ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
102ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
103ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
104ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
10581d3153dSAlexander V. Chernikov       { "lookup",	TOK_LOOKUP },
106ac35ff17SAlexander V. Chernikov       { NULL, 0 }
107ac35ff17SAlexander V. Chernikov };
108ac35ff17SAlexander V. Chernikov 
109f1220db8SAlexander V. Chernikov static int
110f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
111f1220db8SAlexander V. Chernikov {
112f1220db8SAlexander V. Chernikov 	struct hostent *he;
113f1220db8SAlexander V. Chernikov 
114f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
115f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
116f1220db8SAlexander V. Chernikov 			return(-1);
117f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
118f1220db8SAlexander V. Chernikov 	}
119f1220db8SAlexander V. Chernikov 	return(0);
120f1220db8SAlexander V. Chernikov }
121f1220db8SAlexander V. Chernikov 
122f1220db8SAlexander V. Chernikov /*
123f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
124ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
125ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
126ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
127ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
128ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
129ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
130ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
131f1220db8SAlexander V. Chernikov  */
132f1220db8SAlexander V. Chernikov void
133f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
134f1220db8SAlexander V. Chernikov {
135ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
136ac35ff17SAlexander V. Chernikov 	int error, tcmd;
137ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
138ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
139f1220db8SAlexander V. Chernikov 	char *tablename;
140ac35ff17SAlexander V. Chernikov 	uint32_t set;
141f1220db8SAlexander V. Chernikov 
142ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
143ac35ff17SAlexander V. Chernikov 	is_all = 0;
144ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
145ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
146ac35ff17SAlexander V. Chernikov 	else
147ac35ff17SAlexander V. Chernikov 		set = 0;
148f1220db8SAlexander V. Chernikov 
149f1220db8SAlexander V. Chernikov 	ac--; av++;
1509d099b4fSAlexander V. Chernikov 	NEED1("table needs name");
151f1220db8SAlexander V. Chernikov 	tablename = *av;
152f1220db8SAlexander V. Chernikov 
153ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
154ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
155ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
156ac35ff17SAlexander V. Chernikov 	} else {
157ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
158ac35ff17SAlexander V. Chernikov 			is_all = 1;
159ac35ff17SAlexander V. Chernikov 		else
160ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
161ac35ff17SAlexander V. Chernikov 	}
162ac35ff17SAlexander V. Chernikov 	ac--; av++;
1639d099b4fSAlexander V. Chernikov 	NEED1("table needs command");
164ac35ff17SAlexander V. Chernikov 
165ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
166ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
167ac35ff17SAlexander V. Chernikov 
168ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
169ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
170ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
171ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
172ac35ff17SAlexander V. Chernikov 		break;
173ac35ff17SAlexander V. Chernikov 	default:
174ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
175ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
176ac35ff17SAlexander V. Chernikov 	}
177ac35ff17SAlexander V. Chernikov 
178ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
179ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
180ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
181f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
182f1220db8SAlexander V. Chernikov 		ac--; av++;
183ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
184ac35ff17SAlexander V. Chernikov 		break;
185ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
186f1220db8SAlexander V. Chernikov 		ac--; av++;
187ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
188ac35ff17SAlexander V. Chernikov 		break;
189ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
190ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
191ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
192ac35ff17SAlexander V. Chernikov 		break;
193ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
194f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
195ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
196f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
197f1220db8SAlexander V. Chernikov 				    tablename);
198f1220db8SAlexander V. Chernikov 		} else {
199ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
200f1220db8SAlexander V. Chernikov 			if (error != 0)
201f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
202f1220db8SAlexander V. Chernikov 		}
203ac35ff17SAlexander V. Chernikov 		break;
204ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
205f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
206ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
207f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
208f1220db8SAlexander V. Chernikov 			table_show_info(&i, NULL);
209f1220db8SAlexander V. Chernikov 		} else {
210f1220db8SAlexander V. Chernikov 			error = tables_foreach(table_show_info, NULL, 1);
211f1220db8SAlexander V. Chernikov 			if (error != 0)
212f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
213f1220db8SAlexander V. Chernikov 		}
214ac35ff17SAlexander V. Chernikov 		break;
215ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
216ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
217ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
218ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
219ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
220ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
221f1220db8SAlexander V. Chernikov 		} else {
222ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
223ac35ff17SAlexander V. Chernikov 			if (error != 0)
224ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
225f1220db8SAlexander V. Chernikov 		}
226ac35ff17SAlexander V. Chernikov 		break;
22781d3153dSAlexander V. Chernikov 	case TOK_LOOKUP:
22881d3153dSAlexander V. Chernikov 		ac--; av++;
22981d3153dSAlexander V. Chernikov 		table_lookup(&oh, ac, av);
23081d3153dSAlexander V. Chernikov 		break;
231f1220db8SAlexander V. Chernikov 	}
232f1220db8SAlexander V. Chernikov }
233f1220db8SAlexander V. Chernikov 
234f1220db8SAlexander V. Chernikov static void
235ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
236f1220db8SAlexander V. Chernikov {
237f1220db8SAlexander V. Chernikov 
238563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
239f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
240f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
241ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
242f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
243f1220db8SAlexander V. Chernikov }
244f1220db8SAlexander V. Chernikov 
245f1220db8SAlexander V. Chernikov static void
246f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
247f1220db8SAlexander V. Chernikov {
248f1220db8SAlexander V. Chernikov 
249f1220db8SAlexander V. Chernikov 	oh->idx = 1;
25081d3153dSAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
251ac35ff17SAlexander V. Chernikov }
252ac35ff17SAlexander V. Chernikov 
253ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
254ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE},
255ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
256ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
257ac35ff17SAlexander V. Chernikov       { NULL, 0 }
258ac35ff17SAlexander V. Chernikov };
259ac35ff17SAlexander V. Chernikov 
260*914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = {
261*914bffb6SAlexander V. Chernikov       { "src-ip",	IPFW_TFFLAG_SRCIP },
262*914bffb6SAlexander V. Chernikov       { "proto",	IPFW_TFFLAG_PROTO },
263*914bffb6SAlexander V. Chernikov       { "src-port",	IPFW_TFFLAG_SRCPORT },
264*914bffb6SAlexander V. Chernikov       { "dst-ip",	IPFW_TFFLAG_DSTIP },
265*914bffb6SAlexander V. Chernikov       { "dst-port",	IPFW_TFFLAG_DSTPORT },
266*914bffb6SAlexander V. Chernikov       { NULL, 0 }
267*914bffb6SAlexander V. Chernikov };
268*914bffb6SAlexander V. Chernikov 
269*914bffb6SAlexander V. Chernikov int
270*914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
271*914bffb6SAlexander V. Chernikov {
272*914bffb6SAlexander V. Chernikov 	uint8_t fset, fclear;
273*914bffb6SAlexander V. Chernikov 
274*914bffb6SAlexander V. Chernikov 	/* Parse type options */
275*914bffb6SAlexander V. Chernikov 	switch(ttype) {
276*914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
277*914bffb6SAlexander V. Chernikov 		fset = fclear = 0;
278*914bffb6SAlexander V. Chernikov 		fill_flags(flowtypecmds, p, &fset,
279*914bffb6SAlexander V. Chernikov 		    &fclear);
280*914bffb6SAlexander V. Chernikov 		*tflags = fset;
281*914bffb6SAlexander V. Chernikov 		break;
282*914bffb6SAlexander V. Chernikov 	default:
283*914bffb6SAlexander V. Chernikov 		return (EX_USAGE);
284*914bffb6SAlexander V. Chernikov 	}
285*914bffb6SAlexander V. Chernikov 
286*914bffb6SAlexander V. Chernikov 	return (0);
287*914bffb6SAlexander V. Chernikov }
288*914bffb6SAlexander V. Chernikov 
289*914bffb6SAlexander V. Chernikov void
290*914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
291*914bffb6SAlexander V. Chernikov {
292*914bffb6SAlexander V. Chernikov 	const char *tname;
293*914bffb6SAlexander V. Chernikov 	int l;
294*914bffb6SAlexander V. Chernikov 
295*914bffb6SAlexander V. Chernikov 	if ((tname = match_value(tabletypes, type)) == NULL)
296*914bffb6SAlexander V. Chernikov 		tname = "unknown";
297*914bffb6SAlexander V. Chernikov 
298*914bffb6SAlexander V. Chernikov 	l = snprintf(tbuf, size, "%s", tname);
299*914bffb6SAlexander V. Chernikov 	tbuf += l;
300*914bffb6SAlexander V. Chernikov 	size -= l;
301*914bffb6SAlexander V. Chernikov 
302*914bffb6SAlexander V. Chernikov 	switch(type) {
303*914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
304*914bffb6SAlexander V. Chernikov 		if (tflags != 0) {
305*914bffb6SAlexander V. Chernikov 			*tbuf++ = ':';
306*914bffb6SAlexander V. Chernikov 			l--;
307*914bffb6SAlexander V. Chernikov 			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
308*914bffb6SAlexander V. Chernikov 		}
309*914bffb6SAlexander V. Chernikov 		break;
310*914bffb6SAlexander V. Chernikov 	}
311*914bffb6SAlexander V. Chernikov }
312*914bffb6SAlexander V. Chernikov 
313ac35ff17SAlexander V. Chernikov /*
314ac35ff17SAlexander V. Chernikov  * Creates new table
315ac35ff17SAlexander V. Chernikov  *
316ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
317ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
318ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
319ac35ff17SAlexander V. Chernikov  *
320ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
321ac35ff17SAlexander V. Chernikov  */
322ac35ff17SAlexander V. Chernikov static void
323ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
324ac35ff17SAlexander V. Chernikov {
325ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
326ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
327ac35ff17SAlexander V. Chernikov 	size_t sz;
328*914bffb6SAlexander V. Chernikov 	char *p;
329ac35ff17SAlexander V. Chernikov 	char tbuf[128];
330ac35ff17SAlexander V. Chernikov 
331ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
332ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
333ac35ff17SAlexander V. Chernikov 
334ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
335ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
336ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
337ac35ff17SAlexander V. Chernikov 
338ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
339ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
340ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
341ac35ff17SAlexander V. Chernikov 		ac--; av++;
342ac35ff17SAlexander V. Chernikov 
343ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
344ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
345ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
346*914bffb6SAlexander V. Chernikov 			/* Type may have suboptions after ':' */
347*914bffb6SAlexander V. Chernikov 			if ((p = strchr(*av, ':')) != NULL)
348*914bffb6SAlexander V. Chernikov 				*p++ = '\0';
349ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
350*914bffb6SAlexander V. Chernikov 			if (val == -1) {
351*914bffb6SAlexander V. Chernikov 				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
352*914bffb6SAlexander V. Chernikov 				    ", ");
353*914bffb6SAlexander V. Chernikov 				errx(EX_USAGE,
354*914bffb6SAlexander V. Chernikov 				    "Unknown tabletype: %s. Supported: %s",
355ac35ff17SAlexander V. Chernikov 				    *av, tbuf);
356*914bffb6SAlexander V. Chernikov 			}
357*914bffb6SAlexander V. Chernikov 			xi.type = val;
358*914bffb6SAlexander V. Chernikov 			if (p != NULL) {
359*914bffb6SAlexander V. Chernikov 				error = table_parse_type(val, p, &xi.tflags);
360*914bffb6SAlexander V. Chernikov 				if (error != 0)
361*914bffb6SAlexander V. Chernikov 					errx(EX_USAGE,
362*914bffb6SAlexander V. Chernikov 					    "Unsupported suboptions: %s", p);
363*914bffb6SAlexander V. Chernikov 			}
364*914bffb6SAlexander V. Chernikov 			ac--; av++;
365ac35ff17SAlexander V. Chernikov 			break;
366ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
367ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
368ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
369ac35ff17SAlexander V. Chernikov 			if (val != -1) {
370ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
371ac35ff17SAlexander V. Chernikov 				ac--; av++;
372ac35ff17SAlexander V. Chernikov 				break;
373ac35ff17SAlexander V. Chernikov 			}
374ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
375ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
376ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
377ac35ff17SAlexander V. Chernikov 			break;
378ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
379ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
380ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
381ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
382ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
383ac35ff17SAlexander V. Chernikov 			ac--; av++;
384ac35ff17SAlexander V. Chernikov 			break;
385ac35ff17SAlexander V. Chernikov 		}
386ac35ff17SAlexander V. Chernikov 	}
387ac35ff17SAlexander V. Chernikov 
388ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
389ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
390f1220db8SAlexander V. Chernikov }
391f1220db8SAlexander V. Chernikov 
392f1220db8SAlexander V. Chernikov /*
393ac35ff17SAlexander V. Chernikov  * Creates new table
394ac35ff17SAlexander V. Chernikov  *
395ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
396ac35ff17SAlexander V. Chernikov  *
397f1220db8SAlexander V. Chernikov  * Returns 0 on success.
398f1220db8SAlexander V. Chernikov  */
399f1220db8SAlexander V. Chernikov static int
400ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
401f1220db8SAlexander V. Chernikov {
402ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
403ac35ff17SAlexander V. Chernikov 	int error;
404f1220db8SAlexander V. Chernikov 
405ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
406ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
407ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
408ac35ff17SAlexander V. Chernikov 
409ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
410ac35ff17SAlexander V. Chernikov 
411ac35ff17SAlexander V. Chernikov 	return (error);
412ac35ff17SAlexander V. Chernikov }
413ac35ff17SAlexander V. Chernikov 
414ac35ff17SAlexander V. Chernikov /*
415ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
416ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
417ac35ff17SAlexander V. Chernikov  */
418ac35ff17SAlexander V. Chernikov static int
419ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
420ac35ff17SAlexander V. Chernikov {
421ac35ff17SAlexander V. Chernikov 
422ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
423f1220db8SAlexander V. Chernikov 		return (-1);
424f1220db8SAlexander V. Chernikov 
425f1220db8SAlexander V. Chernikov 	return (0);
426f1220db8SAlexander V. Chernikov }
427f1220db8SAlexander V. Chernikov 
428f1220db8SAlexander V. Chernikov /*
429ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
430f1220db8SAlexander V. Chernikov  * Returns 0 on success.
431f1220db8SAlexander V. Chernikov  */
432f1220db8SAlexander V. Chernikov static int
433ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
434f1220db8SAlexander V. Chernikov {
435f1220db8SAlexander V. Chernikov 
436ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
437f1220db8SAlexander V. Chernikov 		return (-1);
438f1220db8SAlexander V. Chernikov 
439f1220db8SAlexander V. Chernikov 	return (0);
440f1220db8SAlexander V. Chernikov }
441f1220db8SAlexander V. Chernikov 
442f1220db8SAlexander V. Chernikov /*
443ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
444f1220db8SAlexander V. Chernikov  * it inside @i.
445f1220db8SAlexander V. Chernikov  * Returns 0 on success.
446f1220db8SAlexander V. Chernikov  */
447f1220db8SAlexander V. Chernikov static int
448ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
449f1220db8SAlexander V. Chernikov {
450f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
451ac35ff17SAlexander V. Chernikov 	int error;
452f1220db8SAlexander V. Chernikov 	size_t sz;
453f1220db8SAlexander V. Chernikov 
454f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
455f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
456ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
457f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
458f1220db8SAlexander V. Chernikov 
459ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
460ac35ff17SAlexander V. Chernikov 		return (error);
461f1220db8SAlexander V. Chernikov 
462f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
463ac35ff17SAlexander V. Chernikov 		return (EINVAL);
464f1220db8SAlexander V. Chernikov 
465f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
466f1220db8SAlexander V. Chernikov 
467f1220db8SAlexander V. Chernikov 	return (0);
468f1220db8SAlexander V. Chernikov }
469f1220db8SAlexander V. Chernikov 
470f1220db8SAlexander V. Chernikov /*
471f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
472f1220db8SAlexander V. Chernikov  */
473f1220db8SAlexander V. Chernikov static int
474f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
475f1220db8SAlexander V. Chernikov {
476*914bffb6SAlexander V. Chernikov 	const char *vtype;
477*914bffb6SAlexander V. Chernikov 	char ttype[64];
478f1220db8SAlexander V. Chernikov 
479*914bffb6SAlexander V. Chernikov 	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
480ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
481ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
482ac35ff17SAlexander V. Chernikov 
483*914bffb6SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
484*914bffb6SAlexander V. Chernikov 	printf(" kindex: %d, type: %s\n", i->kidx, ttype);
4859d099b4fSAlexander V. Chernikov 	printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
4869d099b4fSAlexander V. Chernikov 	printf(" algorithm: %s\n", i->algoname);
487f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
488f1220db8SAlexander V. Chernikov 
489f1220db8SAlexander V. Chernikov 	return (0);
490f1220db8SAlexander V. Chernikov }
491f1220db8SAlexander V. Chernikov 
492f1220db8SAlexander V. Chernikov 
493f1220db8SAlexander V. Chernikov /*
494f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
495f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
496f1220db8SAlexander V. Chernikov  */
497f1220db8SAlexander V. Chernikov 
498f1220db8SAlexander V. Chernikov static int
499f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
500f1220db8SAlexander V. Chernikov {
501f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
50281d3153dSAlexander V. Chernikov 	int error;
503f1220db8SAlexander V. Chernikov 
504ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
505f1220db8SAlexander V. Chernikov 		return (ENOMEM);
506f1220db8SAlexander V. Chernikov 
50781d3153dSAlexander V. Chernikov 	if ((error = table_get_list(i, oh)) != 0) {
50881d3153dSAlexander V. Chernikov 		err(EX_OSERR, "Error requesting table %s list", i->tablename);
50981d3153dSAlexander V. Chernikov 		return (error);
51081d3153dSAlexander V. Chernikov 	}
51181d3153dSAlexander V. Chernikov 
512f1220db8SAlexander V. Chernikov 	table_show_list(oh, 1);
513f1220db8SAlexander V. Chernikov 
514f1220db8SAlexander V. Chernikov 	free(oh);
515f1220db8SAlexander V. Chernikov 	return (0);
516f1220db8SAlexander V. Chernikov }
517f1220db8SAlexander V. Chernikov 
518f1220db8SAlexander V. Chernikov static int
519f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
520f1220db8SAlexander V. Chernikov {
521ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
522f1220db8SAlexander V. Chernikov 
523ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
524ac35ff17SAlexander V. Chernikov 
525ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
526ac35ff17SAlexander V. Chernikov 
527ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
528f1220db8SAlexander V. Chernikov }
529f1220db8SAlexander V. Chernikov 
530ac35ff17SAlexander V. Chernikov static int
531ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
532ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
533ac35ff17SAlexander V. Chernikov {
534db785d31SAlexander V. Chernikov 	ipfw_obj_ctlv *ctlv;
535db785d31SAlexander V. Chernikov 	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
536ac35ff17SAlexander V. Chernikov 	int error;
537ac35ff17SAlexander V. Chernikov 
538ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
539ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
540ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
541ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
542ac35ff17SAlexander V. Chernikov 
543db785d31SAlexander V. Chernikov 	ctlv = (ipfw_obj_ctlv *)(oh + 1);
544db785d31SAlexander V. Chernikov 	ctlv->count = 1;
545db785d31SAlexander V. Chernikov 	ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
546db785d31SAlexander V. Chernikov 
547db785d31SAlexander V. Chernikov 	memcpy(ctlv + 1, tent, sizeof(*tent));
548db785d31SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(ctlv + 1);
549ac35ff17SAlexander V. Chernikov 	if (update != 0)
55081d3153dSAlexander V. Chernikov 		tent->head.flags |= IPFW_TF_UPDATE;
551ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
552ac35ff17SAlexander V. Chernikov 
553ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
554ac35ff17SAlexander V. Chernikov 
555ac35ff17SAlexander V. Chernikov 	return (error);
556ac35ff17SAlexander V. Chernikov }
557ac35ff17SAlexander V. Chernikov 
558ac35ff17SAlexander V. Chernikov static void
559ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
560ac35ff17SAlexander V. Chernikov {
561ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
56281d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
563ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
564ac35ff17SAlexander V. Chernikov 	int cmd;
565ac35ff17SAlexander V. Chernikov 	char *texterr;
566ac35ff17SAlexander V. Chernikov 
567ac35ff17SAlexander V. Chernikov 	if (ac == 0)
568ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
569ac35ff17SAlexander V. Chernikov 
570ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
571ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
572ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
573ac35ff17SAlexander V. Chernikov 
57481d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
575db785d31SAlexander V. Chernikov 
576db785d31SAlexander V. Chernikov 	/*
577db785d31SAlexander V. Chernikov 	 * compability layer: auto-create table if not exists
578db785d31SAlexander V. Chernikov 	 */
579db785d31SAlexander V. Chernikov 	if (xi.tablename[0] == '\0') {
580db785d31SAlexander V. Chernikov 		xi.type = type;
581db785d31SAlexander V. Chernikov 		xi.vtype = vtype;
582db785d31SAlexander V. Chernikov 		strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
583db785d31SAlexander V. Chernikov 		fprintf(stderr, "DEPRECATED: inserting data info non-existent "
584db785d31SAlexander V. Chernikov 		    "table %s. (auto-created)\n", xi.tablename);
585db785d31SAlexander V. Chernikov 		table_do_create(oh, &xi);
586db785d31SAlexander V. Chernikov 	}
587db785d31SAlexander V. Chernikov 
588ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
589ac35ff17SAlexander V. Chernikov 	ac--; av++;
590ac35ff17SAlexander V. Chernikov 
591ac35ff17SAlexander V. Chernikov 	if (add != 0) {
592ac35ff17SAlexander V. Chernikov 		if (ac > 0)
593ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
594ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
595ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XADD)";
596ac35ff17SAlexander V. Chernikov 	} else {
597ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
598ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XDEL)";
599ac35ff17SAlexander V. Chernikov 	}
600ac35ff17SAlexander V. Chernikov 
601ac35ff17SAlexander V. Chernikov 	if (table_do_modify_record(cmd, oh, &tent, update) != 0)
602ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "%s", texterr);
603ac35ff17SAlexander V. Chernikov }
604ac35ff17SAlexander V. Chernikov 
60581d3153dSAlexander V. Chernikov static int
60681d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
60781d3153dSAlexander V. Chernikov     ipfw_obj_tentry *xtent)
60881d3153dSAlexander V. Chernikov {
60981d3153dSAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
61081d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
61181d3153dSAlexander V. Chernikov 	uint8_t type, vtype;
61281d3153dSAlexander V. Chernikov 	int error;
61381d3153dSAlexander V. Chernikov 	size_t sz;
61481d3153dSAlexander V. Chernikov 
61581d3153dSAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
61681d3153dSAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
61781d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
61881d3153dSAlexander V. Chernikov 
61981d3153dSAlexander V. Chernikov 	memset(tent, 0, sizeof(*tent));
62081d3153dSAlexander V. Chernikov 	tent->head.length = sizeof(*tent);
62181d3153dSAlexander V. Chernikov 	tent->idx = 1;
62281d3153dSAlexander V. Chernikov 
62381d3153dSAlexander V. Chernikov 	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
62481d3153dSAlexander V. Chernikov 	oh->ntlv.type = type;
62581d3153dSAlexander V. Chernikov 
62681d3153dSAlexander V. Chernikov 	sz = sizeof(xbuf);
62781d3153dSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
62881d3153dSAlexander V. Chernikov 		return (error);
62981d3153dSAlexander V. Chernikov 
63081d3153dSAlexander V. Chernikov 	if (sz < sizeof(xbuf))
63181d3153dSAlexander V. Chernikov 		return (EINVAL);
63281d3153dSAlexander V. Chernikov 
63381d3153dSAlexander V. Chernikov 	*xtent = *tent;
63481d3153dSAlexander V. Chernikov 
63581d3153dSAlexander V. Chernikov 	return (0);
63681d3153dSAlexander V. Chernikov }
63781d3153dSAlexander V. Chernikov 
63881d3153dSAlexander V. Chernikov static void
63981d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[])
64081d3153dSAlexander V. Chernikov {
64181d3153dSAlexander V. Chernikov 	ipfw_obj_tentry xtent;
64281d3153dSAlexander V. Chernikov 	ipfw_xtable_info xi;
643*914bffb6SAlexander V. Chernikov 	char key[64];
64481d3153dSAlexander V. Chernikov 	int error;
64581d3153dSAlexander V. Chernikov 
64681d3153dSAlexander V. Chernikov 	if (ac == 0)
64781d3153dSAlexander V. Chernikov 		errx(EX_USAGE, "address required");
64881d3153dSAlexander V. Chernikov 
649*914bffb6SAlexander V. Chernikov 	strlcpy(key, *av, sizeof(key));
650*914bffb6SAlexander V. Chernikov 
651*914bffb6SAlexander V. Chernikov 	error = table_do_lookup(oh, key, &xi, &xtent);
65281d3153dSAlexander V. Chernikov 
65381d3153dSAlexander V. Chernikov 	switch (error) {
65481d3153dSAlexander V. Chernikov 	case 0:
65581d3153dSAlexander V. Chernikov 		break;
65681d3153dSAlexander V. Chernikov 	case ESRCH:
65781d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
65881d3153dSAlexander V. Chernikov 	case ENOENT:
65981d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
66081d3153dSAlexander V. Chernikov 	case ENOTSUP:
66181d3153dSAlexander V. Chernikov 		errx(EX_UNAVAILABLE, "Table %s algo does not support "
66281d3153dSAlexander V. Chernikov 		    "\"lookup\" method", oh->ntlv.name);
66381d3153dSAlexander V. Chernikov 	default:
66481d3153dSAlexander V. Chernikov 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
66581d3153dSAlexander V. Chernikov 	}
66681d3153dSAlexander V. Chernikov 
66781d3153dSAlexander V. Chernikov 	table_show_entry(&xi, &xtent);
66881d3153dSAlexander V. Chernikov }
669ac35ff17SAlexander V. Chernikov 
670ac35ff17SAlexander V. Chernikov static void
671*914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
672*914bffb6SAlexander V. Chernikov     uint8_t tflags)
673ac35ff17SAlexander V. Chernikov {
674*914bffb6SAlexander V. Chernikov 	char *p, *pp;
675ac35ff17SAlexander V. Chernikov 	int mask, af;
676*914bffb6SAlexander V. Chernikov 	struct in6_addr *paddr, tmp;
677*914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
678ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
679*914bffb6SAlexander V. Chernikov 	uint16_t port;
680*914bffb6SAlexander V. Chernikov 	struct protoent *pent;
681*914bffb6SAlexander V. Chernikov 	struct servent *sent;
682ac35ff17SAlexander V. Chernikov 	int masklen;
683ac35ff17SAlexander V. Chernikov 
684ac35ff17SAlexander V. Chernikov 	masklen = 0;
685ac35ff17SAlexander V. Chernikov 	af = 0;
686ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
687ac35ff17SAlexander V. Chernikov 
688ac35ff17SAlexander V. Chernikov 	switch (type) {
689ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
690ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
691ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
692ac35ff17SAlexander V. Chernikov 			*p = '\0';
693ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
694ac35ff17SAlexander V. Chernikov 		}
695ac35ff17SAlexander V. Chernikov 
696ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
697ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
698ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
699ac35ff17SAlexander V. Chernikov 				    p + 1);
700ac35ff17SAlexander V. Chernikov 
701ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
702ac35ff17SAlexander V. Chernikov 			af = AF_INET;
703ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
704ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
705ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
706ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
707ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
708ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
709ac35ff17SAlexander V. Chernikov 				    p + 1);
710ac35ff17SAlexander V. Chernikov 
711ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
712ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
713ac35ff17SAlexander V. Chernikov 		} else {
714ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
715ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
716ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
717ac35ff17SAlexander V. Chernikov 
718ac35ff17SAlexander V. Chernikov 			masklen = 32;
719ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
720ac35ff17SAlexander V. Chernikov 			af = AF_INET;
721ac35ff17SAlexander V. Chernikov 		}
722ac35ff17SAlexander V. Chernikov 		break;
723ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
724ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
725ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
726ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
727ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
728ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
729ac35ff17SAlexander V. Chernikov 		break;
730b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
731ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
732ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
733ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
734ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
735ac35ff17SAlexander V. Chernikov 
736ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
737ac35ff17SAlexander V. Chernikov 		*pkey = key;
738ac35ff17SAlexander V. Chernikov 		masklen = 32;
739ac35ff17SAlexander V. Chernikov 		break;
740*914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
741*914bffb6SAlexander V. Chernikov 		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
742*914bffb6SAlexander V. Chernikov 		tfe = &tentry->k.flow;
743*914bffb6SAlexander V. Chernikov 		af = 0;
744*914bffb6SAlexander V. Chernikov 
745*914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
746*914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
747*914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
748*914bffb6SAlexander V. Chernikov 				*p++ = '\0';
749*914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
750*914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
751*914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
752*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
753*914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
754*914bffb6SAlexander V. Chernikov 				af = AF_INET;
755*914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.sip, &tmp, 4);
756*914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
757*914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
758*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
759*914bffb6SAlexander V. Chernikov 					    "Inconsistent address family\n");
760*914bffb6SAlexander V. Chernikov 				af = AF_INET6;
761*914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.sip6, &tmp, 16);
762*914bffb6SAlexander V. Chernikov 			}
763*914bffb6SAlexander V. Chernikov 
764*914bffb6SAlexander V. Chernikov 			arg = p;
765*914bffb6SAlexander V. Chernikov 		}
766*914bffb6SAlexander V. Chernikov 
767*914bffb6SAlexander V. Chernikov 		/* Handle <proto-num|proto-name> */
768*914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
769*914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
770*914bffb6SAlexander V. Chernikov 				*p++ = '\0';
771*914bffb6SAlexander V. Chernikov 
772*914bffb6SAlexander V. Chernikov 			key = strtol(arg, &pp, 10);
773*914bffb6SAlexander V. Chernikov 			if (*pp != '\0') {
774*914bffb6SAlexander V. Chernikov 				if ((pent = getprotobyname(arg)) == NULL)
775*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown proto: %s",
776*914bffb6SAlexander V. Chernikov 					    arg);
777*914bffb6SAlexander V. Chernikov 				else
778*914bffb6SAlexander V. Chernikov 					key = pent->p_proto;
779*914bffb6SAlexander V. Chernikov 			}
780*914bffb6SAlexander V. Chernikov 
781*914bffb6SAlexander V. Chernikov 			if (key > 255)
782*914bffb6SAlexander V. Chernikov 				errx(EX_DATAERR, "Bad protocol number: %u",key);
783*914bffb6SAlexander V. Chernikov 
784*914bffb6SAlexander V. Chernikov 			tfe->proto = key;
785*914bffb6SAlexander V. Chernikov 
786*914bffb6SAlexander V. Chernikov 			arg = p;
787*914bffb6SAlexander V. Chernikov 		}
788*914bffb6SAlexander V. Chernikov 
789*914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
790*914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
791*914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
792*914bffb6SAlexander V. Chernikov 				*p++ = '\0';
793*914bffb6SAlexander V. Chernikov 
794*914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
795*914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
796*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
797*914bffb6SAlexander V. Chernikov 					    arg);
798*914bffb6SAlexander V. Chernikov 				else
799*914bffb6SAlexander V. Chernikov 					key = sent->s_port;
800*914bffb6SAlexander V. Chernikov 			}
801*914bffb6SAlexander V. Chernikov 
802*914bffb6SAlexander V. Chernikov 			tfe->sport = port;
803*914bffb6SAlexander V. Chernikov 
804*914bffb6SAlexander V. Chernikov 			arg = p;
805*914bffb6SAlexander V. Chernikov 		}
806*914bffb6SAlexander V. Chernikov 
807*914bffb6SAlexander V. Chernikov 		/* Handle <ipv4|ipv6>*/
808*914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
809*914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
810*914bffb6SAlexander V. Chernikov 				*p++ = '\0';
811*914bffb6SAlexander V. Chernikov 			/* Determine family using temporary storage */
812*914bffb6SAlexander V. Chernikov 			if (inet_pton(AF_INET, arg, &tmp) == 1) {
813*914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET)
814*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
815*914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
816*914bffb6SAlexander V. Chernikov 				af = AF_INET;
817*914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a4.dip, &tmp, 4);
818*914bffb6SAlexander V. Chernikov 			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
819*914bffb6SAlexander V. Chernikov 				if (af != 0 && af != AF_INET6)
820*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR,
821*914bffb6SAlexander V. Chernikov 					    "Inconsistent address family");
822*914bffb6SAlexander V. Chernikov 				af = AF_INET6;
823*914bffb6SAlexander V. Chernikov 				memcpy(&tfe->a.a6.dip6, &tmp, 16);
824*914bffb6SAlexander V. Chernikov 			}
825*914bffb6SAlexander V. Chernikov 
826*914bffb6SAlexander V. Chernikov 			arg = p;
827*914bffb6SAlexander V. Chernikov 		}
828*914bffb6SAlexander V. Chernikov 
829*914bffb6SAlexander V. Chernikov 		/* Handle <port-num|service-name> */
830*914bffb6SAlexander V. Chernikov 		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
831*914bffb6SAlexander V. Chernikov 			if ((p = strchr(arg, ',')) != NULL)
832*914bffb6SAlexander V. Chernikov 				*p++ = '\0';
833*914bffb6SAlexander V. Chernikov 
834*914bffb6SAlexander V. Chernikov 			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
835*914bffb6SAlexander V. Chernikov 				if ((sent = getservbyname(arg, NULL)) == NULL)
836*914bffb6SAlexander V. Chernikov 					errx(EX_DATAERR, "Unknown service: %s",
837*914bffb6SAlexander V. Chernikov 					    arg);
838*914bffb6SAlexander V. Chernikov 				else
839*914bffb6SAlexander V. Chernikov 					key = sent->s_port;
840*914bffb6SAlexander V. Chernikov 			}
841*914bffb6SAlexander V. Chernikov 
842*914bffb6SAlexander V. Chernikov 			tfe->dport = port;
843*914bffb6SAlexander V. Chernikov 
844*914bffb6SAlexander V. Chernikov 			arg = p;
845*914bffb6SAlexander V. Chernikov 		}
846*914bffb6SAlexander V. Chernikov 
847*914bffb6SAlexander V. Chernikov 		tfe->af = af;
848*914bffb6SAlexander V. Chernikov 
849*914bffb6SAlexander V. Chernikov 		break;
850*914bffb6SAlexander V. Chernikov 
851ac35ff17SAlexander V. Chernikov 	default:
852ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
853ac35ff17SAlexander V. Chernikov 	}
854ac35ff17SAlexander V. Chernikov 
855ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
856ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
857ac35ff17SAlexander V. Chernikov }
858ac35ff17SAlexander V. Chernikov 
859ac35ff17SAlexander V. Chernikov static void
860ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
86181d3153dSAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
862ac35ff17SAlexander V. Chernikov {
863*914bffb6SAlexander V. Chernikov 	uint8_t type, tflags, vtype;
864ac35ff17SAlexander V. Chernikov 	int error;
865db785d31SAlexander V. Chernikov 	char *del;
866ac35ff17SAlexander V. Chernikov 
867ac35ff17SAlexander V. Chernikov 	type = 0;
868*914bffb6SAlexander V. Chernikov 	tflags = 0;
869ac35ff17SAlexander V. Chernikov 	vtype = 0;
870ac35ff17SAlexander V. Chernikov 
87181d3153dSAlexander V. Chernikov 	error = table_get_info(oh, xi);
87281d3153dSAlexander V. Chernikov 
87381d3153dSAlexander V. Chernikov 	if (error == 0) {
87481d3153dSAlexander V. Chernikov 		/* Table found. */
87581d3153dSAlexander V. Chernikov 		type = xi->type;
876*914bffb6SAlexander V. Chernikov 		tflags = xi->tflags;
87781d3153dSAlexander V. Chernikov 		vtype = xi->vtype;
87881d3153dSAlexander V. Chernikov 	} else {
87981d3153dSAlexander V. Chernikov 		if (error != ESRCH)
88081d3153dSAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
88181d3153dSAlexander V. Chernikov 			    oh->ntlv.name);
882ac35ff17SAlexander V. Chernikov 		/*
88381d3153dSAlexander V. Chernikov 		 * Table does not exist.
88481d3153dSAlexander V. Chernikov 		 * Compability layer: try to interpret data as CIDR
88581d3153dSAlexander V. Chernikov 		 * before failing.
886ac35ff17SAlexander V. Chernikov 		 */
887db785d31SAlexander V. Chernikov 		if ((del = strchr(key, '/')) != NULL)
888db785d31SAlexander V. Chernikov 			*del = '\0';
889ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
890ac35ff17SAlexander V. Chernikov 		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
891ac35ff17SAlexander V. Chernikov 			/* OK Prepare and send */
892ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
893ac35ff17SAlexander V. Chernikov 			/*
89481d3153dSAlexander V. Chernikov 			 * XXX: Value type is forced to be u32.
89581d3153dSAlexander V. Chernikov 			 * This should be changed for MFC.
896ac35ff17SAlexander V. Chernikov 			 */
89781d3153dSAlexander V. Chernikov 			vtype = IPFW_VTYPE_U32;
89881d3153dSAlexander V. Chernikov 		} else {
89981d3153dSAlexander V. Chernikov 			/* Inknown key */
90081d3153dSAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
901db785d31SAlexander V. Chernikov 			    "key '%s' type", oh->ntlv.name, key);
90281d3153dSAlexander V. Chernikov 		}
903db785d31SAlexander V. Chernikov 		if (del != NULL)
904db785d31SAlexander V. Chernikov 			*del = '/';
905ac35ff17SAlexander V. Chernikov 	}
906ac35ff17SAlexander V. Chernikov 
907*914bffb6SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type, tflags);
908ac35ff17SAlexander V. Chernikov 
909ac35ff17SAlexander V. Chernikov 	*ptype = type;
910ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
911ac35ff17SAlexander V. Chernikov }
912ac35ff17SAlexander V. Chernikov 
913ac35ff17SAlexander V. Chernikov static void
914ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
915ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
916ac35ff17SAlexander V. Chernikov {
917ac35ff17SAlexander V. Chernikov 	int code;
918ac35ff17SAlexander V. Chernikov 	char *p;
919ac35ff17SAlexander V. Chernikov 
920ac35ff17SAlexander V. Chernikov 	switch (vtype) {
921ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
922ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
923ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
924ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
925ac35ff17SAlexander V. Chernikov 		break;
926ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
927ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
928ac35ff17SAlexander V. Chernikov 			break;
929ac35ff17SAlexander V. Chernikov 		/* Try hostname */
930ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
931ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
932ac35ff17SAlexander V. Chernikov 		break;
933ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
934ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
935ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
936ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
937ac35ff17SAlexander V. Chernikov 		} else {
938ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
939ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
940ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
941ac35ff17SAlexander V. Chernikov 		}
942ac35ff17SAlexander V. Chernikov 		tent->value = code;
943ac35ff17SAlexander V. Chernikov 		break;
944ac35ff17SAlexander V. Chernikov 	default:
945ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
946ac35ff17SAlexander V. Chernikov 	}
947ac35ff17SAlexander V. Chernikov }
948f1220db8SAlexander V. Chernikov 
949f1220db8SAlexander V. Chernikov /*
950f1220db8SAlexander V. Chernikov  * Compare table names.
951f1220db8SAlexander V. Chernikov  * Honor number comparison.
952f1220db8SAlexander V. Chernikov  */
953f1220db8SAlexander V. Chernikov static int
954f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
955f1220db8SAlexander V. Chernikov {
956f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
957f1220db8SAlexander V. Chernikov 
958f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
959f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
960f1220db8SAlexander V. Chernikov 
96168394ec8SAlexander V. Chernikov 	return (stringnum_cmp(ia->tablename, ib->tablename));
962f1220db8SAlexander V. Chernikov }
963f1220db8SAlexander V. Chernikov 
964f1220db8SAlexander V. Chernikov /*
965f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
966f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
967f1220db8SAlexander V. Chernikov  * Returns 0 on success.
968f1220db8SAlexander V. Chernikov  */
969f1220db8SAlexander V. Chernikov static int
970f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
971f1220db8SAlexander V. Chernikov {
972f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
973f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
974f1220db8SAlexander V. Chernikov 	size_t sz;
975f1220db8SAlexander V. Chernikov 	int i, error;
976f1220db8SAlexander V. Chernikov 
977f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
978f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
979f1220db8SAlexander V. Chernikov 
980d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
981f1220db8SAlexander V. Chernikov 		return (errno);
982f1220db8SAlexander V. Chernikov 
983f1220db8SAlexander V. Chernikov 	sz = req.size;
984f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
985f1220db8SAlexander V. Chernikov 		return (ENOMEM);
986f1220db8SAlexander V. Chernikov 
987f1220db8SAlexander V. Chernikov 	olh->size = sz;
988d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
989f1220db8SAlexander V. Chernikov 		free(olh);
990f1220db8SAlexander V. Chernikov 		return (errno);
991f1220db8SAlexander V. Chernikov 	}
992f1220db8SAlexander V. Chernikov 
993f1220db8SAlexander V. Chernikov 	if (sort != 0)
994f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
995f1220db8SAlexander V. Chernikov 
996f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
997f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
998f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
999f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
1000f1220db8SAlexander V. Chernikov 	}
1001f1220db8SAlexander V. Chernikov 
1002f1220db8SAlexander V. Chernikov 	free(olh);
1003f1220db8SAlexander V. Chernikov 
1004f1220db8SAlexander V. Chernikov 	return (0);
1005f1220db8SAlexander V. Chernikov }
1006f1220db8SAlexander V. Chernikov 
1007f1220db8SAlexander V. Chernikov /*
1008f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
1009d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
1010d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
1011f1220db8SAlexander V. Chernikov  *
1012f1220db8SAlexander V. Chernikov  * Returns 0 on success.
1013f1220db8SAlexander V. Chernikov  */
1014f1220db8SAlexander V. Chernikov static int
1015f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
1016f1220db8SAlexander V. Chernikov {
1017f1220db8SAlexander V. Chernikov 	size_t sz;
101881d3153dSAlexander V. Chernikov 	int error, c;
1019f1220db8SAlexander V. Chernikov 
102081d3153dSAlexander V. Chernikov 	sz = 0;
102181d3153dSAlexander V. Chernikov 	for (c = 0; c < 3; c++) {
1022f1220db8SAlexander V. Chernikov 		table_fill_objheader(oh, i);
102381d3153dSAlexander V. Chernikov 		if (sz < i->size)
1024f1220db8SAlexander V. Chernikov 			sz = i->size;
1025f1220db8SAlexander V. Chernikov 
1026d3a4f924SAlexander V. Chernikov 		oh->opheader.version = 1; /* Current version */
102781d3153dSAlexander V. Chernikov 		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
1028d3a4f924SAlexander V. Chernikov 
102981d3153dSAlexander V. Chernikov 		if (error != ENOMEM)
1030f1220db8SAlexander V. Chernikov 			return (errno);
103181d3153dSAlexander V. Chernikov 	}
1032f1220db8SAlexander V. Chernikov 
103381d3153dSAlexander V. Chernikov 	return (ENOMEM);
1034f1220db8SAlexander V. Chernikov }
1035f1220db8SAlexander V. Chernikov 
1036f1220db8SAlexander V. Chernikov /*
1037f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
1038f1220db8SAlexander V. Chernikov  */
1039f1220db8SAlexander V. Chernikov static void
1040f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
1041f1220db8SAlexander V. Chernikov {
104281d3153dSAlexander V. Chernikov 	ipfw_obj_tentry *tent;
104381d3153dSAlexander V. Chernikov 	uint32_t count;
1044f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
1045f1220db8SAlexander V. Chernikov 
1046f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
104781d3153dSAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(i + 1);
1048f1220db8SAlexander V. Chernikov 
1049f1220db8SAlexander V. Chernikov 	if (need_header)
1050f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1051f1220db8SAlexander V. Chernikov 
1052f1220db8SAlexander V. Chernikov 	count = i->count;
1053f1220db8SAlexander V. Chernikov 	while (count > 0) {
105481d3153dSAlexander V. Chernikov 		table_show_entry(i, tent);
105581d3153dSAlexander V. Chernikov 		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
105681d3153dSAlexander V. Chernikov 		count--;
105781d3153dSAlexander V. Chernikov 	}
105881d3153dSAlexander V. Chernikov }
105981d3153dSAlexander V. Chernikov 
106081d3153dSAlexander V. Chernikov static void
106181d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
106281d3153dSAlexander V. Chernikov {
1063*914bffb6SAlexander V. Chernikov 	char *comma, tbuf[128], pval[32];
1064*914bffb6SAlexander V. Chernikov 	void *paddr;
106581d3153dSAlexander V. Chernikov 	uint32_t tval;
1066*914bffb6SAlexander V. Chernikov 	struct tflow_entry *tfe;
106781d3153dSAlexander V. Chernikov 
106881d3153dSAlexander V. Chernikov 	tval = tent->value;
106981d3153dSAlexander V. Chernikov 
1070*914bffb6SAlexander V. Chernikov 	if (co.do_value_as_ip) {
1071*914bffb6SAlexander V. Chernikov 		tval = htonl(tval);
1072*914bffb6SAlexander V. Chernikov 		inet_ntop(AF_INET, &tval, pval, sizeof(pval));
1073*914bffb6SAlexander V. Chernikov 	} else
1074*914bffb6SAlexander V. Chernikov 		snprintf(pval, sizeof(pval), "%u", tval);
1075*914bffb6SAlexander V. Chernikov 
1076f1220db8SAlexander V. Chernikov 	switch (i->type) {
1077f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
1078f1220db8SAlexander V. Chernikov 		/* IPv4 or IPv6 prefixes */
107981d3153dSAlexander V. Chernikov 		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1080*914bffb6SAlexander V. Chernikov 		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1081f1220db8SAlexander V. Chernikov 		break;
1082f1220db8SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
1083f1220db8SAlexander V. Chernikov 		/* Interface names */
1084*914bffb6SAlexander V. Chernikov 		printf("%s %s\n", tent->k.iface, pval);
1085b23d5de9SAlexander V. Chernikov 		break;
1086b23d5de9SAlexander V. Chernikov 	case IPFW_TABLE_NUMBER:
1087b23d5de9SAlexander V. Chernikov 		/* numbers */
1088*914bffb6SAlexander V. Chernikov 		printf("%u %s\n", tent->k.key, pval);
1089b23d5de9SAlexander V. Chernikov 		break;
1090*914bffb6SAlexander V. Chernikov 	case IPFW_TABLE_FLOW:
1091*914bffb6SAlexander V. Chernikov 		/* flows */
1092*914bffb6SAlexander V. Chernikov 		tfe = &tent->k.flow;
1093*914bffb6SAlexander V. Chernikov 		comma = "";
1094*914bffb6SAlexander V. Chernikov 
1095*914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1096*914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1097*914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.sip;
1098*914bffb6SAlexander V. Chernikov 			else
1099*914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.sip6;
1100*914bffb6SAlexander V. Chernikov 
1101*914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1102*914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1103*914bffb6SAlexander V. Chernikov 			comma = ",";
1104*914bffb6SAlexander V. Chernikov 		}
1105*914bffb6SAlexander V. Chernikov 
1106*914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1107*914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, tfe->proto);
1108*914bffb6SAlexander V. Chernikov 			comma = ",";
1109*914bffb6SAlexander V. Chernikov 		}
1110*914bffb6SAlexander V. Chernikov 
1111*914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1112*914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->sport));
1113*914bffb6SAlexander V. Chernikov 			comma = ",";
1114*914bffb6SAlexander V. Chernikov 		}
1115*914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1116*914bffb6SAlexander V. Chernikov 			if (tfe->af == AF_INET)
1117*914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a4.dip;
1118*914bffb6SAlexander V. Chernikov 			else
1119*914bffb6SAlexander V. Chernikov 				paddr = &tfe->a.a6.dip6;
1120*914bffb6SAlexander V. Chernikov 
1121*914bffb6SAlexander V. Chernikov 			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1122*914bffb6SAlexander V. Chernikov 			printf("%s%s", comma, tbuf);
1123*914bffb6SAlexander V. Chernikov 			comma = ",";
1124*914bffb6SAlexander V. Chernikov 		}
1125*914bffb6SAlexander V. Chernikov 
1126*914bffb6SAlexander V. Chernikov 		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1127*914bffb6SAlexander V. Chernikov 			printf("%s%d", comma, ntohs(tfe->dport));
1128*914bffb6SAlexander V. Chernikov 			comma = ",";
1129*914bffb6SAlexander V. Chernikov 		}
1130*914bffb6SAlexander V. Chernikov 
1131*914bffb6SAlexander V. Chernikov 		printf(" %s\n", pval);
1132f1220db8SAlexander V. Chernikov 	}
1133f1220db8SAlexander V. Chernikov }
1134f1220db8SAlexander V. Chernikov 
11359d099b4fSAlexander V. Chernikov static int
11369d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh)
11379d099b4fSAlexander V. Chernikov {
11389d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
11399d099b4fSAlexander V. Chernikov 	size_t sz;
11409d099b4fSAlexander V. Chernikov 	int error;
11419d099b4fSAlexander V. Chernikov 
11429d099b4fSAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
11439d099b4fSAlexander V. Chernikov 	sz = sizeof(req);
11449d099b4fSAlexander V. Chernikov 
11459d099b4fSAlexander V. Chernikov 	error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
11469d099b4fSAlexander V. Chernikov 	if (error != 0 && error != ENOMEM)
11479d099b4fSAlexander V. Chernikov 		return (error);
11489d099b4fSAlexander V. Chernikov 
11499d099b4fSAlexander V. Chernikov 	sz = req.size;
11509d099b4fSAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
11519d099b4fSAlexander V. Chernikov 		return (ENOMEM);
11529d099b4fSAlexander V. Chernikov 
11539d099b4fSAlexander V. Chernikov 	olh->size = sz;
11549d099b4fSAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
11559d099b4fSAlexander V. Chernikov 		free(olh);
11569d099b4fSAlexander V. Chernikov 		return (error);
11579d099b4fSAlexander V. Chernikov 	}
11589d099b4fSAlexander V. Chernikov 
11599d099b4fSAlexander V. Chernikov 	*polh = olh;
11609d099b4fSAlexander V. Chernikov 	return (0);
11619d099b4fSAlexander V. Chernikov }
11629d099b4fSAlexander V. Chernikov 
11639d099b4fSAlexander V. Chernikov void
11649d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[])
11659d099b4fSAlexander V. Chernikov {
11669d099b4fSAlexander V. Chernikov 	ipfw_obj_lheader *olh;
11679d099b4fSAlexander V. Chernikov 	ipfw_ta_info *info;
11689d099b4fSAlexander V. Chernikov 	int error, i;
11699d099b4fSAlexander V. Chernikov 	const char *atype;
11709d099b4fSAlexander V. Chernikov 
11719d099b4fSAlexander V. Chernikov 	error = table_do_get_algolist(&olh);
11729d099b4fSAlexander V. Chernikov 	if (error != 0)
11739d099b4fSAlexander V. Chernikov 		err(EX_OSERR, "Unable to request algorithm list");
11749d099b4fSAlexander V. Chernikov 
11759d099b4fSAlexander V. Chernikov 	info = (ipfw_ta_info *)(olh + 1);
11769d099b4fSAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
11779d099b4fSAlexander V. Chernikov 		if ((atype = match_value(tabletypes, info->type)) == NULL)
11789d099b4fSAlexander V. Chernikov 			atype = "unknown";
11798ce7a2bcSAlexander V. Chernikov 		printf("--- %s ---\n", info->algoname);
11808ce7a2bcSAlexander V. Chernikov 		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
11819d099b4fSAlexander V. Chernikov 
11829d099b4fSAlexander V. Chernikov 		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
11839d099b4fSAlexander V. Chernikov 	}
11849d099b4fSAlexander V. Chernikov 
11859d099b4fSAlexander V. Chernikov 	free(olh);
11869d099b4fSAlexander V. Chernikov }
11879d099b4fSAlexander V. Chernikov 
11886c2997ffSAlexander V. Chernikov int
11896c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
11906c2997ffSAlexander V. Chernikov {
11916c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
11926c2997ffSAlexander V. Chernikov 
11936c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
11946c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
11956c2997ffSAlexander V. Chernikov 
11966c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
11976c2997ffSAlexander V. Chernikov 		return (-1);
11986c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
11996c2997ffSAlexander V. Chernikov 		return (1);
12006c2997ffSAlexander V. Chernikov 
12016c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
12026c2997ffSAlexander V. Chernikov 		return (-1);
12036c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
12046c2997ffSAlexander V. Chernikov 		return (1);
12056c2997ffSAlexander V. Chernikov 
12066c2997ffSAlexander V. Chernikov 	return (0);
12076c2997ffSAlexander V. Chernikov }
1208563b5ab1SAlexander V. Chernikov 
1209563b5ab1SAlexander V. Chernikov int
12106c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
1211563b5ab1SAlexander V. Chernikov {
1212563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1213563b5ab1SAlexander V. Chernikov 	uint16_t key;
1214563b5ab1SAlexander V. Chernikov 
1215563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
1216563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
1217563b5ab1SAlexander V. Chernikov 
1218563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
1219563b5ab1SAlexander V. Chernikov 		return (-1);
1220563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
1221563b5ab1SAlexander V. Chernikov 		return (1);
1222563b5ab1SAlexander V. Chernikov 
1223563b5ab1SAlexander V. Chernikov 	return (0);
1224563b5ab1SAlexander V. Chernikov }
1225563b5ab1SAlexander V. Chernikov 
1226563b5ab1SAlexander V. Chernikov /*
1227563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
1228563b5ab1SAlexander V. Chernikov  * Uses the following facts:
1229563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
1230563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
1231563b5ab1SAlexander V. Chernikov  *
1232563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
1233563b5ab1SAlexander V. Chernikov  */
1234563b5ab1SAlexander V. Chernikov char *
1235563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
1236563b5ab1SAlexander V. Chernikov {
1237563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
1238563b5ab1SAlexander V. Chernikov 
1239563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
12406c2997ffSAlexander V. Chernikov 	    compare_kntlv);
1241563b5ab1SAlexander V. Chernikov 
1242563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
1243563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
1244563b5ab1SAlexander V. Chernikov 
1245563b5ab1SAlexander V. Chernikov 	return (NULL);
1246563b5ab1SAlexander V. Chernikov }
1247563b5ab1SAlexander V. Chernikov 
12486c2997ffSAlexander V. Chernikov void
12496c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
12506c2997ffSAlexander V. Chernikov {
12516c2997ffSAlexander V. Chernikov 
12526c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
12536c2997ffSAlexander V. Chernikov }
12546c2997ffSAlexander V. Chernikov 
12556c2997ffSAlexander V. Chernikov int
12566c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
12576c2997ffSAlexander V. Chernikov {
12586c2997ffSAlexander V. Chernikov 	int c, i, l;
12596c2997ffSAlexander V. Chernikov 
12606c2997ffSAlexander V. Chernikov 	/*
12616c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
12626c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
1263ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
12646c2997ffSAlexander V. Chernikov 	 */
12656c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
12666c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
12676c2997ffSAlexander V. Chernikov 		return (EINVAL);
12686c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
12696c2997ffSAlexander V. Chernikov 		c = tablename[i];
12706c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
12716c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
12726c2997ffSAlexander V. Chernikov 			continue;
12736c2997ffSAlexander V. Chernikov 		return (EINVAL);
12746c2997ffSAlexander V. Chernikov 	}
12756c2997ffSAlexander V. Chernikov 
1276ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
1277ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
1278ac35ff17SAlexander V. Chernikov 		return (EINVAL);
1279ac35ff17SAlexander V. Chernikov 
12806c2997ffSAlexander V. Chernikov 	return (0);
12816c2997ffSAlexander V. Chernikov }
12826c2997ffSAlexander V. Chernikov 
1283