]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net...
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 25 Sep 2016 21:23:57 +0000 (23:23 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 25 Sep 2016 21:34:19 +0000 (23:34 +0200)
Conflicts:
net/netfilter/core.c
net/netfilter/nf_tables_netdev.c

Resolve two conflicts before pull request for David's net-next tree:

1) Between c73c24849011 ("netfilter: nf_tables_netdev: remove redundant
   ip_hdr assignment") from the net tree and commit ddc8b6027ad0
   ("netfilter: introduce nft_set_pktinfo_{ipv4, ipv6}_validate()").

2) Between e8bffe0cf964 ("net: Add _nf_(un)register_hooks symbols") and
   Aaron Conole's patches to replace list_head with single linked list.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
89 files changed:
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/netfilter/nf_conntrack_common.h
include/linux/netfilter/nf_conntrack_proto_gre.h
include/linux/netfilter_ingress.h
include/net/netfilter/br_netfilter.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_log.h
include/net/netfilter/nf_queue.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nf_tables_bridge.h [deleted file]
include/net/netfilter/nf_tables_core.h
include/net/netfilter/nf_tables_ipv4.h
include/net/netfilter/nf_tables_ipv6.h
include/net/netns/netfilter.h
include/uapi/linux/if_tunnel.h
include/uapi/linux/netfilter/nf_log.h [new file with mode: 0644]
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/netfilter/nfnetlink_conntrack.h
include/uapi/linux/netfilter/xt_hashlimit.h
net/bridge/br_netfilter_hooks.c
net/bridge/br_netfilter_ipv6.c
net/bridge/netfilter/ebt_log.c
net/bridge/netfilter/ebt_redirect.c
net/bridge/netfilter/ebtables.c
net/bridge/netfilter/nf_tables_bridge.c
net/bridge/netfilter/nft_reject_bridge.c
net/core/dev.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/netfilter/nf_log_arp.c
net/ipv4/netfilter/nf_log_ipv4.c
net/ipv4/netfilter/nf_nat_proto_gre.c
net/ipv4/netfilter/nf_tables_arp.c
net/ipv4/netfilter/nf_tables_ipv4.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/ipv6/netfilter/nf_log_ipv6.c
net/ipv6/netfilter/nf_tables_ipv6.c
net/ipv6/netfilter/nft_chain_route_ipv6.c
net/netfilter/Makefile
net/netfilter/core.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_seqadj.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_internals.h
net/netfilter/nf_log_common.c
net/netfilter/nf_queue.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nf_tables_inet.c
net/netfilter/nf_tables_netdev.c
net/netfilter/nf_tables_trace.c
net/netfilter/nfnetlink_cthelper.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_bitwise.c
net/netfilter/nft_byteorder.c
net/netfilter/nft_cmp.c
net/netfilter/nft_ct.c
net/netfilter/nft_dynset.c
net/netfilter/nft_exthdr.c
net/netfilter/nft_hash.c
net/netfilter/nft_immediate.c
net/netfilter/nft_log.c
net/netfilter/nft_lookup.c
net/netfilter/nft_meta.c
net/netfilter/nft_numgen.c
net/netfilter/nft_payload.c
net/netfilter/nft_queue.c
net/netfilter/nft_quota.c
net/netfilter/nft_range.c [new file with mode: 0644]
net/netfilter/xt_RATEEST.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_TEE.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_helper.c
net/netfilter/xt_recent.c

index 1e8a5c734d728c4a80f07631bcda807290ba6bd8..136ae6bbe81e12f769b38776ccbceac9f151360e 100644 (file)
@@ -1799,7 +1799,7 @@ struct net_device {
 #endif
        struct netdev_queue __rcu *ingress_queue;
 #ifdef CONFIG_NETFILTER_INGRESS
-       struct list_head        nf_hooks_ingress;
+       struct nf_hook_entry __rcu *nf_hooks_ingress;
 #endif
 
        unsigned char           broadcast[MAX_ADDR_LEN];
index e82b76781bf65fe503c8493621bd094e5af1381c..abc7fdcb9eb1a204c5a93669e7d17d618151f329 100644 (file)
@@ -55,12 +55,34 @@ struct nf_hook_state {
        struct net_device *out;
        struct sock *sk;
        struct net *net;
-       struct list_head *hook_list;
+       struct nf_hook_entry __rcu *hook_entries;
        int (*okfn)(struct net *, struct sock *, struct sk_buff *);
 };
 
+typedef unsigned int nf_hookfn(void *priv,
+                              struct sk_buff *skb,
+                              const struct nf_hook_state *state);
+struct nf_hook_ops {
+       struct list_head        list;
+
+       /* User fills in from here down. */
+       nf_hookfn               *hook;
+       struct net_device       *dev;
+       void                    *priv;
+       u_int8_t                pf;
+       unsigned int            hooknum;
+       /* Hooks are ordered in ascending priority. */
+       int                     priority;
+};
+
+struct nf_hook_entry {
+       struct nf_hook_entry __rcu      *next;
+       struct nf_hook_ops              ops;
+       const struct nf_hook_ops        *orig_ops;
+};
+
 static inline void nf_hook_state_init(struct nf_hook_state *p,
-                                     struct list_head *hook_list,
+                                     struct nf_hook_entry *hook_entry,
                                      unsigned int hook,
                                      int thresh, u_int8_t pf,
                                      struct net_device *indev,
@@ -76,26 +98,11 @@ static inline void nf_hook_state_init(struct nf_hook_state *p,
        p->out = outdev;
        p->sk = sk;
        p->net = net;
-       p->hook_list = hook_list;
+       RCU_INIT_POINTER(p->hook_entries, hook_entry);
        p->okfn = okfn;
 }
 
-typedef unsigned int nf_hookfn(void *priv,
-                              struct sk_buff *skb,
-                              const struct nf_hook_state *state);
-
-struct nf_hook_ops {
-       struct list_head        list;
 
-       /* User fills in from here down. */
-       nf_hookfn               *hook;
-       struct net_device       *dev;
-       void                    *priv;
-       u_int8_t                pf;
-       unsigned int            hooknum;
-       /* Hooks are ordered in ascending priority. */
-       int                     priority;
-};
 
 struct nf_sockopt_ops {
        struct list_head list;
@@ -163,7 +170,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
                                 int (*okfn)(struct net *, struct sock *, struct sk_buff *),
                                 int thresh)
 {
-       struct list_head *hook_list;
+       struct nf_hook_entry *hook_head;
+       int ret = 1;
 
 #ifdef HAVE_JUMP_LABEL
        if (__builtin_constant_p(pf) &&
@@ -172,16 +180,19 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
                return 1;
 #endif
 
-       hook_list = &net->nf.hooks[pf][hook];
-
-       if (!list_empty(hook_list)) {
+       rcu_read_lock();
+       hook_head = rcu_dereference(net->nf.hooks[pf][hook]);
+       if (hook_head) {
                struct nf_hook_state state;
 
-               nf_hook_state_init(&state, hook_list, hook, thresh,
+               nf_hook_state_init(&state, hook_head, hook, thresh,
                                   pf, indev, outdev, sk, net, okfn);
-               return nf_hook_slow(skb, &state);
+
+               ret = nf_hook_slow(skb, &state);
        }
-       return 1;
+       rcu_read_unlock();
+
+       return ret;
 }
 
 static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
index 275505792664ae4e835401a0503d5d3d9fa66808..1d1ef4e205121cf8999e5adc195e0fe22ecd599a 100644 (file)
@@ -4,13 +4,9 @@
 #include <uapi/linux/netfilter/nf_conntrack_common.h>
 
 struct ip_conntrack_stat {
-       unsigned int searched;
        unsigned int found;
-       unsigned int new;
        unsigned int invalid;
        unsigned int ignore;
-       unsigned int delete;
-       unsigned int delete_list;
        unsigned int insert;
        unsigned int insert_failed;
        unsigned int drop;
index df78dc2b5524245c68489a8f1d3995ed99379899..dee0acd0dd318c9eafde85601318d4b6013cface 100644 (file)
@@ -1,68 +1,8 @@
 #ifndef _CONNTRACK_PROTO_GRE_H
 #define _CONNTRACK_PROTO_GRE_H
 #include <asm/byteorder.h>
-
-/* GRE PROTOCOL HEADER */
-
-/* GRE Version field */
-#define GRE_VERSION_1701       0x0
-#define GRE_VERSION_PPTP       0x1
-
-/* GRE Protocol field */
-#define GRE_PROTOCOL_PPTP      0x880B
-
-/* GRE Flags */
-#define GRE_FLAG_C             0x80
-#define GRE_FLAG_R             0x40
-#define GRE_FLAG_K             0x20
-#define GRE_FLAG_S             0x10
-#define GRE_FLAG_A             0x80
-
-#define GRE_IS_C(f)    ((f)&GRE_FLAG_C)
-#define GRE_IS_R(f)    ((f)&GRE_FLAG_R)
-#define GRE_IS_K(f)    ((f)&GRE_FLAG_K)
-#define GRE_IS_S(f)    ((f)&GRE_FLAG_S)
-#define GRE_IS_A(f)    ((f)&GRE_FLAG_A)
-
-/* GRE is a mess: Four different standards */
-struct gre_hdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u16   rec:3,
-               srr:1,
-               seq:1,
-               key:1,
-               routing:1,
-               csum:1,
-               version:3,
-               reserved:4,
-               ack:1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       __u16   csum:1,
-               routing:1,
-               key:1,
-               seq:1,
-               srr:1,
-               rec:3,
-               ack:1,
-               reserved:4,
-               version:3;
-#else
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
-       __be16  protocol;
-};
-
-/* modified GRE header for PPTP */
-struct gre_hdr_pptp {
-       __u8   flags;           /* bitfield */
-       __u8   version;         /* should be GRE_VERSION_PPTP */
-       __be16 protocol;        /* should be GRE_PROTOCOL_PPTP */
-       __be16 payload_len;     /* size of ppp payload, not inc. gre header */
-       __be16 call_id;         /* peer's call_id for this session */
-       __be32 seq;             /* sequence number.  Present if S==1 */
-       __be32 ack;             /* seq number of highest packet received by */
-                               /*  sender in this session */
-};
+#include <net/gre.h>
+#include <net/pptp.h>
 
 struct nf_ct_gre {
        unsigned int stream_timeout;
index 5fcd375ef175b1a4e4870e99eb54d729a343b194..33e37fb41d5d40df1779860e6a4f17ab6a47ef6f 100644 (file)
@@ -11,22 +11,30 @@ static inline bool nf_hook_ingress_active(const struct sk_buff *skb)
        if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_INGRESS]))
                return false;
 #endif
-       return !list_empty(&skb->dev->nf_hooks_ingress);
+       return rcu_access_pointer(skb->dev->nf_hooks_ingress);
 }
 
+/* caller must hold rcu_read_lock */
 static inline int nf_hook_ingress(struct sk_buff *skb)
 {
+       struct nf_hook_entry *e = rcu_dereference(skb->dev->nf_hooks_ingress);
        struct nf_hook_state state;
 
-       nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress,
-                          NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV,
-                          skb->dev, NULL, NULL, dev_net(skb->dev), NULL);
+       /* Must recheck the ingress hook head, in the event it became NULL
+        * after the check in nf_hook_ingress_active evaluated to true.
+        */
+       if (unlikely(!e))
+               return 0;
+
+       nf_hook_state_init(&state, e, NF_NETDEV_INGRESS, INT_MIN,
+                          NFPROTO_NETDEV, skb->dev, NULL, NULL,
+                          dev_net(skb->dev), NULL);
        return nf_hook_slow(skb, &state);
 }
 
 static inline void nf_hook_ingress_init(struct net_device *dev)
 {
-       INIT_LIST_HEAD(&dev->nf_hooks_ingress);
+       RCU_INIT_POINTER(dev->nf_hooks_ingress, NULL);
 }
 #else /* CONFIG_NETFILTER_INGRESS */
 static inline int nf_hook_ingress_active(struct sk_buff *skb)
index e8d1448425a717facd1a6cfb71d72a9dfacc3ed7..0b0c35c37125eb8c15ba42e9413ba8206447a2c6 100644 (file)
@@ -15,6 +15,12 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
 
 void nf_bridge_update_protocol(struct sk_buff *skb);
 
+int br_nf_hook_thresh(unsigned int hook, struct net *net, struct sock *sk,
+                     struct sk_buff *skb, struct net_device *indev,
+                     struct net_device *outdev,
+                     int (*okfn)(struct net *, struct sock *,
+                                 struct sk_buff *));
+
 static inline struct nf_bridge_info *
 nf_bridge_info_get(const struct sk_buff *skb)
 {
index cdc920b4c4c2a3e9d770409d10384d5ec80e8705..8992e4229da95a07b771736a317d253f4fd2a61c 100644 (file)
@@ -63,10 +63,6 @@ struct nf_conntrack_l3proto {
 
        size_t nla_size;
 
-#ifdef CONFIG_SYSCTL
-       const char              *ctl_table_path;
-#endif /* CONFIG_SYSCTL */
-
        /* Init l3proto pernet data */
        int (*init_net)(struct net *net);
 
index ee07dc8b0a7bd06c2f563657dde75a11315e8497..309cd267be4faf589927478c39615e1eef144fd6 100644 (file)
@@ -2,15 +2,10 @@
 #define _NF_LOG_H
 
 #include <linux/netfilter.h>
+#include <linux/netfilter/nf_log.h>
 
-/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will
- * disappear once iptables is replaced with pkttables.  Please DO NOT use them
- * for any new code! */
-#define NF_LOG_TCPSEQ          0x01    /* Log TCP sequence numbers */
-#define NF_LOG_TCPOPT          0x02    /* Log TCP options */
-#define NF_LOG_IPOPT           0x04    /* Log IP options */
-#define NF_LOG_UID             0x08    /* Log UID owning local socket */
-#define NF_LOG_MASK            0x0f
+/* Log tcp sequence, tcp options, ip options and uid owning local socket */
+#define NF_LOG_DEFAULT_MASK    0x0f
 
 /* This flag indicates that copy_len field in nf_loginfo is set */
 #define NF_LOG_F_COPY_LEN      0x1
index 0dbce55437f2c57cc1642d865a91ffc4169c9866..2280cfe86c56157f3ca1165baf6f4ad0e73a18be 100644 (file)
@@ -11,7 +11,6 @@ struct nf_queue_entry {
        struct sk_buff          *skb;
        unsigned int            id;
 
-       struct nf_hook_ops      *elem;
        struct nf_hook_state    state;
        u16                     size; /* sizeof(entry) + saved route keys */
 
@@ -22,10 +21,10 @@ struct nf_queue_entry {
 
 /* Packet queuing */
 struct nf_queue_handler {
-       int                     (*outfn)(struct nf_queue_entry *entry,
-                                        unsigned int queuenum);
-       void                    (*nf_hook_drop)(struct net *net,
-                                               struct nf_hook_ops *ops);
+       int             (*outfn)(struct nf_queue_entry *entry,
+                                unsigned int queuenum);
+       void            (*nf_hook_drop)(struct net *net,
+                                       const struct nf_hook_entry *hooks);
 };
 
 void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
@@ -41,23 +40,19 @@ static inline void init_hashrandom(u32 *jhash_initval)
                *jhash_initval = prandom_u32();
 }
 
-static inline u32 hash_v4(const struct sk_buff *skb, u32 jhash_initval)
+static inline u32 hash_v4(const struct iphdr *iph, u32 initval)
 {
-       const struct iphdr *iph = ip_hdr(skb);
-
        /* packets in either direction go into same queue */
        if ((__force u32)iph->saddr < (__force u32)iph->daddr)
                return jhash_3words((__force u32)iph->saddr,
-                       (__force u32)iph->daddr, iph->protocol, jhash_initval);
+                       (__force u32)iph->daddr, iph->protocol, initval);
 
        return jhash_3words((__force u32)iph->daddr,
-                       (__force u32)iph->saddr, iph->protocol, jhash_initval);
+                       (__force u32)iph->saddr, iph->protocol, initval);
 }
 
-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
-static inline u32 hash_v6(const struct sk_buff *skb, u32 jhash_initval)
+static inline u32 hash_v6(const struct ipv6hdr *ip6h, u32 initval)
 {
-       const struct ipv6hdr *ip6h = ipv6_hdr(skb);
        u32 a, b, c;
 
        if ((__force u32)ip6h->saddr.s6_addr32[3] <
@@ -75,20 +70,50 @@ static inline u32 hash_v6(const struct sk_buff *skb, u32 jhash_initval)
        else
                c = (__force u32) ip6h->daddr.s6_addr32[1];
 
-       return jhash_3words(a, b, c, jhash_initval);
+       return jhash_3words(a, b, c, initval);
+}
+
+static inline u32 hash_bridge(const struct sk_buff *skb, u32 initval)
+{
+       struct ipv6hdr *ip6h, _ip6h;
+       struct iphdr *iph, _iph;
+
+       switch (eth_hdr(skb)->h_proto) {
+       case htons(ETH_P_IP):
+               iph = skb_header_pointer(skb, skb_network_offset(skb),
+                                        sizeof(*iph), &_iph);
+               if (iph)
+                       return hash_v4(iph, initval);
+               break;
+       case htons(ETH_P_IPV6):
+               ip6h = skb_header_pointer(skb, skb_network_offset(skb),
+                                         sizeof(*ip6h), &_ip6h);
+               if (ip6h)
+                       return hash_v6(ip6h, initval);
+               break;
+       }
+
+       return 0;
 }
-#endif
 
 static inline u32
 nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family,
-            u32 jhash_initval)
+            u32 initval)
 {
-       if (family == NFPROTO_IPV4)
-               queue += ((u64) hash_v4(skb, jhash_initval) * queues_total) >> 32;
-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
-       else if (family == NFPROTO_IPV6)
-               queue += ((u64) hash_v6(skb, jhash_initval) * queues_total) >> 32;
-#endif
+       switch (family) {
+       case NFPROTO_IPV4:
+               queue += reciprocal_scale(hash_v4(ip_hdr(skb), initval),
+                                         queues_total);
+               break;
+       case NFPROTO_IPV6:
+               queue += reciprocal_scale(hash_v6(ipv6_hdr(skb), initval),
+                                         queues_total);
+               break;
+       case NFPROTO_BRIDGE:
+               queue += reciprocal_scale(hash_bridge(skb, initval),
+                                         queues_total);
+               break;
+       }
 
        return queue;
 }
index 8972468bc94bc717a39e88a13298bf245f4bf855..5031e072567bd85318d5a6ab240b3ab79199facd 100644 (file)
@@ -19,6 +19,7 @@ struct nft_pktinfo {
        const struct net_device         *out;
        u8                              pf;
        u8                              hook;
+       bool                            tprot_set;
        u8                              tprot;
        /* for x_tables compatibility */
        struct xt_action_param          xt;
@@ -36,6 +37,23 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
        pkt->pf = pkt->xt.family = state->pf;
 }
 
+static inline void nft_set_pktinfo_proto_unspec(struct nft_pktinfo *pkt,
+                                               struct sk_buff *skb)
+{
+       pkt->tprot_set = false;
+       pkt->tprot = 0;
+       pkt->xt.thoff = 0;
+       pkt->xt.fragoff = 0;
+}
+
+static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt,
+                                         struct sk_buff *skb,
+                                         const struct nf_hook_state *state)
+{
+       nft_set_pktinfo(pkt, skb, state);
+       nft_set_pktinfo_proto_unspec(pkt, skb);
+}
+
 /**
  *     struct nft_verdict - nf_tables verdict
  *
@@ -127,6 +145,7 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
        return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE;
 }
 
+unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
 unsigned int nft_parse_register(const struct nlattr *attr);
 int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);
 
diff --git a/include/net/netfilter/nf_tables_bridge.h b/include/net/netfilter/nf_tables_bridge.h
deleted file mode 100644 (file)
index 511fb79..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _NET_NF_TABLES_BRIDGE_H
-#define _NET_NF_TABLES_BRIDGE_H
-
-int nft_bridge_iphdr_validate(struct sk_buff *skb);
-int nft_bridge_ip6hdr_validate(struct sk_buff *skb);
-
-#endif /* _NET_NF_TABLES_BRIDGE_H */
index a9060dd99db7691fb9521eb0fc22f70b75e26fb5..00f4f6b1b1ba0758735ebabdff902c43b22630ee 100644 (file)
@@ -28,6 +28,9 @@ extern const struct nft_expr_ops nft_cmp_fast_ops;
 int nft_cmp_module_init(void);
 void nft_cmp_module_exit(void);
 
