]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 24 Jun 2019 23:32:59 +0000 (01:32 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 24 Jun 2019 23:32:59 +0000 (01:32 +0200)
Resolve conflict between d2912cb15bdd ("treewide: Replace GPLv2
boilerplate/reference with SPDX - rule 500") removing the GPL disclaimer
and fe03d4745675 ("Update my email address") which updates Jozsef
Kadlecsik's email.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
58 files changed:
CREDITS
MAINTAINERS
include/linux/jhash.h
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/ipset/ip_set_counter.h
include/linux/netfilter/ipset/ip_set_skbinfo.h
include/linux/netfilter/ipset/ip_set_timeout.h
include/linux/netfilter_ipv6.h
include/net/netfilter/br_netfilter.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_synproxy.h
include/net/netfilter/nf_synproxy.h [new file with mode: 0644]
include/net/netfilter/nf_tables.h
include/uapi/linux/netfilter/ipset/ip_set.h
include/uapi/linux/netfilter/nf_SYNPROXY.h [new file with mode: 0644]
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/netfilter/xt_SYNPROXY.h
include/uapi/linux/netfilter/xt_owner.h
net/bridge/br_netfilter_hooks.c
net/bridge/br_netfilter_ipv6.c
net/bridge/netfilter/nf_conntrack_bridge.c
net/ipv4/ip_options.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/nf_nat_h323.c
net/ipv6/netfilter.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/netfilter/ip6table_raw.c
net/netfilter/ipset/ip_set_bitmap_gen.h
net/netfilter/ipset/ip_set_bitmap_ip.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_bitmap_port.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_getport.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipset/ip_set_hash_ip.c
net/netfilter/ipset/ip_set_hash_ipmark.c
net/netfilter/ipset/ip_set_hash_ipport.c
net/netfilter/ipset/ip_set_hash_ipportip.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_mac.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netnet.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipset/ip_set_hash_netportnet.c
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_ct.c
net/netfilter/nft_dynset.c
net/netfilter/nft_exthdr.c
net/netfilter/xt_iprange.c
net/netfilter/xt_owner.c
net/netfilter/xt_set.c

diff --git a/CREDITS b/CREDITS
index 681335f424919e0deda5789e233a54238742dc8b..beac0c81d0813376a359363493645d7bc231e9f7 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1800,7 +1800,7 @@ S: 2300 Copenhagen S.
 S: Denmark
 
 N: Jozsef Kadlecsik
-E: kadlec@blackhole.kfki.hu
+E: kadlec@netfilter.org
 P: 1024D/470DB964 4CB3 1A05 713E 9BF7 FAC5  5809 DD8C B7B1 470D B964
 D: netfilter: TCP window tracking code
 D: netfilter: raw table
index 606d1f80bc4929a8f2461b29fc0454994cb0373f..a75f8478b8723bce3ec9c6dc9e91665bda42667d 100644 (file)
@@ -10866,7 +10866,7 @@ F:      drivers/net/ethernet/neterion/
 
 NETFILTER
 M:     Pablo Neira Ayuso <pablo@netfilter.org>
-M:     Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+M:     Jozsef Kadlecsik <kadlec@netfilter.org>
 M:     Florian Westphal <fw@strlen.de>
 L:     netfilter-devel@vger.kernel.org
 L:     coreteam@netfilter.org
index 8037850f31041696a30a046696c99f902d222b03..ba2f6a9776b6fa2e82bf1255cacee75921946854 100644 (file)
@@ -17,7 +17,7 @@
  * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
  * the public domain.  It has no warranty.
  *
- * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@netfilter.org)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
  * any bugs present are my fault.
index f5e03809cdb29dd7e80534613b2ad0575552a6cc..12ad9b1853b4b4db743a7aa8bd247424eaa94680 100644 (file)
@@ -2,7 +2,7 @@
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
  *                         Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 #ifndef _IP_SET_H
 #define _IP_SET_H
index 5477492c8374236fb030d691bf04cc32ad56a392..3400958c07be573532034685dd2da62bc1782df6 100644 (file)
@@ -2,8 +2,7 @@
 #ifndef _IP_SET_COUNTER_H
 #define _IP_SET_COUNTER_H
 
-/* Copyright (C) 2015 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2015 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 #ifdef __KERNEL__
 
index aae081e085c63338534e3f74c795616716fa1452..3a2df02dbd55178252fafa115a3fca1141d66c67 100644 (file)
@@ -2,8 +2,7 @@
 #ifndef _IP_SET_SKBINFO_H
 #define _IP_SET_SKBINFO_H
 
-/* Copyright (C) 2015 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2015 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 #ifdef __KERNEL__
 
index 88926b4c75f043b4139c383b114f2df2a1e3995a..2be60e379ecf55af9f621cd4e658bf57f76a5421 100644 (file)
@@ -2,8 +2,7 @@
 #ifndef _IP_SET_TIMEOUT_H
 #define _IP_SET_TIMEOUT_H
 
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 #ifdef __KERNEL__
 
index 3a3dc4b1f0e7fae54ca5b6765b072ba8630e9b35..7beb681e1ce5e6d2a7ad2a13eab686a3571e8cc8 100644 (file)
@@ -8,6 +8,7 @@
 #define __LINUX_IP6_NETFILTER_H
 
 #include <uapi/linux/netfilter_ipv6.h>
+#include <net/tcp.h>
 
 /* Extra routing may needed on local out, as the QUEUE target never returns
  * control to the table.
@@ -35,6 +36,10 @@ struct nf_ipv6_ops {
                       struct in6_addr *saddr);
        int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl,
                     bool strict);
+       u32 (*cookie_init_sequence)(const struct ipv6hdr *iph,
+                                   const struct tcphdr *th, u16 *mssp);
+       int (*cookie_v6_check)(const struct ipv6hdr *iph,
+                              const struct tcphdr *th, __u32 cookie);
 #endif
        void (*route_input)(struct sk_buff *skb);
        int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb,
@@ -70,8 +75,10 @@ static inline int nf_ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
                return 1;
 
        return v6_ops->chk_addr(net, addr, dev, strict);
-#else
+#elif IS_BUILTIN(CONFIG_IPV6)
        return ipv6_chk_addr(net, addr, dev, strict);
+#else
+       return 1;
 #endif
 }
 
@@ -108,8 +115,10 @@ static inline int nf_ipv6_br_defrag(struct net *net, struct sk_buff *skb,
                return 1;
 
        return v6_ops->br_defrag(net, skb, user);
-#else
+#elif IS_BUILTIN(CONFIG_IPV6)
        return nf_ct_frag6_gather(net, skb, user);
+#else
+       return 1;
 #endif
 }
 
@@ -133,8 +142,10 @@ static inline int nf_br_ip6_fragment(struct net *net, struct sock *sk,
                return 1;
 
        return v6_ops->br_fragment(net, sk, skb, data, output);
-#else
+#elif IS_BUILTIN(CONFIG_IPV6)
        return br_ip6_fragment(net, sk, skb, data, output);
+#else
+       return 1;
 #endif
 }
 
@@ -149,9 +160,44 @@ static inline int nf_ip6_route_me_harder(struct net *net, struct sk_buff *skb)
                return -EHOSTUNREACH;
 
        return v6_ops->route_me_harder(net, skb);
-#else
+#elif IS_BUILTIN(CONFIG_IPV6)
        return ip6_route_me_harder(net, skb);
+#else
+       return -EHOSTUNREACH;
+#endif
+}
+
+static inline u32 nf_ipv6_cookie_init_sequence(const struct ipv6hdr *iph,
+                                              const struct tcphdr *th,
+                                              u16 *mssp)
+{
+#if IS_ENABLED(CONFIG_SYN_COOKIES)
+#if IS_MODULE(CONFIG_IPV6)
+       const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops();
+
+       if (v6_ops)
+               return v6_ops->cookie_init_sequence(iph, th, mssp);
+#elif IS_BUILTIN(CONFIG_IPV6)
+       return __cookie_v6_init_sequence(iph, th, mssp);
+#endif
+#endif
+       return 0;
+}
+
+static inline int nf_cookie_v6_check(const struct ipv6hdr *iph,
+                                    const struct tcphdr *th, __u32 cookie)
+{
+#if IS_ENABLED(CONFIG_SYN_COOKIES)
+#if IS_MODULE(CONFIG_IPV6)
+       const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops();
+
+       if (v6_ops)
+               return v6_ops->cookie_v6_check(iph, th, cookie);
+#elif IS_BUILTIN(CONFIG_IPV6)
+       return __cookie_v6_check(iph, th, cookie);
+#endif
 #endif
+       return 0;
 }
 
 __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
index 89808ce293c411f272566cc8370fe8e82226e9f1..302fcd3aade2178b75be742e646c0f6016421d59 100644 (file)
@@ -42,7 +42,8 @@ static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
        return port ? &port->br->fake_rtable : NULL;
 }
 
-struct net_device *setup_pre_routing(struct sk_buff *skb);
+struct net_device *setup_pre_routing(struct sk_buff *skb,
+                                    const struct net *net);
 
 #if IS_ENABLED(CONFIG_IPV6)
 int br_validate_ipv6(struct net *net, struct sk_buff *skb);
index 5cb19ce454d1eb6afaa2be584dcd0d48d6551b35..c86657d9963095946244d4f9f2fedfbd0c4227e4 100644 (file)
@@ -70,7 +70,8 @@ struct nf_conn {
        struct nf_conntrack ct_general;
 
        spinlock_t      lock;
-       u16             cpu;
+       /* jiffies32 when this ct is considered dead */
+       u32 timeout;
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        struct nf_conntrack_zone zone;
@@ -82,9 +83,7 @@ struct nf_conn {
        /* Have we seen traffic both ways yet? (bitset) */
        unsigned long status;
 
-       /* jiffies32 when this ct is considered dead */
-       u32 timeout;
-
+       u16             cpu;
        possible_net_t ct_net;
 
 #if IS_ENABLED(CONFIG_NF_NAT)
index 2c7559a54092724308a0ff3e01677935a910f24e..c5659dcf5b1a2ddf1425e2d0970b47b475c4949d 100644 (file)
@@ -72,21 +72,12 @@ struct synproxy_options {
 };
 
 struct tcphdr;
-struct xt_synproxy_info;
+struct nf_synproxy_info;
 bool synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                            const struct tcphdr *th,
                            struct synproxy_options *opts);
-unsigned int synproxy_options_size(const struct synproxy_options *opts);
-void synproxy_build_options(struct tcphdr *th,
-                           const struct synproxy_options *opts);
 
-void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info,
+void synproxy_init_timestamp_cookie(const struct nf_synproxy_info *info,
                                    struct synproxy_options *opts);
-void synproxy_check_timestamp_cookie(struct synproxy_options *opts);
-
-unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,
-                                   struct tcphdr *th, struct nf_conn *ct,
-                                   enum ip_conntrack_info ctinfo,
-                                   const struct nf_conn_synproxy *synproxy);
 
 #endif /* _NF_CONNTRACK_SYNPROXY_H */
diff --git a/include/net/netfilter/nf_synproxy.h b/include/net/netfilter/nf_synproxy.h
new file mode 100644 (file)
index 0000000..3e8b3f0
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NF_SYNPROXY_SHARED_H
+#define _NF_SYNPROXY_SHARED_H
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/ip6_checksum.h>
+#include <net/ip6_route.h>
+#include <net/tcp.h>
+
+#include <net/netfilter/nf_conntrack_seqadj.h>
+#include <net/netfilter/nf_conntrack_synproxy.h>
+
+void synproxy_send_client_synack(struct net *net, const struct sk_buff *skb,
+                                const struct tcphdr *th,
+                                const struct synproxy_options *opts);
+
+bool synproxy_recv_client_ack(struct net *net,
+                             const struct sk_buff *skb,
+                             const struct tcphdr *th,
+                             struct synproxy_options *opts, u32 recv_seq);
+
+unsigned int ipv4_synproxy_hook(void *priv, struct sk_buff *skb,
+                               const struct nf_hook_state *nhs);
+int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net);
+void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net);
+
+#if IS_ENABLED(CONFIG_IPV6)
+void synproxy_send_client_synack_ipv6(struct net *net,
+                                     const struct sk_buff *skb,
+                                     const struct tcphdr *th,
+                                     const struct synproxy_options *opts);
+
+bool synproxy_recv_client_ack_ipv6(struct net *net, const struct sk_buff *skb,
+                                  const struct tcphdr *th,
+                                  struct synproxy_options *opts, u32 recv_seq);
+
+unsigned int ipv6_synproxy_hook(void *priv, struct sk_buff *skb,
+                               const struct nf_hook_state *nhs);
+int nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net);
+void nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net);
+#endif /* CONFIG_IPV6 */
+
+#endif /* _NF_SYNPROXY_SHARED_H */
index 5b8624ae4a27f4b2617b32ab971bfc700835f5e5..9e8493aad49d6b868f114cb7e376ee11459198bd 100644 (file)
@@ -636,7 +636,7 @@ static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
 void *nft_set_elem_init(const struct nft_set *set,
                        const struct nft_set_ext_tmpl *tmpl,
                        const u32 *key, const u32 *data,
-                       u64 timeout, gfp_t gfp);
+                       u64 timeout, u64 expiration, gfp_t gfp);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
                          bool destroy_expr);
 
index ea69ca21ff23def3e697d7f5f78a0bbaba00fe35..eea166c52c365a43edd654fab41bf9f9201842df 100644 (file)
@@ -2,7 +2,7 @@
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
  *                         Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@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
