]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add netdev family support
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 4 Jun 2015 18:58:59 +0000 (20:58 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 16 Jun 2015 16:22:43 +0000 (18:22 +0200)
This patch adds support for the new 'netdev' table. So far, this table allows
you to create filter chains from ingress.

The following example shows a very simple base configuration with one table that
contains a basechain that is attached to the 'eth0':

 # nft list table netdev filter
 table netdev filter {
        chain eth0-ingress {
                type filter hook ingress device eth0 priority 0; policy accept;
        }
 }

You can test that this works by adding a simple rule with counters:

 # nft add rule netdev filter eth0-ingress counter

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
doc/nft.xml
include/linux/netfilter.h
include/rule.h
src/evaluate.c
src/netlink.c
src/parser_bison.y
src/payload.c
src/proto.c
src/rule.c
src/scanner.l

index 8d79016c1f777c5728c2644b1e6ce83f325eb305..d51876cd1b7252c8f0cb416da850485f9ff8b7f5 100644 (file)
@@ -267,6 +267,14 @@ filter input iif $int_ifs accept
                                                </para>
                                        </listitem>
                                </varlistentry>
+                               <varlistentry>
+                                       <term><option>netdev</option></term>
+                                       <listitem>
+                                               <para>
+                                                       Netdev address family, handling packets from ingress.
+                                               </para>
+                                       </listitem>
+                               </varlistentry>
                        </variablelist>
                </para>
                <para>
@@ -373,6 +381,38 @@ filter input iif $int_ifs accept
                                The bridge address family handles ethernet packets traversing bridge devices.
                        </para>
                </refsect2>
+               <refsect2>
+                       <title>Netdev address family</title>
+                       <para>
+                               The Netdev address family handles packets from ingress.
+                       </para>
+                       <para>
+                               <table frame="all">
+                                       <title>Netdev address family hooks</title>
+                                       <tgroup cols='2' align='left' colsep='1' rowsep='1' pgwide="1">
+                                               <colspec colname='c1' colwidth="1*"/>
+                                               <colspec colname='c2' colwidth="5*"/>
+                                               <thead>
+                                                       <row>
+                                                               <entry>Hook</entry>
+                                                               <entry>Description</entry>
+                                                       </row>
+                                               </thead>
+                                               <tbody>
+                                                       <row>
+                                                               <entry>ingress</entry>
+                                                               <entry>
+                                                                       All packets entering the system are processed by this hook. It is invoked
+                                                                       before layer 3 protocol handlers and it can be used for early filtering and
+                                                                       policing.
+                                                               </entry>
+                                                       </row>
+                                               </tbody>
+                                       </tgroup>
+                               </table>
+                       </para>
+               </refsect2>
+
        </refsect1>
 
        <refsect1>
@@ -401,6 +441,7 @@ filter input iif $int_ifs accept
                                <member><literal>inet</literal></member>
                                <member><literal>arp</literal></member>
                                <member><literal>bridge</literal></member>
+                               <member><literal>netdev</literal></member>
                        </simplelist>.
 
                        The <literal>inet</literal> address family is a dummy family which is used to create
@@ -457,6 +498,7 @@ filter input iif $int_ifs accept
                                <arg choice="req"><replaceable>hook</replaceable></arg>
                                <arg choice="req"><replaceable>priority</replaceable></arg>
                                <arg choice="req"><replaceable>policy</replaceable></arg>
+                               <arg choice="req"><replaceable>device</replaceable></arg>
                        </cmdsynopsis>
                        <cmdsynopsis>
                                <group choice="req">
index be0bc18239919a27930d14e2f11e378f1a5a40b0..18075f958c8d7b2bc1855ccb8b487ba439bfd226 100644 (file)
@@ -32,6 +32,7 @@
 #define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP)
 
 /* only for userspace compatibility */
+#ifndef __KERNEL__
 /* Generic cache responses from hook functions.
    <= 0x2000 is used for protocol-flags. */
 #define NFC_UNKNOWN 0x4000
@@ -39,6 +40,7 @@
 
 /* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */
 #define NF_VERDICT_BITS 16
+#endif
 
 enum nf_inet_hooks {
        NF_INET_PRE_ROUTING,
@@ -49,11 +51,17 @@ enum nf_inet_hooks {
        NF_INET_NUMHOOKS
 };
 
+enum nf_dev_hooks {
+       NF_NETDEV_INGRESS,
+       NF_NETDEV_NUMHOOKS
+};
+
 enum {
        NFPROTO_UNSPEC =  0,
        NFPROTO_INET   =  1,
        NFPROTO_IPV4   =  2,
        NFPROTO_ARP    =  3,
+       NFPROTO_NETDEV =  5,
        NFPROTO_BRIDGE =  7,
        NFPROTO_IPV6   = 10,
        NFPROTO_DECNET = 12,
index 5d4459932775e3c45da46439b061315f28e586d0..604de14d8a90416a6f565e21a1fce5a758bd6af0 100644 (file)
@@ -113,6 +113,7 @@ enum chain_flags {
  * @priority:  hook priority (base chains)
  * @policy:    default chain policy (base chains)
  * @type:      chain type
+ * @dev:       device (if any)
  * @rules:     rules contained in the chain
  */
 struct chain {
@@ -125,6 +126,7 @@ struct chain {
        int                     priority;
        int                     policy;
        const char              *type;
+       const char              *dev;
        struct scope            scope;
        struct list_head        rules;
 };
index d99b38f4457e0560d21dccb052e371a015cc9dcf..0bf4fecb99eba7f6ea6ea113572ffef2a38fddbc 100644 (file)
@@ -1847,6 +1847,10 @@ static uint32_t str2hooknum(uint32_t family, const char *hook)
                else if (!strcmp(hook, "output"))
                        return NF_ARP_OUT;
                break;
+       case NFPROTO_NETDEV:
+               if (!strcmp(hook, "ingress"))
+                       return NF_NETDEV_INGRESS;
+               break;
        default:
                break;
        }
index 1167c9516ad19c77775c74cc010bc8789b356349..bef33a1de0701985d17c9f416561499242781b3d 100644 (file)
@@ -555,6 +555,9 @@ static int netlink_add_chain_batch(struct netlink_ctx *ctx,
                if (chain->policy != -1)
                        nft_chain_attr_set_u32(nlc, NFT_CHAIN_ATTR_POLICY,
                                               chain->policy);
+               if (chain->dev != NULL)
+                       nft_chain_attr_set_str(nlc, NFT_CHAIN_ATTR_DEV,
+                                              chain->dev);
        }
 
        netlink_dump_chain(nlc);
@@ -697,6 +700,10 @@ static struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
                        xstrdup(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_TYPE));
                chain->policy          =
                        nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_POLICY);
+               if (nft_chain_attr_is_set(nlc, NFT_CHAIN_ATTR_DEV)) {
+                       chain->dev      =
+                               xstrdup(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_DEV));
+               }
                chain->flags        |= CHAIN_F_BASECHAIN;
        }
 