+int nft_range_module_init(void);
+void nft_range_module_exit(void);
+
 int nft_lookup_module_init(void);
 void nft_lookup_module_exit(void);
 
index ca6ef6bf775ef544bce93b892ee156d449a62f9e..968f00b82fb5590202a232f09a2256ad1f8f9bd2 100644 (file)
@@ -14,11 +14,54 @@ nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
        nft_set_pktinfo(pkt, skb, state);
 
        ip = ip_hdr(pkt->skb);
+       pkt->tprot_set = true;
        pkt->tprot = ip->protocol;
        pkt->xt.thoff = ip_hdrlen(pkt->skb);
        pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
 }
 
+static inline int
+__nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
+                               struct sk_buff *skb,
+                               const struct nf_hook_state *state)
+{
+       struct iphdr *iph, _iph;
+       u32 len, thoff;
+
+       iph = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*iph),
+                                &_iph);
+       if (!iph)
+               return -1;
+
+       iph = ip_hdr(skb);
+       if (iph->ihl < 5 || iph->version != 4)
+               return -1;
+
+       len = ntohs(iph->tot_len);
+       thoff = iph->ihl * 4;
+       if (skb->len < len)
+               return -1;
+       else if (len < thoff)
+               return -1;
+
+       pkt->tprot_set = true;
+       pkt->tprot = iph->protocol;
+       pkt->xt.thoff = thoff;
+       pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
+
+       return 0;
+}
+
+static inline void
+nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
+                             struct sk_buff *skb,
+                             const struct nf_hook_state *state)
+{
+       nft_set_pktinfo(pkt, skb, state);
+       if (__nft_set_pktinfo_ipv4_validate(pkt, skb, state) < 0)
+               nft_set_pktinfo_proto_unspec(pkt, skb);
+}
+
 extern struct nft_af_info nft_af_ipv4;
 
 #endif
index 8ad39a6a5fe18703be7808b5ed4d92cf186bafd6..d150b50662017378644c8f3ccf0218ecceaa2331 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <net/ipv6.h>
 
-static inline int
+static inline void
 nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
                     struct sk_buff *skb,
                     const struct nf_hook_state *state)
@@ -15,15 +15,64 @@ nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
        nft_set_pktinfo(pkt, skb, state);
 
        protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL);
-       /* If malformed, drop it */
+       if (protohdr < 0) {
+               nft_set_pktinfo_proto_unspec(pkt, skb);
+               return;
+       }
+
+       pkt->tprot_set = true;
+       pkt->tprot = protohdr;
+       pkt->xt.thoff = thoff;
+       pkt->xt.fragoff = frag_off;
+}
+
+static inline int
+__nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
+                               struct sk_buff *skb,
+                               const struct nf_hook_state *state)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+       struct ipv6hdr *ip6h, _ip6h;
+       unsigned int thoff = 0;
+       unsigned short frag_off;
+       int protohdr;
+       u32 pkt_len;
+
+       ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h),
+                                 &_ip6h);
+       if (!ip6h)
+               return -1;
+
+       if (ip6h->version != 6)
+               return -1;
+
+       pkt_len = ntohs(ip6h->payload_len);
+       if (pkt_len + sizeof(*ip6h) > skb->len)
+               return -1;
+
+       protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL);
        if (protohdr < 0)
                return -1;
 
+       pkt->tprot_set = true;
        pkt->tprot = protohdr;
        pkt->xt.thoff = thoff;
        pkt->xt.fragoff = frag_off;
 
        return 0;
+#else
+       return -1;
+#endif
+}
+
+static inline void
+nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
+                             struct sk_buff *skb,
+                             const struct nf_hook_state *state)
+{
+       nft_set_pktinfo(pkt, skb, state);
+       if (__nft_set_pktinfo_ipv6_validate(pkt, skb, state) < 0)
+               nft_set_pktinfo_proto_unspec(pkt, skb);
 }
 
 extern struct nft_af_info nft_af_ipv6;
index 36d723579af21f78e2da780c4840762ce88a4770..58487b1cc99ab09e9d5f00e1cc9608ac9db606e9 100644 (file)
@@ -16,6 +16,6 @@ struct netns_nf {
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header *nf_log_dir_header;
 #endif
-       struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+       struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 };
 #endif
index 18d5dc13985dd88fa91face0c92972b428af033a..92f3c8677523237ea0db55b0269aa0b73b9c2009 100644 (file)
@@ -39,6 +39,7 @@
 #define GRE_IS_REC(f)          ((f) & GRE_REC)
 #define GRE_IS_ACK(f)          ((f) & GRE_ACK)
 
+#define GRE_VERSION_0          __cpu_to_be16(0x0000)
 #define GRE_VERSION_1          __cpu_to_be16(0x0001)
 #define GRE_PROTO_PPP          __cpu_to_be16(0x880b)
 #define GRE_PPTP_KEY_MASK      __cpu_to_be32(0xffff)
diff --git a/include/uapi/linux/netfilter/nf_log.h b/include/uapi/linux/netfilter/nf_log.h
new file mode 100644 (file)
index 0000000..8be21e0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _NETFILTER_NF_LOG_H
+#define _NETFILTER_NF_LOG_H
+
+#define NF_LOG_TCPSEQ          0x01    /* Log TCP sequence numbers */
+#define NF_LOG_TCPOPT          0x02    /* Log TCP options */
+#define NF_LOG_IPOPT           0x04    /* Log IP options */
+#define NF_LOG_UID             0x08    /* Log UID owning local socket */
+#define NF_LOG_NFLOG           0x10    /* Unsupported, don't reuse */
+#define NF_LOG_MACDECODE       0x20    /* Decode MAC header */
+#define NF_LOG_MASK            0x2f
+
+#endif /* _NETFILTER_NF_LOG_H */
index 28ce01d79707e20169839cbe4be7e1269e4a9c8c..c6c4477c136b9f77749088bc8b054f853b45b0f6 100644 (file)
@@ -546,6 +546,35 @@ enum nft_cmp_attributes {
 };
 #define NFTA_CMP_MAX           (__NFTA_CMP_MAX - 1)
 
+/**
+ * enum nft_range_ops - nf_tables range operator
+ *
+ * @NFT_RANGE_EQ: equal
+ * @NFT_RANGE_NEQ: not equal
+ */
+enum nft_range_ops {
+       NFT_RANGE_EQ,
+       NFT_RANGE_NEQ,
+};
+
+/**
+ * enum nft_range_attributes - nf_tables range expression netlink attributes
+ *
+ * @NFTA_RANGE_SREG: source register of data to compare (NLA_U32: nft_registers)
+ * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_cmp_ops)
+ * @NFTA_RANGE_FROM_DATA: data range from (NLA_NESTED: nft_data_attributes)
+ * @NFTA_RANGE_TO_DATA: data range to (NLA_NESTED: nft_data_attributes)
+ */
+enum nft_range_attributes {
+       NFTA_RANGE_UNSPEC,
+       NFTA_RANGE_SREG,
+       NFTA_RANGE_OP,
+       NFTA_RANGE_FROM_DATA,
+       NFTA_RANGE_TO_DATA,
+       __NFTA_RANGE_MAX
+};
+#define NFTA_RANGE_MAX         (__NFTA_RANGE_MAX - 1)
+
 enum nft_lookup_flags {
        NFT_LOOKUP_F_INV = (1 << 0),
 };
@@ -575,6 +604,10 @@ enum nft_dynset_ops {
        NFT_DYNSET_OP_UPDATE,
 };
 
+enum nft_dynset_flags {
+       NFT_DYNSET_F_INV        = (1 << 0),
+};
+
 /**
  * enum nft_dynset_attributes - dynset expression attributes
  *
@@ -585,6 +618,7 @@ enum nft_dynset_ops {
  * @NFTA_DYNSET_SREG_DATA: source register of the data (NLA_U32)
  * @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
  * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_DYNSET_FLAGS: flags (NLA_U32)
  */
 enum nft_dynset_attributes {
        NFTA_DYNSET_UNSPEC,
@@ -596,6 +630,7 @@ enum nft_dynset_attributes {
        NFTA_DYNSET_TIMEOUT,
        NFTA_DYNSET_EXPR,
        NFTA_DYNSET_PAD,
+       NFTA_DYNSET_FLAGS,
        __NFTA_DYNSET_MAX,
 };
 #define NFTA_DYNSET_MAX                (__NFTA_DYNSET_MAX - 1)
@@ -731,6 +766,7 @@ enum nft_meta_keys {
  * @NFTA_HASH_LEN: source data length (NLA_U32)
  * @NFTA_HASH_MODULUS: modulus value (NLA_U32)
  * @NFTA_HASH_SEED: seed value (NLA_U32)
+ * @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
  */
 enum nft_hash_attributes {
        NFTA_HASH_UNSPEC,
@@ -739,6 +775,7 @@ enum nft_hash_attributes {
        NFTA_HASH_LEN,
        NFTA_HASH_MODULUS,
        NFTA_HASH_SEED,
+       NFTA_HASH_OFFSET,
        __NFTA_HASH_MAX,
 };
 #define NFTA_HASH_MAX  (__NFTA_HASH_MAX - 1)
@@ -886,12 +923,14 @@ enum nft_log_attributes {
  * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
  * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16)
  * @NFTA_QUEUE_FLAGS: various flags (NLA_U16)
+ * @NFTA_QUEUE_SREG_QNUM: source register of queue number (NLA_U32: nft_registers)
  */
 enum nft_queue_attributes {
        NFTA_QUEUE_UNSPEC,
        NFTA_QUEUE_NUM,
        NFTA_QUEUE_TOTAL,
        NFTA_QUEUE_FLAGS,
+       NFTA_QUEUE_SREG_QNUM,
        __NFTA_QUEUE_MAX
 };
 #define NFTA_QUEUE_MAX         (__NFTA_QUEUE_MAX - 1)
@@ -1126,14 +1165,16 @@ enum nft_trace_types {
  * enum nft_ng_attributes - nf_tables number generator expression netlink attributes
  *
  * @NFTA_NG_DREG: destination register (NLA_U32)
- * @NFTA_NG_UNTIL: source value to increment the counter until reset (NLA_U32)
+ * @NFTA_NG_MODULUS: maximum counter value (NLA_U32)
  * @NFTA_NG_TYPE: operation type (NLA_U32)
+ * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32)
  */
 enum nft_ng_attributes {
        NFTA_NG_UNSPEC,
        NFTA_NG_DREG,
-       NFTA_NG_UNTIL,
+       NFTA_NG_MODULUS,
        NFTA_NG_TYPE,
+       NFTA_NG_OFFSET,
        __NFTA_NG_MAX
 };
 #define NFTA_NG_MAX    (__NFTA_NG_MAX - 1)
index 9df789709abe018f76a6b9c581718ac4374dc6da..6deb8867c5fc000f357b959065076fdbf5082486 100644 (file)
@@ -231,13 +231,13 @@ enum ctattr_secctx {
 
 enum ctattr_stats_cpu {
        CTA_STATS_UNSPEC,
-       CTA_STATS_SEARCHED,
+       CTA_STATS_SEARCHED,     /* no longer used */
        CTA_STATS_FOUND,
-       CTA_STATS_NEW,
+       CTA_STATS_NEW,          /* no longer used */
        CTA_STATS_INVALID,
        CTA_STATS_IGNORE,
-       CTA_STATS_DELETE,
-       CTA_STATS_DELETE_LIST,
+       CTA_STATS_DELETE,       /* no longer used */
+       CTA_STATS_DELETE_LIST,  /* no longer used */
        CTA_STATS_INSERT,
        CTA_STATS_INSERT_FAILED,
        CTA_STATS_DROP,
index 6db90372f09c3fbd2fa3facd42d0e0487691fbcb..3efc0ca18345e397e6c9704f2777d61b192ed455 100644 (file)
@@ -6,6 +6,7 @@
 
 /* timings are in milliseconds. */
 #define XT_HASHLIMIT_SCALE 10000
+#define XT_HASHLIMIT_SCALE_v2 1000000llu
 /* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
  * seconds, or one packet every 59 hours.
  */
@@ -63,6 +64,20 @@ struct hashlimit_cfg1 {
        __u8 srcmask, dstmask;
 };
 
+struct hashlimit_cfg2 {
+       __u64 avg;              /* Average secs between packets * scale */
+       __u64 burst;            /* Period multiplier for upper limit. */
+       __u32 mode;             /* bitmask of XT_HASHLIMIT_HASH_* */
+
+       /* user specified */
+       __u32 size;             /* how many buckets */
+       __u32 max;              /* max number of entries */
+       __u32 gc_interval;      /* gc interval */
+       __u32 expire;           /* when do entries expire? */
+
+       __u8 srcmask, dstmask;
+};
+
 struct xt_hashlimit_mtinfo1 {
        char name[IFNAMSIZ];
        struct hashlimit_cfg1 cfg;
@@ -71,4 +86,12 @@ struct xt_hashlimit_mtinfo1 {
        struct xt_hashlimit_htable *hinfo __attribute__((aligned(8)));
 };
 
+struct xt_hashlimit_mtinfo2 {
+       char name[NAME_MAX];
+       struct hashlimit_cfg2 cfg;
+
+       /* Used internally by the kernel */
+       struct xt_hashlimit_htable *hinfo __attribute__((aligned(8)));
+};
+
 #endif /* _UAPI_XT_HASHLIMIT_H */
index 77e7f69bf80d4ca8e31e09b5b07230bca1abf170..2fe9345c1407108bf5a0802671fa419aa9b24e7e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/netfilter_ipv6.h>
 #include <linux/netfilter_arp.h>
 #include <linux/in_route.h>
+#include <linux/rculist.h>
 #include <linux/inetdevice.h>
 
 #include <net/ip.h>
@@ -395,11 +396,10 @@ bridged_dnat:
                                skb->dev = nf_bridge->physindev;
                                nf_bridge_update_protocol(skb);
                                nf_bridge_push_encap_header(skb);
-                               NF_HOOK_THRESH(NFPROTO_BRIDGE,
-                                              NF_BR_PRE_ROUTING,
-                                              net, sk, skb, skb->dev, NULL,
-                                              br_nf_pre_routing_finish_bridge,
-                                              1);
+                               br_nf_hook_thresh(NF_BR_PRE_ROUTING,
+                                                 net, sk, skb, skb->dev,
+                                                 NULL,
+                                                 br_nf_pre_routing_finish);
                                return 0;
                        }
                        ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
@@ -417,10 +417,8 @@ bridged_dnat:
        skb->dev = nf_bridge->physindev;
        nf_bridge_update_protocol(skb);
        nf_bridge_push_encap_header(skb);
-       NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, net, sk, skb,
-                      skb->dev, NULL,
-                      br_handle_frame_finish, 1);
-
+       br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
+                         br_handle_frame_finish);
        return 0;
 }
 
@@ -992,6 +990,43 @@ static struct notifier_block brnf_notifier __read_mostly = {
        .notifier_call = brnf_device_event,
 };
 
+/* recursively invokes nf_hook_slow (again), skipping already-called
+ * hooks (< NF_BR_PRI_BRNF).
+ *
+ * Called with rcu read lock held.
+ */
+int br_nf_hook_thresh(unsigned int hook, struct net *net,
+                     struct sock *sk, struct sk_buff *skb,
+                     struct net_device *indev,
+                     struct net_device *outdev,
+                     int (*okfn)(struct net *, struct sock *,
+                                 struct sk_buff *))
+{
+       struct nf_hook_entry *elem;
+       struct nf_hook_state state;
+       int ret;
+
+       elem = rcu_dereference(net->nf.hooks[NFPROTO_BRIDGE][hook]);
+
+       while (elem && (elem->ops.priority <= NF_BR_PRI_BRNF))
+               elem = rcu_dereference(elem->next);
+
+       if (!elem)
+               return okfn(net, sk, skb);
+
+       /* We may already have this, but read-locks nest anyway */
+       rcu_read_lock();
+       nf_hook_state_init(&state, elem, hook, NF_BR_PRI_BRNF + 1,
+                          NFPROTO_BRIDGE, indev, outdev, sk, net, okfn);
+
+       ret = nf_hook_slow(skb, &state);
+       rcu_read_unlock();
+       if (ret == 1)
+               ret = okfn(net, sk, skb);
+
+       return ret;
+}
+
 #ifdef CONFIG_SYSCTL
 static
 int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
index 5e59a8457e7b19ddbd80a0f295a206e9202f3ccd..5989661c659f52e0ee352e8af8aba876e83290b4 100644 (file)
@@ -187,10 +187,9 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
                        skb->dev = nf_bridge->physindev;
                        nf_bridge_update_protocol(skb);
                        nf_bridge_push_encap_header(skb);
-                       NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
-                                      net, sk, skb, skb->dev, NULL,
-                                      br_nf_pre_routing_finish_bridge,
-                                      1);
+                       br_nf_hook_thresh(NF_BR_PRE_ROUTING,
+                                         net, sk, skb, skb->dev, NULL,
+                                         br_nf_pre_routing_finish_bridge);
                        return 0;
                }
                ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
@@ -207,9 +206,8 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
        skb->dev = nf_bridge->physindev;
        nf_bridge_update_protocol(skb);
        nf_bridge_push_encap_header(skb);
-       NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, net, sk, skb,
-                      skb->dev, NULL,
-                      br_handle_frame_finish, 1);
+       br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb,
+                         skb->dev, NULL, br_handle_frame_finish);
 
        return 0;
 }
index 152300d164acd1bb9702aa60db5f7a3ccc4752fe..9a11086ba6ff4a966e551ea650bc15df1b4483ac 100644 (file)
@@ -91,7 +91,7 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
        if (loginfo->type == NF_LOG_TYPE_LOG)
                bitmask = loginfo->u.log.logflags;
        else