diff --git a/include/uapi/linux/netfilter/nf_SYNPROXY.h b/include/uapi/linux/netfilter/nf_SYNPROXY.h
new file mode 100644 (file)
index 0000000..068d1b3
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NF_SYNPROXY_H
+#define _NF_SYNPROXY_H
+
+#include <linux/types.h>
+
+#define NF_SYNPROXY_OPT_MSS            0x01
+#define NF_SYNPROXY_OPT_WSCALE         0x02
+#define NF_SYNPROXY_OPT_SACK_PERM      0x04
+#define NF_SYNPROXY_OPT_TIMESTAMP      0x08
+#define NF_SYNPROXY_OPT_ECN            0x10
+
+struct nf_synproxy_info {
+       __u8    options;
+       __u8    wscale;
+       __u16   mss;
+};
+
+#endif /* _NF_SYNPROXY_H */
index 505393c6e959ff737fccbf2f8dd8e84750af1e12..c6c8ec5c7c0022a55c28476644d9b24840a9167e 100644 (file)
@@ -730,10 +730,12 @@ enum nft_exthdr_flags {
  *
  * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
  * @NFT_EXTHDR_OP_TCP: match against tcp options
+ * @NFT_EXTHDR_OP_IPV4: match against ipv4 options
  */
 enum nft_exthdr_op {
        NFT_EXTHDR_OP_IPV6,
        NFT_EXTHDR_OP_TCPOPT,
+       NFT_EXTHDR_OP_IPV4,
        __NFT_EXTHDR_OP_MAX
 };
 #define NFT_EXTHDR_OP_MAX      (__NFT_EXTHDR_OP_MAX - 1)
@@ -1445,6 +1447,17 @@ enum nft_ct_timeout_timeout_attributes {
 };
 #define NFTA_CT_TIMEOUT_MAX    (__NFTA_CT_TIMEOUT_MAX - 1)
 
+enum nft_ct_expectation_attributes {
+       NFTA_CT_EXPECT_UNSPEC,
+       NFTA_CT_EXPECT_L3PROTO,
+       NFTA_CT_EXPECT_L4PROTO,
+       NFTA_CT_EXPECT_DPORT,
+       NFTA_CT_EXPECT_TIMEOUT,
+       NFTA_CT_EXPECT_SIZE,
+       __NFTA_CT_EXPECT_MAX,
+};
+#define NFTA_CT_EXPECT_MAX     (__NFTA_CT_EXPECT_MAX - 1)
+
 #define NFT_OBJECT_UNSPEC      0
 #define NFT_OBJECT_COUNTER     1
 #define NFT_OBJECT_QUOTA       2
@@ -1454,7 +1467,8 @@ enum nft_ct_timeout_timeout_attributes {
 #define NFT_OBJECT_TUNNEL      6
 #define NFT_OBJECT_CT_TIMEOUT  7
 #define NFT_OBJECT_SECMARK     8
-#define __NFT_OBJECT_MAX       9
+#define NFT_OBJECT_CT_EXPECT   9
+#define __NFT_OBJECT_MAX       10
 #define NFT_OBJECT_MAX         (__NFT_OBJECT_MAX - 1)
 
 /**
index ea5eba15d4c1be75ad1bf5b0c1234a02826cf90a..4d5611d647dfec6f7875856736f88bdbd04cb5cf 100644 (file)
@@ -2,18 +2,14 @@
 #ifndef _XT_SYNPROXY_H
 #define _XT_SYNPROXY_H
 
-#include <linux/types.h>
+#include <linux/netfilter/nf_SYNPROXY.h>
 
-#define XT_SYNPROXY_OPT_MSS            0x01
-#define XT_SYNPROXY_OPT_WSCALE         0x02
-#define XT_SYNPROXY_OPT_SACK_PERM      0x04
-#define XT_SYNPROXY_OPT_TIMESTAMP      0x08
-#define XT_SYNPROXY_OPT_ECN            0x10
+#define XT_SYNPROXY_OPT_MSS            NF_SYNPROXY_OPT_MSS
+#define XT_SYNPROXY_OPT_WSCALE         NF_SYNPROXY_OPT_WSCALE
+#define XT_SYNPROXY_OPT_SACK_PERM      NF_SYNPROXY_OPT_SACK_PERM
+#define XT_SYNPROXY_OPT_TIMESTAMP      NF_SYNPROXY_OPT_TIMESTAMP
+#define XT_SYNPROXY_OPT_ECN            NF_SYNPROXY_OPT_ECN
 
-struct xt_synproxy_info {
-       __u8    options;
-       __u8    wscale;
-       __u16   mss;
-};
+#define xt_synproxy_info               nf_synproxy_info
 
 #endif /* _XT_SYNPROXY_H */
index 9e98c09eda32741d21bbe85833583fdcc1f67cae..5108df4d03134a1ca822397870f67224c981f719 100644 (file)
@@ -11,6 +11,11 @@ enum {
        XT_OWNER_SUPPL_GROUPS = 1 << 3,
 };
 
+#define XT_OWNER_MASK  (XT_OWNER_UID |         \
+                        XT_OWNER_GID |         \
+                        XT_OWNER_SOCKET |      \
+                        XT_OWNER_SUPPL_GROUPS)
+
 struct xt_owner_match_info {
        __u32 uid_min, uid_max;
        __u32 gid_min, gid_max;
index 34fa72c72ad8f4fb1f9261e3f6c68045cb8caebc..d3f9592f4ff8d8435861cd95dd0d130e8fa22fbb 100644 (file)
@@ -47,25 +47,22 @@ static unsigned int brnf_net_id __read_mostly;
 
 struct brnf_net {
        bool enabled;
-};
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *brnf_sysctl_header;
-static int brnf_call_iptables __read_mostly = 1;
-static int brnf_call_ip6tables __read_mostly = 1;
-static int brnf_call_arptables __read_mostly = 1;
-static int brnf_filter_vlan_tagged __read_mostly;
-static int brnf_filter_pppoe_tagged __read_mostly;
-static int brnf_pass_vlan_indev __read_mostly;
-#else
-#define brnf_call_iptables 1
-#define brnf_call_ip6tables 1
-#define brnf_call_arptables 1
-#define brnf_filter_vlan_tagged 0
-#define brnf_filter_pppoe_tagged 0
-#define brnf_pass_vlan_indev 0
+       struct ctl_table_header *ctl_hdr;
 #endif
 
+       /* default value is 1 */
+       int call_iptables;
+       int call_ip6tables;
+       int call_arptables;
+
+       /* default value is 0 */
+       int filter_vlan_tagged;
+       int filter_pppoe_tagged;
+       int pass_vlan_indev;
+};
+
 #define IS_IP(skb) \
        (!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
 
@@ -85,17 +82,28 @@ static inline __be16 vlan_proto(const struct sk_buff *skb)
                return 0;
 }
 
-#define IS_VLAN_IP(skb) \
-       (vlan_proto(skb) == htons(ETH_P_IP) && \
-        brnf_filter_vlan_tagged)
+static inline bool is_vlan_ip(const struct sk_buff *skb, const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       return vlan_proto(skb) == htons(ETH_P_IP) && brnet->filter_vlan_tagged;
+}
 
-#define IS_VLAN_IPV6(skb) \
-       (vlan_proto(skb) == htons(ETH_P_IPV6) && \
-        brnf_filter_vlan_tagged)
+static inline bool is_vlan_ipv6(const struct sk_buff *skb,
+                               const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
 
-#define IS_VLAN_ARP(skb) \
-       (vlan_proto(skb) == htons(ETH_P_ARP) && \
-        brnf_filter_vlan_tagged)
+       return vlan_proto(skb) == htons(ETH_P_IPV6) &&
+              brnet->filter_vlan_tagged;
+}
+
+static inline bool is_vlan_arp(const struct sk_buff *skb, const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       return vlan_proto(skb) == htons(ETH_P_ARP) && brnet->filter_vlan_tagged;
+}
 
 static inline __be16 pppoe_proto(const struct sk_buff *skb)
 {
@@ -103,15 +111,23 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
                            sizeof(struct pppoe_hdr)));
 }
 
-#define IS_PPPOE_IP(skb) \
-       (skb->protocol == htons(ETH_P_PPP_SES) && \
-        pppoe_proto(skb) == htons(PPP_IP) && \
-        brnf_filter_pppoe_tagged)
+static inline bool is_pppoe_ip(const struct sk_buff *skb, const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       return skb->protocol == htons(ETH_P_PPP_SES) &&
+              pppoe_proto(skb) == htons(PPP_IP) && brnet->filter_pppoe_tagged;
+}
+
+static inline bool is_pppoe_ipv6(const struct sk_buff *skb,
+                                const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
 
-#define IS_PPPOE_IPV6(skb) \
-       (skb->protocol == htons(ETH_P_PPP_SES) && \
-        pppoe_proto(skb) == htons(PPP_IPV6) && \
-        brnf_filter_pppoe_tagged)
+       return skb->protocol == htons(ETH_P_PPP_SES) &&
+              pppoe_proto(skb) == htons(PPP_IPV6) &&
+              brnet->filter_pppoe_tagged;
+}
 
 /* largest possible L2 header, see br_nf_dev_queue_xmit() */
 #define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN)
@@ -408,12 +424,16 @@ bridged_dnat:
        return 0;
 }
 
