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