-               bitmask = NF_LOG_MASK;
+               bitmask = NF_LOG_DEFAULT_MASK;
 
        if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
           htons(ETH_P_IP)) {
index 203964997a515a6bc4d961e59b365a5354df6518..2e7c4f974340919c2101ee60c3b3b86a727755d5 100644 (file)
@@ -24,7 +24,7 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
                return EBT_DROP;
 
        if (par->hooknum != NF_BR_BROUTING)
-               /* rcu_read_lock()ed by nf_hook_slow */
+               /* rcu_read_lock()ed by nf_hook_thresh */
                ether_addr_copy(eth_hdr(skb)->h_dest,
                                br_port_get_rcu(par->in)->br->dev->dev_addr);
        else
index 0833c251aef7963dc471e4385282c491b2fb2340..f5c11bbe27db651dfd66f6cb8e7dc5b77b88a511 100644 (file)
@@ -146,7 +146,7 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
                return 1;
        if (NF_INVF(e, EBT_IOUT, ebt_dev_check(e->out, out)))
                return 1;
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        if (in && (p = br_port_get_rcu(in)) != NULL &&
            NF_INVF(e, EBT_ILOGICALIN,
                    ebt_dev_check(e->logical_in, p->br->dev)))
index a78c4e2826e5a56d509635e2ca8f9ec4eeac481f..97afdc0744e6dce6ba83943d136e4c6fb886fbf8 100644 (file)
 #include <linux/module.h>
 #include <linux/netfilter_bridge.h>
 #include <net/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_bridge.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <net/netfilter/nf_tables_ipv4.h>
 #include <net/netfilter/nf_tables_ipv6.h>
 
-int nft_bridge_iphdr_validate(struct sk_buff *skb)
-{
-       struct iphdr *iph;
-       u32 len;
-
-       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-               return 0;
-
-       iph = ip_hdr(skb);
-       if (iph->ihl < 5 || iph->version != 4)
-               return 0;
-
-       len = ntohs(iph->tot_len);
-       if (skb->len < len)
-               return 0;
-       else if (len < (iph->ihl*4))
-               return 0;
-
-       if (!pskb_may_pull(skb, iph->ihl*4))
-               return 0;
-
-       return 1;
-}
-EXPORT_SYMBOL_GPL(nft_bridge_iphdr_validate);
-
-int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
-{
-       struct ipv6hdr *hdr;
-       u32 pkt_len;
-
-       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
-               return 0;
-
-       hdr = ipv6_hdr(skb);
-       if (hdr->version != 6)
-               return 0;
-
-       pkt_len = ntohs(hdr->payload_len);
-       if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
-               return 0;
-
-       return 1;
-}
-EXPORT_SYMBOL_GPL(nft_bridge_ip6hdr_validate);
-
-static inline void nft_bridge_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
-                                              struct sk_buff *skb,
-                                              const struct nf_hook_state *state)
-{
-       if (nft_bridge_iphdr_validate(skb))
-               nft_set_pktinfo_ipv4(pkt, skb, state);
-       else
-               nft_set_pktinfo(pkt, skb, state);
-}
-
-static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
-                                              struct sk_buff *skb,
-                                              const struct nf_hook_state *state)
-{
-#if IS_ENABLED(CONFIG_IPV6)
-       if (nft_bridge_ip6hdr_validate(skb) &&
-           nft_set_pktinfo_ipv6(pkt, skb, state) == 0)
-               return;
-#endif
-       nft_set_pktinfo(pkt, skb, state);
-}
-
 static unsigned int
 nft_do_chain_bridge(void *priv,
                    struct sk_buff *skb,
@@ -95,13 +27,13 @@ nft_do_chain_bridge(void *priv,
 
        switch (eth_hdr(skb)->h_proto) {
        case htons(ETH_P_IP):
-               nft_bridge_set_pktinfo_ipv4(&pkt, skb, state);
+               nft_set_pktinfo_ipv4_validate(&pkt, skb, state);
                break;
        case htons(ETH_P_IPV6):
-               nft_bridge_set_pktinfo_ipv6(&pkt, skb, state);
+               nft_set_pktinfo_ipv6_validate(&pkt, skb, state);
                break;
        default:
-               nft_set_pktinfo(&pkt, skb, state);
+               nft_set_pktinfo_unspec(&pkt, skb, state);
                break;
        }
 
@@ -207,12 +139,20 @@ static int __init nf_tables_bridge_init(void)
        int ret;
 
        nf_register_afinfo(&nf_br_afinfo);
-       nft_register_chain_type(&filter_bridge);
+       ret = nft_register_chain_type(&filter_bridge);
+       if (ret < 0)
+               goto err1;
+
        ret = register_pernet_subsys(&nf_tables_bridge_net_ops);
-       if (ret < 0) {
-               nft_unregister_chain_type(&filter_bridge);
-               nf_unregister_afinfo(&nf_br_afinfo);
-       }
+       if (ret < 0)
+               goto err2;
+
+       return ret;
+
+err2:
+       nft_unregister_chain_type(&filter_bridge);
+err1:
+       nf_unregister_afinfo(&nf_br_afinfo);
        return ret;
 }
 
index 0b77ffbc27d6d5714bea1a9477fc09e18a26a7c2..4b3df6b0e3b93cc47531950a9b4c8e6c9b5d1c13 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nft_reject.h>
-#include <net/netfilter/nf_tables_bridge.h>
 #include <net/netfilter/ipv4/nf_reject.h>
 #include <net/netfilter/ipv6/nf_reject.h>
 #include <linux/ip.h>
@@ -37,6 +36,30 @@ static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
        skb_pull(nskb, ETH_HLEN);
 }
 
+static int nft_bridge_iphdr_validate(struct sk_buff *skb)
+{
+       struct iphdr *iph;
+       u32 len;
+
+       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+               return 0;
+
+       iph = ip_hdr(skb);
+       if (iph->ihl < 5 || iph->version != 4)
+               return 0;
+
+       len = ntohs(iph->tot_len);
+       if (skb->len < len)
+               return 0;
+       else if (len < (iph->ihl*4))
+               return 0;
+
+       if (!pskb_may_pull(skb, iph->ihl*4))
+               return 0;
+
+       return 1;
+}
+
 /* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT)
  * or the bridge port (NF_BRIDGE PREROUTING).
  */
@@ -143,6 +166,25 @@ static void nft_reject_br_send_v4_unreach(struct net *net,
        br_forward(br_port_get_rcu(dev), nskb, false, true);
 }
 