-static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
+static struct net_device *brnf_get_logical_dev(struct sk_buff *skb,
+                                              const struct net_device *dev,
+                                              const struct net *net)
 {
        struct net_device *vlan, *br;
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
 
        br = bridge_parent(dev);
-       if (brnf_pass_vlan_indev == 0 || !skb_vlan_tag_present(skb))
+
+       if (brnet->pass_vlan_indev == 0 || !skb_vlan_tag_present(skb))
                return br;
 
        vlan = __vlan_find_dev_deep_rcu(br, skb->vlan_proto,
@@ -423,7 +443,7 @@ static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct
 }
 
 /* Some common code for IPv4/IPv6 */
-struct net_device *setup_pre_routing(struct sk_buff *skb)
+struct net_device *setup_pre_routing(struct sk_buff *skb, const struct net *net)
 {
        struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
 
@@ -434,7 +454,7 @@ struct net_device *setup_pre_routing(struct sk_buff *skb)
 
        nf_bridge->in_prerouting = 1;
        nf_bridge->physindev = skb->dev;
-       skb->dev = brnf_get_logical_dev(skb, skb->dev);
+       skb->dev = brnf_get_logical_dev(skb, skb->dev, net);
 
        if (skb->protocol == htons(ETH_P_8021Q))
                nf_bridge->orig_proto = BRNF_PROTO_8021Q;
@@ -460,6 +480,7 @@ static unsigned int br_nf_pre_routing(void *priv,
        struct net_bridge_port *p;
        struct net_bridge *br;
        __u32 len = nf_bridge_encap_header_len(skb);
+       struct brnf_net *brnet;
 
        if (unlikely(!pskb_may_pull(skb, len)))
                return NF_DROP;
@@ -469,8 +490,10 @@ static unsigned int br_nf_pre_routing(void *priv,
                return NF_DROP;
        br = p->br;
 
-       if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
-               if (!brnf_call_ip6tables &&
+       brnet = net_generic(state->net, brnf_net_id);
+       if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
+           is_pppoe_ipv6(skb, state->net)) {
+               if (!brnet->call_ip6tables &&
                    !br_opt_get(br, BROPT_NF_CALL_IP6TABLES))
                        return NF_ACCEPT;
 
@@ -478,10 +501,11 @@ static unsigned int br_nf_pre_routing(void *priv,
                return br_nf_pre_routing_ipv6(priv, skb, state);
        }
 
-       if (!brnf_call_iptables && !br_opt_get(br, BROPT_NF_CALL_IPTABLES))
+       if (!brnet->call_iptables && !br_opt_get(br, BROPT_NF_CALL_IPTABLES))
                return NF_ACCEPT;
 
-       if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb))
+       if (!IS_IP(skb) && !is_vlan_ip(skb, state->net) &&
+           !is_pppoe_ip(skb, state->net))
                return NF_ACCEPT;
 
        nf_bridge_pull_encap_header_rcsum(skb);
@@ -491,7 +515,7 @@ static unsigned int br_nf_pre_routing(void *priv,
 
        if (!nf_bridge_alloc(skb))
                return NF_DROP;
-       if (!setup_pre_routing(skb))
+       if (!setup_pre_routing(skb, state->net))
                return NF_DROP;
 
        nf_bridge = nf_bridge_info_get(skb);
@@ -514,7 +538,7 @@ static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff
        struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
        struct net_device *in;
 
-       if (!IS_ARP(skb) && !IS_VLAN_ARP(skb)) {
+       if (!IS_ARP(skb) && !is_vlan_arp(skb, net)) {
 
                if (skb->protocol == htons(ETH_P_IP))
                        nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
@@ -569,9 +593,11 @@ static unsigned int br_nf_forward_ip(void *priv,
        if (!parent)
                return NF_DROP;
 
-       if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
+       if (IS_IP(skb) || is_vlan_ip(skb, state->net) ||
+           is_pppoe_ip(skb, state->net))
                pf = NFPROTO_IPV4;
-       else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
+       else if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
+                is_pppoe_ipv6(skb, state->net))
                pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
@@ -602,7 +628,7 @@ static unsigned int br_nf_forward_ip(void *priv,
                skb->protocol = htons(ETH_P_IPV6);
 
        NF_HOOK(pf, NF_INET_FORWARD, state->net, NULL, skb,
-               brnf_get_logical_dev(skb, state->in),
+               brnf_get_logical_dev(skb, state->in, state->net),
                parent, br_nf_forward_finish);
 
        return NF_STOLEN;
@@ -615,23 +641,25 @@ static unsigned int br_nf_forward_arp(void *priv,
        struct net_bridge_port *p;
        struct net_bridge *br;
        struct net_device **d = (struct net_device **)(skb->cb);
+       struct brnf_net *brnet;
 
        p = br_port_get_rcu(state->out);
        if (p == NULL)
                return NF_ACCEPT;
        br = p->br;
 
-       if (!brnf_call_arptables && !br_opt_get(br, BROPT_NF_CALL_ARPTABLES))
+       brnet = net_generic(state->net, brnf_net_id);
+       if (!brnet->call_arptables && !br_opt_get(br, BROPT_NF_CALL_ARPTABLES))
                return NF_ACCEPT;
 
        if (!IS_ARP(skb)) {
-               if (!IS_VLAN_ARP(skb))
+               if (!is_vlan_arp(skb, state->net))
                        return NF_ACCEPT;
                nf_bridge_pull_encap_header(skb);
        }
 
        if (arp_hdr(skb)->ar_pln != 4) {
-               if (IS_VLAN_ARP(skb))
+               if (is_vlan_arp(skb, state->net))
                        nf_bridge_push_encap_header(skb);
                return NF_ACCEPT;
        }
@@ -791,9 +819,11 @@ static unsigned int br_nf_post_routing(void *priv,
        if (!realoutdev)
                return NF_DROP;
 
-       if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
+       if (IS_IP(skb) || is_vlan_ip(skb, state->net) ||
+           is_pppoe_ip(skb, state->net))
                pf = NFPROTO_IPV4;
-       else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
+       else if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
+                is_pppoe_ipv6(skb, state->net))
                pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
@@ -946,23 +976,6 @@ static int brnf_device_event(struct notifier_block *unused, unsigned long event,
        return NOTIFY_OK;
 }
 
-static void __net_exit brnf_exit_net(struct net *net)
-{
-       struct brnf_net *brnet = net_generic(net, brnf_net_id);
-
-       if (!brnet->enabled)
-               return;
-
-       nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
-       brnet->enabled = false;
-}
-
-static struct pernet_operations brnf_net_ops __read_mostly = {
-       .exit = brnf_exit_net,
-       .id   = &brnf_net_id,
-       .size = sizeof(struct brnf_net),
-};
-
 static struct notifier_block brnf_notifier __read_mostly = {
        .notifier_call = brnf_device_event,
 };
@@ -1021,49 +1034,124 @@ int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
 static struct ctl_table brnf_table[] = {
        {
                .procname       = "bridge-nf-call-arptables",
-               .data           = &brnf_call_arptables,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-call-iptables",
-               .data           = &brnf_call_iptables,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-call-ip6tables",
-               .data           = &brnf_call_ip6tables,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-filter-vlan-tagged",
-               .data           = &brnf_filter_vlan_tagged,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-filter-pppoe-tagged",
-               .data           = &brnf_filter_pppoe_tagged,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-pass-vlan-input-dev",
-               .data           = &brnf_pass_vlan_indev,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        { }
 };
+
+static inline void br_netfilter_sysctl_default(struct brnf_net *brnf)
+{
+       brnf->call_iptables = 1;
+       brnf->call_ip6tables = 1;
+       brnf->call_arptables = 1;
+       brnf->filter_vlan_tagged = 0;
+       brnf->filter_pppoe_tagged = 0;
+       brnf->pass_vlan_indev = 0;
+}
+
+static int br_netfilter_sysctl_init_net(struct net *net)
+{
+       struct ctl_table *table = brnf_table;
+       struct brnf_net *brnet;
+
+       if (!net_eq(net, &init_net)) {
+               table = kmemdup(table, sizeof(brnf_table), GFP_KERNEL);
+               if (!table)
+                       return -ENOMEM;
+       }
+
+       brnet = net_generic(net, brnf_net_id);
+       table[0].data = &brnet->call_arptables;
+       table[1].data = &brnet->call_iptables;
+       table[2].data = &brnet->call_ip6tables;
+       table[3].data = &brnet->filter_vlan_tagged;
+       table[4].data = &brnet->filter_pppoe_tagged;
+       table[5].data = &brnet->pass_vlan_indev;
+
+       br_netfilter_sysctl_default(brnet);
+
+       brnet->ctl_hdr = register_net_sysctl(net, "net/bridge", table);
+       if (!brnet->ctl_hdr) {
+               if (!net_eq(net, &init_net))
+                       kfree(table);
+
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void br_netfilter_sysctl_exit_net(struct net *net,
+                                        struct brnf_net *brnet)
+{
+       struct ctl_table *table = brnet->ctl_hdr->ctl_table_arg;
+
+       unregister_net_sysctl_table(brnet->ctl_hdr);
+       if (!net_eq(net, &init_net))
+               kfree(table);
+}
+
+static int __net_init brnf_init_net(struct net *net)
+{
+       return br_netfilter_sysctl_init_net(net);
+}
+#endif
+
+static void __net_exit brnf_exit_net(struct net *net)
+{
+       struct brnf_net *brnet;
+
+       brnet = net_generic(net, brnf_net_id);
+       if (brnet->enabled) {
+               nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
+               brnet->enabled = false;
+       }
+
+#ifdef CONFIG_SYSCTL
+       br_netfilter_sysctl_exit_net(net, brnet);
 #endif
+}
+
+static struct pernet_operations brnf_net_ops __read_mostly = {
+#ifdef CONFIG_SYSCTL
+       .init = brnf_init_net,
+#endif
+       .exit = brnf_exit_net,
+       .id   = &brnf_net_id,
+       .size = sizeof(struct brnf_net),
+};
 
 static int __init br_netfilter_init(void)
 {
@@ -1079,16 +1167,6 @@ static int __init br_netfilter_init(void)
                return ret;
        }
 
-#ifdef CONFIG_SYSCTL
-       brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
-       if (brnf_sysctl_header == NULL) {
-               printk(KERN_WARNING
-                      "br_netfilter: can't register to sysctl.\n");
-               unregister_netdevice_notifier(&brnf_notifier);
-               unregister_pernet_subsys(&brnf_net_ops);
-               return -ENOMEM;
-       }
-#endif
        RCU_INIT_POINTER(nf_br_ops, &br_ops);
        printk(KERN_NOTICE "Bridge firewalling registered\n");
        return 0;
@@ -1099,9 +1177,6 @@ static void __exit br_netfilter_fini(void)
        RCU_INIT_POINTER(nf_br_ops, NULL);
        unregister_netdevice_notifier(&brnf_notifier);
        unregister_pernet_subsys(&brnf_net_ops);
-#ifdef CONFIG_SYSCTL
-       unregister_net_sysctl_table(brnf_sysctl_header);
-#endif
 }
 
 module_init(br_netfilter_init);
index 0e63e5dc5ac4f3907fad315edb9079aac7ee5a21..e4e0c836c3f51d9edfa351b67fed34549ff9e01d 100644 (file)
@@ -224,7 +224,7 @@ unsigned int br_nf_pre_routing_ipv6(void *priv,
        nf_bridge = nf_bridge_alloc(skb);
        if (!nf_bridge)
                return NF_DROP;
-       if (!setup_pre_routing(skb))
+       if (!setup_pre_routing(skb, state->net))
                return NF_DROP;
 
        nf_bridge = nf_bridge_info_get(skb);
index b675cd7c1a82b9c54114ed4c48461865f9529603..4f5444d2a526a3dfb72a322ca1ec9c94ad0440ef 100644 (file)
@@ -331,6 +331,8 @@ static int nf_ct_bridge_frag_restore(struct sk_buff *skb,
        }
        if (data->vlan_present)
                __vlan_hwaccel_put_tag(skb, data->vlan_proto, data->vlan_tci);
+       else if (skb_vlan_tag_present(skb))
+               __vlan_hwaccel_clear_tag(skb);
 
        skb_copy_to_linear_data_offset(skb, -ETH_HLEN, data->mac, ETH_HLEN);
        skb_reset_mac_header(skb);
index 3db31bb9df50622f8c9ae961f4eabc566d1cb74a..ddaa01ec2bce82f77333972813eeee4cbf87d1c9 100644 (file)
@@ -473,6 +473,7 @@ error:
                *info = htonl((pp_ptr-iph)<<24);
        return -EINVAL;
 }
+EXPORT_SYMBOL(__ip_options_compile);
 
 int ip_options_compile(struct net *net,
                       struct ip_options *opt, struct sk_buff *skb)
index 64d9563c0218f7170353a3a29e6869b9e481d719..8e7f84ec783da52e78a2f040a13f6bd60f2efee5 100644 (file)
  * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
  */
 
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <net/tcp.h>
-
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_SYNPROXY.h>
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_seqadj.h>
-#include <net/netfilter/nf_conntrack_synproxy.h>
-#include <net/netfilter/nf_conntrack_ecache.h>
-
-static struct iphdr *
-synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
-                 __be32 daddr)
-{
-       struct iphdr *iph;
-
-       skb_reset_network_header(skb);
-       iph = skb_put(skb, sizeof(*iph));
-       iph->version    = 4;
-       iph->ihl        = sizeof(*iph) / 4;
-       iph->tos        = 0;
-       iph->id         = 0;
-       iph->frag_off   = htons(IP_DF);
-       iph->ttl        = net->ipv4.sysctl_ip_default_ttl;
-       iph->protocol   = IPPROTO_TCP;
-       iph->check      = 0;
-       iph->saddr      = saddr;
-       iph->daddr      = daddr;
-
-       return iph;
-}
-
-static void
-synproxy_send_tcp(struct net *net,
-                 const struct sk_buff *skb, struct sk_buff *nskb,
-                 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
-                 struct iphdr *niph, struct tcphdr *nth,
-                 unsigned int tcp_hdr_size)
-{
-       nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0);
-       nskb->ip_summed   = CHECKSUM_PARTIAL;
-       nskb->csum_start  = (unsigned char *)nth - nskb->head;
-       nskb->csum_offset = offsetof(struct tcphdr, check);
-
-       skb_dst_set_noref(nskb, skb_dst(skb));
-       nskb->protocol = htons(ETH_P_IP);
-       if (ip_route_me_harder(net, nskb, RTN_UNSPEC))
-               goto free_nskb;
-
-       if (nfct) {
-               nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
-               nf_conntrack_get(nfct);
-       }
-
-       ip_local_out(net, nskb->sk, nskb);
-       return;
-
-free_nskb:
-       kfree_skb(nskb);
-}
-
-static void
-synproxy_send_client_synack(struct net *net,
-                           const struct sk_buff *skb, const struct tcphdr *th,
-                           const struct synproxy_options *opts)
-{
-       struct sk_buff *nskb;
-       struct iphdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-       u16 mss = opts->mss;
-
-       iph = ip_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->dest;
-       nth->dest       = th->source;
-       nth->seq        = htonl(__cookie_v4_init_sequence(iph, th, &mss));
-       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
-       tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
-       if (opts->options & XT_SYNPROXY_OPT_ECN)
-               tcp_flag_word(nth) |= TCP_FLAG_ECE;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = 0;
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
-                         IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
-}
-
-static void
-synproxy_send_server_syn(struct net *net,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        const struct synproxy_options *opts, u32 recv_seq)
-{
-       struct synproxy_net *snet = synproxy_pernet(net);
-       struct sk_buff *nskb;
-       struct iphdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-
-       iph = ip_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->source;
-       nth->dest       = th->dest;
-       nth->seq        = htonl(recv_seq - 1);
-       /* ack_seq is used to relay our ISN to the synproxy hook to initialize
-        * sequence number translation once a connection tracking entry exists.
-        */
-       nth->ack_seq    = htonl(ntohl(th->ack_seq) - 1);
-       tcp_flag_word(nth) = TCP_FLAG_SYN;
-       if (opts->options & XT_SYNPROXY_OPT_ECN)
-               tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = th->window;
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
-                         niph, nth, tcp_hdr_size);
-}
-
-static void
-synproxy_send_server_ack(struct net *net,
-                        const struct ip_ct_tcp *state,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        const struct synproxy_options *opts)
-{
-       struct sk_buff *nskb;
-       struct iphdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-
-       iph = ip_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
 
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->dest;
-       nth->dest       = th->source;
-       nth->seq        = htonl(ntohl(th->ack_seq));
-       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
-       tcp_flag_word(nth) = TCP_FLAG_ACK;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
-}
-
-static void
-synproxy_send_client_ack(struct net *net,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        const struct synproxy_options *opts)
-{
-       struct sk_buff *nskb;
-       struct iphdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-
-       iph = ip_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->source;
-       nth->dest       = th->dest;
-       nth->seq        = htonl(ntohl(th->seq) + 1);
-       nth->ack_seq    = th->ack_seq;
-       tcp_flag_word(nth) = TCP_FLAG_ACK;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = htons(ntohs(th->window) >> opts->wscale);
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
-                         IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
-}
-
-static bool
-synproxy_recv_client_ack(struct net *net,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        struct synproxy_options *opts, u32 recv_seq)
-{
-       struct synproxy_net *snet = synproxy_pernet(net);
-       int mss;
-
-       mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1);
-       if (mss == 0) {
-               this_cpu_inc(snet->stats->cookie_invalid);
-               return false;
-       }
-
-       this_cpu_inc(snet->stats->cookie_valid);
-       opts->mss = mss;
-       opts->options |= XT_SYNPROXY_OPT_MSS;
-
-       if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
-               synproxy_check_timestamp_cookie(opts);
-
-       synproxy_send_server_syn(net, skb, th, opts, recv_seq);
-       return true;
-}
+#include <net/netfilter/nf_synproxy.h>
 
 static unsigned int
 synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
@@ -306,135 +59,6 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
        return XT_CONTINUE;
 }
 
-static unsigned int ipv4_synproxy_hook(void *priv,
-                                      struct sk_buff *skb,
-                                      const struct nf_hook_state *nhs)
-{
-       struct net *net = nhs->net;
-       struct synproxy_net *snet = synproxy_pernet(net);
-       enum ip_conntrack_info ctinfo;
-       struct nf_conn *ct;
-       struct nf_conn_synproxy *synproxy;
-       struct synproxy_options opts = {};
-       const struct ip_ct_tcp *state;
-       struct tcphdr *th, _th;
-       unsigned int thoff;
-
-       ct = nf_ct_get(skb, &ctinfo);
-       if (ct == NULL)
-               return NF_ACCEPT;
-
-       synproxy = nfct_synproxy(ct);
-       if (synproxy == NULL)
-               return NF_ACCEPT;
-
-       if (nf_is_loopback_packet(skb) ||
-           ip_hdr(skb)->protocol != IPPROTO_TCP)
-               return NF_ACCEPT;
-
-       thoff = ip_hdrlen(skb);
-       th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
-       if (th == NULL)
-               return NF_DROP;
-
-       state = &ct->proto.tcp;
-       switch (state->state) {
-       case TCP_CONNTRACK_CLOSE:
-               if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
-                       nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
-                                                     ntohl(th->seq) + 1);
-                       break;
-               }
-
-               if (!th->syn || th->ack ||
-                   CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
-                       break;
-
-               /* Reopened connection - reset the sequence number and timestamp
-                * adjustments, they will get initialized once the connection is
-                * reestablished.
-                */
-               nf_ct_seqadj_init(ct, ctinfo, 0);
-               synproxy->tsoff = 0;
-               this_cpu_inc(snet->stats->conn_reopened);
-
-               /* fall through */
-       case TCP_CONNTRACK_SYN_SENT:
-               if (!synproxy_parse_options(skb, thoff, th, &opts))
-                       return NF_DROP;
-
-               if (!th->syn && th->ack &&
-                   CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
-                       /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
-                        * therefore we need to add 1 to make the SYN sequence
-                        * number match the one of first SYN.
-                        */
-                       if (synproxy_recv_client_ack(net, skb, th, &opts,
-                                                    ntohl(th->seq) + 1)) {
-                               this_cpu_inc(snet->stats->cookie_retrans);
-                               consume_skb(skb);
-                               return NF_STOLEN;
-                       } else {
-                               return NF_DROP;
-                       }
-               }
-
-               synproxy->isn = ntohl(th->ack_seq);
-               if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
-                       synproxy->its = opts.tsecr;
-
-               nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
-               break;
-       case TCP_CONNTRACK_SYN_RECV:
-               if (!th->syn || !th->ack)
-                       break;
-
-               if (!synproxy_parse_options(skb, thoff, th, &opts))
-                       return NF_DROP;
-
-               if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) {
-                       synproxy->tsoff = opts.tsval - synproxy->its;
-                       nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
-               }
-
-               opts.options &= ~(XT_SYNPROXY_OPT_MSS |
-                                 XT_SYNPROXY_OPT_WSCALE |
-                                 XT_SYNPROXY_OPT_SACK_PERM);
-
-               swap(opts.tsval, opts.tsecr);
-               synproxy_send_server_ack(net, state, skb, th, &opts);
-
-               nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
-               nf_conntrack_event_cache(IPCT_SEQADJ, ct);
-
-               swap(opts.tsval, opts.tsecr);
-               synproxy_send_client_ack(net, skb, th, &opts);
-
-               consume_skb(skb);
-               return NF_STOLEN;
-       default:
-               break;
-       }
-
-       synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
-       return NF_ACCEPT;
-}
-
-static const struct nf_hook_ops ipv4_synproxy_ops[] = {
-       {
-               .hook           = ipv4_synproxy_hook,
-               .pf             = NFPROTO_IPV4,
-               .hooknum        = NF_INET_LOCAL_IN,
-               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
-       },
-       {
-               .hook           = ipv4_synproxy_hook,
-               .pf             = NFPROTO_IPV4,
-               .hooknum        = NF_INET_POST_ROUTING,
-               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
-       },
-};
-
 static int synproxy_tg4_check(const struct xt_tgchk_param *par)
 {
        struct synproxy_net *snet = synproxy_pernet(par->net);
@@ -449,16 +73,12 @@ static int synproxy_tg4_check(const struct xt_tgchk_param *par)
        if (err)
                return err;
 
-       if (snet->hook_ref4 == 0) {
-               err = nf_register_net_hooks(par->net, ipv4_synproxy_ops,
-                                           ARRAY_SIZE(ipv4_synproxy_ops));
-               if (err) {
-                       nf_ct_netns_put(par->net, par->family);
-                       return err;
-               }
+       err = nf_synproxy_ipv4_init(snet, par->net);
+       if (err) {
+               nf_ct_netns_put(par->net, par->family);
+               return err;
        }
 
-       snet->hook_ref4++;
        return err;
 }
 
@@ -466,10 +86,7 @@ static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par)
 {
        struct synproxy_net *snet = synproxy_pernet(par->net);
 
-       snet->hook_ref4--;
-       if (snet->hook_ref4 == 0)
-               nf_unregister_net_hooks(par->net, ipv4_synproxy_ops,
-                                       ARRAY_SIZE(ipv4_synproxy_ops));
+       nf_synproxy_ipv4_fini(snet, par->net);
        nf_ct_netns_put(par->net, par->family);
 }
 
index 6eefde5bc468b5cdc9b68fe674dd18643cf20019..69697eb4bfc6fb0637356d0646188a2fd4b50448 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
  *
- * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
index f03340e75ce95efe4e5438827357fac26f968c04..87b711fd5a442633fc493dee2fcacc3ff34b9095 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 2006-2012 Patrick McHardy <kaber@trash.net>
  *
  * Based on the 'brute force' H.323 NAT module by
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 
 #include <linux/module.h>
index d9673e10c60cc73364d3d193dbf4a04352282dc9..61819ed858b10ffee0169ba889905a8a45887732 100644 (file)
@@ -234,12 +234,18 @@ static const struct nf_ipv6_ops ipv6ops = {
        .route_me_harder        = ip6_route_me_harder,
        .dev_get_saddr          = ipv6_dev_get_saddr,
        .route                  = __nf_ip6_route,
+#if IS_ENABLED(CONFIG_SYN_COOKIES)
+       .cookie_init_sequence   = __cookie_v6_init_sequence,
+       .cookie_v6_check        = __cookie_v6_check,
+#endif
 #endif
        .route_input            = ip6_route_input,
        .fragment               = ip6_fragment,
        .reroute                = nf_ip6_reroute,
-#if IS_MODULE(CONFIG_IPV6)
+#if IS_MODULE(CONFIG_IPV6) && IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
        .br_defrag              = nf_ct_frag6_gather,
+#endif
+#if IS_MODULE(CONFIG_IPV6)
        .br_fragment            = br_ip6_fragment,
 #endif
 };
index 41325d51747879a12e0dc44e2899c5e7589c878d..e77ea1ed5eddd41faeb5879c93879d0d29d6b903 100644 (file)
  * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
  */
 
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <net/ip6_checksum.h>
-#include <net/ip6_route.h>
-#include <net/tcp.h>
-
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_SYNPROXY.h>
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_seqadj.h>
-#include <net/netfilter/nf_conntrack_synproxy.h>
-#include <net/netfilter/nf_conntrack_ecache.h>
-
-static struct ipv6hdr *
-synproxy_build_ip(struct net *net, struct sk_buff *skb,
-                 const struct in6_addr *saddr,
-                 const struct in6_addr *daddr)
-{
-       struct ipv6hdr *iph;
-
-       skb_reset_network_header(skb);
-       iph = skb_put(skb, sizeof(*iph));
-       ip6_flow_hdr(iph, 0, 0);
-       iph->hop_limit  = net->ipv6.devconf_all->hop_limit;
-       iph->nexthdr    = IPPROTO_TCP;
-       iph->saddr      = *saddr;
-       iph->daddr      = *daddr;
-
-       return iph;
-}
-
-static void
-synproxy_send_tcp(struct net *net,
-                 const struct sk_buff *skb, struct sk_buff *nskb,
-                 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
-                 struct ipv6hdr *niph, struct tcphdr *nth,
-                 unsigned int tcp_hdr_size)
-{
-       struct dst_entry *dst;
-       struct flowi6 fl6;
-
-       nth->check = ~tcp_v6_check(tcp_hdr_size, &niph->saddr, &niph->daddr, 0);
-       nskb->ip_summed   = CHECKSUM_PARTIAL;
-       nskb->csum_start  = (unsigned char *)nth - nskb->head;
-       nskb->csum_offset = offsetof(struct tcphdr, check);
-
-       memset(&fl6, 0, sizeof(fl6));
-       fl6.flowi6_proto = IPPROTO_TCP;
-       fl6.saddr = niph->saddr;
-       fl6.daddr = niph->daddr;
-       fl6.fl6_sport = nth->source;
-       fl6.fl6_dport = nth->dest;
-       security_skb_classify_flow((struct sk_buff *)skb, flowi6_to_flowi(&fl6));
-       dst = ip6_route_output(net, NULL, &fl6);
-       if (dst->error) {
-               dst_release(dst);
-               goto free_nskb;
-       }
-       dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
-       if (IS_ERR(dst))
-               goto free_nskb;
-
-       skb_dst_set(nskb, dst);
-
-       if (nfct) {
-               nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
-               nf_conntrack_get(nfct);
-       }
-
-       ip6_local_out(net, nskb->sk, nskb);
-       return;
-
-free_nskb:
-       kfree_skb(nskb);
-}
-
-static void
-synproxy_send_client_synack(struct net *net,
-                           const struct sk_buff *skb, const struct tcphdr *th,
-                           const struct synproxy_options *opts)
-{
-       struct sk_buff *nskb;
-       struct ipv6hdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-       u16 mss = opts->mss;
-
-       iph = ipv6_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, &iph->daddr, &iph->saddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->dest;
-       nth->dest       = th->source;
-       nth->seq        = htonl(__cookie_v6_init_sequence(iph, th, &mss));
-       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
-       tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
-       if (opts->options & XT_SYNPROXY_OPT_ECN)
-               tcp_flag_word(nth) |= TCP_FLAG_ECE;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = 0;
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
-                         IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
-}
 
-static void
-synproxy_send_server_syn(struct net *net,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        const struct synproxy_options *opts, u32 recv_seq)
-{
-       struct synproxy_net *snet = synproxy_pernet(net);
-       struct sk_buff *nskb;
-       struct ipv6hdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-
-       iph = ipv6_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, &iph->saddr, &iph->daddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->source;
-       nth->dest       = th->dest;
-       nth->seq        = htonl(recv_seq - 1);
-       /* ack_seq is used to relay our ISN to the synproxy hook to initialize
-        * sequence number translation once a connection tracking entry exists.
-        */
-       nth->ack_seq    = htonl(ntohl(th->ack_seq) - 1);
-       tcp_flag_word(nth) = TCP_FLAG_SYN;
-       if (opts->options & XT_SYNPROXY_OPT_ECN)
-               tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = th->window;
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
-                         niph, nth, tcp_hdr_size);
-}
-
-static void
-synproxy_send_server_ack(struct net *net,
-                        const struct ip_ct_tcp *state,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        const struct synproxy_options *opts)
-{
-       struct sk_buff *nskb;
-       struct ipv6hdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-
-       iph = ipv6_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, &iph->daddr, &iph->saddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->dest;
-       nth->dest       = th->source;
-       nth->seq        = htonl(ntohl(th->ack_seq));
-       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
-       tcp_flag_word(nth) = TCP_FLAG_ACK;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
-}
-
-static void
-synproxy_send_client_ack(struct net *net,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        const struct synproxy_options *opts)
-{
-       struct sk_buff *nskb;
-       struct ipv6hdr *iph, *niph;
-       struct tcphdr *nth;
-       unsigned int tcp_hdr_size;
-
-       iph = ipv6_hdr(skb);
-
-       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
-       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
-                        GFP_ATOMIC);
-       if (nskb == NULL)
-               return;
-       skb_reserve(nskb, MAX_TCP_HEADER);
-
-       niph = synproxy_build_ip(net, nskb, &iph->saddr, &iph->daddr);
-
-       skb_reset_transport_header(nskb);
-       nth = skb_put(nskb, tcp_hdr_size);
-       nth->source     = th->source;
-       nth->dest       = th->dest;
-       nth->seq        = htonl(ntohl(th->seq) + 1);
-       nth->ack_seq    = th->ack_seq;
-       tcp_flag_word(nth) = TCP_FLAG_ACK;
-       nth->doff       = tcp_hdr_size / 4;
-       nth->window     = htons(ntohs(th->window) >> opts->wscale);
-       nth->check      = 0;
-       nth->urg_ptr    = 0;
-
-       synproxy_build_options(nth, opts);
-
-       synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
-                         IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
-}
-
-static bool
-synproxy_recv_client_ack(struct net *net,
-                        const struct sk_buff *skb, const struct tcphdr *th,
-                        struct synproxy_options *opts, u32 recv_seq)
-{
-       struct synproxy_net *snet = synproxy_pernet(net);
-       int mss;
-
-       mss = __cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1);
-       if (mss == 0) {
-               this_cpu_inc(snet->stats->cookie_invalid);
-               return false;
-       }
-
-       this_cpu_inc(snet->stats->cookie_valid);
-       opts->mss = mss;
-       opts->options |= XT_SYNPROXY_OPT_MSS;
-
-       if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
-               synproxy_check_timestamp_cookie(opts);
-
-       synproxy_send_server_syn(net, skb, th, opts, recv_seq);
-       return true;
-}
+#include <net/netfilter/nf_synproxy.h>
 
 static unsigned int
 synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
