]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add support for base hook dumping
authorFlorian Westphal <fw@strlen.de>
Wed, 27 Jan 2021 13:29:50 +0000 (14:29 +0100)
committerFlorian Westphal <fw@strlen.de>
Wed, 9 Jun 2021 21:19:11 +0000 (23:19 +0200)
Example output:
$ nft list hook ip input
family ip hook input {
        +0000000000 nft_do_chain_inet [nf_tables]       # nft table ip filter chain input
        +0000000010 nft_do_chain_inet [nf_tables]       # nft table ip firewalld chain filter_INPUT
        +0000000100 nf_nat_ipv4_local_in [nf_nat]
        +2147483647 ipv4_confirm [nf_conntrack]
}

$ nft list hooks netdev type ingress device lo
family netdev hook ingress device lo {
        +0000000000 nft_do_chain_netdev [nf_tables]
}

$ nft list hooks inet
family ip hook prerouting {
        -0000000400 ipv4_conntrack_defrag [nf_defrag_ipv4]
        -0000000300 iptable_raw_hook [iptable_raw]
        -0000000290 nft_do_chain_inet [nf_tables]       # nft table ip firewalld chain raw_PREROUTING
        -0000000200 ipv4_conntrack_in [nf_conntrack]
        -0000000140 nft_do_chain_inet [nf_tables]       # nft table ip firewalld chain mangle_PREROUTING
        -0000000100 nf_nat_ipv4_pre_routing [nf_nat]
}
...

'nft list hooks' will display everyting except the netdev family
via successive dump request for all family:hook combinations.

Signed-off-by: Florian Westphal <fw@strlen.de>
include/linux/netfilter/nfnetlink.h
include/linux/netfilter/nfnetlink_hook.h [new file with mode: 0644]
include/mnl.h
include/rule.h
src/evaluate.c
src/mnl.c
src/parser_bison.y
src/rule.c
src/scanner.l

index 454f78d0af0ad719c1dcec4bba5c5f12fa951d73..49e2b2c508a8ac5765e5dfe79b195613f135b6f9 100644 (file)
@@ -59,7 +59,8 @@ struct nfgenmsg {
 #define NFNL_SUBSYS_CTHELPER           9
 #define NFNL_SUBSYS_NFTABLES           10
 #define NFNL_SUBSYS_NFT_COMPAT         11
-#define NFNL_SUBSYS_COUNT              12
+#define NFNL_SUBSYS_HOOK               12
+#define NFNL_SUBSYS_COUNT              13
 
 /* Reserved control nfnetlink messages */
 #define NFNL_MSG_BATCH_BEGIN           NLMSG_MIN_TYPE
diff --git a/include/linux/netfilter/nfnetlink_hook.h b/include/linux/netfilter/nfnetlink_hook.h
new file mode 100644 (file)
index 0000000..d8ac827
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NFNL_HOOK_H_
+#define _NFNL_HOOK_H_
+
+enum nfnl_hook_msg_types {
+       NFNL_MSG_HOOK_GET,
+       NFNL_MSG_HOOK_MAX,
+};
+
+/**
+ * enum nfnl_hook_attributes - nf_tables netfilter hook netlink attributes
+ *
+ * @NFNLA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
+ * @NFNLAA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ * @NFNLA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFNLA_HOOK_FUNCTION_NAME: hook function name (NLA_STRING)
+ * @NFNLA_HOOK_MODULE_NAME: kernel module that registered this hook (NLA_STRING)
+ * @NFNLA_HOOK_CHAIN_INFO: basechain hook metadata (NLA_NESTED)
+ */
+enum nfnl_hook_attributes {
+       NFNLA_HOOK_UNSPEC,
+       NFNLA_HOOK_HOOKNUM,
+       NFNLA_HOOK_PRIORITY,
+       NFNLA_HOOK_DEV,
+       NFNLA_HOOK_FUNCTION_NAME,
+       NFNLA_HOOK_MODULE_NAME,
+       NFNLA_HOOK_CHAIN_INFO,
+       __NFNLA_HOOK_MAX
+};
+#define NFNLA_HOOK_MAX         (__NFNLA_HOOK_MAX - 1)
+
+/**
+ * enum nfnl_hook_chain_info_attributes - chain description
+ *
+ * NFNLA_HOOK_INFO_DESC: nft chain and table name (enum nft_table_attributes) (NLA_NESTED)
+ * NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32)
+ */
+enum nfnl_hook_chain_info_attributes {
+       NFNLA_HOOK_INFO_UNSPEC,
+       NFNLA_HOOK_INFO_DESC,
+       NFNLA_HOOK_INFO_TYPE,
+       __NFNLA_HOOK_INFO_MAX,
+};
+#define NFNLA_HOOK_INFO_MAX (__NFNLA_HOOK_INFO_MAX - 1)
+
+/**
+ * enum nfnl_hook_chaintype - chain type
+ *
+ * @NFNL_HOOK_TYPE_NFTABLES nf_tables base chain
+ */
+enum nfnl_hook_chaintype {
+       NFNL_HOOK_TYPE_NFTABLES = 0x1,
+};
+#endif /* _NFNL_HOOK_H */
index 979929c31c17bfcc5b9c34e384830c0eb461b615..68ec80cd22821703b37ee9fc3f15e062e650873c 100644 (file)
@@ -82,6 +82,9 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
                          unsigned int flags);
 int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd);
 
