Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
authorDavid S. Miller <davem@davemloft.net>
Sun, 9 Feb 2014 22:20:00 +0000 (14:20 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 9 Feb 2014 22:20:00 +0000 (14:20 -0800)
Pablo Neira Ayuso says:

====================
Netfilter/nftables/IPVS fixes for net

The following patchset contains Netfilter/IPVS fixes, mostly nftables
fixes, most relevantly they are:

* Fix a crash in the h323 conntrack NAT helper due to expectation list
  corruption, from Alexey Dobriyan.

* A couple of RCU race fixes for conntrack, one manifests by hitting BUG_ON
  in nf_nat_setup_info() and the destroy path, patches from Andrey Vagin and
  me.

* Dump direction attribute in nft_ct only if it is set, from Arturo
  Borrero.

* Fix IPVS bug in its own connection tracking system that may lead to
  copying only 4 bytes of the IPv6 address when initializing the
  ip_vs_conn object, from Michal Kubecek.

* Fix -EBUSY errors in nftables when deleting the rules, chain and tables
  in a row due mixture of asynchronous and synchronous object releasing,
  from me.

* Three fixes for the nf_tables set infrastructure when using intervals and
  mappings, from me.

* Four patches to fixing the nf_tables log, reject and ct expressions from
  the new inet table, from Patrick McHardy.

* Fix memory overrun in the map that is used to dynamically allocate names
  from anonymous sets, also from Patrick.

* Fix a potential oops if you dump a set with NFPROTO_UNSPEC and a table
  name, from Patrick McHardy.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
24 files changed:
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nft_reject.h [new file with mode: 0644]
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/netfilter/nft_reject_ipv4.c [new file with mode: 0644]
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/nft_reject_ipv6.c [new file with mode: 0644]
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nft_ct.c
net/netfilter/nft_log.c
net/netfilter/nft_queue.c
net/netfilter/nft_rbtree.c
net/netfilter/nft_reject.c
net/netfilter/nft_reject_inet.c [new file with mode: 0644]
net/netfilter/xt_CT.c

index 01ea6eed1bb1ddcc9b8c9001286ae85730bea416..b2ac6246b7e0abe156b26a06bf9a4463331baa6e 100644 (file)
@@ -284,6 +284,8 @@ extern unsigned int nf_conntrack_max;
 extern unsigned int nf_conntrack_hash_rnd;
 void init_nf_conntrack_hash_rnd(void);
 
+void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl);
+
 #define NF_CT_STAT_INC(net, count)       __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
 
index 57c8ff7955dfbd109e8ac2c731d595539220b3d4..e7e14ffe0f6a0e0f545af45864aa248980250da2 100644 (file)
@@ -252,6 +252,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
  *     @owner: module reference
  *     @policy: netlink attribute policy
  *     @maxattr: highest netlink attribute number