+static int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
+{
+       struct ipv6hdr *hdr;
+       u32 pkt_len;
+
+       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+               return 0;
+
+       hdr = ipv6_hdr(skb);
+       if (hdr->version != 6)
+               return 0;
+
+       pkt_len = ntohs(hdr->payload_len);
+       if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
+               return 0;
+
+       return 1;
+}
+
 static void nft_reject_br_send_v6_tcp_reset(struct net *net,
                                            struct sk_buff *oldskb,
                                            const struct net_device *dev,
index 9dbece2f1296b65b4c66f8d9d9c3172b59ee1819..c0c291f721d6ce2065024df7085cd07f51a6db6b 100644 (file)
@@ -4055,12 +4055,17 @@ static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev,
 {
 #ifdef CONFIG_NETFILTER_INGRESS
        if (nf_hook_ingress_active(skb)) {
+               int ingress_retval;
+
                if (*pt_prev) {
                        *ret = deliver_skb(skb, *pt_prev, orig_dev);
                        *pt_prev = NULL;
                }
 
-               return nf_hook_ingress(skb);
+               rcu_read_lock();
+               ingress_retval = nf_hook_ingress(skb);
+               rcu_read_unlock();
+               return ingress_retval;
        }
 #endif /* CONFIG_NETFILTER_INGRESS */
        return 0;
index f993545a337342d2fbb912b7560cd1529c0b8145..7c00ce90adb8496ed9fb97894163f783b158e7cf 100644 (file)
@@ -156,7 +156,7 @@ static struct nf_loginfo trace_loginfo = {
        .u = {
                .log = {
                        .level = 4,
-                       .logflags = NF_LOG_MASK,
+                       .logflags = NF_LOG_DEFAULT_MASK,
                },
        },
 };
index 870aebda2932e317923f16438d5c4832aef516e8..713c09a74b9009cd3132bd388638f25590b5bdc6 100644 (file)
@@ -110,7 +110,7 @@ static unsigned int ipv4_helper(void *priv,
        if (!help)
                return NF_ACCEPT;
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        helper = rcu_dereference(help->helper);
        if (!helper)
                return NF_ACCEPT;
index 4b5904bc2614691cbd9ac0fcbf0e391f6074c517..d075b3cf24000c6eaba53964ce254b42214bd4b4 100644 (file)
@@ -149,7 +149,7 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
                return -NF_ACCEPT;
        }
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum);
 
        /* Ordinarily, we'd expect the inverted tupleproto, but it's
index 8945c26538149110c979ce58abd4f56461908718..b24795e2ee6d486c871149811b7916145345f6ea 100644 (file)
@@ -30,7 +30,7 @@ static struct nf_loginfo default_loginfo = {
        .u = {
                .log = {
                        .level    = LOGLEVEL_NOTICE,
-                       .logflags = NF_LOG_MASK,
+                       .logflags = NF_LOG_DEFAULT_MASK,
                },
        },
 };
index 20f225593a8b14563d68f13685d571aa2cfc47b8..856648966f4c209b5d01b608afb1b25a069b8b54 100644 (file)
@@ -29,7 +29,7 @@ static struct nf_loginfo default_loginfo = {
        .u = {
                .log = {
                        .level    = LOGLEVEL_NOTICE,
-                       .logflags = NF_LOG_MASK,
+                       .logflags = NF_LOG_DEFAULT_MASK,
                },
        },
 };
@@ -46,7 +46,7 @@ static void dump_ipv4_packet(struct nf_log_buf *m,
        if (info->type == NF_LOG_TYPE_LOG)
                logflags = info->u.log.logflags;
        else
-               logflags = NF_LOG_MASK;
+               logflags = NF_LOG_DEFAULT_MASK;
 
        ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
        if (ih == NULL) {
@@ -76,7 +76,7 @@ static void dump_ipv4_packet(struct nf_log_buf *m,
        if (ntohs(ih->frag_off) & IP_OFFSET)
                nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
 
-       if ((logflags & XT_LOG_IPOPT) &&
+       if ((logflags & NF_LOG_IPOPT) &&
            ih->ihl * 4 > sizeof(struct iphdr)) {
                const unsigned char *op;
                unsigned char _opt[4 * 15 - sizeof(struct iphdr)];
@@ -250,7 +250,7 @@ static void dump_ipv4_packet(struct nf_log_buf *m,
        }
 
        /* Max length: 15 "UID=4294967295 " */
-       if ((logflags & XT_LOG_UID) && !iphoff)
+       if ((logflags & NF_LOG_UID) && !iphoff)
                nf_log_dump_sk_uid_gid(m, skb->sk);
 
        /* Max length: 16 "MARK=0xFFFFFFFF " */
@@ -282,7 +282,7 @@ static void dump_ipv4_mac_header(struct nf_log_buf *m,
        if (info->type == NF_LOG_TYPE_LOG)
                logflags = info->u.log.logflags;
 
-       if (!(logflags & XT_LOG_MACDECODE))
+       if (!(logflags & NF_LOG_MACDECODE))
                goto fallback;
 
        switch (dev->type) {
index 9414923f1e156939bbd68acf22ca76d2e7e34698..edf05002d674eea2feb73a835577a158d9a6fa8f 100644 (file)
@@ -88,8 +88,8 @@ gre_manip_pkt(struct sk_buff *skb,
              const struct nf_conntrack_tuple *tuple,
              enum nf_nat_manip_type maniptype)
 {
-       const struct gre_hdr *greh;
-       struct gre_hdr_pptp *pgreh;
+       const struct gre_base_hdr *greh;
+       struct pptp_gre_header *pgreh;
 
        /* pgreh includes two optional 32bit fields which are not required
         * to be there.  That's where the magic '8' comes from */
@@ -97,18 +97,19 @@ gre_manip_pkt(struct sk_buff *skb,
                return false;
 
        greh = (void *)skb->data + hdroff;
-       pgreh = (struct gre_hdr_pptp *)greh;
+       pgreh = (struct pptp_gre_header *)greh;
 
        /* we only have destination manip of a packet, since 'source key'
         * is not present in the packet itself */
        if (maniptype != NF_NAT_MANIP_DST)
                return true;
-       switch (greh->version) {
-       case GRE_VERSION_1701:
+
+       switch (greh->flags & GRE_VERSION) {
+       case GRE_VERSION_0:
                /* We do not currently NAT any GREv0 packets.
                 * Try to behave like "nf_nat_proto_unknown" */
                break;
-       case GRE_VERSION_PPTP:
+       case GRE_VERSION_1:
                pr_debug("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
                pgreh->call_id = tuple->dst.u.gre.key;
                break;
index cd84d4295a2027642f46523fd105068144abfdfd..805c8ddfe86022e6b47df2026d5c5830c613b0ff 100644 (file)
@@ -21,7 +21,7 @@ nft_do_chain_arp(void *priv,
 {
        struct nft_pktinfo pkt;
 
-       nft_set_pktinfo(&pkt, skb, state);
+       nft_set_pktinfo_unspec(&pkt, skb, state);
 
        return nft_do_chain(&pkt, priv);
 }
@@ -80,7 +80,10 @@ static int __init nf_tables_arp_init(void)
 {
        int ret;
 
-       nft_register_chain_type(&filter_arp);
+       ret = nft_register_chain_type(&filter_arp);
+       if (ret < 0)
+               return ret;
+
        ret = register_pernet_subsys(&nf_tables_arp_net_ops);
        if (ret < 0)
                nft_unregister_chain_type(&filter_arp);
index e44ba3b12fbb03ac4f34626c35fa31a23f3633fa..2840a29b2e04d91c0cab54f67ba10d7d2bf30937 100644 (file)
@@ -103,7 +103,10 @@ static int __init nf_tables_ipv4_init(void)
 {
        int ret;
 
-       nft_register_chain_type(&filter_ipv4);
+       ret = nft_register_chain_type(&filter_ipv4);
+       if (ret < 0)
+               return ret;
+
        ret = register_pernet_subsys(&nf_tables_ipv4_net_ops);
        if (ret < 0)
                nft_unregister_chain_type(&filter_ipv4);
index 4062ed2530d2d9d88c489f31e2fadc49b55064a4..8c6ad2d319d674fbaf903ef57b999e558e224992 100644 (file)
@@ -6326,6 +6326,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 
        tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
        tcp_openreq_init(req, &tmp_opt, skb, sk);
+       inet_rsk(req)->no_srccheck = inet_sk(sk)->transparent;
 
        /* Note: tcp_v6_init_req() might override ir_iif for link locals */
        inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
index 04b9893285581eb783de801330f4ca45f08cbfcd..7ac37c314312b71e8db7e771b5191ab20785e899 100644 (file)
@@ -1196,7 +1196,6 @@ static void tcp_v4_init_req(struct request_sock *req,
 
        sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr);
        sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr);
-       ireq->no_srccheck = inet_sk(sk_listener)->transparent;
        ireq->opt = tcp_v4_save_options(skb);
 }
 
index 552fac2f390a2747c3ca9821fbb06d52ccaf0d9e..55aacea24396dc17d429896c5ff77e5e8162a52e 100644 (file)
@@ -190,7 +190,7 @@ static struct nf_loginfo trace_loginfo = {
        .u = {
                .log = {
                        .level = LOGLEVEL_WARNING,
-                       .logflags = NF_LOG_MASK,
+                       .logflags = NF_LOG_DEFAULT_MASK,
                },
        },
 };
index 1aa5848764a78a1691e8bbb9af4240eb1733c73e..963ee38486755487f3f4562a01091674de0fb279 100644 (file)
@@ -115,7 +115,7 @@ static unsigned int ipv6_helper(void *priv,
        help = nfct_help(ct);
        if (!help)
                return NF_ACCEPT;
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        helper = rcu_dereference(help->helper);
        if (!helper)
                return NF_ACCEPT;
index 660bc10c7a9c178ae50c12e0ba6245cb7bb6202d..f5a61bc3ec2b3b5bfd9ce75c3646a37598b9b71f 100644 (file)
@@ -165,7 +165,7 @@ icmpv6_error_message(struct net *net, struct nf_conn *tmpl,
                return -NF_ACCEPT;
        }
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum);
 
        /* Ordinarily, we'd expect the inverted tupleproto, but it's
index c1bcf699a23d1fb00f4d389bcdf6bcbe286d9e7d..57d86066a13bc567d0526da14b13173657acac9c 100644 (file)
@@ -30,7 +30,7 @@ static struct nf_loginfo default_loginfo = {
        .u = {
                .log = {
                        .level    = LOGLEVEL_NOTICE,
-                       .logflags = NF_LOG_MASK,
+                       .logflags = NF_LOG_DEFAULT_MASK,
                },
        },
 };
@@ -52,7 +52,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
        if (info->type == NF_LOG_TYPE_LOG)
                logflags = info->u.log.logflags;
        else
-               logflags = NF_LOG_MASK;
+               logflags = NF_LOG_DEFAULT_MASK;
 
        ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
        if (ih == NULL) {
@@ -84,7 +84,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
                }
 
                /* Max length: 48 "OPT (...) " */
-               if (logflags & XT_LOG_IPOPT)
+               if (logflags & NF_LOG_IPOPT)
                        nf_log_buf_add(m, "OPT ( ");
 
                switch (currenthdr) {
@@ -121,7 +121,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
                case IPPROTO_ROUTING:
                case IPPROTO_HOPOPTS:
                        if (fragment) {
-                               if (logflags & XT_LOG_IPOPT)
+                               if (logflags & NF_LOG_IPOPT)
                                        nf_log_buf_add(m, ")");
                                return;
                        }
@@ -129,7 +129,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
                        break;
                /* Max Length */
                case IPPROTO_AH:
-                       if (logflags & XT_LOG_IPOPT) {
+                       if (logflags & NF_LOG_IPOPT) {
                                struct ip_auth_hdr _ahdr;
                                const struct ip_auth_hdr *ah;
 
@@ -161,7 +161,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
                        hdrlen = (hp->hdrlen+2)<<2;
                        break;
                case IPPROTO_ESP:
-                       if (logflags & XT_LOG_IPOPT) {
+                       if (logflags & NF_LOG_IPOPT) {
                                struct ip_esp_hdr _esph;
                                const struct ip_esp_hdr *eh;
 
@@ -194,7 +194,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
                        nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr);
                        return;
                }
-               if (logflags & XT_LOG_IPOPT)
+               if (logflags & NF_LOG_IPOPT)
                        nf_log_buf_add(m, ") ");
 
                currenthdr = hp->nexthdr;
@@ -277,7 +277,7 @@ static void dump_ipv6_packet(struct nf_log_buf *m,
        }
 
        /* Max length: 15 "UID=4294967295 " */
-       if ((logflags & XT_LOG_UID) && recurse)
+       if ((logflags & NF_LOG_UID) && recurse)
                nf_log_dump_sk_uid_gid(m, skb->sk);
 
        /* Max length: 16 "MARK=0xFFFFFFFF " */
@@ -295,7 +295,7 @@ static void dump_ipv6_mac_header(struct nf_log_buf *m,
        if (info->type == NF_LOG_TYPE_LOG)
                logflags = info->u.log.logflags;
 
-       if (!(logflags & XT_LOG_MACDECODE))
+       if (!(logflags & NF_LOG_MACDECODE))
                goto fallback;
 
        switch (dev->type) {
index 30b22f4dff55e7cfc5f83a3549192f54615c8701..d6e4ba5de916a3e57782764a4e3ac9fcf54e341d 100644 (file)
@@ -22,9 +22,7 @@ static unsigned int nft_do_chain_ipv6(void *priv,
 {
        struct nft_pktinfo pkt;
 
-       /* malformed packet, drop it */
-       if (nft_set_pktinfo_ipv6(&pkt, skb, state) < 0)
-               return NF_DROP;
+       nft_set_pktinfo_ipv6(&pkt, skb, state);
 
        return nft_do_chain(&pkt, priv);
 }
@@ -102,7 +100,10 @@ static int __init nf_tables_ipv6_init(void)
 {
        int ret;
 
-       nft_register_chain_type(&filter_ipv6);
+       ret = nft_register_chain_type(&filter_ipv6);
+       if (ret < 0)
+               return ret;
+
        ret = register_pernet_subsys(&nf_tables_ipv6_net_ops);
        if (ret < 0)
                nft_unregister_chain_type(&filter_ipv6);
index 2535223ba9569112d84dae7d3d22b4816fd53497..f2727475895e77939d48a9df72fec6017fd8de95 100644 (file)
@@ -33,9 +33,7 @@ static unsigned int nf_route_table_hook(void *priv,
        u32 mark, flowlabel;
        int err;
 
-       /* malformed packet, drop it */
-       if (nft_set_pktinfo_ipv6(&pkt, skb, state) < 0)
-               return NF_DROP;
+       nft_set_pktinfo_ipv6(&pkt, skb, state);
 
        /* save source/dest address, mark, hoplimit, flowlabel, priority */
        memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
index 0c8581100ac62bfa6ea39c1a7cc3b05406611b55..c23c3c84416f7e3cdffd43d158a8722747190acb 100644 (file)
@@ -71,8 +71,9 @@ obj-$(CONFIG_NF_DUP_NETDEV)   += nf_dup_netdev.o
 
 # nf_tables
 nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o
-nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o nft_dynset.o
+nf_tables-objs += nft_immediate.o nft_cmp.o nft_range.o
 nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
+nf_tables-objs += nft_lookup.o nft_dynset.o
 
 obj-$(CONFIG_NF_TABLES)                += nf_tables.o
 obj-$(CONFIG_NF_TABLES_INET)   += nf_tables_inet.o
index 2c5327e43a88a3906e8f9653ebcb72e1882cb7f9..fa6715db4581087c360e77cdbe9d5a497c5bce38 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 #include <net/net_namespace.h>
 #include <net/sock.h>
 
@@ -61,33 +62,55 @@ EXPORT_SYMBOL(nf_hooks_needed);
 #endif
 
 static DEFINE_MUTEX(nf_hook_mutex);
+#define nf_entry_dereference(e) \
+       rcu_dereference_protected(e, lockdep_is_held(&nf_hook_mutex))
 
-static struct list_head *nf_find_hook_list(struct net *net,
-                                          const struct nf_hook_ops *reg)
+static struct nf_hook_entry *nf_hook_entry_head(struct net *net,
+                                               const struct nf_hook_ops *reg)
 {
-       struct list_head *hook_list = NULL;
+       struct nf_hook_entry *hook_head = NULL;
 
        if (reg->pf != NFPROTO_NETDEV)
-               hook_list = &net->nf.hooks[reg->pf][reg->hooknum];
+               hook_head = nf_entry_dereference(net->nf.hooks[reg->pf]
+                                                [reg->hooknum]);
        else if (reg->hooknum == NF_NETDEV_INGRESS) {
 #ifdef CONFIG_NETFILTER_INGRESS
                if (reg->dev && dev_net(reg->dev) == net)
-                       hook_list = &reg->dev->nf_hooks_ingress;
+                       hook_head =
+                               nf_entry_dereference(
+                                       reg->dev->nf_hooks_ingress);
 #endif
        }
-       return hook_list;
+       return hook_head;
 }
 
-struct nf_hook_entry {
-       const struct nf_hook_ops        *orig_ops;
-       struct nf_hook_ops              ops;
-};
+/* must hold nf_hook_mutex */
+static void nf_set_hooks_head(struct net *net, const struct nf_hook_ops *reg,
+                             struct nf_hook_entry *entry)
+{
+       switch (reg->pf) {
+       case NFPROTO_NETDEV:
+               /* We already checked in nf_register_net_hook() that this is
+                * used from ingress.
+                */
+               rcu_assign_pointer(reg->dev->nf_hooks_ingress, entry);
+               break;
+       default:
+               rcu_assign_pointer(net->nf.hooks[reg->pf][reg->hooknum],
+                                  entry);
+               break;
+       }
+}
 
 int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
 {
-       struct list_head *hook_list;
+       struct nf_hook_entry *hooks_entry;
        struct nf_hook_entry *entry;
-       struct nf_hook_ops *elem;
+
+       if (reg->pf == NFPROTO_NETDEV &&
+           (reg->hooknum != NF_NETDEV_INGRESS ||
+            !reg->dev || dev_net(reg->dev) != net))
+               return -EINVAL;
 
        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
@@ -95,19 +118,30 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
 
        entry->orig_ops = reg;
        entry->ops      = *reg;
+       entry->next     = NULL;
+
+       mutex_lock(&nf_hook_mutex);
+       hooks_entry = nf_hook_entry_head(net, reg);
 
-       hook_list = nf_find_hook_list(net, reg);
-       if (!hook_list) {
-               kfree(entry);
-               return -ENOENT;
+       if (hooks_entry && hooks_entry->orig_ops->priority > reg->priority) {
+               /* This is the case where we need to insert at the head */
+               entry->next = hooks_entry;
+               hooks_entry = NULL;
        }
 
-       mutex_lock(&nf_hook_mutex);
-       list_for_each_entry(elem, hook_list, list) {
-               if (reg->priority < elem->priority)
-                       break;
+       while (hooks_entry &&
+               reg->priority >= hooks_entry->orig_ops->priority &&
+               nf_entry_dereference(hooks_entry->next)) {
+               hooks_entry = nf_entry_dereference(hooks_entry->next);
+       }
+
+       if (hooks_entry) {
+               entry->next = nf_entry_dereference(hooks_entry->next);
+               rcu_assign_pointer(hooks_entry->next, entry);
+       } else {
+               nf_set_hooks_head(net, reg, entry);
        }
-       list_add_rcu(&entry->ops.list, elem->list.prev);
+
        mutex_unlock(&nf_hook_mutex);
 #ifdef CONFIG_NETFILTER_INGRESS
        if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
@@ -122,24 +156,33 @@ EXPORT_SYMBOL(nf_register_net_hook);
 
 void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
 {
-       struct list_head *hook_list;
-       struct nf_hook_entry *entry;
-       struct nf_hook_ops *elem;
-
-       hook_list = nf_find_hook_list(net, reg);
-       if (!hook_list)
-               return;
+       struct nf_hook_entry *hooks_entry;
 
        mutex_lock(&nf_hook_mutex);
-       list_for_each_entry(elem, hook_list, list) {
-               entry = container_of(elem, struct nf_hook_entry, ops);
-               if (entry->orig_ops == reg) {
-                       list_del_rcu(&entry->ops.list);
-                       break;
+       hooks_entry = nf_hook_entry_head(net, reg);
+       if (hooks_entry->orig_ops == reg) {
+               nf_set_hooks_head(net, reg,
+                                 nf_entry_dereference(hooks_entry->next));
+               goto unlock;
+       }
+       while (hooks_entry && nf_entry_dereference(hooks_entry->next)) {
+               struct nf_hook_entry *next =
+                       nf_entry_dereference(hooks_entry->next);
+               struct nf_hook_entry *nnext;
+
+               if (next->orig_ops != reg) {
+                       hooks_entry = next;
+                       continue;
                }
+               nnext = nf_entry_dereference(next->next);
+               rcu_assign_pointer(hooks_entry->next, nnext);
+               hooks_entry = next;
+               break;
        }
+
+unlock:
        mutex_unlock(&nf_hook_mutex);
-       if (&elem->list == hook_list) {
+       if (!hooks_entry) {
                WARN(1, "nf_unregister_net_hook: hook not found!\n");
                return;
        }
@@ -151,10 +194,10 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
        static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
 #endif
        synchronize_net();
-       nf_queue_nf_hook_drop(net, &entry->ops);
+       nf_queue_nf_hook_drop(net, hooks_entry);
        /* other cpu might still process nfqueue verdict that used reg */
        synchronize_net();
-       kfree(entry);
+       kfree(hooks_entry);
 }
 EXPORT_SYMBOL(nf_unregister_net_hook);
 
@@ -294,10 +337,9 @@ void _nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
 }
 EXPORT_SYMBOL(_nf_unregister_hooks);
 
-unsigned int nf_iterate(struct list_head *head,
-                       struct sk_buff *skb,
+unsigned int nf_iterate(struct sk_buff *skb,
                        struct nf_hook_state *state,
-                       struct nf_hook_ops **elemp)
+                       struct nf_hook_entry **entryp)
 {
        unsigned int verdict;
 
@@ -305,20 +347,23 @@ unsigned int nf_iterate(struct list_head *head,
         * The caller must not block between calls to this
         * function because of risk of continuing from deleted element.
         */
-       list_for_each_entry_continue_rcu((*elemp), head, list) {
-               if (state->thresh > (*elemp)->priority)
+       while (*entryp) {
+               if (state->thresh > (*entryp)->ops.priority) {
+                       *entryp = rcu_dereference((*entryp)->next);
                        continue;
+               }
 
                /* Optimization: we don't need to hold module
                   reference here, since function can't sleep. --RR */
 repeat:
-               verdict = (*elemp)->hook((*elemp)->priv, skb, state);
+               verdict = (*entryp)->ops.hook((*entryp)->ops.priv, skb, state);
                if (verdict != NF_ACCEPT) {
 #ifdef CONFIG_NETFILTER_DEBUG
                        if (unlikely((verdict & NF_VERDICT_MASK)
                                                        > NF_MAX_VERDICT)) {
                                NFDEBUG("Evil return from %p(%u).\n",
-                                       (*elemp)->hook, state->hook);
+                                       (*entryp)->ops.hook, state->hook);
+                               *entryp = rcu_dereference((*entryp)->next);
                                continue;
                        }
 #endif
@@ -326,25 +371,23 @@ repeat:
                                return verdict;
                        goto repeat;
                }
+               *entryp = rcu_dereference((*entryp)->next);
        }
        return NF_ACCEPT;
 }
 
 
 /* Returns 1 if okfn() needs to be executed by the caller,
- * -EPERM for NF_DROP, 0 otherwise. */
+ * -EPERM for NF_DROP, 0 otherwise.  Caller must hold rcu_read_lock. */
 int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
 {
-       struct nf_hook_ops *elem;
+       struct nf_hook_entry *entry;
        unsigned int verdict;
        int ret = 0;
 
-       /* We may already have this, but read-locks nest anyway */
-       rcu_read_lock();
-
-       elem = list_entry_rcu(state->hook_list, struct nf_hook_ops, list);
+       entry = rcu_dereference(state->hook_entries);
 next_hook:
-       verdict = nf_iterate(state->hook_list, skb, state, &elem);
+       verdict = nf_iterate(skb, state, &entry);
        if (verdict == NF_ACCEPT || verdict == NF_STOP) {
                ret = 1;
        } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) {
@@ -353,8 +396,10 @@ next_hook:
                if (ret == 0)
                        ret = -EPERM;
        } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
-               int err = nf_queue(skb, elem, state,
-                                  verdict >> NF_VERDICT_QBITS);
+               int err;
+
+               RCU_INIT_POINTER(state->hook_entries, entry);
+               err = nf_queue(skb, state, verdict >> NF_VERDICT_QBITS);
                if (err < 0) {
                        if (err == -ESRCH &&
                           (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
@@ -362,7 +407,6 @@ next_hook:
                        kfree_skb(skb);
                }
        }
-       rcu_read_unlock();
        return ret;
 }
 EXPORT_SYMBOL(nf_hook_slow);
@@ -482,7 +526,7 @@ static int __net_init netfilter_net_init(struct net *net)
 
        for (i = 0; i < ARRAY_SIZE(net->nf.hooks); i++) {
                for (h = 0; h < NF_MAX_HOOKS; h++)
-                       INIT_LIST_HEAD(&net->nf.hooks[i][h]);
+                       RCU_INIT_POINTER(net->nf.hooks[i][h], NULL);
        }
 
 #ifdef CONFIG_PROC_FS
index 6570982605e257c98a8a5fa4c5717c0dcdd71525..ba6a1d4212225f5ff735eed006e12b3a244a5076 100644 (file)
@@ -379,7 +379,6 @@ static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
        struct nf_conn *ct = (struct nf_conn *)nfct;
-       struct net *net = nf_ct_net(ct);
        struct nf_conntrack_l4proto *l4proto;
 
        pr_debug("destroy_conntrack(%p)\n", ct);
@@ -406,7 +405,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
 
        nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
-       NF_CT_STAT_INC(net, delete);
        local_bh_enable();
 
        if (ct->master)
@@ -438,7 +436,6 @@ static void nf_ct_delete_from_lists(struct nf_conn *ct)
 
        nf_ct_add_to_dying_list(ct);
 
-       NF_CT_STAT_INC(net, delete_list);
        local_bh_enable();
 }
 
@@ -529,11 +526,8 @@ begin:
                if (nf_ct_is_dying(ct))
                        continue;
 
-               if (nf_ct_key_equal(h, tuple, zone, net)) {
-                       NF_CT_STAT_INC_ATOMIC(net, found);
+               if (nf_ct_key_equal(h, tuple, zone, net))
                        return h;
-               }
-               NF_CT_STAT_INC_ATOMIC(net, searched);
        }
        /*
         * if the nulls value we got at the end of this lookup is
@@ -798,7 +792,6 @@ __nf_conntrack_confirm(struct sk_buff *skb)
         */
        __nf_conntrack_hash_insert(ct, hash, reply_hash);
        nf_conntrack_double_unlock(hash, reply_hash);
-       NF_CT_STAT_INC(net, insert);
        local_bh_enable();
 
        help = nfct_help(ct);
@@ -857,7 +850,6 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
                        rcu_read_unlock();
                        return 1;
                }
-               NF_CT_STAT_INC_ATOMIC(net, searched);
        }
 
        if (get_nulls_value(n) != hash) {
@@ -1177,10 +1169,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                }
                spin_unlock(&nf_conntrack_expect_lock);
        }
-       if (!exp) {
+       if (!exp)
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
-               NF_CT_STAT_INC(net, new);
-       }
 
        /* Now it is inserted into the unconfirmed list, bump refcount */
        nf_conntrack_get(&ct->ct_general);
@@ -1285,7 +1275,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
                skb->nfct = NULL;
        }
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        l3proto = __nf_ct_l3proto_find(pf);
        ret = l3proto->get_l4proto(skb, skb_network_offset(skb),
                                   &dataoff, &protonum);
index b6934b5edf7a0afff352435ca96d1e75e897dfe3..e3ed200608788bc5e8dc96a14b8674d0fbaa7d4b 100644 (file)
@@ -301,8 +301,6 @@ static int find_pattern(const char *data, size_t dlen,
        size_t i = plen;
 
        pr_debug("find_pattern `%s': dlen = %Zu\n", pattern, dlen);
-       if (dlen == 0)
-               return 0;
 
        if (dlen <= plen) {
                /* Short packet: try for partial? */
@@ -311,19 +309,8 @@ static int find_pattern(const char *data, size_t dlen,
                else return 0;
        }
 
-       if (strncasecmp(data, pattern, plen) != 0) {
-#if 0
-               size_t i;
-
-               pr_debug("ftp: string mismatch\n");
-               for (i = 0; i < plen; i++) {
-                       pr_debug("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
-                                i, data[i], data[i],
-                                pattern[i], pattern[i]);
-               }
-#endif
+       if (strncasecmp(data, pattern, plen) != 0)
                return 0;
-       }
 
        pr_debug("Pattern matches!\n");
        /* Now we've found the constant string, try to skip
index 5c0db5c64734a98d909e7e329ac7aecc54cfb431..f65d93639d12595884081726808f4c1e17caec03 100644 (file)
@@ -736,7 +736,7 @@ static int callforward_do_filter(struct net *net,
        const struct nf_afinfo *afinfo;
        int ret = 0;
 
-       /* rcu_read_lock()ed by nf_hook_slow() */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        afinfo = nf_get_afinfo(family);
        if (!afinfo)
                return 0;
index b989b81ac156380b5151a14fb26bf46e3f000dcc..336e21559e011d4f0fe154934ecf7d5a765aefdd 100644 (file)
@@ -189,7 +189,6 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
        struct nf_conntrack_helper *helper = NULL;
        struct nf_conn_help *help;
        struct net *net = nf_ct_net(ct);
-       int ret = 0;
 
        /* We already got a helper explicitly attached. The function
         * nf_conntrack_alter_reply - in case NAT is in use - asks for looking
@@ -223,15 +222,13 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
        if (helper == NULL) {
                if (help)
                        RCU_INIT_POINTER(help->helper, NULL);
-               goto out;
+               return 0;
        }
 
        if (help == NULL) {
                help = nf_ct_helper_ext_add(ct, helper, flags);
-               if (help == NULL) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (help == NULL)
+                       return -ENOMEM;
        } else {
                /* We only allow helper re-assignment of the same sort since
                 * we cannot reallocate the helper extension area.
@@ -240,13 +237,13 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
 
                if (tmp && tmp->help != helper->help) {
                        RCU_INIT_POINTER(help->helper, NULL);
-                       goto out;
+                       return 0;
                }
        }
 
        rcu_assign_pointer(help->helper, helper);
-out:
-       return ret;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
 
@@ -349,7 +346,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
        /* Called from the helper function, this call never fails */
        help = nfct_help(ct);
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        helper = rcu_dereference(help->helper);
 
        nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
index c052b712c49f056d67ddddfd3de28fe165ccfd63..27540455dc62a3e827e2267a0b25e8ed210f8cb9 100644 (file)
@@ -1984,13 +1984,9 @@ ctnetlink_ct_stat_cpu_fill_info(struct sk_buff *skb, u32 portid, u32 seq,
        nfmsg->version      = NFNETLINK_V0;
        nfmsg->res_id       = htons(cpu);
 
-       if (nla_put_be32(skb, CTA_STATS_SEARCHED, htonl(st->searched)) ||
-           nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
-           nla_put_be32(skb, CTA_STATS_NEW, htonl(st->new)) ||
+       if (nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
            nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) ||
            nla_put_be32(skb, CTA_STATS_IGNORE, htonl(st->ignore)) ||
-           nla_put_be32(skb, CTA_STATS_DELETE, htonl(st->delete)) ||
-           nla_put_be32(skb, CTA_STATS_DELETE_LIST, htonl(st->delete_list)) ||
            nla_put_be32(skb, CTA_STATS_INSERT, htonl(st->insert)) ||
            nla_put_be32(skb, CTA_STATS_INSERT_FAILED,
                                htonl(st->insert_failed)) ||
index a96451a7af20a8104c82711f31958b043de4bde7..9a715f88b2f194e90a64c3b15449810e832b9b2c 100644 (file)
@@ -192,15 +192,15 @@ static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple,
 static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                             struct net *net, struct nf_conntrack_tuple *tuple)
 {
-       const struct gre_hdr_pptp *pgrehdr;
-       struct gre_hdr_pptp _pgrehdr;
+       const struct pptp_gre_header *pgrehdr;
+       struct pptp_gre_header _pgrehdr;
        __be16 srckey;
-       const struct gre_hdr *grehdr;
-       struct gre_hdr _grehdr;
+       const struct gre_base_hdr *grehdr;
+       struct gre_base_hdr _grehdr;
 
        /* first only delinearize old RFC1701 GRE header */
        grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
-       if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {
+       if (!grehdr || (grehdr->flags & GRE_VERSION) != GRE_VERSION_1) {
                /* try to behave like "nf_conntrack_proto_generic" */
                tuple->src.u.all = 0;
                tuple->dst.u.all = 0;
@@ -212,8 +212,8 @@ static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
        if (!pgrehdr)
                return true;
 
-       if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
-               pr_debug("GRE_VERSION_PPTP but unknown proto\n");
+       if (grehdr->protocol != GRE_PROTO_PPP) {
+               pr_debug("Unsupported GRE proto(0x%x)\n", ntohs(grehdr->protocol));
                return false;
        }
 
index dff0f0cc59e456171d81b8c5400bf30378f5ea66..ef7063eced7c490dd6813d3e54ee72fdad9a8565 100644 (file)
@@ -169,7 +169,7 @@ int nf_ct_seq_adjust(struct sk_buff *skb,
        s32 seqoff, ackoff;
        struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
        struct nf_ct_seqadj *this_way, *other_way;
-       int res;
+       int res = 1;
 
        this_way  = &seqadj->seq[dir];
        other_way = &seqadj->seq[!dir];
@@ -184,27 +184,31 @@ int nf_ct_seq_adjust(struct sk_buff *skb,
        else
                seqoff = this_way->offset_before;
 
+       newseq = htonl(ntohl(tcph->seq) + seqoff);
+       inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, false);
+       pr_debug("Adjusting sequence number from %u->%u\n",
+                ntohl(tcph->seq), ntohl(newseq));
+       tcph->seq = newseq;
+
+       if (!tcph->ack)
+               goto out;
+
        if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
                  other_way->correction_pos))
                ackoff = other_way->offset_after;
        else
                ackoff = other_way->offset_before;
 
-       newseq = htonl(ntohl(tcph->seq) + seqoff);
        newack = htonl(ntohl(tcph->ack_seq) - ackoff);
-
-       inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, false);
        inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack,
                                 false);
-
-       pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
+       pr_debug("Adjusting ack number from %u->%u, ack from %u->%u\n",
                 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
                 ntohl(newack));
-
-       tcph->seq = newseq;
        tcph->ack_seq = newack;
 
        res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo);
+out:
        spin_unlock_bh(&ct->lock);
 
        return res;
index 7d77217de6a3b4e7821452f721c0902ca6fecd81..621b81c7bddc5d486dff5cff77c4070a41edda36 100644 (file)
@@ -83,9 +83,10 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
 static int iswordc(const char c)
 {
        if (isalnum(c) || c == '!' || c == '"' || c == '%' ||
-           (c >= '(' && c <= '/') || c == ':' || c == '<' || c == '>' ||
+           (c >= '(' && c <= '+') || c == ':' || c == '<' || c == '>' ||
            c == '?' || (c >= '[' && c <= ']') || c == '_' || c == '`' ||
-           c == '{' || c == '}' || c == '~')
+           c == '{' || c == '}' || c == '~' || (c >= '-' && c <= '/') ||
+           c == '\'')
                return 1;
        return 0;
 }
@@ -329,13 +330,12 @@ static const char *sip_follow_continuation(const char *dptr, const char *limit)
 static const char *sip_skip_whitespace(const char *dptr, const char *limit)
 {
        for (; dptr < limit; dptr++) {
-               if (*dptr == ' ')
+               if (*dptr == ' ' || *dptr == '\t')
                        continue;
                if (*dptr != '\r' && *dptr != '\n')
                        break;
                dptr = sip_follow_continuation(dptr, limit);
-               if (dptr == NULL)
-                       return NULL;
+               break;
        }
        return dptr;
 }
index 3d9a316a3c77a84fa68212669b00ecb33418880c..5f446cd9f3fd4ef5116741f0732f39775a4b65df 100644 (file)
@@ -212,6 +212,11 @@ static int ct_seq_show(struct seq_file *s, void *v)
        if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
                return 0;
 
+       if (nf_ct_should_gc(ct)) {
+               nf_ct_kill(ct);
+               goto release;
+       }
+
        /* we only want to print DIR_ORIGINAL */
        if (NF_CT_DIRECTION(hash))
                goto release;
@@ -352,13 +357,13 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
        seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
                        "%08x %08x %08x %08x %08x  %08x %08x %08x %08x\n",
                   nr_conntracks,
-                  st->searched,
+                  0,
                   st->found,
-                  st->new,
+                  0,
                   st->invalid,
                   st->ignore,
-                  st->delete,
-                  st->delete_list,
+                  0,
+                  0,
                   st->insert,
                   st->insert_failed,
                   st->drop,
index 065522564ac6a032ce1ece83be62438f7d8b0636..e0adb5959342148d9501a48f6bb92b90d2566c00 100644 (file)
 
 
 /* core.c */
-unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb,
-                       struct nf_hook_state *state, struct nf_hook_ops **elemp);
+unsigned int nf_iterate(struct sk_buff *skb, struct nf_hook_state *state,
+                       struct nf_hook_entry **entryp);
 
 /* nf_queue.c */
-int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem,
-            struct nf_hook_state *state, unsigned int queuenum);
-void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops);
+int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
+            unsigned int queuenum);
+void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry);
 int __init netfilter_queue_init(void);
 
 /* nf_log.c */
index a5aa5967b8e17b894a798dbf29d07bf12063fc16..119fe1cb1ea917918d586e96c1e034d82e0d151a 100644 (file)
@@ -77,7 +77,7 @@ int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb,
        nf_log_buf_add(m, "SPT=%u DPT=%u ",
                       ntohs(th->source), ntohs(th->dest));
        /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
-       if (logflags & XT_LOG_TCPSEQ) {
+       if (logflags & NF_LOG_TCPSEQ) {
                nf_log_buf_add(m, "SEQ=%u ACK=%u ",
                               ntohl(th->seq), ntohl(th->ack_seq));
        }
@@ -107,7 +107,7 @@ int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb,
        /* Max length: 11 "URGP=65535 " */
        nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr));
 
-       if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) {
+       if ((logflags & NF_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) {
                u_int8_t _opt[60 - sizeof(struct tcphdr)];
                const u_int8_t *op;
                unsigned int i;
index b19ad20a705ca7845ad21a5d272accba190f3f38..96964a0070e11da46aa97b3fe94fb4f778e40418 100644 (file)
@@ -96,14 +96,14 @@ void nf_queue_entry_get_refs(struct nf_queue_entry *entry)
 }
 EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
 
-void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
+void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry)
 {
        const struct nf_queue_handler *qh;
 
        rcu_read_lock();
        qh = rcu_dereference(net->nf.queue_handler);
        if (qh)
-               qh->nf_hook_drop(net, ops);
+               qh->nf_hook_drop(net, entry);
        rcu_read_unlock();
 }
 
@@ -112,7 +112,6 @@ void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
  * through nf_reinject().
  */
 int nf_queue(struct sk_buff *skb,
-            struct nf_hook_ops *elem,
             struct nf_hook_state *state,
             unsigned int queuenum)
 {
@@ -141,7 +140,6 @@ int nf_queue(struct sk_buff *skb,
 
        *entry = (struct nf_queue_entry) {
                .skb    = skb,
-               .elem   = elem,
                .state  = *state,
                .size   = sizeof(*entry) + afinfo->route_key_size,
        };
@@ -165,11 +163,15 @@ err:
 
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 {
+       struct nf_hook_entry *hook_entry;
        struct sk_buff *skb = entry->skb;
-       struct nf_hook_ops *elem = entry->elem;
        const struct nf_afinfo *afinfo;
+       struct nf_hook_ops *elem;
        int err;
 
+       hook_entry = rcu_dereference(entry->state.hook_entries);
+       elem = &hook_entry->ops;
+
        nf_queue_entry_release_refs(entry);
 
        /* Continue traversal iff userspace said ok... */
@@ -186,8 +188,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 
        if (verdict == NF_ACCEPT) {
        next_hook:
-               verdict = nf_iterate(entry->state.hook_list,
-                                    skb, &entry->state, &elem);
+               verdict = nf_iterate(skb, &entry->state, &hook_entry);
        }
 
        switch (verdict & NF_VERDICT_MASK) {
@@ -198,7 +199,8 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
                local_bh_enable();
                break;
        case NF_QUEUE:
-               err = nf_queue(skb, elem, &entry->state,
+               RCU_INIT_POINTER(entry->state.hook_entries, hook_entry);
+               err = nf_queue(skb, &entry->state,
                               verdict >> NF_VERDICT_QBITS);
                if (err < 0) {
                        if (err == -ESRCH &&
index bd9715e5ff266202ab4c93f6475410d64e0ec9c5..b70d3ea1430e7db49c4a4fc86f87dbb47cfdbe8c 100644 (file)
@@ -4409,6 +4409,31 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
        return 0;
 }
 
+/**
+ *     nft_parse_u32_check - fetch u32 attribute and check for maximum value
+ *
+ *     @attr: netlink attribute to fetch value from
+ *     @max: maximum value to be stored in dest
+ *     @dest: pointer to the variable
+ *
+ *     Parse, check and store a given u32 netlink attribute into variable.
+ *     This function returns -ERANGE if the value goes over maximum value.
+ *     Otherwise a 0 is returned and the attribute value is stored in the
+ *     destination variable.
+ */
+unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest)
+{
+       int val;
+
+       val = ntohl(nla_get_be32(attr));
+       if (val > max)
+               return -ERANGE;
+
+       *dest = val;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nft_parse_u32_check);
+
 /**
  *     nft_parse_register - parse a register value from a netlink attribute
  *
index fb8b5892b5ffa8ec6b0cf35792991b9125f082eb..0dd5c695482f64b248de0906fcbbd1dcb8df6364 100644 (file)
@@ -34,7 +34,7 @@ static struct nf_loginfo trace_loginfo = {
        .u = {
                .log = {
                        .level = LOGLEVEL_WARNING,
-                       .logflags = NF_LOG_MASK,
+                       .logflags = NF_LOG_DEFAULT_MASK,
                },
        },
 };
@@ -93,12 +93,15 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
 
        if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
                ptr = skb_network_header(skb);
-       else
+       else {
+               if (!pkt->tprot_set)
+                       return false;
                ptr = skb_network_header(skb) + pkt->xt.thoff;
+       }
 
        ptr += priv->offset;
 
-       if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
+       if (unlikely(ptr + priv->len > skb_tail_pointer(skb)))
                return false;
 
        *dest = 0;
@@ -260,8 +263,13 @@ int __init nf_tables_core_module_init(void)
        if (err < 0)
                goto err7;
 
-       return 0;
+       err = nft_range_module_init();
+       if (err < 0)
+               goto err8;
 
+       return 0;
+err8:
+       nft_dynset_module_exit();
 err7:
        nft_payload_module_exit();
 err6:
index 6b5f76295d3d534f3c4255d037ea0b30bfdbb22f..f713cc205669bfcd9f2b187940bdb6f880875624 100644 (file)
@@ -82,7 +82,10 @@ static int __init nf_tables_inet_init(void)
 {
        int ret;
 
-       nft_register_chain_type(&filter_inet);
+       ret = nft_register_chain_type(&filter_inet);
+       if (ret < 0)
+               return ret;
+
        ret = register_pernet_subsys(&nf_tables_inet_net_ops);
        if (ret < 0)
                nft_unregister_chain_type(&filter_inet);
index 75d696f11045779bd08503bb49ec954abc63eeb4..9e2ae424b64005555d5a7132ea1aa469dc4d0fc1 100644 (file)
 #include <net/netfilter/nf_tables_ipv4.h>
 #include <net/netfilter/nf_tables_ipv6.h>
 
-static inline void
-nft_netdev_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
-                           struct sk_buff *skb,
-                           const struct nf_hook_state *state)
-{
-       struct iphdr *iph, _iph;
-       u32 len, thoff;
-
-       nft_set_pktinfo(pkt, skb, state);
-
-       iph = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*iph),
-                                &_iph);
-       if (!iph)
-               return;
-
-       if (iph->ihl < 5 || iph->version != 4)
-               return;
-
-       len = ntohs(iph->tot_len);
-       thoff = iph->ihl * 4;
-       if (skb->len < len)
-               return;
-       else if (len < thoff)
-               return;
-
-       pkt->tprot = iph->protocol;
-       pkt->xt.thoff = thoff;
-       pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
-}
-
-static inline void
-__nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
-                             struct sk_buff *skb,
-                             const struct nf_hook_state *state)
-{
-#if IS_ENABLED(CONFIG_IPV6)
-       struct ipv6hdr *ip6h, _ip6h;
-       unsigned int thoff = 0;
-       unsigned short frag_off;
-       int protohdr;
-       u32 pkt_len;
-
-       ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h),
-                                 &_ip6h);
-       if (!ip6h)
-               return;
-
-       if (ip6h->version != 6)
-               return;
-
-       pkt_len = ntohs(ip6h->payload_len);
-       if (pkt_len + sizeof(*ip6h) > skb->len)
-               return;
-
-       protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL);
-       if (protohdr < 0)
-                return;
-
-       pkt->tprot = protohdr;
-       pkt->xt.thoff = thoff;
-       pkt->xt.fragoff = frag_off;
-#endif
-}
-
-static inline void nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
-                                              struct sk_buff *skb,
-                                              const struct nf_hook_state *state)
-{
-       nft_set_pktinfo(pkt, skb, state);
-       __nft_netdev_set_pktinfo_ipv6(pkt, skb, state);
-}
-
 static unsigned int
 nft_do_chain_netdev(void *priv, struct sk_buff *skb,
                    const struct nf_hook_state *state)
@@ -95,13 +23,13 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
-               nft_netdev_set_pktinfo_ipv4(&pkt, skb, state);
+               nft_set_pktinfo_ipv4_validate(&pkt, skb, state);
                break;
        case htons(ETH_P_IPV6):
-               nft_netdev_set_pktinfo_ipv6(&pkt, skb, state);
+               nft_set_pktinfo_ipv6_validate(&pkt, skb, state);
                break;
        default:
-               nft_set_pktinfo(&pkt, skb, state);
+               nft_set_pktinfo_unspec(&pkt, skb, state);
                break;
        }
 
@@ -221,14 +149,25 @@ static int __init nf_tables_netdev_init(void)
 {
        int ret;
 
-       nft_register_chain_type(&nft_filter_chain_netdev);
-       ret = register_pernet_subsys(&nf_tables_netdev_net_ops);
-       if (ret < 0) {
-               nft_unregister_chain_type(&nft_filter_chain_netdev);
+       ret = nft_register_chain_type(&nft_filter_chain_netdev);
+       if (ret)
                return ret;
-       }
-       register_netdevice_notifier(&nf_tables_netdev_notifier);
+
+       ret = register_pernet_subsys(&nf_tables_netdev_net_ops);
+       if (ret)
+               goto err1;
+
+       ret = register_netdevice_notifier(&nf_tables_netdev_notifier);
+       if (ret)
+               goto err2;
+
        return 0;
+
+err2:
+       unregister_pernet_subsys(&nf_tables_netdev_net_ops);
+err1:
+       nft_unregister_chain_type(&nft_filter_chain_netdev);
+       return ret;
 }
 
 static void __exit nf_tables_netdev_exit(void)
index fa24a5b398b1f889817b8873be1aa197bbf179d3..ab695f8e2d294b0c69df035cd3d153d03ab34fce 100644 (file)
@@ -113,20 +113,22 @@ static int nf_trace_fill_pkt_info(struct sk_buff *nlskb,
                                  const struct nft_pktinfo *pkt)
 {
        const struct sk_buff *skb = pkt->skb;
-       unsigned int len = min_t(unsigned int,
-                                pkt->xt.thoff - skb_network_offset(skb),
-                                NFT_TRACETYPE_NETWORK_HSIZE);
        int off = skb_network_offset(skb);
+       unsigned int len, nh_end;
 
+       nh_end = pkt->tprot_set ? pkt->xt.thoff : skb->len;
+       len = min_t(unsigned int, nh_end - skb_network_offset(skb),
+                   NFT_TRACETYPE_NETWORK_HSIZE);
        if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len))
                return -1;
 
-       len = min_t(unsigned int, skb->len - pkt->xt.thoff,
-                   NFT_TRACETYPE_TRANSPORT_HSIZE);
-
-       if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
-                             pkt->xt.thoff, len))
-               return -1;
+       if (pkt->tprot_set) {
+               len = min_t(unsigned int, skb->len - pkt->xt.thoff,
+                           NFT_TRACETYPE_TRANSPORT_HSIZE);
+               if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
+                                     pkt->xt.thoff, len))
+                       return -1;
+       }
 
        if (!skb_mac_header_was_set(skb))
                return 0;
index e924e95fcc7ff48a0724692723bc17c3800930ef..3b79f34b5095eff787cffa727bd286b341821a3d 100644 (file)
@@ -43,7 +43,7 @@ nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
        if (help == NULL)
                return NF_DROP;
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        helper = rcu_dereference(help->helper);
        if (helper == NULL)
                return NF_DROP;
index 6577db524ef672d7ba6aed4a39a0d7dc41baa226..eb086a192c5a0d8c0f64bbe0c52818b8afe4fa90 100644 (file)
@@ -442,7 +442,9 @@ __build_packet_message(struct nfnl_log_net *log,
                        if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
                                         htonl(indev->ifindex)) ||
                        /* this is the bridge group "brX" */
-                       /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
+                       /* rcu_read_lock()ed by nf_hook_thresh or
+                        * nf_log_packet.
+                        */
                            nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV,
                                         htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
                                goto nla_put_failure;
@@ -477,7 +479,9 @@ __build_packet_message(struct nfnl_log_net *log,
                        if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
                                         htonl(outdev->ifindex)) ||
                        /* this is the bridge group "brX" */
-                       /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
+                       /* rcu_read_lock()ed by nf_hook_thresh or
+                        * nf_log_packet.
+                        */
                            nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV,
                                         htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
                                goto nla_put_failure;
index f49f45081acb2200cc8acaed205f82a3298888ba..af832c5260485f3f99a3dae8fdf0019f896350ef 100644 (file)
@@ -740,7 +740,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
        struct net *net = entry->state.net;
        struct nfnl_queue_net *q = nfnl_queue_pernet(net);
 
-       /* rcu_read_lock()ed by nf_hook_slow() */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        queue = instance_lookup(q, queuenum);
        if (!queue)
                return -ESRCH;
@@ -917,12 +917,14 @@ static struct notifier_block nfqnl_dev_notifier = {
        .notifier_call  = nfqnl_rcv_dev_event,
 };
 
-static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long ops_ptr)
+static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long entry_ptr)
 {
-       return entry->elem == (struct nf_hook_ops *)ops_ptr;
+       return rcu_access_pointer(entry->state.hook_entries) ==
+               (struct nf_hook_entry *)entry_ptr;
 }
 
-static void nfqnl_nf_hook_drop(struct net *net, struct nf_hook_ops *hook)
+static void nfqnl_nf_hook_drop(struct net *net,
+                              const struct nf_hook_entry *hook)
 {
        struct nfnl_queue_net *q = nfnl_queue_pernet(net);
        int i;
@@ -1522,9 +1524,16 @@ static int __init nfnetlink_queue_init(void)
                goto cleanup_netlink_notifier;
        }
 
-       register_netdevice_notifier(&nfqnl_dev_notifier);
+       status = register_netdevice_notifier(&nfqnl_dev_notifier);
+       if (status < 0) {
+               pr_err("nf_queue: failed to register netdevice notifier\n");
+               goto cleanup_netlink_subsys;
+       }
+
        return status;
 
+cleanup_netlink_subsys:
+       nfnetlink_subsys_unregister(&nfqnl_subsys);
 cleanup_netlink_notifier:
        netlink_unregister_notifier(&nfqnl_rtnl_notifier);
        unregister_pernet_subsys(&nfnl_queue_net_ops);
index d71cc18fa35daaee8e2c12cfdbee557d17daf559..31c15ed2e5fcb1cce63c620650d17bc0942a8ce2 100644 (file)
@@ -52,6 +52,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
 {
        struct nft_bitwise *priv = nft_expr_priv(expr);
        struct nft_data_desc d1, d2;
+       u32 len;
        int err;
 
        if (tb[NFTA_BITWISE_SREG] == NULL ||
@@ -61,7 +62,12 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
            tb[NFTA_BITWISE_XOR] == NULL)
                return -EINVAL;
 
-       priv->len  = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
+       err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
+       if (err < 0)
+               return err;
+
+       priv->len = len;
+
        priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
        err = nft_validate_register_load(priv->sreg, priv->len);
        if (err < 0)
index b78c28ba465ff9c1eed6b6006b6c5e9d9da58072..ee63d981268d9ebb8fd42329bd0e242195e09003 100644 (file)
@@ -99,6 +99,7 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
                              const struct nlattr * const tb[])
 {
        struct nft_byteorder *priv = nft_expr_priv(expr);
+       u32 size, len;
        int err;
 
        if (tb[NFTA_BYTEORDER_SREG] == NULL ||
@@ -117,7 +118,12 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
                return -EINVAL;
        }
 
-       priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
+       err = nft_parse_u32_check(tb[NFTA_BYTEORDER_SIZE], U8_MAX, &size);
+       if (err < 0)
+               return err;
+
+       priv->size = size;
+
        switch (priv->size) {
        case 2:
        case 4:
@@ -128,7 +134,12 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
        }
 
        priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]);
-       priv->len  = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
+       err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len);
+       if (err < 0)
+               return err;
+
+       priv->len = len;
+
        err = nft_validate_register_load(priv->sreg, priv->len);
        if (err < 0)
                return err;
index e25b35d70e4dc8a1f63de86f112f37760c132227..2e53739812b1712af2f60762ed5c8a029facd5a0 100644 (file)
@@ -84,6 +84,9 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        if (err < 0)
                return err;
 
+       if (desc.len > U8_MAX)
+               return -ERANGE;
+
        priv->op  = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
        priv->len = desc.len;
        return 0;
index 51e180f2a00374d3d28860817a6d5e40b3d27c6b..d7b0d171172ad792321d3d46eaf413791c4174a5 100644 (file)
@@ -128,15 +128,18 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                memcpy(dest, &count, sizeof(count));
                return;
        }
+       case NFT_CT_L3PROTOCOL:
+               *dest = nf_ct_l3num(ct);
+               return;
+       case NFT_CT_PROTOCOL:
+               *dest = nf_ct_protonum(ct);
+               return;
        default:
                break;
        }
 
        tuple = &ct->tuplehash[priv->dir].tuple;
        switch (priv->key) {
-       case NFT_CT_L3PROTOCOL:
-               *dest = nf_ct_l3num(ct);
-               return;
        case NFT_CT_SRC:
                memcpy(dest, tuple->src.u3.all,
                       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
@@ -145,9 +148,6 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                memcpy(dest, tuple->dst.u3.all,
                       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
                return;
-       case NFT_CT_PROTOCOL:
-               *dest = nf_ct_protonum(ct);
-               return;
        case NFT_CT_PROTO_SRC:
                *dest = (__force __u16)tuple->src.u.all;
                return;
@@ -283,8 +283,9 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
 
        case NFT_CT_L3PROTOCOL:
        case NFT_CT_PROTOCOL:
-               if (tb[NFTA_CT_DIRECTION] == NULL)
-                       return -EINVAL;
+               /* For compatibility, do not report error if NFTA_CT_DIRECTION
+                * attribute is specified.
+                */
                len = sizeof(u8);
                break;
        case NFT_CT_SRC:
@@ -363,6 +364,8 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
        switch (priv->key) {
 #ifdef CONFIG_NF_CONNTRACK_MARK
        case NFT_CT_MARK:
+               if (tb[NFTA_CT_DIRECTION])
+                       return -EINVAL;
                len = FIELD_SIZEOF(struct nf_conn, mark);
                break;
 #endif
@@ -432,8 +435,6 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
 
        switch (priv->key) {
-       case NFT_CT_L3PROTOCOL:
-       case NFT_CT_PROTOCOL:
        case NFT_CT_SRC:
        case NFT_CT_DST:
        case NFT_CT_PROTO_SRC:
index 0af26699bf048ecc2abcc0f8d1fa4d5828a8d182..e3b83c31da2e56ee9932d4d3d22dc8acfd87a617 100644 (file)
@@ -22,6 +22,7 @@ struct nft_dynset {
        enum nft_dynset_ops             op:8;
        enum nft_registers              sreg_key:8;
        enum nft_registers              sreg_data:8;
+       bool                            invert;
        u64                             timeout;
        struct nft_expr                 *expr;
        struct nft_set_binding          binding;
@@ -82,10 +83,14 @@ static void nft_dynset_eval(const struct nft_expr *expr,
 
                if (sexpr != NULL)
                        sexpr->ops->eval(sexpr, regs, pkt);
+
+               if (priv->invert)
+                       regs->verdict.code = NFT_BREAK;
                return;
        }
 out:
-       regs->verdict.code = NFT_BREAK;
+       if (!priv->invert)
+               regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
@@ -96,6 +101,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
        [NFTA_DYNSET_SREG_DATA] = { .type = NLA_U32 },
        [NFTA_DYNSET_TIMEOUT]   = { .type = NLA_U64 },
        [NFTA_DYNSET_EXPR]      = { .type = NLA_NESTED },
+       [NFTA_DYNSET_FLAGS]     = { .type = NLA_U32 },
 };
 
 static int nft_dynset_init(const struct nft_ctx *ctx,
@@ -113,6 +119,15 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
            tb[NFTA_DYNSET_SREG_KEY] == NULL)
                return -EINVAL;
 
+       if (tb[NFTA_DYNSET_FLAGS]) {
+               u32 flags = ntohl(nla_get_be32(tb[NFTA_DYNSET_FLAGS]));
+
+               if (flags & ~NFT_DYNSET_F_INV)
+                       return -EINVAL;
+               if (flags & NFT_DYNSET_F_INV)
+                       priv->invert = true;
+       }
+
        set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME],
                                   genmask);
        if (IS_ERR(set)) {
@@ -220,6 +235,7 @@ static void nft_dynset_destroy(const struct nft_ctx *ctx,
 static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_dynset *priv = nft_expr_priv(expr);
+       u32 flags = priv->invert ? NFT_DYNSET_F_INV : 0;
 
        if (nft_dump_register(skb, NFTA_DYNSET_SREG_KEY, priv->sreg_key))
                goto nla_put_failure;
@@ -235,6 +251,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
        if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr))
                goto nla_put_failure;
+       if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags)))
+               goto nla_put_failure;
        return 0;
 
 nla_put_failure:
index 82c264e402781d8b8c52d04332c1b993e5c83fed..a84cf3d6605661aa8bb8966e226a79ea1b63786a 100644 (file)
@@ -59,7 +59,7 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_exthdr *priv = nft_expr_priv(expr);
-       u32 offset, len;
+       u32 offset, len, err;
 
        if (tb[NFTA_EXTHDR_DREG] == NULL ||
            tb[NFTA_EXTHDR_TYPE] == NULL ||
@@ -67,11 +67,13 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
            tb[NFTA_EXTHDR_LEN] == NULL)
                return -EINVAL;
 
-       offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
-       len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
+       err = nft_parse_u32_check(tb[NFTA_EXTHDR_OFFSET], U8_MAX, &offset);
+       if (err < 0)
+               return err;
 
-       if (offset > U8_MAX || len > U8_MAX)
-               return -ERANGE;
+       err = nft_parse_u32_check(tb[NFTA_EXTHDR_LEN], U8_MAX, &len);
+       if (err < 0)
+               return err;
 
        priv->type   = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
        priv->offset = offset;
index 764251d31e4653337bb6728f13b51565d9557e3e..09473b415b95b281c3264cda23d446dd5a3d56ab 100644 (file)
@@ -23,6 +23,7 @@ struct nft_hash {
        u8                      len;
        u32                     modulus;
        u32                     seed;
+       u32                     offset;
 };
 
 static void nft_hash_eval(const struct nft_expr *expr,
@@ -31,10 +32,10 @@ static void nft_hash_eval(const struct nft_expr *expr,
 {
        struct nft_hash *priv = nft_expr_priv(expr);
        const void *data = &regs->data[priv->sreg];
+       u32 h;
 
-       regs->data[priv->dreg] =
-               reciprocal_scale(jhash(data, priv->len, priv->seed),
-                                priv->modulus);
+       h = reciprocal_scale(jhash(data, priv->len, priv->seed), priv->modulus);
+       regs->data[priv->dreg] = h + priv->offset;
 }
 
 static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
@@ -59,6 +60,9 @@ static int nft_hash_init(const struct nft_ctx *ctx,
            !tb[NFTA_HASH_MODULUS])
                return -EINVAL;
 
+       if (tb[NFTA_HASH_OFFSET])
+               priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
+
        priv->sreg = nft_parse_register(tb[NFTA_HASH_SREG]);
        priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
 
@@ -72,6 +76,9 @@ static int nft_hash_init(const struct nft_ctx *ctx,
        if (priv->modulus <= 1)
                return -ERANGE;
 
+       if (priv->offset + priv->modulus - 1 < priv->offset)
+               return -EOVERFLOW;
+
        priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
 
        return nft_validate_register_load(priv->sreg, len) &&
@@ -94,7 +101,9 @@ static int nft_hash_dump(struct sk_buff *skb,
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
                goto nla_put_failure;
-
+       if (priv->offset != 0)
+               if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
+                       goto nla_put_failure;
        return 0;
 
 nla_put_failure:
index db3b746858e35a008ad0668f42e6037e36e1f80e..d17018ff54e6e67accc7f60e22f3cbfea6adfa94 100644 (file)
@@ -53,6 +53,10 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
                            tb[NFTA_IMMEDIATE_DATA]);
        if (err < 0)
                return err;
+
+       if (desc.len > U8_MAX)
+               return -ERANGE;
+
        priv->dlen = desc.len;
 
        priv->dreg = nft_parse_register(tb[NFTA_IMMEDIATE_DREG]);
index 24a73bb26e94471d00491cdf0211a791c9518533..1b01404bb33fa7832b9cbe14ba9ad24142f363f9 100644 (file)
@@ -58,8 +58,11 @@ static int nft_log_init(const struct nft_ctx *ctx,
        if (tb[NFTA_LOG_LEVEL] != NULL &&
            tb[NFTA_LOG_GROUP] != NULL)
                return -EINVAL;
-       if (tb[NFTA_LOG_GROUP] != NULL)
+       if (tb[NFTA_LOG_GROUP] != NULL) {
                li->type = NF_LOG_TYPE_ULOG;
+               if (tb[NFTA_LOG_FLAGS] != NULL)
+                       return -EINVAL;
+       }
 
        nla = tb[NFTA_LOG_PREFIX];
        if (nla != NULL) {
@@ -87,6 +90,10 @@ static int nft_log_init(const struct nft_ctx *ctx,
                if (tb[NFTA_LOG_FLAGS] != NULL) {
                        li->u.log.logflags =
                                ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
+                       if (li->u.log.logflags & ~NF_LOG_MASK) {
+                               err = -EINVAL;
+                               goto err1;
+                       }
                }
                break;
        case NF_LOG_TYPE_ULOG:
index e164325d1bc05d66d6a4fb296a2a3d6778ef15ce..8166b6994cc75dcd6a556172ae541c13ce337fc4 100644 (file)
@@ -43,7 +43,7 @@ static void nft_lookup_eval(const struct nft_expr *expr,
                return;
        }
 
-       if (found && set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP)
                nft_data_copy(&regs->data[priv->dreg],
                              nft_set_ext_data(ext), set->dlen);
 
index 8a6bc7630912dea058df1b3ed896daa535ad95f1..6c1e0246706e06b492dbdb2ed068acf1fa2879da 100644 (file)
@@ -52,6 +52,8 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                *dest = pkt->pf;
                break;
        case NFT_META_L4PROTO:
+               if (!pkt->tprot_set)
+                       goto err;
                *dest = pkt->tprot;
                break;
        case NFT_META_PRIORITY:
index 294745ecb0fcca6d6738dcf108db6ac82b0073db..55bc5ab78d4a292b6326e57f2a12f0ee25232b20 100644 (file)
@@ -21,8 +21,9 @@ static DEFINE_PER_CPU(struct rnd_state, nft_numgen_prandom_state);
 
 struct nft_ng_inc {
        enum nft_registers      dreg:8;
-       u32                     until;
+       u32                     modulus;
        atomic_t                counter;
+       u32                     offset;
 };
 
 static void nft_ng_inc_eval(const struct nft_expr *expr,
@@ -34,16 +35,17 @@ static void nft_ng_inc_eval(const struct nft_expr *expr,
 
        do {
                oval = atomic_read(&priv->counter);
-               nval = (oval + 1 < priv->until) ? oval + 1 : 0;
+               nval = (oval + 1 < priv->modulus) ? oval + 1 : 0;
        } while (atomic_cmpxchg(&priv->counter, oval, nval) != oval);
 
-       memcpy(&regs->data[priv->dreg], &priv->counter, sizeof(u32));
+       regs->data[priv->dreg] = nval + priv->offset;
 }
 
 static const struct nla_policy nft_ng_policy[NFTA_NG_MAX + 1] = {
        [NFTA_NG_DREG]          = { .type = NLA_U32 },
-       [NFTA_NG_UNTIL]         = { .type = NLA_U32 },
+       [NFTA_NG_MODULUS]       = { .type = NLA_U32 },
        [NFTA_NG_TYPE]          = { .type = NLA_U32 },
+       [NFTA_NG_OFFSET]        = { .type = NLA_U32 },
 };
 
 static int nft_ng_inc_init(const struct nft_ctx *ctx,
@@ -52,10 +54,16 @@ static int nft_ng_inc_init(const struct nft_ctx *ctx,
 {
        struct nft_ng_inc *priv = nft_expr_priv(expr);
 
-       priv->until = ntohl(nla_get_be32(tb[NFTA_NG_UNTIL]));
-       if (priv->until == 0)
+       if (tb[NFTA_NG_OFFSET])
+               priv->offset = ntohl(nla_get_be32(tb[NFTA_NG_OFFSET]));
+
+       priv->modulus = ntohl(nla_get_be32(tb[NFTA_NG_MODULUS]));
+       if (priv->modulus == 0)
                return -ERANGE;
 
+       if (priv->offset + priv->modulus - 1 < priv->offset)
+               return -EOVERFLOW;
+
        priv->dreg = nft_parse_register(tb[NFTA_NG_DREG]);
        atomic_set(&priv->counter, 0);
 
@@ -64,14 +72,16 @@ static int nft_ng_inc_init(const struct nft_ctx *ctx,
 }
 
 static int nft_ng_dump(struct sk_buff *skb, enum nft_registers dreg,
-                      u32 until, enum nft_ng_types type)
+                      u32 modulus, enum nft_ng_types type, u32 offset)
 {
        if (nft_dump_register(skb, NFTA_NG_DREG, dreg))
                goto nla_put_failure;
-       if (nla_put_be32(skb, NFTA_NG_UNTIL, htonl(until)))
+       if (nla_put_be32(skb, NFTA_NG_MODULUS, htonl(modulus)))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_NG_TYPE, htonl(type)))
                goto nla_put_failure;
+       if (nla_put_be32(skb, NFTA_NG_OFFSET, htonl(offset)))
+               goto nla_put_failure;
 
        return 0;
 
@@ -83,12 +93,14 @@ static int nft_ng_inc_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_ng_inc *priv = nft_expr_priv(expr);
 
-       return nft_ng_dump(skb, priv->dreg, priv->until, NFT_NG_INCREMENTAL);
+       return nft_ng_dump(skb, priv->dreg, priv->modulus, NFT_NG_INCREMENTAL,
+                          priv->offset);
 }
 
 struct nft_ng_random {
        enum nft_registers      dreg:8;
-       u32                     until;
+       u32                     modulus;
+       u32                     offset;
 };
 
 static void nft_ng_random_eval(const struct nft_expr *expr,
@@ -97,9 +109,10 @@ static void nft_ng_random_eval(const struct nft_expr *expr,
 {
        struct nft_ng_random *priv = nft_expr_priv(expr);
        struct rnd_state *state = this_cpu_ptr(&nft_numgen_prandom_state);
+       u32 val;
 
-       regs->data[priv->dreg] = reciprocal_scale(prandom_u32_state(state),
-                                                 priv->until);
+       val = reciprocal_scale(prandom_u32_state(state), priv->modulus);
+       regs->data[priv->dreg] = val + priv->offset;
 }
 
 static int nft_ng_random_init(const struct nft_ctx *ctx,
@@ -108,10 +121,16 @@ static int nft_ng_random_init(const struct nft_ctx *ctx,
 {
        struct nft_ng_random *priv = nft_expr_priv(expr);
 
-       priv->until = ntohl(nla_get_be32(tb[NFTA_NG_UNTIL]));
-       if (priv->until == 0)
+       if (tb[NFTA_NG_OFFSET])
+               priv->offset = ntohl(nla_get_be32(tb[NFTA_NG_OFFSET]));
+
+       priv->modulus = ntohl(nla_get_be32(tb[NFTA_NG_MODULUS]));
+       if (priv->modulus == 0)
                return -ERANGE;
 
+       if (priv->offset + priv->modulus - 1 < priv->offset)
+               return -EOVERFLOW;
+
        prandom_init_once(&nft_numgen_prandom_state);
 
        priv->dreg = nft_parse_register(tb[NFTA_NG_DREG]);
@@ -124,7 +143,8 @@ static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_ng_random *priv = nft_expr_priv(expr);
 
-       return nft_ng_dump(skb, priv->dreg, priv->until, NFT_NG_RANDOM);
+       return nft_ng_dump(skb, priv->dreg, priv->modulus, NFT_NG_RANDOM,
+                          priv->offset);
 }
 
 static struct nft_expr_type nft_ng_type;
@@ -149,8 +169,8 @@ nft_ng_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
 {
        u32 type;
 
-       if (!tb[NFTA_NG_DREG]   ||
-           !tb[NFTA_NG_UNTIL]  ||
+       if (!tb[NFTA_NG_DREG]    ||
+           !tb[NFTA_NG_MODULUS] ||
            !tb[NFTA_NG_TYPE])
                return ERR_PTR(-EINVAL);
 
index 12cd4bf16d17d36f1c5c250771792d853443c853..b2f88617611aac450631e606174f5bfd58cd38fa 100644 (file)
@@ -92,6 +92,8 @@ static void nft_payload_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
+               if (!pkt->tprot_set)
+                       goto err;
                offset = pkt->xt.thoff;
                break;
        default:
@@ -184,6 +186,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
+               if (!pkt->tprot_set)
+                       goto err;
                offset = pkt->xt.thoff;
                break;
        default:
index 61d216eb79175ac2a699190b04eb5d447ed66759..393d359a1889fe30541271973fadc489936d5c44 100644 (file)
 static u32 jhash_initval __read_mostly;
 
 struct nft_queue {
-       u16     queuenum;
-       u16     queues_total;
-       u16     flags;
+       enum nft_registers      sreg_qnum:8;
+       u16                     queuenum;
+       u16                     queues_total;
+       u16                     flags;
 };
 
 static void nft_queue_eval(const struct nft_expr *expr,
@@ -54,31 +55,78 @@ static void nft_queue_eval(const struct nft_expr *expr,
        regs->verdict.code = ret;
 }
 
+static void nft_queue_sreg_eval(const struct nft_expr *expr,
+                               struct nft_regs *regs,
+                               const struct nft_pktinfo *pkt)
+{
+       struct nft_queue *priv = nft_expr_priv(expr);
+       u32 queue, ret;
+
+       queue = regs->data[priv->sreg_qnum];
+
+       ret = NF_QUEUE_NR(queue);
+       if (priv->flags & NFT_QUEUE_FLAG_BYPASS)
+               ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
+
+       regs->verdict.code = ret;
+}
+
 static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
        [NFTA_QUEUE_NUM]        = { .type = NLA_U16 },
        [NFTA_QUEUE_TOTAL]      = { .type = NLA_U16 },
        [NFTA_QUEUE_FLAGS]      = { .type = NLA_U16 },
+       [NFTA_QUEUE_SREG_QNUM]  = { .type = NLA_U32 },
 };
 
 static int nft_queue_init(const struct nft_ctx *ctx,
-                          const struct nft_expr *expr,
-                          const struct nlattr * const tb[])
+                         const struct nft_expr *expr,
+                         const struct nlattr * const tb[])
 {
        struct nft_queue *priv = nft_expr_priv(expr);
+       u32 maxid;
 
-       if (tb[NFTA_QUEUE_NUM] == NULL)
-               return -EINVAL;
-
-       init_hashrandom(&jhash_initval);
        priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM]));
 
-       if (tb[NFTA_QUEUE_TOTAL] != NULL)
+       if (tb[NFTA_QUEUE_TOTAL])
                priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL]));
-       if (tb[NFTA_QUEUE_FLAGS] != NULL) {
+       else
+               priv->queues_total = 1;
+
+       if (priv->queues_total == 0)
+               return -EINVAL;
+
+       maxid = priv->queues_total - 1 + priv->queuenum;
+       if (maxid > U16_MAX)
+               return -ERANGE;
+
+       if (tb[NFTA_QUEUE_FLAGS]) {
+               priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS]));
+               if (priv->flags & ~NFT_QUEUE_FLAG_MASK)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static int nft_queue_sreg_init(const struct nft_ctx *ctx,
+                              const struct nft_expr *expr,
+                              const struct nlattr * const tb[])
+{
+       struct nft_queue *priv = nft_expr_priv(expr);
+       int err;
+
+       priv->sreg_qnum = nft_parse_register(tb[NFTA_QUEUE_SREG_QNUM]);
+       err = nft_validate_register_load(priv->sreg_qnum, sizeof(u32));
+       if (err < 0)
+               return err;
+
+       if (tb[NFTA_QUEUE_FLAGS]) {
                priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS]));
                if (priv->flags & ~NFT_QUEUE_FLAG_MASK)
                        return -EINVAL;
+               if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT)
+                       return -EOPNOTSUPP;
        }
+
        return 0;
 }
 
@@ -97,6 +145,21 @@ nla_put_failure:
        return -1;
 }
 
+static int
+nft_queue_sreg_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+       const struct nft_queue *priv = nft_expr_priv(expr);
+
+       if (nft_dump_register(skb, NFTA_QUEUE_SREG_QNUM, priv->sreg_qnum) ||
+           nla_put_be16(skb, NFTA_QUEUE_FLAGS, htons(priv->flags)))
+               goto nla_put_failure;
+
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
 static struct nft_expr_type nft_queue_type;
 static const struct nft_expr_ops nft_queue_ops = {
        .type           = &nft_queue_type,
@@ -106,9 +169,35 @@ static const struct nft_expr_ops nft_queue_ops = {
        .dump           = nft_queue_dump,
 };
 
+static const struct nft_expr_ops nft_queue_sreg_ops = {
+       .type           = &nft_queue_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_queue)),
+       .eval           = nft_queue_sreg_eval,
+       .init           = nft_queue_sreg_init,
+       .dump           = nft_queue_sreg_dump,
+};
+
+static const struct nft_expr_ops *
+nft_queue_select_ops(const struct nft_ctx *ctx,
+                    const struct nlattr * const tb[])
+{
+       if (tb[NFTA_QUEUE_NUM] && tb[NFTA_QUEUE_SREG_QNUM])
+               return ERR_PTR(-EINVAL);
+
+       init_hashrandom(&jhash_initval);
+
+       if (tb[NFTA_QUEUE_NUM])
+               return &nft_queue_ops;
+
+       if (tb[NFTA_QUEUE_SREG_QNUM])
+               return &nft_queue_sreg_ops;
+
+       return ERR_PTR(-EINVAL);
+}
+
 static struct nft_expr_type nft_queue_type __read_mostly = {
        .name           = "queue",
-       .ops            = &nft_queue_ops,
+       .select_ops     = &nft_queue_select_ops,
        .policy         = nft_queue_policy,
        .maxattr        = NFTA_QUEUE_MAX,
        .owner          = THIS_MODULE,
index 6eafbf987ed9c682f5c01ebae1e5665d8fccdb87..c00104c070958b8b3835274b8b99215828bdd126 100644 (file)
@@ -21,10 +21,10 @@ struct nft_quota {
        atomic64_t      remain;
 };
 
-static inline long nft_quota(struct nft_quota *priv,
-                            const struct nft_pktinfo *pkt)
+static inline bool nft_overquota(struct nft_quota *priv,
+                                const struct nft_pktinfo *pkt)
 {
-       return atomic64_sub_return(pkt->skb->len, &priv->remain);
+       return atomic64_sub_return(pkt->skb->len, &priv->remain) < 0;
 }
 
 static void nft_quota_eval(const struct nft_expr *expr,
@@ -33,7 +33,7 @@ static void nft_quota_eval(const struct nft_expr *expr,
 {
        struct nft_quota *priv = nft_expr_priv(expr);
 
-       if (nft_quota(priv, pkt) < 0 && !priv->invert)
+       if (nft_overquota(priv, pkt) ^ priv->invert)
                regs->verdict.code = NFT_BREAK;
 }
 
diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c
new file mode 100644 (file)
index 0000000..c6d5358
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.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.
+ */
+
+#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_core.h>
+#include <net/netfilter/nf_tables.h>
+
+struct nft_range_expr {
+       struct nft_data         data_from;
+       struct nft_data         data_to;
+       enum nft_registers      sreg:8;
+       u8                      len;
+       enum nft_range_ops      op:8;
+};
+
+static void nft_range_eval(const struct nft_expr *expr,
+                        struct nft_regs *regs,
+                        const struct nft_pktinfo *pkt)
+{
+       const struct nft_range_expr *priv = nft_expr_priv(expr);
+       bool mismatch;
+       int d1, d2;
+
+       d1 = memcmp(&regs->data[priv->sreg], &priv->data_from, priv->len);
+       d2 = memcmp(&regs->data[priv->sreg], &priv->data_to, priv->len);
+       switch (priv->op) {
+       case NFT_RANGE_EQ:
+               mismatch = (d1 < 0 || d2 > 0);
+               break;
+       case NFT_RANGE_NEQ:
+               mismatch = (d1 >= 0 && d2 <= 0);
+               break;
+       }
+
+       if (mismatch)
+               regs->verdict.code = NFT_BREAK;
+}
+
+static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = {
+       [NFTA_RANGE_SREG]               = { .type = NLA_U32 },
+       [NFTA_RANGE_OP]                 = { .type = NLA_U32 },
+       [NFTA_RANGE_FROM_DATA]          = { .type = NLA_NESTED },
+       [NFTA_RANGE_TO_DATA]            = { .type = NLA_NESTED },
+};
+
+static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+                       const struct nlattr * const tb[])
+{
+       struct nft_range_expr *priv = nft_expr_priv(expr);
+       struct nft_data_desc desc_from, desc_to;
+       int err;
+
+       err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from),
+                           &desc_from, tb[NFTA_RANGE_FROM_DATA]);
+       if (err < 0)
+               return err;
+
+       err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to),
+                           &desc_to, tb[NFTA_RANGE_TO_DATA]);
+       if (err < 0)
+               goto err1;
+
+       if (desc_from.len != desc_to.len) {
+               err = -EINVAL;
+               goto err2;
+       }
+
+       priv->sreg = nft_parse_register(tb[NFTA_RANGE_SREG]);
+       err = nft_validate_register_load(priv->sreg, desc_from.len);
+       if (err < 0)
+               goto err2;
+
+       priv->op  = ntohl(nla_get_be32(tb[NFTA_RANGE_OP]));
+       priv->len = desc_from.len;
+       return 0;
+err2:
+       nft_data_uninit(&priv->data_to, desc_to.type);
+err1:
+       nft_data_uninit(&priv->data_from, desc_from.type);
+       return err;
+}
+
+static int nft_range_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+       const struct nft_range_expr *priv = nft_expr_priv(expr);
+
+       if (nft_dump_register(skb, NFTA_RANGE_SREG, priv->sreg))
+               goto nla_put_failure;
+       if (nla_put_be32(skb, NFTA_RANGE_OP, htonl(priv->op)))
+               goto nla_put_failure;
+
+       if (nft_data_dump(skb, NFTA_RANGE_FROM_DATA, &priv->data_from,
+                         NFT_DATA_VALUE, priv->len) < 0 ||
+           nft_data_dump(skb, NFTA_RANGE_TO_DATA, &priv->data_to,
+                         NFT_DATA_VALUE, priv->len) < 0)
+               goto nla_put_failure;
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
+static struct nft_expr_type nft_range_type;
+static const struct nft_expr_ops nft_range_ops = {
+       .type           = &nft_range_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_range_expr)),
+       .eval           = nft_range_eval,
+       .init           = nft_range_init,
+       .dump           = nft_range_dump,
+};
+
+static struct nft_expr_type nft_range_type __read_mostly = {
+       .name           = "range",
+       .ops            = &nft_range_ops,
+       .policy         = nft_range_policy,
+       .maxattr        = NFTA_RANGE_MAX,
+       .owner          = THIS_MODULE,
+};
+
+int __init nft_range_module_init(void)
+{
+       return nft_register_expr(&nft_range_type);
+}
+
+void nft_range_module_exit(void)
+{
+       nft_unregister_expr(&nft_range_type);
+}
index 515131f9e021a659d5305fe9b7455db7fc74c57e..dbd6c4a12b97435d2937c92fd79a035fd5828965 100644 (file)
@@ -24,7 +24,6 @@ static DEFINE_MUTEX(xt_rateest_mutex);
 #define RATEEST_HSIZE  16
 static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
 static unsigned int jhash_rnd __read_mostly;
-static bool rnd_inited __read_mostly;
 
 static unsigned int xt_rateest_hash(const char *name)
 {
@@ -99,10 +98,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
        } cfg;
        int ret;
 
-       if (unlikely(!rnd_inited)) {
-               get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
-               rnd_inited = true;
-       }
+       net_get_random_once(&jhash_rnd, sizeof(jhash_rnd));
 
        est = xt_rateest_lookup(info->name);
        if (est) {
index e118397254af026fd23ed3097ddc78c8ee9fc0c4..872db2d0e2a9970642c50e933c0a2225f8dd4599 100644 (file)
@@ -110,18 +110,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
                struct net *net = par->net;
                unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family);
+               unsigned int min_mtu = min(dst_mtu(skb_dst(skb)), in_mtu);
 
-               if (dst_mtu(skb_dst(skb)) <= minlen) {
+               if (min_mtu <= minlen) {
                        net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
-                                           dst_mtu(skb_dst(skb)));
+                                           min_mtu);
                        return -1;
                }
-               if (in_mtu <= minlen) {
-                       net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
-                                           in_mtu);
-                       return -1;
-               }
-               newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
+               newmss = min_mtu - minlen;
        } else
                newmss = info->mss;
 
index 6e57a3966dc5748a8cbb99cdf28c62ba1d5b90f1..0471db4032c5ea6eb839229124762cbf1901e53f 100644 (file)
@@ -89,6 +89,8 @@ static int tee_tg_check(const struct xt_tgchk_param *par)
                return -EINVAL;
 
        if (info->oif[0]) {
+               int ret;
+
                if (info->oif[sizeof(info->oif)-1] != '\0')
                        return -EINVAL;
 
@@ -101,7 +103,11 @@ static int tee_tg_check(const struct xt_tgchk_param *par)
                priv->notifier.notifier_call = tee_netdev_event;
                info->priv    = priv;
 
-               register_netdevice_notifier(&priv->notifier);
+               ret = register_netdevice_notifier(&priv->notifier);
+               if (ret) {
+                       kfree(priv);
+                       return ret;
+               }
        } else
                info->priv = NULL;
 
index 99bbc829868d5042ab5dbcbc02dc70c8e57f6b85..b6dc322593a34586aa7b0a0b73b23fcf9c47f5d2 100644 (file)
@@ -366,14 +366,8 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par)
        unsigned int i;
        int ret;
 
-       if (unlikely(!connlimit_rnd)) {
-               u_int32_t rand;
+       net_get_random_once(&connlimit_rnd, sizeof(connlimit_rnd));
 
-               do {
-                       get_random_bytes(&rand, sizeof(rand));
-               } while (!rand);
-               cmpxchg(&connlimit_rnd, 0, rand);
-       }
        ret = nf_ct_l3proto_try_module_get(par->family);
        if (ret < 0) {
                pr_info("cannot load conntrack support for "
index 178696852bde39d25bb5fdcaa7961511e6b4ec25..44a095ecc7b70cbebff92a47e455588c748985c6 100644 (file)
@@ -56,6 +56,7 @@ static inline struct hashlimit_net *hashlimit_pernet(struct net *net)
 }
 
 /* need to declare this at the top */
+static const struct file_operations dl_file_ops_v1;
 static const struct file_operations dl_file_ops;
 
 /* hash table crap */
@@ -86,8 +87,8 @@ struct dsthash_ent {
        unsigned long expires;          /* precalculated expiry time */
        struct {
                unsigned long prev;     /* last modification */
-               u_int32_t credit;
-               u_int32_t credit_cap, cost;
+               u_int64_t credit;
+               u_int64_t credit_cap, cost;
        } rateinfo;
        struct rcu_head rcu;
 };
@@ -98,7 +99,7 @@ struct xt_hashlimit_htable {
        u_int8_t family;
        bool rnd_initialized;
 
-       struct hashlimit_cfg1 cfg;      /* config */
+       struct hashlimit_cfg2 cfg;      /* config */
 
        /* used internally */
        spinlock_t lock;                /* lock for list_head */
@@ -114,6 +115,30 @@ struct xt_hashlimit_htable {
        struct hlist_head hash[0];      /* hashtable itself */
 };
 
+static int
+cfg_copy(struct hashlimit_cfg2 *to, void *from, int revision)
+{
+       if (revision == 1) {
+               struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from;
+
+               to->mode = cfg->mode;
+               to->avg = cfg->avg;
+               to->burst = cfg->burst;
+               to->size = cfg->size;
+               to->max = cfg->max;
+               to->gc_interval = cfg->gc_interval;
+               to->expire = cfg->expire;
+               to->srcmask = cfg->srcmask;
+               to->dstmask = cfg->dstmask;
+       } else if (revision == 2) {
+               memcpy(to, from, sizeof(struct hashlimit_cfg2));
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static DEFINE_MUTEX(hashlimit_mutex);  /* protects htables list */
 static struct kmem_cache *hashlimit_cachep __read_mostly;
 
@@ -215,16 +240,18 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
 }
 static void htable_gc(struct work_struct *work);
 
-static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
-                        u_int8_t family)
+static int htable_create(struct net *net, struct hashlimit_cfg2 *cfg,
+                        const char *name, u_int8_t family,
+                        struct xt_hashlimit_htable **out_hinfo,
+                        int revision)
 {
        struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
        struct xt_hashlimit_htable *hinfo;
-       unsigned int size;
-       unsigned int i;
+       unsigned int size, i;
+       int ret;
 
-       if (minfo->cfg.size) {
-               size = minfo->cfg.size;
+       if (cfg->size) {
+               size = cfg->size;
        } else {
                size = (totalram_pages << PAGE_SHIFT) / 16384 /
                       sizeof(struct list_head);
@@ -238,10 +265,14 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
                        sizeof(struct list_head) * size);
        if (hinfo == NULL)
                return -ENOMEM;
-       minfo->hinfo = hinfo;
+       *out_hinfo = hinfo;
 
        /* copy match config into hashtable config */
-       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
+       ret = cfg_copy(&hinfo->cfg, (void *)cfg, 2);
+
+       if (ret)
+               return ret;
+
        hinfo->cfg.size = size;
        if (hinfo->cfg.max == 0)
                hinfo->cfg.max = 8 * hinfo->cfg.size;
@@ -255,17 +286,18 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
        hinfo->count = 0;
        hinfo->family = family;
        hinfo->rnd_initialized = false;
-       hinfo->name = kstrdup(minfo->name, GFP_KERNEL);
+       hinfo->name = kstrdup(name, GFP_KERNEL);
        if (!hinfo->name) {
                vfree(hinfo);
                return -ENOMEM;
        }
        spin_lock_init(&hinfo->lock);
 
-       hinfo->pde = proc_create_data(minfo->name, 0,
+       hinfo->pde = proc_create_data(name, 0,
                (family == NFPROTO_IPV4) ?
                hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit,
-               &dl_file_ops, hinfo);
+               (revision == 1) ? &dl_file_ops_v1 : &dl_file_ops,
+               hinfo);
        if (hinfo->pde == NULL) {
                kfree(hinfo->name);
                vfree(hinfo);
@@ -398,7 +430,8 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
    (slowest userspace tool allows), which means
    CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
 */
-#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
+#define MAX_CPJ_v1 (0xFFFFFFFF / (HZ*60*60*24))
+#define MAX_CPJ (0xFFFFFFFFFFFFFFFF / (HZ*60*60*24))
 
 /* Repeated shift and or gives us all 1s, final shift and add 1 gives
  * us the power of 2 below the theoretical max, so GCC simply does a
@@ -408,9 +441,12 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
 #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
 #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
 #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
+#define _POW2_BELOW64(x) (_POW2_BELOW32(x)|_POW2_BELOW32((x)>>32))
 #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
+#define POW2_BELOW64(x) ((_POW2_BELOW64(x)>>1) + 1)
 
-#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
+#define CREDITS_PER_JIFFY POW2_BELOW64(MAX_CPJ)
+#define CREDITS_PER_JIFFY_v1 POW2_BELOW32(MAX_CPJ_v1)
 
 /* in byte mode, the lowest possible rate is one packet/second.
  * credit_cap is used as a counter that tells us how many times we can
@@ -425,14 +461,24 @@ static u32 xt_hashlimit_len_to_chunks(u32 len)
 }
 
 /* Precision saver. */
-static u32 user2credits(u32 user)
+static u64 user2credits(u64 user, int revision)
 {
-       /* If multiplying would overflow... */
-       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
-               /* Divide first. */
-               return (user / XT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
+       if (revision == 1) {
+               /* If multiplying would overflow... */
+               if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1))
+                       /* Divide first. */
+                       return (user / XT_HASHLIMIT_SCALE) *\
+                                               HZ * CREDITS_PER_JIFFY_v1;
+
+               return (user * HZ * CREDITS_PER_JIFFY_v1) \
+                                               / XT_HASHLIMIT_SCALE;
+       } else {
+               if (user > 0xFFFFFFFFFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
+                       return (user / XT_HASHLIMIT_SCALE_v2) *\
+                                               HZ * CREDITS_PER_JIFFY;
 
-       return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE;
+               return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE_v2;
+       }
 }
 
 static u32 user2credits_byte(u32 user)
@@ -442,10 +488,11 @@ static u32 user2credits_byte(u32 user)
        return (u32) (us >> 32);
 }
 
-static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode)
+static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now,
+                           u32 mode, int revision)
 {
        unsigned long delta = now - dh->rateinfo.prev;
-       u32 cap;
+       u64 cap, cpj;
 
        if (delta == 0)
                return;
@@ -453,7 +500,7 @@ static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode)
        dh->rateinfo.prev = now;
 
        if (mode & XT_HASHLIMIT_BYTES) {
-               u32 tmp = dh->rateinfo.credit;
+               u64 tmp = dh->rateinfo.credit;
                dh->rateinfo.credit += CREDITS_PER_JIFFY_BYTES * delta;
                cap = CREDITS_PER_JIFFY_BYTES * HZ;
                if (tmp >= dh->rateinfo.credit) {/* overflow */
@@ -461,7 +508,9 @@ static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode)
                        return;
                }
        } else {
-               dh->rateinfo.credit += delta * CREDITS_PER_JIFFY;
+               cpj = (revision == 1) ?
+                       CREDITS_PER_JIFFY_v1 : CREDITS_PER_JIFFY;
+               dh->rateinfo.credit += delta * cpj;
                cap = dh->rateinfo.credit_cap;
        }
        if (dh->rateinfo.credit > cap)
@@ -469,7 +518,7 @@ static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode)
 }
 
 static void rateinfo_init(struct dsthash_ent *dh,
-                         struct xt_hashlimit_htable *hinfo)
+                         struct xt_hashlimit_htable *hinfo, int revision)
 {
        dh->rateinfo.prev = jiffies;
        if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) {
@@ -478,8 +527,8 @@ static void rateinfo_init(struct dsthash_ent *dh,
                dh->rateinfo.credit_cap = hinfo->cfg.burst;
        } else {
                dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
-                                                  hinfo->cfg.burst);
-               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
+                                                  hinfo->cfg.burst, revision);
+               dh->rateinfo.cost = user2credits(hinfo->cfg.avg, revision);
                dh->rateinfo.credit_cap = dh->rateinfo.credit;
        }
 }
