提交 9f0e896f 编写于 作者: D David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter/IPVS updates for net-next

The following patchset contains Netfilter/IPVS updates for your
net-next tree:

1) Free hooks via call_rcu to speed up netns release path, from
   Florian Westphal.

2) Reduce memory footprint of hook arrays, skip allocation if family is
   not present - useful in case decnet support is not compiled built-in.
   Patches from Florian Westphal.

3) Remove defensive check for malformed IPv4 - including ihl field - and
   IPv6 headers in x_tables and nf_tables.

4) Add generic flow table offload infrastructure for nf_tables, this
   includes the netlink control plane and support for IPv4, IPv6 and
   mixed IPv4/IPv6 dataplanes. This comes with NAT support too. This
   patchset adds the IPS_OFFLOAD conntrack status bit to indicate that
   this flow has been offloaded.

5) Add secpath matching support for nf_tables, from Florian.

6) Save some code bytes in the fast path for the nf_tables netdev,
   bridge and inet families.

7) Allow one single NAT hook per point and do not allow to register NAT
   hooks in nf_tables before the conntrack hook, patches from Florian.

8) Seven patches to remove the struct nf_af_info abstraction, instead
   we perform direct calls for IPv4 which is faster. IPv6 indirections
   are still needed to avoid dependencies with the 'ipv6' module, but
   these now reside in struct nf_ipv6_ops.

9) Seven patches to handle NFPROTO_INET from the Netfilter core,
   hence we can remove specific code in nf_tables to handle this
   pseudofamily.

10) No need for synchronize_net() call for nf_queue after conversion
    to hook arrays. Also from Florian.

11) Call cond_resched_rcu() when dumping large sets in ipset to avoid
    softlockup. Again from Florian.

12) Pass lockdep_nfnl_is_held() to rcu_dereference_protected(), patch
    from Florian Westphal.

13) Fix matching of counters in ipset, from Jozsef Kadlecsik.

14) Missing nfnl lock protection in the ip_set_net_exit path, also
    from Jozsef.

15) Move connlimit code that we can reuse from nf_tables into
    nf_conncount, from Florian Westhal.

And asorted cleanups:

16) Get rid of nft_dereference(), it only has one single caller.

17) Add nft_set_is_anonymous() helper function.

18) Remove NF_ARP_FORWARD leftover chain definition in nf_tables_arp.

19) Remove unnecessary comments in nf_conntrack_h323_asn1.c
    From Varsha Rao.

20) Remove useless parameters in frag_safe_skb_hp(), from Gao Feng.

21) Constify layer 4 conntrack protocol definitions, function
    parameters to register/unregister these protocol trackers, and
    timeouts. Patches from Florian Westphal.

22) Remove nlattr_size indirection, from Florian Westphal.

23) Add fall-through comments as -Wimplicit-fallthrough needs this,
    from Gustavo A. R. Silva.

