2 * Copyright (c) 2014 Yandex LLC
3 * Copyright (c) 2014 Alexander V. Chernikov
5 * Redistribution and use in source forms, with and without modification,
6 * are permitted provided that this entire comment appears intact.
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.
12 * This software is provided ``AS IS'' without any warranties of any kind.
14 * in-kernel ipfw tables support.
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
23 #include <sys/sysctl.h>
35 #include <netinet/in.h>
36 #include <netinet/ip_fw.h>
37 #include <arpa/inet.h>
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 static void table_fill_ntlv(ipfw_obj_ntlv
*ntlv
, const char *name
,
57 uint32_t set
, uint16_t uidx
);
59 static int table_flush_one(ipfw_xtable_info
*i
, void *arg
);
60 static int table_show_one(ipfw_xtable_info
*i
, void *arg
);
61 static int table_do_get_list(ipfw_xtable_info
*i
, ipfw_obj_header
**poh
);
62 static void table_show_list(ipfw_obj_header
*oh
, int need_header
);
63 static void table_show_entry(ipfw_xtable_info
*i
, ipfw_obj_tentry
*tent
);
65 static void tentry_fill_key(ipfw_obj_header
*oh
, ipfw_obj_tentry
*tent
,
66 char *key
, int add
, uint8_t *ptype
, uint32_t *pvmask
, ipfw_xtable_info
*xi
);
67 static void tentry_fill_value(ipfw_obj_header
*oh
, ipfw_obj_tentry
*tent
,
68 char *arg
, uint8_t type
, uint32_t vmask
);
69 static void table_show_value(char *buf
, size_t bufsize
, ipfw_table_value
*v
,
70 uint32_t vmask
, int print_ip
);
72 typedef int (table_cb_t
)(ipfw_xtable_info
*i
, void *arg
);
73 static int tables_foreach(table_cb_t
*f
, void *arg
, int sort
);
76 #define s6_addr32 __u6_addr.__u6_addr32
79 static struct _s_x tabletypes
[] = {
80 { "addr", IPFW_TABLE_ADDR
},
81 { "iface", IPFW_TABLE_INTERFACE
},
82 { "number", IPFW_TABLE_NUMBER
},
83 { "flow", IPFW_TABLE_FLOW
},
87 static struct _s_x tablevaltypes
[] = {
88 { "skipto", IPFW_VTYPE_SKIPTO
},
89 { "pipe", IPFW_VTYPE_PIPE
},
90 { "fib", IPFW_VTYPE_FIB
},
91 { "nat", IPFW_VTYPE_NAT
},
92 { "dscp", IPFW_VTYPE_DSCP
},
93 { "tag", IPFW_VTYPE_TAG
},
94 { "divert", IPFW_VTYPE_DIVERT
},
95 { "netgraph", IPFW_VTYPE_NETGRAPH
},
96 { "limit", IPFW_VTYPE_LIMIT
},
97 { "ipv4", IPFW_VTYPE_NH4
},
98 { "ipv6", IPFW_VTYPE_NH6
},
102 static struct _s_x tablecmds
[] = {
104 { "delete", TOK_DEL
},
105 { "create", TOK_CREATE
},
106 { "destroy", TOK_DESTROY
},
107 { "flush", TOK_FLUSH
},
108 { "modify", TOK_MODIFY
},
109 { "swap", TOK_SWAP
},
110 { "info", TOK_INFO
},
111 { "detail", TOK_DETAIL
},
112 { "list", TOK_LIST
},
113 { "lookup", TOK_LOOKUP
},
114 { "atomic", TOK_ATOMIC
},
115 { "lock", TOK_LOCK
},
116 { "unlock", TOK_UNLOCK
},
121 lookup_host (char *host
, struct in_addr
*ipaddr
)
125 if (!inet_aton(host
, ipaddr
)) {
126 if ((he
= gethostbyname(host
)) == NULL
)
128 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
134 * This one handles all table-related commands
135 * ipfw table NAME create ...
136 * ipfw table NAME modify ...
137 * ipfw table NAME destroy
138 * ipfw table NAME swap NAME
139 * ipfw table NAME lock
140 * ipfw table NAME unlock
141 * ipfw table NAME add addr[/masklen] [value]
142 * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] ..
143 * ipfw table NAME delete addr[/masklen] [addr[/masklen]] ..
144 * ipfw table NAME lookup addr
145 * ipfw table {NAME | all} flush
146 * ipfw table {NAME | all} list
147 * ipfw table {NAME | all} info
148 * ipfw table {NAME | all} detail
151 ipfw_table_handler(int ac
, char *av
[])
154 int atomic
, error
, tcmd
;
161 memset(&oh
, 0, sizeof(oh
));
164 set
= co
.use_set
- 1;
169 NEED1("table needs name");
172 if (table_check_name(tablename
) == 0) {
173 table_fill_ntlv(&oh
.ntlv
, *av
, set
, 1);
176 if (strcmp(tablename
, "all") == 0)
179 errx(EX_USAGE
, "table name %s is invalid", tablename
);
182 NEED1("table needs command");
184 tcmd
= get_token(tablecmds
, *av
, "table command");
185 /* Check if atomic operation was requested */
187 if (tcmd
== TOK_ATOMIC
) {
189 NEED1("atomic needs command");
190 tcmd
= get_token(tablecmds
, *av
, "table command");
195 errx(EX_USAGE
, "atomic is not compatible with %s", *av
);
208 errx(EX_USAGE
, "table name required");
214 do_add
= **av
== 'a';
216 table_modify_record(&oh
, ac
, av
, do_add
, co
.do_quiet
,
217 co
.do_quiet
, atomic
);
221 table_create(&oh
, ac
, av
);
225 table_modify(&oh
, ac
, av
);
228 if (table_destroy(&oh
) != 0)
229 err(EX_OSERR
, "failed to destroy table %s", tablename
);
233 if ((error
= table_flush(&oh
)) != 0)
234 err(EX_OSERR
, "failed to flush table %s info",
237 error
= tables_foreach(table_flush_one
, &oh
, 1);
239 err(EX_OSERR
, "failed to flush tables list");
244 NEED1("second table name required");
245 table_swap(&oh
, *av
);
249 table_lock(&oh
, (tcmd
== TOK_LOCK
));
253 arg
= (tcmd
== TOK_DETAIL
) ? (void *)1 : NULL
;
255 if ((error
= table_get_info(&oh
, &i
)) != 0)
256 err(EX_OSERR
, "failed to request table info");
257 table_show_info(&i
, arg
);
259 error
= tables_foreach(table_show_info
, arg
, 1);
261 err(EX_OSERR
, "failed to request tables list");
267 if ((error
= table_get_info(&oh
, &i
)) != 0)
268 err(EX_OSERR
, "failed to request table info");
269 table_show_one(&i
, NULL
);
271 error
= tables_foreach(table_show_one
, NULL
, 1);
273 err(EX_OSERR
, "failed to request tables list");
278 table_lookup(&oh
, ac
, av
);
284 table_fill_ntlv(ipfw_obj_ntlv
*ntlv
, const char *name
, uint32_t set
,
288 ntlv
->head
.type
= IPFW_TLV_TBL_NAME
;
289 ntlv
->head
.length
= sizeof(ipfw_obj_ntlv
);
292 strlcpy(ntlv
->name
, name
, sizeof(ntlv
->name
));
296 table_fill_objheader(ipfw_obj_header
*oh
, ipfw_xtable_info
*i
)
300 table_fill_ntlv(&oh
->ntlv
, i
->tablename
, i
->set
, 1);
303 static struct _s_x tablenewcmds
[] = {
304 { "type", TOK_TYPE
},
305 { "valtype", TOK_VALTYPE
},
306 { "algo", TOK_ALGO
},
307 { "limit", TOK_LIMIT
},
308 { "locked", TOK_LOCK
},
312 static struct _s_x flowtypecmds
[] = {
313 { "src-ip", IPFW_TFFLAG_SRCIP
},
314 { "proto", IPFW_TFFLAG_PROTO
},
315 { "src-port", IPFW_TFFLAG_SRCPORT
},
316 { "dst-ip", IPFW_TFFLAG_DSTIP
},
317 { "dst-port", IPFW_TFFLAG_DSTPORT
},
322 table_parse_type(uint8_t ttype
, char *p
, uint8_t *tflags
)
324 uint32_t fset
, fclear
;
327 /* Parse type options */
329 case IPFW_TABLE_FLOW
:
331 if (fill_flags(flowtypecmds
, p
, &e
, &fset
, &fclear
) != 0)
333 "unable to parse flow option %s", e
);
344 table_print_type(char *tbuf
, size_t size
, uint8_t type
, uint8_t tflags
)
349 if ((tname
= match_value(tabletypes
, type
)) == NULL
)
352 l
= snprintf(tbuf
, size
, "%s", tname
);
357 case IPFW_TABLE_FLOW
:
361 print_flags_buffer(tbuf
, size
, flowtypecmds
, tflags
);
370 * ipfw table NAME create [ type { addr | iface | number | flow } ]
374 table_create(ipfw_obj_header
*oh
, int ac
, char *av
[])
377 int error
, tcmd
, val
;
378 uint32_t fset
, fclear
;
382 memset(&xi
, 0, sizeof(xi
));
385 tcmd
= get_token(tablenewcmds
, *av
, "option");
390 NEED1("limit value required");
391 xi
.limit
= strtol(*av
, NULL
, 10);
395 NEED1("table type required");
396 /* Type may have suboptions after ':' */
397 if ((p
= strchr(*av
, ':')) != NULL
)
399 val
= match_token(tabletypes
, *av
);
401 concat_tokens(tbuf
, sizeof(tbuf
), tabletypes
,
404 "Unknown tabletype: %s. Supported: %s",
409 error
= table_parse_type(val
, p
, &xi
.tflags
);
412 "Unsupported suboptions: %s", p
);
417 NEED1("table value type required");
419 val
= fill_flags(tablevaltypes
, *av
, &e
, &fset
, &fclear
);
425 concat_tokens(tbuf
, sizeof(tbuf
), tablevaltypes
, ", ");
426 errx(EX_USAGE
, "Unknown value type: %s. Supported: %s",
430 NEED1("table algorithm name required");
431 if (strlen(*av
) > sizeof(xi
.algoname
))
432 errx(EX_USAGE
, "algorithm name too long");
433 strlcpy(xi
.algoname
, *av
, sizeof(xi
.algoname
));
437 xi
.flags
|= IPFW_TGFLAGS_LOCKED
;
442 /* Set some defaults to preserve compatibility. */
443 if (xi
.algoname
[0] == '\0' && xi
.type
== 0)
444 xi
.type
= IPFW_TABLE_ADDR
;
446 xi
.vmask
= IPFW_VTYPE_LEGACY
;
448 if ((error
= table_do_create(oh
, &xi
)) != 0)
449 err(EX_OSERR
, "Table creation failed");
455 * Request: [ ipfw_obj_header ipfw_xtable_info ]
457 * Returns 0 on success.
460 table_do_create(ipfw_obj_header
*oh
, ipfw_xtable_info
*i
)
462 char tbuf
[sizeof(ipfw_obj_header
) + sizeof(ipfw_xtable_info
)];
465 memcpy(tbuf
, oh
, sizeof(*oh
));
466 memcpy(tbuf
+ sizeof(*oh
), i
, sizeof(*i
));
467 oh
= (ipfw_obj_header
*)tbuf
;
469 error
= do_set3(IP_FW_TABLE_XCREATE
, &oh
->opheader
, sizeof(tbuf
));
475 * Modifies existing table
477 * ipfw table NAME modify [ limit number ]
480 table_modify(ipfw_obj_header
*oh
, int ac
, char *av
[])
485 memset(&xi
, 0, sizeof(xi
));
488 tcmd
= get_token(tablenewcmds
, *av
, "option");
493 NEED1("limit value required");
494 xi
.limit
= strtol(*av
, NULL
, 10);
495 xi
.mflags
|= IPFW_TMFLAGS_LIMIT
;
499 errx(EX_USAGE
, "cmd is not supported for modificatiob");
503 if (table_do_modify(oh
, &xi
) != 0)
504 err(EX_OSERR
, "Table modification failed");
508 * Modifies existing table.
510 * Request: [ ipfw_obj_header ipfw_xtable_info ]
512 * Returns 0 on success.
515 table_do_modify(ipfw_obj_header
*oh
, ipfw_xtable_info
*i
)
517 char tbuf
[sizeof(ipfw_obj_header
) + sizeof(ipfw_xtable_info
)];
520 memcpy(tbuf
, oh
, sizeof(*oh
));
521 memcpy(tbuf
+ sizeof(*oh
), i
, sizeof(*i
));
522 oh
= (ipfw_obj_header
*)tbuf
;
524 error
= do_set3(IP_FW_TABLE_XMODIFY
, &oh
->opheader
, sizeof(tbuf
));
530 * Locks or unlocks given table
533 table_lock(ipfw_obj_header
*oh
, int lock
)
537 memset(&xi
, 0, sizeof(xi
));
539 xi
.mflags
|= IPFW_TMFLAGS_LOCK
;
540 xi
.flags
|= (lock
!= 0) ? IPFW_TGFLAGS_LOCKED
: 0;
542 if (table_do_modify(oh
, &xi
) != 0)
543 err(EX_OSERR
, "Table %s failed", lock
!= 0 ? "lock" : "unlock");
547 * Destroys given table specified by @oh->ntlv.
548 * Returns 0 on success.
551 table_destroy(ipfw_obj_header
*oh
)
554 if (do_set3(IP_FW_TABLE_XDESTROY
, &oh
->opheader
, sizeof(*oh
)) != 0)
561 * Flushes given table specified by @oh->ntlv.
562 * Returns 0 on success.
565 table_flush(ipfw_obj_header
*oh
)
568 if (do_set3(IP_FW_TABLE_XFLUSH
, &oh
->opheader
, sizeof(*oh
)) != 0)
575 table_do_swap(ipfw_obj_header
*oh
, char *second
)
577 char tbuf
[sizeof(ipfw_obj_header
) + sizeof(ipfw_obj_ntlv
)];
580 memset(tbuf
, 0, sizeof(tbuf
));
581 memcpy(tbuf
, oh
, sizeof(*oh
));
582 oh
= (ipfw_obj_header
*)tbuf
;
583 table_fill_ntlv((ipfw_obj_ntlv
*)(oh
+ 1), second
, oh
->ntlv
.set
, 1);
585 error
= do_set3(IP_FW_TABLE_XSWAP
, &oh
->opheader
, sizeof(tbuf
));
591 * Swaps given table with @second one.
594 table_swap(ipfw_obj_header
*oh
, char *second
)
598 if (table_check_name(second
) != 0)
599 errx(EX_USAGE
, "table name %s is invalid", second
);
601 error
= table_do_swap(oh
, second
);
605 errx(EX_USAGE
, "Unable to swap table: check types");
607 errx(EX_USAGE
, "Unable to swap table: check limits");
615 * Retrieves table in given table specified by @oh->ntlv.
617 * Returns 0 on success.
620 table_get_info(ipfw_obj_header
*oh
, ipfw_xtable_info
*i
)
622 char tbuf
[sizeof(ipfw_obj_header
) + sizeof(ipfw_xtable_info
)];
626 memset(tbuf
, 0, sizeof(tbuf
));
627 memcpy(tbuf
, oh
, sizeof(*oh
));
628 oh
= (ipfw_obj_header
*)tbuf
;
630 if (do_get3(IP_FW_TABLE_XINFO
, &oh
->opheader
, &sz
) != 0)
633 if (sz
< sizeof(tbuf
))
636 *i
= *(ipfw_xtable_info
*)(oh
+ 1);
641 static struct _s_x tablealgoclass
[] = {
642 { "hash", IPFW_TACLASS_HASH
},
643 { "array", IPFW_TACLASS_ARRAY
},
644 { "radix", IPFW_TACLASS_RADIX
},
658 * Print global/per-AF table @i algorithm info.
661 table_show_tainfo(ipfw_xtable_info
*i
, struct ta_cldata
*d
,
662 const char *af
, const char *taclass
)
665 switch (d
->taclass
) {
666 case IPFW_TACLASS_HASH
:
667 case IPFW_TACLASS_ARRAY
:
668 printf(" %salgorithm %s info\n", af
, taclass
);
669 if (d
->itemsize
== d
->itemsize6
)
670 printf(" size: %u items: %u itemsize: %u\n",
671 d
->size
, d
->count
, d
->itemsize
);
673 printf(" size: %u items: %u "
674 "itemsize4: %u itemsize6: %u\n",
676 d
->itemsize
, d
->itemsize6
);
678 case IPFW_TACLASS_RADIX
:
679 printf(" %salgorithm %s info\n", af
, taclass
);
680 if (d
->itemsize
== d
->itemsize6
)
681 printf(" items: %u itemsize: %u\n",
682 d
->count
, d
->itemsize
);
685 "itemsize4: %u itemsize6: %u\n",
686 d
->count
, d
->itemsize
, d
->itemsize6
);
689 printf(" algo class: %s\n", taclass
);
694 table_print_valheader(char *buf
, size_t bufsize
, uint32_t vmask
)
697 if (vmask
== IPFW_VTYPE_LEGACY
) {
698 snprintf(buf
, bufsize
, "legacy");
702 memset(buf
, 0, bufsize
);
703 print_flags_buffer(buf
, bufsize
, tablevaltypes
, vmask
);
707 * Prints table info struct @i in human-readable form.
710 table_show_info(ipfw_xtable_info
*i
, void *arg
)
713 ipfw_ta_tinfo
*tainfo
;
716 char ttype
[64], tvtype
[64];
718 table_print_type(ttype
, sizeof(ttype
), i
->type
, i
->tflags
);
719 table_print_valheader(tvtype
, sizeof(tvtype
), i
->vmask
);
721 printf("--- table(%s), set(%u) ---\n", i
->tablename
, i
->set
);
722 if ((i
->flags
& IPFW_TGFLAGS_LOCKED
) != 0)
723 printf(" kindex: %d, type: %s, locked\n", i
->kidx
, ttype
);
725 printf(" kindex: %d, type: %s\n", i
->kidx
, ttype
);
726 printf(" references: %u, valtype: %s\n", i
->refcnt
, tvtype
);
727 printf(" algorithm: %s\n", i
->algoname
);
728 printf(" items: %u, size: %u\n", i
->count
, i
->size
);
730 printf(" limit: %u\n", i
->limit
);
732 /* Print algo-specific info if requested & set */
736 if ((i
->ta_info
.flags
& IPFW_TATFLAGS_DATA
) == 0)
738 tainfo
= &i
->ta_info
;
742 if (tainfo
->flags
& IPFW_TATFLAGS_AFDATA
)
744 if (tainfo
->flags
& IPFW_TATFLAGS_AFITEM
)
747 memset(&d
, 0, sizeof(d
));
748 d
.taclass
= tainfo
->taclass4
;
749 d
.size
= tainfo
->size4
;
750 d
.count
= tainfo
->count4
;
751 d
.itemsize
= tainfo
->itemsize4
;
752 if (afdata
== 0 && afitem
!= 0)
753 d
.itemsize6
= tainfo
->itemsize6
;
755 d
.itemsize6
= d
.itemsize
;
756 if ((vtype
= match_value(tablealgoclass
, d
.taclass
)) == NULL
)
760 table_show_tainfo(i
, &d
, "", vtype
);
762 table_show_tainfo(i
, &d
, "IPv4 ", vtype
);
763 memset(&d
, 0, sizeof(d
));
764 d
.taclass
= tainfo
->taclass6
;
765 if ((vtype
= match_value(tablealgoclass
, d
.taclass
)) == NULL
)
767 d
.size
= tainfo
->size6
;
768 d
.count
= tainfo
->count6
;
769 d
.itemsize
= tainfo
->itemsize6
;
770 d
.itemsize6
= d
.itemsize
;
771 table_show_tainfo(i
, &d
, "IPv6 ", vtype
);
779 * Function wrappers which can be used either
780 * as is or as foreach function parameter.
784 table_show_one(ipfw_xtable_info
*i
, void *arg
)
789 if ((error
= table_do_get_list(i
, &oh
)) != 0) {
790 err(EX_OSERR
, "Error requesting table %s list", i
->tablename
);
794 table_show_list(oh
, 1);
801 table_flush_one(ipfw_xtable_info
*i
, void *arg
)
805 oh
= (ipfw_obj_header
*)arg
;
807 table_fill_ntlv(&oh
->ntlv
, i
->tablename
, i
->set
, 1);
809 return (table_flush(oh
));
813 table_do_modify_record(int cmd
, ipfw_obj_header
*oh
,
814 ipfw_obj_tentry
*tent
, int count
, int atomic
)
817 ipfw_obj_tentry
*tent_base
;
819 char xbuf
[sizeof(*oh
) + sizeof(ipfw_obj_ctlv
) + sizeof(*tent
)];
823 sz
= sizeof(*ctlv
) + sizeof(*tent
) * count
;
825 memset(xbuf
, 0, sizeof(xbuf
));
828 if ((pbuf
= calloc(1, sizeof(*oh
) + sz
)) == NULL
)
832 memcpy(pbuf
, oh
, sizeof(*oh
));
833 oh
= (ipfw_obj_header
*)pbuf
;
834 oh
->opheader
.version
= 1;
836 ctlv
= (ipfw_obj_ctlv
*)(oh
+ 1);
838 ctlv
->head
.length
= sz
;
840 ctlv
->flags
|= IPFW_CTF_ATOMIC
;
843 memcpy(ctlv
+ 1, tent
, sizeof(*tent
) * count
);
844 tent
= (ipfw_obj_tentry
*)(ctlv
+ 1);
845 for (i
= 0; i
< count
; i
++, tent
++) {
846 tent
->head
.length
= sizeof(ipfw_obj_tentry
);
851 error
= do_get3(cmd
, &oh
->opheader
, &sz
);
852 tent
= (ipfw_obj_tentry
*)(ctlv
+ 1);
853 /* Copy result back to provided buffer */
854 memcpy(tent_base
, ctlv
+ 1, sizeof(*tent
) * count
);
863 table_modify_record(ipfw_obj_header
*oh
, int ac
, char *av
[], int add
,
864 int quiet
, int update
, int atomic
)
866 ipfw_obj_tentry
*ptent
, tent
, *tent_buf
;
870 int cmd
, count
, error
, i
, ignored
;
871 char *texterr
, *etxt
, *px
;
874 errx(EX_USAGE
, "address required");
877 cmd
= IP_FW_TABLE_XADD
;
878 texterr
= "Adding record failed";
880 cmd
= IP_FW_TABLE_XDEL
;
881 texterr
= "Deleting record failed";
885 * Calculate number of entries:
886 * Assume [key val] x N for add
890 count
= (add
!= 0) ? ac
/ 2 + 1 : ac
;
893 /* Adding single entry with/without value */
894 memset(&tent
, 0, sizeof(tent
));
898 if ((tent_buf
= calloc(count
, sizeof(tent
))) == NULL
)
900 "Unable to allocate memory for all entries");
904 memset(&xi
, 0, sizeof(xi
));
907 tentry_fill_key(oh
, ptent
, *av
, add
, &type
, &vmask
, &xi
);
910 * Compatibility layer: auto-create table if not exists.
912 if (xi
.tablename
[0] == '\0') {
915 strlcpy(xi
.tablename
, oh
->ntlv
.name
,
916 sizeof(xi
.tablename
));
917 fprintf(stderr
, "DEPRECATED: inserting data into "
918 "non-existent table %s. (auto-created)\n",
920 table_do_create(oh
, &xi
);
923 oh
->ntlv
.type
= type
;
926 if (add
!= 0 && ac
> 0) {
927 tentry_fill_value(oh
, ptent
, *av
, type
, vmask
);
932 ptent
->head
.flags
|= IPFW_TF_UPDATE
;
938 error
= table_do_modify_record(cmd
, oh
, tent_buf
, count
, atomic
);
943 * Compatibility stuff: do not yell on duplicate keys or
946 if (error
== 0 || (error
== EEXIST
&& add
!= 0) ||
947 (error
== ENOENT
&& add
== 0)) {
949 if (tent_buf
!= &tent
)
955 /* Report results back */
957 for (i
= 0; i
< count
; ptent
++, i
++) {
959 switch (ptent
->result
) {
963 case IPFW_TR_DELETED
:
966 case IPFW_TR_UPDATED
:
977 case IPFW_TR_NOTFOUND
:
985 case IPFW_TR_IGNORED
:
994 if (error
!= 0 && atomic
!= 0 && ignored
== 0)
995 printf("%s(reverted): ", px
);
999 table_show_entry(&xi
, ptent
);
1002 if (tent_buf
!= &tent
)
1007 /* Get real OS error */
1010 /* Try to provide more human-readable error */
1013 etxt
= "record already exists";
1019 etxt
= "table not found";
1022 etxt
= "record not found";
1025 etxt
= "table is locked";
1028 etxt
= strerror(error
);
1031 errx(EX_OSERR
, "%s: %s", texterr
, etxt
);
1035 table_do_lookup(ipfw_obj_header
*oh
, char *key
, ipfw_xtable_info
*xi
,
1036 ipfw_obj_tentry
*xtent
)
1038 char xbuf
[sizeof(ipfw_obj_header
) + sizeof(ipfw_obj_tentry
)];
1039 ipfw_obj_tentry
*tent
;
1044 memcpy(xbuf
, oh
, sizeof(*oh
));
1045 oh
= (ipfw_obj_header
*)xbuf
;
1046 tent
= (ipfw_obj_tentry
*)(oh
+ 1);
1048 memset(tent
, 0, sizeof(*tent
));
1049 tent
->head
.length
= sizeof(*tent
);
1052 tentry_fill_key(oh
, tent
, key
, 0, &type
, &vmask
, xi
);
1053 oh
->ntlv
.type
= type
;
1056 if (do_get3(IP_FW_TABLE_XFIND
, &oh
->opheader
, &sz
) != 0)
1059 if (sz
< sizeof(xbuf
))
1068 table_lookup(ipfw_obj_header
*oh
, int ac
, char *av
[])
1070 ipfw_obj_tentry xtent
;
1071 ipfw_xtable_info xi
;
1076 errx(EX_USAGE
, "address required");
1078 strlcpy(key
, *av
, sizeof(key
));
1080 memset(&xi
, 0, sizeof(xi
));
1081 error
= table_do_lookup(oh
, key
, &xi
, &xtent
);
1087 errx(EX_UNAVAILABLE
, "Table %s not found", oh
->ntlv
.name
);
1089 errx(EX_UNAVAILABLE
, "Entry %s not found", *av
);
1091 errx(EX_UNAVAILABLE
, "Table %s algo does not support "
1092 "\"lookup\" method", oh
->ntlv
.name
);
1094 err(EX_OSERR
, "getsockopt(IP_FW_TABLE_XFIND)");
1097 table_show_entry(&xi
, &xtent
);
1101 tentry_fill_key_type(char *arg
, ipfw_obj_tentry
*tentry
, uint8_t type
,
1106 struct in6_addr
*paddr
, tmp
;
1107 struct tflow_entry
*tfe
;
1108 uint32_t key
, *pkey
;
1110 struct protoent
*pent
;
1111 struct servent
*sent
;
1116 paddr
= (struct in6_addr
*)&tentry
->k
;
1119 case IPFW_TABLE_ADDR
:
1120 /* Remove / if exists */
1121 if ((p
= strchr(arg
, '/')) != NULL
) {
1126 if (inet_pton(AF_INET
, arg
, paddr
) == 1) {
1127 if (p
!= NULL
&& mask
> 32)
1128 errx(EX_DATAERR
, "bad IPv4 mask width: %s",
1131 masklen
= p
? mask
: 32;
1133 } else if (inet_pton(AF_INET6
, arg
, paddr
) == 1) {
1134 if (IN6_IS_ADDR_V4COMPAT(paddr
))
1136 "Use IPv4 instead of v4-compatible");
1137 if (p
!= NULL
&& mask
> 128)
1138 errx(EX_DATAERR
, "bad IPv6 mask width: %s",
1141 masklen
= p
? mask
: 128;
1145 if (lookup_host(arg
, (struct in_addr
*)paddr
) != 0)
1146 errx(EX_NOHOST
, "hostname ``%s'' unknown", arg
);
1149 type
= IPFW_TABLE_ADDR
;
1153 case IPFW_TABLE_INTERFACE
:
1154 /* Assume interface name. Copy significant data only */
1155 mask
= MIN(strlen(arg
), IF_NAMESIZE
- 1);
1156 memcpy(paddr
, arg
, mask
);
1157 /* Set mask to exact match */
1158 masklen
= 8 * IF_NAMESIZE
;
1160 case IPFW_TABLE_NUMBER
:
1161 /* Port or any other key */
1162 key
= strtol(arg
, &p
, 10);
1164 errx(EX_DATAERR
, "Invalid number: %s", arg
);
1166 pkey
= (uint32_t *)paddr
;
1170 case IPFW_TABLE_FLOW
:
1171 /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1172 tfe
= &tentry
->k
.flow
;
1175 /* Handle <ipv4|ipv6> */
1176 if ((tflags
& IPFW_TFFLAG_SRCIP
) != 0) {
1177 if ((p
= strchr(arg
, ',')) != NULL
)
1179 /* Determine family using temporary storage */
1180 if (inet_pton(AF_INET
, arg
, &tmp
) == 1) {
1181 if (af
!= 0 && af
!= AF_INET
)
1183 "Inconsistent address family\n");
1185 memcpy(&tfe
->a
.a4
.sip
, &tmp
, 4);
1186 } else if (inet_pton(AF_INET6
, arg
, &tmp
) == 1) {
1187 if (af
!= 0 && af
!= AF_INET6
)
1189 "Inconsistent address family\n");
1191 memcpy(&tfe
->a
.a6
.sip6
, &tmp
, 16);
1197 /* Handle <proto-num|proto-name> */
1198 if ((tflags
& IPFW_TFFLAG_PROTO
) != 0) {
1200 errx(EX_DATAERR
, "invalid key: proto missing");
1201 if ((p
= strchr(arg
, ',')) != NULL
)
1204 key
= strtol(arg
, &pp
, 10);
1206 if ((pent
= getprotobyname(arg
)) == NULL
)
1207 errx(EX_DATAERR
, "Unknown proto: %s",
1210 key
= pent
->p_proto
;
1214 errx(EX_DATAERR
, "Bad protocol number: %u",key
);
1221 /* Handle <port-num|service-name> */
1222 if ((tflags
& IPFW_TFFLAG_SRCPORT
) != 0) {
1224 errx(EX_DATAERR
, "invalid key: src port missing");
1225 if ((p
= strchr(arg
, ',')) != NULL
)
1228 if ((port
= htons(strtol(arg
, NULL
, 10))) == 0) {
1229 if ((sent
= getservbyname(arg
, NULL
)) == NULL
)
1230 errx(EX_DATAERR
, "Unknown service: %s",
1241 /* Handle <ipv4|ipv6>*/
1242 if ((tflags
& IPFW_TFFLAG_DSTIP
) != 0) {
1244 errx(EX_DATAERR
, "invalid key: dst ip missing");
1245 if ((p
= strchr(arg
, ',')) != NULL
)
1247 /* Determine family using temporary storage */
1248 if (inet_pton(AF_INET
, arg
, &tmp
) == 1) {
1249 if (af
!= 0 && af
!= AF_INET
)
1251 "Inconsistent address family");
1253 memcpy(&tfe
->a
.a4
.dip
, &tmp
, 4);
1254 } else if (inet_pton(AF_INET6
, arg
, &tmp
) == 1) {
1255 if (af
!= 0 && af
!= AF_INET6
)
1257 "Inconsistent address family");
1259 memcpy(&tfe
->a
.a6
.dip6
, &tmp
, 16);
1265 /* Handle <port-num|service-name> */
1266 if ((tflags
& IPFW_TFFLAG_DSTPORT
) != 0) {
1268 errx(EX_DATAERR
, "invalid key: dst port missing");
1269 if ((p
= strchr(arg
, ',')) != NULL
)
1272 if ((port
= htons(strtol(arg
, NULL
, 10))) == 0) {
1273 if ((sent
= getservbyname(arg
, NULL
)) == NULL
)
1274 errx(EX_DATAERR
, "Unknown service: %s",
1290 errx(EX_DATAERR
, "Unsupported table type: %d", type
);
1293 tentry
->subtype
= af
;
1294 tentry
->masklen
= masklen
;
1298 * Tries to guess table key type.
1299 * This procedure is used in legacy table auto-create
1300 * code AND in `ipfw -n` ruleset checking.
1302 * Imported from old table_fill_xentry() parse code.
1305 guess_key_type(char *key
, uint8_t *ptype
)
1308 struct in6_addr addr
;
1311 if (ishexnumber(*key
) != 0 || *key
== ':') {
1312 /* Remove / if exists */
1313 if ((p
= strchr(key
, '/')) != NULL
)
1316 if ((inet_pton(AF_INET
, key
, &addr
) == 1) ||
1317 (inet_pton(AF_INET6
, key
, &addr
) == 1)) {
1318 *ptype
= IPFW_TABLE_CIDR
;
1323 /* Port or any other key */
1324 /* Skip non-base 10 entries like 'fa1' */
1325 kv
= strtol(key
, &p
, 10);
1327 *ptype
= IPFW_TABLE_NUMBER
;
1329 } else if ((p
!= key
) && (*p
== '.')) {
1331 * Warn on IPv4 address strings
1332 * which are "valid" for inet_aton() but not
1335 * Typical examples: '10.5' or '10.0.0.05'
1342 if (strchr(key
, '.') == NULL
) {
1343 *ptype
= IPFW_TABLE_INTERFACE
;
1347 if (lookup_host(key
, (struct in_addr
*)&addr
) != 0)
1350 *ptype
= IPFW_TABLE_CIDR
;
1355 tentry_fill_key(ipfw_obj_header
*oh
, ipfw_obj_tentry
*tent
, char *key
,
1356 int add
, uint8_t *ptype
, uint32_t *pvmask
, ipfw_xtable_info
*xi
)
1358 uint8_t type
, tflags
;
1366 if (xi
->tablename
[0] == '\0')
1367 error
= table_get_info(oh
, xi
);
1372 if (co
.test_only
== 0) {
1375 tflags
= xi
->tflags
;
1379 * We're running `ipfw -n`
1380 * Compatibility layer: try to guess key type
1383 if (guess_key_type(key
, &type
) != 0) {
1385 errx(EX_USAGE
, "Cannot guess "
1386 "key '%s' type", key
);
1388 vmask
= IPFW_VTYPE_LEGACY
;
1392 errx(EX_OSERR
, "Error requesting table %s info",
1395 errx(EX_DATAERR
, "Table %s does not exist",
1398 * Table does not exist
1399 * Compatibility layer: try to guess key type before failing.
1401 if (guess_key_type(key
, &type
) != 0) {
1403 errx(EX_USAGE
, "Table %s does not exist, cannot guess "
1404 "key '%s' type", oh
->ntlv
.name
, key
);
1407 vmask
= IPFW_VTYPE_LEGACY
;
1410 tentry_fill_key_type(key
, tent
, type
, tflags
);
1417 set_legacy_value(uint32_t val
, ipfw_table_value
*v
)
1427 v
->dscp
= (uint8_t)val
;
1432 tentry_fill_value(ipfw_obj_header
*oh
, ipfw_obj_tentry
*tent
, char *arg
,
1433 uint8_t type
, uint32_t vmask
)
1435 struct addrinfo hints
, *res
;
1436 uint32_t a4
, flag
, val
;
1437 ipfw_table_value
*v
;
1440 char *comma
, *e
, *etype
, *n
, *p
;
1444 /* Compat layer: keep old behavior for legacy value types */
1445 if (vmask
== IPFW_VTYPE_LEGACY
) {
1446 /* Try to interpret as number first */
1447 val
= strtoul(arg
, &p
, 0);
1449 set_legacy_value(val
, v
);
1452 if (inet_pton(AF_INET
, arg
, &val
) == 1) {
1453 set_legacy_value(ntohl(val
), v
);
1457 if (lookup_host(arg
, (struct in_addr
*)&val
) == 0) {
1458 set_legacy_value(val
, v
);
1461 errx(EX_OSERR
, "Unable to parse value %s", arg
);
1465 * Shorthands: handle single value if vmask consists
1466 * of numbers only. e.g.:
1467 * vmask = "fib,skipto" -> treat input "1" as "1,1"
1472 for (i
= 1; i
< (1 << 31); i
*= 2) {
1473 if ((flag
= (vmask
& i
)) == 0)
1477 if ((comma
= strchr(n
, ',')) != NULL
)
1481 case IPFW_VTYPE_TAG
:
1482 v
->tag
= strtol(n
, &e
, 10);
1486 case IPFW_VTYPE_PIPE
:
1487 v
->pipe
= strtol(n
, &e
, 10);
1491 case IPFW_VTYPE_DIVERT
:
1492 v
->divert
= strtol(n
, &e
, 10);
1496 case IPFW_VTYPE_SKIPTO
:
1497 v
->skipto
= strtol(n
, &e
, 10);
1501 case IPFW_VTYPE_NETGRAPH
:
1502 v
->netgraph
= strtol(n
, &e
, 10);
1506 case IPFW_VTYPE_FIB
:
1507 v
->fib
= strtol(n
, &e
, 10);
1511 case IPFW_VTYPE_NAT
:
1512 v
->nat
= strtol(n
, &e
, 10);
1516 case IPFW_VTYPE_LIMIT
:
1517 v
->limit
= strtol(n
, &e
, 10);
1521 case IPFW_VTYPE_NH4
:
1522 if (strchr(n
, '.') != NULL
&&
1523 inet_pton(AF_INET
, n
, &a4
) == 1) {
1527 if (lookup_host(n
, (struct in_addr
*)&v
->nh4
) == 0)
1531 case IPFW_VTYPE_DSCP
:
1533 if ((dval
= match_token(f_ipdscp
, n
)) != -1) {
1537 etype
= "DSCP code";
1539 v
->dscp
= strtol(n
, &e
, 10);
1540 if (v
->dscp
> 63 || *e
!= '\0')
1541 etype
= "DSCP value";
1544 case IPFW_VTYPE_NH6
:
1545 if (strchr(n
, ':') != NULL
) {
1546 memset(&hints
, 0, sizeof(hints
));
1547 hints
.ai_family
= AF_INET6
;
1548 hints
.ai_flags
= AI_NUMERICHOST
;
1549 if (getaddrinfo(n
, NULL
, &hints
, &res
) == 0) {
1550 v
->nh6
= ((struct sockaddr_in6
*)
1551 res
->ai_addr
)->sin6_addr
;
1552 v
->zoneid
= ((struct sockaddr_in6
*)
1553 res
->ai_addr
)->sin6_scope_id
;
1563 errx(EX_USAGE
, "Unable to parse %s as %s", n
, etype
);
1568 if ((n
= comma
) != NULL
)
1573 errx(EX_USAGE
, "Not enough fields inside value");
1578 * Compare table names.
1579 * Honor number comparison.
1582 tablename_cmp(const void *a
, const void *b
)
1584 ipfw_xtable_info
*ia
, *ib
;
1586 ia
= (ipfw_xtable_info
*)a
;
1587 ib
= (ipfw_xtable_info
*)b
;
1589 return (stringnum_cmp(ia
->tablename
, ib
->tablename
));
1593 * Retrieves table list from kernel,
1594 * optionally sorts it and calls requested function for each table.
1595 * Returns 0 on success.
1598 tables_foreach(table_cb_t
*f
, void *arg
, int sort
)
1600 ipfw_obj_lheader
*olh
;
1601 ipfw_xtable_info
*info
;
1605 /* Start with reasonable default */
1606 sz
= sizeof(*olh
) + 16 * sizeof(ipfw_xtable_info
);
1609 if ((olh
= calloc(1, sz
)) == NULL
)
1613 if (do_get3(IP_FW_TABLES_XLIST
, &olh
->opheader
, &sz
) != 0) {
1616 if (errno
!= ENOMEM
)
1622 qsort(olh
+ 1, olh
->count
, olh
->objsize
, tablename_cmp
);
1624 info
= (ipfw_xtable_info
*)(olh
+ 1);
1625 for (i
= 0; i
< olh
->count
; i
++) {
1626 error
= f(info
, arg
); /* Ignore errors for now */
1627 info
= (ipfw_xtable_info
*)((caddr_t
)info
+ olh
->objsize
);
1639 * Retrieves all entries for given table @i in
1640 * eXtended format. Allocate buffer large enough
1641 * to store result. Called needs to free it later.
1643 * Returns 0 on success.
1646 table_do_get_list(ipfw_xtable_info
*i
, ipfw_obj_header
**poh
)
1648 ipfw_obj_header
*oh
;
1654 for (c
= 0; c
< 8; c
++) {
1659 if ((oh
= calloc(1, sz
)) == NULL
)
1661 table_fill_objheader(oh
, i
);
1662 oh
->opheader
.version
= 1; /* Current version */
1663 if (do_get3(IP_FW_TABLE_XLIST
, &oh
->opheader
, &sz
) == 0) {
1668 if (errno
!= ENOMEM
)
1677 * Shows all entries from @oh in human-readable format
1680 table_show_list(ipfw_obj_header
*oh
, int need_header
)
1682 ipfw_obj_tentry
*tent
;
1684 ipfw_xtable_info
*i
;
1686 i
= (ipfw_xtable_info
*)(oh
+ 1);
1687 tent
= (ipfw_obj_tentry
*)(i
+ 1);
1690 printf("--- table(%s), set(%u) ---\n", i
->tablename
, i
->set
);
1694 table_show_entry(i
, tent
);
1695 tent
= (ipfw_obj_tentry
*)((caddr_t
)tent
+ tent
->head
.length
);
1701 table_show_value(char *buf
, size_t bufsize
, ipfw_table_value
*v
,
1702 uint32_t vmask
, int print_ip
)
1704 char abuf
[INET6_ADDRSTRLEN
+ IF_NAMESIZE
+ 2];
1705 struct sockaddr_in6 sa6
;
1706 uint32_t flag
, i
, l
;
1713 * Some shorthands for printing values:
1714 * legacy assumes all values are equal, so keep the first one.
1716 if (vmask
== IPFW_VTYPE_LEGACY
) {
1717 if (print_ip
!= 0) {
1718 flag
= htonl(v
->tag
);
1719 inet_ntop(AF_INET
, &flag
, buf
, sz
);
1721 snprintf(buf
, sz
, "%u", v
->tag
);
1725 for (i
= 1; i
< (1 << 31); i
*= 2) {
1726 if ((flag
= (vmask
& i
)) == 0)
1731 case IPFW_VTYPE_TAG
:
1732 l
= snprintf(buf
, sz
, "%u,", v
->tag
);
1734 case IPFW_VTYPE_PIPE
:
1735 l
= snprintf(buf
, sz
, "%u,", v
->pipe
);
1737 case IPFW_VTYPE_DIVERT
:
1738 l
= snprintf(buf
, sz
, "%d,", v
->divert
);
1740 case IPFW_VTYPE_SKIPTO
:
1741 l
= snprintf(buf
, sz
, "%d,", v
->skipto
);
1743 case IPFW_VTYPE_NETGRAPH
:
1744 l
= snprintf(buf
, sz
, "%u,", v
->netgraph
);
1746 case IPFW_VTYPE_FIB
:
1747 l
= snprintf(buf
, sz
, "%u,", v
->fib
);
1749 case IPFW_VTYPE_NAT
:
1750 l
= snprintf(buf
, sz
, "%u,", v
->nat
);
1752 case IPFW_VTYPE_LIMIT
:
1753 l
= snprintf(buf
, sz
, "%u,", v
->limit
);
1755 case IPFW_VTYPE_NH4
:
1756 a4
.s_addr
= htonl(v
->nh4
);
1757 inet_ntop(AF_INET
, &a4
, abuf
, sizeof(abuf
));
1758 l
= snprintf(buf
, sz
, "%s,", abuf
);
1760 case IPFW_VTYPE_DSCP
:
1761 l
= snprintf(buf
, sz
, "%d,", v
->dscp
);
1763 case IPFW_VTYPE_NH6
:
1764 sa6
.sin6_family
= AF_INET6
;
1765 sa6
.sin6_len
= sizeof(sa6
);
1766 sa6
.sin6_addr
= v
->nh6
;
1768 sa6
.sin6_scope_id
= v
->zoneid
;
1769 if (getnameinfo((const struct sockaddr
*)&sa6
,
1770 sa6
.sin6_len
, abuf
, sizeof(abuf
), NULL
, 0,
1771 NI_NUMERICHOST
) == 0)
1772 l
= snprintf(buf
, sz
, "%s,", abuf
);
1785 table_show_entry(ipfw_xtable_info
*i
, ipfw_obj_tentry
*tent
)
1787 char *comma
, tbuf
[128], pval
[128];
1789 struct tflow_entry
*tfe
;
1791 table_show_value(pval
, sizeof(pval
), &tent
->v
.value
, i
->vmask
,
1795 case IPFW_TABLE_ADDR
:
1796 /* IPv4 or IPv6 prefixes */
1797 inet_ntop(tent
->subtype
, &tent
->k
, tbuf
, sizeof(tbuf
));
1798 printf("%s/%u %s\n", tbuf
, tent
->masklen
, pval
);
1800 case IPFW_TABLE_INTERFACE
:
1801 /* Interface names */
1802 printf("%s %s\n", tent
->k
.iface
, pval
);
1804 case IPFW_TABLE_NUMBER
:
1806 printf("%u %s\n", tent
->k
.key
, pval
);
1808 case IPFW_TABLE_FLOW
:
1810 tfe
= &tent
->k
.flow
;
1813 if ((i
->tflags
& IPFW_TFFLAG_SRCIP
) != 0) {
1814 if (tfe
->af
== AF_INET
)
1815 paddr
= &tfe
->a
.a4
.sip
;
1817 paddr
= &tfe
->a
.a6
.sip6
;
1819 inet_ntop(tfe
->af
, paddr
, tbuf
, sizeof(tbuf
));
1820 printf("%s%s", comma
, tbuf
);
1824 if ((i
->tflags
& IPFW_TFFLAG_PROTO
) != 0) {
1825 printf("%s%d", comma
, tfe
->proto
);
1829 if ((i
->tflags
& IPFW_TFFLAG_SRCPORT
) != 0) {
1830 printf("%s%d", comma
, ntohs(tfe
->sport
));
1833 if ((i
->tflags
& IPFW_TFFLAG_DSTIP
) != 0) {
1834 if (tfe
->af
== AF_INET
)
1835 paddr
= &tfe
->a
.a4
.dip
;
1837 paddr
= &tfe
->a
.a6
.dip6
;
1839 inet_ntop(tfe
->af
, paddr
, tbuf
, sizeof(tbuf
));
1840 printf("%s%s", comma
, tbuf
);
1844 if ((i
->tflags
& IPFW_TFFLAG_DSTPORT
) != 0) {
1845 printf("%s%d", comma
, ntohs(tfe
->dport
));
1849 printf(" %s\n", pval
);
1854 table_do_get_stdlist(uint16_t opcode
, ipfw_obj_lheader
**polh
)
1856 ipfw_obj_lheader req
, *olh
;
1859 memset(&req
, 0, sizeof(req
));
1862 if (do_get3(opcode
, &req
.opheader
, &sz
) != 0)
1863 if (errno
!= ENOMEM
)
1867 if ((olh
= calloc(1, sz
)) == NULL
)
1871 if (do_get3(opcode
, &olh
->opheader
, &sz
) != 0) {
1881 table_do_get_algolist(ipfw_obj_lheader
**polh
)
1884 return (table_do_get_stdlist(IP_FW_TABLES_ALIST
, polh
));
1888 table_do_get_vlist(ipfw_obj_lheader
**polh
)
1891 return (table_do_get_stdlist(IP_FW_TABLE_VLIST
, polh
));
1895 ipfw_list_ta(int ac
, char *av
[])
1897 ipfw_obj_lheader
*olh
;
1902 error
= table_do_get_algolist(&olh
);
1904 err(EX_OSERR
, "Unable to request algorithm list");
1906 info
= (ipfw_ta_info
*)(olh
+ 1);
1907 for (i
= 0; i
< olh
->count
; i
++) {
1908 if ((atype
= match_value(tabletypes
, info
->type
)) == NULL
)
1910 printf("--- %s ---\n", info
->algoname
);
1911 printf(" type: %s\n refcount: %u\n", atype
, info
->refcnt
);
1913 info
= (ipfw_ta_info
*)((caddr_t
)info
+ olh
->objsize
);
1920 /* Copy of current kernel table_value structure */
1921 struct _table_value
{
1922 uint32_t tag
; /* O_TAG/O_TAGGED */
1923 uint32_t pipe
; /* O_PIPE/O_QUEUE */
1924 uint16_t divert
; /* O_DIVERT/O_TEE */
1925 uint16_t skipto
; /* skipto, CALLRET */
1926 uint32_t netgraph
; /* O_NETGRAPH/O_NGTEE */
1927 uint32_t fib
; /* O_SETFIB */
1928 uint32_t nat
; /* O_NAT */
1933 /* -- 32 bytes -- */
1934 struct in6_addr nh6
;
1935 uint32_t limit
; /* O_LIMIT */
1937 uint64_t refcnt
; /* Number of references */
1941 compare_values(const void *_a
, const void *_b
)
1943 struct _table_value
*a
, *b
;
1945 a
= (struct _table_value
*)_a
;
1946 b
= (struct _table_value
*)_b
;
1948 if (a
->spare1
< b
->spare1
)
1950 else if (a
->spare1
> b
->spare1
)
1957 ipfw_list_values(int ac
, char *av
[])
1959 ipfw_obj_lheader
*olh
;
1960 struct _table_value
*v
;
1965 error
= table_do_get_vlist(&olh
);
1967 err(EX_OSERR
, "Unable to request value list");
1969 vmask
= 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */
1971 table_print_valheader(buf
, sizeof(buf
), vmask
);
1972 printf("HEADER: %s\n", buf
);
1973 v
= (struct _table_value
*)(olh
+ 1);
1974 qsort(v
, olh
->count
, olh
->objsize
, compare_values
);
1975 for (i
= 0; i
< olh
->count
; i
++) {
1976 table_show_value(buf
, sizeof(buf
), (ipfw_table_value
*)v
,
1978 printf("[%u] refs=%lu %s\n", v
->spare1
, (u_long
)v
->refcnt
, buf
);
1979 v
= (struct _table_value
*)((caddr_t
)v
+ olh
->objsize
);
1986 table_check_name(const char *tablename
)
1989 if (ipfw_check_object_name(tablename
) != 0)
1991 /* Restrict some 'special' names */
1992 if (strcmp(tablename
, "all") == 0)