+ *     @family: address family for AF-specific types
  */
 struct nft_expr_type {
        const struct nft_expr_ops       *(*select_ops)(const struct nft_ctx *,
@@ -262,6 +263,7 @@ struct nft_expr_type {
        struct module                   *owner;
        const struct nla_policy         *policy;
        unsigned int                    maxattr;
+       u8                              family;
 };
 
 /**
@@ -320,7 +322,6 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  *     struct nft_rule - nf_tables rule
  *
  *     @list: used internally
- *     @rcu_head: used internally for rcu
  *     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
@@ -328,7 +329,6 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  */
 struct nft_rule {
        struct list_head                list;
-       struct rcu_head                 rcu_head;
        u64                             handle:46,
                                        genmask:2,
                                        dlen:16;
@@ -389,7 +389,6 @@ enum nft_chain_flags {
  *
  *     @rules: list of rules in the chain
  *     @list: used internally
- *     @rcu_head: used internally
  *     @net: net namespace that this chain belongs to
  *     @table: table that this chain belongs to
  *     @handle: chain handle
@@ -401,7 +400,6 @@ enum nft_chain_flags {
 struct nft_chain {
        struct list_head                rules;
        struct list_head                list;
-       struct rcu_head                 rcu_head;
        struct net                      *net;
        struct nft_table                *table;
        u64                             handle;
@@ -529,6 +527,9 @@ void nft_unregister_expr(struct nft_expr_type *);
 #define MODULE_ALIAS_NFT_CHAIN(family, name) \
        MODULE_ALIAS("nft-chain-" __stringify(family) "-" name)
 
+#define MODULE_ALIAS_NFT_AF_EXPR(family, name) \
+       MODULE_ALIAS("nft-expr-" __stringify(family) "-" name)
+
 #define MODULE_ALIAS_NFT_EXPR(name) \
        MODULE_ALIAS("nft-expr-" name)
 
diff --git a/include/net/netfilter/nft_reject.h b/include/net/netfilter/nft_reject.h
new file mode 100644 (file)
index 0000000..36b0da2
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _NFT_REJECT_H_
+#define _NFT_REJECT_H_
+
+struct nft_reject {
+       enum nft_reject_types   type:8;
+       u8                      icmp_code;
+};
+
+extern const struct nla_policy nft_reject_policy[];
+
+int nft_reject_init(const struct nft_ctx *ctx,
+                   const struct nft_expr *expr,
+                   const struct nlattr * const tb[]);
+
+int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr);
+
+void nft_reject_ipv4_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt);
+
+void nft_reject_ipv6_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt);
+
+#endif
index 81c6910cfa925b315c8efda5e3d79af817c82c88..a26ce035e3fad076a1d76fae0c377771300c7a04 100644 (file)
@@ -61,6 +61,11 @@ config NFT_CHAIN_NAT_IPV4
          packet transformations such as the source, destination address and
          source and destination ports.
 
+config NFT_REJECT_IPV4
+       depends on NF_TABLES_IPV4
+       default NFT_REJECT
+       tristate
+
 config NF_TABLES_ARP
        depends on NF_TABLES
        tristate "ARP nf_tables support"
index c16be9d58420dad15b4218ec119b34d184a7ea7e..90b82405331e1736c8bb4f0d4cacfd3c8fd4e783 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
 obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o
 obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o
+obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
 obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
 
 # generic IP tables 
index 9eea059dd6216225950428819104bfcae77d10ba..574f7ebba0b6238d8e61ffd08dead06a07a619c5 100644 (file)
@@ -229,7 +229,10 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
                        ret = nf_ct_expect_related(rtcp_exp);
                        if (ret == 0)
                                break;
-                       else if (ret != -EBUSY) {
+                       else if (ret == -EBUSY) {
+                               nf_ct_unexpect_related(rtp_exp);
+                               continue;
+                       } else if (ret < 0) {
                                nf_ct_unexpect_related(rtp_exp);
                                nated_port = 0;
                                break;
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c
new file mode 100644 (file)
index 0000000..e79718a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 Eric Leblond <eric@regit.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/icmp.h>
+#include <net/netfilter/ipv4/nf_reject.h>
+#include <net/netfilter/nft_reject.h>
+
+void nft_reject_ipv4_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt)
+{
+       struct nft_reject *priv = nft_expr_priv(expr);
+
+       switch (priv->type) {
+       case NFT_REJECT_ICMP_UNREACH:
+               nf_send_unreach(pkt->skb, priv->icmp_code);
+               break;
+       case NFT_REJECT_TCP_RST:
+               nf_send_reset(pkt->skb, pkt->ops->hooknum);
+               break;
+       }
+
+       data[NFT_REG_VERDICT].verdict = NF_DROP;
+}
+EXPORT_SYMBOL_GPL(nft_reject_ipv4_eval);
+
+static struct nft_expr_type nft_reject_ipv4_type;
+static const struct nft_expr_ops nft_reject_ipv4_ops = {
+       .type           = &nft_reject_ipv4_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
+       .eval           = nft_reject_ipv4_eval,
+       .init           = nft_reject_init,
+       .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_ipv4_type __read_mostly = {
+       .family         = NFPROTO_IPV4,
+       .name           = "reject",
+       .ops            = &nft_reject_ipv4_ops,
+       .policy         = nft_reject_policy,
+       .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
+};
+
+static int __init nft_reject_ipv4_module_init(void)
+{
+       return nft_register_expr(&nft_reject_ipv4_type);
+}
+
+static void __exit nft_reject_ipv4_module_exit(void)
+{
+       nft_unregister_expr(&nft_reject_ipv4_type);
+}
+
+module_init(nft_reject_ipv4_module_init);
+module_exit(nft_reject_ipv4_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS_NFT_AF_EXPR(AF_INET, "reject");
index 35750df744dc9ce92c3b98dcfd5dab27dcf73e85..4bff1f297e39a4affcf82e6b7aca2e6078b4dc50 100644 (file)
@@ -50,6 +50,11 @@ config NFT_CHAIN_NAT_IPV6
          packet transformations such as the source, destination address and
          source and destination ports.
 
+config NFT_REJECT_IPV6
+       depends on NF_TABLES_IPV6
+       default NFT_REJECT
+       tristate
+
 config IP6_NF_IPTABLES
        tristate "IP6 tables support (required for filtering)"
        depends on INET && IPV6
index d1b4928f34f7ba3f80200ec0b9db67c12d47715b..70d3dd66f2cdbf1408d328fd06104671446d5bc9 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
 obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
 obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
+obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
 
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
diff --git a/net/ipv6/netfilter/nft_reject_ipv6.c b/net/ipv6/netfilter/nft_reject_ipv6.c
new file mode 100644 (file)
index 0000000..0bc19fa
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 Eric Leblond <eric@regit.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nft_reject.h>
+#include <net/netfilter/ipv6/nf_reject.h>
+
+void nft_reject_ipv6_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt)
+{
+       struct nft_reject *priv = nft_expr_priv(expr);
+       struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
+
+       switch (priv->type) {
+       case NFT_REJECT_ICMP_UNREACH:
+               nf_send_unreach6(net, pkt->skb, priv->icmp_code,
+                                pkt->ops->hooknum);
+               break;
+       case NFT_REJECT_TCP_RST:
+               nf_send_reset6(net, pkt->skb, pkt->ops->hooknum);
+               break;
+       }
+
+       data[NFT_REG_VERDICT].verdict = NF_DROP;
+}
+EXPORT_SYMBOL_GPL(nft_reject_ipv6_eval);
+
+static struct nft_expr_type nft_reject_ipv6_type;
+static const struct nft_expr_ops nft_reject_ipv6_ops = {
+       .type           = &nft_reject_ipv6_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
+       .eval           = nft_reject_ipv6_eval,
+       .init           = nft_reject_init,
+       .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_ipv6_type __read_mostly = {
+       .family         = NFPROTO_IPV6,
+       .name           = "reject",
+       .ops            = &nft_reject_ipv6_ops,
+       .policy         = nft_reject_policy,
+       .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
+};
+
+static int __init nft_reject_ipv6_module_init(void)
+{
+       return nft_register_expr(&nft_reject_ipv6_type);
+}
+
+static void __exit nft_reject_ipv6_module_exit(void)
+{
+       nft_unregister_expr(&nft_reject_ipv6_type);
+}
+
+module_init(nft_reject_ipv6_module_init);
+module_exit(nft_reject_ipv6_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "reject");
index c37467562fd04ebd5bf7ac1a02bef56e3bd9017a..e9410d17619df52b76620e6a81a51e3c9a549f33 100644 (file)
@@ -513,7 +513,6 @@ config NFT_QUEUE
 
 config NFT_REJECT
        depends on NF_TABLES
-       depends on NF_TABLES_IPV6 || !NF_TABLES_IPV6
        default m if NETFILTER_ADVANCED=n
        tristate "Netfilter nf_tables reject support"
        help
@@ -521,6 +520,11 @@ config NFT_REJECT
          explicitly deny and notify via TCP reset/ICMP informational errors
          unallowed traffic.
 
+config NFT_REJECT_INET
+       depends on NF_TABLES_INET
+       default NFT_REJECT
+       tristate
+
 config NFT_COMPAT
        depends on NF_TABLES
        depends on NETFILTER_XTABLES
index ee9c4de5f8eded2b7e545eea47dfbd1f42edfafc..bffdad774da753131937d53ba1693af8f25b83a0 100644 (file)
@@ -79,6 +79,7 @@ obj-$(CONFIG_NFT_LIMIT)               += nft_limit.o
 obj-$(CONFIG_NFT_NAT)          += nft_nat.o
 obj-$(CONFIG_NFT_QUEUE)                += nft_queue.o
 obj-$(CONFIG_NFT_REJECT)       += nft_reject.o
+obj-$(CONFIG_NFT_REJECT_INET)  += nft_reject_inet.o
 obj-$(CONFIG_NFT_RBTREE)       += nft_rbtree.o
 obj-$(CONFIG_NFT_HASH)         += nft_hash.o
 obj-$(CONFIG_NFT_COUNTER)      += nft_counter.o
index 59a1a85bcb3eb888348cbc818789ebb16aa01cc9..a8eb0a89326ab504ec83421ea7b66aba3ab3a057 100644 (file)
@@ -871,11 +871,11 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
        cp->protocol       = p->protocol;
        ip_vs_addr_set(p->af, &cp->caddr, p->caddr);
        cp->cport          = p->cport;
-       ip_vs_addr_set(p->af, &cp->vaddr, p->vaddr);
-       cp->vport          = p->vport;
-       /* proto should only be IPPROTO_IP if d_addr is a fwmark */
+       /* proto should only be IPPROTO_IP if p->vaddr is a fwmark */
        ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
-                      &cp->daddr, daddr);
+                      &cp->vaddr, p->vaddr);
+       cp->vport          = p->vport;
+       ip_vs_addr_set(p->af, &cp->daddr, daddr);
        cp->dport          = dport;
        cp->flags          = flags;
        cp->fwmark         = fwmark;
index 8824ed0ccc9cd544e4799484ea7158f1f8db9c67..356bef519fe5b781f6225557f64186c0075852a1 100644 (file)
@@ -312,6 +312,21 @@ static void death_by_timeout(unsigned long ul_conntrack)
        nf_ct_delete((struct nf_conn *)ul_conntrack, 0, 0);
 }
 
+static inline bool
+nf_ct_key_equal(struct nf_conntrack_tuple_hash *h,
+                       const struct nf_conntrack_tuple *tuple,
+                       u16 zone)
+{
+       struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+
+       /* A conntrack can be recreated with the equal tuple,
+        * so we need to check that the conntrack is confirmed
+        */
+       return nf_ct_tuple_equal(tuple, &h->tuple) &&
+               nf_ct_zone(ct) == zone &&
+               nf_ct_is_confirmed(ct);
+}
+
 /*
  * Warning :
  * - Caller must take a reference on returned object
@@ -333,8 +348,7 @@ ____nf_conntrack_find(struct net *net, u16 zone,
        local_bh_disable();
 begin:
        hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) {
-               if (nf_ct_tuple_equal(tuple, &h->tuple) &&
-                   nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
+               if (nf_ct_key_equal(h, tuple, zone)) {
                        NF_CT_STAT_INC(net, found);
                        local_bh_enable();
                        return h;
@@ -372,8 +386,7 @@ begin:
                             !atomic_inc_not_zero(&ct->ct_general.use)))
                        h = NULL;
                else {
-                       if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
-                                    nf_ct_zone(ct) != zone)) {
+                       if (unlikely(!nf_ct_key_equal(h, tuple, zone))) {
                                nf_ct_put(ct);
                                goto begin;
                        }
@@ -435,7 +448,9 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
                        goto out;
 
        add_timer(&ct->timeout);
-       nf_conntrack_get(&ct->ct_general);
+       smp_wmb();
+       /* The caller holds a reference to this object */
+       atomic_set(&ct->ct_general.use, 2);
        __nf_conntrack_hash_insert(ct, hash, repl_hash);
        NF_CT_STAT_INC(net, insert);
        spin_unlock_bh(&nf_conntrack_lock);
@@ -449,6 +464,21 @@ out:
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
 
+/* deletion from this larval template list happens via nf_ct_put() */
+void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
+{
+       __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
+       __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
+       nf_conntrack_get(&tmpl->ct_general);
+
+       spin_lock_bh(&nf_conntrack_lock);
+       /* Overload tuple linked list to put us in template list. */
+       hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                                &net->ct.tmpl);
+       spin_unlock_bh(&nf_conntrack_lock);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
+
 /* Confirm a connection given skb; places it in hash table */
 int
 __nf_conntrack_confirm(struct sk_buff *skb)
@@ -720,11 +750,10 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
                nf_ct_zone->id = zone;
        }
 #endif
-       /*
-        * changes to lookup keys must be done before setting refcnt to 1
+       /* Because we use RCU lookups, we set ct_general.use to zero before
+        * this is inserted in any list.
         */
-       smp_wmb();
-       atomic_set(&ct->ct_general.use, 1);
+       atomic_set(&ct->ct_general.use, 0);
        return ct;
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
@@ -748,6 +777,11 @@ void nf_conntrack_free(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
 
+       /* A freed object has refcnt == 0, that's
+        * the golden rule for SLAB_DESTROY_BY_RCU
+        */
+       NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 0);
+
        nf_ct_ext_destroy(ct);
        nf_ct_ext_free(ct);
        kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
@@ -843,6 +877,9 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                NF_CT_STAT_INC(net, new);
        }
 
+       /* Now it is inserted into the unconfirmed list, bump refcount */
+       nf_conntrack_get(&ct->ct_general);
+
        /* Overload tuple linked list to put us in unconfirmed list. */
        hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
                       &net->ct.unconfirmed);