@@ -304,13 +43,14 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
                                          XT_SYNPROXY_OPT_SACK_PERM |
                                          XT_SYNPROXY_OPT_ECN);
 
-               synproxy_send_client_synack(net, skb, th, &opts);
+               synproxy_send_client_synack_ipv6(net, skb, th, &opts);
                consume_skb(skb);
                return NF_STOLEN;
 
        } else if (th->ack && !(th->fin || th->rst || th->syn)) {
                /* ACK from client */
-               if (synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq))) {
+               if (synproxy_recv_client_ack_ipv6(net, skb, th, &opts,
+                                                 ntohl(th->seq))) {
                        consume_skb(skb);
                        return NF_STOLEN;
                } else {
@@ -321,141 +61,6 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        return XT_CONTINUE;
 }
 
-static unsigned int ipv6_synproxy_hook(void *priv,
-                                      struct sk_buff *skb,
-                                      const struct nf_hook_state *nhs)
-{
-       struct net *net = nhs->net;
-       struct synproxy_net *snet = synproxy_pernet(net);
-       enum ip_conntrack_info ctinfo;
-       struct nf_conn *ct;
-       struct nf_conn_synproxy *synproxy;
-       struct synproxy_options opts = {};
-       const struct ip_ct_tcp *state;
-       struct tcphdr *th, _th;
-       __be16 frag_off;
-       u8 nexthdr;
-       int thoff;
-
-       ct = nf_ct_get(skb, &ctinfo);
-       if (ct == NULL)
-               return NF_ACCEPT;
-
-       synproxy = nfct_synproxy(ct);
-       if (synproxy == NULL)
-               return NF_ACCEPT;
-
-       if (nf_is_loopback_packet(skb))
-               return NF_ACCEPT;
-
-       nexthdr = ipv6_hdr(skb)->nexthdr;
-       thoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
-                                &frag_off);
-       if (thoff < 0 || nexthdr != IPPROTO_TCP)
-               return NF_ACCEPT;
-
-       th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
-       if (th == NULL)
-               return NF_DROP;
-
-       state = &ct->proto.tcp;
-       switch (state->state) {
-       case TCP_CONNTRACK_CLOSE:
-               if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
-                       nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
-                                                     ntohl(th->seq) + 1);
-                       break;
-               }
-
-               if (!th->syn || th->ack ||
-                   CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
-                       break;
-
-               /* Reopened connection - reset the sequence number and timestamp
-                * adjustments, they will get initialized once the connection is
-                * reestablished.
-                */
-               nf_ct_seqadj_init(ct, ctinfo, 0);
-               synproxy->tsoff = 0;
-               this_cpu_inc(snet->stats->conn_reopened);
-
-               /* fall through */
-       case TCP_CONNTRACK_SYN_SENT:
-               if (!synproxy_parse_options(skb, thoff, th, &opts))
-                       return NF_DROP;
-
-               if (!th->syn && th->ack &&
-                   CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
-                       /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
-                        * therefore we need to add 1 to make the SYN sequence
-                        * number match the one of first SYN.
-                        */
-                       if (synproxy_recv_client_ack(net, skb, th, &opts,
-                                                    ntohl(th->seq) + 1)) {
-                               this_cpu_inc(snet->stats->cookie_retrans);
-                               consume_skb(skb);
-                               return NF_STOLEN;
-                       } else {
-                               return NF_DROP;
-                       }
-               }
-
-               synproxy->isn = ntohl(th->ack_seq);
-               if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
-                       synproxy->its = opts.tsecr;
-
-               nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
-               break;
-       case TCP_CONNTRACK_SYN_RECV:
-               if (!th->syn || !th->ack)
-                       break;
-
-               if (!synproxy_parse_options(skb, thoff, th, &opts))
-                       return NF_DROP;
-
-               if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) {
-                       synproxy->tsoff = opts.tsval - synproxy->its;
-                       nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
-               }
-
-               opts.options &= ~(XT_SYNPROXY_OPT_MSS |
-                                 XT_SYNPROXY_OPT_WSCALE |
-                                 XT_SYNPROXY_OPT_SACK_PERM);
-
-               swap(opts.tsval, opts.tsecr);
-               synproxy_send_server_ack(net, state, skb, th, &opts);
-
-               nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
-               nf_conntrack_event_cache(IPCT_SEQADJ, ct);
-
-               swap(opts.tsval, opts.tsecr);
-               synproxy_send_client_ack(net, skb, th, &opts);
-
-               consume_skb(skb);
-               return NF_STOLEN;
-       default:
-               break;
-       }
-
-       synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
-       return NF_ACCEPT;
-}
-
-static const struct nf_hook_ops ipv6_synproxy_ops[] = {
-       {
-               .hook           = ipv6_synproxy_hook,
-               .pf             = NFPROTO_IPV6,
-               .hooknum        = NF_INET_LOCAL_IN,
-               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
-       },
-       {
-               .hook           = ipv6_synproxy_hook,
-               .pf             = NFPROTO_IPV6,
-               .hooknum        = NF_INET_POST_ROUTING,
-               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
-       },
-};
-
 static int synproxy_tg6_check(const struct xt_tgchk_param *par)
 {
        struct synproxy_net *snet = synproxy_pernet(par->net);
@@ -471,16 +76,12 @@ static int synproxy_tg6_check(const struct xt_tgchk_param *par)
        if (err)
                return err;
 
-       if (snet->hook_ref6 == 0) {
-               err = nf_register_net_hooks(par->net, ipv6_synproxy_ops,
-                                           ARRAY_SIZE(ipv6_synproxy_ops));
-               if (err) {
-                       nf_ct_netns_put(par->net, par->family);
-                       return err;
-               }
+       err = nf_synproxy_ipv6_init(snet, par->net);
+       if (err) {
+               nf_ct_netns_put(par->net, par->family);
+               return err;
        }
 
-       snet->hook_ref6++;
        return err;
 }
 
@@ -488,10 +89,7 @@ static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
 {
        struct synproxy_net *snet = synproxy_pernet(par->net);
 
-       snet->hook_ref6--;
-       if (snet->hook_ref6 == 0)
-               nf_unregister_net_hooks(par->net, ipv6_synproxy_ops,
-                                       ARRAY_SIZE(ipv6_synproxy_ops));
+       nf_synproxy_ipv6_fini(snet, par->net);
        nf_ct_netns_put(par->net, par->family);
 }
 
index 3f7d4691c4238a4ec0c4470c97f425913255e51c..a22100b1cf2cd23c8aa138c2a9ae9aabb87d8a18 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * IPv6 raw table, a port of the IPv4 raw table to IPv6
  *
- * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
index 8acc4e173167b2c87078aa95f6d83ab863eef07b..063df74b4647004b4279199d44e03fc765d7da47 100644 (file)
@@ -1,6 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 #ifndef __IP_SET_BITMAP_IP_GEN_H
 #define __IP_SET_BITMAP_IP_GEN_H
index e3884b0cca912bd4f08a86726398cb8faf137a50..11ff9d4a70063bc8b730986abdce0cd79dafd27c 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
- * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 
 /* Kernel module implementing an IP set type: the bitmap:ip type */
@@ -28,7 +28,7 @@
 #define IPSET_TYPE_REV_MAX     3       /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("bitmap:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_bitmap:ip");
 
index b73c37b3a791f2d9a0dfa7a81077f3e94b51bf0f..ca7ac4a25ada2f1527175f03d204d90bedfea7ba 100644 (file)
@@ -2,7 +2,6 @@
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
  *                        Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  */
 
 /* Kernel module implementing an IP set type: the bitmap:ip,mac type */
@@ -28,7 +27,7 @@
 #define IPSET_TYPE_REV_MAX     3       /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_bitmap:ip,mac");
 
index d8c14055337977d77ace349a2b84a500e0d7e9fd..704a0dda16090aab2660105ef96a03a37003de76 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the bitmap:port type */
 
@@ -23,7 +22,7 @@
 #define IPSET_TYPE_REV_MAX     3       /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("bitmap:port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_bitmap:port");
 
index 3cdf171cd4682e90a28758c30c561c9ba2a9c6fe..2e151856ad9992f1ec338f8fd6bed53b98c30be4 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
- * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 
 /* Kernel module for IP set management */
@@ -48,7 +48,7 @@ static unsigned int max_sets;
 module_param(max_sets, int, 0600);
 MODULE_PARM_DESC(max_sets, "maximal number of sets");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 MODULE_DESCRIPTION("core IP set support");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
 
@@ -1290,11 +1290,13 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
        struct nlattr *attr = (void *)nlh + min_len;
        u32 dump_type;
        ip_set_id_t index;
+       int ret;
 
-       /* Second pass, so parser can't fail */
-       nla_parse_deprecated(cda, IPSET_ATTR_CMD_MAX, attr,
-                            nlh->nlmsg_len - min_len, ip_set_setname_policy,
-                            NULL);
+       ret = nla_parse_deprecated(cda, IPSET_ATTR_CMD_MAX, attr,
+                                  nlh->nlmsg_len - min_len,
+                                  ip_set_setname_policy, NULL);
+       if (ret)
+               return ret;
 
        cb->args[IPSET_CB_PROTO] = nla_get_u8(cda[IPSET_ATTR_PROTOCOL]);
        if (cda[IPSET_ATTR_SETNAME]) {
@@ -1541,10 +1543,14 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
                memcpy(&errmsg->msg, nlh, nlh->nlmsg_len);
                cmdattr = (void *)&errmsg->msg + min_len;
 
-               nla_parse_deprecated(cda, IPSET_ATTR_CMD_MAX, cmdattr,
-                                    nlh->nlmsg_len - min_len,
-                                    ip_set_adt_policy, NULL);
+               ret = nla_parse_deprecated(cda, IPSET_ATTR_CMD_MAX, cmdattr,
+                                          nlh->nlmsg_len - min_len,
+                                          ip_set_adt_policy, NULL);
 
+               if (ret) {
+                       nlmsg_free(skb2);
+                       return ret;
+               }
                errline = nla_data(cda[IPSET_ATTR_LINENO]);
 
                *errline = lineno;
@@ -1558,10 +1564,12 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
        return ret;
 }
 
-static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
-                      const struct nlmsghdr *nlh,
-                      const struct nlattr * const attr[],
-                      struct netlink_ext_ack *extack)
+static int ip_set_ad(struct net *net, struct sock *ctnl,
+                    struct sk_buff *skb,
+                    enum ipset_adt adt,
+                    const struct nlmsghdr *nlh,
+                    const struct nlattr * const attr[],
+                    struct netlink_ext_ack *extack)
 {
        struct ip_set_net *inst = ip_set_pernet(net);
        struct ip_set *set;
@@ -1590,18 +1598,17 @@ static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
        if (attr[IPSET_ATTR_DATA]) {
                if (nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], set->type->adt_policy, NULL))
                        return -IPSET_ERR_PROTOCOL;