24) Use swap() macro to exchange values in ipset, patch from
    Gustavo A. R. Silva.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -67,6 +67,7 @@ struct nf_hook_ops { ...@@ -67,6 +67,7 @@ struct nf_hook_ops {
struct net_device *dev; struct net_device *dev;
void *priv; void *priv;
u_int8_t pf; u_int8_t pf;
bool nat_hook;
unsigned int hooknum; unsigned int hooknum;
/* Hooks are ordered in ascending priority. */ /* Hooks are ordered in ascending priority. */
int priority; int priority;
...@@ -77,17 +78,28 @@ struct nf_hook_entry { ...@@ -77,17 +78,28 @@ struct nf_hook_entry {
void *priv; void *priv;
}; };
struct nf_hook_entries_rcu_head {
struct rcu_head head;
void *allocation;
};
struct nf_hook_entries { struct nf_hook_entries {
u16 num_hook_entries; u16 num_hook_entries;
/* padding */ /* padding */
struct nf_hook_entry hooks[]; struct nf_hook_entry hooks[];
/* trailer: pointers to original orig_ops of each hook. /* trailer: pointers to original orig_ops of each hook,
* * followed by rcu_head and scratch space used for freeing
* This is not part of struct nf_hook_entry since its only * the structure via call_rcu.
* needed in slow path (hook register/unregister).
* *
* This is not part of struct nf_hook_entry since its only
* needed in slow path (hook register/unregister):
* const struct nf_hook_ops *orig_ops[] * const struct nf_hook_ops *orig_ops[]
*
* For the same reason, we store this at end -- its
* only needed when a hook is deleted, not during
* packet path processing:
* struct nf_hook_entries_rcu_head head
*/ */
}; };
...@@ -184,7 +196,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net, ...@@ -184,7 +196,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
struct net_device *indev, struct net_device *outdev, struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct net *, struct sock *, struct sk_buff *)) int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{ {
struct nf_hook_entries *hook_head; struct nf_hook_entries *hook_head = NULL;
int ret = 1; int ret = 1;
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
...@@ -195,7 +207,33 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net, ...@@ -195,7 +207,33 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
#endif #endif
rcu_read_lock(); rcu_read_lock();
hook_head = rcu_dereference(net->nf.hooks[pf][hook]); switch (pf) {
case NFPROTO_IPV4:
hook_head = rcu_dereference(net->nf.hooks_ipv4[hook]);
break;
case NFPROTO_IPV6:
hook_head = rcu_dereference(net->nf.hooks_ipv6[hook]);
break;
case NFPROTO_ARP:
#ifdef CONFIG_NETFILTER_FAMILY_ARP
hook_head = rcu_dereference(net->nf.hooks_arp[hook]);
#endif
break;
case NFPROTO_BRIDGE:
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
hook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
#endif
break;
#if IS_ENABLED(CONFIG_DECNET)
case NFPROTO_DECNET:
hook_head = rcu_dereference(net->nf.hooks_decnet[hook]);
break;
#endif
default:
WARN_ON_ONCE(1);
break;
}
if (hook_head) { if (hook_head) {
struct nf_hook_state state; struct nf_hook_state state;
...@@ -271,64 +309,16 @@ int skb_make_writable(struct sk_buff *skb, unsigned int writable_len); ...@@ -271,64 +309,16 @@ int skb_make_writable(struct sk_buff *skb, unsigned int writable_len);
struct flowi; struct flowi;
struct nf_queue_entry; struct nf_queue_entry;
struct nf_afinfo { __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
unsigned short family; unsigned int dataoff, u_int8_t protocol,
__sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, unsigned short family);
unsigned int dataoff, u_int8_t protocol);
__sum16 (*checksum_partial)(struct sk_buff *skb,
unsigned int hook,
unsigned int dataoff,
unsigned int len,
u_int8_t protocol);
int (*route)(struct net *net, struct dst_entry **dst,
struct flowi *fl, bool strict);
void (*saveroute)(const struct sk_buff *skb,
struct nf_queue_entry *entry);
int (*reroute)(struct net *net, struct sk_buff *skb,
const struct nf_queue_entry *entry);
int route_key_size;
};
extern const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO];
static inline const struct nf_afinfo *nf_get_afinfo(unsigned short family)
{
return rcu_dereference(nf_afinfo[family]);
}
static inline __sum16
nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff,
u_int8_t protocol, unsigned short family)
{
const struct nf_afinfo *afinfo;
__sum16 csum = 0;
rcu_read_lock();
afinfo = nf_get_afinfo(family);
if (afinfo)
csum = afinfo->checksum(skb, hook, dataoff, protocol);
rcu_read_unlock();
return csum;
}
static inline __sum16
nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, unsigned int len,
u_int8_t protocol, unsigned short family)
{
const struct nf_afinfo *afinfo;
__sum16 csum = 0;
rcu_read_lock();
afinfo = nf_get_afinfo(family);
if (afinfo)
csum = afinfo->checksum_partial(skb, hook, dataoff, len,
protocol);
rcu_read_unlock();
return csum;
}
int nf_register_afinfo(const struct nf_afinfo *afinfo); __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
void nf_unregister_afinfo(const struct nf_afinfo *afinfo); unsigned int dataoff, unsigned int len,
u_int8_t protocol, unsigned short family);
int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
bool strict, unsigned short family);
int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry);
#include <net/flow.h> #include <net/flow.h>
extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
......
...@@ -122,6 +122,8 @@ struct ip_set_ext { ...@@ -122,6 +122,8 @@ struct ip_set_ext {
u64 bytes; u64 bytes;
char *comment; char *comment;
u32 timeout; u32 timeout;
u8 packets_op;
u8 bytes_op;
}; };
struct ip_set; struct ip_set;
...@@ -339,6 +341,10 @@ extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], ...@@ -339,6 +341,10 @@ extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext); struct ip_set_ext *ext);
extern int ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, extern int ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set,
const void *e, bool active); const void *e, bool active);
extern bool ip_set_match_extensions(struct ip_set *set,
const struct ip_set_ext *ext,
struct ip_set_ext *mext,
u32 flags, void *data);
static inline int static inline int
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
......
...@@ -34,20 +34,33 @@ ip_set_get_packets(const struct ip_set_counter *counter) ...@@ -34,20 +34,33 @@ ip_set_get_packets(const struct ip_set_counter *counter)
return (u64)atomic64_read(&(counter)->packets); return (u64)atomic64_read(&(counter)->packets);
} }
static inline bool
ip_set_match_counter(u64 counter, u64 match, u8 op)
{
switch (op) {
case IPSET_COUNTER_NONE:
return true;
case IPSET_COUNTER_EQ:
return counter == match;
case IPSET_COUNTER_NE:
return counter != match;
case IPSET_COUNTER_LT:
return counter < match;
case IPSET_COUNTER_GT:
return counter > match;
}
return false;
}
static inline void static inline void
ip_set_update_counter(struct ip_set_counter *counter, ip_set_update_counter(struct ip_set_counter *counter,
const struct ip_set_ext *ext, const struct ip_set_ext *ext, u32 flags)
struct ip_set_ext *mext, u32 flags)
{ {
if (ext->packets != ULLONG_MAX && if (ext->packets != ULLONG_MAX &&
!(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) { !(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) {
ip_set_add_bytes(ext->bytes, counter); ip_set_add_bytes(ext->bytes, counter);
ip_set_add_packets(ext->packets, counter); ip_set_add_packets(ext->packets, counter);
} }
if (flags & IPSET_FLAG_MATCH_COUNTERS) {
mext->packets = ip_set_get_packets(counter);
mext->bytes = ip_set_get_bytes(counter);
}
} }
static inline bool static inline bool
......
...@@ -320,6 +320,8 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target, ...@@ -320,6 +320,8 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target,
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name); const char *name);
struct xt_table *xt_request_find_table_lock(struct net *net, u_int8_t af,
const char *name);
void xt_table_unlock(struct xt_table *t); void xt_table_unlock(struct xt_table *t);
int xt_proto_init(struct net *net, u_int8_t af); int xt_proto_init(struct net *net, u_int8_t af);
......
...@@ -4,7 +4,17 @@ ...@@ -4,7 +4,17 @@
#include <uapi/linux/netfilter.h> #include <uapi/linux/netfilter.h>
/* in/out/forward only */
#define NF_ARP_NUMHOOKS 3
/* max hook is NF_DN_ROUTE (6), also see uapi/linux/netfilter_decnet.h */
#define NF_DN_NUMHOOKS 7
#if IS_ENABLED(CONFIG_DECNET)
/* Largest hook number + 1, see uapi/linux/netfilter_decnet.h */ /* Largest hook number + 1, see uapi/linux/netfilter_decnet.h */
#define NF_MAX_HOOKS 8 #define NF_MAX_HOOKS NF_DN_NUMHOOKS
#else
#define NF_MAX_HOOKS NF_INET_NUMHOOKS
#endif
#endif #endif
...@@ -6,7 +6,53 @@ ...@@ -6,7 +6,53 @@
#include <uapi/linux/netfilter_ipv4.h> #include <uapi/linux/netfilter_ipv4.h>
/* Extra routing may needed on local out, as the QUEUE target never returns
* control to the table.
*/
struct ip_rt_info {
__be32 daddr;
__be32 saddr;
u_int8_t tos;
u_int32_t mark;
};
int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned addr_type); int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned addr_type);
struct nf_queue_entry;
#ifdef CONFIG_INET
__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol); unsigned int dataoff, u_int8_t protocol);
__sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, unsigned int len,
u_int8_t protocol);
int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
bool strict);
int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry);
#else
static inline __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol)
{
return 0;
}
static inline __sum16 nf_ip_checksum_partial(struct sk_buff *skb,
unsigned int hook,
unsigned int dataoff,
unsigned int len,
u_int8_t protocol)
{
return 0;
}
static inline int nf_ip_route(struct net *net, struct dst_entry **dst,
struct flowi *fl, bool strict)
{
return -EOPNOTSUPP;
}
static inline int nf_ip_reroute(struct sk_buff *skb,
const struct nf_queue_entry *entry)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_INET */
#endif /*__LINUX_IP_NETFILTER_H*/ #endif /*__LINUX_IP_NETFILTER_H*/
...@@ -9,6 +9,17 @@ ...@@ -9,6 +9,17 @@
#include <uapi/linux/netfilter_ipv6.h> #include <uapi/linux/netfilter_ipv6.h>
/* Extra routing may needed on local out, as the QUEUE target never returns
* control to the table.
*/
struct ip6_rt_info {
struct in6_addr daddr;
struct in6_addr saddr;
u_int32_t mark;
};
struct nf_queue_entry;
/* /*
* Hook functions for ipv6 to allow xt_* modules to be built-in even * Hook functions for ipv6 to allow xt_* modules to be built-in even
* if IPv6 is a module. * if IPv6 is a module.
...@@ -19,6 +30,14 @@ struct nf_ipv6_ops { ...@@ -19,6 +30,14 @@ struct nf_ipv6_ops {
void (*route_input)(struct sk_buff *skb); void (*route_input)(struct sk_buff *skb);
int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb, int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb,
int (*output)(struct net *, struct sock *, struct sk_buff *)); int (*output)(struct net *, struct sock *, struct sk_buff *));
__sum16 (*checksum)(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol);
__sum16 (*checksum_partial)(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, unsigned int len,
u_int8_t protocol);
int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl,
bool strict);
int (*reroute)(struct sk_buff *skb, const struct nf_queue_entry *entry);
}; };
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
......
...@@ -69,8 +69,7 @@ struct ip_vs_iphdr { ...@@ -69,8 +69,7 @@ struct ip_vs_iphdr {
}; };
static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset, static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
int len, void *buffer, int len, void *buffer)
const struct ip_vs_iphdr *ipvsh)
{ {
return skb_header_pointer(skb, offset, len, buffer); return skb_header_pointer(skb, offset, len, buffer);
} }
......
...@@ -969,6 +969,8 @@ static inline struct sk_buff *ip6_finish_skb(struct sock *sk) ...@@ -969,6 +969,8 @@ static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
&inet6_sk(sk)->cork); &inet6_sk(sk)->cork);
} }
unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst);
int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
struct flowi6 *fl6); struct flowi6 *fl6);
struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6, struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
......
...@@ -13,17 +13,17 @@ ...@@ -13,17 +13,17 @@
const extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; const extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp;
#ifdef CONFIG_NF_CT_PROTO_DCCP #ifdef CONFIG_NF_CT_PROTO_DCCP
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4;
#endif #endif
#ifdef CONFIG_NF_CT_PROTO_SCTP #ifdef CONFIG_NF_CT_PROTO_SCTP
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4;
#endif #endif
#ifdef CONFIG_NF_CT_PROTO_UDPLITE #ifdef CONFIG_NF_CT_PROTO_UDPLITE
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4;
#endif #endif
int nf_conntrack_ipv4_compat_init(void); int nf_conntrack_ipv4_compat_init(void);
......
...@@ -4,17 +4,17 @@ ...@@ -4,17 +4,17 @@
extern const struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; extern const struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6;
#ifdef CONFIG_NF_CT_PROTO_DCCP #ifdef CONFIG_NF_CT_PROTO_DCCP
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6;
#endif #endif
#ifdef CONFIG_NF_CT_PROTO_SCTP #ifdef CONFIG_NF_CT_PROTO_SCTP
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6;
#endif #endif
#ifdef CONFIG_NF_CT_PROTO_UDPLITE #ifdef CONFIG_NF_CT_PROTO_UDPLITE
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6;
#endif #endif
#include <linux/sysctl.h> #include <linux/sysctl.h>
......
#ifndef _NF_CONNTRACK_COUNT_H
#define _NF_CONNTRACK_COUNT_H
struct nf_conncount_data;
struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family,
unsigned int keylen);
void nf_conncount_destroy(struct net *net, unsigned int family,
struct nf_conncount_data *data);
unsigned int nf_conncount_count(struct net *net,
struct nf_conncount_data *data,
const u32 *key,
unsigned int family,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone);
#endif
...@@ -27,6 +27,9 @@ struct nf_conntrack_l4proto { ...@@ -27,6 +27,9 @@ struct nf_conntrack_l4proto {
/* Resolve clashes on insertion races. */ /* Resolve clashes on insertion races. */
bool allow_clash; bool allow_clash;
/* protoinfo nlattr size, closes a hole */
u16 nlattr_size;
/* Try to fill in the third arg: dataoff is offset past network protocol /* Try to fill in the third arg: dataoff is offset past network protocol
hdr. Return true if possible. */ hdr. Return true if possible. */
bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff, bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff,
...@@ -66,8 +69,6 @@ struct nf_conntrack_l4proto { ...@@ -66,8 +69,6 @@ struct nf_conntrack_l4proto {
/* convert protoinfo to nfnetink attributes */ /* convert protoinfo to nfnetink attributes */
int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
struct nf_conn *ct); struct nf_conn *ct);
/* Calculate protoinfo nlattr size */
int (*nlattr_size)(void);
/* convert nfnetlink attributes to protoinfo */ /* convert nfnetlink attributes to protoinfo */
int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct);
...@@ -80,8 +81,6 @@ struct nf_conntrack_l4proto { ...@@ -80,8 +81,6 @@ struct nf_conntrack_l4proto {
struct nf_conntrack_tuple *t); struct nf_conntrack_tuple *t);
const struct nla_policy *nla_policy; const struct nla_policy *nla_policy;
size_t nla_size;
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
struct { struct {
int (*nlattr_to_obj)(struct nlattr *tb[], int (*nlattr_to_obj)(struct nlattr *tb[],
...@@ -109,7 +108,7 @@ struct nf_conntrack_l4proto { ...@@ -109,7 +108,7 @@ struct nf_conntrack_l4proto {
}; };
/* Existing built-in generic protocol */ /* Existing built-in generic protocol */
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
#define MAX_NF_CT_PROTO 256 #define MAX_NF_CT_PROTO 256
...@@ -126,18 +125,18 @@ int nf_ct_l4proto_pernet_register_one(struct net *net, ...@@ -126,18 +125,18 @@ int nf_ct_l4proto_pernet_register_one(struct net *net,
void nf_ct_l4proto_pernet_unregister_one(struct net *net, void nf_ct_l4proto_pernet_unregister_one(struct net *net,
const struct nf_conntrack_l4proto *proto); const struct nf_conntrack_l4proto *proto);
int nf_ct_l4proto_pernet_register(struct net *net, int nf_ct_l4proto_pernet_register(struct net *net,
struct nf_conntrack_l4proto *const proto[], const struct nf_conntrack_l4proto *const proto[],
unsigned int num_proto); unsigned int num_proto);
void nf_ct_l4proto_pernet_unregister(struct net *net, void nf_ct_l4proto_pernet_unregister(struct net *net,
struct nf_conntrack_l4proto *const proto[], const struct nf_conntrack_l4proto *const proto[],
unsigned int num_proto); unsigned int num_proto);
/* Protocol global registration. */ /* Protocol global registration. */
int nf_ct_l4proto_register_one(struct nf_conntrack_l4proto *proto); int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *proto);
void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *proto); void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *proto);
int nf_ct_l4proto_register(struct nf_conntrack_l4proto *proto[], int nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const proto[],
unsigned int num_proto); unsigned int num_proto);
void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *proto[], void nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const proto[],
unsigned int num_proto); unsigned int num_proto);
/* Generic netlink helpers */ /* Generic netlink helpers */
......
#ifndef _NF_FLOW_TABLE_H
#define _NF_FLOW_TABLE_H
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/rhashtable.h>
#include <linux/rcupdate.h>
#include <net/dst.h>
struct nf_flowtable;
struct nf_flowtable_type {
struct list_head list;
int family;
void (*gc)(struct work_struct *work);
const struct rhashtable_params *params;
nf_hookfn *hook;
struct module *owner;
};
struct nf_flowtable {
struct rhashtable rhashtable;
const struct nf_flowtable_type *type;
struct delayed_work gc_work;
};
enum flow_offload_tuple_dir {
FLOW_OFFLOAD_DIR_ORIGINAL,
FLOW_OFFLOAD_DIR_REPLY,
__FLOW_OFFLOAD_DIR_MAX = FLOW_OFFLOAD_DIR_REPLY,
};
#define FLOW_OFFLOAD_DIR_MAX (__FLOW_OFFLOAD_DIR_MAX + 1)
struct flow_offload_tuple {
union {
struct in_addr src_v4;
struct in6_addr src_v6;
};
union {
struct in_addr dst_v4;
struct in6_addr dst_v6;
};
struct {
__be16 src_port;
__be16 dst_port;
};
int iifidx;
u8 l3proto;
u8 l4proto;
u8 dir;
int oifidx;
struct dst_entry *dst_cache;
};
struct flow_offload_tuple_rhash {
struct rhash_head node;
struct flow_offload_tuple tuple;
};
#define FLOW_OFFLOAD_SNAT 0x1
#define FLOW_OFFLOAD_DNAT 0x2
#define FLOW_OFFLOAD_DYING 0x4
struct flow_offload {
struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
u32 flags;
union {
/* Your private driver data here. */
u32 timeout;
};
};
#define NF_FLOW_TIMEOUT (30 * HZ)
struct nf_flow_route {
struct {
struct dst_entry *dst;
int ifindex;
} tuple[FLOW_OFFLOAD_DIR_MAX];
};
struct flow_offload *flow_offload_alloc(struct nf_conn *ct,
struct nf_flow_route *route);
void flow_offload_free(struct flow_offload *flow);
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
void flow_offload_del(struct nf_flowtable *flow_table, struct flow_offload *flow);
struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
struct flow_offload_tuple *tuple);
int nf_flow_table_iterate(struct nf_flowtable *flow_table,
void (*iter)(struct flow_offload *flow, void *data),
void *data);
void nf_flow_offload_work_gc(struct work_struct *work);
extern const struct rhashtable_params nf_flow_offload_rhash_params;
void flow_offload_dead(struct flow_offload *flow);
int nf_flow_snat_port(const struct flow_offload *flow,
struct sk_buff *skb, unsigned int thoff,
u8 protocol, enum flow_offload_tuple_dir dir);
int nf_flow_dnat_port(const struct flow_offload *flow,
struct sk_buff *skb, unsigned int thoff,
u8 protocol, enum flow_offload_tuple_dir dir);
struct flow_ports {
__be16 source, dest;
};
unsigned int nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state);
unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state);
#define MODULE_ALIAS_NF_FLOWTABLE(family) \
MODULE_ALIAS("nf-flowtable-" __stringify(family))
#endif /* _FLOW_OFFLOAD_H */
...@@ -25,7 +25,7 @@ struct nf_queue_entry { ...@@ -25,7 +25,7 @@ struct nf_queue_entry {
struct nf_queue_handler { struct nf_queue_handler {
int (*outfn)(struct nf_queue_entry *entry, int (*outfn)(struct nf_queue_entry *entry,
unsigned int queuenum); unsigned int queuenum);
unsigned int (*nf_hook_drop)(struct net *net); void (*nf_hook_drop)(struct net *net);
}; };
void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh); void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <linux/u64_stats_sync.h> #include <linux/u64_stats_sync.h>
#include <net/netfilter/nf_flow_table.h>
#include <net/netlink.h> #include <net/netlink.h>
#define NFT_JUMP_STACK_SIZE 16 #define NFT_JUMP_STACK_SIZE 16
...@@ -54,8 +55,8 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt, ...@@ -54,8 +55,8 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
pkt->xt.state = state; pkt->xt.state = state;
} }
static inline void nft_set_pktinfo_proto_unspec(struct nft_pktinfo *pkt, static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt,
struct sk_buff *skb) struct sk_buff *skb)
{ {
pkt->tprot_set = false; pkt->tprot_set = false;
pkt->tprot = 0; pkt->tprot = 0;
...@@ -63,14 +64,6 @@ static inline void nft_set_pktinfo_proto_unspec(struct nft_pktinfo *pkt, ...@@ -63,14 +64,6 @@ static inline void nft_set_pktinfo_proto_unspec(struct nft_pktinfo *pkt,
pkt->xt.fragoff = 0; pkt->xt.fragoff = 0;
} }
static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
nft_set_pktinfo(pkt, skb, state);
nft_set_pktinfo_proto_unspec(pkt, skb);
}
/** /**
* struct nft_verdict - nf_tables verdict * struct nft_verdict - nf_tables verdict
* *
...@@ -424,6 +417,11 @@ struct nft_set { ...@@ -424,6 +417,11 @@ struct nft_set {
__attribute__((aligned(__alignof__(u64)))); __attribute__((aligned(__alignof__(u64))));
}; };
static inline bool nft_set_is_anonymous(const struct nft_set *set)
{
return set->flags & NFT_SET_ANONYMOUS;
}
static inline void *nft_set_priv(const struct nft_set *set) static inline void *nft_set_priv(const struct nft_set *set)
{ {
return (void *)set->data; return (void *)set->data;
...@@ -883,7 +881,7 @@ enum nft_chain_type { ...@@ -883,7 +881,7 @@ enum nft_chain_type {
* @family: address family * @family: address family
* @owner: module owner * @owner: module owner
* @hook_mask: mask of valid hooks * @hook_mask: mask of valid hooks
* @hooks: hookfn overrides * @hooks: array of hook functions
*/ */
struct nf_chain_type { struct nf_chain_type {
const char *name; const char *name;
...@@ -905,8 +903,6 @@ struct nft_stats { ...@@ -905,8 +903,6 @@ struct nft_stats {
struct u64_stats_sync syncp; struct u64_stats_sync syncp;
}; };
#define NFT_HOOK_OPS_MAX 2
/** /**
* struct nft_base_chain - nf_tables base chain * struct nft_base_chain - nf_tables base chain
* *
...@@ -918,7 +914,7 @@ struct nft_stats { ...@@ -918,7 +914,7 @@ struct nft_stats {
* @dev_name: device name that this base chain is attached to (if any) * @dev_name: device name that this base chain is attached to (if any)
*/ */
struct nft_base_chain { struct nft_base_chain {
struct nf_hook_ops ops[NFT_HOOK_OPS_MAX]; struct nf_hook_ops ops;
const struct nf_chain_type *type; const struct nf_chain_type *type;
u8 policy; u8 policy;
u8 flags; u8 flags;
...@@ -948,6 +944,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv); ...@@ -948,6 +944,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
* @chains: chains in the table * @chains: chains in the table
* @sets: sets in the table * @sets: sets in the table
* @objects: stateful objects in the table * @objects: stateful objects in the table
* @flowtables: flow tables in the table
* @hgenerator: handle generator state * @hgenerator: handle generator state
* @use: number of chain references to this table * @use: number of chain references to this table
* @flags: table flag (see enum nft_table_flags) * @flags: table flag (see enum nft_table_flags)
...@@ -959,6 +956,7 @@ struct nft_table { ...@@ -959,6 +956,7 @@ struct nft_table {
struct list_head chains; struct list_head chains;
struct list_head sets; struct list_head sets;
struct list_head objects; struct list_head objects;
struct list_head flowtables;
u64 hgenerator; u64 hgenerator;
u32 use; u32 use;
u16 flags:14, u16 flags:14,
...@@ -979,9 +977,6 @@ enum nft_af_flags { ...@@ -979,9 +977,6 @@ enum nft_af_flags {
* @owner: module owner * @owner: module owner
* @tables: used internally * @tables: used internally
* @flags: family flags * @flags: family flags
* @nops: number of hook ops in this family
* @hook_ops_init: initialization function for chain hook ops
* @hooks: hookfn overrides for packet validation
*/ */
struct nft_af_info { struct nft_af_info {
struct list_head list; struct list_head list;
...@@ -990,10 +985,6 @@ struct nft_af_info { ...@@ -990,10 +985,6 @@ struct nft_af_info {
struct module *owner; struct module *owner;
struct list_head tables; struct list_head tables;
u32 flags; u32 flags;
unsigned int nops;
void (*hook_ops_init)(struct nf_hook_ops *,
unsigned int);
nf_hookfn *hooks[NF_MAX_HOOKS];
}; };
int nft_register_afinfo(struct net *, struct nft_af_info *); int nft_register_afinfo(struct net *, struct nft_af_info *);
...@@ -1096,6 +1087,44 @@ struct nft_object_ops { ...@@ -1096,6 +1087,44 @@ struct nft_object_ops {
int nft_register_obj(struct nft_object_type *obj_type); int nft_register_obj(struct nft_object_type *obj_type);
void nft_unregister_obj(struct nft_object_type *obj_type); void nft_unregister_obj(struct nft_object_type *obj_type);
/**
* struct nft_flowtable - nf_tables flow table
*
* @list: flow table list node in table list
* @table: the table the flow table is contained in
* @name: name of this flow table
* @hooknum: hook number
* @priority: hook priority
* @ops_len: number of hooks in array
* @genmask: generation mask
* @use: number of references to this flow table
* @data: rhashtable and garbage collector
* @ops: array of hooks
*/
struct nft_flowtable {
struct list_head list;
struct nft_table *table;
char *name;
int hooknum;
int priority;
int ops_len;
u32 genmask:2,
use:30;
/* runtime data below here */
struct nf_hook_ops *ops ____cacheline_aligned;
struct nf_flowtable data;
};
struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
const struct nlattr *nla,
u8 genmask);
void nft_flow_table_iterate(struct net *net,
void (*iter)(struct nf_flowtable *flowtable, void *data),
void *data);
void nft_register_flowtable_type(struct nf_flowtable_type *type);
void nft_unregister_flowtable_type(struct nf_flowtable_type *type);
/** /**
* struct nft_traceinfo - nft tracing information and state * struct nft_traceinfo - nft tracing information and state
* *
...@@ -1125,9 +1154,6 @@ void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt, ...@@ -1125,9 +1154,6 @@ void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,
void nft_trace_notify(struct nft_traceinfo *info); void nft_trace_notify(struct nft_traceinfo *info);
#define nft_dereference(p) \
nfnl_dereference(p, NFNL_SUBSYS_NFTABLES)
#define MODULE_ALIAS_NFT_FAMILY(family) \ #define MODULE_ALIAS_NFT_FAMILY(family) \
MODULE_ALIAS("nft-afinfo-" __stringify(family)) MODULE_ALIAS("nft-afinfo-" __stringify(family))
...@@ -1332,4 +1358,11 @@ struct nft_trans_obj { ...@@ -1332,4 +1358,11 @@ struct nft_trans_obj {
#define nft_trans_obj(trans) \ #define nft_trans_obj(trans) \
(((struct nft_trans_obj *)trans->data)->obj) (((struct nft_trans_obj *)trans->data)->obj)
struct nft_trans_flowtable {
struct nft_flowtable *flowtable;
};
#define nft_trans_flowtable(trans) \
(((struct nft_trans_flowtable *)trans->data)->flowtable)
#endif /* _NET_NF_TABLES_H */ #endif /* _NET_NF_TABLES_H */
...@@ -5,15 +5,11 @@ ...@@ -5,15 +5,11 @@
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <net/ip.h> #include <net/ip.h>
static inline void static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt, struct sk_buff *skb)
struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
struct iphdr *ip; struct iphdr *ip;
nft_set_pktinfo(pkt, skb, state);
ip = ip_hdr(pkt->skb); ip = ip_hdr(pkt->skb);
pkt->tprot_set = true; pkt->tprot_set = true;
pkt->tprot = ip->protocol; pkt->tprot = ip->protocol;
...@@ -21,10 +17,8 @@ nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt, ...@@ -21,10 +17,8 @@ nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET; pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
} }
static inline int static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
__nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt, struct sk_buff *skb)
struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
struct iphdr *iph, _iph; struct iphdr *iph, _iph;
u32 len, thoff; u32 len, thoff;
...@@ -52,16 +46,11 @@ __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt, ...@@ -52,16 +46,11 @@ __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
return 0; return 0;
} }
static inline void static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt, struct sk_buff *skb)
struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
nft_set_pktinfo(pkt, skb, state); if (__nft_set_pktinfo_ipv4_validate(pkt, skb) < 0)
if (__nft_set_pktinfo_ipv4_validate(pkt, skb, state) < 0) nft_set_pktinfo_unspec(pkt, skb);
nft_set_pktinfo_proto_unspec(pkt, skb);
} }
extern struct nft_af_info nft_af_ipv4;
#endif #endif
...@@ -5,20 +5,16 @@ ...@@ -5,20 +5,16 @@
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ipv6.h> #include <net/ipv6.h>
static inline void static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt, struct sk_buff *skb)
struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
unsigned int flags = IP6_FH_F_AUTH; unsigned int flags = IP6_FH_F_AUTH;
int protohdr, thoff = 0; int protohdr, thoff = 0;
unsigned short frag_off; unsigned short frag_off;
nft_set_pktinfo(pkt, skb, state);
protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags); protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags);
if (protohdr < 0) { if (protohdr < 0) {
nft_set_pktinfo_proto_unspec(pkt, skb); nft_set_pktinfo_unspec(pkt, skb);
return; return;
} }
...@@ -28,10 +24,8 @@ nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt, ...@@ -28,10 +24,8 @@ nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
pkt->xt.fragoff = frag_off; pkt->xt.fragoff = frag_off;
} }
static inline int static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
__nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt, struct sk_buff *skb)
struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
unsigned int flags = IP6_FH_F_AUTH; unsigned int flags = IP6_FH_F_AUTH;
...@@ -68,16 +62,11 @@ __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt, ...@@ -68,16 +62,11 @@ __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
#endif #endif
} }
static inline void static inline void nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt, struct sk_buff *skb)
struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
nft_set_pktinfo(pkt, skb, state); if (__nft_set_pktinfo_ipv6_validate(pkt, skb) < 0)
if (__nft_set_pktinfo_ipv6_validate(pkt, skb, state) < 0) nft_set_pktinfo_unspec(pkt, skb);
nft_set_pktinfo_proto_unspec(pkt, skb);
} }
extern struct nft_af_info nft_af_ipv6;
#endif #endif
...@@ -17,7 +17,17 @@ struct netns_nf { ...@@ -17,7 +17,17 @@ struct netns_nf {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
struct ctl_table_header *nf_log_dir_header; struct ctl_table_header *nf_log_dir_header;
#endif #endif
struct nf_hook_entries __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; struct nf_hook_entries __rcu *hooks_ipv4[NF_INET_NUMHOOKS];
struct nf_hook_entries __rcu *hooks_ipv6[NF_INET_NUMHOOKS];
#ifdef CONFIG_NETFILTER_FAMILY_ARP
struct nf_hook_entries __rcu *hooks_arp[NF_ARP_NUMHOOKS];
#endif
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
struct nf_hook_entries __rcu *hooks_bridge[NF_INET_NUMHOOKS];
#endif
#if IS_ENABLED(CONFIG_DECNET)
struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS];
#endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
bool defrag_ipv4; bool defrag_ipv4;
#endif #endif
......
...@@ -101,12 +101,16 @@ enum ip_conntrack_status { ...@@ -101,12 +101,16 @@ enum ip_conntrack_status {
IPS_HELPER_BIT = 13, IPS_HELPER_BIT = 13,
IPS_HELPER = (1 << IPS_HELPER_BIT), IPS_HELPER = (1 << IPS_HELPER_BIT),
/* Conntrack has been offloaded to flow table. */
IPS_OFFLOAD_BIT = 14,
IPS_OFFLOAD = (1 << IPS_OFFLOAD_BIT),
/* Be careful here, modifying these bits can make things messy, /* Be careful here, modifying these bits can make things messy,
* so don't let users modify them directly. * so don't let users modify them directly.
*/ */
IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK | IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING | IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
IPS_SEQ_ADJUST | IPS_TEMPLATE), IPS_SEQ_ADJUST | IPS_TEMPLATE | IPS_OFFLOAD),
__IPS_MAX_BIT = 14, __IPS_MAX_BIT = 14,
}; };
......
...@@ -92,6 +92,9 @@ enum nft_verdicts { ...@@ -92,6 +92,9 @@ enum nft_verdicts {
* @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes) * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
* @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes) * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
* @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes) * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
* @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
* @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
* @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
*/ */
enum nf_tables_msg_types { enum nf_tables_msg_types {
NFT_MSG_NEWTABLE, NFT_MSG_NEWTABLE,
...@@ -116,6 +119,9 @@ enum nf_tables_msg_types { ...@@ -116,6 +119,9 @@ enum nf_tables_msg_types {
NFT_MSG_GETOBJ, NFT_MSG_GETOBJ,
NFT_MSG_DELOBJ, NFT_MSG_DELOBJ,
NFT_MSG_GETOBJ_RESET, NFT_MSG_GETOBJ_RESET,
NFT_MSG_NEWFLOWTABLE,
NFT_MSG_GETFLOWTABLE,
NFT_MSG_DELFLOWTABLE,
NFT_MSG_MAX, NFT_MSG_MAX,
}; };
...@@ -777,6 +783,7 @@ enum nft_exthdr_attributes { ...@@ -777,6 +783,7 @@ enum nft_exthdr_attributes {
* @NFT_META_OIFGROUP: packet output interface group * @NFT_META_OIFGROUP: packet output interface group
* @NFT_META_CGROUP: socket control group (skb->sk->sk_classid) * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid)
* @NFT_META_PRANDOM: a 32bit pseudo-random number * @NFT_META_PRANDOM: a 32bit pseudo-random number
* @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp)
*/ */
enum nft_meta_keys { enum nft_meta_keys {
NFT_META_LEN, NFT_META_LEN,
...@@ -804,6 +811,7 @@ enum nft_meta_keys { ...@@ -804,6 +811,7 @@ enum nft_meta_keys {
NFT_META_OIFGROUP, NFT_META_OIFGROUP,
NFT_META_CGROUP, NFT_META_CGROUP,
NFT_META_PRANDOM, NFT_META_PRANDOM,
NFT_META_SECPATH,
}; };
/** /**
...@@ -949,6 +957,17 @@ enum nft_ct_attributes { ...@@ -949,6 +957,17 @@ enum nft_ct_attributes {
}; };
#define NFTA_CT_MAX (__NFTA_CT_MAX - 1) #define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
/**
* enum nft_flow_attributes - ct offload expression attributes
* @NFTA_FLOW_TABLE_NAME: flow table name (NLA_STRING)
*/
enum nft_offload_attributes {
NFTA_FLOW_UNSPEC,
NFTA_FLOW_TABLE_NAME,
__NFTA_FLOW_MAX,
};
#define NFTA_FLOW_MAX (__NFTA_FLOW_MAX - 1)
enum nft_limit_type { enum nft_limit_type {
NFT_LIMIT_PKTS, NFT_LIMIT_PKTS,
NFT_LIMIT_PKT_BYTES NFT_LIMIT_PKT_BYTES
...@@ -1307,6 +1326,53 @@ enum nft_object_attributes { ...@@ -1307,6 +1326,53 @@ enum nft_object_attributes {
}; };
#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1) #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
/**
* enum nft_flowtable_attributes - nf_tables flow table netlink attributes
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
* @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
*/
enum nft_flowtable_attributes {
NFTA_FLOWTABLE_UNSPEC,
NFTA_FLOWTABLE_TABLE,
NFTA_FLOWTABLE_NAME,
NFTA_FLOWTABLE_HOOK,
NFTA_FLOWTABLE_USE,
__NFTA_FLOWTABLE_MAX
};
#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
/**
* enum nft_flowtable_hook_attributes - nf_tables flow table hook netlink attributes
*
* @NFTA_FLOWTABLE_HOOK_NUM: netfilter hook number (NLA_U32)
* @NFTA_FLOWTABLE_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
* @NFTA_FLOWTABLE_HOOK_DEVS: input devices this flow table is bound to (NLA_NESTED)
*/
enum nft_flowtable_hook_attributes {
NFTA_FLOWTABLE_HOOK_UNSPEC,
NFTA_FLOWTABLE_HOOK_NUM,
NFTA_FLOWTABLE_HOOK_PRIORITY,
NFTA_FLOWTABLE_HOOK_DEVS,
__NFTA_FLOWTABLE_HOOK_MAX
};
#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1)
/**
* enum nft_device_attributes - nf_tables device netlink attributes
*
* @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
*/
enum nft_devices_attributes {
NFTA_DEVICE_UNSPEC,
NFTA_DEVICE_NAME,
__NFTA_DEVICE_MAX
};
#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
/** /**
* enum nft_trace_attributes - nf_tables trace netlink attributes * enum nft_trace_attributes - nf_tables trace netlink attributes
* *
......
...@@ -27,7 +27,7 @@ struct xt_connlimit_info { ...@@ -27,7 +27,7 @@ struct xt_connlimit_info {
__u32 flags; __u32 flags;
/* Used internally by the kernel */ /* Used internally by the kernel */
struct xt_connlimit_data *data __attribute__((aligned(8))); struct nf_conncount_data *data __attribute__((aligned(8)));
}; };
#endif /* _XT_CONNLIMIT_H */ #endif /* _XT_CONNLIMIT_H */
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#define NF_ARP_IN 0 #define NF_ARP_IN 0
#define NF_ARP_OUT 1 #define NF_ARP_OUT 1
#define NF_ARP_FORWARD 2 #define NF_ARP_FORWARD 2
#ifndef __KERNEL__
#define NF_ARP_NUMHOOKS 3 #define NF_ARP_NUMHOOKS 3
#endif
#endif /* __LINUX_ARP_NETFILTER_H */ #endif /* __LINUX_ARP_NETFILTER_H */
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
#define NFC_DN_IF_IN 0x0004 #define NFC_DN_IF_IN 0x0004
/* Output device. */ /* Output device. */
#define NFC_DN_IF_OUT 0x0008 #define NFC_DN_IF_OUT 0x0008
/* kernel define is in netfilter_defs.h */
#define NF_DN_NUMHOOKS 7
#endif /* ! __KERNEL__ */ #endif /* ! __KERNEL__ */
/* DECnet Hooks */ /* DECnet Hooks */
...@@ -41,7 +44,6 @@ ...@@ -41,7 +44,6 @@
#define NF_DN_HELLO 5 #define NF_DN_HELLO 5
/* Input Routing Packets */ /* Input Routing Packets */
#define NF_DN_ROUTE 6 #define NF_DN_ROUTE 6
#define NF_DN_NUMHOOKS 7
enum nf_dn_hook_priorities { enum nf_dn_hook_priorities {
NF_DN_PRI_FIRST = INT_MIN, NF_DN_PRI_FIRST = INT_MIN,
......
...@@ -182,6 +182,7 @@ config BRIDGE_NETFILTER ...@@ -182,6 +182,7 @@ config BRIDGE_NETFILTER
depends on BRIDGE depends on BRIDGE
depends on NETFILTER && INET depends on NETFILTER && INET
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
select NETFILTER_FAMILY_BRIDGE
default m default m
---help--- ---help---
Enabling this option will let arptables resp. iptables see bridged Enabling this option will let arptables resp. iptables see bridged
......
...@@ -991,7 +991,7 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net, ...@@ -991,7 +991,7 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net,
unsigned int i; unsigned int i;
int ret; int ret;
e = rcu_dereference(net->nf.hooks[NFPROTO_BRIDGE][hook]); e = rcu_dereference(net->nf.hooks_bridge[hook]);
if (!e) if (!e)
return okfn(net, sk, skb); return okfn(net, sk, skb);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# #
menuconfig NF_TABLES_BRIDGE menuconfig NF_TABLES_BRIDGE
depends on BRIDGE && NETFILTER && NF_TABLES depends on BRIDGE && NETFILTER && NF_TABLES
select NETFILTER_FAMILY_BRIDGE
tristate "Ethernet Bridge nf_tables support" tristate "Ethernet Bridge nf_tables support"
if NF_TABLES_BRIDGE if NF_TABLES_BRIDGE
...@@ -29,6 +30,7 @@ endif # NF_TABLES_BRIDGE ...@@ -29,6 +30,7 @@ endif # NF_TABLES_BRIDGE
menuconfig BRIDGE_NF_EBTABLES menuconfig BRIDGE_NF_EBTABLES
tristate "Ethernet Bridge tables (ebtables) support" tristate "Ethernet Bridge tables (ebtables) support"
depends on BRIDGE && NETFILTER && NETFILTER_XTABLES depends on BRIDGE && NETFILTER && NETFILTER_XTABLES
select NETFILTER_FAMILY_BRIDGE
help help
ebtables is a general, extensible frame/packet identification ebtables is a general, extensible frame/packet identification
framework. Say 'Y' or 'M' here if you want to do Ethernet framework. Say 'Y' or 'M' here if you want to do Ethernet
......
...@@ -25,15 +25,17 @@ nft_do_chain_bridge(void *priv, ...@@ -25,15 +25,17 @@ nft_do_chain_bridge(void *priv,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo(&pkt, skb, state);
switch (eth_hdr(skb)->h_proto) { switch (eth_hdr(skb)->h_proto) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
nft_set_pktinfo_ipv4_validate(&pkt, skb, state); nft_set_pktinfo_ipv4_validate(&pkt, skb);
break; break;
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
nft_set_pktinfo_ipv6_validate(&pkt, skb, state); nft_set_pktinfo_ipv6_validate(&pkt, skb);
break; break;
default: default:
nft_set_pktinfo_unspec(&pkt, skb, state); nft_set_pktinfo_unspec(&pkt, skb);
break; break;
} }
...@@ -44,14 +46,6 @@ static struct nft_af_info nft_af_bridge __read_mostly = { ...@@ -44,14 +46,6 @@ static struct nft_af_info nft_af_bridge __read_mostly = {
.family = NFPROTO_BRIDGE, .family = NFPROTO_BRIDGE,
.nhooks = NF_BR_NUMHOOKS, .nhooks = NF_BR_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = {
[NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
[NF_BR_LOCAL_IN] = nft_do_chain_bridge,
[NF_BR_FORWARD] = nft_do_chain_bridge,
[NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
[NF_BR_POST_ROUTING] = nft_do_chain_bridge,
},
}; };
static int nf_tables_bridge_init_net(struct net *net) static int nf_tables_bridge_init_net(struct net *net)
...@@ -92,67 +86,32 @@ static const struct nf_chain_type filter_bridge = { ...@@ -92,67 +86,32 @@ static const struct nf_chain_type filter_bridge = {
(1 << NF_BR_FORWARD) | (1 << NF_BR_FORWARD) |
(1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_LOCAL_OUT) |
(1 << NF_BR_POST_ROUTING), (1 << NF_BR_POST_ROUTING),
}; .hooks = {
[NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
static void nf_br_saveroute(const struct sk_buff *skb, [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
struct nf_queue_entry *entry) [NF_BR_FORWARD] = nft_do_chain_bridge,
{ [NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
} [NF_BR_POST_ROUTING] = nft_do_chain_bridge,
},
static int nf_br_reroute(struct net *net, struct sk_buff *skb,
const struct nf_queue_entry *entry)
{
return 0;
}
static __sum16 nf_br_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol)
{
return 0;
}
static __sum16 nf_br_checksum_partial(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, unsigned int len,
u_int8_t protocol)
{
return 0;
}
static int nf_br_route(struct net *net, struct dst_entry **dst,
struct flowi *fl, bool strict __always_unused)
{
return 0;
}
static const struct nf_afinfo nf_br_afinfo = {
.family = AF_BRIDGE,
.checksum = nf_br_checksum,
.checksum_partial = nf_br_checksum_partial,
.route = nf_br_route,
.saveroute = nf_br_saveroute,
.reroute = nf_br_reroute,
.route_key_size = 0,
}; };
static int __init nf_tables_bridge_init(void) static int __init nf_tables_bridge_init(void)
{ {
int ret; int ret;
nf_register_afinfo(&nf_br_afinfo);
ret = nft_register_chain_type(&filter_bridge); ret = nft_register_chain_type(&filter_bridge);
if (ret < 0) if (ret < 0)
goto err1; return ret;
ret = register_pernet_subsys(&nf_tables_bridge_net_ops); ret = register_pernet_subsys(&nf_tables_bridge_net_ops);
if (ret < 0) if (ret < 0)
goto err2; goto err_register_subsys;
return ret; return ret;
err2: err_register_subsys:
nft_unregister_chain_type(&filter_bridge); nft_unregister_chain_type(&filter_bridge);
err1:
nf_unregister_afinfo(&nf_br_afinfo);
return ret; return ret;
} }
...@@ -160,7 +119,6 @@ static void __exit nf_tables_bridge_exit(void) ...@@ -160,7 +119,6 @@ static void __exit nf_tables_bridge_exit(void)
{ {
unregister_pernet_subsys(&nf_tables_bridge_net_ops); unregister_pernet_subsys(&nf_tables_bridge_net_ops);
nft_unregister_chain_type(&filter_bridge); nft_unregister_chain_type(&filter_bridge);
nf_unregister_afinfo(&nf_br_afinfo);
} }
module_init(nf_tables_bridge_init); module_init(nf_tables_bridge_init);
......
...@@ -80,35 +80,7 @@ int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned int addr_t ...@@ -80,35 +80,7 @@ int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned int addr_t
} }
EXPORT_SYMBOL(ip_route_me_harder); EXPORT_SYMBOL(ip_route_me_harder);
/* int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry)
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
*/
struct ip_rt_info {
__be32 daddr;
__be32 saddr;
u_int8_t tos;
u_int32_t mark;
};
static void nf_ip_saveroute(const struct sk_buff *skb,
struct nf_queue_entry *entry)
{
struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
if (entry->state.hook == NF_INET_LOCAL_OUT) {
const struct iphdr *iph = ip_hdr(skb);
rt_info->tos = iph->tos;
rt_info->daddr = iph->daddr;
rt_info->saddr = iph->saddr;
rt_info->mark = skb->mark;
}
}
static int nf_ip_reroute(struct net *net, struct sk_buff *skb,
const struct nf_queue_entry *entry)
{ {
const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
...@@ -119,10 +91,12 @@ static int nf_ip_reroute(struct net *net, struct sk_buff *skb, ...@@ -119,10 +91,12 @@ static int nf_ip_reroute(struct net *net, struct sk_buff *skb,
skb->mark == rt_info->mark && skb->mark == rt_info->mark &&
iph->daddr == rt_info->daddr && iph->daddr == rt_info->daddr &&
iph->saddr == rt_info->saddr)) iph->saddr == rt_info->saddr))
return ip_route_me_harder(net, skb, RTN_UNSPEC); return ip_route_me_harder(entry->state.net, skb,
RTN_UNSPEC);
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nf_ip_reroute);
__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol) unsigned int dataoff, u_int8_t protocol)
...@@ -155,9 +129,9 @@ __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, ...@@ -155,9 +129,9 @@ __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
} }
EXPORT_SYMBOL(nf_ip_checksum); EXPORT_SYMBOL(nf_ip_checksum);
static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, unsigned int len, unsigned int dataoff, unsigned int len,
u_int8_t protocol) u_int8_t protocol)
{ {
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
__sum16 csum = 0; __sum16 csum = 0;
...@@ -175,9 +149,10 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, ...@@ -175,9 +149,10 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
} }
return csum; return csum;
} }
EXPORT_SYMBOL_GPL(nf_ip_checksum_partial);
static int nf_ip_route(struct net *net, struct dst_entry **dst, int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
struct flowi *fl, bool strict __always_unused) bool strict __always_unused)
{ {
struct rtable *rt = ip_route_output_key(net, &fl->u.ip4); struct rtable *rt = ip_route_output_key(net, &fl->u.ip4);
if (IS_ERR(rt)) if (IS_ERR(rt))
...@@ -185,19 +160,4 @@ static int nf_ip_route(struct net *net, struct dst_entry **dst, ...@@ -185,19 +160,4 @@ static int nf_ip_route(struct net *net, struct dst_entry **dst,
*dst = &rt->dst; *dst = &rt->dst;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nf_ip_route);
static const struct nf_afinfo nf_ip_afinfo = {
.family = AF_INET,
.checksum = nf_ip_checksum,
.checksum_partial = nf_ip_checksum_partial,
.route = nf_ip_route,
.saveroute = nf_ip_saveroute,
.reroute = nf_ip_reroute,
.route_key_size = sizeof(struct ip_rt_info),
};
static int __init ipv4_netfilter_init(void)
{
return nf_register_afinfo(&nf_ip_afinfo);
}
subsys_initcall(ipv4_netfilter_init);
...@@ -72,11 +72,20 @@ endif # NF_TABLES_IPV4 ...@@ -72,11 +72,20 @@ endif # NF_TABLES_IPV4
config NF_TABLES_ARP config NF_TABLES_ARP
tristate "ARP nf_tables support" tristate "ARP nf_tables support"
select NETFILTER_FAMILY_ARP
help help
This option enables the ARP support for nf_tables. This option enables the ARP support for nf_tables.
endif # NF_TABLES endif # NF_TABLES
config NF_FLOW_TABLE_IPV4
select NF_FLOW_TABLE
tristate "Netfilter flow table IPv4 module"
help
This option adds the flow table IPv4 support.
To compile it as a module, choose M here.
config NF_DUP_IPV4 config NF_DUP_IPV4
tristate "Netfilter IPv4 packet duplication to alternate destination" tristate "Netfilter IPv4 packet duplication to alternate destination"
depends on !NF_CONNTRACK || NF_CONNTRACK depends on !NF_CONNTRACK || NF_CONNTRACK
...@@ -392,6 +401,7 @@ endif # IP_NF_IPTABLES ...@@ -392,6 +401,7 @@ endif # IP_NF_IPTABLES
config IP_NF_ARPTABLES config IP_NF_ARPTABLES
tristate "ARP tables support" tristate "ARP tables support"
select NETFILTER_XTABLES select NETFILTER_XTABLES
select NETFILTER_FAMILY_ARP
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
help help
arptables is a general, extensible packet identification framework. arptables is a general, extensible packet identification framework.
......
...@@ -43,6 +43,9 @@ obj-$(CONFIG_NFT_REDIR_IPV4) += nft_redir_ipv4.o ...@@ -43,6 +43,9 @@ obj-$(CONFIG_NFT_REDIR_IPV4) += nft_redir_ipv4.o
obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o
obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
# flow table support
obj-$(CONFIG_NF_FLOW_TABLE_IPV4) += nf_flow_table_ipv4.o
# generic IP tables # generic IP tables
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
......
...@@ -810,9 +810,8 @@ static int get_info(struct net *net, void __user *user, ...@@ -810,9 +810,8 @@ static int get_info(struct net *net, void __user *user,
if (compat) if (compat)
xt_compat_lock(NFPROTO_ARP); xt_compat_lock(NFPROTO_ARP);
#endif #endif
t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name), t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
"arptable_%s", name); if (!IS_ERR(t)) {
if (t) {
struct arpt_getinfo info; struct arpt_getinfo info;
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -841,7 +840,7 @@ static int get_info(struct net *net, void __user *user, ...@@ -841,7 +840,7 @@ static int get_info(struct net *net, void __user *user,
xt_table_unlock(t); xt_table_unlock(t);
module_put(t->me); module_put(t->me);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
if (compat) if (compat)
xt_compat_unlock(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP);
...@@ -866,7 +865,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, ...@@ -866,7 +865,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
get.name[sizeof(get.name) - 1] = '\0'; get.name[sizeof(get.name) - 1] = '\0';
t = xt_find_table_lock(net, NFPROTO_ARP, get.name); t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
if (t) { if (!IS_ERR(t)) {
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
if (get.size == private->size) if (get.size == private->size)
...@@ -878,7 +877,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, ...@@ -878,7 +877,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
return ret; return ret;
} }
...@@ -903,10 +902,9 @@ static int __do_replace(struct net *net, const char *name, ...@@ -903,10 +902,9 @@ static int __do_replace(struct net *net, const char *name,
goto out; goto out;
} }
t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name), t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
"arptable_%s", name); if (IS_ERR(t)) {
if (!t) { ret = PTR_ERR(t);
ret = -ENOENT;
goto free_newinfo_counters_untrans; goto free_newinfo_counters_untrans;
} }
...@@ -1020,8 +1018,8 @@ static int do_add_counters(struct net *net, const void __user *user, ...@@ -1020,8 +1018,8 @@ static int do_add_counters(struct net *net, const void __user *user,
return PTR_ERR(paddc); return PTR_ERR(paddc);
t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name); t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name);
if (!t) { if (IS_ERR(t)) {
ret = -ENOENT; ret = PTR_ERR(t);
goto free; goto free;
} }
...@@ -1408,7 +1406,7 @@ static int compat_get_entries(struct net *net, ...@@ -1408,7 +1406,7 @@ static int compat_get_entries(struct net *net,
xt_compat_lock(NFPROTO_ARP); xt_compat_lock(NFPROTO_ARP);
t = xt_find_table_lock(net, NFPROTO_ARP, get.name); t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
if (t) { if (!IS_ERR(t)) {
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
struct xt_table_info info; struct xt_table_info info;
...@@ -1423,7 +1421,7 @@ static int compat_get_entries(struct net *net, ...@@ -1423,7 +1421,7 @@ static int compat_get_entries(struct net *net,
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
xt_compat_unlock(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP);
return ret; return ret;
......
...@@ -973,9 +973,8 @@ static int get_info(struct net *net, void __user *user, ...@@ -973,9 +973,8 @@ static int get_info(struct net *net, void __user *user,
if (compat) if (compat)
xt_compat_lock(AF_INET); xt_compat_lock(AF_INET);
#endif #endif
t = try_then_request_module(xt_find_table_lock(net, AF_INET, name), t = xt_request_find_table_lock(net, AF_INET, name);
"iptable_%s", name); if (!IS_ERR(t)) {
if (t) {
struct ipt_getinfo info; struct ipt_getinfo info;
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -1005,7 +1004,7 @@ static int get_info(struct net *net, void __user *user, ...@@ -1005,7 +1004,7 @@ static int get_info(struct net *net, void __user *user,
xt_table_unlock(t); xt_table_unlock(t);
module_put(t->me); module_put(t->me);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
if (compat) if (compat)
xt_compat_unlock(AF_INET); xt_compat_unlock(AF_INET);
...@@ -1030,7 +1029,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, ...@@ -1030,7 +1029,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr,
get.name[sizeof(get.name) - 1] = '\0'; get.name[sizeof(get.name) - 1] = '\0';
t = xt_find_table_lock(net, AF_INET, get.name); t = xt_find_table_lock(net, AF_INET, get.name);
if (t) { if (!IS_ERR(t)) {
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
if (get.size == private->size) if (get.size == private->size)
ret = copy_entries_to_user(private->size, ret = copy_entries_to_user(private->size,
...@@ -1041,7 +1040,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, ...@@ -1041,7 +1040,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr,
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
return ret; return ret;
} }
...@@ -1064,10 +1063,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, ...@@ -1064,10 +1063,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
goto out; goto out;
} }
t = try_then_request_module(xt_find_table_lock(net, AF_INET, name), t = xt_request_find_table_lock(net, AF_INET, name);
"iptable_%s", name); if (IS_ERR(t)) {
if (!t) { ret = PTR_ERR(t);
ret = -ENOENT;
goto free_newinfo_counters_untrans; goto free_newinfo_counters_untrans;
} }
...@@ -1181,8 +1179,8 @@ do_add_counters(struct net *net, const void __user *user, ...@@ -1181,8 +1179,8 @@ do_add_counters(struct net *net, const void __user *user,
return PTR_ERR(paddc); return PTR_ERR(paddc);
t = xt_find_table_lock(net, AF_INET, tmp.name); t = xt_find_table_lock(net, AF_INET, tmp.name);
if (!t) { if (IS_ERR(t)) {
ret = -ENOENT; ret = PTR_ERR(t);
goto free; goto free;
} }
...@@ -1625,7 +1623,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, ...@@ -1625,7 +1623,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
xt_compat_lock(AF_INET); xt_compat_lock(AF_INET);
t = xt_find_table_lock(net, AF_INET, get.name); t = xt_find_table_lock(net, AF_INET, get.name);
if (t) { if (!IS_ERR(t)) {
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
struct xt_table_info info; struct xt_table_info info;
ret = compat_table_info(private, &info); ret = compat_table_info(private, &info);
...@@ -1639,7 +1637,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, ...@@ -1639,7 +1637,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
xt_compat_unlock(AF_INET); xt_compat_unlock(AF_INET);
return ret; return ret;
......
...@@ -38,12 +38,6 @@ static unsigned int ...@@ -38,12 +38,6 @@ static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb, iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, state, state->net->ipv4.iptable_filter); return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
} }
......
...@@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
u_int32_t mark; u_int32_t mark;
int err; int err;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
/* Save things which could affect route */ /* Save things which could affect route */
mark = skb->mark; mark = skb->mark;
iph = ip_hdr(skb); iph = ip_hdr(skb);
......
...@@ -72,6 +72,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = { ...@@ -72,6 +72,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
{ {
.hook = iptable_nat_ipv4_in, .hook = iptable_nat_ipv4_in,
.pf = NFPROTO_IPV4, .pf = NFPROTO_IPV4,
.nat_hook = true,
.hooknum = NF_INET_PRE_ROUTING, .hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_NAT_DST, .priority = NF_IP_PRI_NAT_DST,
}, },
...@@ -79,6 +80,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = { ...@@ -79,6 +80,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
{ {
.hook = iptable_nat_ipv4_out, .hook = iptable_nat_ipv4_out,
.pf = NFPROTO_IPV4, .pf = NFPROTO_IPV4,
.nat_hook = true,
.hooknum = NF_INET_POST_ROUTING, .hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_NAT_SRC, .priority = NF_IP_PRI_NAT_SRC,
}, },
...@@ -86,6 +88,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = { ...@@ -86,6 +88,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
{ {
.hook = iptable_nat_ipv4_local_fn, .hook = iptable_nat_ipv4_local_fn,
.pf = NFPROTO_IPV4, .pf = NFPROTO_IPV4,
.nat_hook = true,
.hooknum = NF_INET_LOCAL_OUT, .hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_NAT_DST, .priority = NF_IP_PRI_NAT_DST,
}, },
...@@ -93,6 +96,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = { ...@@ -93,6 +96,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
{ {
.hook = iptable_nat_ipv4_fn, .hook = iptable_nat_ipv4_fn,
.pf = NFPROTO_IPV4, .pf = NFPROTO_IPV4,
.nat_hook = true,
.hooknum = NF_INET_LOCAL_IN, .hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_NAT_SRC, .priority = NF_IP_PRI_NAT_SRC,
}, },
......
...@@ -26,12 +26,6 @@ static unsigned int ...@@ -26,12 +26,6 @@ static unsigned int
iptable_raw_hook(void *priv, struct sk_buff *skb, iptable_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, state, state->net->ipv4.iptable_raw); return ipt_do_table(skb, state, state->net->ipv4.iptable_raw);
} }
......
...@@ -43,12 +43,6 @@ static unsigned int ...@@ -43,12 +43,6 @@ static unsigned int
iptable_security_hook(void *priv, struct sk_buff *skb, iptable_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* Somebody is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, state, state->net->ipv4.iptable_security); return ipt_do_table(skb, state, state->net->ipv4.iptable_security);
} }
......
...@@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local(void *priv, ...@@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */ if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */
return NF_ACCEPT; return NF_ACCEPT;
...@@ -368,7 +363,7 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); ...@@ -368,7 +363,7 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
MODULE_ALIAS("ip_conntrack"); MODULE_ALIAS("ip_conntrack");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static struct nf_conntrack_l4proto *builtin_l4proto4[] = { static const struct nf_conntrack_l4proto * const builtin_l4proto4[] = {
&nf_conntrack_l4proto_tcp4, &nf_conntrack_l4proto_tcp4,
&nf_conntrack_l4proto_udp4, &nf_conntrack_l4proto_udp4,
&nf_conntrack_l4proto_icmp, &nf_conntrack_l4proto_icmp,
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_log.h> #include <net/netfilter/nf_log.h>
static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ; static const unsigned int nf_ct_icmp_timeout = 30*HZ;
static inline struct nf_icmp_net *icmp_pernet(struct net *net) static inline struct nf_icmp_net *icmp_pernet(struct net *net)
{ {
...@@ -351,7 +351,7 @@ static struct nf_proto_net *icmp_get_net_proto(struct net *net) ...@@ -351,7 +351,7 @@ static struct nf_proto_net *icmp_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.icmp.pn; return &net->ct.nf_ct_proto.icmp.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp =
{ {
.l3proto = PF_INET, .l3proto = PF_INET,
.l4proto = IPPROTO_ICMP, .l4proto = IPPROTO_ICMP,
......
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/rhashtable.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <net/ip.h>
#include <net/neighbour.h>
#include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_tables.h>
/* For layer 4 checksum field offset. */
#include <linux/tcp.h>
#include <linux/udp.h>
static int nf_flow_nat_ip_tcp(struct sk_buff *skb, unsigned int thoff,
__be32 addr, __be32 new_addr)
{
struct tcphdr *tcph;
if (!pskb_may_pull(skb, thoff + sizeof(*tcph)) ||
skb_try_make_writable(skb, thoff + sizeof(*tcph)))
return -1;
tcph = (void *)(skb_network_header(skb) + thoff);
inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, true);
return 0;
}
static int nf_flow_nat_ip_udp(struct sk_buff *skb, unsigned int thoff,
__be32 addr, __be32 new_addr)
{
struct udphdr *udph;
if (!pskb_may_pull(skb, thoff + sizeof(*udph)) ||
skb_try_make_writable(skb, thoff + sizeof(*udph)))
return -1;
udph = (void *)(skb_network_header(skb) + thoff);
if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
inet_proto_csum_replace4(&udph->check, skb, addr,
new_addr, true);
if (!udph->check)
udph->check = CSUM_MANGLED_0;
}
return 0;
}
static int nf_flow_nat_ip_l4proto(struct sk_buff *skb, struct iphdr *iph,
unsigned int thoff, __be32 addr,
__be32 new_addr)
{
switch (iph->protocol) {
case IPPROTO_TCP:
if (nf_flow_nat_ip_tcp(skb, thoff, addr, new_addr) < 0)
return NF_DROP;
break;
case IPPROTO_UDP:
if (nf_flow_nat_ip_udp(skb, thoff, addr, new_addr) < 0)
return NF_DROP;
break;
}
return 0;
}
static int nf_flow_snat_ip(const struct flow_offload *flow, struct sk_buff *skb,
struct iphdr *iph, unsigned int thoff,
enum flow_offload_tuple_dir dir)
{
__be32 addr, new_addr;
switch (dir) {
case FLOW_OFFLOAD_DIR_ORIGINAL:
addr = iph->saddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
iph->saddr = new_addr;
break;
case FLOW_OFFLOAD_DIR_REPLY:
addr = iph->daddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v4.s_addr;
iph->daddr = new_addr;
break;
default:
return -1;
}
csum_replace4(&iph->check, addr, new_addr);
return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
}
static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb,
struct iphdr *iph, unsigned int thoff,
enum flow_offload_tuple_dir dir)
{
__be32 addr, new_addr;
switch (dir) {
case FLOW_OFFLOAD_DIR_ORIGINAL:
addr = iph->daddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
iph->daddr = new_addr;
break;
case FLOW_OFFLOAD_DIR_REPLY:
addr = iph->saddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v4.s_addr;
iph->saddr = new_addr;
break;
default:
return -1;
}
return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
}
static int nf_flow_nat_ip(const struct flow_offload *flow, struct sk_buff *skb,
enum flow_offload_tuple_dir dir)
{
struct iphdr *iph = ip_hdr(skb);
unsigned int thoff = iph->ihl * 4;
if (flow->flags & FLOW_OFFLOAD_SNAT &&
(nf_flow_snat_port(flow, skb, thoff, iph->protocol, dir) < 0 ||
nf_flow_snat_ip(flow, skb, iph, thoff, dir) < 0))
return -1;
if (flow->flags & FLOW_OFFLOAD_DNAT &&
(nf_flow_dnat_port(flow, skb, thoff, iph->protocol, dir) < 0 ||
nf_flow_dnat_ip(flow, skb, iph, thoff, dir) < 0))
return -1;
return 0;
}
static bool ip_has_options(unsigned int thoff)
{
return thoff != sizeof(struct iphdr);
}
static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
struct flow_offload_tuple *tuple)
{
struct flow_ports *ports;
unsigned int thoff;
struct iphdr *iph;
if (!pskb_may_pull(skb, sizeof(*iph)))
return -1;
iph = ip_hdr(skb);
thoff = iph->ihl * 4;
if (ip_is_fragment(iph) ||
unlikely(ip_has_options(thoff)))
return -1;
if (iph->protocol != IPPROTO_TCP &&
iph->protocol != IPPROTO_UDP)
return -1;
thoff = iph->ihl * 4;
if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
return -1;
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v4.s_addr = iph->saddr;
tuple->dst_v4.s_addr = iph->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
tuple->l3proto = AF_INET;
tuple->l4proto = iph->protocol;
tuple->iifidx = dev->ifindex;
return 0;
}
/* Based on ip_exceeds_mtu(). */
static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
{
if (skb->len <= mtu)
return false;
if ((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0)
return false;
if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
return false;
return true;
}
static bool nf_flow_exceeds_mtu(struct sk_buff *skb, const struct rtable *rt)
{
u32 mtu;
mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
if (__nf_flow_exceeds_mtu(skb, mtu))
return true;
return false;
}
unsigned int
nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct flow_offload_tuple_rhash *tuplehash;
struct nf_flowtable *flow_table = priv;
struct flow_offload_tuple tuple = {};
enum flow_offload_tuple_dir dir;
struct flow_offload *flow;
struct net_device *outdev;
const struct rtable *rt;
struct iphdr *iph;
__be32 nexthop;
if (skb->protocol != htons(ETH_P_IP))
return NF_ACCEPT;
if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
return NF_ACCEPT;
tuplehash = flow_offload_lookup(flow_table, &tuple);
if (tuplehash == NULL)
return NF_ACCEPT;
outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.oifidx);
if (!outdev)
return NF_ACCEPT;
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
rt = (const struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
if (unlikely(nf_flow_exceeds_mtu(skb, rt)))
return NF_ACCEPT;
if (skb_try_make_writable(skb, sizeof(*iph)))
return NF_DROP;
if (flow->flags & (FLOW_OFFLOAD_SNAT | FLOW_OFFLOAD_DNAT) &&
nf_flow_nat_ip(flow, skb, dir) < 0)
return NF_DROP;
flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
iph = ip_hdr(skb);
ip_decrease_ttl(iph);
skb->dev = outdev;
nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
return NF_STOLEN;
}
EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
static struct nf_flowtable_type flowtable_ipv4 = {
.family = NFPROTO_IPV4,
.params = &nf_flow_offload_rhash_params,
.gc = nf_flow_offload_work_gc,
.hook = nf_flow_offload_ip_hook,
.owner = THIS_MODULE,
};
static int __init nf_flow_ipv4_module_init(void)
{
nft_register_flowtable_type(&flowtable_ipv4);
return 0;
}
static void __exit nf_flow_ipv4_module_exit(void)
{
nft_unregister_flowtable_type(&flowtable_ipv4);
}
module_init(nf_flow_ipv4_module_init);
module_exit(nf_flow_ipv4_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
MODULE_ALIAS_NF_FLOWTABLE(AF_INET);
...@@ -356,11 +356,6 @@ nf_nat_ipv4_out(void *priv, struct sk_buff *skb, ...@@ -356,11 +356,6 @@ nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
#endif #endif
unsigned int ret; unsigned int ret;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
ret = nf_nat_ipv4_fn(priv, skb, state, do_chain); ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
...@@ -396,11 +391,6 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb, ...@@ -396,11 +391,6 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
unsigned int ret; unsigned int ret;
int err; int err;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
ret = nf_nat_ipv4_fn(priv, skb, state, do_chain); ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(skb, &ctinfo)) != NULL) { (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
......
...@@ -21,7 +21,8 @@ nft_do_chain_arp(void *priv, ...@@ -21,7 +21,8 @@ nft_do_chain_arp(void *priv,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo_unspec(&pkt, skb, state); nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_unspec(&pkt, skb);
return nft_do_chain(&pkt, priv); return nft_do_chain(&pkt, priv);
} }
...@@ -30,12 +31,6 @@ static struct nft_af_info nft_af_arp __read_mostly = { ...@@ -30,12 +31,6 @@ static struct nft_af_info nft_af_arp __read_mostly = {
.family = NFPROTO_ARP, .family = NFPROTO_ARP,
.nhooks = NF_ARP_NUMHOOKS, .nhooks = NF_ARP_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = {
[NF_ARP_IN] = nft_do_chain_arp,
[NF_ARP_OUT] = nft_do_chain_arp,
[NF_ARP_FORWARD] = nft_do_chain_arp,
},
}; };
static int nf_tables_arp_init_net(struct net *net) static int nf_tables_arp_init_net(struct net *net)
...@@ -73,6 +68,10 @@ static const struct nf_chain_type filter_arp = { ...@@ -73,6 +68,10 @@ static const struct nf_chain_type filter_arp = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hook_mask = (1 << NF_ARP_IN) | .hook_mask = (1 << NF_ARP_IN) |
(1 << NF_ARP_OUT), (1 << NF_ARP_OUT),
.hooks = {
[NF_ARP_IN] = nft_do_chain_arp,
[NF_ARP_OUT] = nft_do_chain_arp,
},
}; };
static int __init nf_tables_arp_init(void) static int __init nf_tables_arp_init(void)
......
...@@ -24,40 +24,17 @@ static unsigned int nft_do_chain_ipv4(void *priv, ...@@ -24,40 +24,17 @@ static unsigned int nft_do_chain_ipv4(void *priv,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo_ipv4(&pkt, skb, state); nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_ipv4(&pkt, skb);
return nft_do_chain(&pkt, priv); return nft_do_chain(&pkt, priv);
} }
static unsigned int nft_ipv4_output(void *priv, static struct nft_af_info nft_af_ipv4 __read_mostly = {
struct sk_buff *skb,
const struct nf_hook_state *state)
{
if (unlikely(skb->len < sizeof(struct iphdr) ||
ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
if (net_ratelimit())
pr_info("nf_tables_ipv4: ignoring short SOCK_RAW "
"packet\n");
return NF_ACCEPT;
}
return nft_do_chain_ipv4(priv, skb, state);
}
struct nft_af_info nft_af_ipv4 __read_mostly = {
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
[NF_INET_LOCAL_OUT] = nft_ipv4_output,
[NF_INET_FORWARD] = nft_do_chain_ipv4,
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
[NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
},
}; };
EXPORT_SYMBOL_GPL(nft_af_ipv4);
static int nf_tables_ipv4_init_net(struct net *net) static int nf_tables_ipv4_init_net(struct net *net)
{ {
...@@ -97,6 +74,13 @@ static const struct nf_chain_type filter_ipv4 = { ...@@ -97,6 +74,13 @@ static const struct nf_chain_type filter_ipv4 = {
(1 << NF_INET_FORWARD) | (1 << NF_INET_FORWARD) |
(1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING), (1 << NF_INET_POST_ROUTING),
.hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
[NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
[NF_INET_FORWARD] = nft_do_chain_ipv4,
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
[NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
},
}; };
static int __init nf_tables_ipv4_init(void) static int __init nf_tables_ipv4_init(void)
......
...@@ -33,7 +33,8 @@ static unsigned int nft_nat_do_chain(void *priv, ...@@ -33,7 +33,8 @@ static unsigned int nft_nat_do_chain(void *priv,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo_ipv4(&pkt, skb, state); nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_ipv4(&pkt, skb);
return nft_do_chain(&pkt, priv); return nft_do_chain(&pkt, priv);
} }
......
...@@ -33,12 +33,8 @@ static unsigned int nf_route_table_hook(void *priv, ...@@ -33,12 +33,8 @@ static unsigned int nf_route_table_hook(void *priv,
const struct iphdr *iph; const struct iphdr *iph;
int err; int err;
/* root is playing with raw sockets. */ nft_set_pktinfo(&pkt, skb, state);
if (skb->len < sizeof(struct iphdr) || nft_set_pktinfo_ipv4(&pkt, skb);
ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
nft_set_pktinfo_ipv4(&pkt, skb, state);
mark = skb->mark; mark = skb->mark;
iph = ip_hdr(skb); iph = ip_hdr(skb);
......
...@@ -378,7 +378,7 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk, ...@@ -378,7 +378,7 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,
return dst_output(net, sk, skb); return dst_output(net, sk, skb);
} }
static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
{ {
unsigned int mtu; unsigned int mtu;
struct inet6_dev *idev; struct inet6_dev *idev;
...@@ -398,6 +398,7 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) ...@@ -398,6 +398,7 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
return mtu; return mtu;
} }
EXPORT_SYMBOL_GPL(ip6_dst_mtu_forward);
static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
{ {
......
...@@ -68,32 +68,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb) ...@@ -68,32 +68,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
} }
EXPORT_SYMBOL(ip6_route_me_harder); EXPORT_SYMBOL(ip6_route_me_harder);
/* static int nf_ip6_reroute(struct sk_buff *skb,
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
*/
struct ip6_rt_info {
struct in6_addr daddr;
struct in6_addr saddr;
u_int32_t mark;
};
static void nf_ip6_saveroute(const struct sk_buff *skb,
struct nf_queue_entry *entry)
{
struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
if (entry->state.hook == NF_INET_LOCAL_OUT) {
const struct ipv6hdr *iph = ipv6_hdr(skb);
rt_info->daddr = iph->daddr;
rt_info->saddr = iph->saddr;
rt_info->mark = skb->mark;
}
}
static int nf_ip6_reroute(struct net *net, struct sk_buff *skb,
const struct nf_queue_entry *entry) const struct nf_queue_entry *entry)
{ {
struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
...@@ -103,7 +78,7 @@ static int nf_ip6_reroute(struct net *net, struct sk_buff *skb, ...@@ -103,7 +78,7 @@ static int nf_ip6_reroute(struct net *net, struct sk_buff *skb,
if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
!ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
skb->mark != rt_info->mark) skb->mark != rt_info->mark)
return ip6_route_me_harder(net, skb); return ip6_route_me_harder(entry->state.net, skb);
} }
return 0; return 0;
} }
...@@ -190,25 +165,19 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, ...@@ -190,25 +165,19 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
}; };
static const struct nf_ipv6_ops ipv6ops = { static const struct nf_ipv6_ops ipv6ops = {
.chk_addr = ipv6_chk_addr, .chk_addr = ipv6_chk_addr,
.route_input = ip6_route_input, .route_input = ip6_route_input,
.fragment = ip6_fragment .fragment = ip6_fragment,
};
static const struct nf_afinfo nf_ip6_afinfo = {
.family = AF_INET6,
.checksum = nf_ip6_checksum, .checksum = nf_ip6_checksum,
.checksum_partial = nf_ip6_checksum_partial, .checksum_partial = nf_ip6_checksum_partial,
.route = nf_ip6_route, .route = nf_ip6_route,
.saveroute = nf_ip6_saveroute,
.reroute = nf_ip6_reroute, .reroute = nf_ip6_reroute,
.route_key_size = sizeof(struct ip6_rt_info),
}; };
int __init ipv6_netfilter_init(void) int __init ipv6_netfilter_init(void)
{ {
RCU_INIT_POINTER(nf_ipv6_ops, &ipv6ops); RCU_INIT_POINTER(nf_ipv6_ops, &ipv6ops);
return nf_register_afinfo(&nf_ip6_afinfo); return 0;
} }
/* This can be called from inet6_init() on errors, so it cannot /* This can be called from inet6_init() on errors, so it cannot
...@@ -217,5 +186,4 @@ int __init ipv6_netfilter_init(void) ...@@ -217,5 +186,4 @@ int __init ipv6_netfilter_init(void)
void ipv6_netfilter_fini(void) void ipv6_netfilter_fini(void)
{ {
RCU_INIT_POINTER(nf_ipv6_ops, NULL); RCU_INIT_POINTER(nf_ipv6_ops, NULL);
nf_unregister_afinfo(&nf_ip6_afinfo);
} }
...@@ -71,6 +71,14 @@ config NFT_FIB_IPV6 ...@@ -71,6 +71,14 @@ config NFT_FIB_IPV6
endif # NF_TABLES_IPV6 endif # NF_TABLES_IPV6
endif # NF_TABLES endif # NF_TABLES
config NF_FLOW_TABLE_IPV6
select NF_FLOW_TABLE
tristate "Netfilter flow table IPv6 module"
help
This option adds the flow table IPv6 support.
To compile it as a module, choose M here.
config NF_DUP_IPV6 config NF_DUP_IPV6
tristate "Netfilter IPv6 packet duplication to alternate destination" tristate "Netfilter IPv6 packet duplication to alternate destination"
depends on !NF_CONNTRACK || NF_CONNTRACK depends on !NF_CONNTRACK || NF_CONNTRACK
......
...@@ -45,6 +45,9 @@ obj-$(CONFIG_NFT_REDIR_IPV6) += nft_redir_ipv6.o ...@@ -45,6 +45,9 @@ obj-$(CONFIG_NFT_REDIR_IPV6) += nft_redir_ipv6.o
obj-$(CONFIG_NFT_DUP_IPV6) += nft_dup_ipv6.o obj-$(CONFIG_NFT_DUP_IPV6) += nft_dup_ipv6.o
obj-$(CONFIG_NFT_FIB_IPV6) += nft_fib_ipv6.o obj-$(CONFIG_NFT_FIB_IPV6) += nft_fib_ipv6.o
# flow table support
obj-$(CONFIG_NF_FLOW_TABLE_IPV6) += nf_flow_table_ipv6.o
# matches # matches
obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
......
...@@ -991,9 +991,8 @@ static int get_info(struct net *net, void __user *user, ...@@ -991,9 +991,8 @@ static int get_info(struct net *net, void __user *user,
if (compat) if (compat)
xt_compat_lock(AF_INET6); xt_compat_lock(AF_INET6);
#endif #endif
t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), t = xt_request_find_table_lock(net, AF_INET6, name);
"ip6table_%s", name); if (!IS_ERR(t)) {
if (t) {
struct ip6t_getinfo info; struct ip6t_getinfo info;
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -1023,7 +1022,7 @@ static int get_info(struct net *net, void __user *user, ...@@ -1023,7 +1022,7 @@ static int get_info(struct net *net, void __user *user,
xt_table_unlock(t); xt_table_unlock(t);
module_put(t->me); module_put(t->me);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
if (compat) if (compat)
xt_compat_unlock(AF_INET6); xt_compat_unlock(AF_INET6);
...@@ -1049,7 +1048,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, ...@@ -1049,7 +1048,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
get.name[sizeof(get.name) - 1] = '\0'; get.name[sizeof(get.name) - 1] = '\0';
t = xt_find_table_lock(net, AF_INET6, get.name); t = xt_find_table_lock(net, AF_INET6, get.name);
if (t) { if (!IS_ERR(t)) {
struct xt_table_info *private = t->private; struct xt_table_info *private = t->private;
if (get.size == private->size) if (get.size == private->size)
ret = copy_entries_to_user(private->size, ret = copy_entries_to_user(private->size,
...@@ -1060,7 +1059,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, ...@@ -1060,7 +1059,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
return ret; return ret;
} }
...@@ -1083,10 +1082,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, ...@@ -1083,10 +1082,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
goto out; goto out;
} }
t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), t = xt_request_find_table_lock(net, AF_INET6, name);
"ip6table_%s", name); if (IS_ERR(t)) {
if (!t) { ret = PTR_ERR(t);
ret = -ENOENT;
goto free_newinfo_counters_untrans; goto free_newinfo_counters_untrans;
} }
...@@ -1199,8 +1197,8 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, ...@@ -1199,8 +1197,8 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
if (IS_ERR(paddc)) if (IS_ERR(paddc))
return PTR_ERR(paddc); return PTR_ERR(paddc);
t = xt_find_table_lock(net, AF_INET6, tmp.name); t = xt_find_table_lock(net, AF_INET6, tmp.name);
if (!t) { if (IS_ERR(t)) {
ret = -ENOENT; ret = PTR_ERR(t);
goto free; goto free;
} }
...@@ -1636,7 +1634,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, ...@@ -1636,7 +1634,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
xt_compat_lock(AF_INET6); xt_compat_lock(AF_INET6);
t = xt_find_table_lock(net, AF_INET6, get.name); t = xt_find_table_lock(net, AF_INET6, get.name);
if (t) { if (!IS_ERR(t)) {
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
struct xt_table_info info; struct xt_table_info info;
ret = compat_table_info(private, &info); ret = compat_table_info(private, &info);
...@@ -1650,7 +1648,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, ...@@ -1650,7 +1648,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
} else } else
ret = -ENOENT; ret = PTR_ERR(t);
xt_compat_unlock(AF_INET6); xt_compat_unlock(AF_INET6);
return ret; return ret;
......
...@@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
u_int8_t hop_limit; u_int8_t hop_limit;
u_int32_t flowlabel, mark; u_int32_t flowlabel, mark;
int err; int err;
#if 0
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)) {
net_warn_ratelimited("ip6t_hook: happy cracking\n");
return NF_ACCEPT;
}
#endif
/* save source/dest address, mark, hoplimit, flowlabel, priority, */ /* save source/dest address, mark, hoplimit, flowlabel, priority, */
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr)); memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
......
...@@ -74,6 +74,7 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = { ...@@ -74,6 +74,7 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
{ {
.hook = ip6table_nat_in, .hook = ip6table_nat_in,
.pf = NFPROTO_IPV6, .pf = NFPROTO_IPV6,
.nat_hook = true,
.hooknum = NF_INET_PRE_ROUTING, .hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP6_PRI_NAT_DST, .priority = NF_IP6_PRI_NAT_DST,
}, },
...@@ -81,6 +82,7 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = { ...@@ -81,6 +82,7 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
{ {
.hook = ip6table_nat_out, .hook = ip6table_nat_out,
.pf = NFPROTO_IPV6, .pf = NFPROTO_IPV6,
.nat_hook = true,
.hooknum = NF_INET_POST_ROUTING, .hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_NAT_SRC, .priority = NF_IP6_PRI_NAT_SRC,
}, },
...@@ -88,12 +90,14 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = { ...@@ -88,12 +90,14 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
{ {
.hook = ip6table_nat_local_fn, .hook = ip6table_nat_local_fn,
.pf = NFPROTO_IPV6, .pf = NFPROTO_IPV6,
.nat_hook = true,
.hooknum = NF_INET_LOCAL_OUT, .hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_NAT_DST, .priority = NF_IP6_PRI_NAT_DST,
}, },
/* After packet filtering, change source */ /* After packet filtering, change source */
{ {
.hook = ip6table_nat_fn, .hook = ip6table_nat_fn,
.nat_hook = true,
.pf = NFPROTO_IPV6, .pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN, .hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP6_PRI_NAT_SRC, .priority = NF_IP6_PRI_NAT_SRC,
......
...@@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local(void *priv, ...@@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct ipv6hdr)) {
net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
return NF_ACCEPT;
}
return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
} }
...@@ -368,7 +363,7 @@ static struct nf_sockopt_ops so_getorigdst6 = { ...@@ -368,7 +363,7 @@ static struct nf_sockopt_ops so_getorigdst6 = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static struct nf_conntrack_l4proto *builtin_l4proto6[] = { static const struct nf_conntrack_l4proto * const builtin_l4proto6[] = {
&nf_conntrack_l4proto_tcp6, &nf_conntrack_l4proto_tcp6,
&nf_conntrack_l4proto_udp6, &nf_conntrack_l4proto_udp6,
&nf_conntrack_l4proto_icmpv6, &nf_conntrack_l4proto_icmpv6,
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
#include <net/netfilter/nf_log.h> #include <net/netfilter/nf_log.h>
static unsigned int nf_ct_icmpv6_timeout __read_mostly = 30*HZ; static const unsigned int nf_ct_icmpv6_timeout = 30*HZ;
static inline struct nf_icmp_net *icmpv6_pernet(struct net *net) static inline struct nf_icmp_net *icmpv6_pernet(struct net *net)
{ {
...@@ -352,7 +352,7 @@ static struct nf_proto_net *icmpv6_get_net_proto(struct net *net) ...@@ -352,7 +352,7 @@ static struct nf_proto_net *icmpv6_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.icmpv6.pn; return &net->ct.nf_ct_proto.icmpv6.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 =
{ {
.l3proto = PF_INET6, .l3proto = PF_INET6,
.l4proto = IPPROTO_ICMPV6, .l4proto = IPPROTO_ICMPV6,
......
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/rhashtable.h>
#include <linux/ipv6.h>
#include <linux/netdevice.h>
#include <linux/ipv6.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/neighbour.h>
#include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_tables.h>
/* For layer 4 checksum field offset. */
#include <linux/tcp.h>
#include <linux/udp.h>
static int nf_flow_nat_ipv6_tcp(struct sk_buff *skb, unsigned int thoff,
struct in6_addr *addr,
struct in6_addr *new_addr)
{
struct tcphdr *tcph;
if (!pskb_may_pull(skb, thoff + sizeof(*tcph)) ||
skb_try_make_writable(skb, thoff + sizeof(*tcph)))
return -1;
tcph = (void *)(skb_network_header(skb) + thoff);
inet_proto_csum_replace16(&tcph->check, skb, addr->s6_addr32,
new_addr->s6_addr32, true);
return 0;
}
static int nf_flow_nat_ipv6_udp(struct sk_buff *skb, unsigned int thoff,
struct in6_addr *addr,
struct in6_addr *new_addr)
{
struct udphdr *udph;
if (!pskb_may_pull(skb, thoff + sizeof(*udph)) ||
skb_try_make_writable(skb, thoff + sizeof(*udph)))
return -1;
udph = (void *)(skb_network_header(skb) + thoff);
if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
inet_proto_csum_replace16(&udph->check, skb, addr->s6_addr32,
new_addr->s6_addr32, true);
if (!udph->check)
udph->check = CSUM_MANGLED_0;
}
return 0;
}
static int nf_flow_nat_ipv6_l4proto(struct sk_buff *skb, struct ipv6hdr *ip6h,
unsigned int thoff, struct in6_addr *addr,
struct in6_addr *new_addr)
{
switch (ip6h->nexthdr) {
case IPPROTO_TCP:
if (nf_flow_nat_ipv6_tcp(skb, thoff, addr, new_addr) < 0)
return NF_DROP;
break;
case IPPROTO_UDP:
if (nf_flow_nat_ipv6_udp(skb, thoff, addr, new_addr) < 0)
return NF_DROP;
break;
}
return 0;
}
static int nf_flow_snat_ipv6(const struct flow_offload *flow,
struct sk_buff *skb, struct ipv6hdr *ip6h,
unsigned int thoff,
enum flow_offload_tuple_dir dir)
{
struct in6_addr addr, new_addr;
switch (dir) {
case FLOW_OFFLOAD_DIR_ORIGINAL:
addr = ip6h->saddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v6;
ip6h->saddr = new_addr;
break;
case FLOW_OFFLOAD_DIR_REPLY:
addr = ip6h->daddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v6;
ip6h->daddr = new_addr;
break;
default:
return -1;
}
return nf_flow_nat_ipv6_l4proto(skb, ip6h, thoff, &addr, &new_addr);
}
static int nf_flow_dnat_ipv6(const struct flow_offload *flow,
struct sk_buff *skb, struct ipv6hdr *ip6h,
unsigned int thoff,
enum flow_offload_tuple_dir dir)
{
struct in6_addr addr, new_addr;
switch (dir) {
case FLOW_OFFLOAD_DIR_ORIGINAL:
addr = ip6h->daddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v6;
ip6h->daddr = new_addr;
break;
case FLOW_OFFLOAD_DIR_REPLY:
addr = ip6h->saddr;
new_addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v6;
ip6h->saddr = new_addr;
break;
default:
return -1;
}
return nf_flow_nat_ipv6_l4proto(skb, ip6h, thoff, &addr, &new_addr);
}
static int nf_flow_nat_ipv6(const struct flow_offload *flow,
struct sk_buff *skb,
enum flow_offload_tuple_dir dir)
{
struct ipv6hdr *ip6h = ipv6_hdr(skb);
unsigned int thoff = sizeof(*ip6h);
if (flow->flags & FLOW_OFFLOAD_SNAT &&
(nf_flow_snat_port(flow, skb, thoff, ip6h->nexthdr, dir) < 0 ||
nf_flow_snat_ipv6(flow, skb, ip6h, thoff, dir) < 0))
return -1;
if (flow->flags & FLOW_OFFLOAD_DNAT &&
(nf_flow_dnat_port(flow, skb, thoff, ip6h->nexthdr, dir) < 0 ||
nf_flow_dnat_ipv6(flow, skb, ip6h, thoff, dir) < 0))
return -1;
return 0;
}
static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
struct flow_offload_tuple *tuple)
{
struct flow_ports *ports;
struct ipv6hdr *ip6h;
unsigned int thoff;
if (!pskb_may_pull(skb, sizeof(*ip6h)))
return -1;
ip6h = ipv6_hdr(skb);
if (ip6h->nexthdr != IPPROTO_TCP &&
ip6h->nexthdr != IPPROTO_UDP)
return -1;
thoff = sizeof(*ip6h);
if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
return -1;
ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
tuple->src_v6 = ip6h->saddr;
tuple->dst_v6 = ip6h->daddr;
tuple->src_port = ports->source;
tuple->dst_port = ports->dest;
tuple->l3proto = AF_INET6;
tuple->l4proto = ip6h->nexthdr;
tuple->iifidx = dev->ifindex;
return 0;
}
/* Based on ip_exceeds_mtu(). */
static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
{
if (skb->len <= mtu)
return false;
if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
return false;
return true;
}
static bool nf_flow_exceeds_mtu(struct sk_buff *skb, const struct rt6_info *rt)
{
u32 mtu;
mtu = ip6_dst_mtu_forward(&rt->dst);
if (__nf_flow_exceeds_mtu(skb, mtu))
return true;
return false;
}
unsigned int
nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct flow_offload_tuple_rhash *tuplehash;
struct nf_flowtable *flow_table = priv;
struct flow_offload_tuple tuple = {};
enum flow_offload_tuple_dir dir;
struct flow_offload *flow;
struct net_device *outdev;
struct in6_addr *nexthop;
struct ipv6hdr *ip6h;
struct rt6_info *rt;
if (skb->protocol != htons(ETH_P_IPV6))
return NF_ACCEPT;
if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0)
return NF_ACCEPT;
tuplehash = flow_offload_lookup(flow_table, &tuple);
if (tuplehash == NULL)
return NF_ACCEPT;
outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.oifidx);
if (!outdev)
return NF_ACCEPT;
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
if (unlikely(nf_flow_exceeds_mtu(skb, rt)))
return NF_ACCEPT;
if (skb_try_make_writable(skb, sizeof(*ip6h)))
return NF_DROP;
if (flow->flags & (FLOW_OFFLOAD_SNAT | FLOW_OFFLOAD_DNAT) &&
nf_flow_nat_ipv6(flow, skb, dir) < 0)
return NF_DROP;
flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
ip6h = ipv6_hdr(skb);
ip6h->hop_limit--;
skb->dev = outdev;
nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
return NF_STOLEN;
}
EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
static struct nf_flowtable_type flowtable_ipv6 = {
.family = NFPROTO_IPV6,
.params = &nf_flow_offload_rhash_params,
.gc = nf_flow_offload_work_gc,
.hook = nf_flow_offload_ipv6_hook,
.owner = THIS_MODULE,
};
static int __init nf_flow_ipv6_module_init(void)
{
nft_register_flowtable_type(&flowtable_ipv6);
return 0;
}
static void __exit nf_flow_ipv6_module_exit(void)
{
nft_unregister_flowtable_type(&flowtable_ipv6);
}
module_init(nf_flow_ipv6_module_init);
module_exit(nf_flow_ipv6_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
MODULE_ALIAS_NF_FLOWTABLE(AF_INET6);
...@@ -369,10 +369,6 @@ nf_nat_ipv6_out(void *priv, struct sk_buff *skb, ...@@ -369,10 +369,6 @@ nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
#endif #endif
unsigned int ret; unsigned int ret;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct ipv6hdr))
return NF_ACCEPT;
ret = nf_nat_ipv6_fn(priv, skb, state, do_chain); ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
...@@ -408,10 +404,6 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb, ...@@ -408,10 +404,6 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
unsigned int ret; unsigned int ret;
int err; int err;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct ipv6hdr))
return NF_ACCEPT;
ret = nf_nat_ipv6_fn(priv, skb, state, do_chain); ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(skb, &ctinfo)) != NULL) { (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
......
...@@ -22,39 +22,17 @@ static unsigned int nft_do_chain_ipv6(void *priv, ...@@ -22,39 +22,17 @@ static unsigned int nft_do_chain_ipv6(void *priv,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo_ipv6(&pkt, skb, state); nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_ipv6(&pkt, skb);
return nft_do_chain(&pkt, priv); return nft_do_chain(&pkt, priv);
} }
static unsigned int nft_ipv6_output(void *priv, static struct nft_af_info nft_af_ipv6 __read_mostly = {
struct sk_buff *skb,
const struct nf_hook_state *state)
{
if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
if (net_ratelimit())
pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
"packet\n");
return NF_ACCEPT;
}
return nft_do_chain_ipv6(priv, skb, state);
}
struct nft_af_info nft_af_ipv6 __read_mostly = {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
[NF_INET_LOCAL_OUT] = nft_ipv6_output,
[NF_INET_FORWARD] = nft_do_chain_ipv6,
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
[NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
},
}; };
EXPORT_SYMBOL_GPL(nft_af_ipv6);
static int nf_tables_ipv6_init_net(struct net *net) static int nf_tables_ipv6_init_net(struct net *net)
{ {
...@@ -94,6 +72,13 @@ static const struct nf_chain_type filter_ipv6 = { ...@@ -94,6 +72,13 @@ static const struct nf_chain_type filter_ipv6 = {
(1 << NF_INET_FORWARD) | (1 << NF_INET_FORWARD) |
(1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING), (1 << NF_INET_POST_ROUTING),
.hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
[NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
[NF_INET_FORWARD] = nft_do_chain_ipv6,
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
[NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
},
}; };
static int __init nf_tables_ipv6_init(void) static int __init nf_tables_ipv6_init(void)
......
...@@ -31,7 +31,8 @@ static unsigned int nft_nat_do_chain(void *priv, ...@@ -31,7 +31,8 @@ static unsigned int nft_nat_do_chain(void *priv,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo_ipv6(&pkt, skb, state); nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_ipv6(&pkt, skb);
return nft_do_chain(&pkt, priv); return nft_do_chain(&pkt, priv);
} }
......
...@@ -33,7 +33,8 @@ static unsigned int nf_route_table_hook(void *priv, ...@@ -33,7 +33,8 @@ static unsigned int nf_route_table_hook(void *priv,
u32 mark, flowlabel; u32 mark, flowlabel;
int err; int err;
nft_set_pktinfo_ipv6(&pkt, skb, state); nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_ipv6(&pkt, skb);
/* save source/dest address, mark, hoplimit, flowlabel, priority */ /* save source/dest address, mark, hoplimit, flowlabel, priority */
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr)); memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
......
...@@ -60,7 +60,6 @@ static u32 __nft_fib6_eval_type(const struct nft_fib *priv, ...@@ -60,7 +60,6 @@ static u32 __nft_fib6_eval_type(const struct nft_fib *priv,
{ {
const struct net_device *dev = NULL; const struct net_device *dev = NULL;
const struct nf_ipv6_ops *v6ops; const struct nf_ipv6_ops *v6ops;
const struct nf_afinfo *afinfo;
int route_err, addrtype; int route_err, addrtype;
struct rt6_info *rt; struct rt6_info *rt;
struct flowi6 fl6 = { struct flowi6 fl6 = {
...@@ -69,8 +68,8 @@ static u32 __nft_fib6_eval_type(const struct nft_fib *priv, ...@@ -69,8 +68,8 @@ static u32 __nft_fib6_eval_type(const struct nft_fib *priv,
}; };
u32 ret = 0; u32 ret = 0;
afinfo = nf_get_afinfo(NFPROTO_IPV6); v6ops = nf_get_ipv6_ops();
if (!afinfo) if (!v6ops)
return RTN_UNREACHABLE; return RTN_UNREACHABLE;
if (priv->flags & NFTA_FIB_F_IIF) if (priv->flags & NFTA_FIB_F_IIF)
...@@ -80,12 +79,11 @@ static u32 __nft_fib6_eval_type(const struct nft_fib *priv, ...@@ -80,12 +79,11 @@ static u32 __nft_fib6_eval_type(const struct nft_fib *priv,
nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph); nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph);
v6ops = nf_get_ipv6_ops(); if (dev && v6ops->chk_addr(nft_net(pkt), &fl6.daddr, dev, true))
if (dev && v6ops && v6ops->chk_addr(nft_net(pkt), &fl6.daddr, dev, true))
ret = RTN_LOCAL; ret = RTN_LOCAL;
route_err = afinfo->route(nft_net(pkt), (struct dst_entry **)&rt, route_err = v6ops->route(nft_net(pkt), (struct dst_entry **)&rt,
flowi6_to_flowi(&fl6), false); flowi6_to_flowi(&fl6), false);
if (route_err) if (route_err)
goto err; goto err;
......
...@@ -12,6 +12,12 @@ config NETFILTER_INGRESS ...@@ -12,6 +12,12 @@ config NETFILTER_INGRESS
config NETFILTER_NETLINK config NETFILTER_NETLINK
tristate tristate
config NETFILTER_FAMILY_BRIDGE
bool
config NETFILTER_FAMILY_ARP
bool
config NETFILTER_NETLINK_ACCT config NETFILTER_NETLINK_ACCT
tristate "Netfilter NFACCT over NFNETLINK interface" tristate "Netfilter NFACCT over NFNETLINK interface"
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
...@@ -62,6 +68,8 @@ config NF_LOG_NETDEV ...@@ -62,6 +68,8 @@ config NF_LOG_NETDEV
select NF_LOG_COMMON select NF_LOG_COMMON
if NF_CONNTRACK if NF_CONNTRACK
config NETFILTER_CONNCOUNT
tristate
config NF_CONNTRACK_MARK config NF_CONNTRACK_MARK
bool 'Connection mark tracking support' bool 'Connection mark tracking support'
...@@ -497,6 +505,13 @@ config NFT_CT ...@@ -497,6 +505,13 @@ config NFT_CT
This option adds the "ct" expression that you can use to match This option adds the "ct" expression that you can use to match
connection tracking information such as the flow state. connection tracking information such as the flow state.
config NFT_FLOW_OFFLOAD
depends on NF_CONNTRACK
tristate "Netfilter nf_tables hardware flow offload module"
help
This option adds the "flow_offload" expression that you can use to
choose what flows are placed into the hardware.
config NFT_SET_RBTREE config NFT_SET_RBTREE
tristate "Netfilter nf_tables rbtree set module" tristate "Netfilter nf_tables rbtree set module"
help help
...@@ -649,6 +664,21 @@ endif # NF_TABLES_NETDEV ...@@ -649,6 +664,21 @@ endif # NF_TABLES_NETDEV
endif # NF_TABLES endif # NF_TABLES
config NF_FLOW_TABLE_INET
select NF_FLOW_TABLE
tristate "Netfilter flow table mixed IPv4/IPv6 module"
help
This option adds the flow table mixed IPv4/IPv6 support.
To compile it as a module, choose M here.
config NF_FLOW_TABLE
tristate "Netfilter flow table module"
help
This option adds the flow table core infrastructure.
To compile it as a module, choose M here.
config NETFILTER_XTABLES config NETFILTER_XTABLES
tristate "Netfilter Xtables support (required for ip_tables)" tristate "Netfilter Xtables support (required for ip_tables)"
default m if NETFILTER_ADVANCED=n default m if NETFILTER_ADVANCED=n
...@@ -1120,6 +1150,7 @@ config NETFILTER_XT_MATCH_CONNLIMIT ...@@ -1120,6 +1150,7 @@ config NETFILTER_XT_MATCH_CONNLIMIT
tristate '"connlimit" match support' tristate '"connlimit" match support'
depends on NF_CONNTRACK depends on NF_CONNTRACK
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
select NETFILTER_CONNCOUNT
---help--- ---help---
This match allows you to match against the number of parallel This match allows you to match against the number of parallel
connections to a server per client IP address (or address block). connections to a server per client IP address (or address block).
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o utils.o
nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o nf_conntrack_seqadj.o nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o nf_conntrack_seqadj.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
...@@ -67,6 +67,8 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o ...@@ -67,6 +67,8 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
# SYNPROXY # SYNPROXY
obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
obj-$(CONFIG_NETFILTER_CONNCOUNT) += nf_conncount.o
# generic packet duplication from netdev family # generic packet duplication from netdev family
obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o
...@@ -84,6 +86,7 @@ obj-$(CONFIG_NFT_META) += nft_meta.o ...@@ -84,6 +86,7 @@ obj-$(CONFIG_NFT_META) += nft_meta.o
obj-$(CONFIG_NFT_RT) += nft_rt.o obj-$(CONFIG_NFT_RT) += nft_rt.o
obj-$(CONFIG_NFT_NUMGEN) += nft_numgen.o obj-$(CONFIG_NFT_NUMGEN) += nft_numgen.o
obj-$(CONFIG_NFT_CT) += nft_ct.o obj-$(CONFIG_NFT_CT) += nft_ct.o
obj-$(CONFIG_NFT_FLOW_OFFLOAD) += nft_flow_offload.o
obj-$(CONFIG_NFT_LIMIT) += nft_limit.o obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
obj-$(CONFIG_NFT_NAT) += nft_nat.o obj-$(CONFIG_NFT_NAT) += nft_nat.o
obj-$(CONFIG_NFT_OBJREF) += nft_objref.o obj-$(CONFIG_NFT_OBJREF) += nft_objref.o
...@@ -107,6 +110,10 @@ obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o ...@@ -107,6 +110,10 @@ obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o
obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o
obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o
# flow table infrastructure
obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o
obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
# generic X tables # generic X tables
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
......
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
* Thanks to Rob `CmdrTaco' Malda for not influencing this code in any * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
* way. * way.
* *
* Rusty Russell (C)2000 -- This code is GPL. * This code is GPL.
* Patrick McHardy (c) 2006-2012
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
...@@ -28,34 +27,12 @@ ...@@ -28,34 +27,12 @@
#include "nf_internals.h" #include "nf_internals.h"
static DEFINE_MUTEX(afinfo_mutex);
const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly;
EXPORT_SYMBOL(nf_afinfo);
const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly; const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly;
EXPORT_SYMBOL_GPL(nf_ipv6_ops); EXPORT_SYMBOL_GPL(nf_ipv6_ops);
DEFINE_PER_CPU(bool, nf_skb_duplicated); DEFINE_PER_CPU(bool, nf_skb_duplicated);
EXPORT_SYMBOL_GPL(nf_skb_duplicated); EXPORT_SYMBOL_GPL(nf_skb_duplicated);
int nf_register_afinfo(const struct nf_afinfo *afinfo)
{
mutex_lock(&afinfo_mutex);
RCU_INIT_POINTER(nf_afinfo[afinfo->family], afinfo);
mutex_unlock(&afinfo_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(nf_register_afinfo);
void nf_unregister_afinfo(const struct nf_afinfo *afinfo)
{
mutex_lock(&afinfo_mutex);
RCU_INIT_POINTER(nf_afinfo[afinfo->family], NULL);
mutex_unlock(&afinfo_mutex);
synchronize_rcu();
}
EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
EXPORT_SYMBOL(nf_hooks_needed); EXPORT_SYMBOL(nf_hooks_needed);
...@@ -74,7 +51,8 @@ static struct nf_hook_entries *allocate_hook_entries_size(u16 num) ...@@ -74,7 +51,8 @@ static struct nf_hook_entries *allocate_hook_entries_size(u16 num)
struct nf_hook_entries *e; struct nf_hook_entries *e;
size_t alloc = sizeof(*e) + size_t alloc = sizeof(*e) +
sizeof(struct nf_hook_entry) * num + sizeof(struct nf_hook_entry) * num +
sizeof(struct nf_hook_ops *) * num; sizeof(struct nf_hook_ops *) * num +
sizeof(struct nf_hook_entries_rcu_head);
if (num == 0) if (num == 0)
return NULL; return NULL;
...@@ -85,6 +63,30 @@ static struct nf_hook_entries *allocate_hook_entries_size(u16 num) ...@@ -85,6 +63,30 @@ static struct nf_hook_entries *allocate_hook_entries_size(u16 num)
return e; return e;
} }
static void __nf_hook_entries_free(struct rcu_head *h)
{
struct nf_hook_entries_rcu_head *head;
head = container_of(h, struct nf_hook_entries_rcu_head, head);
kvfree(head->allocation);
}
static void nf_hook_entries_free(struct nf_hook_entries *e)
{
struct nf_hook_entries_rcu_head *head;
struct nf_hook_ops **ops;
unsigned int num;
if (!e)
return;
num = e->num_hook_entries;
ops = nf_hook_entries_get_hook_ops(e);
head = (void *)&ops[num];
head->allocation = e;
call_rcu(&head->head, __nf_hook_entries_free);
}
static unsigned int accept_all(void *priv, static unsigned int accept_all(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
...@@ -135,6 +137,12 @@ nf_hook_entries_grow(const struct nf_hook_entries *old, ...@@ -135,6 +137,12 @@ nf_hook_entries_grow(const struct nf_hook_entries *old,
++i; ++i;
continue; continue;
} }
if (reg->nat_hook && orig_ops[i]->nat_hook) {
kvfree(new);
return ERR_PTR(-EEXIST);
}
if (inserted || reg->priority > orig_ops[i]->priority) { if (inserted || reg->priority > orig_ops[i]->priority) {
new_ops[nhooks] = (void *)orig_ops[i]; new_ops[nhooks] = (void *)orig_ops[i];
new->hooks[nhooks] = old->hooks[i]; new->hooks[nhooks] = old->hooks[i];
...@@ -237,27 +245,61 @@ static void *__nf_hook_entries_try_shrink(struct nf_hook_entries __rcu **pp) ...@@ -237,27 +245,61 @@ static void *__nf_hook_entries_try_shrink(struct nf_hook_entries __rcu **pp)
return old; return old;
} }
static struct nf_hook_entries __rcu **nf_hook_entry_head(struct net *net, const struct nf_hook_ops *reg) static struct nf_hook_entries __rcu **
nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
struct net_device *dev)
{ {
if (reg->pf != NFPROTO_NETDEV) switch (pf) {
return net->nf.hooks[reg->pf]+reg->hooknum; case NFPROTO_NETDEV:
break;
#ifdef CONFIG_NETFILTER_FAMILY_ARP
case NFPROTO_ARP:
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_arp) <= hooknum))
return NULL;
return net->nf.hooks_arp + hooknum;
#endif
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
case NFPROTO_BRIDGE:
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum))
return NULL;
return net->nf.hooks_bridge + hooknum;
#endif
case NFPROTO_IPV4:
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
return NULL;
return net->nf.hooks_ipv4 + hooknum;
case NFPROTO_IPV6:
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv6) <= hooknum))
return NULL;
return net->nf.hooks_ipv6 + hooknum;
#if IS_ENABLED(CONFIG_DECNET)
case NFPROTO_DECNET:
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_decnet) <= hooknum))
return NULL;
return net->nf.hooks_decnet + hooknum;
#endif
default:
WARN_ON_ONCE(1);
return NULL;
}
#ifdef CONFIG_NETFILTER_INGRESS #ifdef CONFIG_NETFILTER_INGRESS
if (reg->hooknum == NF_NETDEV_INGRESS) { if (hooknum == NF_NETDEV_INGRESS) {
if (reg->dev && dev_net(reg->dev) == net) if (dev && dev_net(dev) == net)
return &reg->dev->nf_hooks_ingress; return &dev->nf_hooks_ingress;
} }
#endif #endif
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return NULL; return NULL;
} }
int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) static int __nf_register_net_hook(struct net *net, int pf,
const struct nf_hook_ops *reg)
{ {
struct nf_hook_entries *p, *new_hooks; struct nf_hook_entries *p, *new_hooks;
struct nf_hook_entries __rcu **pp; struct nf_hook_entries __rcu **pp;
if (reg->pf == NFPROTO_NETDEV) { if (pf == NFPROTO_NETDEV) {
#ifndef CONFIG_NETFILTER_INGRESS #ifndef CONFIG_NETFILTER_INGRESS
if (reg->hooknum == NF_NETDEV_INGRESS) if (reg->hooknum == NF_NETDEV_INGRESS)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -267,7 +309,7 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) ...@@ -267,7 +309,7 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
return -EINVAL; return -EINVAL;
} }
pp = nf_hook_entry_head(net, reg); pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
if (!pp) if (!pp)
return -EINVAL; return -EINVAL;
...@@ -285,21 +327,19 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) ...@@ -285,21 +327,19 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
hooks_validate(new_hooks); hooks_validate(new_hooks);
#ifdef CONFIG_NETFILTER_INGRESS #ifdef CONFIG_NETFILTER_INGRESS
if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) if (pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
net_inc_ingress_queue(); net_inc_ingress_queue();
#endif #endif
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]); static_key_slow_inc(&nf_hooks_needed[pf][reg->hooknum]);
#endif #endif
synchronize_net();
BUG_ON(p == new_hooks); BUG_ON(p == new_hooks);
kvfree(p); nf_hook_entries_free(p);
return 0; return 0;
} }
EXPORT_SYMBOL(nf_register_net_hook);
/* /*
* __nf_unregister_net_hook - remove a hook from blob * nf_remove_net_hook - remove a hook from blob
* *
* @oldp: current address of hook blob * @oldp: current address of hook blob
* @unreg: hook to unregister * @unreg: hook to unregister
...@@ -307,8 +347,8 @@ EXPORT_SYMBOL(nf_register_net_hook); ...@@ -307,8 +347,8 @@ EXPORT_SYMBOL(nf_register_net_hook);
* This cannot fail, hook unregistration must always succeed. * This cannot fail, hook unregistration must always succeed.
* Therefore replace the to-be-removed hook with a dummy hook. * Therefore replace the to-be-removed hook with a dummy hook.
*/ */
static void __nf_unregister_net_hook(struct nf_hook_entries *old, static void nf_remove_net_hook(struct nf_hook_entries *old,
const struct nf_hook_ops *unreg) const struct nf_hook_ops *unreg, int pf)
{ {
struct nf_hook_ops **orig_ops; struct nf_hook_ops **orig_ops;
bool found = false; bool found = false;
...@@ -326,24 +366,24 @@ static void __nf_unregister_net_hook(struct nf_hook_entries *old, ...@@ -326,24 +366,24 @@ static void __nf_unregister_net_hook(struct nf_hook_entries *old,
if (found) { if (found) {
#ifdef CONFIG_NETFILTER_INGRESS #ifdef CONFIG_NETFILTER_INGRESS
if (unreg->pf == NFPROTO_NETDEV && unreg->hooknum == NF_NETDEV_INGRESS) if (pf == NFPROTO_NETDEV && unreg->hooknum == NF_NETDEV_INGRESS)
net_dec_ingress_queue(); net_dec_ingress_queue();
#endif #endif
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
static_key_slow_dec(&nf_hooks_needed[unreg->pf][unreg->hooknum]); static_key_slow_dec(&nf_hooks_needed[pf][unreg->hooknum]);
#endif #endif
} else { } else {
WARN_ONCE(1, "hook not found, pf %d num %d", unreg->pf, unreg->hooknum); WARN_ONCE(1, "hook not found, pf %d num %d", pf, unreg->hooknum);
} }
} }
void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) void __nf_unregister_net_hook(struct net *net, int pf,
const struct nf_hook_ops *reg)
{ {
struct nf_hook_entries __rcu **pp; struct nf_hook_entries __rcu **pp;
struct nf_hook_entries *p; struct nf_hook_entries *p;
unsigned int nfq;
pp = nf_hook_entry_head(net, reg); pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
if (!pp) if (!pp)
return; return;
...@@ -355,23 +395,52 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) ...@@ -355,23 +395,52 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
return; return;
} }
__nf_unregister_net_hook(p, reg); nf_remove_net_hook(p, reg, pf);
p = __nf_hook_entries_try_shrink(pp); p = __nf_hook_entries_try_shrink(pp);
mutex_unlock(&nf_hook_mutex); mutex_unlock(&nf_hook_mutex);
if (!p) if (!p)
return; return;
synchronize_net(); nf_queue_nf_hook_drop(net);
nf_hook_entries_free(p);
}
/* other cpu might still process nfqueue verdict that used reg */ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
nfq = nf_queue_nf_hook_drop(net); {
if (nfq) if (reg->pf == NFPROTO_INET) {
synchronize_net(); __nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
kvfree(p); __nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
} else {
__nf_unregister_net_hook(net, reg->pf, reg);
}
} }
EXPORT_SYMBOL(nf_unregister_net_hook); EXPORT_SYMBOL(nf_unregister_net_hook);
int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
{
int err;
if (reg->pf == NFPROTO_INET) {
err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
if (err < 0)
return err;
err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
if (err < 0) {
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
return err;
}
} else {
err = __nf_register_net_hook(net, reg->pf, reg);
if (err < 0)
return err;
}
return 0;
}
EXPORT_SYMBOL(nf_register_net_hook);
int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg,
unsigned int n) unsigned int n)
{ {
...@@ -395,63 +464,10 @@ EXPORT_SYMBOL(nf_register_net_hooks); ...@@ -395,63 +464,10 @@ EXPORT_SYMBOL(nf_register_net_hooks);
void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg, void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
unsigned int hookcount) unsigned int hookcount)
{ {
struct nf_hook_entries *to_free[16], *p; unsigned int i;
struct nf_hook_entries __rcu **pp;
unsigned int i, j, n;
mutex_lock(&nf_hook_mutex);
for (i = 0; i < hookcount; i++) {
pp = nf_hook_entry_head(net, &reg[i]);
if (!pp)
continue;
p = nf_entry_dereference(*pp);
if (WARN_ON_ONCE(!p))
continue;
__nf_unregister_net_hook(p, &reg[i]);
}
mutex_unlock(&nf_hook_mutex);
do {
n = min_t(unsigned int, hookcount, ARRAY_SIZE(to_free));
mutex_lock(&nf_hook_mutex);
for (i = 0, j = 0; i < hookcount && j < n; i++) {
pp = nf_hook_entry_head(net, &reg[i]);
if (!pp)
continue;
p = nf_entry_dereference(*pp);
if (!p)
continue;
to_free[j] = __nf_hook_entries_try_shrink(pp);
if (to_free[j])
++j;
}
mutex_unlock(&nf_hook_mutex);
if (j) {
unsigned int nfq;
synchronize_net();
/* need 2nd synchronize_net() if nfqueue is used, skb
* can get reinjected right before nf_queue_hook_drop()
*/
nfq = nf_queue_nf_hook_drop(net);
if (nfq)
synchronize_net();
for (i = 0; i < j; i++)
kvfree(to_free[i]);
}
reg += n; for (i = 0; i < hookcount; i++)
hookcount -= n; nf_unregister_net_hook(net, &reg[i]);
} while (hookcount > 0);
} }
EXPORT_SYMBOL(nf_unregister_net_hooks); EXPORT_SYMBOL(nf_unregister_net_hooks);
...@@ -569,14 +585,27 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); ...@@ -569,14 +585,27 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
EXPORT_SYMBOL(nf_nat_decode_session_hook); EXPORT_SYMBOL(nf_nat_decode_session_hook);
#endif #endif
static int __net_init netfilter_net_init(struct net *net) static void __net_init __netfilter_net_init(struct nf_hook_entries **e, int max)
{ {
int i, h; int h;
for (i = 0; i < ARRAY_SIZE(net->nf.hooks); i++) { for (h = 0; h < max; h++)
for (h = 0; h < NF_MAX_HOOKS; h++) RCU_INIT_POINTER(e[h], NULL);
RCU_INIT_POINTER(net->nf.hooks[i][h], NULL); }
}
static int __net_init netfilter_net_init(struct net *net)
{
__netfilter_net_init(net->nf.hooks_ipv4, ARRAY_SIZE(net->nf.hooks_ipv4));
__netfilter_net_init(net->nf.hooks_ipv6, ARRAY_SIZE(net->nf.hooks_ipv6));
#ifdef CONFIG_NETFILTER_FAMILY_ARP
__netfilter_net_init(net->nf.hooks_arp, ARRAY_SIZE(net->nf.hooks_arp));
#endif
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
__netfilter_net_init(net->nf.hooks_bridge, ARRAY_SIZE(net->nf.hooks_bridge));
#endif
#if IS_ENABLED(CONFIG_DECNET)
__netfilter_net_init(net->nf.hooks_decnet, ARRAY_SIZE(net->nf.hooks_decnet));
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter", net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter",
......
...@@ -127,14 +127,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -127,14 +127,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (ret <= 0) if (ret <= 0)
return ret; return ret;
if (SET_WITH_TIMEOUT(set) && return ip_set_match_extensions(set, ext, mext, flags, x);
ip_set_timeout_expired(ext_timeout(x, set)))
return 0;
if (SET_WITH_COUNTER(set))
ip_set_update_counter(ext_counter(x, set), ext, mext, flags);
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(x, set), ext, mext, flags);
return 1;
} }
static int static int
...@@ -227,6 +220,7 @@ mtype_list(const struct ip_set *set, ...@@ -227,6 +220,7 @@ mtype_list(const struct ip_set *set,
rcu_read_lock(); rcu_read_lock();
for (; cb->args[IPSET_CB_ARG0] < map->elements; for (; cb->args[IPSET_CB_ARG0] < map->elements;
cb->args[IPSET_CB_ARG0]++) { cb->args[IPSET_CB_ARG0]++) {
cond_resched_rcu();
id = cb->args[IPSET_CB_ARG0]; id = cb->args[IPSET_CB_ARG0];
x = get_ext(set, map, id); x = get_ext(set, map, id);
if (!test_bit(id, map->members) || if (!test_bit(id, map->members) ||
......
...@@ -263,12 +263,8 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -263,12 +263,8 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
if (ret) if (ret)
return ret; return ret;
if (first_ip > last_ip) { if (first_ip > last_ip)
u32 tmp = first_ip; swap(first_ip, last_ip);
first_ip = last_ip;
last_ip = tmp;
}
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
......
...@@ -337,12 +337,8 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -337,12 +337,8 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
if (ret) if (ret)
return ret; return ret;
if (first_ip > last_ip) { if (first_ip > last_ip)
u32 tmp = first_ip; swap(first_ip, last_ip);
first_ip = last_ip;
last_ip = tmp;
}
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
......
...@@ -238,12 +238,8 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -238,12 +238,8 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]); first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (first_port > last_port) { if (first_port > last_port)
u16 tmp = first_port; swap(first_port, last_port);
first_port = last_port;
last_port = tmp;
}
elements = last_port - first_port + 1; elements = last_port - first_port + 1;
set->dsize = ip_set_elem_len(set, tb, 0, 0); set->dsize = ip_set_elem_len(set, tb, 0, 0);
......
...@@ -57,7 +57,7 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); ...@@ -57,7 +57,7 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
/* When the nfnl mutex is held: */ /* When the nfnl mutex is held: */
#define ip_set_dereference(p) \ #define ip_set_dereference(p) \
rcu_dereference_protected(p, 1) rcu_dereference_protected(p, lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
#define ip_set(inst, id) \ #define ip_set(inst, id) \
ip_set_dereference((inst)->ip_set_list)[id] ip_set_dereference((inst)->ip_set_list)[id]
...@@ -472,6 +472,31 @@ ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, ...@@ -472,6 +472,31 @@ ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set,
} }
EXPORT_SYMBOL_GPL(ip_set_put_extensions); EXPORT_SYMBOL_GPL(ip_set_put_extensions);
bool
ip_set_match_extensions(struct ip_set *set, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags, void *data)
{
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(data, set)))
return false;
if (SET_WITH_COUNTER(set)) {
struct ip_set_counter *counter = ext_counter(data, set);
if (flags & IPSET_FLAG_MATCH_COUNTERS &&
!(ip_set_match_counter(ip_set_get_packets(counter),
mext->packets, mext->packets_op) &&
ip_set_match_counter(ip_set_get_bytes(counter),
mext->bytes, mext->bytes_op)))
return false;
ip_set_update_counter(counter, ext, flags);
}
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(data, set),
ext, mext, flags);
return true;
}
EXPORT_SYMBOL_GPL(ip_set_match_extensions);
/* Creating/destroying/renaming/swapping affect the existence and /* Creating/destroying/renaming/swapping affect the existence and
* the properties of a set. All of these can be executed from userspace * the properties of a set. All of these can be executed from userspace
* only and serialized by the nfnl mutex indirectly from nfnetlink. * only and serialized by the nfnl mutex indirectly from nfnetlink.
...@@ -1386,11 +1411,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1386,11 +1411,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
goto next_set; goto next_set;
if (set->variant->uref) if (set->variant->uref)
set->variant->uref(set, cb, true); set->variant->uref(set, cb, true);
/* Fall through and add elements */ /* fall through */
default: default:
rcu_read_lock_bh();
ret = set->variant->list(set, skb, cb); ret = set->variant->list(set, skb, cb);
rcu_read_unlock_bh();
if (!cb->args[IPSET_CB_ARG0]) if (!cb->args[IPSET_CB_ARG0])
/* Set is done, proceed with next one */ /* Set is done, proceed with next one */
goto next_set; goto next_set;
...@@ -2055,6 +2078,7 @@ ip_set_net_exit(struct net *net) ...@@ -2055,6 +2078,7 @@ ip_set_net_exit(struct net *net)
inst->is_deleted = true; /* flag for ip_set_nfnl_put */ inst->is_deleted = true; /* flag for ip_set_nfnl_put */
nfnl_lock(NFNL_SUBSYS_IPSET);
for (i = 0; i < inst->ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
set = ip_set(inst, i); set = ip_set(inst, i);
if (set) { if (set) {
...@@ -2062,6 +2086,7 @@ ip_set_net_exit(struct net *net) ...@@ -2062,6 +2086,7 @@ ip_set_net_exit(struct net *net)
ip_set_destroy_set(set); ip_set_destroy_set(set);
} }
} }
nfnl_unlock(NFNL_SUBSYS_IPSET);
kfree(rcu_dereference_protected(inst->ip_set_list, 1)); kfree(rcu_dereference_protected(inst->ip_set_list, 1));
} }
......
...@@ -917,12 +917,9 @@ static inline int ...@@ -917,12 +917,9 @@ static inline int
mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext, mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
struct ip_set_ext *mext, struct ip_set *set, u32 flags) struct ip_set_ext *mext, struct ip_set *set, u32 flags)
{ {
if (SET_WITH_COUNTER(set)) if (!ip_set_match_extensions(set, ext, mext, flags, data))
ip_set_update_counter(ext_counter(data, set), return 0;
ext, mext, flags); /* nomatch entries return -ENOTEMPTY */
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(data, set),
ext, mext, flags);
return mtype_do_data_match(data); return mtype_do_data_match(data);
} }
...@@ -941,9 +938,9 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, ...@@ -941,9 +938,9 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
struct mtype_elem *data; struct mtype_elem *data;
#if IPSET_NET_COUNT == 2 #if IPSET_NET_COUNT == 2
struct mtype_elem orig = *d; struct mtype_elem orig = *d;
int i, j = 0, k; int ret, i, j = 0, k;
#else #else
int i, j = 0; int ret, i, j = 0;
#endif #endif
u32 key, multi = 0; u32 key, multi = 0;
...@@ -969,18 +966,13 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, ...@@ -969,18 +966,13 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
data = ahash_data(n, i, set->dsize); data = ahash_data(n, i, set->dsize);
if (!mtype_data_equal(data, d, &multi)) if (!mtype_data_equal(data, d, &multi))
continue; continue;
if (SET_WITH_TIMEOUT(set)) { ret = mtype_data_match(data, ext, mext, set, flags);
if (!ip_set_timeout_expired( if (ret != 0)
ext_timeout(data, set))) return ret;
return mtype_data_match(data, ext,
mext, set,
flags);
#ifdef IP_SET_HASH_WITH_MULTI #ifdef IP_SET_HASH_WITH_MULTI
multi = 0; /* No match, reset multiple match flag */
multi = 0;
#endif #endif
} else
return mtype_data_match(data, ext,
mext, set, flags);
} }
#if IPSET_NET_COUNT == 2 #if IPSET_NET_COUNT == 2
} }
...@@ -1027,12 +1019,11 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -1027,12 +1019,11 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (!test_bit(i, n->used)) if (!test_bit(i, n->used))
continue; continue;
data = ahash_data(n, i, set->dsize); data = ahash_data(n, i, set->dsize);
if (mtype_data_equal(data, d, &multi) && if (!mtype_data_equal(data, d, &multi))
!(SET_WITH_TIMEOUT(set) && continue;
ip_set_timeout_expired(ext_timeout(data, set)))) { ret = mtype_data_match(data, ext, mext, set, flags);
ret = mtype_data_match(data, ext, mext, set, flags); if (ret != 0)
goto out; goto out;
}
} }
out: out:
return ret; return ret;
...@@ -1143,6 +1134,7 @@ mtype_list(const struct ip_set *set, ...@@ -1143,6 +1134,7 @@ mtype_list(const struct ip_set *set,
rcu_read_lock(); rcu_read_lock();
for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits); for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits);
cb->args[IPSET_CB_ARG0]++) { cb->args[IPSET_CB_ARG0]++) {
cond_resched_rcu();
incomplete = skb_tail_pointer(skb); incomplete = skb_tail_pointer(skb);
n = rcu_dereference(hbucket(t, cb->args[IPSET_CB_ARG0])); n = rcu_dereference(hbucket(t, cb->args[IPSET_CB_ARG0]));
pr_debug("cb->arg bucket: %lu, t %p n %p\n", pr_debug("cb->arg bucket: %lu, t %p n %p\n",
......
...@@ -55,8 +55,9 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb, ...@@ -55,8 +55,9 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
struct ip_set_adt_opt *opt, const struct ip_set_ext *ext) struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
{ {
struct list_set *map = set->data; struct list_set *map = set->data;
struct ip_set_ext *mext = &opt->ext;
struct set_elem *e; struct set_elem *e;
u32 cmdflags = opt->cmdflags; u32 flags = opt->cmdflags;
int ret; int ret;
/* Don't lookup sub-counters at all */ /* Don't lookup sub-counters at all */
...@@ -64,21 +65,11 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb, ...@@ -64,21 +65,11 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE) if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE; opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
list_for_each_entry_rcu(e, &map->members, list) { list_for_each_entry_rcu(e, &map->members, list) {
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(e, set)))
continue;
ret = ip_set_test(e->id, skb, par, opt); ret = ip_set_test(e->id, skb, par, opt);
if (ret > 0) { if (ret <= 0)
if (SET_WITH_COUNTER(set)) continue;
ip_set_update_counter(ext_counter(e, set), if (ip_set_match_extensions(set, ext, mext, flags, e))
ext, &opt->ext, return 1;
cmdflags);
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(e, set),
ext, &opt->ext,
cmdflags);
return ret;
}
} }
return 0; return 0;
} }
......
...@@ -322,7 +322,7 @@ ip_vs_conn_fill_param_proto(struct netns_ipvs *ipvs, ...@@ -322,7 +322,7 @@ ip_vs_conn_fill_param_proto(struct netns_ipvs *ipvs,
{ {
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports);
if (pptr == NULL) if (pptr == NULL)
return 1; return 1;
......
...@@ -433,7 +433,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, ...@@ -433,7 +433,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
/* /*
* IPv6 frags, only the first hit here. * IPv6 frags, only the first hit here.
*/ */
pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports);
if (pptr == NULL) if (pptr == NULL)
return NULL; return NULL;
...@@ -566,7 +566,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, ...@@ -566,7 +566,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct netns_ipvs *ipvs = svc->ipvs; struct netns_ipvs *ipvs = svc->ipvs;
struct net *net = ipvs->net; struct net *net = ipvs->net;
pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports);
if (!pptr) if (!pptr)
return NF_DROP; return NF_DROP;
dport = likely(!ip_vs_iph_inverse(iph)) ? pptr[1] : pptr[0]; dport = likely(!ip_vs_iph_inverse(iph)) ? pptr[1] : pptr[0];
...@@ -982,7 +982,7 @@ static int ip_vs_out_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb, ...@@ -982,7 +982,7 @@ static int ip_vs_out_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
unsigned int offset; unsigned int offset;
*related = 1; *related = 1;
ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph, ipvsh); ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph);
if (ic == NULL) if (ic == NULL)
return NF_DROP; return NF_DROP;
...@@ -1214,7 +1214,7 @@ static struct ip_vs_conn *__ip_vs_rs_conn_out(unsigned int hooknum, ...@@ -1214,7 +1214,7 @@ static struct ip_vs_conn *__ip_vs_rs_conn_out(unsigned int hooknum,
return NULL; return NULL;
pptr = frag_safe_skb_hp(skb, iph->len, pptr = frag_safe_skb_hp(skb, iph->len,
sizeof(_ports), _ports, iph); sizeof(_ports), _ports);
if (!pptr) if (!pptr)
return NULL; return NULL;
...@@ -1407,7 +1407,7 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in ...@@ -1407,7 +1407,7 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
pptr = frag_safe_skb_hp(skb, iph.len, pptr = frag_safe_skb_hp(skb, iph.len,
sizeof(_ports), _ports, &iph); sizeof(_ports), _ports);
if (pptr == NULL) if (pptr == NULL)
return NF_ACCEPT; /* Not for me */ return NF_ACCEPT; /* Not for me */
if (ip_vs_has_real_service(ipvs, af, iph.protocol, &iph.saddr, if (ip_vs_has_real_service(ipvs, af, iph.protocol, &iph.saddr,
...@@ -1741,7 +1741,7 @@ static int ip_vs_in_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb, ...@@ -1741,7 +1741,7 @@ static int ip_vs_in_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
*related = 1; *related = 1;
ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph, iph); ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph);
if (ic == NULL) if (ic == NULL)
return NF_DROP; return NF_DROP;
......
...@@ -315,6 +315,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp) ...@@ -315,6 +315,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
switch (skb->ip_summed) { switch (skb->ip_summed) {
case CHECKSUM_NONE: case CHECKSUM_NONE:
skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
/* fall through */
case CHECKSUM_COMPLETE: case CHECKSUM_COMPLETE:
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) { if (af == AF_INET6) {
......
...@@ -319,6 +319,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp) ...@@ -319,6 +319,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
case CHECKSUM_NONE: case CHECKSUM_NONE:
skb->csum = skb_checksum(skb, udphoff, skb->csum = skb_checksum(skb, udphoff,
skb->len - udphoff, 0); skb->len - udphoff, 0);
/* fall through */
case CHECKSUM_COMPLETE: case CHECKSUM_COMPLETE:
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) { if (af == AF_INET6) {
......
/*
* count the number of connections matching an arbitrary key.
*
* (C) 2017 Red Hat GmbH
* Author: Florian Westphal <fw@strlen.de>
*
* split from xt_connlimit.c:
* (c) 2000 Gerd Knorr <kraxel@bytesex.org>
* Nov 2002: Martin Bene <martin.bene@icomedias.com>:
* only ignore TIME_WAIT or gone connections
* (C) CC Computer Consultants GmbH, 2007
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/jhash.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/rbtree.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/netfilter/nf_conntrack_tcp.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_count.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_zones.h>
#define CONNCOUNT_SLOTS 256U
#ifdef CONFIG_LOCKDEP
#define CONNCOUNT_LOCK_SLOTS 8U
#else
#define CONNCOUNT_LOCK_SLOTS 256U
#endif
#define CONNCOUNT_GC_MAX_NODES 8
#define MAX_KEYLEN 5
/* we will save the tuples of all connections we care about */
struct nf_conncount_tuple {
struct hlist_node node;
struct nf_conntrack_tuple tuple;
};
struct nf_conncount_rb {
struct rb_node node;
struct hlist_head hhead; /* connections/hosts in same subnet */
u32 key[MAX_KEYLEN];
};
static spinlock_t nf_conncount_locks[CONNCOUNT_LOCK_SLOTS] __cacheline_aligned_in_smp;
struct nf_conncount_data {
unsigned int keylen;
struct rb_root root[CONNCOUNT_SLOTS];
};
static u_int32_t conncount_rnd __read_mostly;
static struct kmem_cache *conncount_rb_cachep __read_mostly;
static struct kmem_cache *conncount_conn_cachep __read_mostly;
static inline bool already_closed(const struct nf_conn *conn)
{
if (nf_ct_protonum(conn) == IPPROTO_TCP)
return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT ||
conn->proto.tcp.state == TCP_CONNTRACK_CLOSE;
else
return 0;
}
static int key_diff(const u32 *a, const u32 *b, unsigned int klen)
{
return memcmp(a, b, klen * sizeof(u32));
}
static bool add_hlist(struct hlist_head *head,
const struct nf_conntrack_tuple *tuple)
{
struct nf_conncount_tuple *conn;
conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
if (conn == NULL)
return false;
conn->tuple = *tuple;
hlist_add_head(&conn->node, head);
return true;
}
static unsigned int check_hlist(struct net *net,
struct hlist_head *head,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone,
bool *addit)
{
const struct nf_conntrack_tuple_hash *found;
struct nf_conncount_tuple *conn;
struct hlist_node *n;
struct nf_conn *found_ct;
unsigned int length = 0;
*addit = true;
/* check the saved connections */
hlist_for_each_entry_safe(conn, n, head, node) {
found = nf_conntrack_find_get(net, zone, &conn->tuple);
if (found == NULL) {
hlist_del(&conn->node);
kmem_cache_free(conncount_conn_cachep, conn);
continue;
}
found_ct = nf_ct_tuplehash_to_ctrack(found);
if (nf_ct_tuple_equal(&conn->tuple, tuple)) {
/*
* Just to be sure we have it only once in the list.
* We should not see tuples twice unless someone hooks
* this into a table without "-p tcp --syn".
*/
*addit = false;
} else if (already_closed(found_ct)) {
/*
* we do not care about connections which are
* closed already -> ditch it
*/
nf_ct_put(found_ct);
hlist_del(&conn->node);
kmem_cache_free(conncount_conn_cachep, conn);
continue;
}
nf_ct_put(found_ct);
length++;
}
return length;
}
static void tree_nodes_free(struct rb_root *root,
struct nf_conncount_rb *gc_nodes[],
unsigned int gc_count)
{
struct nf_conncount_rb *rbconn;
while (gc_count) {
rbconn = gc_nodes[--gc_count];
rb_erase(&rbconn->node, root);
kmem_cache_free(conncount_rb_cachep, rbconn);
}
}
static unsigned int
count_tree(struct net *net, struct rb_root *root,
const u32 *key, u8 keylen,
u8 family,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone)
{
struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES];
struct rb_node **rbnode, *parent;
struct nf_conncount_rb *rbconn;
struct nf_conncount_tuple *conn;
unsigned int gc_count;
bool no_gc = false;
restart:
gc_count = 0;
parent = NULL;
rbnode = &(root->rb_node);
while (*rbnode) {
int diff;
bool addit;
rbconn = rb_entry(*rbnode, struct nf_conncount_rb, node);
parent = *rbnode;
diff = key_diff(key, rbconn->key, keylen);
if (diff < 0) {
rbnode = &((*rbnode)->rb_left);
} else if (diff > 0) {
rbnode = &((*rbnode)->rb_right);
} else {
/* same source network -> be counted! */
unsigned int count;
count = check_hlist(net, &rbconn->hhead, tuple, zone, &addit);
tree_nodes_free(root, gc_nodes, gc_count);
if (!addit)
return count;
if (!add_hlist(&rbconn->hhead, tuple))
return 0; /* hotdrop */
return count + 1;
}
if (no_gc || gc_count >= ARRAY_SIZE(gc_nodes))
continue;
/* only used for GC on hhead, retval and 'addit' ignored */
check_hlist(net, &rbconn->hhead, tuple, zone, &addit);
if (hlist_empty(&rbconn->hhead))
gc_nodes[gc_count++] = rbconn;
}
if (gc_count) {
no_gc = true;
tree_nodes_free(root, gc_nodes, gc_count);
/* tree_node_free before new allocation permits
* allocator to re-use newly free'd object.
*
* This is a rare event; in most cases we will find
* existing node to re-use. (or gc_count is 0).
*/
goto restart;
}
/* no match, need to insert new node */
rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC);
if (rbconn == NULL)
return 0;
conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
if (conn == NULL) {
kmem_cache_free(conncount_rb_cachep, rbconn);
return 0;
}
conn->tuple = *tuple;
memcpy(rbconn->key, key, sizeof(u32) * keylen);
INIT_HLIST_HEAD(&rbconn->hhead);
hlist_add_head(&conn->node, &rbconn->hhead);
rb_link_node(&rbconn->node, parent, rbnode);
rb_insert_color(&rbconn->node, root);
return 1;
}
unsigned int nf_conncount_count(struct net *net,
struct nf_conncount_data *data,
const u32 *key,
unsigned int family,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone)
{
struct rb_root *root;
int count;
u32 hash;
hash = jhash2(key, data->keylen, conncount_rnd) % CONNCOUNT_SLOTS;
root = &data->root[hash];
spin_lock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]);
count = count_tree(net, root, key, data->keylen, family, tuple, zone);
spin_unlock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]);
return count;
}
EXPORT_SYMBOL_GPL(nf_conncount_count);
struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family,
unsigned int keylen)
{
struct nf_conncount_data *data;
int ret, i;
if (keylen % sizeof(u32) ||
keylen / sizeof(u32) > MAX_KEYLEN ||
keylen == 0)
return ERR_PTR(-EINVAL);
net_get_random_once(&conncount_rnd, sizeof(conncount_rnd));
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
ret = nf_ct_netns_get(net, family);
if (ret < 0) {
kfree(data);
return ERR_PTR(ret);
}
for (i = 0; i < ARRAY_SIZE(data->root); ++i)
data->root[i] = RB_ROOT;
data->keylen = keylen / sizeof(u32);
return data;
}
EXPORT_SYMBOL_GPL(nf_conncount_init);
static void destroy_tree(struct rb_root *r)
{
struct nf_conncount_tuple *conn;
struct nf_conncount_rb *rbconn;
struct hlist_node *n;
struct rb_node *node;
while ((node = rb_first(r)) != NULL) {
rbconn = rb_entry(node, struct nf_conncount_rb, node);
rb_erase(node, r);
hlist_for_each_entry_safe(conn, n, &rbconn->hhead, node)
kmem_cache_free(conncount_conn_cachep, conn);
kmem_cache_free(conncount_rb_cachep, rbconn);
}
}
void nf_conncount_destroy(struct net *net, unsigned int family,
struct nf_conncount_data *data)
{
unsigned int i;
nf_ct_netns_put(net, family);
for (i = 0; i < ARRAY_SIZE(data->root); ++i)
destroy_tree(&data->root[i]);
kfree(data);
}
EXPORT_SYMBOL_GPL(nf_conncount_destroy);
static int __init nf_conncount_modinit(void)
{
int i;
BUILD_BUG_ON(CONNCOUNT_LOCK_SLOTS > CONNCOUNT_SLOTS);
BUILD_BUG_ON((CONNCOUNT_SLOTS % CONNCOUNT_LOCK_SLOTS) != 0);
for (i = 0; i < CONNCOUNT_LOCK_SLOTS; ++i)
spin_lock_init(&nf_conncount_locks[i]);
conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple",
sizeof(struct nf_conncount_tuple),
0, 0, NULL);
if (!conncount_conn_cachep)
return -ENOMEM;
conncount_rb_cachep = kmem_cache_create("nf_conncount_rb",
sizeof(struct nf_conncount_rb),
0, 0, NULL);
if (!conncount_rb_cachep) {
kmem_cache_destroy(conncount_conn_cachep);
return -ENOMEM;
}
return 0;
}
static void __exit nf_conncount_modexit(void)
{
kmem_cache_destroy(conncount_conn_cachep);
kmem_cache_destroy(conncount_rb_cachep);
}
module_init(nf_conncount_modinit);
module_exit(nf_conncount_modexit);
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
MODULE_DESCRIPTION("netfilter: count number of connections matching a key");
MODULE_LICENSE("GPL");
...@@ -901,6 +901,9 @@ static unsigned int early_drop_list(struct net *net, ...@@ -901,6 +901,9 @@ static unsigned int early_drop_list(struct net *net,
hlist_nulls_for_each_entry_rcu(h, n, head, hnnode) { hlist_nulls_for_each_entry_rcu(h, n, head, hnnode) {
tmp = nf_ct_tuplehash_to_ctrack(h); tmp = nf_ct_tuplehash_to_ctrack(h);
if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
continue;
if (nf_ct_is_expired(tmp)) { if (nf_ct_is_expired(tmp)) {
nf_ct_gc_expired(tmp); nf_ct_gc_expired(tmp);
continue; continue;
...@@ -975,6 +978,18 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct) ...@@ -975,6 +978,18 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct)
return false; return false;
} }
#define DAY (86400 * HZ)
/* Set an arbitrary timeout large enough not to ever expire, this save
* us a check for the IPS_OFFLOAD_BIT from the packet path via
* nf_ct_is_expired().
*/
static void nf_ct_offload_timeout(struct nf_conn *ct)
{
if (nf_ct_expires(ct) < DAY / 2)
ct->timeout = nfct_time_stamp + DAY;
}
static void gc_worker(struct work_struct *work) static void gc_worker(struct work_struct *work)
{ {
unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u); unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
...@@ -1011,6 +1026,11 @@ static void gc_worker(struct work_struct *work) ...@@ -1011,6 +1026,11 @@ static void gc_worker(struct work_struct *work)
tmp = nf_ct_tuplehash_to_ctrack(h); tmp = nf_ct_tuplehash_to_ctrack(h);
scanned++; scanned++;
if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
nf_ct_offload_timeout(tmp);
continue;
}
if (nf_ct_is_expired(tmp)) { if (nf_ct_is_expired(tmp)) {
nf_ct_gc_expired(tmp); nf_ct_gc_expired(tmp);
expired_count++; expired_count++;
......
/**************************************************************************** /*
* ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
* conntrack/NAT module. * conntrack/NAT module.
* *
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* See ip_conntrack_helper_h323_asn1.h for details. * See ip_conntrack_helper_h323_asn1.h for details.
* *
****************************************************************************/ */
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -140,14 +140,15 @@ static const decoder_t Decoders[] = { ...@@ -140,14 +140,15 @@ static const decoder_t Decoders[] = {
decode_choice, decode_choice,
}; };
/**************************************************************************** /*
* H.323 Types * H.323 Types
****************************************************************************/ */
#include "nf_conntrack_h323_types.c" #include "nf_conntrack_h323_types.c"
/**************************************************************************** /*
* Functions * Functions
****************************************************************************/ */
/* Assume bs is aligned && v < 16384 */ /* Assume bs is aligned && v < 16384 */
static unsigned int get_len(struct bitstr *bs) static unsigned int get_len(struct bitstr *bs)
{ {
...@@ -177,7 +178,6 @@ static int nf_h323_error_boundary(struct bitstr *bs, size_t bytes, size_t bits) ...@@ -177,7 +178,6 @@ static int nf_h323_error_boundary(struct bitstr *bs, size_t bytes, size_t bits)
return 0; return 0;
} }
/****************************************************************************/
static unsigned int get_bit(struct bitstr *bs) static unsigned int get_bit(struct bitstr *bs)
{ {
unsigned int b = (*bs->cur) & (0x80 >> bs->bit); unsigned int b = (*bs->cur) & (0x80 >> bs->bit);
...@@ -187,7 +187,6 @@ static unsigned int get_bit(struct bitstr *bs) ...@@ -187,7 +187,6 @@ static unsigned int get_bit(struct bitstr *bs)
return b; return b;
} }
/****************************************************************************/
/* Assume b <= 8 */ /* Assume b <= 8 */
static unsigned int get_bits(struct bitstr *bs, unsigned int b) static unsigned int get_bits(struct bitstr *bs, unsigned int b)
{ {
...@@ -213,7 +212,6 @@ static unsigned int get_bits(struct bitstr *bs, unsigned int b) ...@@ -213,7 +212,6 @@ static unsigned int get_bits(struct bitstr *bs, unsigned int b)
return v; return v;
} }
/****************************************************************************/
/* Assume b <= 32 */ /* Assume b <= 32 */
static unsigned int get_bitmap(struct bitstr *bs, unsigned int b) static unsigned int get_bitmap(struct bitstr *bs, unsigned int b)
{ {
...@@ -251,9 +249,9 @@ static unsigned int get_bitmap(struct bitstr *bs, unsigned int b) ...@@ -251,9 +249,9 @@ static unsigned int get_bitmap(struct bitstr *bs, unsigned int b)
return v; return v;
} }
/**************************************************************************** /*
* Assume bs is aligned and sizeof(unsigned int) == 4 * Assume bs is aligned and sizeof(unsigned int) == 4
****************************************************************************/ */
static unsigned int get_uint(struct bitstr *bs, int b) static unsigned int get_uint(struct bitstr *bs, int b)
{ {
unsigned int v = 0; unsigned int v = 0;
...@@ -262,12 +260,15 @@ static unsigned int get_uint(struct bitstr *bs, int b) ...@@ -262,12 +260,15 @@ static unsigned int get_uint(struct bitstr *bs, int b)
case 4: case 4:
v |= *bs->cur++; v |= *bs->cur++;
v <<= 8; v <<= 8;
/* fall through */
case 3: case 3:
v |= *bs->cur++; v |= *bs->cur++;
v <<= 8; v <<= 8;
/* fall through */
case 2: case 2:
v |= *bs->cur++; v |= *bs->cur++;
v <<= 8; v <<= 8;
/* fall through */
case 1: case 1:
v |= *bs->cur++; v |= *bs->cur++;
break; break;
...@@ -275,7 +276,6 @@ static unsigned int get_uint(struct bitstr *bs, int b) ...@@ -275,7 +276,6 @@ static unsigned int get_uint(struct bitstr *bs, int b)
return v; return v;
} }
/****************************************************************************/
static int decode_nul(struct bitstr *bs, const struct field_t *f, static int decode_nul(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -284,7 +284,6 @@ static int decode_nul(struct bitstr *bs, const struct field_t *f, ...@@ -284,7 +284,6 @@ static int decode_nul(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_bool(struct bitstr *bs, const struct field_t *f, static int decode_bool(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -296,7 +295,6 @@ static int decode_bool(struct bitstr *bs, const struct field_t *f, ...@@ -296,7 +295,6 @@ static int decode_bool(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_oid(struct bitstr *bs, const struct field_t *f, static int decode_oid(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -316,7 +314,6 @@ static int decode_oid(struct bitstr *bs, const struct field_t *f, ...@@ -316,7 +314,6 @@ static int decode_oid(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_int(struct bitstr *bs, const struct field_t *f, static int decode_int(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -364,7 +361,6 @@ static int decode_int(struct bitstr *bs, const struct field_t *f, ...@@ -364,7 +361,6 @@ static int decode_int(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_enum(struct bitstr *bs, const struct field_t *f, static int decode_enum(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -381,7 +377,6 @@ static int decode_enum(struct bitstr *bs, const struct field_t *f, ...@@ -381,7 +377,6 @@ static int decode_enum(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_bitstr(struct bitstr *bs, const struct field_t *f, static int decode_bitstr(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -418,7 +413,6 @@ static int decode_bitstr(struct bitstr *bs, const struct field_t *f, ...@@ -418,7 +413,6 @@ static int decode_bitstr(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_numstr(struct bitstr *bs, const struct field_t *f, static int decode_numstr(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -439,7 +433,6 @@ static int decode_numstr(struct bitstr *bs, const struct field_t *f, ...@@ -439,7 +433,6 @@ static int decode_numstr(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_octstr(struct bitstr *bs, const struct field_t *f, static int decode_octstr(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -493,7 +486,6 @@ static int decode_octstr(struct bitstr *bs, const struct field_t *f, ...@@ -493,7 +486,6 @@ static int decode_octstr(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_bmpstr(struct bitstr *bs, const struct field_t *f, static int decode_bmpstr(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -523,7 +515,6 @@ static int decode_bmpstr(struct bitstr *bs, const struct field_t *f, ...@@ -523,7 +515,6 @@ static int decode_bmpstr(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_seq(struct bitstr *bs, const struct field_t *f, static int decode_seq(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -653,7 +644,6 @@ static int decode_seq(struct bitstr *bs, const struct field_t *f, ...@@ -653,7 +644,6 @@ static int decode_seq(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_seqof(struct bitstr *bs, const struct field_t *f, static int decode_seqof(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -750,8 +740,6 @@ static int decode_seqof(struct bitstr *bs, const struct field_t *f, ...@@ -750,8 +740,6 @@ static int decode_seqof(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
static int decode_choice(struct bitstr *bs, const struct field_t *f, static int decode_choice(struct bitstr *bs, const struct field_t *f,
char *base, int level) char *base, int level)
{ {
...@@ -833,7 +821,6 @@ static int decode_choice(struct bitstr *bs, const struct field_t *f, ...@@ -833,7 +821,6 @@ static int decode_choice(struct bitstr *bs, const struct field_t *f,
return H323_ERROR_NONE; return H323_ERROR_NONE;
} }
/****************************************************************************/
int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras) int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras)
{ {
static const struct field_t ras_message = { static const struct field_t ras_message = {
...@@ -849,7 +836,6 @@ int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras) ...@@ -849,7 +836,6 @@ int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras)
return decode_choice(&bs, &ras_message, (char *) ras, 0); return decode_choice(&bs, &ras_message, (char *) ras, 0);
} }
/****************************************************************************/
static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
size_t sz, H323_UserInformation *uuie) size_t sz, H323_UserInformation *uuie)
{ {
...@@ -867,7 +853,6 @@ static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, ...@@ -867,7 +853,6 @@ static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0);
} }
/****************************************************************************/
int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
MultimediaSystemControlMessage * MultimediaSystemControlMessage *
mscm) mscm)
...@@ -886,7 +871,6 @@ int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, ...@@ -886,7 +871,6 @@ int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
(char *) mscm, 0); (char *) mscm, 0);
} }
/****************************************************************************/
int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931) int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
{ {
unsigned char *p = buf; unsigned char *p = buf;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/route.h> #include <net/route.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>
#include <linux/netfilter_ipv6.h>
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_core.h>
...@@ -115,7 +116,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245; ...@@ -115,7 +116,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245;
static struct nf_conntrack_helper nf_conntrack_helper_q931[]; static struct nf_conntrack_helper nf_conntrack_helper_q931[];
static struct nf_conntrack_helper nf_conntrack_helper_ras[]; static struct nf_conntrack_helper nf_conntrack_helper_ras[];
/****************************************************************************/
static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff, static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo, struct nf_conn *ct, enum ip_conntrack_info ctinfo,
unsigned char **data, int *datalen, int *dataoff) unsigned char **data, int *datalen, int *dataoff)
...@@ -219,7 +219,6 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff, ...@@ -219,7 +219,6 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
return 0; return 0;
} }
/****************************************************************************/
static int get_h245_addr(struct nf_conn *ct, const unsigned char *data, static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
H245_TransportAddress *taddr, H245_TransportAddress *taddr,
union nf_inet_addr *addr, __be16 *port) union nf_inet_addr *addr, __be16 *port)
...@@ -254,7 +253,6 @@ static int get_h245_addr(struct nf_conn *ct, const unsigned char *data, ...@@ -254,7 +253,6 @@ static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
return 1; return 1;
} }
/****************************************************************************/
static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -328,7 +326,6 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, ...@@ -328,7 +326,6 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
return ret; return ret;
} }
/****************************************************************************/
static int expect_t120(struct sk_buff *skb, static int expect_t120(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
...@@ -380,7 +377,6 @@ static int expect_t120(struct sk_buff *skb, ...@@ -380,7 +377,6 @@ static int expect_t120(struct sk_buff *skb,
return ret; return ret;
} }
/****************************************************************************/
static int process_h245_channel(struct sk_buff *skb, static int process_h245_channel(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
...@@ -410,7 +406,6 @@ static int process_h245_channel(struct sk_buff *skb, ...@@ -410,7 +406,6 @@ static int process_h245_channel(struct sk_buff *skb,
return 0; return 0;
} }
/****************************************************************************/
static int process_olc(struct sk_buff *skb, struct nf_conn *ct, static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -472,7 +467,6 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct, ...@@ -472,7 +467,6 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_olca(struct sk_buff *skb, struct nf_conn *ct, static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned char **data, int dataoff, unsigned int protoff, unsigned char **data, int dataoff,
...@@ -542,7 +536,6 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct, ...@@ -542,7 +536,6 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_h245(struct sk_buff *skb, struct nf_conn *ct, static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned char **data, int dataoff, unsigned int protoff, unsigned char **data, int dataoff,
...@@ -578,7 +571,6 @@ static int process_h245(struct sk_buff *skb, struct nf_conn *ct, ...@@ -578,7 +571,6 @@ static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int h245_help(struct sk_buff *skb, unsigned int protoff, static int h245_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo) struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{ {
...@@ -628,7 +620,6 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff, ...@@ -628,7 +620,6 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
return NF_DROP; return NF_DROP;
} }
/****************************************************************************/
static const struct nf_conntrack_expect_policy h245_exp_policy = { static const struct nf_conntrack_expect_policy h245_exp_policy = {
.max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */, .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
.timeout = 240, .timeout = 240,
...@@ -643,7 +634,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = { ...@@ -643,7 +634,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
.expect_policy = &h245_exp_policy, .expect_policy = &h245_exp_policy,
}; };
/****************************************************************************/
int get_h225_addr(struct nf_conn *ct, unsigned char *data, int get_h225_addr(struct nf_conn *ct, unsigned char *data,
TransportAddress *taddr, TransportAddress *taddr,
union nf_inet_addr *addr, __be16 *port) union nf_inet_addr *addr, __be16 *port)
...@@ -675,7 +665,6 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data, ...@@ -675,7 +665,6 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
return 1; return 1;
} }
/****************************************************************************/
static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned char **data, int dataoff, unsigned int protoff, unsigned char **data, int dataoff,
...@@ -726,20 +715,15 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, ...@@ -726,20 +715,15 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
} }
/* If the calling party is on the same side of the forward-to party, /* If the calling party is on the same side of the forward-to party,
* we don't need to track the second call */ * we don't need to track the second call
*/
static int callforward_do_filter(struct net *net, static int callforward_do_filter(struct net *net,
const union nf_inet_addr *src, const union nf_inet_addr *src,
const union nf_inet_addr *dst, const union nf_inet_addr *dst,
u_int8_t family) u_int8_t family)
{ {
const struct nf_afinfo *afinfo;
int ret = 0; int ret = 0;
/* rcu_read_lock()ed by nf_hook_thresh */
afinfo = nf_get_afinfo(family);
if (!afinfo)
return 0;
switch (family) { switch (family) {
case AF_INET: { case AF_INET: {
struct flowi4 fl1, fl2; struct flowi4 fl1, fl2;
...@@ -750,10 +734,10 @@ static int callforward_do_filter(struct net *net, ...@@ -750,10 +734,10 @@ static int callforward_do_filter(struct net *net,
memset(&fl2, 0, sizeof(fl2)); memset(&fl2, 0, sizeof(fl2));
fl2.daddr = dst->ip; fl2.daddr = dst->ip;
if (!afinfo->route(net, (struct dst_entry **)&rt1, if (!nf_ip_route(net, (struct dst_entry **)&rt1,
flowi4_to_flowi(&fl1), false)) { flowi4_to_flowi(&fl1), false)) {
if (!afinfo->route(net, (struct dst_entry **)&rt2, if (!nf_ip_route(net, (struct dst_entry **)&rt2,
flowi4_to_flowi(&fl2), false)) { flowi4_to_flowi(&fl2), false)) {
if (rt_nexthop(rt1, fl1.daddr) == if (rt_nexthop(rt1, fl1.daddr) ==
rt_nexthop(rt2, fl2.daddr) && rt_nexthop(rt2, fl2.daddr) &&
rt1->dst.dev == rt2->dst.dev) rt1->dst.dev == rt2->dst.dev)
...@@ -766,18 +750,23 @@ static int callforward_do_filter(struct net *net, ...@@ -766,18 +750,23 @@ static int callforward_do_filter(struct net *net,
} }
#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) #if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
case AF_INET6: { case AF_INET6: {
struct flowi6 fl1, fl2; const struct nf_ipv6_ops *v6ops;
struct rt6_info *rt1, *rt2; struct rt6_info *rt1, *rt2;
struct flowi6 fl1, fl2;
v6ops = nf_get_ipv6_ops();
if (!v6ops)
return 0;
memset(&fl1, 0, sizeof(fl1)); memset(&fl1, 0, sizeof(fl1));
fl1.daddr = src->in6; fl1.daddr = src->in6;
memset(&fl2, 0, sizeof(fl2)); memset(&fl2, 0, sizeof(fl2));
fl2.daddr = dst->in6; fl2.daddr = dst->in6;
if (!afinfo->route(net, (struct dst_entry **)&rt1, if (!v6ops->route(net, (struct dst_entry **)&rt1,
flowi6_to_flowi(&fl1), false)) { flowi6_to_flowi(&fl1), false)) {
if (!afinfo->route(net, (struct dst_entry **)&rt2, if (!v6ops->route(net, (struct dst_entry **)&rt2,
flowi6_to_flowi(&fl2), false)) { flowi6_to_flowi(&fl2), false)) {
if (ipv6_addr_equal(rt6_nexthop(rt1, &fl1.daddr), if (ipv6_addr_equal(rt6_nexthop(rt1, &fl1.daddr),
rt6_nexthop(rt2, &fl2.daddr)) && rt6_nexthop(rt2, &fl2.daddr)) &&
rt1->dst.dev == rt2->dst.dev) rt1->dst.dev == rt2->dst.dev)
...@@ -794,7 +783,6 @@ static int callforward_do_filter(struct net *net, ...@@ -794,7 +783,6 @@ static int callforward_do_filter(struct net *net,
} }
/****************************************************************************/
static int expect_callforwarding(struct sk_buff *skb, static int expect_callforwarding(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
...@@ -815,7 +803,8 @@ static int expect_callforwarding(struct sk_buff *skb, ...@@ -815,7 +803,8 @@ static int expect_callforwarding(struct sk_buff *skb,
return 0; return 0;
/* If the calling party is on the same side of the forward-to party, /* If the calling party is on the same side of the forward-to party,
* we don't need to track the second call */ * we don't need to track the second call
*/
if (callforward_filter && if (callforward_filter &&
callforward_do_filter(net, &addr, &ct->tuplehash[!dir].tuple.src.u3, callforward_do_filter(net, &addr, &ct->tuplehash[!dir].tuple.src.u3,
nf_ct_l3num(ct))) { nf_ct_l3num(ct))) {
...@@ -854,7 +843,6 @@ static int expect_callforwarding(struct sk_buff *skb, ...@@ -854,7 +843,6 @@ static int expect_callforwarding(struct sk_buff *skb,
return ret; return ret;
} }
/****************************************************************************/
static int process_setup(struct sk_buff *skb, struct nf_conn *ct, static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -925,7 +913,6 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct, ...@@ -925,7 +913,6 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_callproceeding(struct sk_buff *skb, static int process_callproceeding(struct sk_buff *skb,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
...@@ -958,7 +945,6 @@ static int process_callproceeding(struct sk_buff *skb, ...@@ -958,7 +945,6 @@ static int process_callproceeding(struct sk_buff *skb,
return 0; return 0;
} }
/****************************************************************************/
static int process_connect(struct sk_buff *skb, struct nf_conn *ct, static int process_connect(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -990,7 +976,6 @@ static int process_connect(struct sk_buff *skb, struct nf_conn *ct, ...@@ -990,7 +976,6 @@ static int process_connect(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_alerting(struct sk_buff *skb, struct nf_conn *ct, static int process_alerting(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1022,7 +1007,6 @@ static int process_alerting(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1022,7 +1007,6 @@ static int process_alerting(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_facility(struct sk_buff *skb, struct nf_conn *ct, static int process_facility(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1063,7 +1047,6 @@ static int process_facility(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1063,7 +1047,6 @@ static int process_facility(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_progress(struct sk_buff *skb, struct nf_conn *ct, static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1095,7 +1078,6 @@ static int process_progress(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1095,7 +1078,6 @@ static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_q931(struct sk_buff *skb, struct nf_conn *ct, static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned char **data, int dataoff, unsigned int protoff, unsigned char **data, int dataoff,
...@@ -1154,7 +1136,6 @@ static int process_q931(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1154,7 +1136,6 @@ static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int q931_help(struct sk_buff *skb, unsigned int protoff, static int q931_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo) struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{ {
...@@ -1203,7 +1184,6 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff, ...@@ -1203,7 +1184,6 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
return NF_DROP; return NF_DROP;
} }
/****************************************************************************/
static const struct nf_conntrack_expect_policy q931_exp_policy = { static const struct nf_conntrack_expect_policy q931_exp_policy = {
/* T.120 and H.245 */ /* T.120 and H.245 */
.max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4,
...@@ -1231,7 +1211,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = { ...@@ -1231,7 +1211,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
}, },
}; };
/****************************************************************************/
static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff, static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
int *datalen) int *datalen)
{ {
...@@ -1249,7 +1228,6 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff, ...@@ -1249,7 +1228,6 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
return skb_header_pointer(skb, dataoff, *datalen, h323_buffer); return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
} }
/****************************************************************************/
static struct nf_conntrack_expect *find_expect(struct nf_conn *ct, static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
union nf_inet_addr *addr, union nf_inet_addr *addr,
__be16 port) __be16 port)
...@@ -1270,7 +1248,6 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct, ...@@ -1270,7 +1248,6 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
return NULL; return NULL;
} }
/****************************************************************************/
static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned char **data, unsigned int protoff, unsigned char **data,
...@@ -1328,7 +1305,6 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1328,7 +1305,6 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
return ret; return ret;
} }
/****************************************************************************/
static int process_grq(struct sk_buff *skb, struct nf_conn *ct, static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1346,7 +1322,6 @@ static int process_grq(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1346,7 +1322,6 @@ static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1391,7 +1366,6 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1391,7 +1366,6 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
return ret; return ret;
} }
/****************************************************************************/
static int process_rrq(struct sk_buff *skb, struct nf_conn *ct, static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1428,7 +1402,6 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1428,7 +1402,6 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1480,7 +1453,6 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1480,7 +1453,6 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_urq(struct sk_buff *skb, struct nf_conn *ct, static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1514,7 +1486,6 @@ static int process_urq(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1514,7 +1486,6 @@ static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_arq(struct sk_buff *skb, struct nf_conn *ct, static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1559,7 +1530,6 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1559,7 +1530,6 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_acf(struct sk_buff *skb, struct nf_conn *ct, static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1608,7 +1578,6 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1608,7 +1578,6 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
return ret; return ret;
} }
/****************************************************************************/
static int process_lrq(struct sk_buff *skb, struct nf_conn *ct, static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1626,7 +1595,6 @@ static int process_lrq(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1626,7 +1595,6 @@ static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1666,7 +1634,6 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1666,7 +1634,6 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
return ret; return ret;
} }
/****************************************************************************/
static int process_irr(struct sk_buff *skb, struct nf_conn *ct, static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1700,7 +1667,6 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1700,7 +1667,6 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int process_ras(struct sk_buff *skb, struct nf_conn *ct, static int process_ras(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int protoff, unsigned int protoff,
...@@ -1745,7 +1711,6 @@ static int process_ras(struct sk_buff *skb, struct nf_conn *ct, ...@@ -1745,7 +1711,6 @@ static int process_ras(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
/****************************************************************************/
static int ras_help(struct sk_buff *skb, unsigned int protoff, static int ras_help(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo) struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{ {
...@@ -1788,7 +1753,6 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff, ...@@ -1788,7 +1753,6 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
return NF_DROP; return NF_DROP;
} }
/****************************************************************************/
static const struct nf_conntrack_expect_policy ras_exp_policy = { static const struct nf_conntrack_expect_policy ras_exp_policy = {
.max_expected = 32, .max_expected = 32,
.timeout = 240, .timeout = 240,
...@@ -1849,7 +1813,6 @@ static void __exit h323_helper_exit(void) ...@@ -1849,7 +1813,6 @@ static void __exit h323_helper_exit(void)
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245); nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
} }
/****************************************************************************/
static void __exit nf_conntrack_h323_fini(void) static void __exit nf_conntrack_h323_fini(void)
{ {
h323_helper_exit(); h323_helper_exit();
...@@ -1857,7 +1820,6 @@ static void __exit nf_conntrack_h323_fini(void) ...@@ -1857,7 +1820,6 @@ static void __exit nf_conntrack_h323_fini(void)
pr_debug("nf_ct_h323: fini\n"); pr_debug("nf_ct_h323: fini\n");
} }
/****************************************************************************/
static int __init nf_conntrack_h323_init(void) static int __init nf_conntrack_h323_init(void)
{ {
int ret; int ret;
...@@ -1877,7 +1839,6 @@ static int __init nf_conntrack_h323_init(void) ...@@ -1877,7 +1839,6 @@ static int __init nf_conntrack_h323_init(void)
return ret; return ret;
} }
/****************************************************************************/
module_init(nf_conntrack_h323_init); module_init(nf_conntrack_h323_init);
module_exit(nf_conntrack_h323_fini); module_exit(nf_conntrack_h323_fini);
......
...@@ -544,7 +544,7 @@ static size_t ctnetlink_proto_size(const struct nf_conn *ct) ...@@ -544,7 +544,7 @@ static size_t ctnetlink_proto_size(const struct nf_conn *ct)
len *= 3u; /* ORIG, REPLY, MASTER */ len *= 3u; /* ORIG, REPLY, MASTER */
l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
len += l4proto->nla_size; len += l4proto->nlattr_size;
if (l4proto->nlattr_tuple_size) { if (l4proto->nlattr_tuple_size) {
len4 = l4proto->nlattr_tuple_size(); len4 = l4proto->nlattr_tuple_size();
len4 *= 3u; /* ORIG, REPLY, MASTER */ len4 *= 3u; /* ORIG, REPLY, MASTER */
...@@ -1110,6 +1110,14 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { ...@@ -1110,6 +1110,14 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
.len = NF_CT_LABELS_MAX_SIZE }, .len = NF_CT_LABELS_MAX_SIZE },
}; };
static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)
{
if (test_bit(IPS_OFFLOAD_BIT, &ct->status))
return 0;
return ctnetlink_filter_match(ct, data);
}
static int ctnetlink_flush_conntrack(struct net *net, static int ctnetlink_flush_conntrack(struct net *net,
const struct nlattr * const cda[], const struct nlattr * const cda[],
u32 portid, int report) u32 portid, int report)
...@@ -1122,7 +1130,7 @@ static int ctnetlink_flush_conntrack(struct net *net, ...@@ -1122,7 +1130,7 @@ static int ctnetlink_flush_conntrack(struct net *net,
return PTR_ERR(filter); return PTR_ERR(filter);
} }
nf_ct_iterate_cleanup_net(net, ctnetlink_filter_match, filter, nf_ct_iterate_cleanup_net(net, ctnetlink_flush_iterate, filter,
portid, report); portid, report);
kfree(filter); kfree(filter);
...@@ -1168,6 +1176,11 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, ...@@ -1168,6 +1176,11 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) {
nf_ct_put(ct);
return -EBUSY;
}
if (cda[CTA_ID]) { if (cda[CTA_ID]) {
u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID])); u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID]));
if (id != (u32)(unsigned long)ct) { if (id != (u32)(unsigned long)ct) {
......
...@@ -385,14 +385,14 @@ void nf_ct_l4proto_unregister_sysctl(struct net *net, ...@@ -385,14 +385,14 @@ void nf_ct_l4proto_unregister_sysctl(struct net *net,
/* FIXME: Allow NULL functions and sub in pointers to generic for /* FIXME: Allow NULL functions and sub in pointers to generic for
them. --RR */ them. --RR */
int nf_ct_l4proto_register_one(struct nf_conntrack_l4proto *l4proto) int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *l4proto)
{ {
int ret = 0; int ret = 0;
if (l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos)) if (l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos))
return -EBUSY; return -EBUSY;
if ((l4proto->to_nlattr && !l4proto->nlattr_size) || if ((l4proto->to_nlattr && l4proto->nlattr_size == 0) ||
(l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size))
return -EINVAL; return -EINVAL;
...@@ -428,10 +428,6 @@ int nf_ct_l4proto_register_one(struct nf_conntrack_l4proto *l4proto) ...@@ -428,10 +428,6 @@ int nf_ct_l4proto_register_one(struct nf_conntrack_l4proto *l4proto)
goto out_unlock; goto out_unlock;
} }
l4proto->nla_size = 0;
if (l4proto->nlattr_size)
l4proto->nla_size += l4proto->nlattr_size();
rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
l4proto); l4proto);
out_unlock: out_unlock:
...@@ -502,7 +498,7 @@ void nf_ct_l4proto_pernet_unregister_one(struct net *net, ...@@ -502,7 +498,7 @@ void nf_ct_l4proto_pernet_unregister_one(struct net *net,
} }
EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one); EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister_one);
int nf_ct_l4proto_register(struct nf_conntrack_l4proto *l4proto[], int nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[],
unsigned int num_proto) unsigned int num_proto)
{ {
int ret = -EINVAL, ver; int ret = -EINVAL, ver;
...@@ -524,7 +520,7 @@ int nf_ct_l4proto_register(struct nf_conntrack_l4proto *l4proto[], ...@@ -524,7 +520,7 @@ int nf_ct_l4proto_register(struct nf_conntrack_l4proto *l4proto[],
EXPORT_SYMBOL_GPL(nf_ct_l4proto_register); EXPORT_SYMBOL_GPL(nf_ct_l4proto_register);
int nf_ct_l4proto_pernet_register(struct net *net, int nf_ct_l4proto_pernet_register(struct net *net,
struct nf_conntrack_l4proto *const l4proto[], const struct nf_conntrack_l4proto *const l4proto[],
unsigned int num_proto) unsigned int num_proto)
{ {
int ret = -EINVAL; int ret = -EINVAL;
...@@ -545,7 +541,7 @@ int nf_ct_l4proto_pernet_register(struct net *net, ...@@ -545,7 +541,7 @@ int nf_ct_l4proto_pernet_register(struct net *net,
} }
EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register);
void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto[], void nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[],
unsigned int num_proto) unsigned int num_proto)
{ {
mutex_lock(&nf_ct_proto_mutex); mutex_lock(&nf_ct_proto_mutex);
...@@ -555,12 +551,12 @@ void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto[], ...@@ -555,12 +551,12 @@ void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto[],
synchronize_net(); synchronize_net();
/* Remove all contrack entries for this protocol */ /* Remove all contrack entries for this protocol */
nf_ct_iterate_destroy(kill_l4proto, l4proto); nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto);
} }
EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister); EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister);
void nf_ct_l4proto_pernet_unregister(struct net *net, void nf_ct_l4proto_pernet_unregister(struct net *net,
struct nf_conntrack_l4proto *const l4proto[], const struct nf_conntrack_l4proto *const l4proto[],
unsigned int num_proto) unsigned int num_proto)
{ {
while (num_proto-- != 0) while (num_proto-- != 0)
......
...@@ -654,6 +654,12 @@ static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { ...@@ -654,6 +654,12 @@ static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
[CTA_PROTOINFO_DCCP_PAD] = { .type = NLA_UNSPEC }, [CTA_PROTOINFO_DCCP_PAD] = { .type = NLA_UNSPEC },
}; };
#define DCCP_NLATTR_SIZE ( \
NLA_ALIGN(NLA_HDRLEN + 1) + \
NLA_ALIGN(NLA_HDRLEN + 1) + \
NLA_ALIGN(NLA_HDRLEN + sizeof(u64)) + \
NLA_ALIGN(NLA_HDRLEN + 0))
static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
{ {
struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; struct nlattr *attr = cda[CTA_PROTOINFO_DCCP];
...@@ -691,13 +697,6 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) ...@@ -691,13 +697,6 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
spin_unlock_bh(&ct->lock); spin_unlock_bh(&ct->lock);
return 0; return 0;
} }
static int dccp_nlattr_size(void)
{
return nla_total_size(0) /* CTA_PROTOINFO_DCCP */
+ nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1);
}
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
...@@ -862,7 +861,7 @@ static struct nf_proto_net *dccp_get_net_proto(struct net *net) ...@@ -862,7 +861,7 @@ static struct nf_proto_net *dccp_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.dccp.pn; return &net->ct.nf_ct_proto.dccp.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 __read_mostly = { const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = {
.l3proto = AF_INET, .l3proto = AF_INET,
.l4proto = IPPROTO_DCCP, .l4proto = IPPROTO_DCCP,
.pkt_to_tuple = dccp_pkt_to_tuple, .pkt_to_tuple = dccp_pkt_to_tuple,
...@@ -876,8 +875,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 __read_mostly = { ...@@ -876,8 +875,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 __read_mostly = {
.print_conntrack = dccp_print_conntrack, .print_conntrack = dccp_print_conntrack,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_size = DCCP_NLATTR_SIZE,
.to_nlattr = dccp_to_nlattr, .to_nlattr = dccp_to_nlattr,
.nlattr_size = dccp_nlattr_size,
.from_nlattr = nlattr_to_dccp, .from_nlattr = nlattr_to_dccp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
...@@ -898,7 +897,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 __read_mostly = { ...@@ -898,7 +897,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 __read_mostly = {
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp4);
struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 __read_mostly = { const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 = {
.l3proto = AF_INET6, .l3proto = AF_INET6,
.l4proto = IPPROTO_DCCP, .l4proto = IPPROTO_DCCP,
.pkt_to_tuple = dccp_pkt_to_tuple, .pkt_to_tuple = dccp_pkt_to_tuple,
...@@ -912,8 +911,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 __read_mostly = { ...@@ -912,8 +911,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 __read_mostly = {
.print_conntrack = dccp_print_conntrack, .print_conntrack = dccp_print_conntrack,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_size = DCCP_NLATTR_SIZE,
.to_nlattr = dccp_to_nlattr, .to_nlattr = dccp_to_nlattr,
.nlattr_size = dccp_nlattr_size,
.from_nlattr = nlattr_to_dccp, .from_nlattr = nlattr_to_dccp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_l4proto.h>
static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ; static const unsigned int nf_ct_generic_timeout = 600*HZ;
static bool nf_generic_should_process(u8 proto) static bool nf_generic_should_process(u8 proto)
{ {
...@@ -163,7 +163,7 @@ static struct nf_proto_net *generic_get_net_proto(struct net *net) ...@@ -163,7 +163,7 @@ static struct nf_proto_net *generic_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.generic.pn; return &net->ct.nf_ct_proto.generic.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic =
{ {
.l3proto = PF_UNSPEC, .l3proto = PF_UNSPEC,
.l4proto = 255, .l4proto = 255,
......
...@@ -48,7 +48,7 @@ enum grep_conntrack { ...@@ -48,7 +48,7 @@ enum grep_conntrack {
GRE_CT_MAX GRE_CT_MAX
}; };
static unsigned int gre_timeouts[GRE_CT_MAX] = { static const unsigned int gre_timeouts[GRE_CT_MAX] = {
[GRE_CT_UNREPLIED] = 30*HZ, [GRE_CT_UNREPLIED] = 30*HZ,
[GRE_CT_REPLIED] = 180*HZ, [GRE_CT_REPLIED] = 180*HZ,
}; };
...@@ -352,7 +352,7 @@ static int gre_init_net(struct net *net, u_int16_t proto) ...@@ -352,7 +352,7 @@ static int gre_init_net(struct net *net, u_int16_t proto)
} }
/* protocol helper struct */ /* protocol helper struct */
static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { static const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = {
.l3proto = AF_INET, .l3proto = AF_INET,
.l4proto = IPPROTO_GRE, .l4proto = IPPROTO_GRE,
.pkt_to_tuple = gre_pkt_to_tuple, .pkt_to_tuple = gre_pkt_to_tuple,
......
...@@ -52,7 +52,7 @@ static const char *const sctp_conntrack_names[] = { ...@@ -52,7 +52,7 @@ static const char *const sctp_conntrack_names[] = {
#define HOURS * 60 MINS #define HOURS * 60 MINS
#define DAYS * 24 HOURS #define DAYS * 24 HOURS
static unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] __read_mostly = { static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
[SCTP_CONNTRACK_CLOSED] = 10 SECS, [SCTP_CONNTRACK_CLOSED] = 10 SECS,
[SCTP_CONNTRACK_COOKIE_WAIT] = 3 SECS, [SCTP_CONNTRACK_COOKIE_WAIT] = 3 SECS,
[SCTP_CONNTRACK_COOKIE_ECHOED] = 3 SECS, [SCTP_CONNTRACK_COOKIE_ECHOED] = 3 SECS,
...@@ -578,6 +578,11 @@ static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { ...@@ -578,6 +578,11 @@ static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
[CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 }, [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 },
}; };
#define SCTP_NLATTR_SIZE ( \
NLA_ALIGN(NLA_HDRLEN + 1) + \
NLA_ALIGN(NLA_HDRLEN + 4) + \
NLA_ALIGN(NLA_HDRLEN + 4))
static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct)
{ {
struct nlattr *attr = cda[CTA_PROTOINFO_SCTP]; struct nlattr *attr = cda[CTA_PROTOINFO_SCTP];
...@@ -608,12 +613,6 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) ...@@ -608,12 +613,6 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct)
return 0; return 0;
} }
static int sctp_nlattr_size(void)
{
return nla_total_size(0) /* CTA_PROTOINFO_SCTP */
+ nla_policy_len(sctp_nla_policy, CTA_PROTOINFO_SCTP_MAX + 1);
}
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
...@@ -778,7 +777,7 @@ static struct nf_proto_net *sctp_get_net_proto(struct net *net) ...@@ -778,7 +777,7 @@ static struct nf_proto_net *sctp_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.sctp.pn; return &net->ct.nf_ct_proto.sctp.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = {
.l3proto = PF_INET, .l3proto = PF_INET,
.l4proto = IPPROTO_SCTP, .l4proto = IPPROTO_SCTP,
.pkt_to_tuple = sctp_pkt_to_tuple, .pkt_to_tuple = sctp_pkt_to_tuple,
...@@ -793,8 +792,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { ...@@ -793,8 +792,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.can_early_drop = sctp_can_early_drop, .can_early_drop = sctp_can_early_drop,
.me = THIS_MODULE, .me = THIS_MODULE,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_size = SCTP_NLATTR_SIZE,
.to_nlattr = sctp_to_nlattr, .to_nlattr = sctp_to_nlattr,
.nlattr_size = sctp_nlattr_size,
.from_nlattr = nlattr_to_sctp, .from_nlattr = nlattr_to_sctp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
...@@ -815,7 +814,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { ...@@ -815,7 +814,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp4);
struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = {
.l3proto = PF_INET6, .l3proto = PF_INET6,
.l4proto = IPPROTO_SCTP, .l4proto = IPPROTO_SCTP,
.pkt_to_tuple = sctp_pkt_to_tuple, .pkt_to_tuple = sctp_pkt_to_tuple,
...@@ -830,8 +829,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { ...@@ -830,8 +829,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.can_early_drop = sctp_can_early_drop, .can_early_drop = sctp_can_early_drop,
.me = THIS_MODULE, .me = THIS_MODULE,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_size = SCTP_NLATTR_SIZE,
.to_nlattr = sctp_to_nlattr, .to_nlattr = sctp_to_nlattr,
.nlattr_size = sctp_nlattr_size,
.from_nlattr = nlattr_to_sctp, .from_nlattr = nlattr_to_sctp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
......
...@@ -68,7 +68,7 @@ static const char *const tcp_conntrack_names[] = { ...@@ -68,7 +68,7 @@ static const char *const tcp_conntrack_names[] = {
#define HOURS * 60 MINS #define HOURS * 60 MINS
#define DAYS * 24 HOURS #define DAYS * 24 HOURS
static unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] __read_mostly = { static const unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] = {
[TCP_CONNTRACK_SYN_SENT] = 2 MINS, [TCP_CONNTRACK_SYN_SENT] = 2 MINS,
[TCP_CONNTRACK_SYN_RECV] = 60 SECS, [TCP_CONNTRACK_SYN_RECV] = 60 SECS,
[TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS,
...@@ -305,6 +305,9 @@ static bool tcp_invert_tuple(struct nf_conntrack_tuple *tuple, ...@@ -305,6 +305,9 @@ static bool tcp_invert_tuple(struct nf_conntrack_tuple *tuple,
/* Print out the private part of the conntrack. */ /* Print out the private part of the conntrack. */
static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct) static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
{ {
if (test_bit(IPS_OFFLOAD_BIT, &ct->status))
return;
seq_printf(s, "%s ", tcp_conntrack_names[ct->proto.tcp.state]); seq_printf(s, "%s ", tcp_conntrack_names[ct->proto.tcp.state]);
} }
#endif #endif
...@@ -1222,6 +1225,12 @@ static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = { ...@@ -1222,6 +1225,12 @@ static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = {
[CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .len = sizeof(struct nf_ct_tcp_flags) }, [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .len = sizeof(struct nf_ct_tcp_flags) },
}; };
#define TCP_NLATTR_SIZE ( \
NLA_ALIGN(NLA_HDRLEN + 1) + \
NLA_ALIGN(NLA_HDRLEN + 1) + \
NLA_ALIGN(NLA_HDRLEN + sizeof(sizeof(struct nf_ct_tcp_flags))) + \
NLA_ALIGN(NLA_HDRLEN + sizeof(sizeof(struct nf_ct_tcp_flags))))
static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
{ {
struct nlattr *pattr = cda[CTA_PROTOINFO_TCP]; struct nlattr *pattr = cda[CTA_PROTOINFO_TCP];
...@@ -1274,12 +1283,6 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) ...@@ -1274,12 +1283,6 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
return 0; return 0;
} }
static int tcp_nlattr_size(void)
{
return nla_total_size(0) /* CTA_PROTOINFO_TCP */
+ nla_policy_len(tcp_nla_policy, CTA_PROTOINFO_TCP_MAX + 1);
}
static unsigned int tcp_nlattr_tuple_size(void) static unsigned int tcp_nlattr_tuple_size(void)
{ {
static unsigned int size __read_mostly; static unsigned int size __read_mostly;
...@@ -1541,7 +1544,7 @@ static struct nf_proto_net *tcp_get_net_proto(struct net *net) ...@@ -1541,7 +1544,7 @@ static struct nf_proto_net *tcp_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.tcp.pn; return &net->ct.nf_ct_proto.tcp.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 =
{ {
.l3proto = PF_INET, .l3proto = PF_INET,
.l4proto = IPPROTO_TCP, .l4proto = IPPROTO_TCP,
...@@ -1557,11 +1560,11 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = ...@@ -1557,11 +1560,11 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
.can_early_drop = tcp_can_early_drop, .can_early_drop = tcp_can_early_drop,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.to_nlattr = tcp_to_nlattr, .to_nlattr = tcp_to_nlattr,
.nlattr_size = tcp_nlattr_size,
.from_nlattr = nlattr_to_tcp, .from_nlattr = nlattr_to_tcp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nlattr_tuple_size = tcp_nlattr_tuple_size, .nlattr_tuple_size = tcp_nlattr_tuple_size,
.nlattr_size = TCP_NLATTR_SIZE,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
...@@ -1579,7 +1582,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = ...@@ -1579,7 +1582,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 =
{ {
.l3proto = PF_INET6, .l3proto = PF_INET6,
.l4proto = IPPROTO_TCP, .l4proto = IPPROTO_TCP,
...@@ -1594,8 +1597,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = ...@@ -1594,8 +1597,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
.error = tcp_error, .error = tcp_error,
.can_early_drop = tcp_can_early_drop, .can_early_drop = tcp_can_early_drop,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_size = TCP_NLATTR_SIZE,
.to_nlattr = tcp_to_nlattr, .to_nlattr = tcp_to_nlattr,
.nlattr_size = tcp_nlattr_size,
.from_nlattr = nlattr_to_tcp, .from_nlattr = nlattr_to_tcp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
static unsigned int udp_timeouts[UDP_CT_MAX] = { static const unsigned int udp_timeouts[UDP_CT_MAX] = {
[UDP_CT_UNREPLIED] = 30*HZ, [UDP_CT_UNREPLIED] = 30*HZ,
[UDP_CT_REPLIED] = 180*HZ, [UDP_CT_REPLIED] = 180*HZ,
}; };
...@@ -296,7 +296,7 @@ static struct nf_proto_net *udp_get_net_proto(struct net *net) ...@@ -296,7 +296,7 @@ static struct nf_proto_net *udp_get_net_proto(struct net *net)
return &net->ct.nf_ct_proto.udp.pn; return &net->ct.nf_ct_proto.udp.pn;
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 =
{ {
.l3proto = PF_INET, .l3proto = PF_INET,
.l4proto = IPPROTO_UDP, .l4proto = IPPROTO_UDP,
...@@ -328,7 +328,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = ...@@ -328,7 +328,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
#ifdef CONFIG_NF_CT_PROTO_UDPLITE #ifdef CONFIG_NF_CT_PROTO_UDPLITE
struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 =
{ {
.l3proto = PF_INET, .l3proto = PF_INET,
.l4proto = IPPROTO_UDPLITE, .l4proto = IPPROTO_UDPLITE,
...@@ -360,7 +360,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = ...@@ -360,7 +360,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4);
#endif #endif
struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 =
{ {
.l3proto = PF_INET6, .l3proto = PF_INET6,
.l4proto = IPPROTO_UDP, .l4proto = IPPROTO_UDP,
...@@ -392,7 +392,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = ...@@ -392,7 +392,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
#ifdef CONFIG_NF_CT_PROTO_UDPLITE #ifdef CONFIG_NF_CT_PROTO_UDPLITE
struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 =
{ {
.l3proto = PF_INET6, .l3proto = PF_INET6,
.l4proto = IPPROTO_UDPLITE, .l4proto = IPPROTO_UDPLITE,
......
...@@ -309,10 +309,12 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -309,10 +309,12 @@ static int ct_seq_show(struct seq_file *s, void *v)
WARN_ON(!l4proto); WARN_ON(!l4proto);
ret = -ENOSPC; ret = -ENOSPC;
seq_printf(s, "%-8s %u %-8s %u %ld ", seq_printf(s, "%-8s %u %-8s %u ",
l3proto_name(l3proto->l3proto), nf_ct_l3num(ct), l3proto_name(l3proto->l3proto), nf_ct_l3num(ct),
l4proto_name(l4proto->l4proto), nf_ct_protonum(ct), l4proto_name(l4proto->l4proto), nf_ct_protonum(ct));
nf_ct_expires(ct) / HZ);
if (!test_bit(IPS_OFFLOAD_BIT, &ct->status))
seq_printf(s, "%ld ", nf_ct_expires(ct) / HZ);
if (l4proto->print_conntrack) if (l4proto->print_conntrack)
l4proto->print_conntrack(s, ct); l4proto->print_conntrack(s, ct);
...@@ -339,7 +341,9 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -339,7 +341,9 @@ static int ct_seq_show(struct seq_file *s, void *v)
if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
goto release; goto release;
if (test_bit(IPS_ASSURED_BIT, &ct->status)) if (test_bit(IPS_OFFLOAD_BIT, &ct->status))
seq_puts(s, "[OFFLOAD] ");
else if (test_bit(IPS_ASSURED_BIT, &ct->status))
seq_puts(s, "[ASSURED] "); seq_puts(s, "[ASSURED] ");
if (seq_has_overflowed(s)) if (seq_has_overflowed(s))
......
此差异已折叠。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/rhashtable.h>
#include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_tables.h>
static unsigned int
nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
switch (skb->protocol) {
case htons(ETH_P_IP):
return nf_flow_offload_ip_hook(priv, skb, state);
case htons(ETH_P_IPV6):
return nf_flow_offload_ipv6_hook(priv, skb, state);
}
return NF_ACCEPT;
}
static struct nf_flowtable_type flowtable_inet = {
.family = NFPROTO_INET,
.params = &nf_flow_offload_rhash_params,
.gc = nf_flow_offload_work_gc,
.hook = nf_flow_offload_inet_hook,
.owner = THIS_MODULE,
};
static int __init nf_flow_inet_module_init(void)
{
nft_register_flowtable_type(&flowtable_inet);
return 0;
}
static void __exit nf_flow_inet_module_exit(void)
{
nft_unregister_flowtable_type(&flowtable_inet);
}
module_init(nf_flow_inet_module_init);
module_exit(nf_flow_inet_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
MODULE_ALIAS_NF_FLOWTABLE(1); /* NFPROTO_INET */
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
const struct nf_hook_entries *entries, unsigned int index, const struct nf_hook_entries *entries, unsigned int index,
unsigned int verdict); unsigned int verdict);
unsigned int nf_queue_nf_hook_drop(struct net *net); void nf_queue_nf_hook_drop(struct net *net);
/* nf_log.c */ /* nf_log.c */
int __init netfilter_log_init(void); int __init netfilter_log_init(void);
......
此差异已折叠。
此差异已折叠。
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
...@@ -16,26 +17,31 @@ ...@@ -16,26 +17,31 @@
#include <net/netfilter/nf_tables_ipv6.h> #include <net/netfilter/nf_tables_ipv6.h>
#include <net/ip.h> #include <net/ip.h>
static void nft_inet_hook_ops_init(struct nf_hook_ops *ops, unsigned int n) static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{ {
struct nft_af_info *afi; struct nft_pktinfo pkt;
if (n == 1) nft_set_pktinfo(&pkt, skb, state);
afi = &nft_af_ipv4;
else switch (state->pf) {
afi = &nft_af_ipv6; case NFPROTO_IPV4:
nft_set_pktinfo_ipv4(&pkt, skb);
ops->pf = afi->family; break;
if (afi->hooks[ops->hooknum]) case NFPROTO_IPV6:
ops->hook = afi->hooks[ops->hooknum]; nft_set_pktinfo_ipv6(&pkt, skb);
break;
default:
break;
}
return nft_do_chain(&pkt, priv);
} }
static struct nft_af_info nft_af_inet __read_mostly = { static struct nft_af_info nft_af_inet __read_mostly = {
.family = NFPROTO_INET, .family = NFPROTO_INET,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 2,
.hook_ops_init = nft_inet_hook_ops_init,
}; };
static int __net_init nf_tables_inet_init_net(struct net *net) static int __net_init nf_tables_inet_init_net(struct net *net)
...@@ -76,6 +82,13 @@ static const struct nf_chain_type filter_inet = { ...@@ -76,6 +82,13 @@ static const struct nf_chain_type filter_inet = {
(1 << NF_INET_FORWARD) | (1 << NF_INET_FORWARD) |
(1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING), (1 << NF_INET_POST_ROUTING),
.hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_inet,
[NF_INET_LOCAL_OUT] = nft_do_chain_inet,
[NF_INET_FORWARD] = nft_do_chain_inet,
[NF_INET_PRE_ROUTING] = nft_do_chain_inet,
[NF_INET_POST_ROUTING] = nft_do_chain_inet,
},
}; };
static int __init nf_tables_inet_init(void) static int __init nf_tables_inet_init(void)
......
...@@ -21,15 +21,17 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb, ...@@ -21,15 +21,17 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
{ {
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
nft_set_pktinfo(&pkt, skb, state);
switch (skb->protocol) { switch (skb->protocol) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
nft_set_pktinfo_ipv4_validate(&pkt, skb, state); nft_set_pktinfo_ipv4_validate(&pkt, skb);
break; break;
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
nft_set_pktinfo_ipv6_validate(&pkt, skb, state); nft_set_pktinfo_ipv6_validate(&pkt, skb);
break; break;
default: default:
nft_set_pktinfo_unspec(&pkt, skb, state); nft_set_pktinfo_unspec(&pkt, skb);
break; break;
} }
...@@ -41,10 +43,6 @@ static struct nft_af_info nft_af_netdev __read_mostly = { ...@@ -41,10 +43,6 @@ static struct nft_af_info nft_af_netdev __read_mostly = {
.nhooks = NF_NETDEV_NUMHOOKS, .nhooks = NF_NETDEV_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.flags = NFT_AF_NEEDS_DEV, .flags = NFT_AF_NEEDS_DEV,
.nops = 1,
.hooks = {
[NF_NETDEV_INGRESS] = nft_do_chain_netdev,
},
}; };
static int nf_tables_netdev_init_net(struct net *net) static int nf_tables_netdev_init_net(struct net *net)
...@@ -81,6 +79,9 @@ static const struct nf_chain_type nft_filter_chain_netdev = { ...@@ -81,6 +79,9 @@ static const struct nf_chain_type nft_filter_chain_netdev = {
.family = NFPROTO_NETDEV, .family = NFPROTO_NETDEV,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hook_mask = (1 << NF_NETDEV_INGRESS), .hook_mask = (1 << NF_NETDEV_INGRESS),
.hooks = {
[NF_NETDEV_INGRESS] = nft_do_chain_netdev,
},
}; };
static void nft_netdev_event(unsigned long event, struct net_device *dev, static void nft_netdev_event(unsigned long event, struct net_device *dev,
...@@ -96,7 +97,7 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev, ...@@ -96,7 +97,7 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev,
__nft_release_basechain(ctx); __nft_release_basechain(ctx);
break; break;
case NETDEV_CHANGENAME: case NETDEV_CHANGENAME:
if (dev->ifindex != basechain->ops[0].dev->ifindex) if (dev->ifindex != basechain->ops.dev->ifindex)
return; return;
strncpy(basechain->dev_name, dev->name, IFNAMSIZ); strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
......
...@@ -941,23 +941,18 @@ static struct notifier_block nfqnl_dev_notifier = { ...@@ -941,23 +941,18 @@ static struct notifier_block nfqnl_dev_notifier = {
.notifier_call = nfqnl_rcv_dev_event, .notifier_call = nfqnl_rcv_dev_event,
}; };
static unsigned int nfqnl_nf_hook_drop(struct net *net) static void nfqnl_nf_hook_drop(struct net *net)
{ {
struct nfnl_queue_net *q = nfnl_queue_pernet(net); struct nfnl_queue_net *q = nfnl_queue_pernet(net);
unsigned int instances = 0;
int i; int i;
for (i = 0; i < INSTANCE_BUCKETS; i++) { for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct nfqnl_instance *inst; struct nfqnl_instance *inst;
struct hlist_head *head = &q->instance_table[i]; struct hlist_head *head = &q->instance_table[i];
hlist_for_each_entry_rcu(inst, head, hlist) { hlist_for_each_entry_rcu(inst, head, hlist)
nfqnl_flush(inst, NULL, 0); nfqnl_flush(inst, NULL, 0);
instances++;
}
} }
return instances;
} }
static int static int
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册