+int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, int hook,
+                         const char *devname);
+
 int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
                           struct output_ctx *octx,
                           int (*cb)(const struct nlmsghdr *nlh, void *data),
index f469db55bf601ddc8f1a9f6eeb6f4bbb517487e3..357326a3fcebb1732cc79d8fd1ac352307821fe7 100644 (file)
@@ -644,6 +644,7 @@ enum cmd_obj {
        CMD_OBJ_CT_EXPECT,
        CMD_OBJ_SYNPROXY,
        CMD_OBJ_SYNPROXYS,
+       CMD_OBJ_HOOKS,
 };
 
 struct markup {
index 2ed68aad03928706ee40e7d6e37c319018bf3068..43f1f8a3977b25c899fe9d72d85958dc82848f23 100644 (file)
@@ -4719,6 +4719,16 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
        case CMD_OBJ_METERS:
        case CMD_OBJ_MAPS:
                return 0;
+       case CMD_OBJ_HOOKS:
+               if (cmd->handle.chain.name) {
+                       int hooknum = str2hooknum(cmd->handle.family, cmd->handle.chain.name);
+
+                       if (hooknum == NF_INET_NUMHOOKS)
+                               return chain_not_found(ctx);
+
+                       cmd->handle.chain_id = hooknum;
+               }
+               return 0;
        default:
                BUG("invalid command object type %u\n", cmd->obj);
        }
index ef45cbd193f9ac7da0ac22ef07a3fbe9d3aee659..ce58ae7219ecc92880412ced3c478f020e6eace0 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -22,6 +22,7 @@
 #include <libnftnl/udata.h>
 
 #include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_hook.h>
 #include <linux/netfilter/nf_tables.h>
 
 #include <mnl.h>
 #include <stdlib.h>
 #include <utils.h>
 #include <nftables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+
+struct basehook {
+       struct list_head list;
+       const char *module_name;
+       const char *hookfn;
+       const char *table;
+       const char *chain;
+       int prio;
+};
 
 struct mnl_socket *nft_mnl_socket_open(void)
 {
@@ -1874,7 +1886,7 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
                           void *cb_data)
 {
        /* Set netlink socket buffer size to 16 Mbytes to reduce chances of
-        * message loss due to ENOBUFS.
+        * message loss due to ENOBUFS.
         */
        unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ;
        int fd = mnl_socket_get_fd(nf_sock);
@@ -1918,3 +1930,317 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
        }
        return ret;
 }