index 9858e3e51a3a049ce796b3ed625e3d3ad8bbe5cc..52e20c9a46a58be4328276964c1bb255c51a423c 100644 (file)
@@ -363,9 +363,8 @@ static int __net_init synproxy_net_init(struct net *net)
                goto err2;
        if (!nfct_synproxy_ext_add(ct))
                goto err2;
-       __set_bit(IPS_TEMPLATE_BIT, &ct->status);
-       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
 
+       nf_conntrack_tmpl_insert(net, ct);
        snet->tmpl = ct;
 
        snet->stats = alloc_percpu(struct synproxy_stats);
@@ -390,7 +389,7 @@ static void __net_exit synproxy_net_exit(struct net *net)
 {
        struct synproxy_net *snet = synproxy_pernet(net);
 
-       nf_conntrack_free(snet->tmpl);
+       nf_ct_put(snet->tmpl);
        synproxy_proc_exit(net);
        free_percpu(snet->stats);
 }
index 117bbaaddde636a7b5cbf754012ab2f696898e71..adce01e8bb57e7fb9794eebceae274707d96899e 100644 (file)
@@ -1008,10 +1008,8 @@ notify:
        return 0;
 }
 
-static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
+static void nf_tables_chain_destroy(struct nft_chain *chain)
 {
-       struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
-
        BUG_ON(chain->use > 0);
 
        if (chain->flags & NFT_BASE_CHAIN) {
@@ -1045,7 +1043,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
        if (IS_ERR(chain))
                return PTR_ERR(chain);
 
-       if (!list_empty(&chain->rules))
+       if (!list_empty(&chain->rules) || chain->use > 0)
                return -EBUSY;
 
        list_del(&chain->list);
@@ -1059,7 +1057,9 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
                               family);
 
        /* Make sure all rule references are gone before this is released */
-       call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
+       synchronize_rcu();
+
+       nf_tables_chain_destroy(chain);
        return 0;
 }
 