@@ -603,15 +652,15 @@ static u32 hashlimit_byte_cost(unsigned int len, struct dsthash_ent *dh)
 }
 
 static bool
-hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
+hashlimit_mt_common(const struct sk_buff *skb, struct xt_action_param *par,
+                   struct xt_hashlimit_htable *hinfo,
+                   const struct hashlimit_cfg2 *cfg, int revision)
 {
-       const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
-       struct xt_hashlimit_htable *hinfo = info->hinfo;
        unsigned long now = jiffies;
        struct dsthash_ent *dh;
        struct dsthash_dst dst;
        bool race = false;
-       u32 cost;
+       u64 cost;
 
        if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
                goto hotdrop;
@@ -626,18 +675,18 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
                } else if (race) {
                        /* Already got an entry, update expiration timeout */
                        dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
-                       rateinfo_recalc(dh, now, hinfo->cfg.mode);
+                       rateinfo_recalc(dh, now, hinfo->cfg.mode, revision);
                } else {
                        dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
-                       rateinfo_init(dh, hinfo);
+                       rateinfo_init(dh, hinfo, revision);
                }
        } else {
                /* update expiration timeout */
                dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
-               rateinfo_recalc(dh, now, hinfo->cfg.mode);
+               rateinfo_recalc(dh, now, hinfo->cfg.mode, revision);
        }
 