-               ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags,
+               ret = call_ad(ctnl, skb, set, tb, adt, flags,
                              use_lineno);
        } else {
                int nla_rem;
 
                nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
-                       memset(tb, 0, sizeof(tb));
                        if (nla_type(nla) != IPSET_ATTR_DATA ||
                            !flag_nested(nla) ||
                            nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, nla, set->type->adt_policy, NULL))
                                return -IPSET_ERR_PROTOCOL;
-                       ret = call_ad(ctnl, skb, set, tb, IPSET_ADD,
+                       ret = call_ad(ctnl, skb, set, tb, adt,
                                      flags, use_lineno);
                        if (ret < 0)
                                return ret;
@@ -1610,56 +1617,22 @@ static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
        return ret;
 }
 
-static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb,
-                      const struct nlmsghdr *nlh,
+static int ip_set_uadd(struct net *net, struct sock *ctnl,
+                      struct sk_buff *skb, const struct nlmsghdr *nlh,
                       const struct nlattr * const attr[],
                       struct netlink_ext_ack *extack)
 {
-       struct ip_set_net *inst = ip_set_pernet(net);
-       struct ip_set *set;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
-       const struct nlattr *nla;
-       u32 flags = flag_exist(nlh);
-       bool use_lineno;
-       int ret = 0;
-
-       if (unlikely(protocol_min_failed(attr) ||
-                    !attr[IPSET_ATTR_SETNAME] ||
-                    !((attr[IPSET_ATTR_DATA] != NULL) ^
-                      (attr[IPSET_ATTR_ADT] != NULL)) ||
-                    (attr[IPSET_ATTR_DATA] &&
-                     !flag_nested(attr[IPSET_ATTR_DATA])) ||
-                    (attr[IPSET_ATTR_ADT] &&
-                     (!flag_nested(attr[IPSET_ATTR_ADT]) ||
-                      !attr[IPSET_ATTR_LINENO]))))
-               return -IPSET_ERR_PROTOCOL;
-
-       set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
-       if (!set)
-               return -ENOENT;
-
-       use_lineno = !!attr[IPSET_ATTR_LINENO];
-       if (attr[IPSET_ATTR_DATA]) {
-               if (nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], set->type->adt_policy, NULL))
-                       return -IPSET_ERR_PROTOCOL;
-               ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags,
-                             use_lineno);
-       } else {
-               int nla_rem;
+       return ip_set_ad(net, ctnl, skb,
+                        IPSET_ADD, nlh, attr, extack);
+}
 
-               nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
-                       memset(tb, 0, sizeof(*tb));
-                       if (nla_type(nla) != IPSET_ATTR_DATA ||
-                           !flag_nested(nla) ||
-                           nla_parse_nested_deprecated(tb, IPSET_ATTR_ADT_MAX, nla, set->type->adt_policy, NULL))
-                               return -IPSET_ERR_PROTOCOL;
-                       ret = call_ad(ctnl, skb, set, tb, IPSET_DEL,
-                                     flags, use_lineno);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
-       return ret;
+static int ip_set_udel(struct net *net, struct sock *ctnl,
+                      struct sk_buff *skb, const struct nlmsghdr *nlh,
+                      const struct nlattr * const attr[],
+                      struct netlink_ext_ack *extack)
+{
+       return ip_set_ad(net, ctnl, skb,
+                        IPSET_DEL, nlh, attr, extack);
 }
 
 static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
index 2384e36aef5cf2470fdbc9d3994c59ad130996af..2b8f959574b4475ab4231cee0f115f89e7d44113 100644 (file)
@@ -1,5 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@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.
  */
 
 /* Get Layer-4 data from the packets */
index 10f619625abdead9151a4fdf0dd1aa362438edd0..0feb77fa9edcee1fd51f6939d001b14c5d5be728 100644 (file)
@@ -1,6 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 #ifndef _IP_SET_HASH_GEN_H
 #define _IP_SET_HASH_GEN_H
@@ -622,7 +621,7 @@ retry:
                                        goto cleanup;
                                }
                                m->size = AHASH_INIT_SIZE;
-                               extsize = ext_size(AHASH_INIT_SIZE, dsize);
+                               extsize += ext_size(AHASH_INIT_SIZE, dsize);
                                RCU_INIT_POINTER(hbucket(t, key), m);
                        } else if (m->pos >= m->size) {
                                struct hbucket *ht;
index 69d7576be2e6579068030d33495ca067e46ee93f..f4432d9fcad0dde2e832df706122f5dcddc08a33 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:ip type */
 
@@ -27,7 +26,7 @@
 #define IPSET_TYPE_REV_MAX     4       /* skbinfo support  */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:ip");
 
index 6fe1ec0d2154c11350bd4ff491d406f9037844c0..7a1734aad0c57c4cded438401af2fd9e824aa5e3 100644 (file)
@@ -1,7 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- * Copyright (C) 2013 Smoothwall Ltd. <vytas.dauksa@smoothwall.net>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:ip,mark type */
 
index 74ec7e097e34cdf3281886fe6213a706e792affc..32e240658334f338fcf02d67693bba805697fb52 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:ip,port type */
 
@@ -29,7 +28,7 @@
 #define IPSET_TYPE_REV_MAX     5 /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:ip,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:ip,port");
 
index ced57d63b01f21cdcaf956f6d1fd7598e1f8bbbd..15d41935317940a6693f42c780951e8ba08a0820 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:ip,port,ip type */
 
@@ -29,7 +28,7 @@
 #define IPSET_TYPE_REV_MAX     5 /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:ip,port,ip");
 
index 905f6cf0f55e316d03e9f831c8252da9e1ee1baa..7a4d7afd4121580845a4a2d0668229b22b593841 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:ip,port,net type */
 
@@ -31,7 +30,7 @@
 #define IPSET_TYPE_REV_MAX     7 /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:ip,port,net");
 
index 853e772ab4d962e000a78e31526cc048bf7cd5dd..d94c585d33c5c32d7ab93b9dbc79a6d8f4f5f190 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2014 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2014 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:mac type */
 
@@ -20,7 +19,7 @@
 #define IPSET_TYPE_REV_MAX     0
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:mac");
 
index 06c91e49bf25d46e9dcb2d47798e6f0b3859b55f..c259cbc3ef453eaee5461e2b98fc3dc735d196ad 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:net type */
 
@@ -28,7 +27,7 @@
 #define IPSET_TYPE_REV_MAX     6 /* skbinfo mapping support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:net");
 
index 0a8cbcdfb42ba48ae51488fc9675eb8806ae5584..87b29f971226f90d512c57bba4faf59c73e73ef3 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2011-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2011-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:net,iface type */
 
@@ -29,7 +28,7 @@
 #define IPSET_TYPE_REV_MAX     6 /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:net,iface");
 
index 832e4f5491cbf3f762a2f8798eea2250964d52bd..a3ae69bfee668466f276f5cdebb451048a7eb5e9 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
  * Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
  */
 
index a4f3f15b874a4f5402845564ff5a9ad14ceee543..799f2272cc65b5fb6161a626c41db7ffe68dd9e0 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:net,port type */
 
@@ -30,7 +29,7 @@
 #define IPSET_TYPE_REV_MAX     7 /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("hash:net,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:net,port");
 
index e54d415405f34e4dbdacbb411abf38dda3199a51..a82b70e8b9a631a143bfdf2ba642972386beec8d 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the hash:ip,port,net type */
 
index 8ada318bf09dbb8865b63101ddc1e27649120791..6f9ead6319e0d840a64de28327b409399dcd8c73 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2008-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
+/* Copyright (C) 2008-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
 
 /* Kernel module implementing an IP set type: the list:set type */
 
@@ -19,7 +18,7 @@
 #define IPSET_TYPE_REV_MAX     3 /* skbinfo support added */
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_list:set");
 
index f4f9b8344a32dccd6f3a64a44f526220540f759c..bdfeacee081771023bb734dc465915a74f062a01 100644 (file)
@@ -749,9 +749,6 @@ begin:
                        continue;
                }
 
-               if (nf_ct_is_dying(ct))
-                       continue;
-
                if (nf_ct_key_equal(h, tuple, zone, net))
                        return h;
        }
@@ -777,20 +774,24 @@ __nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone,
        struct nf_conn *ct;
 
        rcu_read_lock();
-begin:
+
        h = ____nf_conntrack_find(net, zone, tuple, hash);
        if (h) {
+               /* We have a candidate that matches the tuple we're interested
+                * in, try to obtain a reference and re-check tuple
+                */
                ct = nf_ct_tuplehash_to_ctrack(h);
-               if (unlikely(nf_ct_is_dying(ct) ||
-                            !atomic_inc_not_zero(&ct->ct_general.use)))
-                       h = NULL;
-               else {
-                       if (unlikely(!nf_ct_key_equal(h, tuple, zone, net))) {
-                               nf_ct_put(ct);
-                               goto begin;
-                       }
+               if (likely(atomic_inc_not_zero(&ct->ct_general.use))) {
+                       if (likely(nf_ct_key_equal(h, tuple, zone, net)))
+                               goto found;
+
+                       /* TYPESAFE_BY_RCU recycled the candidate */
+                       nf_ct_put(ct);
                }
+
+               h = NULL;
        }
+found:
        rcu_read_unlock();
 
        return h;
index fac6986d37a8f04140ad7d5a33d99d9e61c02bdc..6497e5fc087101b4dc7664616f113e0c4857ce70 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 2006-2012 Patrick McHardy <kaber@trash.net>
  *
  * Based on the 'brute force' H.323 connection tracking module by
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Jozsef Kadlecsik <kadlec@netfilter.org>
  *
  * For more information, please see http://nath323.sourceforge.net/
  */
index 1e2cc83ff5da8378ceecd695039c22955052711e..d5fdfa00d683098d53d14a1932ef6d8224283d32 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- * (C) 2002-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * (C) 2002-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
  * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
  */
 
index 41ff0f3faf61e21bb30139c3ba04a73362445ccf..409722d233023e2420b830fc5abfa1ba9702edc2 100644 (file)
 #include <net/netns/generic.h>
 #include <linux/proc_fs.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_tcpudp.h>
-#include <linux/netfilter/xt_SYNPROXY.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/nf_SYNPROXY.h>
 
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_conntrack_extend.h>
 #include <net/netfilter/nf_conntrack_seqadj.h>
 #include <net/netfilter/nf_conntrack_synproxy.h>
 #include <net/netfilter/nf_conntrack_zones.h>
+#include <net/netfilter/nf_synproxy.h>
 
 unsigned int synproxy_net_id;
 EXPORT_SYMBOL_GPL(synproxy_net_id);
@@ -57,7 +57,7 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                        case TCPOPT_MSS:
                                if (opsize == TCPOLEN_MSS) {
                                        opts->mss = get_unaligned_be16(ptr);
-                                       opts->options |= XT_SYNPROXY_OPT_MSS;
+                                       opts->options |= NF_SYNPROXY_OPT_MSS;
                                }
                                break;
                        case TCPOPT_WINDOW:
@@ -65,19 +65,19 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                                        opts->wscale = *ptr;
                                        if (opts->wscale > TCP_MAX_WSCALE)
                                                opts->wscale = TCP_MAX_WSCALE;
-                                       opts->options |= XT_SYNPROXY_OPT_WSCALE;
+                                       opts->options |= NF_SYNPROXY_OPT_WSCALE;
                                }
                                break;
                        case TCPOPT_TIMESTAMP:
                                if (opsize == TCPOLEN_TIMESTAMP) {
                                        opts->tsval = get_unaligned_be32(ptr);
                                        opts->tsecr = get_unaligned_be32(ptr + 4);
-                                       opts->options |= XT_SYNPROXY_OPT_TIMESTAMP;
+                                       opts->options |= NF_SYNPROXY_OPT_TIMESTAMP;
                                }
                                break;
                        case TCPOPT_SACK_PERM:
                                if (opsize == TCPOLEN_SACK_PERM)
-                                       opts->options |= XT_SYNPROXY_OPT_SACK_PERM;
+                                       opts->options |= NF_SYNPROXY_OPT_SACK_PERM;
                                break;
                        }
 
@@ -89,36 +89,36 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
 }
 EXPORT_SYMBOL_GPL(synproxy_parse_options);
 
-unsigned int synproxy_options_size(const struct synproxy_options *opts)
+static unsigned int
+synproxy_options_size(const struct synproxy_options *opts)
 {
        unsigned int size = 0;
 
-       if (opts->options & XT_SYNPROXY_OPT_MSS)
+       if (opts->options & NF_SYNPROXY_OPT_MSS)
                size += TCPOLEN_MSS_ALIGNED;
-       if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
+       if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
                size += TCPOLEN_TSTAMP_ALIGNED;
-       else if (opts->options & XT_SYNPROXY_OPT_SACK_PERM)
+       else if (opts->options & NF_SYNPROXY_OPT_SACK_PERM)
                size += TCPOLEN_SACKPERM_ALIGNED;
-       if (opts->options & XT_SYNPROXY_OPT_WSCALE)
+       if (opts->options & NF_SYNPROXY_OPT_WSCALE)
                size += TCPOLEN_WSCALE_ALIGNED;
 
        return size;
 }
