xref: /freebsd/sbin/ipfw/tables.c (revision ac35ff17842a49c0fc98ad5afda2410078651a86)
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);
52*ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
53*ac35ff17SAlexander V. Chernikov     int add, int update);
54*ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh);
55*ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh);
56*ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
57*ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
58*ac35ff17SAlexander 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);
60*ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
61*ac35ff17SAlexander 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);
65f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
66f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header);
67f1220db8SAlexander V. Chernikov 
68*ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
69*ac35ff17SAlexander V. Chernikov     char *key, uint8_t *ptype, uint8_t *pvtype);
70*ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
71*ac35ff17SAlexander V. Chernikov     char *arg, uint8_t type, uint8_t vtype);
72*ac35ff17SAlexander V. Chernikov 
73f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
74f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort);
75f1220db8SAlexander V. Chernikov 
76f1220db8SAlexander V. Chernikov #ifndef s6_addr32
77f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32
78f1220db8SAlexander V. Chernikov #endif
79f1220db8SAlexander V. Chernikov 
80*ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = {
81*ac35ff17SAlexander V. Chernikov       { "cidr",		IPFW_TABLE_CIDR },
82*ac35ff17SAlexander V. Chernikov       { "iface",	IPFW_TABLE_INTERFACE },
83*ac35ff17SAlexander V. Chernikov       { "u32",		IPFW_TABLE_U32 },
84*ac35ff17SAlexander V. Chernikov       { NULL, 0 }
85*ac35ff17SAlexander V. Chernikov };
86*ac35ff17SAlexander V. Chernikov 
87*ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = {
88*ac35ff17SAlexander V. Chernikov       { "dscp",		IPFW_VTYPE_DSCP },
89*ac35ff17SAlexander V. Chernikov       { "ip",		IPFW_VTYPE_IP },
90*ac35ff17SAlexander V. Chernikov       { "number",	IPFW_VTYPE_U32 },
91*ac35ff17SAlexander V. Chernikov       { NULL, 0 }
92*ac35ff17SAlexander V. Chernikov };
93*ac35ff17SAlexander V. Chernikov 
94*ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = {
95*ac35ff17SAlexander V. Chernikov       { "add",		TOK_ADD },
96*ac35ff17SAlexander V. Chernikov       { "create",	TOK_CREATE },
97*ac35ff17SAlexander V. Chernikov       { "delete",	TOK_DEL },
98*ac35ff17SAlexander V. Chernikov       { "destroy",	TOK_DESTROY },
99*ac35ff17SAlexander V. Chernikov       { "flush",	TOK_FLUSH },
100*ac35ff17SAlexander V. Chernikov       { "info",		TOK_INFO },
101*ac35ff17SAlexander V. Chernikov       { "list",		TOK_LIST },
102*ac35ff17SAlexander V. Chernikov       { NULL, 0 }
103*ac35ff17SAlexander V. Chernikov };
104*ac35ff17SAlexander V. Chernikov 
105f1220db8SAlexander V. Chernikov static int
106f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr)
107f1220db8SAlexander V. Chernikov {
108f1220db8SAlexander V. Chernikov 	struct hostent *he;
109f1220db8SAlexander V. Chernikov 
110f1220db8SAlexander V. Chernikov 	if (!inet_aton(host, ipaddr)) {
111f1220db8SAlexander V. Chernikov 		if ((he = gethostbyname(host)) == NULL)
112f1220db8SAlexander V. Chernikov 			return(-1);
113f1220db8SAlexander V. Chernikov 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
114f1220db8SAlexander V. Chernikov 	}
115f1220db8SAlexander V. Chernikov 	return(0);
116f1220db8SAlexander V. Chernikov }
117f1220db8SAlexander V. Chernikov 
118f1220db8SAlexander V. Chernikov /*
119f1220db8SAlexander V. Chernikov  * This one handles all table-related commands
120*ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME create ...
121*ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME destroy
122*ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME add addr[/masklen] [value]
123*ac35ff17SAlexander V. Chernikov  * 	ipfw table NAME delete addr[/masklen]
124*ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} flush
125*ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} list
126*ac35ff17SAlexander V. Chernikov  * 	ipfw table {NAME | all} info
127f1220db8SAlexander V. Chernikov  */
128f1220db8SAlexander V. Chernikov void
129f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[])
130f1220db8SAlexander V. Chernikov {
131*ac35ff17SAlexander V. Chernikov 	int do_add, is_all;
132*ac35ff17SAlexander V. Chernikov 	int error, tcmd;
133*ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info i;
134*ac35ff17SAlexander V. Chernikov 	ipfw_obj_header oh;
135f1220db8SAlexander V. Chernikov 	char *tablename;
136*ac35ff17SAlexander V. Chernikov 	uint32_t set;
137f1220db8SAlexander V. Chernikov 
138*ac35ff17SAlexander V. Chernikov 	memset(&oh, 0, sizeof(oh));
139*ac35ff17SAlexander V. Chernikov 	is_all = 0;
140*ac35ff17SAlexander V. Chernikov 	if (co.use_set != 0)
141*ac35ff17SAlexander V. Chernikov 		set = co.use_set - 1;
142*ac35ff17SAlexander V. Chernikov 	else
143*ac35ff17SAlexander V. Chernikov 		set = 0;
144f1220db8SAlexander V. Chernikov 
145f1220db8SAlexander V. Chernikov 	ac--; av++;
146f1220db8SAlexander V. Chernikov 	tablename = *av;
147f1220db8SAlexander V. Chernikov 
148*ac35ff17SAlexander V. Chernikov 	if (table_check_name(tablename) == 0) {
149*ac35ff17SAlexander V. Chernikov 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
150*ac35ff17SAlexander V. Chernikov 		//oh->set = set;
151*ac35ff17SAlexander V. Chernikov 		oh.idx = 1;
152*ac35ff17SAlexander V. Chernikov 	} else {
153*ac35ff17SAlexander V. Chernikov 		if (strcmp(tablename, "all") == 0)
154*ac35ff17SAlexander V. Chernikov 			is_all = 1;
155*ac35ff17SAlexander V. Chernikov 		else
156*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name %s is invalid", tablename);
157*ac35ff17SAlexander V. Chernikov 	}
158*ac35ff17SAlexander V. Chernikov 	ac--; av++;
159*ac35ff17SAlexander V. Chernikov 
160*ac35ff17SAlexander V. Chernikov 	if ((tcmd = match_token(tablecmds, *av)) == -1)
161*ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "invalid table command %s", *av);
162*ac35ff17SAlexander V. Chernikov 
163*ac35ff17SAlexander V. Chernikov 	NEED1("table needs command");
164*ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
165*ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
166*ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
167*ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
168*ac35ff17SAlexander V. Chernikov 		break;
169*ac35ff17SAlexander V. Chernikov 	default:
170*ac35ff17SAlexander V. Chernikov 		if (is_all != 0)
171*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "table name required");
172*ac35ff17SAlexander V. Chernikov 	}
173*ac35ff17SAlexander V. Chernikov 
174*ac35ff17SAlexander V. Chernikov 	switch (tcmd) {
175*ac35ff17SAlexander V. Chernikov 	case TOK_ADD:
176*ac35ff17SAlexander V. Chernikov 	case TOK_DEL:
177f1220db8SAlexander V. Chernikov 		do_add = **av == 'a';
178f1220db8SAlexander V. Chernikov 		ac--; av++;
179*ac35ff17SAlexander V. Chernikov 		table_modify_record(&oh, ac, av, do_add, co.do_quiet);
180*ac35ff17SAlexander V. Chernikov 		break;
181*ac35ff17SAlexander V. Chernikov 	case TOK_CREATE:
182f1220db8SAlexander V. Chernikov 		ac--; av++;
183*ac35ff17SAlexander V. Chernikov 		table_create(&oh, ac, av);
184*ac35ff17SAlexander V. Chernikov 		break;
185*ac35ff17SAlexander V. Chernikov 	case TOK_DESTROY:
186*ac35ff17SAlexander V. Chernikov 		if (table_destroy(&oh) != 0)
187*ac35ff17SAlexander V. Chernikov 			err(EX_OSERR, "failed to destroy table %s", tablename);
188*ac35ff17SAlexander V. Chernikov 		break;
189*ac35ff17SAlexander V. Chernikov 	case TOK_FLUSH:
190f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
191*ac35ff17SAlexander V. Chernikov 			if ((error = table_flush(&oh)) != 0)
192f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush table %s info",
193f1220db8SAlexander V. Chernikov 				    tablename);
194f1220db8SAlexander V. Chernikov 		} else {
195*ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_flush_one, &oh, 1);
196f1220db8SAlexander V. Chernikov 			if (error != 0)
197f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to flush tables list");
198f1220db8SAlexander V. Chernikov 		}
199*ac35ff17SAlexander V. Chernikov 		break;
200*ac35ff17SAlexander V. Chernikov 	case TOK_INFO:
201f1220db8SAlexander V. Chernikov 		if (is_all == 0) {
202*ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
203f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
204f1220db8SAlexander V. Chernikov 			table_show_info(&i, NULL);
205f1220db8SAlexander V. Chernikov 		} else {
206f1220db8SAlexander V. Chernikov 			error = tables_foreach(table_show_info, NULL, 1);
207f1220db8SAlexander V. Chernikov 			if (error != 0)
208f1220db8SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
209f1220db8SAlexander V. Chernikov 		}
210*ac35ff17SAlexander V. Chernikov 		break;
211*ac35ff17SAlexander V. Chernikov 	case TOK_LIST:
212*ac35ff17SAlexander V. Chernikov 		if (is_all == 0) {
213*ac35ff17SAlexander V. Chernikov 			ipfw_xtable_info i;
214*ac35ff17SAlexander V. Chernikov 			if ((error = table_get_info(&oh, &i)) != 0)
215*ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request table info");
216*ac35ff17SAlexander V. Chernikov 			table_show_one(&i, NULL);
217f1220db8SAlexander V. Chernikov 		} else {
218*ac35ff17SAlexander V. Chernikov 			error = tables_foreach(table_show_one, NULL, 1);
219*ac35ff17SAlexander V. Chernikov 			if (error != 0)
220*ac35ff17SAlexander V. Chernikov 				err(EX_OSERR, "failed to request tables list");
221f1220db8SAlexander V. Chernikov 		}
222*ac35ff17SAlexander V. Chernikov 		break;
223f1220db8SAlexander V. Chernikov 	}
224f1220db8SAlexander V. Chernikov }
225f1220db8SAlexander V. Chernikov 
226f1220db8SAlexander V. Chernikov static void
227*ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
228f1220db8SAlexander V. Chernikov {
229f1220db8SAlexander V. Chernikov 
230563b5ab1SAlexander V. Chernikov 	ntlv->head.type = IPFW_TLV_TBL_NAME;
231f1220db8SAlexander V. Chernikov 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
232f1220db8SAlexander V. Chernikov 	ntlv->idx = uidx;
233*ac35ff17SAlexander V. Chernikov 	ntlv->set = set;
234f1220db8SAlexander V. Chernikov 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
235f1220db8SAlexander V. Chernikov }
236f1220db8SAlexander V. Chernikov 
237f1220db8SAlexander V. Chernikov static void
238f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
239f1220db8SAlexander V. Chernikov {
240f1220db8SAlexander V. Chernikov 
241f1220db8SAlexander V. Chernikov 	oh->set = i->set;
242f1220db8SAlexander V. Chernikov 	oh->idx = 1;
243*ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, oh->set, 1);
244*ac35ff17SAlexander V. Chernikov }
245*ac35ff17SAlexander V. Chernikov 
246*ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = {
247*ac35ff17SAlexander V. Chernikov       { "type",		TOK_TYPE},
248*ac35ff17SAlexander V. Chernikov       { "valtype",	TOK_VALTYPE },
249*ac35ff17SAlexander V. Chernikov       { "algo",		TOK_ALGO },
250*ac35ff17SAlexander V. Chernikov       { NULL, 0 }
251*ac35ff17SAlexander V. Chernikov };
252*ac35ff17SAlexander V. Chernikov 
253*ac35ff17SAlexander V. Chernikov /*
254*ac35ff17SAlexander V. Chernikov  * Creates new table
255*ac35ff17SAlexander V. Chernikov  *
256*ac35ff17SAlexander V. Chernikov  * ipfw table NAME create [ type { cidr | iface | u32 } ]
257*ac35ff17SAlexander V. Chernikov  *     [ valtype { number | ip | dscp } ]
258*ac35ff17SAlexander V. Chernikov  *     [ algo algoname ]
259*ac35ff17SAlexander V. Chernikov  *
260*ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
261*ac35ff17SAlexander V. Chernikov  */
262*ac35ff17SAlexander V. Chernikov static void
263*ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[])
264*ac35ff17SAlexander V. Chernikov {
265*ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
266*ac35ff17SAlexander V. Chernikov 	int error, tcmd, val;
267*ac35ff17SAlexander V. Chernikov 	size_t sz;
268*ac35ff17SAlexander V. Chernikov 	char tbuf[128];
269*ac35ff17SAlexander V. Chernikov 
270*ac35ff17SAlexander V. Chernikov 	sz = sizeof(tbuf);
271*ac35ff17SAlexander V. Chernikov 	memset(&xi, 0, sizeof(xi));
272*ac35ff17SAlexander V. Chernikov 
273*ac35ff17SAlexander V. Chernikov 	/* Set some defaults to preserve compability */
274*ac35ff17SAlexander V. Chernikov 	xi.type = IPFW_TABLE_CIDR;
275*ac35ff17SAlexander V. Chernikov 	xi.vtype = IPFW_VTYPE_U32;
276*ac35ff17SAlexander V. Chernikov 
277*ac35ff17SAlexander V. Chernikov 	while (ac > 0) {
278*ac35ff17SAlexander V. Chernikov 		if ((tcmd = match_token(tablenewcmds, *av)) == -1)
279*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "unknown option: %s", *av);
280*ac35ff17SAlexander V. Chernikov 		ac--; av++;
281*ac35ff17SAlexander V. Chernikov 
282*ac35ff17SAlexander V. Chernikov 		switch (tcmd) {
283*ac35ff17SAlexander V. Chernikov 		case TOK_TYPE:
284*ac35ff17SAlexander V. Chernikov 			NEED1("table type required");
285*ac35ff17SAlexander V. Chernikov 			val = match_token(tabletypes, *av);
286*ac35ff17SAlexander V. Chernikov 			if (val != -1) {
287*ac35ff17SAlexander V. Chernikov 				printf("av %s type %d\n", *av, xi.type);
288*ac35ff17SAlexander V. Chernikov 				xi.type = val;
289*ac35ff17SAlexander V. Chernikov 				ac--; av++;
290*ac35ff17SAlexander V. Chernikov 				break;
291*ac35ff17SAlexander V. Chernikov 			}
292*ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", ");
293*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s",
294*ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
295*ac35ff17SAlexander V. Chernikov 			break;
296*ac35ff17SAlexander V. Chernikov 		case TOK_VALTYPE:
297*ac35ff17SAlexander V. Chernikov 			NEED1("table value type required");
298*ac35ff17SAlexander V. Chernikov 			val = match_token(tablevaltypes, *av);
299*ac35ff17SAlexander V. Chernikov 			if (val != -1) {
300*ac35ff17SAlexander V. Chernikov 				xi.vtype = val;
301*ac35ff17SAlexander V. Chernikov 				ac--; av++;
302*ac35ff17SAlexander V. Chernikov 				break;
303*ac35ff17SAlexander V. Chernikov 			}
304*ac35ff17SAlexander V. Chernikov 			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
305*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
306*ac35ff17SAlexander V. Chernikov 			    *av, tbuf);
307*ac35ff17SAlexander V. Chernikov 			break;
308*ac35ff17SAlexander V. Chernikov 		case TOK_ALGO:
309*ac35ff17SAlexander V. Chernikov 			NEED1("table algorithm name required");
310*ac35ff17SAlexander V. Chernikov 			if (strlen(*av) > sizeof(xi.algoname))
311*ac35ff17SAlexander V. Chernikov 				errx(EX_USAGE, "algorithm name too long");
312*ac35ff17SAlexander V. Chernikov 			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
313*ac35ff17SAlexander V. Chernikov 			ac--; av++;
314*ac35ff17SAlexander V. Chernikov 			break;
315*ac35ff17SAlexander V. Chernikov 		}
316*ac35ff17SAlexander V. Chernikov 	}
317*ac35ff17SAlexander V. Chernikov 
318*ac35ff17SAlexander V. Chernikov 	if ((error = table_do_create(oh, &xi)) != 0)
319*ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "Table creation failed");
320f1220db8SAlexander V. Chernikov }
321f1220db8SAlexander V. Chernikov 
322f1220db8SAlexander V. Chernikov /*
323*ac35ff17SAlexander V. Chernikov  * Creates new table
324*ac35ff17SAlexander V. Chernikov  *
325*ac35ff17SAlexander V. Chernikov  * Request: [ ipfw_obj_header ipfw_xtable_info ]
326*ac35ff17SAlexander V. Chernikov  *
327f1220db8SAlexander V. Chernikov  * Returns 0 on success.
328f1220db8SAlexander V. Chernikov  */
329f1220db8SAlexander V. Chernikov static int
330*ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
331f1220db8SAlexander V. Chernikov {
332*ac35ff17SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
333*ac35ff17SAlexander V. Chernikov 	int error;
334f1220db8SAlexander V. Chernikov 
335*ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
336*ac35ff17SAlexander V. Chernikov 	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
337*ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
338*ac35ff17SAlexander V. Chernikov 
339*ac35ff17SAlexander V. Chernikov 	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
340*ac35ff17SAlexander V. Chernikov 
341*ac35ff17SAlexander V. Chernikov 	return (error);
342*ac35ff17SAlexander V. Chernikov }
343*ac35ff17SAlexander V. Chernikov 
344*ac35ff17SAlexander V. Chernikov /*
345*ac35ff17SAlexander V. Chernikov  * Destroys given table specified by @oh->ntlv.
346*ac35ff17SAlexander V. Chernikov  * Returns 0 on success.
347*ac35ff17SAlexander V. Chernikov  */
348*ac35ff17SAlexander V. Chernikov static int
349*ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh)
350*ac35ff17SAlexander V. Chernikov {
351*ac35ff17SAlexander V. Chernikov 
352*ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
353f1220db8SAlexander V. Chernikov 		return (-1);
354f1220db8SAlexander V. Chernikov 
355f1220db8SAlexander V. Chernikov 	return (0);
356f1220db8SAlexander V. Chernikov }
357f1220db8SAlexander V. Chernikov 
358f1220db8SAlexander V. Chernikov /*
359*ac35ff17SAlexander V. Chernikov  * Flushes given table specified by @oh->ntlv.
360f1220db8SAlexander V. Chernikov  * Returns 0 on success.
361f1220db8SAlexander V. Chernikov  */
362f1220db8SAlexander V. Chernikov static int
363*ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh)
364f1220db8SAlexander V. Chernikov {
365f1220db8SAlexander V. Chernikov 
366*ac35ff17SAlexander V. Chernikov 	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
367f1220db8SAlexander V. Chernikov 		return (-1);
368f1220db8SAlexander V. Chernikov 
369f1220db8SAlexander V. Chernikov 	return (0);
370f1220db8SAlexander V. Chernikov }
371f1220db8SAlexander V. Chernikov 
372f1220db8SAlexander V. Chernikov /*
373*ac35ff17SAlexander V. Chernikov  * Retrieves table in given table specified by @oh->ntlv.
374f1220db8SAlexander V. Chernikov  * it inside @i.
375f1220db8SAlexander V. Chernikov  * Returns 0 on success.
376f1220db8SAlexander V. Chernikov  */
377f1220db8SAlexander V. Chernikov static int
378*ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
379f1220db8SAlexander V. Chernikov {
380f1220db8SAlexander V. Chernikov 	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
381*ac35ff17SAlexander V. Chernikov 	int error;
382f1220db8SAlexander V. Chernikov 	size_t sz;
383f1220db8SAlexander V. Chernikov 
384f1220db8SAlexander V. Chernikov 	sz = sizeof(tbuf);
385f1220db8SAlexander V. Chernikov 	memset(tbuf, 0, sizeof(tbuf));
386*ac35ff17SAlexander V. Chernikov 	memcpy(tbuf, oh, sizeof(*oh));
387f1220db8SAlexander V. Chernikov 	oh = (ipfw_obj_header *)tbuf;
388f1220db8SAlexander V. Chernikov 
389*ac35ff17SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
390*ac35ff17SAlexander V. Chernikov 		return (error);
391f1220db8SAlexander V. Chernikov 
392f1220db8SAlexander V. Chernikov 	if (sz < sizeof(tbuf))
393*ac35ff17SAlexander V. Chernikov 		return (EINVAL);
394f1220db8SAlexander V. Chernikov 
395f1220db8SAlexander V. Chernikov 	*i = *(ipfw_xtable_info *)(oh + 1);
396f1220db8SAlexander V. Chernikov 
397f1220db8SAlexander V. Chernikov 	return (0);
398f1220db8SAlexander V. Chernikov }
399f1220db8SAlexander V. Chernikov 
400f1220db8SAlexander V. Chernikov /*
401f1220db8SAlexander V. Chernikov  * Prints table info struct @i in human-readable form.
402f1220db8SAlexander V. Chernikov  */
403f1220db8SAlexander V. Chernikov static int
404f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg)
405f1220db8SAlexander V. Chernikov {
406*ac35ff17SAlexander V. Chernikov 	const char *ttype, *vtype;
407f1220db8SAlexander V. Chernikov 
408f1220db8SAlexander V. Chernikov 	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
409*ac35ff17SAlexander V. Chernikov 	if ((ttype = match_value(tabletypes, i->type)) == NULL)
410*ac35ff17SAlexander V. Chernikov 		ttype = "unknown";
411*ac35ff17SAlexander V. Chernikov 	if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
412*ac35ff17SAlexander V. Chernikov 		vtype = "unknown";
413*ac35ff17SAlexander V. Chernikov 
414*ac35ff17SAlexander V. Chernikov 	printf(" type: %s, kindex: %d\n", ttype, i->kidx);
415*ac35ff17SAlexander V. Chernikov 	printf(" valtype: %s, algorithm: %s\n", vtype, i->algoname);
416f1220db8SAlexander V. Chernikov 	printf(" references: %u\n", i->refcnt);
417f1220db8SAlexander V. Chernikov 	printf(" items: %u, size: %u\n", i->count, i->size);
418f1220db8SAlexander V. Chernikov 
419f1220db8SAlexander V. Chernikov 	return (0);
420f1220db8SAlexander V. Chernikov }
421f1220db8SAlexander V. Chernikov 
422f1220db8SAlexander V. Chernikov 
423f1220db8SAlexander V. Chernikov /*
424f1220db8SAlexander V. Chernikov  * Function wrappers which can be used either
425f1220db8SAlexander V. Chernikov  * as is or as foreach function parameter.
426f1220db8SAlexander V. Chernikov  */
427f1220db8SAlexander V. Chernikov 
428f1220db8SAlexander V. Chernikov static int
429f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg)
430f1220db8SAlexander V. Chernikov {
431f1220db8SAlexander V. Chernikov 	ipfw_obj_header *oh;
432f1220db8SAlexander V. Chernikov 
433*ac35ff17SAlexander V. Chernikov 	if ((oh = calloc(1, i->size)) == NULL)
434f1220db8SAlexander V. Chernikov 		return (ENOMEM);
435f1220db8SAlexander V. Chernikov 
436f1220db8SAlexander V. Chernikov 	if (table_get_list(i, oh) == 0)
437f1220db8SAlexander V. Chernikov 		table_show_list(oh, 1);
438f1220db8SAlexander V. Chernikov 
439f1220db8SAlexander V. Chernikov 	free(oh);
440f1220db8SAlexander V. Chernikov 	return (0);
441f1220db8SAlexander V. Chernikov }
442f1220db8SAlexander V. Chernikov 
443f1220db8SAlexander V. Chernikov static int
444f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg)
445f1220db8SAlexander V. Chernikov {
446*ac35ff17SAlexander V. Chernikov 	ipfw_obj_header *oh;
447f1220db8SAlexander V. Chernikov 
448*ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)arg;
449*ac35ff17SAlexander V. Chernikov 
450*ac35ff17SAlexander V. Chernikov 	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
451*ac35ff17SAlexander V. Chernikov 
452*ac35ff17SAlexander V. Chernikov 	return (table_flush(oh));
453f1220db8SAlexander V. Chernikov }
454f1220db8SAlexander V. Chernikov 
455*ac35ff17SAlexander V. Chernikov static int
456*ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh,
457*ac35ff17SAlexander V. Chernikov     ipfw_obj_tentry *tent, int update)
458*ac35ff17SAlexander V. Chernikov {
459*ac35ff17SAlexander V. Chernikov 	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
460*ac35ff17SAlexander V. Chernikov 	int error;
461*ac35ff17SAlexander V. Chernikov 
462*ac35ff17SAlexander V. Chernikov 	memset(xbuf, 0, sizeof(xbuf));
463*ac35ff17SAlexander V. Chernikov 	memcpy(xbuf, oh, sizeof(*oh));
464*ac35ff17SAlexander V. Chernikov 	oh = (ipfw_obj_header *)xbuf;
465*ac35ff17SAlexander V. Chernikov 	oh->opheader.version = 1;
466*ac35ff17SAlexander V. Chernikov 
467*ac35ff17SAlexander V. Chernikov 	memcpy(oh + 1, tent, sizeof(*tent));
468*ac35ff17SAlexander V. Chernikov 	tent = (ipfw_obj_tentry *)(oh + 1);
469*ac35ff17SAlexander V. Chernikov 	if (update != 0)
470*ac35ff17SAlexander V. Chernikov 		tent->flags |= IPFW_TF_UPDATE;
471*ac35ff17SAlexander V. Chernikov 	tent->head.length = sizeof(ipfw_obj_tentry);
472*ac35ff17SAlexander V. Chernikov 
473*ac35ff17SAlexander V. Chernikov 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
474*ac35ff17SAlexander V. Chernikov 
475*ac35ff17SAlexander V. Chernikov 	return (error);
476*ac35ff17SAlexander V. Chernikov }
477*ac35ff17SAlexander V. Chernikov 
478*ac35ff17SAlexander V. Chernikov static void
479*ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
480*ac35ff17SAlexander V. Chernikov {
481*ac35ff17SAlexander V. Chernikov 	ipfw_obj_tentry tent;
482*ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
483*ac35ff17SAlexander V. Chernikov 	int cmd;
484*ac35ff17SAlexander V. Chernikov 	char *texterr;
485*ac35ff17SAlexander V. Chernikov 
486*ac35ff17SAlexander V. Chernikov 	if (ac == 0)
487*ac35ff17SAlexander V. Chernikov 		errx(EX_USAGE, "address required");
488*ac35ff17SAlexander V. Chernikov 
489*ac35ff17SAlexander V. Chernikov 	memset(&tent, 0, sizeof(tent));
490*ac35ff17SAlexander V. Chernikov 	tent.head.length = sizeof(tent);
491*ac35ff17SAlexander V. Chernikov 	tent.idx = 1;
492*ac35ff17SAlexander V. Chernikov 
493*ac35ff17SAlexander V. Chernikov 	tentry_fill_key(oh, &tent, *av, &type, &vtype);
494*ac35ff17SAlexander V. Chernikov 	oh->ntlv.type = type;
495*ac35ff17SAlexander V. Chernikov 	ac--; av++;
496*ac35ff17SAlexander V. Chernikov 
497*ac35ff17SAlexander V. Chernikov 	if (add != 0) {
498*ac35ff17SAlexander V. Chernikov 		if (ac > 0)
499*ac35ff17SAlexander V. Chernikov 			tentry_fill_value(oh, &tent, *av, type, vtype);
500*ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XADD;
501*ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XADD)";
502*ac35ff17SAlexander V. Chernikov 	} else {
503*ac35ff17SAlexander V. Chernikov 		cmd = IP_FW_TABLE_XDEL;
504*ac35ff17SAlexander V. Chernikov 		texterr = "setsockopt(IP_FW_TABLE_XDEL)";
505*ac35ff17SAlexander V. Chernikov 	}
506*ac35ff17SAlexander V. Chernikov 
507*ac35ff17SAlexander V. Chernikov 	if (table_do_modify_record(cmd, oh, &tent, update) != 0)
508*ac35ff17SAlexander V. Chernikov 		err(EX_OSERR, "%s", texterr);
509*ac35ff17SAlexander V. Chernikov }
510*ac35ff17SAlexander V. Chernikov 
511*ac35ff17SAlexander V. Chernikov 
512*ac35ff17SAlexander V. Chernikov static void
513*ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
514*ac35ff17SAlexander V. Chernikov {
515*ac35ff17SAlexander V. Chernikov 	char *p;
516*ac35ff17SAlexander V. Chernikov 	int mask, af;
517*ac35ff17SAlexander V. Chernikov 	struct in6_addr *paddr;
518*ac35ff17SAlexander V. Chernikov 	uint32_t key, *pkey;
519*ac35ff17SAlexander V. Chernikov 	int masklen;
520*ac35ff17SAlexander V. Chernikov 
521*ac35ff17SAlexander V. Chernikov 	masklen = 0;
522*ac35ff17SAlexander V. Chernikov 	af = 0;
523*ac35ff17SAlexander V. Chernikov 	paddr = (struct in6_addr *)&tentry->k;
524*ac35ff17SAlexander V. Chernikov 
525*ac35ff17SAlexander V. Chernikov 	switch (type) {
526*ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_CIDR:
527*ac35ff17SAlexander V. Chernikov 		/* Remove / if exists */
528*ac35ff17SAlexander V. Chernikov 		if ((p = strchr(arg, '/')) != NULL) {
529*ac35ff17SAlexander V. Chernikov 			*p = '\0';
530*ac35ff17SAlexander V. Chernikov 			mask = atoi(p + 1);
531*ac35ff17SAlexander V. Chernikov 		}
532*ac35ff17SAlexander V. Chernikov 
533*ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, paddr) == 1) {
534*ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 32)
535*ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv4 mask width: %s",
536*ac35ff17SAlexander V. Chernikov 				    p + 1);
537*ac35ff17SAlexander V. Chernikov 
538*ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 32;
539*ac35ff17SAlexander V. Chernikov 			af = AF_INET;
540*ac35ff17SAlexander V. Chernikov 		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
541*ac35ff17SAlexander V. Chernikov 			if (IN6_IS_ADDR_V4COMPAT(paddr))
542*ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR,
543*ac35ff17SAlexander V. Chernikov 				    "Use IPv4 instead of v4-compatible");
544*ac35ff17SAlexander V. Chernikov 			if (p != NULL && mask > 128)
545*ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "bad IPv6 mask width: %s",
546*ac35ff17SAlexander V. Chernikov 				    p + 1);
547*ac35ff17SAlexander V. Chernikov 
548*ac35ff17SAlexander V. Chernikov 			masklen = p ? mask : 128;
549*ac35ff17SAlexander V. Chernikov 			af = AF_INET6;
550*ac35ff17SAlexander V. Chernikov 		} else {
551*ac35ff17SAlexander V. Chernikov 			/* Assume FQDN */
552*ac35ff17SAlexander V. Chernikov 			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
553*ac35ff17SAlexander V. Chernikov 				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
554*ac35ff17SAlexander V. Chernikov 
555*ac35ff17SAlexander V. Chernikov 			masklen = 32;
556*ac35ff17SAlexander V. Chernikov 			type = IPFW_TABLE_CIDR;
557*ac35ff17SAlexander V. Chernikov 			af = AF_INET;
558*ac35ff17SAlexander V. Chernikov 		}
559*ac35ff17SAlexander V. Chernikov 		break;
560*ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_INTERFACE:
561*ac35ff17SAlexander V. Chernikov 		/* Assume interface name. Copy significant data only */
562*ac35ff17SAlexander V. Chernikov 		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
563*ac35ff17SAlexander V. Chernikov 		memcpy(paddr, arg, mask);
564*ac35ff17SAlexander V. Chernikov 		/* Set mask to exact match */
565*ac35ff17SAlexander V. Chernikov 		masklen = 8 * IF_NAMESIZE;
566*ac35ff17SAlexander V. Chernikov 		break;
567*ac35ff17SAlexander V. Chernikov 	case IPFW_TABLE_U32:
568*ac35ff17SAlexander V. Chernikov 		/* Port or any other key */
569*ac35ff17SAlexander V. Chernikov 		key = strtol(arg, &p, 10);
570*ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
571*ac35ff17SAlexander V. Chernikov 			errx(EX_DATAERR, "Invalid number: %s", arg);
572*ac35ff17SAlexander V. Chernikov 
573*ac35ff17SAlexander V. Chernikov 		pkey = (uint32_t *)paddr;
574*ac35ff17SAlexander V. Chernikov 		*pkey = key;
575*ac35ff17SAlexander V. Chernikov 		masklen = 32;
576*ac35ff17SAlexander V. Chernikov 		break;
577*ac35ff17SAlexander V. Chernikov 	default:
578*ac35ff17SAlexander V. Chernikov 		errx(EX_DATAERR, "Unsupported table type: %d", type);
579*ac35ff17SAlexander V. Chernikov 	}
580*ac35ff17SAlexander V. Chernikov 
581*ac35ff17SAlexander V. Chernikov 	tentry->subtype = af;
582*ac35ff17SAlexander V. Chernikov 	tentry->masklen = masklen;
583*ac35ff17SAlexander V. Chernikov }
584*ac35ff17SAlexander V. Chernikov 
585*ac35ff17SAlexander V. Chernikov static void
586*ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
587*ac35ff17SAlexander V. Chernikov     uint8_t *ptype, uint8_t *pvtype)
588*ac35ff17SAlexander V. Chernikov {
589*ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
590*ac35ff17SAlexander V. Chernikov 	uint8_t type, vtype;
591*ac35ff17SAlexander V. Chernikov 	int error;
592*ac35ff17SAlexander V. Chernikov 
593*ac35ff17SAlexander V. Chernikov 	type = 0;
594*ac35ff17SAlexander V. Chernikov 	vtype = 0;
595*ac35ff17SAlexander V. Chernikov 
596*ac35ff17SAlexander V. Chernikov 	/*
597*ac35ff17SAlexander V. Chernikov 	 * Compability layer. Try to interpret data as CIDR first.
598*ac35ff17SAlexander V. Chernikov 	 */
599*ac35ff17SAlexander V. Chernikov 	if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
600*ac35ff17SAlexander V. Chernikov 	    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
601*ac35ff17SAlexander V. Chernikov 		/* OK Prepare and send */
602*ac35ff17SAlexander V. Chernikov 		type = IPFW_TABLE_CIDR;
603*ac35ff17SAlexander V. Chernikov 	} else {
604*ac35ff17SAlexander V. Chernikov 
605*ac35ff17SAlexander V. Chernikov 		/*
606*ac35ff17SAlexander V. Chernikov 		 * Non-CIDR of FQDN hostname. Ask kernel
607*ac35ff17SAlexander V. Chernikov 		 * about given table.
608*ac35ff17SAlexander V. Chernikov 		 */
609*ac35ff17SAlexander V. Chernikov 		error = table_get_info(oh, &xi);
610*ac35ff17SAlexander V. Chernikov 		if (error == ESRCH)
611*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist, cannot intuit "
612*ac35ff17SAlexander V. Chernikov 			    "key type", oh->ntlv.name);
613*ac35ff17SAlexander V. Chernikov 		else if (error != 0)
614*ac35ff17SAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
615*ac35ff17SAlexander V. Chernikov 			    oh->ntlv.name);
616*ac35ff17SAlexander V. Chernikov 
617*ac35ff17SAlexander V. Chernikov 		/* Table found. */
618*ac35ff17SAlexander V. Chernikov 		type = xi.type;
619*ac35ff17SAlexander V. Chernikov 		vtype = xi.vtype;
620*ac35ff17SAlexander V. Chernikov 	}
621*ac35ff17SAlexander V. Chernikov 
622*ac35ff17SAlexander V. Chernikov 	tentry_fill_key_type(key, tent, type);
623*ac35ff17SAlexander V. Chernikov 
624*ac35ff17SAlexander V. Chernikov 	*ptype = type;
625*ac35ff17SAlexander V. Chernikov 	*pvtype = vtype;
626*ac35ff17SAlexander V. Chernikov }
627*ac35ff17SAlexander V. Chernikov 
628*ac35ff17SAlexander V. Chernikov static void
629*ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
630*ac35ff17SAlexander V. Chernikov     uint8_t type, uint8_t vtype)
631*ac35ff17SAlexander V. Chernikov {
632*ac35ff17SAlexander V. Chernikov 	ipfw_xtable_info xi;
633*ac35ff17SAlexander V. Chernikov 	int error;
634*ac35ff17SAlexander V. Chernikov 	int code;
635*ac35ff17SAlexander V. Chernikov 	char *p;
636*ac35ff17SAlexander V. Chernikov 
637*ac35ff17SAlexander V. Chernikov 	if (vtype == 0) {
638*ac35ff17SAlexander V. Chernikov 		/* Format type is unknown, ask kernel */
639*ac35ff17SAlexander V. Chernikov 		error = table_get_info(oh, &xi);
640*ac35ff17SAlexander V. Chernikov 		if (error == ESRCH) {
641*ac35ff17SAlexander V. Chernikov 
642*ac35ff17SAlexander V. Chernikov 			/*
643*ac35ff17SAlexander V. Chernikov 			 * XXX: This one may break some scripts.
644*ac35ff17SAlexander V. Chernikov 			 * Change this behavior for MFC.
645*ac35ff17SAlexander V. Chernikov 			 */
646*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Table %s does not exist. Unable to "
647*ac35ff17SAlexander V. Chernikov 			    "guess value format.",  oh->ntlv.name);
648*ac35ff17SAlexander V. Chernikov 		} else if (error != 0)
649*ac35ff17SAlexander V. Chernikov 			errx(EX_OSERR, "Error requesting table %s info",
650*ac35ff17SAlexander V. Chernikov 			    oh->ntlv.name);
651*ac35ff17SAlexander V. Chernikov 
652*ac35ff17SAlexander V. Chernikov 		vtype = xi.vtype;
653*ac35ff17SAlexander V. Chernikov 	}
654*ac35ff17SAlexander V. Chernikov 
655*ac35ff17SAlexander V. Chernikov 	switch (vtype) {
656*ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_U32:
657*ac35ff17SAlexander V. Chernikov 		tent->value = strtoul(arg, &p, 0);
658*ac35ff17SAlexander V. Chernikov 		if (*p != '\0')
659*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid number: %s", arg);
660*ac35ff17SAlexander V. Chernikov 		break;
661*ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_IP:
662*ac35ff17SAlexander V. Chernikov 		if (inet_pton(AF_INET, arg, &tent->value) == 1)
663*ac35ff17SAlexander V. Chernikov 			break;
664*ac35ff17SAlexander V. Chernikov 		/* Try hostname */
665*ac35ff17SAlexander V. Chernikov 		if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
666*ac35ff17SAlexander V. Chernikov 			errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
667*ac35ff17SAlexander V. Chernikov 		break;
668*ac35ff17SAlexander V. Chernikov 	case IPFW_VTYPE_DSCP:
669*ac35ff17SAlexander V. Chernikov 		if (isalpha(*arg)) {
670*ac35ff17SAlexander V. Chernikov 			if ((code = match_token(f_ipdscp, arg)) == -1)
671*ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Unknown DSCP code");
672*ac35ff17SAlexander V. Chernikov 		} else {
673*ac35ff17SAlexander V. Chernikov 			code = strtoul(arg, NULL, 10);
674*ac35ff17SAlexander V. Chernikov 			if (code < 0 || code > 63)
675*ac35ff17SAlexander V. Chernikov 				errx(EX_DATAERR, "Invalid DSCP value");
676*ac35ff17SAlexander V. Chernikov 		}
677*ac35ff17SAlexander V. Chernikov 		tent->value = code;
678*ac35ff17SAlexander V. Chernikov 		break;
679*ac35ff17SAlexander V. Chernikov 	default:
680*ac35ff17SAlexander V. Chernikov 		errx(EX_OSERR, "Unsupported format type %d", vtype);
681*ac35ff17SAlexander V. Chernikov 	}
682*ac35ff17SAlexander V. Chernikov }
683f1220db8SAlexander V. Chernikov 
684f1220db8SAlexander V. Chernikov /*
685f1220db8SAlexander V. Chernikov  * Compare table names.
686f1220db8SAlexander V. Chernikov  * Honor number comparison.
687f1220db8SAlexander V. Chernikov  */
688f1220db8SAlexander V. Chernikov static int
689f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b)
690f1220db8SAlexander V. Chernikov {
691f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *ia, *ib;
692f1220db8SAlexander V. Chernikov 	int la, lb;
693f1220db8SAlexander V. Chernikov 
694f1220db8SAlexander V. Chernikov 	ia = (ipfw_xtable_info *)a;
695f1220db8SAlexander V. Chernikov 	ib = (ipfw_xtable_info *)b;
696f1220db8SAlexander V. Chernikov 	la = strlen(ia->tablename);
697f1220db8SAlexander V. Chernikov 	lb = strlen(ib->tablename);
698f1220db8SAlexander V. Chernikov 
699f1220db8SAlexander V. Chernikov 	if (la > lb)
700f1220db8SAlexander V. Chernikov 		return (1);
701f1220db8SAlexander V. Chernikov 	else if (la < lb)
702f1220db8SAlexander V. Chernikov 		return (-01);
703f1220db8SAlexander V. Chernikov 
704f1220db8SAlexander V. Chernikov 	return (strcmp(ia->tablename, ib->tablename));
705f1220db8SAlexander V. Chernikov }
706f1220db8SAlexander V. Chernikov 
707f1220db8SAlexander V. Chernikov /*
708f1220db8SAlexander V. Chernikov  * Retrieves table list from kernel,
709f1220db8SAlexander V. Chernikov  * optionally sorts it and calls requested function for each table.
710f1220db8SAlexander V. Chernikov  * Returns 0 on success.
711f1220db8SAlexander V. Chernikov  */
712f1220db8SAlexander V. Chernikov static int
713f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort)
714f1220db8SAlexander V. Chernikov {
715f1220db8SAlexander V. Chernikov 	ipfw_obj_lheader req, *olh;
716f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *info;
717f1220db8SAlexander V. Chernikov 	size_t sz;
718f1220db8SAlexander V. Chernikov 	int i, error;
719f1220db8SAlexander V. Chernikov 
720f1220db8SAlexander V. Chernikov 	memset(&req, 0, sizeof(req));
721f1220db8SAlexander V. Chernikov 	sz = sizeof(req);
722f1220db8SAlexander V. Chernikov 
723d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
724f1220db8SAlexander V. Chernikov 		return (errno);
725f1220db8SAlexander V. Chernikov 
726f1220db8SAlexander V. Chernikov 	sz = req.size;
727f1220db8SAlexander V. Chernikov 	if ((olh = calloc(1, sz)) == NULL)
728f1220db8SAlexander V. Chernikov 		return (ENOMEM);
729f1220db8SAlexander V. Chernikov 
730f1220db8SAlexander V. Chernikov 	olh->size = sz;
731d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
732f1220db8SAlexander V. Chernikov 		free(olh);
733f1220db8SAlexander V. Chernikov 		return (errno);
734f1220db8SAlexander V. Chernikov 	}
735f1220db8SAlexander V. Chernikov 
736f1220db8SAlexander V. Chernikov 	if (sort != 0)
737f1220db8SAlexander V. Chernikov 		qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
738f1220db8SAlexander V. Chernikov 
739f1220db8SAlexander V. Chernikov 	info = (ipfw_xtable_info *)(olh + 1);
740f1220db8SAlexander V. Chernikov 	for (i = 0; i < olh->count; i++) {
741f1220db8SAlexander V. Chernikov 		error = f(info, arg); /* Ignore errors for now */
742f1220db8SAlexander V. Chernikov 		info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
743f1220db8SAlexander V. Chernikov 	}
744f1220db8SAlexander V. Chernikov 
745f1220db8SAlexander V. Chernikov 	free(olh);
746f1220db8SAlexander V. Chernikov 
747f1220db8SAlexander V. Chernikov 	return (0);
748f1220db8SAlexander V. Chernikov }
749f1220db8SAlexander V. Chernikov 
750f1220db8SAlexander V. Chernikov /*
751f1220db8SAlexander V. Chernikov  * Retrieves all entries for given table @i in
752d3a4f924SAlexander V. Chernikov  * eXtended format. Assumes buffer of size
753d3a4f924SAlexander V. Chernikov  * @i->size has already been allocated by caller.
754f1220db8SAlexander V. Chernikov  *
755f1220db8SAlexander V. Chernikov  * Returns 0 on success.
756f1220db8SAlexander V. Chernikov  */
757f1220db8SAlexander V. Chernikov static int
758f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
759f1220db8SAlexander V. Chernikov {
760f1220db8SAlexander V. Chernikov 	size_t sz;
761f1220db8SAlexander V. Chernikov 	int error;
762f1220db8SAlexander V. Chernikov 
763f1220db8SAlexander V. Chernikov 	table_fill_objheader(oh, i);
764f1220db8SAlexander V. Chernikov 	sz = i->size;
765f1220db8SAlexander V. Chernikov 
766d3a4f924SAlexander V. Chernikov 	oh->opheader.version = 1; /* Current version */
767d3a4f924SAlexander V. Chernikov 
768d3a4f924SAlexander V. Chernikov 	if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0)
769f1220db8SAlexander V. Chernikov 		return (errno);
770f1220db8SAlexander V. Chernikov 
771f1220db8SAlexander V. Chernikov 	return (0);
772f1220db8SAlexander V. Chernikov }
773f1220db8SAlexander V. Chernikov 
774f1220db8SAlexander V. Chernikov /*
775f1220db8SAlexander V. Chernikov  * Shows all entries from @oh in human-readable format
776f1220db8SAlexander V. Chernikov  */
777f1220db8SAlexander V. Chernikov static void
778f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header)
779f1220db8SAlexander V. Chernikov {
780f1220db8SAlexander V. Chernikov 	ipfw_table_xentry *xent;
781f1220db8SAlexander V. Chernikov 	uint32_t count, tval;
782f1220db8SAlexander V. Chernikov 	char tbuf[128];
783f1220db8SAlexander V. Chernikov 	struct in6_addr *addr6;
784f1220db8SAlexander V. Chernikov 	ipfw_xtable_info *i;
785f1220db8SAlexander V. Chernikov 
786f1220db8SAlexander V. Chernikov 	i = (ipfw_xtable_info *)(oh + 1);
787f1220db8SAlexander V. Chernikov 	xent = (ipfw_table_xentry *)(i + 1);
788f1220db8SAlexander V. Chernikov 
789f1220db8SAlexander V. Chernikov 	if (need_header)
790f1220db8SAlexander V. Chernikov 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
791f1220db8SAlexander V. Chernikov 
792f1220db8SAlexander V. Chernikov 	count = i->count;
793f1220db8SAlexander V. Chernikov 	while (count > 0) {
794f1220db8SAlexander V. Chernikov 		switch (i->type) {
795f1220db8SAlexander V. Chernikov 		case IPFW_TABLE_CIDR:
796f1220db8SAlexander V. Chernikov 			/* IPv4 or IPv6 prefixes */
797f1220db8SAlexander V. Chernikov 			tval = xent->value;
798f1220db8SAlexander V. Chernikov 			addr6 = &xent->k.addr6;
799f1220db8SAlexander V. Chernikov 
800f1220db8SAlexander V. Chernikov 
801f1220db8SAlexander V. Chernikov 			if ((xent->flags & IPFW_TCF_INET) != 0) {
802f1220db8SAlexander V. Chernikov 				/* IPv4 address */
803f1220db8SAlexander V. Chernikov 				inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf,
804f1220db8SAlexander V. Chernikov 				    sizeof(tbuf));
805f1220db8SAlexander V. Chernikov 			} else {
806f1220db8SAlexander V. Chernikov 				/* IPv6 address */
807f1220db8SAlexander V. Chernikov 				inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
808f1220db8SAlexander V. Chernikov 			}
809f1220db8SAlexander V. Chernikov 
810f1220db8SAlexander V. Chernikov 			if (co.do_value_as_ip) {
811f1220db8SAlexander V. Chernikov 				tval = htonl(tval);
812f1220db8SAlexander V. Chernikov 				printf("%s/%u %s\n", tbuf, xent->masklen,
813f1220db8SAlexander V. Chernikov 				    inet_ntoa(*(struct in_addr *)&tval));
814f1220db8SAlexander V. Chernikov 			} else
815f1220db8SAlexander V. Chernikov 				printf("%s/%u %u\n", tbuf, xent->masklen, tval);
816f1220db8SAlexander V. Chernikov 			break;
817f1220db8SAlexander V. Chernikov 		case IPFW_TABLE_INTERFACE:
818f1220db8SAlexander V. Chernikov 			/* Interface names */
819f1220db8SAlexander V. Chernikov 			tval = xent->value;
820f1220db8SAlexander V. Chernikov 			if (co.do_value_as_ip) {
821f1220db8SAlexander V. Chernikov 				tval = htonl(tval);
822f1220db8SAlexander V. Chernikov 				printf("%s %s\n", xent->k.iface,
823f1220db8SAlexander V. Chernikov 				    inet_ntoa(*(struct in_addr *)&tval));
824f1220db8SAlexander V. Chernikov 			} else
825f1220db8SAlexander V. Chernikov 				printf("%s %u\n", xent->k.iface, tval);
826f1220db8SAlexander V. Chernikov 		}
827f1220db8SAlexander V. Chernikov 
828f1220db8SAlexander V. Chernikov 		xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len);
829f1220db8SAlexander V. Chernikov 		count--;
830f1220db8SAlexander V. Chernikov 	}
831f1220db8SAlexander V. Chernikov }
832f1220db8SAlexander V. Chernikov 
8336c2997ffSAlexander V. Chernikov int
8346c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b)
8356c2997ffSAlexander V. Chernikov {
8366c2997ffSAlexander V. Chernikov 	ipfw_obj_ntlv *a, *b;
8376c2997ffSAlexander V. Chernikov 
8386c2997ffSAlexander V. Chernikov 	a = (ipfw_obj_ntlv *)_a;
8396c2997ffSAlexander V. Chernikov 	b = (ipfw_obj_ntlv *)_b;
8406c2997ffSAlexander V. Chernikov 
8416c2997ffSAlexander V. Chernikov 	if (a->set < b->set)
8426c2997ffSAlexander V. Chernikov 		return (-1);
8436c2997ffSAlexander V. Chernikov 	else if (a->set > b->set)
8446c2997ffSAlexander V. Chernikov 		return (1);
8456c2997ffSAlexander V. Chernikov 
8466c2997ffSAlexander V. Chernikov 	if (a->idx < b->idx)
8476c2997ffSAlexander V. Chernikov 		return (-1);
8486c2997ffSAlexander V. Chernikov 	else if (a->idx > b->idx)
8496c2997ffSAlexander V. Chernikov 		return (1);
8506c2997ffSAlexander V. Chernikov 
8516c2997ffSAlexander V. Chernikov 	return (0);
8526c2997ffSAlexander V. Chernikov }
853563b5ab1SAlexander V. Chernikov 
854563b5ab1SAlexander V. Chernikov int
8556c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v)
856563b5ab1SAlexander V. Chernikov {
857563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
858563b5ab1SAlexander V. Chernikov 	uint16_t key;
859563b5ab1SAlexander V. Chernikov 
860563b5ab1SAlexander V. Chernikov 	key = *((uint16_t *)k);
861563b5ab1SAlexander V. Chernikov 	ntlv = (ipfw_obj_ntlv *)v;
862563b5ab1SAlexander V. Chernikov 
863563b5ab1SAlexander V. Chernikov 	if (key < ntlv->idx)
864563b5ab1SAlexander V. Chernikov 		return (-1);
865563b5ab1SAlexander V. Chernikov 	else if (key > ntlv->idx)
866563b5ab1SAlexander V. Chernikov 		return (1);
867563b5ab1SAlexander V. Chernikov 
868563b5ab1SAlexander V. Chernikov 	return (0);
869563b5ab1SAlexander V. Chernikov }
870563b5ab1SAlexander V. Chernikov 
871563b5ab1SAlexander V. Chernikov /*
872563b5ab1SAlexander V. Chernikov  * Finds table name in @ctlv by @idx.
873563b5ab1SAlexander V. Chernikov  * Uses the following facts:
874563b5ab1SAlexander V. Chernikov  * 1) All TLVs are the same size
875563b5ab1SAlexander V. Chernikov  * 2) Kernel implementation provides already sorted list.
876563b5ab1SAlexander V. Chernikov  *
877563b5ab1SAlexander V. Chernikov  * Returns table name or NULL.
878563b5ab1SAlexander V. Chernikov  */
879563b5ab1SAlexander V. Chernikov char *
880563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
881563b5ab1SAlexander V. Chernikov {
882563b5ab1SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
883563b5ab1SAlexander V. Chernikov 
884563b5ab1SAlexander V. Chernikov 	ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
8856c2997ffSAlexander V. Chernikov 	    compare_kntlv);
886563b5ab1SAlexander V. Chernikov 
887563b5ab1SAlexander V. Chernikov 	if (ntlv != 0)
888563b5ab1SAlexander V. Chernikov 		return (ntlv->name);
889563b5ab1SAlexander V. Chernikov 
890563b5ab1SAlexander V. Chernikov 	return (NULL);
891563b5ab1SAlexander V. Chernikov }
892563b5ab1SAlexander V. Chernikov 
8936c2997ffSAlexander V. Chernikov void
8946c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv)
8956c2997ffSAlexander V. Chernikov {
8966c2997ffSAlexander V. Chernikov 
8976c2997ffSAlexander V. Chernikov 	qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
8986c2997ffSAlexander V. Chernikov }
8996c2997ffSAlexander V. Chernikov 
9006c2997ffSAlexander V. Chernikov int
9016c2997ffSAlexander V. Chernikov table_check_name(char *tablename)
9026c2997ffSAlexander V. Chernikov {
9036c2997ffSAlexander V. Chernikov 	int c, i, l;
9046c2997ffSAlexander V. Chernikov 
9056c2997ffSAlexander V. Chernikov 	/*
9066c2997ffSAlexander V. Chernikov 	 * Check if tablename is null-terminated and contains
9076c2997ffSAlexander V. Chernikov 	 * valid symbols only. Valid mask is:
908*ac35ff17SAlexander V. Chernikov 	 * [a-zA-Z0-9\-_\.]{1,63}
9096c2997ffSAlexander V. Chernikov 	 */
9106c2997ffSAlexander V. Chernikov 	l = strlen(tablename);
9116c2997ffSAlexander V. Chernikov 	if (l == 0 || l >= 64)
9126c2997ffSAlexander V. Chernikov 		return (EINVAL);
9136c2997ffSAlexander V. Chernikov 	for (i = 0; i < l; i++) {
9146c2997ffSAlexander V. Chernikov 		c = tablename[i];
9156c2997ffSAlexander V. Chernikov 		if (isalpha(c) || isdigit(c) || c == '_' ||
9166c2997ffSAlexander V. Chernikov 		    c == '-' || c == '.')
9176c2997ffSAlexander V. Chernikov 			continue;
9186c2997ffSAlexander V. Chernikov 		return (EINVAL);
9196c2997ffSAlexander V. Chernikov 	}
9206c2997ffSAlexander V. Chernikov 
921*ac35ff17SAlexander V. Chernikov 	/* Restrict some 'special' names */
922*ac35ff17SAlexander V. Chernikov 	if (strcmp(tablename, "all") == 0)
923*ac35ff17SAlexander V. Chernikov 		return (EINVAL);
924*ac35ff17SAlexander V. Chernikov 
9256c2997ffSAlexander V. Chernikov 	return (0);
9266c2997ffSAlexander V. Chernikov }
9276c2997ffSAlexander V. Chernikov 
928