-       if (info->cfg.mode & XT_HASHLIMIT_BYTES)
+       if (cfg->mode & XT_HASHLIMIT_BYTES)
                cost = hashlimit_byte_cost(skb->len, dh);
        else
                cost = dh->rateinfo.cost;
@@ -647,84 +696,157 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
                dh->rateinfo.credit -= cost;
                spin_unlock(&dh->lock);
                rcu_read_unlock_bh();
-               return !(info->cfg.mode & XT_HASHLIMIT_INVERT);
+               return !(cfg->mode & XT_HASHLIMIT_INVERT);
        }
 
        spin_unlock(&dh->lock);
        rcu_read_unlock_bh();
        /* default match is underlimit - so over the limit, we need to invert */
-       return info->cfg.mode & XT_HASHLIMIT_INVERT;
+       return cfg->mode & XT_HASHLIMIT_INVERT;
 
  hotdrop:
        par->hotdrop = true;
        return false;
 }
 
-static int hashlimit_mt_check(const struct xt_mtchk_param *par)
+static bool
+hashlimit_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
+       struct xt_hashlimit_htable *hinfo = info->hinfo;
+       struct hashlimit_cfg2 cfg = {};
+       int ret;
+
+       ret = cfg_copy(&cfg, (void *)&info->cfg, 1);
+
+       if (ret)
+               return ret;
+
+       return hashlimit_mt_common(skb, par, hinfo, &cfg, 1);
+}
+
+static bool
+hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       const struct xt_hashlimit_mtinfo2 *info = par->matchinfo;
+       struct xt_hashlimit_htable *hinfo = info->hinfo;
+
+       return hashlimit_mt_common(skb, par, hinfo, &info->cfg, 2);
+}
+
+static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
+                                    struct xt_hashlimit_htable **hinfo,
+                                    struct hashlimit_cfg2 *cfg,
+                                    const char *name, int revision)
 {
        struct net *net = par->net;
-       struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
        int ret;
 
-       if (info->cfg.gc_interval == 0 || info->cfg.expire == 0)
-               return -EINVAL;
-       if (info->name[sizeof(info->name)-1] != '\0')
+       if (cfg->gc_interval == 0 || cfg->expire == 0)
                return -EINVAL;
        if (par->family == NFPROTO_IPV4) {
-               if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32)
+               if (cfg->srcmask > 32 || cfg->dstmask > 32)
                        return -EINVAL;
        } else {
-               if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128)
+               if (cfg->srcmask > 128 || cfg->dstmask > 128)
                        return -EINVAL;
        }
 