-EXPORT_SYMBOL_GPL(synproxy_options_size);
 
-void
+static void
 synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts)
 {
        __be32 *ptr = (__be32 *)(th + 1);
        u8 options = opts->options;
 
-       if (options & XT_SYNPROXY_OPT_MSS)
+       if (options & NF_SYNPROXY_OPT_MSS)
                *ptr++ = htonl((TCPOPT_MSS << 24) |
                               (TCPOLEN_MSS << 16) |
                               opts->mss);
 
-       if (options & XT_SYNPROXY_OPT_TIMESTAMP) {
-               if (options & XT_SYNPROXY_OPT_SACK_PERM)
+       if (options & NF_SYNPROXY_OPT_TIMESTAMP) {
+               if (options & NF_SYNPROXY_OPT_SACK_PERM)
                        *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
                                       (TCPOLEN_SACK_PERM << 16) |
                                       (TCPOPT_TIMESTAMP << 8) |
@@ -131,58 +131,56 @@ synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts)
 
                *ptr++ = htonl(opts->tsval);
                *ptr++ = htonl(opts->tsecr);
-       } else if (options & XT_SYNPROXY_OPT_SACK_PERM)
+       } else if (options & NF_SYNPROXY_OPT_SACK_PERM)
                *ptr++ = htonl((TCPOPT_NOP << 24) |
                               (TCPOPT_NOP << 16) |
                               (TCPOPT_SACK_PERM << 8) |
                               TCPOLEN_SACK_PERM);
 
-       if (options & XT_SYNPROXY_OPT_WSCALE)
+       if (options & NF_SYNPROXY_OPT_WSCALE)
                *ptr++ = htonl((TCPOPT_NOP << 24) |
                               (TCPOPT_WINDOW << 16) |
                               (TCPOLEN_WINDOW << 8) |
                               opts->wscale);
 }
-EXPORT_SYMBOL_GPL(synproxy_build_options);
 
-void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info,
+void synproxy_init_timestamp_cookie(const struct nf_synproxy_info *info,
                                    struct synproxy_options *opts)
 {
        opts->tsecr = opts->tsval;
        opts->tsval = tcp_time_stamp_raw() & ~0x3f;
 
-       if (opts->options & XT_SYNPROXY_OPT_WSCALE) {
+       if (opts->options & NF_SYNPROXY_OPT_WSCALE) {
                opts->tsval |= opts->wscale;
                opts->wscale = info->wscale;
        } else
                opts->tsval |= 0xf;
 
-       if (opts->options & XT_SYNPROXY_OPT_SACK_PERM)
+       if (opts->options & NF_SYNPROXY_OPT_SACK_PERM)
                opts->tsval |= 1 << 4;
 
-       if (opts->options & XT_SYNPROXY_OPT_ECN)
+       if (opts->options & NF_SYNPROXY_OPT_ECN)
                opts->tsval |= 1 << 5;
 }
 EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie);
 
-void synproxy_check_timestamp_cookie(struct synproxy_options *opts)
+static void
+synproxy_check_timestamp_cookie(struct synproxy_options *opts)
 {
        opts->wscale = opts->tsecr & 0xf;
        if (opts->wscale != 0xf)
-               opts->options |= XT_SYNPROXY_OPT_WSCALE;
+               opts->options |= NF_SYNPROXY_OPT_WSCALE;
 
-       opts->options |= opts->tsecr & (1 << 4) ? XT_SYNPROXY_OPT_SACK_PERM : 0;
+       opts->options |= opts->tsecr & (1 << 4) ? NF_SYNPROXY_OPT_SACK_PERM : 0;
 
-       opts->options |= opts->tsecr & (1 << 5) ? XT_SYNPROXY_OPT_ECN : 0;
+       opts->options |= opts->tsecr & (1 << 5) ? NF_SYNPROXY_OPT_ECN : 0;
 }
-EXPORT_SYMBOL_GPL(synproxy_check_timestamp_cookie);
 
-unsigned int synproxy_tstamp_adjust(struct sk_buff *skb,
-                                   unsigned int protoff,
-                                   struct tcphdr *th,
-                                   struct nf_conn *ct,
-                                   enum ip_conntrack_info ctinfo,
-                                   const struct nf_conn_synproxy *synproxy)
+static unsigned int
+synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,
+                      struct tcphdr *th, struct nf_conn *ct,
+                      enum ip_conntrack_info ctinfo,
+                      const struct nf_conn_synproxy *synproxy)
 {
        unsigned int optoff, optend;
        __be32 *ptr, old;
@@ -232,7 +230,6 @@ unsigned int synproxy_tstamp_adjust(struct sk_buff *skb,
        }
        return 1;
 }