index eac3fcbeb638003042ae2d343032b629b037985f..fab4c52e895ba4e0fd17764c42b730c7dc7944b3 100644 (file)
@@ -165,6 +165,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token DEFINE                  "define"
 
 %token HOOK                    "hook"
+%token DEVICE                  "device"
 %token TABLE                   "table"
 %token TABLES                  "tables"
 %token CHAIN                   "chain"
@@ -179,6 +180,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token RULESET                 "ruleset"
 
 %token INET                    "inet"
+%token NETDEV                  "netdev"
 
 %token ADD                     "add"
 %token UPDATE                  "update"
@@ -1090,6 +1092,37 @@ hook_spec                :       TYPE            STRING          HOOK            STRING          PRIORITY        NUM
                                $<chain>0->priority     = -$7;
                                $<chain>0->flags        |= CHAIN_F_BASECHAIN;
                        }
+                       |       TYPE            STRING          HOOK            STRING          DEVICE  STRING  PRIORITY        NUM
+                       {
+                               $<chain>0->type         = chain_type_name_lookup($2);
+                               if ($<chain>0->type == NULL) {
+                                       erec_queue(error(&@2, "unknown chain type %s", $2),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+                               $<chain>0->hookstr      = chain_hookname_lookup($4);
+                               if ($<chain>0->hookstr == NULL) {
+                                       erec_queue(error(&@4, "unknown chain hook %s", $4),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+                               $<chain>0->dev          = $6;
+                               $<chain>0->priority     = $8;
+                               $<chain>0->flags        |= CHAIN_F_BASECHAIN;
+                       }
+                       |       TYPE            STRING          HOOK            STRING          DEVICE  STRING  PRIORITY        DASH    NUM
+                       {
+                               $<chain>0->type         = chain_type_name_lookup($2);
+                               if ($<chain>0->type == NULL) {
+                                       erec_queue(error(&@2, "unknown type name %s", $2),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+                               $<chain>0->hookstr      = chain_hookname_lookup($4);
+                               $<chain>0->dev          = $6;
+                               $<chain>0->priority     = -$9;
+                               $<chain>0->flags        |= CHAIN_F_BASECHAIN;
+                       }
                        ;
 
 policy_spec            :       POLICY          chain_policy
@@ -1137,6 +1170,7 @@ family_spec_explicit      :       IP              { $$ = NFPROTO_IPV4; }
                        |       INET            { $$ = NFPROTO_INET; }
                        |       ARP             { $$ = NFPROTO_ARP; }
                        |       BRIDGE          { $$ = NFPROTO_BRIDGE; }
+                       |       NETDEV          { $$ = NFPROTO_NETDEV; }
                        ;
 
 table_spec             :       family_spec     identifier
index 08578fd86b22eb40d36910a7604751b193959ba2..1a9d4917fb783f199000c47ec71aa05b790c98e1 100644 (file)
@@ -215,6 +215,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
                        }
                        break;
                case NFPROTO_BRIDGE:
+               case NFPROTO_NETDEV:
                        switch (expr->payload.base) {
                        case PROTO_BASE_LL_HDR:
                                desc = &proto_eth;
index 6302016c2f2be4937f61fd625e7774b1fb7f053e..d40caebc8be9fd044a43ab41be08bc84ed88b701 100644 (file)
@@ -123,6 +123,7 @@ const struct proto_desc *proto_dev_desc(uint16_t type)
 
 const struct hook_proto_desc hook_proto_desc[] = {
        [NFPROTO_BRIDGE]        = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR,      &proto_eth),
+       [NFPROTO_NETDEV]        = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR,      &proto_eth),
        [NFPROTO_INET]          = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR,      &proto_inet),
        [NFPROTO_IPV4]          = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_ip),
        [NFPROTO_IPV6]          = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_ip6),
index b2090dddaae84355422771f971632eed1ab04493..f930a374ca69dd09ed799ba94c2ff16d3ed7e3d2 100644 (file)
@@ -333,6 +333,7 @@ static const char *chain_hookname_str_array[] = {
        "forward",
        "postrouting",
        "output",
+       "ingress",
        NULL,
 };
 
@@ -398,6 +399,8 @@ const char *family2str(unsigned int family)
                        return "ip6";
                case NFPROTO_INET:
                        return "inet";
+               case NFPROTO_NETDEV:
+                       return "netdev";
                case NFPROTO_ARP:
                        return "arp";
                case NFPROTO_BRIDGE:
@@ -441,6 +444,13 @@ static const char *hooknum2str(unsigned int family, unsigned int hooknum)
                default:
                        break;
                }
+               break;
+       case NFPROTO_NETDEV:
+               switch (hooknum) {
+               case NF_NETDEV_INGRESS:
+                       return "ingress";
+               }
+               break;
        default:
                break;
        };