@@ -1114,35 +1114,45 @@ void nft_unregister_expr(struct nft_expr_type *type)
 }
 EXPORT_SYMBOL_GPL(nft_unregister_expr);
 
-static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
+static const struct nft_expr_type *__nft_expr_type_get(u8 family,
+                                                      struct nlattr *nla)
 {
        const struct nft_expr_type *type;
 
        list_for_each_entry(type, &nf_tables_expressions, list) {
-               if (!nla_strcmp(nla, type->name))
+               if (!nla_strcmp(nla, type->name) &&
+                   (!type->family || type->family == family))
                        return type;
        }
        return NULL;
 }
 
-static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
+static const struct nft_expr_type *nft_expr_type_get(u8 family,
+                                                    struct nlattr *nla)
 {
        const struct nft_expr_type *type;
 
        if (nla == NULL)
                return ERR_PTR(-EINVAL);
 
-       type = __nft_expr_type_get(nla);
+       type = __nft_expr_type_get(family, nla);
        if (type != NULL && try_module_get(type->owner))
                return type;
 
 #ifdef CONFIG_MODULES
        if (type == NULL) {
+               nfnl_unlock(NFNL_SUBSYS_NFTABLES);
+               request_module("nft-expr-%u-%.*s", family,
+                              nla_len(nla), (char *)nla_data(nla));
+               nfnl_lock(NFNL_SUBSYS_NFTABLES);
+               if (__nft_expr_type_get(family, nla))
+                       return ERR_PTR(-EAGAIN);
+
                nfnl_unlock(NFNL_SUBSYS_NFTABLES);
                request_module("nft-expr-%.*s",
                               nla_len(nla), (char *)nla_data(nla));
                nfnl_lock(NFNL_SUBSYS_NFTABLES);
-               if (__nft_expr_type_get(nla))
+               if (__nft_expr_type_get(family, nla))
                        return ERR_PTR(-EAGAIN);
        }
 #endif
@@ -1193,7 +1203,7 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
        if (err < 0)
                return err;
 
-       type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
+       type = nft_expr_type_get(ctx->afi->family, tb[NFTA_EXPR_NAME]);
        if (IS_ERR(type))
                return PTR_ERR(type);
 
@@ -1521,9 +1531,8 @@ err:
        return err;
 }
 