-EXPORT_SYMBOL_GPL(synproxy_tstamp_adjust);
 
 static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = {
        .len            = sizeof(struct nf_conn_synproxy),
@@ -413,5 +410,830 @@ static void __exit synproxy_core_exit(void)
 module_init(synproxy_core_init);
 module_exit(synproxy_core_exit);
 
+static struct iphdr *
+synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
+                 __be32 daddr)
+{
+       struct iphdr *iph;
+
+       skb_reset_network_header(skb);
+       iph = skb_put(skb, sizeof(*iph));
+       iph->version    = 4;
+       iph->ihl        = sizeof(*iph) / 4;
+       iph->tos        = 0;
+       iph->id         = 0;
+       iph->frag_off   = htons(IP_DF);
+       iph->ttl        = net->ipv4.sysctl_ip_default_ttl;
+       iph->protocol   = IPPROTO_TCP;
+       iph->check      = 0;
+       iph->saddr      = saddr;
+       iph->daddr      = daddr;
+
+       return iph;
+}
+
+static void
+synproxy_send_tcp(struct net *net,
+                 const struct sk_buff *skb, struct sk_buff *nskb,
+                 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
+                 struct iphdr *niph, struct tcphdr *nth,
+                 unsigned int tcp_hdr_size)
+{
+       nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0);
+       nskb->ip_summed   = CHECKSUM_PARTIAL;
+       nskb->csum_start  = (unsigned char *)nth - nskb->head;
+       nskb->csum_offset = offsetof(struct tcphdr, check);
+
+       skb_dst_set_noref(nskb, skb_dst(skb));
+       nskb->protocol = htons(ETH_P_IP);
+       if (ip_route_me_harder(net, nskb, RTN_UNSPEC))
+               goto free_nskb;
+
+       if (nfct) {
+               nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
+               nf_conntrack_get(nfct);
+       }
+
+       ip_local_out(net, nskb->sk, nskb);
+       return;
+
+free_nskb:
+       kfree_skb(nskb);
+}
+
+void
+synproxy_send_client_synack(struct net *net,
+                           const struct sk_buff *skb, const struct tcphdr *th,
+                           const struct synproxy_options *opts)
+{
+       struct sk_buff *nskb;
+       struct iphdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+       u16 mss = opts->mss;
+
+       iph = ip_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->dest;
+       nth->dest       = th->source;
+       nth->seq        = htonl(__cookie_v4_init_sequence(iph, th, &mss));
+       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
+       tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
+       if (opts->options & NF_SYNPROXY_OPT_ECN)
+               tcp_flag_word(nth) |= TCP_FLAG_ECE;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = 0;
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
+                         IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
+}
+EXPORT_SYMBOL_GPL(synproxy_send_client_synack);
+
+static void
+synproxy_send_server_syn(struct net *net,
+                        const struct sk_buff *skb, const struct tcphdr *th,
+                        const struct synproxy_options *opts, u32 recv_seq)
+{
+       struct synproxy_net *snet = synproxy_pernet(net);
+       struct sk_buff *nskb;
+       struct iphdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+
+       iph = ip_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->source;
+       nth->dest       = th->dest;
+       nth->seq        = htonl(recv_seq - 1);
+       /* ack_seq is used to relay our ISN to the synproxy hook to initialize
+        * sequence number translation once a connection tracking entry exists.
+        */
+       nth->ack_seq    = htonl(ntohl(th->ack_seq) - 1);
+       tcp_flag_word(nth) = TCP_FLAG_SYN;
+       if (opts->options & NF_SYNPROXY_OPT_ECN)
+               tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = th->window;
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
+                         niph, nth, tcp_hdr_size);
+}
+
+static void
+synproxy_send_server_ack(struct net *net,
+                        const struct ip_ct_tcp *state,
+                        const struct sk_buff *skb, const struct tcphdr *th,
+                        const struct synproxy_options *opts)
+{
+       struct sk_buff *nskb;
+       struct iphdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+
+       iph = ip_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->dest;
+       nth->dest       = th->source;
+       nth->seq        = htonl(ntohl(th->ack_seq));
+       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
+       tcp_flag_word(nth) = TCP_FLAG_ACK;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+}
+
+static void
+synproxy_send_client_ack(struct net *net,
+                        const struct sk_buff *skb, const struct tcphdr *th,
+                        const struct synproxy_options *opts)
+{
+       struct sk_buff *nskb;
+       struct iphdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+
+       iph = ip_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->source;
+       nth->dest       = th->dest;
+       nth->seq        = htonl(ntohl(th->seq) + 1);
+       nth->ack_seq    = th->ack_seq;
+       tcp_flag_word(nth) = TCP_FLAG_ACK;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = htons(ntohs(th->window) >> opts->wscale);
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
+                         IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
+}
+
+bool
+synproxy_recv_client_ack(struct net *net,
+                        const struct sk_buff *skb, const struct tcphdr *th,
+                        struct synproxy_options *opts, u32 recv_seq)
+{
+       struct synproxy_net *snet = synproxy_pernet(net);
+       int mss;
+
+       mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1);
+       if (mss == 0) {
+               this_cpu_inc(snet->stats->cookie_invalid);
+               return false;
+       }
+
+       this_cpu_inc(snet->stats->cookie_valid);
+       opts->mss = mss;
+       opts->options |= NF_SYNPROXY_OPT_MSS;
+
+       if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
+               synproxy_check_timestamp_cookie(opts);
+
+       synproxy_send_server_syn(net, skb, th, opts, recv_seq);
+       return true;
+}
+EXPORT_SYMBOL_GPL(synproxy_recv_client_ack);
+
+unsigned int
+ipv4_synproxy_hook(void *priv, struct sk_buff *skb,
+                  const struct nf_hook_state *nhs)
+{
+       struct net *net = nhs->net;
+       struct synproxy_net *snet = synproxy_pernet(net);
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct;
+       struct nf_conn_synproxy *synproxy;
+       struct synproxy_options opts = {};
+       const struct ip_ct_tcp *state;
+       struct tcphdr *th, _th;
+       unsigned int thoff;
+
+       ct = nf_ct_get(skb, &ctinfo);
+       if (!ct)
+               return NF_ACCEPT;
+
+       synproxy = nfct_synproxy(ct);
+       if (!synproxy)
+               return NF_ACCEPT;
+
+       if (nf_is_loopback_packet(skb) ||
+           ip_hdr(skb)->protocol != IPPROTO_TCP)
+               return NF_ACCEPT;
+
+       thoff = ip_hdrlen(skb);
+       th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
+       if (!th)
+               return NF_DROP;
+
+       state = &ct->proto.tcp;
+       switch (state->state) {
+       case TCP_CONNTRACK_CLOSE:
+               if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+                       nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
+                                                     ntohl(th->seq) + 1);
+                       break;
+               }
+
+               if (!th->syn || th->ack ||
+                   CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
+                       break;
+
+               /* Reopened connection - reset the sequence number and timestamp
+                * adjustments, they will get initialized once the connection is
+                * reestablished.
+                */
+               nf_ct_seqadj_init(ct, ctinfo, 0);
+               synproxy->tsoff = 0;
+               this_cpu_inc(snet->stats->conn_reopened);
+
+               /* fall through */
+       case TCP_CONNTRACK_SYN_SENT:
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
+               if (!th->syn && th->ack &&
+                   CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+                       /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
+                        * therefore we need to add 1 to make the SYN sequence
+                        * number match the one of first SYN.
+                        */
+                       if (synproxy_recv_client_ack(net, skb, th, &opts,
+                                                    ntohl(th->seq) + 1)) {
+                               this_cpu_inc(snet->stats->cookie_retrans);
+                               consume_skb(skb);
+                               return NF_STOLEN;
+                       } else {
+                               return NF_DROP;
+                       }
+               }
+
+               synproxy->isn = ntohl(th->ack_seq);
+               if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
+                       synproxy->its = opts.tsecr;
+
+               nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
+               break;
+       case TCP_CONNTRACK_SYN_RECV:
+               if (!th->syn || !th->ack)
+                       break;
+
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
+               if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP) {
+                       synproxy->tsoff = opts.tsval - synproxy->its;
+                       nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
+               }
+
+               opts.options &= ~(NF_SYNPROXY_OPT_MSS |
+                                 NF_SYNPROXY_OPT_WSCALE |
+                                 NF_SYNPROXY_OPT_SACK_PERM);
+
+               swap(opts.tsval, opts.tsecr);
+               synproxy_send_server_ack(net, state, skb, th, &opts);
+
+               nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
+               nf_conntrack_event_cache(IPCT_SEQADJ, ct);
+
+               swap(opts.tsval, opts.tsecr);
+               synproxy_send_client_ack(net, skb, th, &opts);
+
+               consume_skb(skb);
+               return NF_STOLEN;
+       default:
+               break;
+       }
+
+       synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
+       return NF_ACCEPT;
+}
+EXPORT_SYMBOL_GPL(ipv4_synproxy_hook);
+
+static const struct nf_hook_ops ipv4_synproxy_ops[] = {
+       {
+               .hook           = ipv4_synproxy_hook,
+               .pf             = NFPROTO_IPV4,
+               .hooknum        = NF_INET_LOCAL_IN,
+               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
+       },
+       {
+               .hook           = ipv4_synproxy_hook,
+               .pf             = NFPROTO_IPV4,
+               .hooknum        = NF_INET_POST_ROUTING,
+               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
+       },
+};
+
+int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net)
+{
+       int err;
+
+       if (snet->hook_ref4 == 0) {
+               err = nf_register_net_hooks(net, ipv4_synproxy_ops,
+                                           ARRAY_SIZE(ipv4_synproxy_ops));
+               if (err)
+                       return err;
+       }
+
+       snet->hook_ref4++;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init);
+
+void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net)
+{
+       snet->hook_ref4--;
+       if (snet->hook_ref4 == 0)
+               nf_unregister_net_hooks(net, ipv4_synproxy_ops,
+                                       ARRAY_SIZE(ipv4_synproxy_ops));
+}
+EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini);
+
+#if IS_ENABLED(CONFIG_IPV6)
+static struct ipv6hdr *
+synproxy_build_ip_ipv6(struct net *net, struct sk_buff *skb,
+                      const struct in6_addr *saddr,
+                      const struct in6_addr *daddr)
+{
+       struct ipv6hdr *iph;
+
+       skb_reset_network_header(skb);
+       iph = skb_put(skb, sizeof(*iph));
+       ip6_flow_hdr(iph, 0, 0);
+       iph->hop_limit  = net->ipv6.devconf_all->hop_limit;
+       iph->nexthdr    = IPPROTO_TCP;
+       iph->saddr      = *saddr;
+       iph->daddr      = *daddr;
+
+       return iph;
+}
+
+static void
+synproxy_send_tcp_ipv6(struct net *net,
+                      const struct sk_buff *skb, struct sk_buff *nskb,
+                      struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
+                      struct ipv6hdr *niph, struct tcphdr *nth,
+                      unsigned int tcp_hdr_size)
+{
+       struct dst_entry *dst;
+       struct flowi6 fl6;
+       int err;
+
+       nth->check = ~tcp_v6_check(tcp_hdr_size, &niph->saddr, &niph->daddr, 0);
+       nskb->ip_summed   = CHECKSUM_PARTIAL;
+       nskb->csum_start  = (unsigned char *)nth - nskb->head;
+       nskb->csum_offset = offsetof(struct tcphdr, check);
+
+       memset(&fl6, 0, sizeof(fl6));
+       fl6.flowi6_proto = IPPROTO_TCP;
+       fl6.saddr = niph->saddr;
+       fl6.daddr = niph->daddr;
+       fl6.fl6_sport = nth->source;
+       fl6.fl6_dport = nth->dest;
+       security_skb_classify_flow((struct sk_buff *)skb,
+                                  flowi6_to_flowi(&fl6));
+       err = nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false);
+       if (err) {
+               goto free_nskb;
+       }
+
+       dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
+       if (IS_ERR(dst))
+               goto free_nskb;
+
+       skb_dst_set(nskb, dst);
+
+       if (nfct) {
+               nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
+               nf_conntrack_get(nfct);
+       }
+
+       ip6_local_out(net, nskb->sk, nskb);
+       return;
+
+free_nskb:
+       kfree_skb(nskb);
+}
+
+void
+synproxy_send_client_synack_ipv6(struct net *net,
+                                const struct sk_buff *skb,
+                                const struct tcphdr *th,
+                                const struct synproxy_options *opts)
+{
+       struct sk_buff *nskb;
+       struct ipv6hdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+       u16 mss = opts->mss;
+
+       iph = ipv6_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip_ipv6(net, nskb, &iph->daddr, &iph->saddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->dest;
+       nth->dest       = th->source;
+       nth->seq        = htonl(nf_ipv6_cookie_init_sequence(iph, th, &mss));
+       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
+       tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
+       if (opts->options & NF_SYNPROXY_OPT_ECN)
+               tcp_flag_word(nth) |= TCP_FLAG_ECE;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = 0;
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp_ipv6(net, skb, nskb, skb_nfct(skb),
+                              IP_CT_ESTABLISHED_REPLY, niph, nth,
+                              tcp_hdr_size);
+}
+EXPORT_SYMBOL_GPL(synproxy_send_client_synack_ipv6);
+
+static void
+synproxy_send_server_syn_ipv6(struct net *net, const struct sk_buff *skb,
+                             const struct tcphdr *th,
+                             const struct synproxy_options *opts, u32 recv_seq)
+{
+       struct synproxy_net *snet = synproxy_pernet(net);
+       struct sk_buff *nskb;
+       struct ipv6hdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+
+       iph = ipv6_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip_ipv6(net, nskb, &iph->saddr, &iph->daddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->source;
+       nth->dest       = th->dest;
+       nth->seq        = htonl(recv_seq - 1);
+       /* ack_seq is used to relay our ISN to the synproxy hook to initialize
+        * sequence number translation once a connection tracking entry exists.
+        */
+       nth->ack_seq    = htonl(ntohl(th->ack_seq) - 1);
+       tcp_flag_word(nth) = TCP_FLAG_SYN;
+       if (opts->options & NF_SYNPROXY_OPT_ECN)
+               tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = th->window;
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp_ipv6(net, skb, nskb, &snet->tmpl->ct_general,
+                              IP_CT_NEW, niph, nth, tcp_hdr_size);
+}
+
+static void
+synproxy_send_server_ack_ipv6(struct net *net, const struct ip_ct_tcp *state,
+                             const struct sk_buff *skb,
+                             const struct tcphdr *th,
+                             const struct synproxy_options *opts)
+{
+       struct sk_buff *nskb;
+       struct ipv6hdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+
+       iph = ipv6_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip_ipv6(net, nskb, &iph->daddr, &iph->saddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->dest;
+       nth->dest       = th->source;
+       nth->seq        = htonl(ntohl(th->ack_seq));
+       nth->ack_seq    = htonl(ntohl(th->seq) + 1);
+       tcp_flag_word(nth) = TCP_FLAG_ACK;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp_ipv6(net, skb, nskb, NULL, 0, niph, nth,
+                              tcp_hdr_size);
+}
+
+static void
+synproxy_send_client_ack_ipv6(struct net *net, const struct sk_buff *skb,
+                             const struct tcphdr *th,
+                             const struct synproxy_options *opts)
+{
+       struct sk_buff *nskb;
+       struct ipv6hdr *iph, *niph;
+       struct tcphdr *nth;
+       unsigned int tcp_hdr_size;
+
+       iph = ipv6_hdr(skb);
+
+       tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
+       nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
+                        GFP_ATOMIC);
+       if (!nskb)
+               return;
+       skb_reserve(nskb, MAX_TCP_HEADER);
+
+       niph = synproxy_build_ip_ipv6(net, nskb, &iph->saddr, &iph->daddr);
+
+       skb_reset_transport_header(nskb);
+       nth = skb_put(nskb, tcp_hdr_size);
+       nth->source     = th->source;
+       nth->dest       = th->dest;
+       nth->seq        = htonl(ntohl(th->seq) + 1);
+       nth->ack_seq    = th->ack_seq;
+       tcp_flag_word(nth) = TCP_FLAG_ACK;
+       nth->doff       = tcp_hdr_size / 4;
+       nth->window     = htons(ntohs(th->window) >> opts->wscale);
+       nth->check      = 0;
+       nth->urg_ptr    = 0;
+
+       synproxy_build_options(nth, opts);
+
+       synproxy_send_tcp_ipv6(net, skb, nskb, skb_nfct(skb),
+                              IP_CT_ESTABLISHED_REPLY, niph, nth,
+                              tcp_hdr_size);
+}
+
+bool
+synproxy_recv_client_ack_ipv6(struct net *net,
+                             const struct sk_buff *skb,
+                             const struct tcphdr *th,
+                             struct synproxy_options *opts, u32 recv_seq)
+{
+       struct synproxy_net *snet = synproxy_pernet(net);
+       int mss;
+
+       mss = nf_cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1);
+       if (mss == 0) {
+               this_cpu_inc(snet->stats->cookie_invalid);
+               return false;
+       }
+
+       this_cpu_inc(snet->stats->cookie_valid);
+       opts->mss = mss;
+       opts->options |= NF_SYNPROXY_OPT_MSS;
+
+       if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
+               synproxy_check_timestamp_cookie(opts);
+
+       synproxy_send_server_syn_ipv6(net, skb, th, opts, recv_seq);
+       return true;
+}
+EXPORT_SYMBOL_GPL(synproxy_recv_client_ack_ipv6);
+
+unsigned int
+ipv6_synproxy_hook(void *priv, struct sk_buff *skb,
+                  const struct nf_hook_state *nhs)
+{
+       struct net *net = nhs->net;
+       struct synproxy_net *snet = synproxy_pernet(net);
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct;
+       struct nf_conn_synproxy *synproxy;
+       struct synproxy_options opts = {};
+       const struct ip_ct_tcp *state;
+       struct tcphdr *th, _th;
+       __be16 frag_off;
+       u8 nexthdr;
+       int thoff;
+
+       ct = nf_ct_get(skb, &ctinfo);
+       if (!ct)
+               return NF_ACCEPT;
+
+       synproxy = nfct_synproxy(ct);
+       if (!synproxy)
+               return NF_ACCEPT;
+
+       if (nf_is_loopback_packet(skb))
+               return NF_ACCEPT;
+
+       nexthdr = ipv6_hdr(skb)->nexthdr;
+       thoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
+                                &frag_off);
+       if (thoff < 0 || nexthdr != IPPROTO_TCP)
+               return NF_ACCEPT;
+
+       th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
+       if (!th)
+               return NF_DROP;
+
+       state = &ct->proto.tcp;
+       switch (state->state) {
+       case TCP_CONNTRACK_CLOSE:
+               if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+                       nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
+                                                     ntohl(th->seq) + 1);
+                       break;
+               }
+
+               if (!th->syn || th->ack ||
+                   CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
+                       break;
+
+               /* Reopened connection - reset the sequence number and timestamp
+                * adjustments, they will get initialized once the connection is
+                * reestablished.
+                */
+               nf_ct_seqadj_init(ct, ctinfo, 0);
+               synproxy->tsoff = 0;
+               this_cpu_inc(snet->stats->conn_reopened);
+
+               /* fall through */
+       case TCP_CONNTRACK_SYN_SENT:
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
+               if (!th->syn && th->ack &&
+                   CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+                       /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
+                        * therefore we need to add 1 to make the SYN sequence
+                        * number match the one of first SYN.
+                        */
+                       if (synproxy_recv_client_ack_ipv6(net, skb, th, &opts,
+                                                         ntohl(th->seq) + 1)) {
+                               this_cpu_inc(snet->stats->cookie_retrans);
+                               consume_skb(skb);
+                               return NF_STOLEN;
+                       } else {
+                               return NF_DROP;
+                       }
+               }
+
+               synproxy->isn = ntohl(th->ack_seq);
+               if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
+                       synproxy->its = opts.tsecr;
+
+               nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
+               break;
+       case TCP_CONNTRACK_SYN_RECV:
+               if (!th->syn || !th->ack)
+                       break;
+
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
+               if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP) {
+                       synproxy->tsoff = opts.tsval - synproxy->its;
+                       nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
+               }
+
+               opts.options &= ~(NF_SYNPROXY_OPT_MSS |
+                                 NF_SYNPROXY_OPT_WSCALE |
+                                 NF_SYNPROXY_OPT_SACK_PERM);
+
+               swap(opts.tsval, opts.tsecr);
+               synproxy_send_server_ack_ipv6(net, state, skb, th, &opts);
+
+               nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
+               nf_conntrack_event_cache(IPCT_SEQADJ, ct);
+
+               swap(opts.tsval, opts.tsecr);
+               synproxy_send_client_ack_ipv6(net, skb, th, &opts);
+
+               consume_skb(skb);
+               return NF_STOLEN;
+       default:
+               break;
+       }
+
+       synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
+       return NF_ACCEPT;
+}
+EXPORT_SYMBOL_GPL(ipv6_synproxy_hook);
+
+static const struct nf_hook_ops ipv6_synproxy_ops[] = {
+       {
+               .hook           = ipv6_synproxy_hook,
+               .pf             = NFPROTO_IPV6,
+               .hooknum        = NF_INET_LOCAL_IN,
+               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
+       },
+       {
+               .hook           = ipv6_synproxy_hook,
+               .pf             = NFPROTO_IPV6,
+               .hooknum        = NF_INET_POST_ROUTING,
+               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
+       },
+};
+
+int
+nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
+{
+       int err;
+
+       if (snet->hook_ref6 == 0) {
+               err = nf_register_net_hooks(net, ipv6_synproxy_ops,
+                                           ARRAY_SIZE(ipv6_synproxy_ops));
+               if (err)
+                       return err;
+       }
+
+       snet->hook_ref6++;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);
+
+void
+nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net)
+{
+       snet->hook_ref6--;
+       if (snet->hook_ref6 == 0)
+               nf_unregister_net_hooks(net, ipv6_synproxy_ops,
+                                       ARRAY_SIZE(ipv6_synproxy_ops));
+}
+EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini);
+#endif /* CONFIG_IPV6 */
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
index 06f2ce0cee4a5ffa6a772e039e427b278acb643e..cae5c46e2dd460b585f2ecf77e92c7a6cfead6a4 100644 (file)
@@ -3870,6 +3870,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
        [NFTA_SET_ELEM_DATA]            = { .type = NLA_NESTED },
        [NFTA_SET_ELEM_FLAGS]           = { .type = NLA_U32 },
        [NFTA_SET_ELEM_TIMEOUT]         = { .type = NLA_U64 },
+       [NFTA_SET_ELEM_EXPIRATION]      = { .type = NLA_U64 },
        [NFTA_SET_ELEM_USERDATA]        = { .type = NLA_BINARY,
                                            .len = NFT_USERDATA_MAXLEN },
        [NFTA_SET_ELEM_EXPR]            = { .type = NLA_NESTED },
@@ -4323,7 +4324,7 @@ static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
 void *nft_set_elem_init(const struct nft_set *set,
                        const struct nft_set_ext_tmpl *tmpl,
                        const u32 *key, const u32 *data,
-                       u64 timeout, gfp_t gfp)
+                       u64 timeout, u64 expiration, gfp_t gfp)
 {
        struct nft_set_ext *ext;
        void *elem;
@@ -4338,9 +4339,11 @@ void *nft_set_elem_init(const struct nft_set *set,
        memcpy(nft_set_ext_key(ext), key, set->klen);
        if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
                memcpy(nft_set_ext_data(ext), data, set->dlen);
-       if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION))
-               *nft_set_ext_expiration(ext) =
-                       get_jiffies_64() + timeout;
+       if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
+               *nft_set_ext_expiration(ext) = get_jiffies_64() + expiration;
+               if (expiration == 0)
+                       *nft_set_ext_expiration(ext) += timeout;
+       }
        if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
                *nft_set_ext_timeout(ext) = timeout;
 
@@ -4405,6 +4408,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        struct nft_trans *trans;
        u32 flags = 0;
        u64 timeout;
+       u64 expiration;
        u8 ulen;
        int err;
 
@@ -4448,6 +4452,16 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                timeout = set->timeout;
        }
 
+       expiration = 0;
+       if (nla[NFTA_SET_ELEM_EXPIRATION] != NULL) {
+               if (!(set->flags & NFT_SET_TIMEOUT))
+                       return -EINVAL;
+               err = nf_msecs_to_jiffies64(nla[NFTA_SET_ELEM_EXPIRATION],
+                                           &expiration);
+               if (err)
+                       return err;
+       }
+
        err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
                            nla[NFTA_SET_ELEM_KEY]);
        if (err < 0)
@@ -4530,7 +4544,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 
        err = -ENOMEM;
        elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
-                                     timeout, GFP_KERNEL);
+                                     timeout, expiration, GFP_KERNEL);
        if (elem.priv == NULL)
                goto err3;
 
@@ -4732,7 +4746,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 
        err = -ENOMEM;
        elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0,
-                                     GFP_KERNEL);
+                                     0, GFP_KERNEL);
        if (elem.priv == NULL)
                goto err2;
 