-       if (info->cfg.mode & ~XT_HASHLIMIT_ALL) {
+       if (cfg->mode & ~XT_HASHLIMIT_ALL) {
                pr_info("Unknown mode mask %X, kernel too old?\n",
-                                               info->cfg.mode);
+                                               cfg->mode);
                return -EINVAL;
        }
 
        /* Check for overflow. */
-       if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
-               if (user2credits_byte(info->cfg.avg) == 0) {
-                       pr_info("overflow, rate too high: %u\n", info->cfg.avg);
+       if (cfg->mode & XT_HASHLIMIT_BYTES) {
+               if (user2credits_byte(cfg->avg) == 0) {
+                       pr_info("overflow, rate too high: %llu\n", cfg->avg);
                        return -EINVAL;
                }
-       } else if (info->cfg.burst == 0 ||
-                   user2credits(info->cfg.avg * info->cfg.burst) <
-                   user2credits(info->cfg.avg)) {
-                       pr_info("overflow, try lower: %u/%u\n",
-                               info->cfg.avg, info->cfg.burst);
+       } else if (cfg->burst == 0 ||
+                   user2credits(cfg->avg * cfg->burst, revision) <
+                   user2credits(cfg->avg, revision)) {
+                       pr_info("overflow, try lower: %llu/%llu\n",
+                               cfg->avg, cfg->burst);
                        return -ERANGE;
        }
 
        mutex_lock(&hashlimit_mutex);
-       info->hinfo = htable_find_get(net, info->name, par->family);
-       if (info->hinfo == NULL) {
-               ret = htable_create(net, info, par->family);
+       *hinfo = htable_find_get(net, name, par->family);
+       if (*hinfo == NULL) {
+               ret = htable_create(net, cfg, name, par->family,
+                                   hinfo, revision);
                if (ret < 0) {
                        mutex_unlock(&hashlimit_mutex);
                        return ret;
                }
        }
        mutex_unlock(&hashlimit_mutex);
+
        return 0;
 }
 
-static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par)
+static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par)
+{
+       struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
+       struct hashlimit_cfg2 cfg = {};
+       int ret;
+
+       if (info->name[sizeof(info->name) - 1] != '\0')
+               return -EINVAL;
+
+       ret = cfg_copy(&cfg, (void *)&info->cfg, 1);
+
+       if (ret)
+               return ret;
+
+       return hashlimit_mt_check_common(par, &info->hinfo,
+                                        &cfg, info->name, 1);
+}
+
+static int hashlimit_mt_check(const struct xt_mtchk_param *par)
+{
+       struct xt_hashlimit_mtinfo2 *info = par->matchinfo;
+
+       if (info->name[sizeof(info->name) - 1] != '\0')
+               return -EINVAL;
+
+       return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg,
+                                        info->name, 2);
+}
+
+static void hashlimit_mt_destroy_v1(const struct xt_mtdtor_param *par)
 {
        const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
 
        htable_put(info->hinfo);
 }
 