-static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
+static void nf_tables_rule_destroy(struct nft_rule *rule)
 {
-       struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
        struct nft_expr *expr;
 
        /*
@@ -1538,11 +1547,6 @@ static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
        kfree(rule);
 }
 
-static void nf_tables_rule_destroy(struct nft_rule *rule)
-{
-       call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
-}
-
 #define NFT_RULE_MAXEXPRS      128
 
 static struct nft_expr_info *info;
@@ -1809,9 +1813,6 @@ static int nf_tables_commit(struct sk_buff *skb)
        synchronize_rcu();
 
        list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
-               /* Delete this rule from the dirty list */
-               list_del(&rupd->list);
-
                /* This rule was inactive in the past and just became active.
                 * Clear the next bit of the genmask since its meaning has
                 * changed, now it is the future.
@@ -1822,6 +1823,7 @@ static int nf_tables_commit(struct sk_buff *skb)
                                              rupd->chain, rupd->rule,
                                              NFT_MSG_NEWRULE, 0,
                                              rupd->family);
+                       list_del(&rupd->list);
                        kfree(rupd);
                        continue;
                }
@@ -1831,7 +1833,15 @@ static int nf_tables_commit(struct sk_buff *skb)
                nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
                                      rupd->rule, NFT_MSG_DELRULE, 0,
                                      rupd->family);
+       }
+
+       /* Make sure we don't see any packet traversing old rules */
+       synchronize_rcu();
+
+       /* Now we can safely release unused old rules */
+       list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
                nf_tables_rule_destroy(rupd->rule);
+               list_del(&rupd->list);
                kfree(rupd);
        }
 
@@ -1844,20 +1854,26 @@ static int nf_tables_abort(struct sk_buff *skb)
        struct nft_rule_trans *rupd, *tmp;
 
        list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
