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