tables.c revision 344668
1/*
2 * Copyright (c) 2014 Yandex LLC
3 * Copyright (c) 2014 Alexander V. Chernikov
4 *
5 * Redistribution and use in source forms, with and without modification,
6 * are permitted provided that this entire comment appears intact.
7 *
8 * Redistribution in binary form may occur without any restrictions.
9 * Obviously, it would be nice if you gave credit where credit is due
10 * but requiring it would be too onerous.
11 *
12 * This software is provided ``AS IS'' without any warranties of any kind.
13 *
14 * in-kernel ipfw tables support.
15 *
16 * $FreeBSD: stable/11/sbin/ipfw/tables.c 344668 2019-02-28 20:57:41Z bdrewery $
17 */
18
19
20#include <sys/types.h>
21#include <sys/param.h>
22#include <sys/socket.h>
23#include <sys/sysctl.h>
24
25#include <ctype.h>
26#include <err.h>
27#include <errno.h>
28#include <netdb.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sysexits.h>
33
34#include <net/if.h>
35#include <netinet/in.h>
36#include <netinet/ip_fw.h>
37#include <arpa/inet.h>
38#include <netdb.h>
39
40#include "ipfw2.h"
41
42static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
43    int add, int quiet, int update, int atomic);
44static int table_flush(ipfw_obj_header *oh);
45static int table_destroy(ipfw_obj_header *oh);
46static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
47static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i);
48static int table_do_swap(ipfw_obj_header *oh, char *second);
49static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
50static void table_modify(ipfw_obj_header *oh, int ac, char *av[]);
51static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
52static void table_lock(ipfw_obj_header *oh, int lock);
53static int table_swap(ipfw_obj_header *oh, char *second);
54static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
55static int table_show_info(ipfw_xtable_info *i, void *arg);
56
57static int table_destroy_one(ipfw_xtable_info *i, void *arg);
58static int table_flush_one(ipfw_xtable_info *i, void *arg);
59static int table_show_one(ipfw_xtable_info *i, void *arg);
60static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh);
61static void table_show_list(ipfw_obj_header *oh, int need_header);
62static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
63
64static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
65    char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi);
66static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
67    char *arg, uint8_t type, uint32_t vmask);
68static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
69    uint32_t vmask, int print_ip);
70
71typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
72static int tables_foreach(table_cb_t *f, void *arg, int sort);
73
74#ifndef s6_addr32
75#define s6_addr32 __u6_addr.__u6_addr32
76#endif
77
78static struct _s_x tabletypes[] = {
79      { "addr",		IPFW_TABLE_ADDR },
80      { "iface",	IPFW_TABLE_INTERFACE },
81      { "number",	IPFW_TABLE_NUMBER },
82      { "flow",		IPFW_TABLE_FLOW },
83      { NULL, 0 }
84};
85
86static struct _s_x tablevaltypes[] = {
87      { "skipto",	IPFW_VTYPE_SKIPTO },
88      { "pipe",		IPFW_VTYPE_PIPE },
89      { "fib",		IPFW_VTYPE_FIB },
90      { "nat",		IPFW_VTYPE_NAT },
91      { "dscp",		IPFW_VTYPE_DSCP },
92      { "tag",		IPFW_VTYPE_TAG },
93      { "divert",	IPFW_VTYPE_DIVERT },
94      { "netgraph",	IPFW_VTYPE_NETGRAPH },
95      { "limit",	IPFW_VTYPE_LIMIT },
96      { "ipv4",		IPFW_VTYPE_NH4 },
97      { "ipv6",		IPFW_VTYPE_NH6 },
98      { NULL, 0 }
99};
100
101static struct _s_x tablecmds[] = {
102      { "add",		TOK_ADD },
103      { "delete",	TOK_DEL },
104      { "create",	TOK_CREATE },
105      { "destroy",	TOK_DESTROY },
106      { "flush",	TOK_FLUSH },
107      { "modify",	TOK_MODIFY },
108      { "swap",		TOK_SWAP },
109      { "info",		TOK_INFO },
110      { "detail",	TOK_DETAIL },
111      { "list",		TOK_LIST },
112      { "lookup",	TOK_LOOKUP },
113      { "atomic",	TOK_ATOMIC },
114      { "lock",		TOK_LOCK },
115      { "unlock",	TOK_UNLOCK },
116      { NULL, 0 }
117};
118
119static int
120lookup_host (char *host, struct in_addr *ipaddr)
121{
122	struct hostent *he;
123
124	if (!inet_aton(host, ipaddr)) {
125		if ((he = gethostbyname(host)) == NULL)
126			return(-1);
127		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
128	}
129	return(0);
130}
131
132/*
133 * This one handles all table-related commands
134 * 	ipfw table NAME create ...
135 * 	ipfw table NAME modify ...
136 * 	ipfw table {NAME | all} destroy
137 * 	ipfw table NAME swap NAME
138 * 	ipfw table NAME lock
139 * 	ipfw table NAME unlock
140 * 	ipfw table NAME add addr[/masklen] [value]
141 * 	ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] ..
142 * 	ipfw table NAME delete addr[/masklen] [addr[/masklen]] ..
143 * 	ipfw table NAME lookup addr
144 * 	ipfw table {NAME | all} flush
145 * 	ipfw table {NAME | all} list
146 * 	ipfw table {NAME | all} info
147 * 	ipfw table {NAME | all} detail
148 */
149void
150ipfw_table_handler(int ac, char *av[])
151{
152	int do_add, is_all;
153	int atomic, error, tcmd;
154	ipfw_xtable_info i;
155	ipfw_obj_header oh;
156	char *tablename;
157	uint8_t set;
158	void *arg;
159
160	memset(&oh, 0, sizeof(oh));
161	is_all = 0;
162	if (co.use_set != 0)
163		set = co.use_set - 1;
164	else
165		set = 0;
166
167	ac--; av++;
168	NEED1("table needs name");
169	tablename = *av;
170
171	if (table_check_name(tablename) == 0) {
172		table_fill_ntlv(&oh.ntlv, *av, set, 1);
173		oh.idx = 1;
174	} else {
175		if (strcmp(tablename, "all") == 0)
176			is_all = 1;
177		else
178			errx(EX_USAGE, "table name %s is invalid", tablename);
179	}
180	ac--; av++;
181	NEED1("table needs command");
182
183	tcmd = get_token(tablecmds, *av, "table command");
184	/* Check if atomic operation was requested */
185	atomic = 0;
186	if (tcmd == TOK_ATOMIC) {
187		ac--; av++;
188		NEED1("atomic needs command");
189		tcmd = get_token(tablecmds, *av, "table command");
190		switch (tcmd) {
191		case TOK_ADD:
192			break;
193		default:
194			errx(EX_USAGE, "atomic is not compatible with %s", *av);
195		}
196		atomic = 1;
197	}
198
199	switch (tcmd) {
200	case TOK_LIST:
201	case TOK_INFO:
202	case TOK_DETAIL:
203	case TOK_FLUSH:
204	case TOK_DESTROY:
205		break;
206	default:
207		if (is_all != 0)
208			errx(EX_USAGE, "table name required");
209	}
210
211	switch (tcmd) {
212	case TOK_ADD:
213	case TOK_DEL:
214		do_add = **av == 'a';
215		ac--; av++;
216		table_modify_record(&oh, ac, av, do_add, co.do_quiet,
217		    co.do_quiet, atomic);
218		break;
219	case TOK_CREATE:
220		ac--; av++;
221		table_create(&oh, ac, av);
222		break;
223	case TOK_MODIFY:
224		ac--; av++;
225		table_modify(&oh, ac, av);
226		break;
227	case TOK_DESTROY:
228		if (is_all == 0) {
229			if (table_destroy(&oh) == 0)
230				break;
231			if (errno != ESRCH)
232				err(EX_OSERR, "failed to destroy table %s",
233				    tablename);
234			/* ESRCH isn't fatal, warn if not quiet mode */
235			if (co.do_quiet == 0)
236				warn("failed to destroy table %s", tablename);
237		} else {
238			error = tables_foreach(table_destroy_one, &oh, 1);
239			if (error != 0)
240				err(EX_OSERR,
241				    "failed to destroy tables list");
242		}
243		break;
244	case TOK_FLUSH:
245		if (is_all == 0) {
246			if ((error = table_flush(&oh)) == 0)
247				break;
248			if (errno != ESRCH)
249				err(EX_OSERR, "failed to flush table %s info",
250				    tablename);
251			/* ESRCH isn't fatal, warn if not quiet mode */
252			if (co.do_quiet == 0)
253				warn("failed to flush table %s info",
254				    tablename);
255		} else {
256			error = tables_foreach(table_flush_one, &oh, 1);
257			if (error != 0)
258				err(EX_OSERR, "failed to flush tables list");
259			/* XXX: we ignore errors here */
260		}
261		break;
262	case TOK_SWAP:
263		ac--; av++;
264		NEED1("second table name required");
265		table_swap(&oh, *av);
266		break;
267	case TOK_LOCK:
268	case TOK_UNLOCK:
269		table_lock(&oh, (tcmd == TOK_LOCK));
270		break;
271	case TOK_DETAIL:
272	case TOK_INFO:
273		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
274		if (is_all == 0) {
275			if ((error = table_get_info(&oh, &i)) != 0)
276				err(EX_OSERR, "failed to request table info");
277			table_show_info(&i, arg);
278		} else {
279			error = tables_foreach(table_show_info, arg, 1);
280			if (error != 0)
281				err(EX_OSERR, "failed to request tables list");
282		}
283		break;
284	case TOK_LIST:
285		arg = is_all ? (void*)1 : NULL;
286		if (is_all == 0) {
287			ipfw_xtable_info i;
288			if ((error = table_get_info(&oh, &i)) != 0)
289				err(EX_OSERR, "failed to request table info");
290			table_show_one(&i, arg);
291		} else {
292			error = tables_foreach(table_show_one, arg, 1);
293			if (error != 0)
294				err(EX_OSERR, "failed to request tables list");
295		}
296		break;
297	case TOK_LOOKUP:
298		ac--; av++;
299		table_lookup(&oh, ac, av);
300		break;
301	}
302}
303
304void
305table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set,
306    uint16_t uidx)
307{
308
309	ntlv->head.type = IPFW_TLV_TBL_NAME;
310	ntlv->head.length = sizeof(ipfw_obj_ntlv);
311	ntlv->idx = uidx;
312	ntlv->set = set;
313	strlcpy(ntlv->name, name, sizeof(ntlv->name));
314}
315
316static void
317table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
318{
319
320	oh->idx = 1;
321	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
322}
323
324static struct _s_x tablenewcmds[] = {
325      { "type",		TOK_TYPE },
326      { "valtype",	TOK_VALTYPE },
327      { "algo",		TOK_ALGO },
328      { "limit",	TOK_LIMIT },
329      { "locked",	TOK_LOCK },
330      { NULL, 0 }
331};
332
333static struct _s_x flowtypecmds[] = {
334      { "src-ip",	IPFW_TFFLAG_SRCIP },
335      { "proto",	IPFW_TFFLAG_PROTO },
336      { "src-port",	IPFW_TFFLAG_SRCPORT },
337      { "dst-ip",	IPFW_TFFLAG_DSTIP },
338      { "dst-port",	IPFW_TFFLAG_DSTPORT },
339      { NULL, 0 }
340};
341
342int
343table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
344{
345	uint32_t fset, fclear;
346	char *e;
347
348	/* Parse type options */
349	switch(ttype) {
350	case IPFW_TABLE_FLOW:
351		fset = fclear = 0;
352		if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0)
353			errx(EX_USAGE,
354			    "unable to parse flow option %s", e);
355		*tflags = fset;
356		break;
357	default:
358		return (EX_USAGE);
359	}
360
361	return (0);
362}
363
364void
365table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
366{
367	const char *tname;
368	int l;
369
370	if ((tname = match_value(tabletypes, type)) == NULL)
371		tname = "unknown";
372
373	l = snprintf(tbuf, size, "%s", tname);
374	tbuf += l;
375	size -= l;
376
377	switch(type) {
378	case IPFW_TABLE_FLOW:
379		if (tflags != 0) {
380			*tbuf++ = ':';
381			l--;
382			print_flags_buffer(tbuf, size, flowtypecmds, tflags);
383		}
384		break;
385	}
386}
387
388/*
389 * Creates new table
390 *
391 * ipfw table NAME create [ type { addr | iface | number | flow } ]
392 *     [ algo algoname ]
393 */
394static void
395table_create(ipfw_obj_header *oh, int ac, char *av[])
396{
397	ipfw_xtable_info xi;
398	int error, tcmd, val;
399	uint32_t fset, fclear;
400	char *e, *p;
401	char tbuf[128];
402
403	memset(&xi, 0, sizeof(xi));
404
405	while (ac > 0) {
406		tcmd = get_token(tablenewcmds, *av, "option");
407		ac--; av++;
408
409		switch (tcmd) {
410		case TOK_LIMIT:
411			NEED1("limit value required");
412			xi.limit = strtol(*av, NULL, 10);
413			ac--; av++;
414			break;
415		case TOK_TYPE:
416			NEED1("table type required");
417			/* Type may have suboptions after ':' */
418			if ((p = strchr(*av, ':')) != NULL)
419				*p++ = '\0';
420			val = match_token(tabletypes, *av);
421			if (val == -1) {
422				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
423				    ", ");
424				errx(EX_USAGE,
425				    "Unknown tabletype: %s. Supported: %s",
426				    *av, tbuf);
427			}
428			xi.type = val;
429			if (p != NULL) {
430				error = table_parse_type(val, p, &xi.tflags);
431				if (error != 0)
432					errx(EX_USAGE,
433					    "Unsupported suboptions: %s", p);
434			}
435			ac--; av++;
436			break;
437		case TOK_VALTYPE:
438			NEED1("table value type required");
439			fset = fclear = 0;
440			val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear);
441			if (val != -1) {
442				xi.vmask = fset;
443				ac--; av++;
444				break;
445			}
446			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
447			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
448			    e, tbuf);
449			break;
450		case TOK_ALGO:
451			NEED1("table algorithm name required");
452			if (strlen(*av) > sizeof(xi.algoname))
453				errx(EX_USAGE, "algorithm name too long");
454			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
455			ac--; av++;
456			break;
457		case TOK_LOCK:
458			xi.flags |= IPFW_TGFLAGS_LOCKED;
459			break;
460		}
461	}
462
463	/* Set some defaults to preserve compatibility. */
464	if (xi.algoname[0] == '\0' && xi.type == 0)
465		xi.type = IPFW_TABLE_ADDR;
466	if (xi.vmask == 0)
467		xi.vmask = IPFW_VTYPE_LEGACY;
468
469	if ((error = table_do_create(oh, &xi)) != 0)
470		err(EX_OSERR, "Table creation failed");
471}
472
473/*
474 * Creates new table
475 *
476 * Request: [ ipfw_obj_header ipfw_xtable_info ]
477 *
478 * Returns 0 on success.
479 */
480static int
481table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
482{
483	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
484	int error;
485
486	memcpy(tbuf, oh, sizeof(*oh));
487	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
488	oh = (ipfw_obj_header *)tbuf;
489
490	error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
491
492	return (error);
493}
494
495/*
496 * Modifies existing table
497 *
498 * ipfw table NAME modify [ limit number ]
499 */
500static void
501table_modify(ipfw_obj_header *oh, int ac, char *av[])
502{
503	ipfw_xtable_info xi;
504	int tcmd;
505
506	memset(&xi, 0, sizeof(xi));
507
508	while (ac > 0) {
509		tcmd = get_token(tablenewcmds, *av, "option");
510		ac--; av++;
511
512		switch (tcmd) {
513		case TOK_LIMIT:
514			NEED1("limit value required");
515			xi.limit = strtol(*av, NULL, 10);
516			xi.mflags |= IPFW_TMFLAGS_LIMIT;
517			ac--; av++;
518			break;
519		default:
520			errx(EX_USAGE, "cmd is not supported for modificatiob");
521		}
522	}
523
524	if (table_do_modify(oh, &xi) != 0)
525		err(EX_OSERR, "Table modification failed");
526}
527
528/*
529 * Modifies existing table.
530 *
531 * Request: [ ipfw_obj_header ipfw_xtable_info ]
532 *
533 * Returns 0 on success.
534 */
535static int
536table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
537{
538	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
539	int error;
540
541	memcpy(tbuf, oh, sizeof(*oh));
542	memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
543	oh = (ipfw_obj_header *)tbuf;
544
545	error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
546
547	return (error);
548}
549
550/*
551 * Locks or unlocks given table
552 */
553static void
554table_lock(ipfw_obj_header *oh, int lock)
555{
556	ipfw_xtable_info xi;
557
558	memset(&xi, 0, sizeof(xi));
559
560	xi.mflags |= IPFW_TMFLAGS_LOCK;
561	xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0;
562
563	if (table_do_modify(oh, &xi) != 0)
564		err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock");
565}
566
567/*
568 * Destroys given table specified by @oh->ntlv.
569 * Returns 0 on success.
570 */
571static int
572table_destroy(ipfw_obj_header *oh)
573{
574
575	if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
576		return (-1);
577
578	return (0);
579}
580
581static int
582table_destroy_one(ipfw_xtable_info *i, void *arg)
583{
584	ipfw_obj_header *oh;
585
586	oh = (ipfw_obj_header *)arg;
587	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
588	if (table_destroy(oh) != 0) {
589		if (co.do_quiet == 0)
590			warn("failed to destroy table(%s) in set %u",
591			    i->tablename, i->set);
592		return (-1);
593	}
594	return (0);
595}
596
597/*
598 * Flushes given table specified by @oh->ntlv.
599 * Returns 0 on success.
600 */
601static int
602table_flush(ipfw_obj_header *oh)
603{
604
605	if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
606		return (-1);
607
608	return (0);
609}
610
611static int
612table_do_swap(ipfw_obj_header *oh, char *second)
613{
614	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
615	int error;
616
617	memset(tbuf, 0, sizeof(tbuf));
618	memcpy(tbuf, oh, sizeof(*oh));
619	oh = (ipfw_obj_header *)tbuf;
620	table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
621
622	error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
623
624	return (error);
625}
626
627/*
628 * Swaps given table with @second one.
629 */
630static int
631table_swap(ipfw_obj_header *oh, char *second)
632{
633
634	if (table_check_name(second) != 0)
635		errx(EX_USAGE, "table name %s is invalid", second);
636
637	if (table_do_swap(oh, second) == 0)
638		return (0);
639
640	switch (errno) {
641	case EINVAL:
642		errx(EX_USAGE, "Unable to swap table: check types");
643	case EFBIG:
644		errx(EX_USAGE, "Unable to swap table: check limits");
645	}
646
647	return (0);
648}
649
650
651/*
652 * Retrieves table in given table specified by @oh->ntlv.
653 * it inside @i.
654 * Returns 0 on success.
655 */
656static int
657table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
658{
659	char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
660	size_t sz;
661
662	sz = sizeof(tbuf);
663	memset(tbuf, 0, sizeof(tbuf));
664	memcpy(tbuf, oh, sizeof(*oh));
665	oh = (ipfw_obj_header *)tbuf;
666
667	if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0)
668		return (errno);
669
670	if (sz < sizeof(tbuf))
671		return (EINVAL);
672
673	*i = *(ipfw_xtable_info *)(oh + 1);
674
675	return (0);
676}
677
678static struct _s_x tablealgoclass[] = {
679      { "hash",		IPFW_TACLASS_HASH },
680      { "array",	IPFW_TACLASS_ARRAY },
681      { "radix",	IPFW_TACLASS_RADIX },
682      { NULL, 0 }
683};
684
685struct ta_cldata {
686	uint8_t		taclass;
687	uint8_t		spare4;
688	uint16_t	itemsize;
689	uint16_t	itemsize6;
690	uint32_t	size;
691	uint32_t	count;
692};
693
694/*
695 * Print global/per-AF table @i algorithm info.
696 */
697static void
698table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
699    const char *af, const char *taclass)
700{
701
702	switch (d->taclass) {
703	case IPFW_TACLASS_HASH:
704	case IPFW_TACLASS_ARRAY:
705		printf(" %salgorithm %s info\n", af, taclass);
706		if (d->itemsize == d->itemsize6)
707			printf("  size: %u items: %u itemsize: %u\n",
708			    d->size, d->count, d->itemsize);
709		else
710			printf("  size: %u items: %u "
711			    "itemsize4: %u itemsize6: %u\n",
712			    d->size, d->count,
713			    d->itemsize, d->itemsize6);
714		break;
715	case IPFW_TACLASS_RADIX:
716		printf(" %salgorithm %s info\n", af, taclass);
717		if (d->itemsize == d->itemsize6)
718			printf("  items: %u itemsize: %u\n",
719			    d->count, d->itemsize);
720		else
721			printf("  items: %u "
722			    "itemsize4: %u itemsize6: %u\n",
723			    d->count, d->itemsize, d->itemsize6);
724		break;
725	default:
726		printf(" algo class: %s\n", taclass);
727	}
728}
729
730static void
731table_print_valheader(char *buf, size_t bufsize, uint32_t vmask)
732{
733
734	if (vmask == IPFW_VTYPE_LEGACY) {
735		snprintf(buf, bufsize, "legacy");
736		return;
737	}
738
739	memset(buf, 0, bufsize);
740	print_flags_buffer(buf, bufsize, tablevaltypes, vmask);
741}
742
743/*
744 * Prints table info struct @i in human-readable form.
745 */
746static int
747table_show_info(ipfw_xtable_info *i, void *arg)
748{
749	const char *vtype;
750	ipfw_ta_tinfo *tainfo;
751	int afdata, afitem;
752	struct ta_cldata d;
753	char ttype[64], tvtype[64];
754
755	table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
756	table_print_valheader(tvtype, sizeof(tvtype), i->vmask);
757
758	printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
759	if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
760		printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
761	else
762		printf(" kindex: %d, type: %s\n", i->kidx, ttype);
763	printf(" references: %u, valtype: %s\n", i->refcnt, tvtype);
764	printf(" algorithm: %s\n", i->algoname);
765	printf(" items: %u, size: %u\n", i->count, i->size);
766	if (i->limit > 0)
767		printf(" limit: %u\n", i->limit);
768
769	/* Print algo-specific info if requested & set  */
770	if (arg == NULL)
771		return (0);
772
773	if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
774		return (0);
775	tainfo = &i->ta_info;
776
777	afdata = 0;
778	afitem = 0;
779	if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
780		afdata = 1;
781	if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
782		afitem = 1;
783
784	memset(&d, 0, sizeof(d));
785	d.taclass = tainfo->taclass4;
786	d.size = tainfo->size4;
787	d.count = tainfo->count4;
788	d.itemsize = tainfo->itemsize4;
789	if (afdata == 0 && afitem != 0)
790		d.itemsize6 = tainfo->itemsize6;
791	else
792		d.itemsize6 = d.itemsize;
793	if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
794		vtype = "unknown";
795
796	if (afdata == 0) {
797		table_show_tainfo(i, &d, "", vtype);
798	} else {
799		table_show_tainfo(i, &d, "IPv4 ", vtype);
800		memset(&d, 0, sizeof(d));
801		d.taclass = tainfo->taclass6;
802		if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
803			vtype = "unknown";
804		d.size = tainfo->size6;
805		d.count = tainfo->count6;
806		d.itemsize = tainfo->itemsize6;
807		d.itemsize6 = d.itemsize;
808		table_show_tainfo(i, &d, "IPv6 ", vtype);
809	}
810
811	return (0);
812}
813
814
815/*
816 * Function wrappers which can be used either
817 * as is or as foreach function parameter.
818 */
819
820static int
821table_show_one(ipfw_xtable_info *i, void *arg)
822{
823	ipfw_obj_header *oh;
824	int error;
825	int is_all;
826
827	is_all = arg == NULL ? 0 : 1;
828
829	if ((error = table_do_get_list(i, &oh)) != 0) {
830		err(EX_OSERR, "Error requesting table %s list", i->tablename);
831		return (error);
832	}
833
834	table_show_list(oh, is_all);
835
836	free(oh);
837	return (0);
838}
839
840static int
841table_flush_one(ipfw_xtable_info *i, void *arg)
842{
843	ipfw_obj_header *oh;
844
845	oh = (ipfw_obj_header *)arg;
846
847	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
848
849	return (table_flush(oh));
850}
851
852static int
853table_do_modify_record(int cmd, ipfw_obj_header *oh,
854    ipfw_obj_tentry *tent, int count, int atomic)
855{
856	ipfw_obj_ctlv *ctlv;
857	ipfw_obj_tentry *tent_base;
858	caddr_t pbuf;
859	char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
860	int error, i;
861	size_t sz;
862
863	sz = sizeof(*ctlv) + sizeof(*tent) * count;
864	if (count == 1) {
865		memset(xbuf, 0, sizeof(xbuf));
866		pbuf = xbuf;
867	} else {
868		if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL)
869			return (ENOMEM);
870	}
871
872	memcpy(pbuf, oh, sizeof(*oh));
873	oh = (ipfw_obj_header *)pbuf;
874	oh->opheader.version = 1;
875
876	ctlv = (ipfw_obj_ctlv *)(oh + 1);
877	ctlv->count = count;
878	ctlv->head.length = sz;
879	if (atomic != 0)
880		ctlv->flags |= IPFW_CTF_ATOMIC;
881
882	tent_base = tent;
883	memcpy(ctlv + 1, tent, sizeof(*tent) * count);
884	tent = (ipfw_obj_tentry *)(ctlv + 1);
885	for (i = 0; i < count; i++, tent++) {
886		tent->head.length = sizeof(ipfw_obj_tentry);
887		tent->idx = oh->idx;
888	}
889
890	sz += sizeof(*oh);
891	error = do_get3(cmd, &oh->opheader, &sz);
892	if (error != 0)
893		error = errno;
894	tent = (ipfw_obj_tentry *)(ctlv + 1);
895	/* Copy result back to provided buffer */
896	memcpy(tent_base, ctlv + 1, sizeof(*tent) * count);
897
898	if (pbuf != xbuf)
899		free(pbuf);
900
901	return (error);
902}
903
904static void
905table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add,
906    int quiet, int update, int atomic)
907{
908	ipfw_obj_tentry *ptent, tent, *tent_buf;
909	ipfw_xtable_info xi;
910	uint8_t type;
911	uint32_t vmask;
912	int cmd, count, error, i, ignored;
913	char *texterr, *etxt, *px;
914
915	if (ac == 0)
916		errx(EX_USAGE, "address required");
917
918	if (add != 0) {
919		cmd = IP_FW_TABLE_XADD;
920		texterr = "Adding record failed";
921	} else {
922		cmd = IP_FW_TABLE_XDEL;
923		texterr = "Deleting record failed";
924	}
925
926	/*
927	 * Calculate number of entries:
928	 * Assume [key val] x N for add
929	 * and
930	 * key x N for delete
931	 */
932	count = (add != 0) ? ac / 2 + 1 : ac;
933
934	if (count <= 1) {
935		/* Adding single entry with/without value */
936		memset(&tent, 0, sizeof(tent));
937		tent_buf = &tent;
938	} else {
939
940		if ((tent_buf = calloc(count, sizeof(tent))) == NULL)
941			errx(EX_OSERR,
942			    "Unable to allocate memory for all entries");
943	}
944	ptent = tent_buf;
945
946	memset(&xi, 0, sizeof(xi));
947	count = 0;
948	while (ac > 0) {
949		tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi);
950
951		/*
952		 * Compatibility layer: auto-create table if not exists.
953		 */
954		if (xi.tablename[0] == '\0') {
955			xi.type = type;
956			xi.vmask = vmask;
957			strlcpy(xi.tablename, oh->ntlv.name,
958			    sizeof(xi.tablename));
959			if (quiet == 0)
960				warnx("DEPRECATED: inserting data into "
961				    "non-existent table %s. (auto-created)",
962				    xi.tablename);
963			table_do_create(oh, &xi);
964		}
965
966		oh->ntlv.type = type;
967		ac--; av++;
968
969		if (add != 0 && ac > 0) {
970			tentry_fill_value(oh, ptent, *av, type, vmask);
971			ac--; av++;
972		}
973
974		if (update != 0)
975			ptent->head.flags |= IPFW_TF_UPDATE;
976
977		count++;
978		ptent++;
979	}
980
981	error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
982
983	/*
984	 * Compatibility stuff: do not yell on duplicate keys or
985	 * failed deletions.
986	 */
987	if (error == 0 || (error == EEXIST && add != 0) ||
988	    (error == ENOENT && add == 0)) {
989		if (quiet != 0) {
990			if (tent_buf != &tent)
991				free(tent_buf);
992			return;
993		}
994	}
995
996	/* Report results back */
997	ptent = tent_buf;
998	for (i = 0; i < count; ptent++, i++) {
999		ignored = 0;
1000		switch (ptent->result) {
1001		case IPFW_TR_ADDED:
1002			px = "added";
1003			break;
1004		case IPFW_TR_DELETED:
1005			px = "deleted";
1006			break;
1007		case IPFW_TR_UPDATED:
1008			px = "updated";
1009			break;
1010		case IPFW_TR_LIMIT:
1011			px = "limit";
1012			ignored = 1;
1013			break;
1014		case IPFW_TR_ERROR:
1015			px = "error";
1016			ignored = 1;
1017			break;
1018		case IPFW_TR_NOTFOUND:
1019			px = "notfound";
1020			ignored = 1;
1021			break;
1022		case IPFW_TR_EXISTS:
1023			px = "exists";
1024			ignored = 1;
1025			break;
1026		case IPFW_TR_IGNORED:
1027			px = "ignored";
1028			ignored = 1;
1029			break;
1030		default:
1031			px = "unknown";
1032			ignored = 1;
1033		}
1034
1035		if (error != 0 && atomic != 0 && ignored == 0)
1036			printf("%s(reverted): ", px);
1037		else
1038			printf("%s: ", px);
1039
1040		table_show_entry(&xi, ptent);
1041	}
1042
1043	if (tent_buf != &tent)
1044		free(tent_buf);
1045
1046	if (error == 0)
1047		return;
1048	/* Get real OS error */
1049	error = errno;
1050
1051	/* Try to provide more human-readable error */
1052	switch (error) {
1053	case EEXIST:
1054		etxt = "record already exists";
1055		break;
1056	case EFBIG:
1057		etxt = "limit hit";
1058		break;
1059	case ESRCH:
1060		etxt = "table not found";
1061		break;
1062	case ENOENT:
1063		etxt = "record not found";
1064		break;
1065	case EACCES:
1066		etxt = "table is locked";
1067		break;
1068	default:
1069		etxt = strerror(error);
1070	}
1071
1072	errx(EX_OSERR, "%s: %s", texterr, etxt);
1073}
1074
1075static int
1076table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
1077    ipfw_obj_tentry *xtent)
1078{
1079	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
1080	ipfw_obj_tentry *tent;
1081	uint8_t type;
1082	uint32_t vmask;
1083	size_t sz;
1084
1085	memcpy(xbuf, oh, sizeof(*oh));
1086	oh = (ipfw_obj_header *)xbuf;
1087	tent = (ipfw_obj_tentry *)(oh + 1);
1088
1089	memset(tent, 0, sizeof(*tent));
1090	tent->head.length = sizeof(*tent);
1091	tent->idx = 1;
1092
1093	tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi);
1094	oh->ntlv.type = type;
1095
1096	sz = sizeof(xbuf);
1097	if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0)
1098		return (errno);
1099
1100	if (sz < sizeof(xbuf))
1101		return (EINVAL);
1102
1103	*xtent = *tent;
1104
1105	return (0);
1106}
1107
1108static void
1109table_lookup(ipfw_obj_header *oh, int ac, char *av[])
1110{
1111	ipfw_obj_tentry xtent;
1112	ipfw_xtable_info xi;
1113	char key[64];
1114	int error;
1115
1116	if (ac == 0)
1117		errx(EX_USAGE, "address required");
1118
1119	strlcpy(key, *av, sizeof(key));
1120
1121	memset(&xi, 0, sizeof(xi));
1122	error = table_do_lookup(oh, key, &xi, &xtent);
1123
1124	switch (error) {
1125	case 0:
1126		break;
1127	case ESRCH:
1128		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
1129	case ENOENT:
1130		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
1131	case ENOTSUP:
1132		errx(EX_UNAVAILABLE, "Table %s algo does not support "
1133		    "\"lookup\" method", oh->ntlv.name);
1134	default:
1135		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
1136	}
1137
1138	table_show_entry(&xi, &xtent);
1139}
1140
1141static void
1142tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
1143    uint8_t tflags)
1144{
1145	char *p, *pp;
1146	int mask, af;
1147	struct in6_addr *paddr, tmp;
1148	struct tflow_entry *tfe;
1149	uint32_t key, *pkey;
1150	uint16_t port;
1151	struct protoent *pent;
1152	struct servent *sent;
1153	int masklen;
1154
1155	masklen = 0;
1156	af = 0;
1157	paddr = (struct in6_addr *)&tentry->k;
1158
1159	switch (type) {
1160	case IPFW_TABLE_ADDR:
1161		/* Remove / if exists */
1162		if ((p = strchr(arg, '/')) != NULL) {
1163			*p = '\0';
1164			mask = atoi(p + 1);
1165		}
1166
1167		if (inet_pton(AF_INET, arg, paddr) == 1) {
1168			if (p != NULL && mask > 32)
1169				errx(EX_DATAERR, "bad IPv4 mask width: %s",
1170				    p + 1);
1171
1172			masklen = p ? mask : 32;
1173			af = AF_INET;
1174		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
1175			if (IN6_IS_ADDR_V4COMPAT(paddr))
1176				errx(EX_DATAERR,
1177				    "Use IPv4 instead of v4-compatible");
1178			if (p != NULL && mask > 128)
1179				errx(EX_DATAERR, "bad IPv6 mask width: %s",
1180				    p + 1);
1181
1182			masklen = p ? mask : 128;
1183			af = AF_INET6;
1184		} else {
1185			/* Assume FQDN */
1186			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
1187				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
1188
1189			masklen = 32;
1190			type = IPFW_TABLE_ADDR;
1191			af = AF_INET;
1192		}
1193		break;
1194	case IPFW_TABLE_INTERFACE:
1195		/* Assume interface name. Copy significant data only */
1196		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
1197		memcpy(paddr, arg, mask);
1198		/* Set mask to exact match */
1199		masklen = 8 * IF_NAMESIZE;
1200		break;
1201	case IPFW_TABLE_NUMBER:
1202		/* Port or any other key */
1203		key = strtol(arg, &p, 10);
1204		if (*p != '\0')
1205			errx(EX_DATAERR, "Invalid number: %s", arg);
1206
1207		pkey = (uint32_t *)paddr;
1208		*pkey = key;
1209		masklen = 32;
1210		break;
1211	case IPFW_TABLE_FLOW:
1212		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1213		tfe = &tentry->k.flow;
1214		af = 0;
1215
1216		/* Handle <ipv4|ipv6> */
1217		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
1218			if ((p = strchr(arg, ',')) != NULL)
1219				*p++ = '\0';
1220			/* Determine family using temporary storage */
1221			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1222				if (af != 0 && af != AF_INET)
1223					errx(EX_DATAERR,
1224					    "Inconsistent address family\n");
1225				af = AF_INET;
1226				memcpy(&tfe->a.a4.sip, &tmp, 4);
1227			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1228				if (af != 0 && af != AF_INET6)
1229					errx(EX_DATAERR,
1230					    "Inconsistent address family\n");
1231				af = AF_INET6;
1232				memcpy(&tfe->a.a6.sip6, &tmp, 16);
1233			}
1234
1235			arg = p;
1236		}
1237
1238		/* Handle <proto-num|proto-name> */
1239		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
1240			if (arg == NULL)
1241				errx(EX_DATAERR, "invalid key: proto missing");
1242			if ((p = strchr(arg, ',')) != NULL)
1243				*p++ = '\0';
1244
1245			key = strtol(arg, &pp, 10);
1246			if (*pp != '\0') {
1247				if ((pent = getprotobyname(arg)) == NULL)
1248					errx(EX_DATAERR, "Unknown proto: %s",
1249					    arg);
1250				else
1251					key = pent->p_proto;
1252			}
1253
1254			if (key > 255)
1255				errx(EX_DATAERR, "Bad protocol number: %u",key);
1256
1257			tfe->proto = key;
1258
1259			arg = p;
1260		}
1261
1262		/* Handle <port-num|service-name> */
1263		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1264			if (arg == NULL)
1265				errx(EX_DATAERR, "invalid key: src port missing");
1266			if ((p = strchr(arg, ',')) != NULL)
1267				*p++ = '\0';
1268
1269			port = htons(strtol(arg, &pp, 10));
1270			if (*pp != '\0') {
1271				if ((sent = getservbyname(arg, NULL)) == NULL)
1272					errx(EX_DATAERR, "Unknown service: %s",
1273					    arg);
1274				port = sent->s_port;
1275			}
1276			tfe->sport = port;
1277			arg = p;
1278		}
1279
1280		/* Handle <ipv4|ipv6>*/
1281		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
1282			if (arg == NULL)
1283				errx(EX_DATAERR, "invalid key: dst ip missing");
1284			if ((p = strchr(arg, ',')) != NULL)
1285				*p++ = '\0';
1286			/* Determine family using temporary storage */
1287			if (inet_pton(AF_INET, arg, &tmp) == 1) {
1288				if (af != 0 && af != AF_INET)
1289					errx(EX_DATAERR,
1290					    "Inconsistent address family");
1291				af = AF_INET;
1292				memcpy(&tfe->a.a4.dip, &tmp, 4);
1293			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1294				if (af != 0 && af != AF_INET6)
1295					errx(EX_DATAERR,
1296					    "Inconsistent address family");
1297				af = AF_INET6;
1298				memcpy(&tfe->a.a6.dip6, &tmp, 16);
1299			}
1300
1301			arg = p;
1302		}
1303
1304		/* Handle <port-num|service-name> */
1305		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1306			if (arg == NULL)
1307				errx(EX_DATAERR, "invalid key: dst port missing");
1308			if ((p = strchr(arg, ',')) != NULL)
1309				*p++ = '\0';
1310
1311			port = htons(strtol(arg, &pp, 10));
1312			if (*pp != '\0') {
1313				if ((sent = getservbyname(arg, NULL)) == NULL)
1314					errx(EX_DATAERR, "Unknown service: %s",
1315					    arg);
1316				port = sent->s_port;
1317			}
1318			tfe->dport = port;
1319			arg = p;
1320		}
1321
1322		tfe->af = af;
1323
1324		break;
1325
1326	default:
1327		errx(EX_DATAERR, "Unsupported table type: %d", type);
1328	}
1329
1330	tentry->subtype = af;
1331	tentry->masklen = masklen;
1332}
1333
1334/*
1335 * Tries to guess table key type.
1336 * This procedure is used in legacy table auto-create
1337 * code AND in `ipfw -n` ruleset checking.
1338 *
1339 * Imported from old table_fill_xentry() parse code.
1340 */
1341static int
1342guess_key_type(char *key, uint8_t *ptype)
1343{
1344	char *p;
1345	struct in6_addr addr;
1346	uint32_t kv;
1347
1348	if (ishexnumber(*key) != 0 || *key == ':') {
1349		/* Remove / if exists */
1350		if ((p = strchr(key, '/')) != NULL)
1351			*p = '\0';
1352
1353		if ((inet_pton(AF_INET, key, &addr) == 1) ||
1354		    (inet_pton(AF_INET6, key, &addr) == 1)) {
1355			*ptype = IPFW_TABLE_CIDR;
1356			if (p != NULL)
1357				*p = '/';
1358			return (0);
1359		} else {
1360			/* Port or any other key */
1361			/* Skip non-base 10 entries like 'fa1' */
1362			kv = strtol(key, &p, 10);
1363			if (*p == '\0') {
1364				*ptype = IPFW_TABLE_NUMBER;
1365				return (0);
1366			} else if ((p != key) && (*p == '.')) {
1367				/*
1368				 * Warn on IPv4 address strings
1369				 * which are "valid" for inet_aton() but not
1370				 * in inet_pton().
1371				 *
1372				 * Typical examples: '10.5' or '10.0.0.05'
1373				 */
1374				return (1);
1375			}
1376		}
1377	}
1378
1379	if (strchr(key, '.') == NULL) {
1380		*ptype = IPFW_TABLE_INTERFACE;
1381		return (0);
1382	}
1383
1384	if (lookup_host(key, (struct in_addr *)&addr) != 0)
1385		return (1);
1386
1387	*ptype = IPFW_TABLE_CIDR;
1388	return (0);
1389}
1390
1391static void
1392tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
1393    int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi)
1394{
1395	uint8_t type, tflags;
1396	uint32_t vmask;
1397	int error;
1398
1399	type = 0;
1400	tflags = 0;
1401	vmask = 0;
1402
1403	if (xi->tablename[0] == '\0')
1404		error = table_get_info(oh, xi);
1405	else
1406		error = 0;
1407
1408	if (error == 0) {
1409		if (co.test_only == 0) {
1410			/* Table found */
1411			type = xi->type;
1412			tflags = xi->tflags;
1413			vmask = xi->vmask;
1414		} else {
1415			/*
1416			 * We're running `ipfw -n`
1417			 * Compatibility layer: try to guess key type
1418			 * before failing.
1419			 */
1420			if (guess_key_type(key, &type) != 0) {
1421				/* Inknown key */
1422				errx(EX_USAGE, "Cannot guess "
1423				    "key '%s' type", key);
1424			}
1425			vmask = IPFW_VTYPE_LEGACY;
1426		}
1427	} else {
1428		if (error != ESRCH)
1429			errx(EX_OSERR, "Error requesting table %s info",
1430			    oh->ntlv.name);
1431		if (add == 0)
1432			errx(EX_DATAERR, "Table %s does not exist",
1433			    oh->ntlv.name);
1434		/*
1435		 * Table does not exist
1436		 * Compatibility layer: try to guess key type before failing.
1437		 */
1438		if (guess_key_type(key, &type) != 0) {
1439			/* Inknown key */
1440			errx(EX_USAGE, "Table %s does not exist, cannot guess "
1441			    "key '%s' type", oh->ntlv.name, key);
1442		}
1443
1444		vmask = IPFW_VTYPE_LEGACY;
1445	}
1446
1447	tentry_fill_key_type(key, tent, type, tflags);
1448
1449	*ptype = type;
1450	*pvmask = vmask;
1451}
1452
1453static void
1454set_legacy_value(uint32_t val, ipfw_table_value *v)
1455{
1456	v->tag = val;
1457	v->pipe = val;
1458	v->divert = val;
1459	v->skipto = val;
1460	v->netgraph = val;
1461	v->fib = val;
1462	v->nat = val;
1463	v->nh4 = val;
1464	v->dscp = (uint8_t)val;
1465	v->limit = val;
1466}
1467
1468static void
1469tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1470    uint8_t type, uint32_t vmask)
1471{
1472	struct addrinfo hints, *res;
1473	uint32_t a4, flag, val;
1474	ipfw_table_value *v;
1475	uint32_t i;
1476	int dval;
1477	char *comma, *e, *etype, *n, *p;
1478
1479	v = &tent->v.value;
1480
1481	/* Compat layer: keep old behavior for legacy value types */
1482	if (vmask == IPFW_VTYPE_LEGACY) {
1483		/* Try to interpret as number first */
1484		val = strtoul(arg, &p, 0);
1485		if (*p == '\0') {
1486			set_legacy_value(val, v);
1487			return;
1488		}
1489		if (inet_pton(AF_INET, arg, &val) == 1) {
1490			set_legacy_value(ntohl(val), v);
1491			return;
1492		}
1493		/* Try hostname */
1494		if (lookup_host(arg, (struct in_addr *)&val) == 0) {
1495			set_legacy_value(val, v);
1496			return;
1497		}
1498		errx(EX_OSERR, "Unable to parse value %s", arg);
1499	}
1500
1501	/*
1502	 * Shorthands: handle single value if vmask consists
1503	 * of numbers only. e.g.:
1504	 * vmask = "fib,skipto" -> treat input "1" as "1,1"
1505	 */
1506
1507	n = arg;
1508	etype = NULL;
1509	for (i = 1; i < (1 << 31); i *= 2) {
1510		if ((flag = (vmask & i)) == 0)
1511			continue;
1512		vmask &= ~flag;
1513
1514		if ((comma = strchr(n, ',')) != NULL)
1515			*comma = '\0';
1516
1517		switch (flag) {
1518		case IPFW_VTYPE_TAG:
1519			v->tag = strtol(n, &e, 10);
1520			if (*e != '\0')
1521				etype = "tag";
1522			break;
1523		case IPFW_VTYPE_PIPE:
1524			v->pipe = strtol(n, &e, 10);
1525			if (*e != '\0')
1526				etype = "pipe";
1527			break;
1528		case IPFW_VTYPE_DIVERT:
1529			v->divert = strtol(n, &e, 10);
1530			if (*e != '\0')
1531				etype = "divert";
1532			break;
1533		case IPFW_VTYPE_SKIPTO:
1534			v->skipto = strtol(n, &e, 10);
1535			if (*e != '\0')
1536				etype = "skipto";
1537			break;
1538		case IPFW_VTYPE_NETGRAPH:
1539			v->netgraph = strtol(n, &e, 10);
1540			if (*e != '\0')
1541				etype = "netgraph";
1542			break;
1543		case IPFW_VTYPE_FIB:
1544			v->fib = strtol(n, &e, 10);
1545			if (*e != '\0')
1546				etype = "fib";
1547			break;
1548		case IPFW_VTYPE_NAT:
1549			v->nat = strtol(n, &e, 10);
1550			if (*e != '\0')
1551				etype = "nat";
1552			break;
1553		case IPFW_VTYPE_LIMIT:
1554			v->limit = strtol(n, &e, 10);
1555			if (*e != '\0')
1556				etype = "limit";
1557			break;
1558		case IPFW_VTYPE_NH4:
1559			if (strchr(n, '.') != NULL &&
1560			    inet_pton(AF_INET, n, &a4) == 1) {
1561				v->nh4 = ntohl(a4);
1562				break;
1563			}
1564			if (lookup_host(n, (struct in_addr *)&v->nh4) == 0)
1565				break;
1566			etype = "ipv4";
1567			break;
1568		case IPFW_VTYPE_DSCP:
1569			if (isalpha(*n)) {
1570				if ((dval = match_token(f_ipdscp, n)) != -1) {
1571					v->dscp = dval;
1572					break;
1573				} else
1574					etype = "DSCP code";
1575			} else {
1576				v->dscp = strtol(n, &e, 10);
1577				if (v->dscp > 63 || *e != '\0')
1578					etype = "DSCP value";
1579			}
1580			break;
1581		case IPFW_VTYPE_NH6:
1582			if (strchr(n, ':') != NULL) {
1583				memset(&hints, 0, sizeof(hints));
1584				hints.ai_family = AF_INET6;
1585				hints.ai_flags = AI_NUMERICHOST;
1586				if (getaddrinfo(n, NULL, &hints, &res) == 0) {
1587					v->nh6 = ((struct sockaddr_in6 *)
1588					    res->ai_addr)->sin6_addr;
1589					v->zoneid = ((struct sockaddr_in6 *)
1590					    res->ai_addr)->sin6_scope_id;
1591					freeaddrinfo(res);
1592					break;
1593				}
1594			}
1595			etype = "ipv6";
1596			break;
1597		}
1598
1599		if (etype != NULL)
1600			errx(EX_USAGE, "Unable to parse %s as %s", n, etype);
1601
1602		if (comma != NULL)
1603			*comma++ = ',';
1604
1605		if ((n = comma) != NULL)
1606			continue;
1607
1608		/* End of input. */
1609		if (vmask != 0)
1610			errx(EX_USAGE, "Not enough fields inside value");
1611	}
1612}
1613
1614/*
1615 * Compare table names.
1616 * Honor number comparison.
1617 */
1618static int
1619tablename_cmp(const void *a, const void *b)
1620{
1621	ipfw_xtable_info *ia, *ib;
1622
1623	ia = (ipfw_xtable_info *)a;
1624	ib = (ipfw_xtable_info *)b;
1625
1626	return (stringnum_cmp(ia->tablename, ib->tablename));
1627}
1628
1629/*
1630 * Retrieves table list from kernel,
1631 * optionally sorts it and calls requested function for each table.
1632 * Returns 0 on success.
1633 */
1634static int
1635tables_foreach(table_cb_t *f, void *arg, int sort)
1636{
1637	ipfw_obj_lheader *olh;
1638	ipfw_xtable_info *info;
1639	size_t sz;
1640	int i, error;
1641
1642	/* Start with reasonable default */
1643	sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
1644
1645	for (;;) {
1646		if ((olh = calloc(1, sz)) == NULL)
1647			return (ENOMEM);
1648
1649		olh->size = sz;
1650		if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) {
1651			sz = olh->size;
1652			free(olh);
1653			if (errno != ENOMEM)
1654				return (errno);
1655			continue;
1656		}
1657
1658		if (sort != 0)
1659			qsort(olh + 1, olh->count, olh->objsize,
1660			    tablename_cmp);
1661
1662		info = (ipfw_xtable_info *)(olh + 1);
1663		for (i = 0; i < olh->count; i++) {
1664			if (co.use_set == 0 || info->set == co.use_set - 1)
1665				error = f(info, arg);
1666			info = (ipfw_xtable_info *)((caddr_t)info +
1667			    olh->objsize);
1668		}
1669		free(olh);
1670		break;
1671	}
1672	return (0);
1673}
1674
1675
1676/*
1677 * Retrieves all entries for given table @i in
1678 * eXtended format. Allocate buffer large enough
1679 * to store result. Called needs to free it later.
1680 *
1681 * Returns 0 on success.
1682 */
1683static int
1684table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
1685{
1686	ipfw_obj_header *oh;
1687	size_t sz;
1688	int c;
1689
1690	sz = 0;
1691	oh = NULL;
1692	for (c = 0; c < 8; c++) {
1693		if (sz < i->size)
1694			sz = i->size + 44;
1695		if (oh != NULL)
1696			free(oh);
1697		if ((oh = calloc(1, sz)) == NULL)
1698			continue;
1699		table_fill_objheader(oh, i);
1700		oh->opheader.version = 1; /* Current version */
1701		if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) {
1702			*poh = oh;
1703			return (0);
1704		}
1705
1706		if (errno != ENOMEM)
1707			break;
1708	}
1709	free(oh);
1710
1711	return (errno);
1712}
1713
1714/*
1715 * Shows all entries from @oh in human-readable format
1716 */
1717static void
1718table_show_list(ipfw_obj_header *oh, int need_header)
1719{
1720	ipfw_obj_tentry *tent;
1721	uint32_t count;
1722	ipfw_xtable_info *i;
1723
1724	i = (ipfw_xtable_info *)(oh + 1);
1725	tent = (ipfw_obj_tentry *)(i + 1);
1726
1727	if (need_header)
1728		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1729
1730	count = i->count;
1731	while (count > 0) {
1732		table_show_entry(i, tent);
1733		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
1734		count--;
1735	}
1736}
1737
1738static void
1739table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
1740    uint32_t vmask, int print_ip)
1741{
1742	char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
1743	struct sockaddr_in6 sa6;
1744	uint32_t flag, i, l;
1745	size_t sz;
1746	struct in_addr a4;
1747
1748	sz = bufsize;
1749
1750	/*
1751	 * Some shorthands for printing values:
1752	 * legacy assumes all values are equal, so keep the first one.
1753	 */
1754	if (vmask == IPFW_VTYPE_LEGACY) {
1755		if (print_ip != 0) {
1756			flag = htonl(v->tag);
1757			inet_ntop(AF_INET, &flag, buf, sz);
1758		} else
1759			snprintf(buf, sz, "%u", v->tag);
1760		return;
1761	}
1762
1763	for (i = 1; i < (1 << 31); i *= 2) {
1764		if ((flag = (vmask & i)) == 0)
1765			continue;
1766		l = 0;
1767
1768		switch (flag) {
1769		case IPFW_VTYPE_TAG:
1770			l = snprintf(buf, sz, "%u,", v->tag);
1771			break;
1772		case IPFW_VTYPE_PIPE:
1773			l = snprintf(buf, sz, "%u,", v->pipe);
1774			break;
1775		case IPFW_VTYPE_DIVERT:
1776			l = snprintf(buf, sz, "%d,", v->divert);
1777			break;
1778		case IPFW_VTYPE_SKIPTO:
1779			l = snprintf(buf, sz, "%d,", v->skipto);
1780			break;
1781		case IPFW_VTYPE_NETGRAPH:
1782			l = snprintf(buf, sz, "%u,", v->netgraph);
1783			break;
1784		case IPFW_VTYPE_FIB:
1785			l = snprintf(buf, sz, "%u,", v->fib);
1786			break;
1787		case IPFW_VTYPE_NAT:
1788			l = snprintf(buf, sz, "%u,", v->nat);
1789			break;
1790		case IPFW_VTYPE_LIMIT:
1791			l = snprintf(buf, sz, "%u,", v->limit);
1792			break;
1793		case IPFW_VTYPE_NH4:
1794			a4.s_addr = htonl(v->nh4);
1795			inet_ntop(AF_INET, &a4, abuf, sizeof(abuf));
1796			l = snprintf(buf, sz, "%s,", abuf);
1797			break;
1798		case IPFW_VTYPE_DSCP:
1799			l = snprintf(buf, sz, "%d,", v->dscp);
1800			break;
1801		case IPFW_VTYPE_NH6:
1802			sa6.sin6_family = AF_INET6;
1803			sa6.sin6_len = sizeof(sa6);
1804			sa6.sin6_addr = v->nh6;
1805			sa6.sin6_port = 0;
1806			sa6.sin6_scope_id = v->zoneid;
1807			if (getnameinfo((const struct sockaddr *)&sa6,
1808			    sa6.sin6_len, abuf, sizeof(abuf), NULL, 0,
1809			    NI_NUMERICHOST) == 0)
1810				l = snprintf(buf, sz, "%s,", abuf);
1811			break;
1812		}
1813
1814		buf += l;
1815		sz -= l;
1816	}
1817
1818	if (sz != bufsize)
1819		*(buf - 1) = '\0';
1820}
1821
1822static void
1823table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
1824{
1825	char *comma, tbuf[128], pval[128];
1826	void *paddr;
1827	struct tflow_entry *tfe;
1828
1829	table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask,
1830	    co.do_value_as_ip);
1831
1832	switch (i->type) {
1833	case IPFW_TABLE_ADDR:
1834		/* IPv4 or IPv6 prefixes */
1835		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1836		printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1837		break;
1838	case IPFW_TABLE_INTERFACE:
1839		/* Interface names */
1840		printf("%s %s\n", tent->k.iface, pval);
1841		break;
1842	case IPFW_TABLE_NUMBER:
1843		/* numbers */
1844		printf("%u %s\n", tent->k.key, pval);
1845		break;
1846	case IPFW_TABLE_FLOW:
1847		/* flows */
1848		tfe = &tent->k.flow;
1849		comma = "";
1850
1851		if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1852			if (tfe->af == AF_INET)
1853				paddr = &tfe->a.a4.sip;
1854			else
1855				paddr = &tfe->a.a6.sip6;
1856
1857			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1858			printf("%s%s", comma, tbuf);
1859			comma = ",";
1860		}
1861
1862		if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1863			printf("%s%d", comma, tfe->proto);
1864			comma = ",";
1865		}
1866
1867		if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1868			printf("%s%d", comma, ntohs(tfe->sport));
1869			comma = ",";
1870		}
1871		if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1872			if (tfe->af == AF_INET)
1873				paddr = &tfe->a.a4.dip;
1874			else
1875				paddr = &tfe->a.a6.dip6;
1876
1877			inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1878			printf("%s%s", comma, tbuf);
1879			comma = ",";
1880		}
1881
1882		if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1883			printf("%s%d", comma, ntohs(tfe->dport));
1884			comma = ",";
1885		}
1886
1887		printf(" %s\n", pval);
1888	}
1889}
1890
1891static int
1892table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh)
1893{
1894	ipfw_obj_lheader req, *olh;
1895	size_t sz;
1896
1897	memset(&req, 0, sizeof(req));
1898	sz = sizeof(req);
1899
1900	if (do_get3(opcode, &req.opheader, &sz) != 0)
1901		if (errno != ENOMEM)
1902			return (errno);
1903
1904	sz = req.size;
1905	if ((olh = calloc(1, sz)) == NULL)
1906		return (ENOMEM);
1907
1908	olh->size = sz;
1909	if (do_get3(opcode, &olh->opheader, &sz) != 0) {
1910		free(olh);
1911		return (errno);
1912	}
1913
1914	*polh = olh;
1915	return (0);
1916}
1917
1918static int
1919table_do_get_algolist(ipfw_obj_lheader **polh)
1920{
1921
1922	return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh));
1923}
1924
1925static int
1926table_do_get_vlist(ipfw_obj_lheader **polh)
1927{
1928
1929	return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh));
1930}
1931
1932void
1933ipfw_list_ta(int ac, char *av[])
1934{
1935	ipfw_obj_lheader *olh;
1936	ipfw_ta_info *info;
1937	int error, i;
1938	const char *atype;
1939
1940	error = table_do_get_algolist(&olh);
1941	if (error != 0)
1942		err(EX_OSERR, "Unable to request algorithm list");
1943
1944	info = (ipfw_ta_info *)(olh + 1);
1945	for (i = 0; i < olh->count; i++) {
1946		if ((atype = match_value(tabletypes, info->type)) == NULL)
1947			atype = "unknown";
1948		printf("--- %s ---\n", info->algoname);
1949		printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
1950
1951		info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
1952	}
1953
1954	free(olh);
1955}
1956
1957
1958/* Copy of current kernel table_value structure */
1959struct _table_value {
1960	uint32_t	tag;		/* O_TAG/O_TAGGED */
1961	uint32_t	pipe;		/* O_PIPE/O_QUEUE */
1962	uint16_t	divert;		/* O_DIVERT/O_TEE */
1963	uint16_t	skipto;		/* skipto, CALLRET */
1964	uint32_t	netgraph;	/* O_NETGRAPH/O_NGTEE */
1965	uint32_t	fib;		/* O_SETFIB */
1966	uint32_t	nat;		/* O_NAT */
1967	uint32_t	nh4;
1968	uint8_t		dscp;
1969	uint8_t		spare0;
1970	uint16_t	spare1;
1971	/* -- 32 bytes -- */
1972	struct in6_addr	nh6;
1973	uint32_t	limit;		/* O_LIMIT */
1974	uint32_t	zoneid;
1975	uint64_t	refcnt;		/* Number of references */
1976};
1977
1978int
1979compare_values(const void *_a, const void *_b)
1980{
1981	struct _table_value *a, *b;
1982
1983	a = (struct _table_value *)_a;
1984	b = (struct _table_value *)_b;
1985
1986	if (a->spare1 < b->spare1)
1987		return (-1);
1988	else if (a->spare1 > b->spare1)
1989		return (1);
1990
1991	return (0);
1992}
1993
1994void
1995ipfw_list_values(int ac, char *av[])
1996{
1997	ipfw_obj_lheader *olh;
1998	struct _table_value *v;
1999	int error, i;
2000	uint32_t vmask;
2001	char buf[128];
2002
2003	error = table_do_get_vlist(&olh);
2004	if (error != 0)
2005		err(EX_OSERR, "Unable to request value list");
2006
2007	vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */
2008
2009	table_print_valheader(buf, sizeof(buf), vmask);
2010	printf("HEADER: %s\n", buf);
2011	v = (struct _table_value *)(olh + 1);
2012	qsort(v, olh->count, olh->objsize, compare_values);
2013	for (i = 0; i < olh->count; i++) {
2014		table_show_value(buf, sizeof(buf), (ipfw_table_value *)v,
2015		    vmask, 0);
2016		printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf);
2017		v = (struct _table_value *)((caddr_t)v + olh->objsize);
2018	}
2019
2020	free(olh);
2021}
2022
2023int
2024table_check_name(const char *tablename)
2025{
2026
2027	if (ipfw_check_object_name(tablename) != 0)
2028		return (EINVAL);
2029	/* Restrict some 'special' names */
2030	if (strcmp(tablename, "all") == 0)
2031		return (EINVAL);
2032	return (0);
2033}
2034
2035