-               /* Delete all rules from the dirty list */
-               list_del(&rupd->list);
-
                if (!nft_rule_is_active_next(net, rupd->rule)) {
                        nft_rule_clear(net, rupd->rule);
+                       list_del(&rupd->list);
                        kfree(rupd);
                        continue;
                }
 
                /* This rule is inactive, get rid of it */
                list_del_rcu(&rupd->rule->list);
+       }
+
+       /* Make sure we don't see any packet accessing aborted rules */
+       synchronize_rcu();
+
+       list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
                nf_tables_rule_destroy(rupd->rule);
+               list_del(&rupd->list);
                kfree(rupd);
        }
+
        return 0;
 }
 
@@ -1943,6 +1959,9 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
        }
 
        if (nla[NFTA_SET_TABLE] != NULL) {
+               if (afi == NULL)
+                       return -EAFNOSUPPORT;
+
                table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
                if (IS_ERR(table))
                        return PTR_ERR(table);
@@ -1989,13 +2008,13 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
 
                        if (!sscanf(i->name, name, &tmp))
                                continue;
-                       if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE)
+                       if (tmp < 0 || tmp >= BITS_PER_BYTE * PAGE_SIZE)
                                continue;
 
                        set_bit(tmp, inuse);
                }
 
-               n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
+               n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
                free_page((unsigned long)inuse);
        }
 
@@ -2428,6 +2447,8 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
        struct nft_ctx ctx;
        int err;
 
+       if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
+               return -EAFNOSUPPORT;
        if (nla[NFTA_SET_TABLE] == NULL)
                return -EINVAL;
 
@@ -2435,9 +2456,6 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
-               return -EAFNOSUPPORT;
-
        set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
        if (IS_ERR(set))
                return PTR_ERR(set);