+static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par)
+{
+       const struct xt_hashlimit_mtinfo2 *info = par->matchinfo;
+
+       htable_put(info->hinfo);
+}
+
 static struct xt_match hashlimit_mt_reg[] __read_mostly = {
        {
                .name           = "hashlimit",
                .revision       = 1,
                .family         = NFPROTO_IPV4,
-               .match          = hashlimit_mt,
+               .match          = hashlimit_mt_v1,
                .matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
+               .checkentry     = hashlimit_mt_check_v1,
+               .destroy        = hashlimit_mt_destroy_v1,
+               .me             = THIS_MODULE,
+       },
+       {
+               .name           = "hashlimit",
+               .revision       = 2,
+               .family         = NFPROTO_IPV4,
+               .match          = hashlimit_mt,
+               .matchsize      = sizeof(struct xt_hashlimit_mtinfo2),
                .checkentry     = hashlimit_mt_check,
                .destroy        = hashlimit_mt_destroy,
                .me             = THIS_MODULE,
@@ -734,8 +856,18 @@ static struct xt_match hashlimit_mt_reg[] __read_mostly = {
                .name           = "hashlimit",
                .revision       = 1,
                .family         = NFPROTO_IPV6,
-               .match          = hashlimit_mt,
+               .match          = hashlimit_mt_v1,
                .matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
+               .checkentry     = hashlimit_mt_check_v1,
+               .destroy        = hashlimit_mt_destroy_v1,
+               .me             = THIS_MODULE,
+       },
+       {
+               .name           = "hashlimit",
+               .revision       = 2,
+               .family         = NFPROTO_IPV6,
+               .match          = hashlimit_mt,
+               .matchsize      = sizeof(struct xt_hashlimit_mtinfo2),
                .checkentry     = hashlimit_mt_check,
                .destroy        = hashlimit_mt_destroy,
                .me             = THIS_MODULE,
@@ -786,18 +918,12 @@ static void dl_seq_stop(struct seq_file *s, void *v)
        spin_unlock_bh(&htable->lock);
 }
 
-static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
-                                  struct seq_file *s)
+static void dl_seq_print(struct dsthash_ent *ent, u_int8_t family,
+                        struct seq_file *s)
 {
-       const struct xt_hashlimit_htable *ht = s->private;
-
-       spin_lock(&ent->lock);
-       /* recalculate to show accurate numbers */
-       rateinfo_recalc(ent, jiffies, ht->cfg.mode);
-
        switch (family) {
        case NFPROTO_IPV4:
-               seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n",
+               seq_printf(s, "%ld %pI4:%u->%pI4:%u %llu %llu %llu\n",
                           (long)(ent->expires - jiffies)/HZ,
                           &ent->dst.ip.src,
                           ntohs(ent->dst.src_port),
@@ -808,7 +934,7 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
                break;
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        case NFPROTO_IPV6:
-               seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n",
+               seq_printf(s, "%ld %pI6:%u->%pI6:%u %llu %llu %llu\n",
                           (long)(ent->expires - jiffies)/HZ,
                           &ent->dst.ip6.src,
                           ntohs(ent->dst.src_port),
@@ -821,10 +947,52 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
        default:
                BUG();
        }
+}
+
+static int dl_seq_real_show_v1(struct dsthash_ent *ent, u_int8_t family,
+                              struct seq_file *s)
+{
+       const struct xt_hashlimit_htable *ht = s->private;
+
+       spin_lock(&ent->lock);
+       /* recalculate to show accurate numbers */
+       rateinfo_recalc(ent, jiffies, ht->cfg.mode, 1);
+
+       dl_seq_print(ent, family, s);
+
+       spin_unlock(&ent->lock);
+       return seq_has_overflowed(s);
+}
+
+static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
+                           struct seq_file *s)
+{
+       const struct xt_hashlimit_htable *ht = s->private;
+
+       spin_lock(&ent->lock);
+       /* recalculate to show accurate numbers */
+       rateinfo_recalc(ent, jiffies, ht->cfg.mode, 2);
+
+       dl_seq_print(ent, family, s);
+
        spin_unlock(&ent->lock);
        return seq_has_overflowed(s);
 }
 
+static int dl_seq_show_v1(struct seq_file *s, void *v)
+{
+       struct xt_hashlimit_htable *htable = s->private;
+       unsigned int *bucket = (unsigned int *)v;
+       struct dsthash_ent *ent;
+
+       if (!hlist_empty(&htable->hash[*bucket])) {
+               hlist_for_each_entry(ent, &htable->hash[*bucket], node)
+                       if (dl_seq_real_show_v1(ent, htable->family, s))
+                               return -1;
+       }
+       return 0;
+}
+
 static int dl_seq_show(struct seq_file *s, void *v)
 {
        struct xt_hashlimit_htable *htable = s->private;
@@ -839,6 +1007,13 @@ static int dl_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
+static const struct seq_operations dl_seq_ops_v1 = {
+       .start = dl_seq_start,
+       .next  = dl_seq_next,
+       .stop  = dl_seq_stop,
+       .show  = dl_seq_show_v1
+};
+
 static const struct seq_operations dl_seq_ops = {
        .start = dl_seq_start,
        .next  = dl_seq_next,
@@ -846,17 +1021,37 @@ static const struct seq_operations dl_seq_ops = {
        .show  = dl_seq_show
 };
 
+static int dl_proc_open_v1(struct inode *inode, struct file *file)
+{
+       int ret = seq_open(file, &dl_seq_ops_v1);
+
+       if (!ret) {
+               struct seq_file *sf = file->private_data;
+               sf->private = PDE_DATA(inode);
+       }
+       return ret;
+}
+
 static int dl_proc_open(struct inode *inode, struct file *file)
 {
        int ret = seq_open(file, &dl_seq_ops);
 
        if (!ret) {
                struct seq_file *sf = file->private_data;
+
                sf->private = PDE_DATA(inode);
        }
        return ret;
 }
 
+static const struct file_operations dl_file_ops_v1 = {
+       .owner   = THIS_MODULE,
+       .open    = dl_proc_open_v1,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release
+};
+
 static const struct file_operations dl_file_ops = {
        .owner   = THIS_MODULE,
        .open    = dl_proc_open,
index 9f4ab00c80500635e8015b2384d25dea98641c56..f679dd4c272a55691bf74ee09e29d6329def06e2 100644 (file)
@@ -41,7 +41,7 @@ helper_mt(const struct sk_buff *skb, struct xt_action_param *par)
        if (!master_help)
                return ret;
 
-       /* rcu_read_lock()ed by nf_hook_slow */
+       /* rcu_read_lock()ed by nf_hook_thresh */
        helper = rcu_dereference(master_help->helper);
        if (!helper)
                return ret;
@@ -65,7 +65,7 @@ static int helper_mt_check(const struct xt_mtchk_param *par)
                        par->family);
                return ret;
        }
-       info->name[29] = '\0';
+       info->name[sizeof(info->name) - 1] = '\0';
        return 0;
 }
 
index d725a27743a169fc80cc00f38dd2278696be3365..e3b7a09b103e490a2c85364d8938b47565b9c66c 100644 (file)
@@ -110,7 +110,6 @@ static const struct file_operations recent_old_fops, recent_mt_fops;
 #endif
 
 static u_int32_t hash_rnd __read_mostly;
-static bool hash_rnd_inited __read_mostly;
 
 static inline unsigned int recent_entry_hash4(const union nf_inet_addr *addr)
 {
@@ -340,10 +339,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        int ret = -EINVAL;
        size_t sz;
 
-       if (unlikely(!hash_rnd_inited)) {
-               get_random_bytes(&hash_rnd, sizeof(hash_rnd));
-               hash_rnd_inited = true;
-       }
+       net_get_random_once(&hash_rnd, sizeof(hash_rnd));
+
        if (info->check_set & ~XT_RECENT_VALID_FLAGS) {
                pr_info("Unsupported user space flags (%08x)\n",
                        info->check_set);