+
+static struct basehook *basehook_alloc(void)
+{
+       return xzalloc(sizeof(struct basehook));
+}
+
+static void basehook_free(struct basehook *b)
+{
+       list_del(&b->list);
+       xfree(b->module_name);
+       xfree(b->hookfn);
+       xfree(b->chain);
+       xfree(b->table);
+       xfree(b);
+}
+
+static void basehook_list_add_tail(struct basehook *b, struct list_head *head)
+{
+       list_add_tail(&b->list, head);
+}
+
+static int dump_nf_attr_cb(const struct nlattr *attr, void *data)
+{
+       int type = mnl_attr_get_type(attr);
+       const struct nlattr **tb = data;
+
+       if (mnl_attr_type_valid(attr, NFNLA_HOOK_MAX) < 0)
+               return MNL_CB_OK;
+
+       switch(type) {
+       case NFNLA_HOOK_HOOKNUM:
+       case NFNLA_HOOK_PRIORITY:
+                if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       case NFNLA_HOOK_DEV:
+                if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       case NFNLA_HOOK_MODULE_NAME:
+       case NFNLA_HOOK_FUNCTION_NAME:
+                if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       case NFNLA_HOOK_CHAIN_INFO:
+                if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       default:
+               return MNL_CB_OK;
+       }
+
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int dump_nf_chain_info_cb(const struct nlattr *attr, void *data)
+{
+       int type = mnl_attr_get_type(attr);
+       const struct nlattr **tb = data;
+
+       if (mnl_attr_type_valid(attr, NFNLA_HOOK_INFO_MAX) < 0)
+               return MNL_CB_OK;
+
+       switch(type) {
+       case NFNLA_HOOK_INFO_DESC:
+                if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       case NFNLA_HOOK_INFO_TYPE:
+                if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       default:
+               return MNL_CB_OK;
+       }
+
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int dump_nf_attr_chain_cb(const struct nlattr *attr, void *data)
+{
+       int type = mnl_attr_get_type(attr);
+       const struct nlattr **tb = data;
+
+       if (mnl_attr_type_valid(attr, NFTA_CHAIN_MAX) < 0)
+               return MNL_CB_OK;
+
+       switch(type) {
+       case NFTA_CHAIN_TABLE:
+       case NFTA_CHAIN_NAME:
+                if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+                        return MNL_CB_ERROR;
+               break;
+       default:
+               return MNL_CB_OK;
+       }
+
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int dump_nf_hooks(const struct nlmsghdr *nlh, void *data)
+{
+       const struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+       struct nlattr *tb[NFNLA_HOOK_MAX + 1] = {};
+       struct list_head *head = data;
+       struct basehook *hook;
+
+       /* NB: Don't check the nft generation ID, this is not
+        * an nftables subsystem.
+        */
+       if (mnl_attr_parse(nlh, sizeof(*nfg), dump_nf_attr_cb, tb) < 0)
+               return -1;
+
+       if (!tb[NFNLA_HOOK_PRIORITY])
+               netlink_abi_error();
+
+       hook = basehook_alloc();
+       hook->prio = ntohl(mnl_attr_get_u32(tb[NFNLA_HOOK_PRIORITY]));
+
+       if (tb[NFNLA_HOOK_FUNCTION_NAME])
+               hook->hookfn = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_FUNCTION_NAME]));
+
+       if (tb[NFNLA_HOOK_MODULE_NAME])
+               hook->module_name = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_MODULE_NAME]));
+
+       if (tb[NFNLA_HOOK_CHAIN_INFO]) {
+               struct nlattr *nested[NFNLA_HOOK_INFO_MAX + 1] = {};
+               uint32_t type;
+
+               if (mnl_attr_parse_nested(tb[NFNLA_HOOK_CHAIN_INFO], dump_nf_chain_info_cb, nested) < 0)
+                       return -1;
+
+               type = ntohl(mnl_attr_get_u32(nested[NFNLA_HOOK_INFO_TYPE]));
+               if (type == NFNL_HOOK_TYPE_NFTABLES) {
+                       struct nlattr *info[NFTA_CHAIN_MAX + 1] = {};
+                       const char *tablename, *chainname;
+
+                       if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC], dump_nf_attr_chain_cb, info) < 0)
+                               return -1;
+
+                       tablename = mnl_attr_get_str(info[NFTA_CHAIN_TABLE]);
+                       chainname = mnl_attr_get_str(info[NFTA_CHAIN_NAME]);
+                       if (tablename && chainname) {
+                               hook->table = xstrdup(tablename);
+                               hook->chain = xstrdup(chainname);
+                       }
+               }
+       }
+
+       basehook_list_add_tail(hook, head);
+       return MNL_CB_OK;
+}
+
+static struct nlmsghdr *nf_hook_dump_request(char *buf, uint8_t family, uint32_t seq)
+{
+       struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+       struct nfgenmsg *nfg;
+
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       nlh->nlmsg_type = NFNL_SUBSYS_HOOK << 8;
+       nlh->nlmsg_seq = seq;
+
+       nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+       nfg->nfgen_family = family;
+       nfg->version = NFNETLINK_V0;
+
+       return nlh;
+}
+
+static int __mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, uint8_t family, uint8_t hooknum, const char *devname)
+{
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct basehook *hook, *tmp;
+       struct nlmsghdr *nlh;
+       LIST_HEAD(hook_list);
+       FILE *fp;
+       int ret;
+
+       nlh = nf_hook_dump_request(buf, family, ctx->seqnum);
+       if (devname)
+               mnl_attr_put_strz(nlh, NFNLA_HOOK_DEV, devname);
+
+       mnl_attr_put_u32(nlh, NFNLA_HOOK_HOOKNUM, htonl(hooknum));
+
+       ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, dump_nf_hooks, &hook_list);
+       if (ret)
+               return ret;
+
+       if (list_empty(&hook_list))
+               return 0;
+
+       fp = ctx->nft->output.output_fp;
+       fprintf(fp, "family %s hook %s", family2str(family), hooknum2str(family, hooknum));
+       if (devname)
+               fprintf(fp, " device %s", devname);
+
+       fprintf(fp, " {\n");
+
+       list_for_each_entry_safe(hook, tmp, &hook_list, list) {
+               int prio = hook->prio;
+
+               if (prio < 0)
+                       fprintf(fp, "\t%011d", prio); /* outputs a '-' sign */
+               else
+                       fprintf(fp, "\t+%010u", prio);
+
+               if (hook->hookfn) {
+                       fprintf(fp, " %s", hook->hookfn);
+                       if (hook->module_name)
+                               fprintf(fp, " [%s]", hook->module_name);
+               }
+
+               if (hook->table && hook->chain)
+                       fprintf(fp, "\t# nft table %s %s chain %s", family2str(family), hook->table, hook->chain);
+
+               fprintf(fp, "\n");
+               basehook_free(hook);
+       }
+
+       fprintf(fp, "}\n");
+       return ret;
+}
+
+int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, int hook, const char *devname)
+{
+       unsigned int i;
+       int ret, err;
+
+       errno = 0;
+       ret = 0;
+
+       switch (family) {
+       case NFPROTO_UNSPEC:
+               if (devname)
+                       return mnl_nft_dump_nf_hooks(ctx, NFPROTO_NETDEV, NF_INET_INGRESS, devname);
+
+               err = mnl_nft_dump_nf_hooks(ctx, NFPROTO_INET, hook, NULL);
+               if (err < 0 && errno != EPROTONOSUPPORT)
+                       ret = err;
+               err = mnl_nft_dump_nf_hooks(ctx, NFPROTO_ARP, hook, NULL);
+               if (err < 0 && errno != EPROTONOSUPPORT)
+                       ret = err;
+               err = mnl_nft_dump_nf_hooks(ctx, NFPROTO_BRIDGE, hook, NULL);
+               if (err < 0 && errno != EPROTONOSUPPORT)
+                       ret = err;
+               err = mnl_nft_dump_nf_hooks(ctx, NFPROTO_DECNET, hook, NULL);
+               if (err < 0 && errno != EPROTONOSUPPORT)
+                       ret = err;
+               break;
+       case NFPROTO_INET:
+               if (devname) {
+                       err = __mnl_nft_dump_nf_hooks(ctx, family, NF_INET_INGRESS, devname);
+                       if (err < 0)
+                               ret = err;
+               }
+
+               err = mnl_nft_dump_nf_hooks(ctx, NFPROTO_IPV4, hook, NULL);
+               if (err < 0)
+                       ret = err;
+               err = mnl_nft_dump_nf_hooks(ctx, NFPROTO_IPV6, hook, NULL);
+               if (err < 0)
+                       ret = err;
+
+               break;
+       case NFPROTO_IPV4:
+       case NFPROTO_IPV6:
+       case NFPROTO_BRIDGE:
+               if (hook >= 0)
+                       return __mnl_nft_dump_nf_hooks(ctx, family, hook, devname);
+
+               for (i = 0; i <= NF_INET_POST_ROUTING; i++) {
+                       err = __mnl_nft_dump_nf_hooks(ctx, family, i, NULL);
+                       if (err < 0)
+                               err = ret;
+               }
+               break;
+       case NFPROTO_ARP:
+               if (hook >= 0)
+                       return __mnl_nft_dump_nf_hooks(ctx, family, hook, devname);
+
+               err = __mnl_nft_dump_nf_hooks(ctx, family, NF_ARP_IN, devname);
+               if (err < 0)
+                       ret = err;
+               err = __mnl_nft_dump_nf_hooks(ctx, family, NF_ARP_OUT, devname);
+               if (err < 0)
+                       ret = err;
+               break;
+       case NFPROTO_NETDEV:
+               if (hook >= 0)
+                       return __mnl_nft_dump_nf_hooks(ctx, family, hook, devname);
+
+               err = __mnl_nft_dump_nf_hooks(ctx, family, NF_INET_INGRESS, devname);
+               if (err < 0)
+                       ret = err;
+               break;
+       case NFPROTO_DECNET:
+               if (hook >= 0)
+                       return __mnl_nft_dump_nf_hooks(ctx, family, hook, devname);
+#define NF_DN_NUMHOOKS         7
+               for (i = 0; i < NF_DN_NUMHOOKS; i++) {
+                       err = __mnl_nft_dump_nf_hooks(ctx, family, i, devname);
+                       if (err < 0) {
+                               ret = err;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       return ret;
+}
index f6c92feb76616111eed399e6494ae2a116afcc99..136ae105f5132a163f06804e60ce36b9643a307a 100644 (file)
@@ -238,6 +238,7 @@ int nft_lex(void *, void *, void *);
 %token TYPEOF                  "typeof"
 
 %token HOOK                    "hook"
+%token HOOKS                   "hooks"
 %token DEVICE                  "device"
 %token DEVICES                 "devices"
 %token TABLE                   "table"
@@ -632,11 +633,15 @@ int nft_lex(void *, void *, void *);
 
 %type <handle>                 set_identifier flowtableid_spec flowtable_identifier obj_identifier
 %destructor { handle_free(&$$); } set_identifier flowtableid_spec obj_identifier
+
+%type <handle>                 basehook_spec
+%destructor { handle_free(&$$); } basehook_spec
+
 %type <val>                    family_spec family_spec_explicit
 %type <val32>                  int_num chain_policy
 %type <prio_spec>              extended_prio_spec prio_spec
-%type <string>                 extended_prio_name quota_unit
-%destructor { xfree($$); }     extended_prio_name quota_unit
+%type <string>                 extended_prio_name quota_unit   basehook_device_name
+%destructor { xfree($$); }     extended_prio_name quota_unit   basehook_device_name
 
 %type <expr>                   dev_spec
 %destructor { xfree($$); }     dev_spec
@@ -1456,6 +1461,45 @@ list_cmd         :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_LIST, $2, &$4, &@$, NULL);
                        }
+                       |       HOOKS   basehook_spec
+                       {
+                               $$ = cmd_alloc(CMD_LIST, CMD_OBJ_HOOKS, &$2, &@$, NULL);
+                       }
+                       ;
+
+basehook_device_name   :       /* NULL */
+                       {
+                               $$ = NULL;
+                       }
+                       |       DEVICE STRING
+                       {
+                               $$ = $2;
+                       }
+                       ;
+
+basehook_spec          :       ruleset_spec
+                       {
+                               $$ = $1;
+                       }
+                       |       ruleset_spec    STRING  basehook_device_name
+                       {
+                               const char *name = chain_hookname_lookup($2);
+
+                               if (name == NULL) {
+                                       erec_queue(error(&@2, "unknown chain hook"),
+                                                  state->msgs);
+                                       xfree($3);
+                                       YYERROR;
+                               }
+
+                               $1.chain.name = $2;
+                               $1.chain.location = @2;
+                               if ($3) {
+                                       $1.obj.name = $3;
+                                       $1.obj.location = @3;
+                               }
+                               $$ = $1;
+                       }
                        ;
 
 reset_cmd              :       COUNTERS        ruleset_spec
index 8e426c5f2fddcd4952e4ada1e7931dcaf207d45f..dbbe744eee0d84a04618645a088040305b9d0aa9 100644 (file)
@@ -2371,6 +2371,17 @@ static int do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
        return 0;
 }
 
+static int do_list_hooks(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+       const char *devname = cmd->handle.obj.name;
+       int hooknum = -1;
+
+       if (cmd->handle.chain.name)
+               hooknum = cmd->handle.chain_id;
+
+       return mnl_nft_dump_nf_hooks(ctx, cmd->handle.family, hooknum, devname);
+}
+
 static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
 {
        struct table *table = NULL;
@@ -2431,6 +2442,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
                return do_list_flowtable(ctx, cmd, table);
        case CMD_OBJ_FLOWTABLES:
                return do_list_flowtables(ctx, cmd);
+       case CMD_OBJ_HOOKS:
+               return do_list_hooks(ctx, cmd);
        default:
                BUG("invalid command object type %u\n", cmd->obj);
        }
index c1bc21aa7ecc387e116d027d94d573938a3e42ec..6dc1be8908cfa673300ae79ab3fca5359738ecf2 100644 (file)
@@ -354,6 +354,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
        "limits"                { return LIMITS; }
        "secmarks"              { return SECMARKS; }
        "synproxys"             { return SYNPROXYS; }
+       "hooks"                 { return HOOKS; }
 }
 
 "counter"              { scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; }