@@ -2723,6 +2741,9 @@ static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
                if (nla[NFTA_SET_ELEM_DATA] == NULL &&
                    !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
                        return -EINVAL;
+               if (nla[NFTA_SET_ELEM_DATA] != NULL &&
+                   elem.flags & NFT_SET_ELEM_INTERVAL_END)
+                       return -EINVAL;
        } else {
                if (nla[NFTA_SET_ELEM_DATA] != NULL)
                        return -EINVAL;
@@ -2977,6 +2998,9 @@ static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
                                        const struct nft_set_iter *iter,
                                        const struct nft_set_elem *elem)
 {
+       if (elem->flags & NFT_SET_ELEM_INTERVAL_END)
+               return 0;
+
        switch (elem->data.verdict) {
        case NFT_JUMP:
        case NFT_GOTO:
index 0d879fcb8763c043430d242d68524e0256c4411d..90998a6ff8b9c1f10712e07d9b753e7d7d1bb2fd 100644 (file)
@@ -103,9 +103,9 @@ static struct nf_loginfo trace_loginfo = {
        },
 };
 
-static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
-                                   const struct nft_chain *chain,
-                                   int rulenum, enum nft_trace type)
+static void nft_trace_packet(const struct nft_pktinfo *pkt,
+                            const struct nft_chain *chain,
+                            int rulenum, enum nft_trace type)
 {
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
index 917052e20602ea1b7cca286edfbe01e429703327..46e2754038387cf978679e2fd4f1032b30e40bd6 100644 (file)
@@ -226,6 +226,7 @@ static int nft_ct_init_validate_get(const struct nft_expr *expr,
                if (tb[NFTA_CT_DIRECTION] != NULL)
                        return -EINVAL;
                break;
+       case NFT_CT_L3PROTOCOL:
        case NFT_CT_PROTOCOL:
        case NFT_CT_SRC:
        case NFT_CT_DST:
@@ -311,8 +312,19 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
                goto nla_put_failure;
-       if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
-               goto nla_put_failure;
+
+       switch (priv->key) {
+       case NFT_CT_PROTOCOL:
+       case NFT_CT_SRC:
+       case NFT_CT_DST:
+       case NFT_CT_PROTO_SRC:
+       case NFT_CT_PROTO_DST:
+               if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
+                       goto nla_put_failure;
+       default:
+               break;
+       }
+
        return 0;
 
 nla_put_failure:
index 5af790123ad865dbb88c9e172ed4b9beb8590e01..26c5154e05f3fc09aae2ebdea968ce564a3d5eb9 100644 (file)
@@ -23,7 +23,6 @@ static const char *nft_log_null_prefix = "";
 struct nft_log {
        struct nf_loginfo       loginfo;
        char                    *prefix;
-       int                     family;
 };
 
 static void nft_log_eval(const struct nft_expr *expr,
@@ -33,7 +32,7 @@ static void nft_log_eval(const struct nft_expr *expr,
        const struct nft_log *priv = nft_expr_priv(expr);
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
-       nf_log_packet(net, priv->family, pkt->ops->hooknum, pkt->skb, pkt->in,
+       nf_log_packet(net, pkt->ops->pf, pkt->ops->hooknum, pkt->skb, pkt->in,
                      pkt->out, &priv->loginfo, "%s", priv->prefix);
 }
 
@@ -52,8 +51,6 @@ static int nft_log_init(const struct nft_ctx *ctx,
        struct nf_loginfo *li = &priv->loginfo;
        const struct nlattr *nla;
 
-       priv->family = ctx->afi->family;
-
        nla = tb[NFTA_LOG_PREFIX];
        if (nla != NULL) {
                priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
index cbea473d69e953e9ba9e9d36ec4962aa3af57c1e..e8ae2f6bf232d8ccef7379f9bb573291da5581b4 100644 (file)
@@ -25,7 +25,6 @@ struct nft_queue {
        u16     queuenum;
        u16     queues_total;
        u16     flags;
-       u8      family;
 };
 
 static void nft_queue_eval(const struct nft_expr *expr,
@@ -43,7 +42,7 @@ static void nft_queue_eval(const struct nft_expr *expr,
                        queue = priv->queuenum + cpu % priv->queues_total;
                } else {
                        queue = nfqueue_hash(pkt->skb, queue,
-                                            priv->queues_total, priv->family,
+                                            priv->queues_total, pkt->ops->pf,
                                             jhash_initval);
                }
        }
@@ -71,7 +70,6 @@ static int nft_queue_init(const struct nft_ctx *ctx,
                return -EINVAL;
 
        init_hashrandom(&jhash_initval);
-       priv->family = ctx->afi->family;
        priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM]));
 
        if (tb[NFTA_QUEUE_TOTAL] != NULL)
index ca0c1b231bfe25cfe3c341c2aea8967f0dd4a4ec..e21d69d13506b95946820f24641fe7e48d885866 100644 (file)
@@ -69,8 +69,10 @@ static void nft_rbtree_elem_destroy(const struct nft_set *set,
                                    struct nft_rbtree_elem *rbe)
 {
        nft_data_uninit(&rbe->key, NFT_DATA_VALUE);
-       if (set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP &&
+           !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                nft_data_uninit(rbe->data, set->dtype);
+
        kfree(rbe);
 }
 
@@ -108,7 +110,8 @@ static int nft_rbtree_insert(const struct nft_set *set,
        int err;
 
        size = sizeof(*rbe);
-       if (set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP &&
+           !(elem->flags & NFT_SET_ELEM_INTERVAL_END))
                size += sizeof(rbe->data[0]);
 
        rbe = kzalloc(size, GFP_KERNEL);
@@ -117,7 +120,8 @@ static int nft_rbtree_insert(const struct nft_set *set,
 
        rbe->flags = elem->flags;
        nft_data_copy(&rbe->key, &elem->key);
-       if (set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP &&
+           !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                nft_data_copy(rbe->data, &elem->data);
 
        err = __nft_rbtree_insert(set, rbe);
@@ -153,7 +157,8 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
                        parent = parent->rb_right;
                else {
                        elem->cookie = rbe;
-                       if (set->flags & NFT_SET_MAP)
+                       if (set->flags & NFT_SET_MAP &&
+                           !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                                nft_data_copy(&elem->data, rbe->data);
                        elem->flags = rbe->flags;
                        return 0;
@@ -177,7 +182,8 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
 
                rbe = rb_entry(node, struct nft_rbtree_elem, node);
                nft_data_copy(&elem.key, &rbe->key);
-               if (set->flags & NFT_SET_MAP)
+               if (set->flags & NFT_SET_MAP &&
+                   !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                        nft_data_copy(&elem.data, rbe->data);
                elem.flags = rbe->flags;
 
index 5e204711d7049781052095ca317a4efd944ea07a..f3448c2964468abc08d2b3630be18953820e1aff 100644 (file)
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
-#include <net/icmp.h>
-#include <net/netfilter/ipv4/nf_reject.h>
+#include <net/netfilter/nft_reject.h>
 
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-#include <net/netfilter/ipv6/nf_reject.h>
-#endif
-
-struct nft_reject {
-       enum nft_reject_types   type:8;
-       u8                      icmp_code;
-       u8                      family;
-};
-
-static void nft_reject_eval(const struct nft_expr *expr,
-                             struct nft_data data[NFT_REG_MAX + 1],
-                             const struct nft_pktinfo *pkt)
-{
-       struct nft_reject *priv = nft_expr_priv(expr);
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-       struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
-#endif
-       switch (priv->type) {
-       case NFT_REJECT_ICMP_UNREACH:
-               if (priv->family == NFPROTO_IPV4)
-                       nf_send_unreach(pkt->skb, priv->icmp_code);
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-               else if (priv->family == NFPROTO_IPV6)
-                       nf_send_unreach6(net, pkt->skb, priv->icmp_code,
-                                     pkt->ops->hooknum);
-#endif
-               break;
-       case NFT_REJECT_TCP_RST:
-               if (priv->family == NFPROTO_IPV4)
-                       nf_send_reset(pkt->skb, pkt->ops->hooknum);
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-               else if (priv->family == NFPROTO_IPV6)
-                       nf_send_reset6(net, pkt->skb, pkt->ops->hooknum);
-#endif
-               break;
-       }
-
-       data[NFT_REG_VERDICT].verdict = NF_DROP;
-}
-
-static const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
+const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
        [NFTA_REJECT_TYPE]              = { .type = NLA_U32 },
        [NFTA_REJECT_ICMP_CODE]         = { .type = NLA_U8 },
 };
+EXPORT_SYMBOL_GPL(nft_reject_policy);
 
-static int nft_reject_init(const struct nft_ctx *ctx,
-                          const struct nft_expr *expr,
-                          const struct nlattr * const tb[])
+int nft_reject_init(const struct nft_ctx *ctx,
+                   const struct nft_expr *expr,
+                   const struct nlattr * const tb[])
 {
        struct nft_reject *priv = nft_expr_priv(expr);
 
        if (tb[NFTA_REJECT_TYPE] == NULL)
                return -EINVAL;
 
-       priv->family = ctx->afi->family;
        priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
        switch (priv->type) {
        case NFT_REJECT_ICMP_UNREACH:
@@ -89,8 +47,9 @@ static int nft_reject_init(const struct nft_ctx *ctx,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nft_reject_init);
 
-static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
+int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_reject *priv = nft_expr_priv(expr);
 
@@ -109,37 +68,7 @@ static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
 nla_put_failure:
        return -1;
 }
-
-static struct nft_expr_type nft_reject_type;
-static const struct nft_expr_ops nft_reject_ops = {
-       .type           = &nft_reject_type,
-       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
-       .eval           = nft_reject_eval,
-       .init           = nft_reject_init,
-       .dump           = nft_reject_dump,
-};
-
-static struct nft_expr_type nft_reject_type __read_mostly = {
-       .name           = "reject",
-       .ops            = &nft_reject_ops,
-       .policy         = nft_reject_policy,
-       .maxattr        = NFTA_REJECT_MAX,
-       .owner          = THIS_MODULE,
-};
-
-static int __init nft_reject_module_init(void)
-{
-       return nft_register_expr(&nft_reject_type);
-}
-
-static void __exit nft_reject_module_exit(void)
-{
-       nft_unregister_expr(&nft_reject_type);
-}
-
-module_init(nft_reject_module_init);
-module_exit(nft_reject_module_exit);
+EXPORT_SYMBOL_GPL(nft_reject_dump);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("reject");
diff --git a/net/netfilter/nft_reject_inet.c b/net/netfilter/nft_reject_inet.c
new file mode 100644 (file)
index 0000000..8a310f2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nft_reject.h>
+
+static void nft_reject_inet_eval(const struct nft_expr *expr,
+                                struct nft_data data[NFT_REG_MAX + 1],
+                                const struct nft_pktinfo *pkt)
+{
+       switch (pkt->ops->pf) {
+       case NFPROTO_IPV4:
+               nft_reject_ipv4_eval(expr, data, pkt);
+       case NFPROTO_IPV6:
+               nft_reject_ipv6_eval(expr, data, pkt);
+       }
+}
+
+static struct nft_expr_type nft_reject_inet_type;
+static const struct nft_expr_ops nft_reject_inet_ops = {
+       .type           = &nft_reject_inet_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
+       .eval           = nft_reject_inet_eval,
+       .init           = nft_reject_init,
+       .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_inet_type __read_mostly = {
+       .family         = NFPROTO_INET,
+       .name           = "reject",
+       .ops            = &nft_reject_inet_ops,
+       .policy         = nft_reject_policy,
+       .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
+};
+
+static int __init nft_reject_inet_module_init(void)
+{
+       return nft_register_expr(&nft_reject_inet_type);
+}
+
+static void __exit nft_reject_inet_module_exit(void)
+{
+       nft_unregister_expr(&nft_reject_inet_type);
+}
+
+module_init(nft_reject_inet_module_init);
+module_exit(nft_reject_inet_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS_NFT_AF_EXPR(1, "reject");
index 5929be622c5cd27b9e706811042c9e176a3c78f7..75747aecdebe6344ccbfcf178c299be013d8f763 100644 (file)
@@ -228,12 +228,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
                        goto err3;
        }
 
-       __set_bit(IPS_TEMPLATE_BIT, &ct->status);
-       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
-
-       /* Overload tuple linked list to put us in template list. */
-       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                                &par->net->ct.tmpl);
+       nf_conntrack_tmpl_insert(par->net, ct);
 out:
        info->ct = ct;
        return 0;