@@ -465,10 +475,17 @@ static void chain_print(const struct chain *chain)
 
        printf("\tchain %s {\n", chain->handle.chain);
        if (chain->flags & CHAIN_F_BASECHAIN) {
-               printf("\t\ttype %s hook %s priority %d; policy %s;\n",
-                      chain->type,
-                      hooknum2str(chain->handle.family, chain->hooknum),
-                      chain->priority, chain_policy2str(chain->policy));
+               if (chain->dev != NULL) {
+                       printf("\t\ttype %s hook %s device %s priority %d;\n",
+                              chain->type,
+                              hooknum2str(chain->handle.family, chain->hooknum),
+                              chain->dev, chain->priority);
+               } else {
+                       printf("\t\ttype %s hook %s priority %d;\n",
+                              chain->type,
+                              hooknum2str(chain->handle.family, chain->hooknum),
+                              chain->priority);
+               }
        }
        list_for_each_entry(rule, &chain->rules, list) {
                printf("\t\t");
index 985ea2a34927796f6f5e30ee848caaba31f4a2da..2d9871d0195ce3991b3620d0359f82daa85dd2b0 100644 (file)
@@ -233,6 +233,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "describe"             { return DESCRIBE; }
 
 "hook"                 { return HOOK; }
+"device"               { return DEVICE; }
 "table"                        { return TABLE; }
 "tables"               { return TABLES; }
 "chain"                        { return CHAIN; }
@@ -255,6 +256,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "to"                   { return TO; }
 
 "inet"                 { return INET; }
+"netdev"               { return NETDEV; }
 
 "add"                  { return ADD; }
 "update"               { return UPDATE; }