index dfcdea6619f1429956894227b93ae8a582675e95..827ab6196df9964ab11ace6980d196155c6388ee 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/netfilter/nf_conntrack_labels.h>
 #include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_expect.h>
 
 struct nft_ct {
        enum nft_ct_keys        key:8;
@@ -1153,6 +1154,135 @@ static struct nft_object_type nft_ct_helper_obj_type __read_mostly = {
        .owner          = THIS_MODULE,
 };
 
+struct nft_ct_expect_obj {
+       u16             l3num;
+       __be16          dport;
+       u8              l4proto;
+       u8              size;
+       u32             timeout;
+};
+
+static int nft_ct_expect_obj_init(const struct nft_ctx *ctx,
+                                 const struct nlattr * const tb[],
+                                 struct nft_object *obj)
+{
+       struct nft_ct_expect_obj *priv = nft_obj_data(obj);
+
+       if (!tb[NFTA_CT_EXPECT_L4PROTO] ||
+           !tb[NFTA_CT_EXPECT_DPORT] ||
+           !tb[NFTA_CT_EXPECT_TIMEOUT] ||
+           !tb[NFTA_CT_EXPECT_SIZE])
+               return -EINVAL;
+
+       priv->l3num = ctx->family;
+       if (tb[NFTA_CT_EXPECT_L3PROTO])
+               priv->l3num = ntohs(nla_get_be16(tb[NFTA_CT_EXPECT_L3PROTO]));
+
+       priv->l4proto = nla_get_u8(tb[NFTA_CT_EXPECT_L4PROTO]);
+       priv->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]);
+       priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]);
+       priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]);
+
+       return nf_ct_netns_get(ctx->net, ctx->family);
+}
+
+static void nft_ct_expect_obj_destroy(const struct nft_ctx *ctx,
+                                      struct nft_object *obj)
+{
+       nf_ct_netns_put(ctx->net, ctx->family);
+}
+
+static int nft_ct_expect_obj_dump(struct sk_buff *skb,
+                                 struct nft_object *obj, bool reset)
+{
+       const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
+
+       if (nla_put_be16(skb, NFTA_CT_EXPECT_L3PROTO, htons(priv->l3num)) ||
+           nla_put_u8(skb, NFTA_CT_EXPECT_L4PROTO, priv->l4proto) ||
+           nla_put_be16(skb, NFTA_CT_EXPECT_DPORT, priv->dport) ||
+           nla_put_u32(skb, NFTA_CT_EXPECT_TIMEOUT, priv->timeout) ||
+           nla_put_u8(skb, NFTA_CT_EXPECT_SIZE, priv->size))
+               return -1;
+
+       return 0;
+}
+
+static void nft_ct_expect_obj_eval(struct nft_object *obj,
+                                  struct nft_regs *regs,
+                                  const struct nft_pktinfo *pkt)
+{
+       const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
+       struct nf_conntrack_expect *exp;
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn_help *help;
+       enum ip_conntrack_dir dir;
+       u16 l3num = priv->l3num;
+       struct nf_conn *ct;
+
+       ct = nf_ct_get(pkt->skb, &ctinfo);
+       if (!ct || ctinfo == IP_CT_UNTRACKED) {
+               regs->verdict.code = NFT_BREAK;
+               return;
+       }
+       dir = CTINFO2DIR(ctinfo);
+
+       help = nfct_help(ct);
+       if (!help)
+               help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+       if (!help) {
+               regs->verdict.code = NF_DROP;
+               return;
+       }
+
+       if (help->expecting[NF_CT_EXPECT_CLASS_DEFAULT] >= priv->size) {
+               regs->verdict.code = NFT_BREAK;
+               return;
+       }
+       if (l3num == NFPROTO_INET)
+               l3num = nf_ct_l3num(ct);
+
+       exp = nf_ct_expect_alloc(ct);
+       if (exp == NULL) {
+               regs->verdict.code = NF_DROP;
+               return;
+       }
+       nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, l3num,
+                         &ct->tuplehash[!dir].tuple.src.u3,
+                         &ct->tuplehash[!dir].tuple.dst.u3,
+                         priv->l4proto, NULL, &priv->dport);
+       exp->timeout.expires = jiffies + priv->timeout * HZ;
+
+       if (nf_ct_expect_related(exp) != 0)
+               regs->verdict.code = NF_DROP;
+}
+
+static const struct nla_policy nft_ct_expect_policy[NFTA_CT_EXPECT_MAX + 1] = {
+       [NFTA_CT_EXPECT_L3PROTO]        = { .type = NLA_U16 },
+       [NFTA_CT_EXPECT_L4PROTO]        = { .type = NLA_U8 },
+       [NFTA_CT_EXPECT_DPORT]          = { .type = NLA_U16 },
+       [NFTA_CT_EXPECT_TIMEOUT]        = { .type = NLA_U32 },
+       [NFTA_CT_EXPECT_SIZE]           = { .type = NLA_U8 },
+};
+
+static struct nft_object_type nft_ct_expect_obj_type;
+
+static const struct nft_object_ops nft_ct_expect_obj_ops = {
+       .type           = &nft_ct_expect_obj_type,
+       .size           = sizeof(struct nft_ct_expect_obj),
+       .eval           = nft_ct_expect_obj_eval,
+       .init           = nft_ct_expect_obj_init,
+       .destroy        = nft_ct_expect_obj_destroy,
+       .dump           = nft_ct_expect_obj_dump,
+};
+
+static struct nft_object_type nft_ct_expect_obj_type __read_mostly = {
+       .type           = NFT_OBJECT_CT_EXPECT,
+       .ops            = &nft_ct_expect_obj_ops,
+       .maxattr        = NFTA_CT_EXPECT_MAX,
+       .policy         = nft_ct_expect_policy,
+       .owner          = THIS_MODULE,
+};
+
 static int __init nft_ct_module_init(void)
 {
        int err;
@@ -1170,17 +1300,23 @@ static int __init nft_ct_module_init(void)
        err = nft_register_obj(&nft_ct_helper_obj_type);
        if (err < 0)
                goto err2;
+
+       err = nft_register_obj(&nft_ct_expect_obj_type);
+       if (err < 0)
+               goto err3;
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
        err = nft_register_obj(&nft_ct_timeout_obj_type);
        if (err < 0)
-               goto err3;
+               goto err4;
 #endif
        return 0;
 
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+err4:
+       nft_unregister_obj(&nft_ct_expect_obj_type);
+#endif
 err3:
        nft_unregister_obj(&nft_ct_helper_obj_type);
-#endif
 err2:
        nft_unregister_expr(&nft_notrack_type);
 err1:
@@ -1193,6 +1329,7 @@ static void __exit nft_ct_module_exit(void)
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
        nft_unregister_obj(&nft_ct_timeout_obj_type);
 #endif
+       nft_unregister_obj(&nft_ct_expect_obj_type);
        nft_unregister_obj(&nft_ct_helper_obj_type);
        nft_unregister_expr(&nft_notrack_type);
        nft_unregister_expr(&nft_ct_type);
@@ -1207,3 +1344,4 @@ MODULE_ALIAS_NFT_EXPR("ct");
 MODULE_ALIAS_NFT_EXPR("notrack");
 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER);
 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_TIMEOUT);
+MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_EXPECT);
index 505bdfc66801f122049ea8dfef572e4a3c320fed..33833a0cb989ca1b8519e848fb8b1908a313bbf2 100644 (file)
@@ -56,7 +56,7 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
        elem = nft_set_elem_init(set, &priv->tmpl,
                                 &regs->data[priv->sreg_key],
                                 &regs->data[priv->sreg_data],
-                                timeout, GFP_ATOMIC);
+                                timeout, 0, GFP_ATOMIC);
        if (elem == NULL)
                goto err1;
 
index c2d85bc2adb4335693d810431992f968c6a603e8..a5e8469859e395422728fe6fa37ff9284f3f4c7d 100644 (file)
@@ -59,6 +59,103 @@ err:
        regs->verdict.code = NFT_BREAK;
 }
 
+/* find the offset to specified option.
+ *
+ * If target header is found, its offset is set in *offset and return option
+ * number. Otherwise, return negative error.
+ *
+ * If the first fragment doesn't contain the End of Options it is considered
+ * invalid.
+ */
+static int ipv4_find_option(struct net *net, struct sk_buff *skb,
+                           unsigned int *offset, int target)
+{
+       unsigned char optbuf[sizeof(struct ip_options) + 40];
+       struct ip_options *opt = (struct ip_options *)optbuf;
+       struct iphdr *iph, _iph;
+       unsigned int start;
+       bool found = false;
+       __be32 info;
+       int optlen;
+
+       iph = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+       if (!iph)
+               return -EBADMSG;
+       start = sizeof(struct iphdr);
+
+       optlen = iph->ihl * 4 - (int)sizeof(struct iphdr);
+       if (optlen <= 0)
+               return -ENOENT;
+
+       memset(opt, 0, sizeof(struct ip_options));
+       /* Copy the options since __ip_options_compile() modifies
+        * the options.
+        */
+       if (skb_copy_bits(skb, start, opt->__data, optlen))
+               return -EBADMSG;
+       opt->optlen = optlen;
+
+       if (__ip_options_compile(net, opt, NULL, &info))
+               return -EBADMSG;
+
+       switch (target) {
+       case IPOPT_SSRR:
+       case IPOPT_LSRR:
+               if (!opt->srr)
+                       break;
+               found = target == IPOPT_SSRR ? opt->is_strictroute :
+                                              !opt->is_strictroute;
+               if (found)
+                       *offset = opt->srr + start;
+               break;
+       case IPOPT_RR:
+               if (!opt->rr)
+                       break;
+               *offset = opt->rr + start;
+               found = true;
+               break;
+       case IPOPT_RA:
+               if (!opt->router_alert)
+                       break;
+               *offset = opt->router_alert + start;
+               found = true;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return found ? target : -ENOENT;
+}
+
+static void nft_exthdr_ipv4_eval(const struct nft_expr *expr,
+                                struct nft_regs *regs,
+                                const struct nft_pktinfo *pkt)
+{
+       struct nft_exthdr *priv = nft_expr_priv(expr);
+       u32 *dest = &regs->data[priv->dreg];
+       struct sk_buff *skb = pkt->skb;
+       unsigned int offset;
+       int err;
+
+       if (skb->protocol != htons(ETH_P_IP))
+               goto err;
+
+       err = ipv4_find_option(nft_net(pkt), skb, &offset, priv->type);
+       if (priv->flags & NFT_EXTHDR_F_PRESENT) {
+               *dest = (err >= 0);
+               return;
+       } else if (err < 0) {
+               goto err;
+       }
+       offset += priv->offset;
+
+       dest[priv->len / NFT_REG32_SIZE] = 0;
+       if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
+               goto err;
+       return;
+err:
+       regs->verdict.code = NFT_BREAK;
+}
+
 static void *
 nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
                       unsigned int len, void *buffer, unsigned int *tcphdr_len)
@@ -312,6 +409,28 @@ static int nft_exthdr_tcp_set_init(const struct nft_ctx *ctx,
        return nft_validate_register_load(priv->sreg, priv->len);
 }
 
+static int nft_exthdr_ipv4_init(const struct nft_ctx *ctx,
+                               const struct nft_expr *expr,
+                               const struct nlattr * const tb[])
+{
+       struct nft_exthdr *priv = nft_expr_priv(expr);
+       int err = nft_exthdr_init(ctx, expr, tb);
+
+       if (err < 0)
+               return err;
+
+       switch (priv->type) {
+       case IPOPT_SSRR:
+       case IPOPT_LSRR:
+       case IPOPT_RR:
+       case IPOPT_RA:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
 static int nft_exthdr_dump_common(struct sk_buff *skb, const struct nft_exthdr *priv)
 {
        if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
@@ -358,6 +477,14 @@ static const struct nft_expr_ops nft_exthdr_ipv6_ops = {
        .dump           = nft_exthdr_dump,
 };
 
+static const struct nft_expr_ops nft_exthdr_ipv4_ops = {
+       .type           = &nft_exthdr_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
+       .eval           = nft_exthdr_ipv4_eval,
+       .init           = nft_exthdr_ipv4_init,
+       .dump           = nft_exthdr_dump,
+};
+
 static const struct nft_expr_ops nft_exthdr_tcp_ops = {
        .type           = &nft_exthdr_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
@@ -398,6 +525,12 @@ nft_exthdr_select_ops(const struct nft_ctx *ctx,
                if (tb[NFTA_EXTHDR_DREG])
                        return &nft_exthdr_ipv6_ops;
                break;
+       case NFT_EXTHDR_OP_IPV4:
+               if (ctx->family != NFPROTO_IPV6) {
+                       if (tb[NFTA_EXTHDR_DREG])
+                               return &nft_exthdr_ipv4_ops;
+               }
+               break;
        }
 
        return ERR_PTR(-EOPNOTSUPP);
index 140ce6be639af9a8b532a80c1a370b3c028c2695..0c9e014e30b494ca19363f244d5aa8290645fd12 100644 (file)
@@ -2,7 +2,7 @@
 /*
  *     xt_iprange - Netfilter module to match IP address ranges
  *
- *     (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *     (C) 2003 Jozsef Kadlecsik <kadlec@netfilter.org>
  *     (C) CC Computer Consultants GmbH, 2008
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -130,7 +130,7 @@ static void __exit iprange_mt_exit(void)
 module_init(iprange_mt_init);
 module_exit(iprange_mt_exit);
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching");
 MODULE_ALIAS("ipt_iprange");
index 7833cf4c67f95d1433ae4ebeb928a2e5629b1e7b..e85ce69924aee95d46ab597b1357ddd0d2c6c2b7 100644 (file)
@@ -22,6 +22,9 @@ static int owner_check(const struct xt_mtchk_param *par)
        struct xt_owner_match_info *info = par->matchinfo;
        struct net *net = par->net;
 
+       if (info->match & ~XT_OWNER_MASK)
+               return -EINVAL;
+
        /* Only allow the common case where the userns of the writer
         * matches the userns of the network namespace.
         */
index f099228cb9c43baa75c69db9be397d768c32c921..ecbfa291fb70bcacff496fd5ba9a43f5dd822ba3 100644 (file)
@@ -2,7 +2,7 @@
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
  *                         Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
  */
 
 /* Kernel module which implements the set match and SET target
@@ -18,7 +18,7 @@
 #include <uapi/linux/netfilter/xt_set.h>
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 MODULE_DESCRIPTION("Xtables: IP set match and target module");
 MODULE_ALIAS("xt_SET");
 MODULE_ALIAS("ipt_set");
@@ -436,6 +436,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 {
        const struct xt_set_info_target_v3 *info = par->targinfo;
        ip_set_id_t index;
+       int ret = 0;
 
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net,
@@ -453,17 +454,16 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
                if (index == IPSET_INVALID_ID) {
                        pr_info_ratelimited("Cannot find del_set index %u as target\n",
                                            info->del_set.index);
-                       if (info->add_set.index != IPSET_INVALID_ID)
-                               ip_set_nfnl_put(par->net,
-                                               info->add_set.index);
-                       return -ENOENT;
+                       ret = -ENOENT;
+                       goto cleanup_add;
                }
        }
 
        if (info->map_set.index != IPSET_INVALID_ID) {
                if (strncmp(par->table, "mangle", 7)) {
                        pr_info_ratelimited("--map-set only usable from mangle table\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto cleanup_del;
                }
                if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
                     (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
@@ -471,20 +471,16 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
                                         1 << NF_INET_LOCAL_OUT |
                                         1 << NF_INET_POST_ROUTING))) {
                        pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto cleanup_del;
                }
                index = ip_set_nfnl_get_byindex(par->net,
                                                info->map_set.index);
                if (index == IPSET_INVALID_ID) {
                        pr_info_ratelimited("Cannot find map_set index %u as target\n",
                                            info->map_set.index);
-                       if (info->add_set.index != IPSET_INVALID_ID)
-                               ip_set_nfnl_put(par->net,
-                                               info->add_set.index);
-                       if (info->del_set.index != IPSET_INVALID_ID)
-                               ip_set_nfnl_put(par->net,
-                                               info->del_set.index);
-                       return -ENOENT;
+                       ret = -ENOENT;
+                       goto cleanup_del;
                }
        }
 
@@ -492,16 +488,21 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
            info->del_set.dim > IPSET_DIM_MAX ||
            info->map_set.dim > IPSET_DIM_MAX) {
                pr_info_ratelimited("SET target dimension over the limit!\n");
-               if (info->add_set.index != IPSET_INVALID_ID)
-                       ip_set_nfnl_put(par->net, info->add_set.index);
-               if (info->del_set.index != IPSET_INVALID_ID)
-                       ip_set_nfnl_put(par->net, info->del_set.index);
-               if (info->map_set.index != IPSET_INVALID_ID)
-                       ip_set_nfnl_put(par->net, info->map_set.index);
-               return -ERANGE;
+               ret = -ERANGE;
+               goto cleanup_mark;
        }
 
        return 0;
+cleanup_mark:
+       if (info->map_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(par->net, info->map_set.index);
+cleanup_del:
+       if (info->del_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(par->net, info->del_set.index);
+cleanup_add:
+       if (info->add_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(par->net, info->add_set.index);
+       return ret;
 }
 
 static void