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

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) The various ip(6)table_foo incarnations are updated to expect
   that the table is passed as 'void *priv' argument that netfilter core
   passes to the hook functions. This reduces the struct net size by 2
   cachelines on x86_64. From Florian Westphal.

2) Add cgroupsv2 support for nftables.

3) Fix bridge log family merge into nf_log_syslog: Missing
   unregistration from netns exit path, from Phil Sutter.

4) Add nft_pernet() helper to access nftables pernet area.

5) Add struct nfnl_info to reduce nfnetlink callback footprint and
   to facilite future updates. Consolidate nfnetlink callbacks.

6) Add CONFIG_NETFILTER_XTABLES_COMPAT Kconfig knob, also from Florian.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2021-04-26 12:31:42 -07:00
commit eb43c081a6
63 changed files with 1504 additions and 1269 deletions

View file

@ -7,21 +7,26 @@
#include <net/netlink.h> #include <net/netlink.h>
#include <uapi/linux/netfilter/nfnetlink.h> #include <uapi/linux/netfilter/nfnetlink.h>
struct nfnl_info {
struct net *net;
struct sock *sk;
const struct nlmsghdr *nlh;
struct netlink_ext_ack *extack;
};
enum nfnl_callback_type {
NFNL_CB_UNSPEC = 0,
NFNL_CB_MUTEX,
NFNL_CB_RCU,
NFNL_CB_BATCH,
};
struct nfnl_callback { struct nfnl_callback {
int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb, int (*call)(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[]);
const struct nlattr * const cda[], const struct nla_policy *policy;
struct netlink_ext_ack *extack); enum nfnl_callback_type type;
int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb, __u16 attr_count;
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
const struct nla_policy *policy; /* netlink attribute policy */
const u_int16_t attr_count; /* number of nlattr's */
}; };
enum nfnl_abort_action { enum nfnl_abort_action {

View file

@ -158,7 +158,7 @@ struct xt_match {
/* Called when entry of this type deleted. */ /* Called when entry of this type deleted. */
void (*destroy)(const struct xt_mtdtor_param *); void (*destroy)(const struct xt_mtdtor_param *);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */ /* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src); void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src); int (*compat_to_user)(void __user *dst, const void *src);
@ -169,7 +169,7 @@ struct xt_match {
const char *table; const char *table;
unsigned int matchsize; unsigned int matchsize;
unsigned int usersize; unsigned int usersize;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize; unsigned int compatsize;
#endif #endif
unsigned int hooks; unsigned int hooks;
@ -199,7 +199,7 @@ struct xt_target {
/* Called when entry of this type deleted. */ /* Called when entry of this type deleted. */
void (*destroy)(const struct xt_tgdtor_param *); void (*destroy)(const struct xt_tgdtor_param *);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */ /* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src); void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src); int (*compat_to_user)(void __user *dst, const void *src);
@ -210,7 +210,7 @@ struct xt_target {
const char *table; const char *table;
unsigned int targetsize; unsigned int targetsize;
unsigned int usersize; unsigned int usersize;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize; unsigned int compatsize;
#endif #endif
unsigned int hooks; unsigned int hooks;
@ -229,6 +229,9 @@ struct xt_table {
/* Man behind the curtain... */ /* Man behind the curtain... */
struct xt_table_info *private; struct xt_table_info *private;
/* hook ops that register the table with the netfilter core */
struct nf_hook_ops *ops;
/* Set this to THIS_MODULE if you are a module, otherwise NULL */ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me; struct module *me;
@ -322,6 +325,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision);
int xt_find_revision(u8 af, const char *name, u8 revision, int target, int xt_find_revision(u8 af, const char *name, u8 revision, int target,
int *err); int *err);
struct xt_table *xt_find_table(struct net *net, u8 af, const char *name);
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, struct xt_table *xt_request_find_table_lock(struct net *net, u_int8_t af,
@ -448,7 +452,7 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu)
struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *); struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_xt_entry_match { struct compat_xt_entry_match {
@ -529,5 +533,5 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset, unsigned int target_offset,
unsigned int next_offset); unsigned int next_offset);
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
#endif /* _X_TABLES_H */ #endif /* _X_TABLES_H */

View file

@ -51,15 +51,15 @@ struct arpt_error {
extern void *arpt_alloc_initial_table(const struct xt_table *); extern void *arpt_alloc_initial_table(const struct xt_table *);
int arpt_register_table(struct net *net, const struct xt_table *table, int arpt_register_table(struct net *net, const struct xt_table *table,
const struct arpt_replace *repl, const struct arpt_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res); const struct nf_hook_ops *ops);
void arpt_unregister_table(struct net *net, struct xt_table *table); void arpt_unregister_table(struct net *net, const char *name);
void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table, void arpt_unregister_table_pre_exit(struct net *net, const char *name,
const struct nf_hook_ops *ops); const struct nf_hook_ops *ops);
extern unsigned int arpt_do_table(struct sk_buff *skb, extern unsigned int arpt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct xt_table *table); struct xt_table *table);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_arpt_entry { struct compat_arpt_entry {

View file

@ -100,6 +100,7 @@ struct ebt_table {
unsigned int valid_hooks); unsigned int valid_hooks);
/* the data used by the kernel */ /* the data used by the kernel */
struct ebt_table_info *private; struct ebt_table_info *private;
struct nf_hook_ops *ops;
struct module *me; struct module *me;
}; };
@ -108,11 +109,9 @@ struct ebt_table {
extern int ebt_register_table(struct net *net, extern int ebt_register_table(struct net *net,
const struct ebt_table *table, const struct ebt_table *table,
const struct nf_hook_ops *ops,
struct ebt_table **res);
extern void ebt_unregister_table(struct net *net, struct ebt_table *table);
void ebt_unregister_table_pre_exit(struct net *net, const char *tablename,
const struct nf_hook_ops *ops); const struct nf_hook_ops *ops);
extern void ebt_unregister_table(struct net *net, const char *tablename);
void ebt_unregister_table_pre_exit(struct net *net, const char *tablename);
extern unsigned int ebt_do_table(struct sk_buff *skb, extern unsigned int ebt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct ebt_table *table); struct ebt_table *table);

View file

@ -24,15 +24,10 @@
int ipt_register_table(struct net *net, const struct xt_table *table, int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl, const struct ipt_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res);
void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops); const struct nf_hook_ops *ops);
void ipt_unregister_table_exit(struct net *net, struct xt_table *table); void ipt_unregister_table_pre_exit(struct net *net, const char *name);
void ipt_unregister_table_exit(struct net *net, const char *name);
void ipt_unregister_table(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops);
/* Standard entry. */ /* Standard entry. */
struct ipt_standard { struct ipt_standard {
@ -72,7 +67,7 @@ extern unsigned int ipt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct xt_table *table); struct xt_table *table);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_ipt_entry { struct compat_ipt_entry {

View file

@ -26,17 +26,14 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *);
int ip6t_register_table(struct net *net, const struct xt_table *table, int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl, const struct ip6t_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res);
void ip6t_unregister_table(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops); const struct nf_hook_ops *ops);
void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table, void ip6t_unregister_table_pre_exit(struct net *net, const char *name);
const struct nf_hook_ops *ops); void ip6t_unregister_table_exit(struct net *net, const char *name);
void ip6t_unregister_table_exit(struct net *net, struct xt_table *table);
extern unsigned int ip6t_do_table(struct sk_buff *skb, extern unsigned int ip6t_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct xt_table *table); struct xt_table *table);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_ip6t_entry { struct compat_ip6t_entry {

View file

@ -3,6 +3,7 @@
#define _NF_DEFRAG_IPV4_H #define _NF_DEFRAG_IPV4_H
struct net; struct net;
int nf_defrag_ipv4_enable(struct net *); int nf_defrag_ipv4_enable(struct net *net);
void nf_defrag_ipv4_disable(struct net *net);
#endif /* _NF_DEFRAG_IPV4_H */ #endif /* _NF_DEFRAG_IPV4_H */

View file

@ -5,7 +5,8 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
int nf_defrag_ipv6_enable(struct net *); int nf_defrag_ipv6_enable(struct net *net);
void nf_defrag_ipv6_disable(struct net *net);
int nf_ct_frag6_init(void); int nf_ct_frag6_init(void);
void nf_ct_frag6_cleanup(void); void nf_ct_frag6_cleanup(void);

View file

@ -104,8 +104,6 @@ unsigned int
nf_nat_inet_fn(void *priv, struct sk_buff *skb, nf_nat_inet_fn(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state); const struct nf_hook_state *state);
int nf_xfrm_me_harder(struct net *n, struct sk_buff *s, unsigned int family);
static inline int nf_nat_initialized(struct nf_conn *ct, static inline int nf_nat_initialized(struct nf_conn *ct,
enum nf_nat_manip_type manip) enum nf_nat_manip_type manip)
{ {

View file

@ -13,6 +13,7 @@
#include <net/netfilter/nf_flow_table.h> #include <net/netfilter/nf_flow_table.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/flow_offload.h> #include <net/flow_offload.h>
#include <net/netns/generic.h>
#define NFT_MAX_HOOKS (NF_INET_INGRESS + 1) #define NFT_MAX_HOOKS (NF_INET_INGRESS + 1)
@ -1580,4 +1581,11 @@ struct nftables_pernet {
u8 validate_state; u8 validate_state;
}; };
extern unsigned int nf_tables_net_id;
static inline struct nftables_pernet *nft_pernet(const struct net *net)
{
return net_generic(net, nf_tables_net_id);
}
#endif /* _NET_NF_TABLES_H */ #endif /* _NET_NF_TABLES_H */

View file

@ -76,16 +76,6 @@ struct netns_ipv4 {
struct inet_peer_base *peers; struct inet_peer_base *peers;
struct sock * __percpu *tcp_sk; struct sock * __percpu *tcp_sk;
struct fqdir *fqdir; struct fqdir *fqdir;
#ifdef CONFIG_NETFILTER
struct xt_table *iptable_filter;
struct xt_table *iptable_mangle;
struct xt_table *iptable_raw;
struct xt_table *arptable_filter;
#ifdef CONFIG_SECURITY
struct xt_table *iptable_security;
#endif
struct xt_table *nat_table;
#endif
u8 sysctl_icmp_echo_ignore_all; u8 sysctl_icmp_echo_ignore_all;
u8 sysctl_icmp_echo_enable_probe; u8 sysctl_icmp_echo_enable_probe;

View file

@ -63,15 +63,6 @@ struct netns_ipv6 {
struct ipv6_devconf *devconf_dflt; struct ipv6_devconf *devconf_dflt;
struct inet_peer_base *peers; struct inet_peer_base *peers;
struct fqdir *fqdir; struct fqdir *fqdir;
#ifdef CONFIG_NETFILTER
struct xt_table *ip6table_filter;
struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw;
#ifdef CONFIG_SECURITY
struct xt_table *ip6table_security;
#endif
struct xt_table *ip6table_nat;
#endif
struct fib6_info *fib6_null_entry; struct fib6_info *fib6_null_entry;
struct rt6_info *ip6_null_entry; struct rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats; struct rt6_statistics *rt6_stats;

View file

@ -5,16 +5,8 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/netfilter_defs.h> #include <linux/netfilter_defs.h>
struct ebt_table;
struct netns_xt { struct netns_xt {
bool notrack_deprecated_warning; bool notrack_deprecated_warning;
bool clusterip_deprecated_warning; bool clusterip_deprecated_warning;
#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
struct ebt_table *broute_table;
struct ebt_table *frame_filter;
struct ebt_table *frame_nat;
#endif
}; };
#endif #endif

View file

@ -1014,11 +1014,13 @@ enum nft_rt_attributes {
* *
* @NFTA_SOCKET_KEY: socket key to match * @NFTA_SOCKET_KEY: socket key to match
* @NFTA_SOCKET_DREG: destination register * @NFTA_SOCKET_DREG: destination register
* @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
*/ */
enum nft_socket_attributes { enum nft_socket_attributes {
NFTA_SOCKET_UNSPEC, NFTA_SOCKET_UNSPEC,
NFTA_SOCKET_KEY, NFTA_SOCKET_KEY,
NFTA_SOCKET_DREG, NFTA_SOCKET_DREG,
NFTA_SOCKET_LEVEL,
__NFTA_SOCKET_MAX __NFTA_SOCKET_MAX
}; };
#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) #define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
@ -1029,11 +1031,13 @@ enum nft_socket_attributes {
* @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
* @NFT_SOCKET_MARK: Value of the socket mark * @NFT_SOCKET_MARK: Value of the socket mark
* @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0) * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
* @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
*/ */
enum nft_socket_keys { enum nft_socket_keys {
NFT_SOCKET_TRANSPARENT, NFT_SOCKET_TRANSPARENT,
NFT_SOCKET_MARK, NFT_SOCKET_MARK,
NFT_SOCKET_WILDCARD, NFT_SOCKET_WILDCARD,
NFT_SOCKET_CGROUPV2,
__NFT_SOCKET_MAX __NFT_SOCKET_MAX
}; };
#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) #define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)

View file

@ -87,7 +87,7 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* /*
* no conversion function needed -- * no conversion function needed --
* only avg/burst have meaningful values in userspace. * only avg/burst have meaningful values in userspace.
@ -107,7 +107,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.checkentry = ebt_limit_mt_check, .checkentry = ebt_limit_mt_check,
.matchsize = sizeof(struct ebt_limit_info), .matchsize = sizeof(struct ebt_limit_info),
.usersize = offsetof(struct ebt_limit_info, prev), .usersize = offsetof(struct ebt_limit_info, prev),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct ebt_compat_limit_info), .compatsize = sizeof(struct ebt_compat_limit_info),
#endif #endif
.me = THIS_MODULE, .me = THIS_MODULE,

View file

@ -53,7 +53,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_t_info { struct compat_ebt_mark_t_info {
compat_ulong_t mark; compat_ulong_t mark;
compat_uint_t target; compat_uint_t target;
@ -87,7 +87,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.target = ebt_mark_tg, .target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check, .checkentry = ebt_mark_tg_check,
.targetsize = sizeof(struct ebt_mark_t_info), .targetsize = sizeof(struct ebt_mark_t_info),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_t_info), .compatsize = sizeof(struct compat_ebt_mark_t_info),
.compat_from_user = mark_tg_compat_from_user, .compat_from_user = mark_tg_compat_from_user,
.compat_to_user = mark_tg_compat_to_user, .compat_to_user = mark_tg_compat_to_user,

View file

@ -37,7 +37,7 @@ static int ebt_mark_mt_check(const struct xt_mtchk_param *par)
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_m_info { struct compat_ebt_mark_m_info {
compat_ulong_t mark, mask; compat_ulong_t mark, mask;
uint8_t invert, bitmask; uint8_t invert, bitmask;
@ -75,7 +75,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.match = ebt_mark_mt, .match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check, .checkentry = ebt_mark_mt_check,
.matchsize = sizeof(struct ebt_mark_m_info), .matchsize = sizeof(struct ebt_mark_m_info),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_m_info), .compatsize = sizeof(struct compat_ebt_mark_m_info),
.compat_from_user = mark_mt_compat_from_user, .compat_from_user = mark_mt_compat_from_user,
.compat_to_user = mark_mt_compat_to_user, .compat_to_user = mark_mt_compat_to_user,

View file

@ -66,8 +66,7 @@ static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
NFPROTO_BRIDGE, s->in, NULL, NULL, NFPROTO_BRIDGE, s->in, NULL, NULL,
s->net, NULL); s->net, NULL);
ret = ebt_do_table(skb, &state, state.net->xt.broute_table); ret = ebt_do_table(skb, &state, priv);
if (ret != NF_DROP) if (ret != NF_DROP)
return ret; return ret;
@ -101,18 +100,17 @@ static const struct nf_hook_ops ebt_ops_broute = {
static int __net_init broute_net_init(struct net *net) static int __net_init broute_net_init(struct net *net)
{ {
return ebt_register_table(net, &broute_table, &ebt_ops_broute, return ebt_register_table(net, &broute_table, &ebt_ops_broute);
&net->xt.broute_table);
} }
static void __net_exit broute_net_pre_exit(struct net *net) static void __net_exit broute_net_pre_exit(struct net *net)
{ {
ebt_unregister_table_pre_exit(net, "broute", &ebt_ops_broute); ebt_unregister_table_pre_exit(net, "broute");
} }
static void __net_exit broute_net_exit(struct net *net) static void __net_exit broute_net_exit(struct net *net)
{ {
ebt_unregister_table(net, net->xt.broute_table); ebt_unregister_table(net, "broute");
} }
static struct pernet_operations broute_net_ops = { static struct pernet_operations broute_net_ops = {

View file

@ -59,34 +59,27 @@ static const struct ebt_table frame_filter = {
}; };
static unsigned int static unsigned int
ebt_in_hook(void *priv, struct sk_buff *skb, ebt_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ebt_do_table(skb, state, state->net->xt.frame_filter); return ebt_do_table(skb, state, priv);
}
static unsigned int
ebt_out_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
return ebt_do_table(skb, state, state->net->xt.frame_filter);
} }
static const struct nf_hook_ops ebt_ops_filter[] = { static const struct nf_hook_ops ebt_ops_filter[] = {
{ {
.hook = ebt_in_hook, .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_IN, .hooknum = NF_BR_LOCAL_IN,
.priority = NF_BR_PRI_FILTER_BRIDGED, .priority = NF_BR_PRI_FILTER_BRIDGED,
}, },
{ {
.hook = ebt_in_hook, .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_FORWARD, .hooknum = NF_BR_FORWARD,
.priority = NF_BR_PRI_FILTER_BRIDGED, .priority = NF_BR_PRI_FILTER_BRIDGED,
}, },
{ {
.hook = ebt_out_hook, .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT, .hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_FILTER_OTHER, .priority = NF_BR_PRI_FILTER_OTHER,
@ -95,18 +88,17 @@ static const struct nf_hook_ops ebt_ops_filter[] = {
static int __net_init frame_filter_net_init(struct net *net) static int __net_init frame_filter_net_init(struct net *net)
{ {
return ebt_register_table(net, &frame_filter, ebt_ops_filter, return ebt_register_table(net, &frame_filter, ebt_ops_filter);
&net->xt.frame_filter);
} }
static void __net_exit frame_filter_net_pre_exit(struct net *net) static void __net_exit frame_filter_net_pre_exit(struct net *net)
{ {
ebt_unregister_table_pre_exit(net, "filter", ebt_ops_filter); ebt_unregister_table_pre_exit(net, "filter");
} }
static void __net_exit frame_filter_net_exit(struct net *net) static void __net_exit frame_filter_net_exit(struct net *net)
{ {
ebt_unregister_table(net, net->xt.frame_filter); ebt_unregister_table(net, "filter");
} }
static struct pernet_operations frame_filter_net_ops = { static struct pernet_operations frame_filter_net_ops = {

View file

@ -58,35 +58,27 @@ static const struct ebt_table frame_nat = {
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
static unsigned int static unsigned int ebt_nat_hook(void *priv, struct sk_buff *skb,
ebt_nat_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ebt_do_table(skb, state, state->net->xt.frame_nat); return ebt_do_table(skb, state, priv);
}
static unsigned int
ebt_nat_out(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
return ebt_do_table(skb, state, state->net->xt.frame_nat);
} }
static const struct nf_hook_ops ebt_ops_nat[] = { static const struct nf_hook_ops ebt_ops_nat[] = {
{ {
.hook = ebt_nat_out, .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT, .hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_NAT_DST_OTHER, .priority = NF_BR_PRI_NAT_DST_OTHER,
}, },
{ {
.hook = ebt_nat_out, .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_POST_ROUTING, .hooknum = NF_BR_POST_ROUTING,
.priority = NF_BR_PRI_NAT_SRC, .priority = NF_BR_PRI_NAT_SRC,
}, },
{ {
.hook = ebt_nat_in, .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_PRE_ROUTING, .hooknum = NF_BR_PRE_ROUTING,
.priority = NF_BR_PRI_NAT_DST_BRIDGED, .priority = NF_BR_PRI_NAT_DST_BRIDGED,
@ -95,18 +87,17 @@ static const struct nf_hook_ops ebt_ops_nat[] = {
static int __net_init frame_nat_net_init(struct net *net) static int __net_init frame_nat_net_init(struct net *net)
{ {
return ebt_register_table(net, &frame_nat, ebt_ops_nat, return ebt_register_table(net, &frame_nat, ebt_ops_nat);
&net->xt.frame_nat);
} }
static void __net_exit frame_nat_net_pre_exit(struct net *net) static void __net_exit frame_nat_net_pre_exit(struct net *net)
{ {
ebt_unregister_table_pre_exit(net, "nat", ebt_ops_nat); ebt_unregister_table_pre_exit(net, "nat");
} }
static void __net_exit frame_nat_net_exit(struct net *net) static void __net_exit frame_nat_net_exit(struct net *net)
{ {
ebt_unregister_table(net, net->xt.frame_nat); ebt_unregister_table(net, "nat");
} }
static struct pernet_operations frame_nat_net_ops = { static struct pernet_operations frame_nat_net_ops = {

View file

@ -47,7 +47,7 @@ struct ebt_pernet {
static unsigned int ebt_pernet_id __read_mostly; static unsigned int ebt_pernet_id __read_mostly;
static DEFINE_MUTEX(ebt_mutex); static DEFINE_MUTEX(ebt_mutex);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void ebt_standard_compat_from_user(void *dst, const void *src) static void ebt_standard_compat_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
@ -73,7 +73,7 @@ static struct xt_target ebt_standard_target = {
.revision = 0, .revision = 0,
.family = NFPROTO_BRIDGE, .family = NFPROTO_BRIDGE,
.targetsize = sizeof(int), .targetsize = sizeof(int),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = ebt_standard_compat_from_user, .compat_from_user = ebt_standard_compat_from_user,
.compat_to_user = ebt_standard_compat_to_user, .compat_to_user = ebt_standard_compat_to_user,
@ -1136,15 +1136,18 @@ static void __ebt_unregister_table(struct net *net, struct ebt_table *table)
vfree(table->private->entries); vfree(table->private->entries);
ebt_free_table_info(table->private); ebt_free_table_info(table->private);
vfree(table->private); vfree(table->private);
kfree(table->ops);
kfree(table); kfree(table);
} }
int ebt_register_table(struct net *net, const struct ebt_table *input_table, int ebt_register_table(struct net *net, const struct ebt_table *input_table,
const struct nf_hook_ops *ops, struct ebt_table **res) const struct nf_hook_ops *template_ops)
{ {
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
struct ebt_table_info *newinfo; struct ebt_table_info *newinfo;
struct ebt_table *t, *table; struct ebt_table *t, *table;
struct nf_hook_ops *ops;
unsigned int num_ops;
struct ebt_replace_kernel *repl; struct ebt_replace_kernel *repl;
int ret, i, countersize; int ret, i, countersize;
void *p; void *p;
@ -1213,15 +1216,31 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
ret = -ENOENT; ret = -ENOENT;
goto free_unlock; goto free_unlock;
} }
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
goto free_unlock;
}
ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (!ops) {
ret = -ENOMEM;
if (newinfo->nentries)
module_put(table->me);
goto free_unlock;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = table;
list_add(&table->list, &ebt_net->tables); list_add(&table->list, &ebt_net->tables);
mutex_unlock(&ebt_mutex); mutex_unlock(&ebt_mutex);
WRITE_ONCE(*res, table); table->ops = ops;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); ret = nf_register_net_hooks(net, ops, num_ops);
if (ret) { if (ret)
__ebt_unregister_table(net, table); __ebt_unregister_table(net, table);
*res = NULL;
}
audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries,
AUDIT_XT_OP_REGISTER, GFP_KERNEL); AUDIT_XT_OP_REGISTER, GFP_KERNEL);
@ -1257,17 +1276,20 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
return NULL; return NULL;
} }
void ebt_unregister_table_pre_exit(struct net *net, const char *name, const struct nf_hook_ops *ops) void ebt_unregister_table_pre_exit(struct net *net, const char *name)
{ {
struct ebt_table *table = __ebt_find_table(net, name); struct ebt_table *table = __ebt_find_table(net, name);
if (table) if (table)
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
} }
EXPORT_SYMBOL(ebt_unregister_table_pre_exit); EXPORT_SYMBOL(ebt_unregister_table_pre_exit);
void ebt_unregister_table(struct net *net, struct ebt_table *table) void ebt_unregister_table(struct net *net, const char *name)
{ {
struct ebt_table *table = __ebt_find_table(net, name);
if (table)
__ebt_unregister_table(net, table); __ebt_unregister_table(net, table);
} }
@ -1480,7 +1502,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
ebt_entry_to_user, entries, tmp.entries); ebt_entry_to_user, entries, tmp.entries);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* 32 bit-userspace compatibility definitions. */ /* 32 bit-userspace compatibility definitions. */
struct compat_ebt_replace { struct compat_ebt_replace {
char name[EBT_TABLE_MAXNAMELEN]; char name[EBT_TABLE_MAXNAMELEN];
@ -2345,7 +2367,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* try real handler in case userland supplied needed padding */ /* try real handler in case userland supplied needed padding */
if (in_compat_syscall() && if (in_compat_syscall() &&
((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) || ((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) ||
@ -2412,7 +2434,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) { switch (cmd) {
case EBT_SO_SET_ENTRIES: case EBT_SO_SET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(net, arg, len); ret = compat_do_replace(net, arg, len);
else else
@ -2420,7 +2442,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
ret = do_replace(net, arg, len); ret = do_replace(net, arg, len);
break; break;
case EBT_SO_SET_COUNTERS: case EBT_SO_SET_COUNTERS:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_update_counters(net, arg, len); ret = compat_update_counters(net, arg, len);
else else

View file

@ -713,7 +713,7 @@ static int copy_entries_to_user(unsigned int total_size,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src) static void compat_standard_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
@ -800,7 +800,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT; return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0'; name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_lock(NFPROTO_ARP); xt_compat_lock(NFPROTO_ARP);
#endif #endif
@ -808,7 +808,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) { if (!IS_ERR(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_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp; struct xt_table_info tmp;
if (in_compat_syscall()) { if (in_compat_syscall()) {
@ -835,7 +835,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me); module_put(t->me);
} else } else
ret = PTR_ERR(t); ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_unlock(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP);
#endif #endif
@ -1044,7 +1044,7 @@ static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_arpt_replace { struct compat_arpt_replace {
char name[XT_TABLE_MAXNAMELEN]; char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks; u32 valid_hooks;
@ -1412,7 +1412,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) { switch (cmd) {
case ARPT_SO_SET_REPLACE: case ARPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len); ret = compat_do_replace(sock_net(sk), arg, len);
else else
@ -1444,7 +1444,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break; break;
case ARPT_SO_GET_ENTRIES: case ARPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len); ret = compat_get_entries(sock_net(sk), user, len);
else else
@ -1499,10 +1499,11 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table)
int arpt_register_table(struct net *net, int arpt_register_table(struct net *net,
const struct xt_table *table, const struct xt_table *table,
const struct arpt_replace *repl, const struct arpt_replace *repl,
const struct nf_hook_ops *ops, const struct nf_hook_ops *template_ops)
struct xt_table **res)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
@ -1516,40 +1517,60 @@ int arpt_register_table(struct net *net,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table);
goto out_free;
}
/* set res now, will see skbs right after nf_register_net_hooks */
WRITE_ONCE(*res, new_table);
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
if (ret != 0) { if (ret != 0) {
__arpt_unregister_table(net, new_table);
*res = NULL;
}
return ret;
out_free:
xt_free_table_info(newinfo); xt_free_table_info(newinfo);
return ret; return ret;
} }
void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table, new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
xt_free_table_info(newinfo);
return PTR_ERR(new_table);
}
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
goto out_free;
}
ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (!ops) {
ret = -ENOMEM;
goto out_free;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret;
out_free:
__arpt_unregister_table(net, new_table);
return ret;
}
void arpt_unregister_table_pre_exit(struct net *net, const char *name,
const struct nf_hook_ops *ops) const struct nf_hook_ops *ops)
{ {
struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
if (table)
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
} }
EXPORT_SYMBOL(arpt_unregister_table_pre_exit); EXPORT_SYMBOL(arpt_unregister_table_pre_exit);
void arpt_unregister_table(struct net *net, struct xt_table *table) void arpt_unregister_table(struct net *net, const char *name)
{ {
struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
if (table)
__arpt_unregister_table(net, table); __arpt_unregister_table(net, table);
} }
@ -1559,7 +1580,7 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET, .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = NFPROTO_ARP, .family = NFPROTO_ARP,
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user, .compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user, .compat_to_user = compat_standard_to_user,

View file

@ -34,7 +34,7 @@ static unsigned int
arptable_filter_hook(void *priv, struct sk_buff *skb, arptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return arpt_do_table(skb, state, state->net->ipv4.arptable_filter); return arpt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *arpfilter_ops __read_mostly; static struct nf_hook_ops *arpfilter_ops __read_mostly;
@ -44,31 +44,22 @@ static int __net_init arptable_filter_table_init(struct net *net)
struct arpt_replace *repl; struct arpt_replace *repl;
int err; int err;
if (net->ipv4.arptable_filter)
return 0;
repl = arpt_alloc_initial_table(&packet_filter); repl = arpt_alloc_initial_table(&packet_filter);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops, err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops);
&net->ipv4.arptable_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
static void __net_exit arptable_filter_net_pre_exit(struct net *net) static void __net_exit arptable_filter_net_pre_exit(struct net *net)
{ {
if (net->ipv4.arptable_filter) arpt_unregister_table_pre_exit(net, "filter", arpfilter_ops);
arpt_unregister_table_pre_exit(net, net->ipv4.arptable_filter,
arpfilter_ops);
} }
static void __net_exit arptable_filter_net_exit(struct net *net) static void __net_exit arptable_filter_net_exit(struct net *net)
{ {
if (!net->ipv4.arptable_filter) arpt_unregister_table(net, "filter");
return;
arpt_unregister_table(net, net->ipv4.arptable_filter);
net->ipv4.arptable_filter = NULL;
} }
static struct pernet_operations arptable_filter_net_ops = { static struct pernet_operations arptable_filter_net_ops = {

View file

@ -868,7 +868,7 @@ copy_entries_to_user(unsigned int total_size,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src) static void compat_standard_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
@ -957,7 +957,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT; return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0'; name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_lock(AF_INET); xt_compat_lock(AF_INET);
#endif #endif
@ -965,7 +965,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) { if (!IS_ERR(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_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp; struct xt_table_info tmp;
if (in_compat_syscall()) { if (in_compat_syscall()) {
@ -993,7 +993,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me); module_put(t->me);
} else } else
ret = PTR_ERR(t); ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_unlock(AF_INET); xt_compat_unlock(AF_INET);
#endif #endif
@ -1199,7 +1199,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_replace { struct compat_ipt_replace {
char name[XT_TABLE_MAXNAMELEN]; char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks; u32 valid_hooks;
@ -1621,7 +1621,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) { switch (cmd) {
case IPT_SO_SET_REPLACE: case IPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len); ret = compat_do_replace(sock_net(sk), arg, len);
else else
@ -1654,7 +1654,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
case IPT_SO_GET_ENTRIES: case IPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len); ret = compat_get_entries(sock_net(sk), user, len);
else else
@ -1716,9 +1716,11 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table)
int ipt_register_table(struct net *net, const struct xt_table *table, int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl, const struct ipt_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res) const struct nf_hook_ops *template_ops)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
@ -1732,49 +1734,64 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table);
goto out_free;
}
/* set res now, will see skbs right after nf_register_net_hooks */
WRITE_ONCE(*res, new_table);
if (!ops)
return 0;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
if (ret != 0) { if (ret != 0) {
__ipt_unregister_table(net, new_table);
*res = NULL;
}
return ret;
out_free:
xt_free_table_info(newinfo); xt_free_table_info(newinfo);
return ret; return ret;
} }
void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table, new_table = xt_register_table(net, table, &bootstrap, newinfo);
const struct nf_hook_ops *ops) if (IS_ERR(new_table)) {
{ xt_free_table_info(newinfo);
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); return PTR_ERR(new_table);
} }
void ipt_unregister_table_exit(struct net *net, struct xt_table *table) /* No template? No need to do anything. This is used by 'nat' table, it registers
{ * with the nat core instead of the netfilter core.
__ipt_unregister_table(net, table); */
if (!template_ops)
return 0;
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
goto out_free;
} }
void ipt_unregister_table(struct net *net, struct xt_table *table, ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
const struct nf_hook_ops *ops) if (!ops) {
ret = -ENOMEM;
goto out_free;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret;
out_free:
__ipt_unregister_table(net, new_table);
return ret;
}
void ipt_unregister_table_pre_exit(struct net *net, const char *name)
{ {
if (ops) struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
ipt_unregister_table_pre_exit(net, table, ops);
if (table)
nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
void ipt_unregister_table_exit(struct net *net, const char *name)
{
struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
if (table)
__ipt_unregister_table(net, table); __ipt_unregister_table(net, table);
} }
@ -1829,7 +1846,7 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET, .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user, .compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user, .compat_to_user = compat_standard_to_user,
@ -1924,7 +1941,6 @@ static void __exit ip_tables_fini(void)
} }
EXPORT_SYMBOL(ipt_register_table); EXPORT_SYMBOL(ipt_register_table);
EXPORT_SYMBOL(ipt_unregister_table);
EXPORT_SYMBOL(ipt_unregister_table_pre_exit); EXPORT_SYMBOL(ipt_unregister_table_pre_exit);
EXPORT_SYMBOL(ipt_unregister_table_exit); EXPORT_SYMBOL(ipt_unregister_table_exit);
EXPORT_SYMBOL(ipt_do_table); EXPORT_SYMBOL(ipt_do_table);

View file

@ -541,7 +541,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
nf_ct_netns_put(par->net, par->family); nf_ct_netns_put(par->net, par->family);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_clusterip_tgt_info struct compat_ipt_clusterip_tgt_info
{ {
u_int32_t flags; u_int32_t flags;
@ -553,7 +553,7 @@ struct compat_ipt_clusterip_tgt_info
u_int32_t hash_initval; u_int32_t hash_initval;
compat_uptr_t config; compat_uptr_t config;
}; };
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_target clusterip_tg_reg __read_mostly = { static struct xt_target clusterip_tg_reg __read_mostly = {
.name = "CLUSTERIP", .name = "CLUSTERIP",
@ -563,9 +563,9 @@ static struct xt_target clusterip_tg_reg __read_mostly = {
.destroy = clusterip_tg_destroy, .destroy = clusterip_tg_destroy,
.targetsize = sizeof(struct ipt_clusterip_tgt_info), .targetsize = sizeof(struct ipt_clusterip_tgt_info),
.usersize = offsetof(struct ipt_clusterip_tgt_info, config), .usersize = offsetof(struct ipt_clusterip_tgt_info, config),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ipt_clusterip_tgt_info), .compatsize = sizeof(struct compat_ipt_clusterip_tgt_info),
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
.me = THIS_MODULE .me = THIS_MODULE
}; };

View file

@ -34,7 +34,7 @@ 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)
{ {
return ipt_do_table(skb, state, state->net->ipv4.iptable_filter); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *filter_ops __read_mostly; static struct nf_hook_ops *filter_ops __read_mostly;
@ -48,9 +48,6 @@ static int __net_init iptable_filter_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int err; int err;
if (net->ipv4.iptable_filter)
return 0;
repl = ipt_alloc_initial_table(&packet_filter); repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
@ -58,8 +55,7 @@ static int __net_init iptable_filter_table_init(struct net *net)
((struct ipt_standard *)repl->entries)[1].target.verdict = ((struct ipt_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ipt_register_table(net, &packet_filter, repl, filter_ops, err = ipt_register_table(net, &packet_filter, repl, filter_ops);
&net->ipv4.iptable_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
@ -74,17 +70,12 @@ static int __net_init iptable_filter_net_init(struct net *net)
static void __net_exit iptable_filter_net_pre_exit(struct net *net) static void __net_exit iptable_filter_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_filter) ipt_unregister_table_pre_exit(net, "filter");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_filter,
filter_ops);
} }
static void __net_exit iptable_filter_net_exit(struct net *net) static void __net_exit iptable_filter_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_filter) ipt_unregister_table_exit(net, "filter");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_filter);
net->ipv4.iptable_filter = NULL;
} }
static struct pernet_operations iptable_filter_net_ops = { static struct pernet_operations iptable_filter_net_ops = {

View file

@ -37,7 +37,7 @@ static const struct xt_table packet_mangler = {
}; };
static unsigned int static unsigned int
ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{ {
unsigned int ret; unsigned int ret;
const struct iphdr *iph; const struct iphdr *iph;
@ -53,7 +53,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
daddr = iph->daddr; daddr = iph->daddr;
tos = iph->tos; tos = iph->tos;
ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle); ret = ipt_do_table(skb, state, priv);
/* Reroute for ANY change. */ /* Reroute for ANY change. */
if (ret != NF_DROP && ret != NF_STOLEN) { if (ret != NF_DROP && ret != NF_STOLEN) {
iph = ip_hdr(skb); iph = ip_hdr(skb);
@ -78,8 +78,8 @@ iptable_mangle_hook(void *priv,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT) if (state->hook == NF_INET_LOCAL_OUT)
return ipt_mangle_out(skb, state); return ipt_mangle_out(skb, state, priv);
return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *mangle_ops __read_mostly; static struct nf_hook_ops *mangle_ops __read_mostly;
@ -88,31 +88,22 @@ static int __net_init iptable_mangle_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int ret; int ret;
if (net->ipv4.iptable_mangle)
return 0;
repl = ipt_alloc_initial_table(&packet_mangler); repl = ipt_alloc_initial_table(&packet_mangler);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops, ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops);
&net->ipv4.iptable_mangle);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit iptable_mangle_net_pre_exit(struct net *net) static void __net_exit iptable_mangle_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_mangle) ipt_unregister_table_pre_exit(net, "mangle");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_mangle,
mangle_ops);
} }
static void __net_exit iptable_mangle_net_exit(struct net *net) static void __net_exit iptable_mangle_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_mangle) ipt_unregister_table_exit(net, "mangle");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_mangle);
net->ipv4.iptable_mangle = NULL;
} }
static struct pernet_operations iptable_mangle_net_ops = { static struct pernet_operations iptable_mangle_net_ops = {

View file

@ -13,8 +13,14 @@
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
struct iptable_nat_pernet {
struct nf_hook_ops *nf_nat_ops;
};
static int __net_init iptable_nat_table_init(struct net *net); static int __net_init iptable_nat_table_init(struct net *net);
static unsigned int iptable_nat_net_id __read_mostly;
static const struct xt_table nf_nat_ipv4_table = { static const struct xt_table nf_nat_ipv4_table = {
.name = "nat", .name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) | .valid_hooks = (1 << NF_INET_PRE_ROUTING) |
@ -30,7 +36,7 @@ static unsigned int iptable_nat_do_chain(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ipt_do_table(skb, state, state->net->ipv4.nat_table); return ipt_do_table(skb, state, priv);
} }
static const struct nf_hook_ops nf_nat_ipv4_ops[] = { static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
@ -62,27 +68,49 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
static int ipt_nat_register_lookups(struct net *net) static int ipt_nat_register_lookups(struct net *net)
{ {
struct iptable_nat_pernet *xt_nat_net;
struct nf_hook_ops *ops;
struct xt_table *table;
int i, ret; int i, ret;
xt_nat_net = net_generic(net, iptable_nat_net_id);
table = xt_find_table(net, NFPROTO_IPV4, "nat");
if (WARN_ON_ONCE(!table))
return -ENOENT;
ops = kmemdup(nf_nat_ipv4_ops, sizeof(nf_nat_ipv4_ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) { for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) {
ret = nf_nat_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]); ops[i].priv = table;
ret = nf_nat_ipv4_register_fn(net, &ops[i]);
if (ret) { if (ret) {
while (i) while (i)
nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]); nf_nat_ipv4_unregister_fn(net, &ops[--i]);
kfree(ops);
return ret; return ret;
} }
} }
xt_nat_net->nf_nat_ops = ops;
return 0; return 0;
} }
static void ipt_nat_unregister_lookups(struct net *net) static void ipt_nat_unregister_lookups(struct net *net)
{ {
struct iptable_nat_pernet *xt_nat_net = net_generic(net, iptable_nat_net_id);
struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops;
int i; int i;
if (!ops)
return;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]); nf_nat_ipv4_unregister_fn(net, &ops[i]);
kfree(ops);
} }
static int __net_init iptable_nat_table_init(struct net *net) static int __net_init iptable_nat_table_init(struct net *net)
@ -90,24 +118,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int ret; int ret;
if (net->ipv4.nat_table)
return 0;
repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
NULL, &net->ipv4.nat_table); ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, NULL);
if (ret < 0) { if (ret < 0) {
kfree(repl); kfree(repl);
return ret; return ret;
} }
ret = ipt_nat_register_lookups(net); ret = ipt_nat_register_lookups(net);
if (ret < 0) { if (ret < 0)
ipt_unregister_table(net, net->ipv4.nat_table, NULL); ipt_unregister_table_exit(net, "nat");
net->ipv4.nat_table = NULL;
}
kfree(repl); kfree(repl);
return ret; return ret;
@ -115,21 +138,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
static void __net_exit iptable_nat_net_pre_exit(struct net *net) static void __net_exit iptable_nat_net_pre_exit(struct net *net)
{ {
if (net->ipv4.nat_table)
ipt_nat_unregister_lookups(net); ipt_nat_unregister_lookups(net);
} }
static void __net_exit iptable_nat_net_exit(struct net *net) static void __net_exit iptable_nat_net_exit(struct net *net)
{ {
if (!net->ipv4.nat_table) ipt_unregister_table_exit(net, "nat");
return;
ipt_unregister_table_exit(net, net->ipv4.nat_table);
net->ipv4.nat_table = NULL;
} }
static struct pernet_operations iptable_nat_net_ops = { static struct pernet_operations iptable_nat_net_ops = {
.pre_exit = iptable_nat_net_pre_exit, .pre_exit = iptable_nat_net_pre_exit,
.exit = iptable_nat_net_exit, .exit = iptable_nat_net_exit,
.id = &iptable_nat_net_id,
.size = sizeof(struct iptable_nat_pernet),
}; };
static int __init iptable_nat_init(void) static int __init iptable_nat_init(void)

View file

@ -41,7 +41,7 @@ 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)
{ {
return ipt_do_table(skb, state, state->net->ipv4.iptable_raw); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *rawtable_ops __read_mostly; static struct nf_hook_ops *rawtable_ops __read_mostly;
@ -55,31 +55,22 @@ static int __net_init iptable_raw_table_init(struct net *net)
if (raw_before_defrag) if (raw_before_defrag)
table = &packet_raw_before_defrag; table = &packet_raw_before_defrag;
if (net->ipv4.iptable_raw)
return 0;
repl = ipt_alloc_initial_table(table); repl = ipt_alloc_initial_table(table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, table, repl, rawtable_ops, ret = ipt_register_table(net, table, repl, rawtable_ops);
&net->ipv4.iptable_raw);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit iptable_raw_net_pre_exit(struct net *net) static void __net_exit iptable_raw_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_raw) ipt_unregister_table_pre_exit(net, "raw");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_raw,
rawtable_ops);
} }
static void __net_exit iptable_raw_net_exit(struct net *net) static void __net_exit iptable_raw_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_raw) ipt_unregister_table_exit(net, "raw");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_raw);
net->ipv4.iptable_raw = NULL;
} }
static struct pernet_operations iptable_raw_net_ops = { static struct pernet_operations iptable_raw_net_ops = {

View file

@ -40,7 +40,7 @@ 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)
{ {
return ipt_do_table(skb, state, state->net->ipv4.iptable_security); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *sectbl_ops __read_mostly; static struct nf_hook_ops *sectbl_ops __read_mostly;
@ -50,31 +50,22 @@ static int __net_init iptable_security_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int ret; int ret;
if (net->ipv4.iptable_security)
return 0;
repl = ipt_alloc_initial_table(&security_table); repl = ipt_alloc_initial_table(&security_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, &security_table, repl, sectbl_ops, ret = ipt_register_table(net, &security_table, repl, sectbl_ops);
&net->ipv4.iptable_security);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit iptable_security_net_pre_exit(struct net *net) static void __net_exit iptable_security_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_security) ipt_unregister_table_pre_exit(net, "security");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_security,
sectbl_ops);
} }
static void __net_exit iptable_security_net_exit(struct net *net) static void __net_exit iptable_security_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_security) ipt_unregister_table_exit(net, "security");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_security);
net->ipv4.iptable_security = NULL;
} }
static struct pernet_operations iptable_security_net_ops = { static struct pernet_operations iptable_security_net_ops = {

View file

@ -141,14 +141,16 @@ int nf_defrag_ipv4_enable(struct net *net)
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id); struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
int err = 0; int err = 0;
might_sleep();
if (nf_defrag->users)
return 0;
mutex_lock(&defrag4_mutex); mutex_lock(&defrag4_mutex);
if (nf_defrag->users) if (nf_defrag->users == UINT_MAX) {
err = -EOVERFLOW;
goto out_unlock; goto out_unlock;
}
if (nf_defrag->users) {
nf_defrag->users++;
goto out_unlock;
}
err = nf_register_net_hooks(net, ipv4_defrag_ops, err = nf_register_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops)); ARRAY_SIZE(ipv4_defrag_ops));
@ -161,6 +163,22 @@ int nf_defrag_ipv4_enable(struct net *net)
} }
EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable); EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
void nf_defrag_ipv4_disable(struct net *net)
{
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
mutex_lock(&defrag4_mutex);
if (nf_defrag->users) {
nf_defrag->users--;
if (nf_defrag->users == 0)
nf_unregister_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops));
}
mutex_unlock(&defrag4_mutex);
}
EXPORT_SYMBOL_GPL(nf_defrag_ipv4_disable);
module_init(nf_defrag_init); module_init(nf_defrag_init);
module_exit(nf_defrag_fini); module_exit(nf_defrag_fini);

View file

@ -884,7 +884,7 @@ copy_entries_to_user(unsigned int total_size,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src) static void compat_standard_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
@ -973,7 +973,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT; return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0'; name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_lock(AF_INET6); xt_compat_lock(AF_INET6);
#endif #endif
@ -981,7 +981,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) { if (!IS_ERR(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_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp; struct xt_table_info tmp;
if (in_compat_syscall()) { if (in_compat_syscall()) {
@ -1009,7 +1009,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me); module_put(t->me);
} else } else
ret = PTR_ERR(t); ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_unlock(AF_INET6); xt_compat_unlock(AF_INET6);
#endif #endif
@ -1215,7 +1215,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ip6t_replace { struct compat_ip6t_replace {
char name[XT_TABLE_MAXNAMELEN]; char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks; u32 valid_hooks;
@ -1630,7 +1630,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) { switch (cmd) {
case IP6T_SO_SET_REPLACE: case IP6T_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len); ret = compat_do_replace(sock_net(sk), arg, len);
else else
@ -1663,7 +1663,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
case IP6T_SO_GET_ENTRIES: case IP6T_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len); ret = compat_get_entries(sock_net(sk), user, len);
else else
@ -1725,10 +1725,11 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table)
int ip6t_register_table(struct net *net, const struct xt_table *table, int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl, const struct ip6t_replace *repl,
const struct nf_hook_ops *ops, const struct nf_hook_ops *template_ops)
struct xt_table **res)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
@ -1742,49 +1743,61 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table);
goto out_free;
}
/* set res now, will see skbs right after nf_register_net_hooks */
WRITE_ONCE(*res, new_table);
if (!ops)
return 0;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
if (ret != 0) { if (ret != 0) {
__ip6t_unregister_table(net, new_table);
*res = NULL;
}
return ret;
out_free:
xt_free_table_info(newinfo); xt_free_table_info(newinfo);
return ret; return ret;
} }
void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table, new_table = xt_register_table(net, table, &bootstrap, newinfo);
const struct nf_hook_ops *ops) if (IS_ERR(new_table)) {
{ xt_free_table_info(newinfo);
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); return PTR_ERR(new_table);
} }
void ip6t_unregister_table_exit(struct net *net, struct xt_table *table) if (!template_ops)
{ return 0;
__ip6t_unregister_table(net, table);
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
goto out_free;
} }
void ip6t_unregister_table(struct net *net, struct xt_table *table, ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
const struct nf_hook_ops *ops) if (!ops) {
ret = -ENOMEM;
goto out_free;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret;
out_free:
__ip6t_unregister_table(net, new_table);
return ret;
}
void ip6t_unregister_table_pre_exit(struct net *net, const char *name)
{ {
if (ops) struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
ip6t_unregister_table_pre_exit(net, table, ops);
if (table)
nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
void ip6t_unregister_table_exit(struct net *net, const char *name)
{
struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
if (table)
__ip6t_unregister_table(net, table); __ip6t_unregister_table(net, table);
} }
@ -1840,7 +1853,7 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET, .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user, .compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user, .compat_to_user = compat_standard_to_user,
@ -1935,7 +1948,6 @@ static void __exit ip6_tables_fini(void)
} }
EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_register_table);
EXPORT_SYMBOL(ip6t_unregister_table);
EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); EXPORT_SYMBOL(ip6t_unregister_table_pre_exit);
EXPORT_SYMBOL(ip6t_unregister_table_exit); EXPORT_SYMBOL(ip6t_unregister_table_exit);
EXPORT_SYMBOL(ip6t_do_table); EXPORT_SYMBOL(ip6t_do_table);

View file

@ -35,7 +35,7 @@ static unsigned int
ip6table_filter_hook(void *priv, struct sk_buff *skb, ip6table_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_filter); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *filter_ops __read_mostly; static struct nf_hook_ops *filter_ops __read_mostly;
@ -49,9 +49,6 @@ static int __net_init ip6table_filter_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int err; int err;
if (net->ipv6.ip6table_filter)
return 0;
repl = ip6t_alloc_initial_table(&packet_filter); repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
@ -59,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net)
((struct ip6t_standard *)repl->entries)[1].target.verdict = ((struct ip6t_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ip6t_register_table(net, &packet_filter, repl, filter_ops, err = ip6t_register_table(net, &packet_filter, repl, filter_ops);
&net->ipv6.ip6table_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
@ -75,17 +71,12 @@ static int __net_init ip6table_filter_net_init(struct net *net)
static void __net_exit ip6table_filter_net_pre_exit(struct net *net) static void __net_exit ip6table_filter_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_filter) ip6t_unregister_table_pre_exit(net, "filter");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_filter,
filter_ops);
} }
static void __net_exit ip6table_filter_net_exit(struct net *net) static void __net_exit ip6table_filter_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_filter) ip6t_unregister_table_exit(net, "filter");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_filter);
net->ipv6.ip6table_filter = NULL;
} }
static struct pernet_operations ip6table_filter_net_ops = { static struct pernet_operations ip6table_filter_net_ops = {

View file

@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = {
}; };
static unsigned int static unsigned int
ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{ {
unsigned int ret; unsigned int ret;
struct in6_addr saddr, daddr; struct in6_addr saddr, daddr;
@ -49,7 +49,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
/* flowlabel and prio (includes version, which shouldn't change either */ /* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb)); flowlabel = *((u_int32_t *)ipv6_hdr(skb));
ret = ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); ret = ip6t_do_table(skb, state, priv);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) || (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) ||
@ -71,8 +71,8 @@ ip6table_mangle_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) if (state->hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, state); return ip6t_mangle_out(skb, state, priv);
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *mangle_ops __read_mostly; static struct nf_hook_ops *mangle_ops __read_mostly;
@ -81,32 +81,22 @@ static int __net_init ip6table_mangle_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int ret; int ret;
if (net->ipv6.ip6table_mangle)
return 0;
repl = ip6t_alloc_initial_table(&packet_mangler); repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops, ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops);
&net->ipv6.ip6table_mangle);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) static void __net_exit ip6table_mangle_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_mangle) ip6t_unregister_table_pre_exit(net, "mangle");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_mangle,
mangle_ops);
} }
static void __net_exit ip6table_mangle_net_exit(struct net *net) static void __net_exit ip6table_mangle_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_mangle) ip6t_unregister_table_exit(net, "mangle");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_mangle);
net->ipv6.ip6table_mangle = NULL;
} }
static struct pernet_operations ip6table_mangle_net_ops = { static struct pernet_operations ip6table_mangle_net_ops = {

View file

@ -15,8 +15,14 @@
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
struct ip6table_nat_pernet {
struct nf_hook_ops *nf_nat_ops;
};
static int __net_init ip6table_nat_table_init(struct net *net); static int __net_init ip6table_nat_table_init(struct net *net);
static unsigned int ip6table_nat_net_id __read_mostly;
static const struct xt_table nf_nat_ipv6_table = { static const struct xt_table nf_nat_ipv6_table = {
.name = "nat", .name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) | .valid_hooks = (1 << NF_INET_PRE_ROUTING) |
@ -32,7 +38,7 @@ static unsigned int ip6table_nat_do_chain(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_nat); return ip6t_do_table(skb, state, priv);
} }
static const struct nf_hook_ops nf_nat_ipv6_ops[] = { static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
@ -64,27 +70,49 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
static int ip6t_nat_register_lookups(struct net *net) static int ip6t_nat_register_lookups(struct net *net)
{ {
struct ip6table_nat_pernet *xt_nat_net;
struct nf_hook_ops *ops;
struct xt_table *table;
int i, ret; int i, ret;
table = xt_find_table(net, NFPROTO_IPV6, "nat");
if (WARN_ON_ONCE(!table))
return -ENOENT;
xt_nat_net = net_generic(net, ip6table_nat_net_id);
ops = kmemdup(nf_nat_ipv6_ops, sizeof(nf_nat_ipv6_ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) { for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) {
ret = nf_nat_ipv6_register_fn(net, &nf_nat_ipv6_ops[i]); ops[i].priv = table;
ret = nf_nat_ipv6_register_fn(net, &ops[i]);
if (ret) { if (ret) {
while (i) while (i)
nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[--i]); nf_nat_ipv6_unregister_fn(net, &ops[--i]);
kfree(ops);
return ret; return ret;
} }
} }
xt_nat_net->nf_nat_ops = ops;
return 0; return 0;
} }
static void ip6t_nat_unregister_lookups(struct net *net) static void ip6t_nat_unregister_lookups(struct net *net)
{ {
struct ip6table_nat_pernet *xt_nat_net = net_generic(net, ip6table_nat_net_id);
struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops;
int i; int i;
if (!ops)
return;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[i]); nf_nat_ipv6_unregister_fn(net, &ops[i]);
kfree(ops);
} }
static int __net_init ip6table_nat_table_init(struct net *net) static int __net_init ip6table_nat_table_init(struct net *net)
@ -92,45 +120,39 @@ static int __net_init ip6table_nat_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int ret; int ret;
if (net->ipv6.ip6table_nat)
return 0;
repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl, ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
NULL, &net->ipv6.ip6table_nat); NULL);
if (ret < 0) { if (ret < 0) {
kfree(repl); kfree(repl);
return ret; return ret;
} }
ret = ip6t_nat_register_lookups(net); ret = ip6t_nat_register_lookups(net);
if (ret < 0) { if (ret < 0)
ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL); ip6t_unregister_table_exit(net, "nat");
net->ipv6.ip6table_nat = NULL;
}
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_nat_net_pre_exit(struct net *net) static void __net_exit ip6table_nat_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_nat)
ip6t_nat_unregister_lookups(net); ip6t_nat_unregister_lookups(net);
} }
static void __net_exit ip6table_nat_net_exit(struct net *net) static void __net_exit ip6table_nat_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_nat) ip6t_unregister_table_exit(net, "nat");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_nat);
net->ipv6.ip6table_nat = NULL;
} }
static struct pernet_operations ip6table_nat_net_ops = { static struct pernet_operations ip6table_nat_net_ops = {
.pre_exit = ip6table_nat_net_pre_exit, .pre_exit = ip6table_nat_net_pre_exit,
.exit = ip6table_nat_net_exit, .exit = ip6table_nat_net_exit,
.id = &ip6table_nat_net_id,
.size = sizeof(struct ip6table_nat_pernet),
}; };
static int __init ip6table_nat_init(void) static int __init ip6table_nat_init(void)

View file

@ -40,7 +40,7 @@ static unsigned int
ip6table_raw_hook(void *priv, struct sk_buff *skb, ip6table_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_raw); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *rawtable_ops __read_mostly; static struct nf_hook_ops *rawtable_ops __read_mostly;
@ -54,31 +54,22 @@ static int __net_init ip6table_raw_table_init(struct net *net)
if (raw_before_defrag) if (raw_before_defrag)
table = &packet_raw_before_defrag; table = &packet_raw_before_defrag;
if (net->ipv6.ip6table_raw)
return 0;
repl = ip6t_alloc_initial_table(table); repl = ip6t_alloc_initial_table(table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, table, repl, rawtable_ops, ret = ip6t_register_table(net, table, repl, rawtable_ops);
&net->ipv6.ip6table_raw);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_raw_net_pre_exit(struct net *net) static void __net_exit ip6table_raw_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_raw) ip6t_unregister_table_pre_exit(net, "raw");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_raw,
rawtable_ops);
} }
static void __net_exit ip6table_raw_net_exit(struct net *net) static void __net_exit ip6table_raw_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_raw) ip6t_unregister_table_exit(net, "raw");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_raw);
net->ipv6.ip6table_raw = NULL;
} }
static struct pernet_operations ip6table_raw_net_ops = { static struct pernet_operations ip6table_raw_net_ops = {

View file

@ -39,7 +39,7 @@ static unsigned int
ip6table_security_hook(void *priv, struct sk_buff *skb, ip6table_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_security); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *sectbl_ops __read_mostly; static struct nf_hook_ops *sectbl_ops __read_mostly;
@ -49,31 +49,22 @@ static int __net_init ip6table_security_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int ret; int ret;
if (net->ipv6.ip6table_security)
return 0;
repl = ip6t_alloc_initial_table(&security_table); repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &security_table, repl, sectbl_ops, ret = ip6t_register_table(net, &security_table, repl, sectbl_ops);
&net->ipv6.ip6table_security);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_security_net_pre_exit(struct net *net) static void __net_exit ip6table_security_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_security) ip6t_unregister_table_pre_exit(net, "security");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_security,
sectbl_ops);
} }
static void __net_exit ip6table_security_net_exit(struct net *net) static void __net_exit ip6table_security_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_security) ip6t_unregister_table_exit(net, "security");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_security);
net->ipv6.ip6table_security = NULL;
} }
static struct pernet_operations ip6table_security_net_ops = { static struct pernet_operations ip6table_security_net_ops = {

View file

@ -137,14 +137,16 @@ int nf_defrag_ipv6_enable(struct net *net)
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id); struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
int err = 0; int err = 0;
might_sleep();
if (nf_frag->users)
return 0;
mutex_lock(&defrag6_mutex); mutex_lock(&defrag6_mutex);
if (nf_frag->users) if (nf_frag->users == UINT_MAX) {
err = -EOVERFLOW;
goto out_unlock; goto out_unlock;
}
if (nf_frag->users) {
nf_frag->users++;
goto out_unlock;
}
err = nf_register_net_hooks(net, ipv6_defrag_ops, err = nf_register_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops)); ARRAY_SIZE(ipv6_defrag_ops));
@ -157,6 +159,21 @@ int nf_defrag_ipv6_enable(struct net *net)
} }
EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
void nf_defrag_ipv6_disable(struct net *net)
{
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
mutex_lock(&defrag6_mutex);
if (nf_frag->users) {
nf_frag->users--;
if (nf_frag->users == 0)
nf_unregister_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops));
}
mutex_unlock(&defrag6_mutex);
}
EXPORT_SYMBOL_GPL(nf_defrag_ipv6_disable);
module_init(nf_defrag_init); module_init(nf_defrag_init);
module_exit(nf_defrag_fini); module_exit(nf_defrag_fini);

View file

@ -728,6 +728,16 @@ config NETFILTER_XTABLES
if NETFILTER_XTABLES if NETFILTER_XTABLES
config NETFILTER_XTABLES_COMPAT
bool "Netfilter Xtables 32bit support"
depends on COMPAT
default y
help
This option provides a translation layer to run 32bit arp,ip(6),ebtables
binaries on 64bit kernels.
If unsure, say N.
comment "Xtables combined modules" comment "Xtables combined modules"
config NETFILTER_XT_MARK config NETFILTER_XT_MARK

View file

@ -1031,26 +1031,22 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
return 0; return 0;
} }
static int ip_set_none(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_none(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int ip_set_create(struct net *net, struct sock *ctnl, static int ip_set_create(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set, *clash = NULL; struct ip_set *set, *clash = NULL;
ip_set_id_t index = IPSET_INVALID_ID; ip_set_id_t index = IPSET_INVALID_ID;
struct nlattr *tb[IPSET_ATTR_CREATE_MAX + 1] = {}; struct nlattr *tb[IPSET_ATTR_CREATE_MAX + 1] = {};
const char *name, *typename; const char *name, *typename;
u8 family, revision; u8 family, revision;
u32 flags = flag_exist(nlh); u32 flags = flag_exist(info->nlh);
int ret = 0; int ret = 0;
if (unlikely(protocol_min_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
@ -1101,7 +1097,7 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
/* Set create flags depending on the type revision */ /* Set create flags depending on the type revision */
set->flags |= set->type->create_flags[revision]; set->flags |= set->type->create_flags[revision];
ret = set->type->create(net, set, tb, flags); ret = set->type->create(info->net, set, tb, flags);
if (ret != 0) if (ret != 0)
goto put_out; goto put_out;
@ -1183,12 +1179,10 @@ ip_set_destroy_set(struct ip_set *set)
kfree(set); kfree(set);
} }
static int ip_set_destroy(struct net *net, struct sock *ctnl, static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *s; struct ip_set *s;
ip_set_id_t i; ip_set_id_t i;
int ret = 0; int ret = 0;
@ -1230,7 +1224,7 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
/* Modified by ip_set_destroy() only, which is serialized */ /* Modified by ip_set_destroy() only, which is serialized */
inst->is_destroyed = false; inst->is_destroyed = false;
} else { } else {
u32 flags = flag_exist(nlh); u32 flags = flag_exist(info->nlh);
s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
&i); &i);
if (!s) { if (!s) {
@ -1264,12 +1258,10 @@ ip_set_flush_set(struct ip_set *set)
ip_set_unlock(set); ip_set_unlock(set);
} }
static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_flush(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *s; struct ip_set *s;
ip_set_id_t i; ip_set_id_t i;
@ -1304,12 +1296,10 @@ ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = {
.len = IPSET_MAXNAMELEN - 1 }, .len = IPSET_MAXNAMELEN - 1 },
}; };
static int ip_set_rename(struct net *net, struct sock *ctnl, static int ip_set_rename(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set, *s; struct ip_set *set, *s;
const char *name2; const char *name2;
ip_set_id_t i; ip_set_id_t i;
@ -1354,12 +1344,10 @@ static int ip_set_rename(struct net *net, struct sock *ctnl,
* so the ip_set_list always contains valid pointers to the sets. * so the ip_set_list always contains valid pointers to the sets.
*/ */
static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *from, *to; struct ip_set *from, *to;
ip_set_id_t from_id, to_id; ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN]; char from_name[IPSET_MAXNAMELEN];
@ -1669,10 +1657,8 @@ ip_set_dump_do(struct sk_buff *skb, struct netlink_callback *cb)
return ret < 0 ? ret : skb->len; return ret < 0 ? ret : skb->len;
} }
static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_dump(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
if (unlikely(protocol_min_failed(attr))) if (unlikely(protocol_min_failed(attr)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@ -1683,7 +1669,7 @@ static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
.dump = ip_set_dump_do, .dump = ip_set_dump_do,
.done = ip_set_dump_done, .done = ip_set_dump_done,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
} }
@ -1817,30 +1803,24 @@ static int ip_set_ad(struct net *net, struct sock *ctnl,
return ret; return ret;
} }
static int ip_set_uadd(struct net *net, struct sock *ctnl, static int ip_set_uadd(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
return ip_set_ad(net, ctnl, skb, return ip_set_ad(info->net, info->sk, skb,
IPSET_ADD, nlh, attr, extack); IPSET_ADD, info->nlh, attr, info->extack);
} }
static int ip_set_udel(struct net *net, struct sock *ctnl, static int ip_set_udel(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
return ip_set_ad(net, ctnl, skb, return ip_set_ad(info->net, info->sk, skb,
IPSET_DEL, nlh, attr, extack); IPSET_DEL, info->nlh, attr, info->extack);
} }
static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_utest(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {}; struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
int ret = 0; int ret = 0;
@ -1872,12 +1852,10 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
/* Get headed data of a set */ /* Get headed data of a set */
static int ip_set_header(struct net *net, struct sock *ctnl, static int ip_set_header(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
const struct ip_set *set; const struct ip_set *set;
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
@ -1895,7 +1873,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
if (!skb2) if (!skb2)
return -ENOMEM; return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_HEADER); IPSET_CMD_HEADER);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
@ -1907,7 +1885,8 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
goto nla_put_failure; goto nla_put_failure;
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1929,10 +1908,8 @@ static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_FAMILY] = { .type = NLA_U8 }, [IPSET_ATTR_FAMILY] = { .type = NLA_U8 },
}; };
static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_type(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
@ -1955,7 +1932,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
if (!skb2) if (!skb2)
return -ENOMEM; return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_TYPE); IPSET_CMD_TYPE);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
@ -1968,7 +1945,8 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len); pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1988,10 +1966,8 @@ ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 }, [IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
}; };
static int ip_set_protocol(struct net *net, struct sock *ctnl, static int ip_set_protocol(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
@ -2004,7 +1980,7 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
if (!skb2) if (!skb2)
return -ENOMEM; return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_PROTOCOL); IPSET_CMD_PROTOCOL);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
@ -2014,7 +1990,8 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
goto nla_put_failure; goto nla_put_failure;
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -2029,12 +2006,10 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
/* Get set by name or index, from userspace */ /* Get set by name or index, from userspace */
static int ip_set_byname(struct net *net, struct sock *ctnl, static int ip_set_byname(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
ip_set_id_t id = IPSET_INVALID_ID; ip_set_id_t id = IPSET_INVALID_ID;
@ -2053,7 +2028,7 @@ static int ip_set_byname(struct net *net, struct sock *ctnl,
if (!skb2) if (!skb2)
return -ENOMEM; return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_GET_BYNAME); IPSET_CMD_GET_BYNAME);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
@ -2063,7 +2038,8 @@ static int ip_set_byname(struct net *net, struct sock *ctnl,
goto nla_put_failure; goto nla_put_failure;
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -2081,12 +2057,10 @@ static const struct nla_policy ip_set_index_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_INDEX] = { .type = NLA_U16 }, [IPSET_ATTR_INDEX] = { .type = NLA_U16 },
}; };
static int ip_set_byindex(struct net *net, struct sock *ctnl, static int ip_set_byindex(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const attr[])
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{ {
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(info->net);
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
ip_set_id_t id = IPSET_INVALID_ID; ip_set_id_t id = IPSET_INVALID_ID;
@ -2108,7 +2082,7 @@ static int ip_set_byindex(struct net *net, struct sock *ctnl,
if (!skb2) if (!skb2)
return -ENOMEM; return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_GET_BYINDEX); IPSET_CMD_GET_BYINDEX);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
@ -2117,7 +2091,8 @@ static int ip_set_byindex(struct net *net, struct sock *ctnl,
goto nla_put_failure; goto nla_put_failure;
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -2133,80 +2108,96 @@ static int ip_set_byindex(struct net *net, struct sock *ctnl,
static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = { static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
[IPSET_CMD_NONE] = { [IPSET_CMD_NONE] = {
.call = ip_set_none, .call = ip_set_none,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
}, },
[IPSET_CMD_CREATE] = { [IPSET_CMD_CREATE] = {
.call = ip_set_create, .call = ip_set_create,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_create_policy, .policy = ip_set_create_policy,
}, },
[IPSET_CMD_DESTROY] = { [IPSET_CMD_DESTROY] = {
.call = ip_set_destroy, .call = ip_set_destroy,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy, .policy = ip_set_setname_policy,
}, },
[IPSET_CMD_FLUSH] = { [IPSET_CMD_FLUSH] = {
.call = ip_set_flush, .call = ip_set_flush,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy, .policy = ip_set_setname_policy,
}, },
[IPSET_CMD_RENAME] = { [IPSET_CMD_RENAME] = {
.call = ip_set_rename, .call = ip_set_rename,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname2_policy, .policy = ip_set_setname2_policy,
}, },
[IPSET_CMD_SWAP] = { [IPSET_CMD_SWAP] = {
.call = ip_set_swap, .call = ip_set_swap,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname2_policy, .policy = ip_set_setname2_policy,
}, },
[IPSET_CMD_LIST] = { [IPSET_CMD_LIST] = {
.call = ip_set_dump, .call = ip_set_dump,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_dump_policy, .policy = ip_set_dump_policy,
}, },
[IPSET_CMD_SAVE] = { [IPSET_CMD_SAVE] = {
.call = ip_set_dump, .call = ip_set_dump,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy, .policy = ip_set_setname_policy,
}, },
[IPSET_CMD_ADD] = { [IPSET_CMD_ADD] = {
.call = ip_set_uadd, .call = ip_set_uadd,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy, .policy = ip_set_adt_policy,
}, },
[IPSET_CMD_DEL] = { [IPSET_CMD_DEL] = {
.call = ip_set_udel, .call = ip_set_udel,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy, .policy = ip_set_adt_policy,
}, },
[IPSET_CMD_TEST] = { [IPSET_CMD_TEST] = {
.call = ip_set_utest, .call = ip_set_utest,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy, .policy = ip_set_adt_policy,
}, },
[IPSET_CMD_HEADER] = { [IPSET_CMD_HEADER] = {
.call = ip_set_header, .call = ip_set_header,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy, .policy = ip_set_setname_policy,
}, },
[IPSET_CMD_TYPE] = { [IPSET_CMD_TYPE] = {
.call = ip_set_type, .call = ip_set_type,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_type_policy, .policy = ip_set_type_policy,
}, },
[IPSET_CMD_PROTOCOL] = { [IPSET_CMD_PROTOCOL] = {
.call = ip_set_protocol, .call = ip_set_protocol,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_protocol_policy, .policy = ip_set_protocol_policy,
}, },
[IPSET_CMD_GET_BYNAME] = { [IPSET_CMD_GET_BYNAME] = {
.call = ip_set_byname, .call = ip_set_byname,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy, .policy = ip_set_setname_policy,
}, },
[IPSET_CMD_GET_BYINDEX] = { [IPSET_CMD_GET_BYINDEX] = {
.call = ip_set_byindex, .call = ip_set_byindex,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_index_policy, .policy = ip_set_index_policy,
}, },

View file

@ -1524,17 +1524,15 @@ static int ctnetlink_flush_conntrack(struct net *net,
return 0; return 0;
} }
static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, static int ctnetlink_del_conntrack(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conn *ct;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nf_conntrack_zone zone; struct nf_conntrack_zone zone;
struct nf_conn *ct;
int err; int err;
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@ -1550,15 +1548,15 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
else { else {
u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC; u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC;
return ctnetlink_flush_conntrack(net, cda, return ctnetlink_flush_conntrack(info->net, cda,
NETLINK_CB(skb).portid, NETLINK_CB(skb).portid,
nlmsg_report(nlh), u3); nlmsg_report(info->nlh), u3);
} }
if (err < 0) if (err < 0)
return err; return err;
h = nf_conntrack_find_get(net, &zone, &tuple); h = nf_conntrack_find_get(info->net, &zone, &tuple);
if (!h) if (!h)
return -ENOENT; return -ENOENT;
@ -1578,28 +1576,26 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
} }
} }
nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(nlh)); nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(info->nlh));
nf_ct_put(ct); nf_ct_put(ct);
return 0; return 0;
} }
static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl, static int ctnetlink_get_conntrack(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conn *ct;
struct sk_buff *skb2 = NULL;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone; struct nf_conntrack_zone zone;
struct sk_buff *skb2;
struct nf_conn *ct;
int err; int err;
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.start = ctnetlink_start, .start = ctnetlink_start,
.dump = ctnetlink_dump_table, .dump = ctnetlink_dump_table,
@ -1607,7 +1603,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
.data = (void *)cda, .data = (void *)cda,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@ -1626,7 +1622,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
if (err < 0) if (err < 0)
return err; return err;
h = nf_conntrack_find_get(net, &zone, &tuple); h = nf_conntrack_find_get(info->net, &zone, &tuple);
if (!h) if (!h)
return -ENOENT; return -ENOENT;
@ -1639,13 +1635,16 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
return -ENOMEM; return -ENOMEM;
} }
err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid,
NFNL_MSG_TYPE(nlh->nlmsg_type), ct, true, 0); info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type), ct,
true, 0);
nf_ct_put(ct); nf_ct_put(ct);
if (err <= 0) if (err <= 0)
goto free; goto free;
err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (err < 0) if (err < 0)
goto out; goto out;
@ -1743,18 +1742,16 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
return ctnetlink_dump_list(skb, cb, true); return ctnetlink_dump_list(skb, cb, true);
} }
static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl, static int ctnetlink_get_ct_dying(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_dump_dying, .dump = ctnetlink_dump_dying,
.done = ctnetlink_done_list, .done = ctnetlink_done_list,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -1766,18 +1763,16 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
return ctnetlink_dump_list(skb, cb, false); return ctnetlink_dump_list(skb, cb, false);
} }
static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl, static int ctnetlink_get_ct_unconfirmed(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_dump_unconfirmed, .dump = ctnetlink_dump_unconfirmed,
.done = ctnetlink_done_list, .done = ctnetlink_done_list,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -2374,18 +2369,16 @@ ctnetlink_create_conntrack(struct net *net,
return ERR_PTR(err); return ERR_PTR(err);
} }
static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, static int ctnetlink_new_conntrack(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_tuple_hash *h = NULL; struct nf_conntrack_tuple_hash *h = NULL;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nf_conn *ct;
u_int8_t u3 = nfmsg->nfgen_family; u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone; struct nf_conntrack_zone zone;
struct nf_conn *ct;
int err; int err;
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@ -2407,13 +2400,13 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
} }
if (cda[CTA_TUPLE_ORIG]) if (cda[CTA_TUPLE_ORIG])
h = nf_conntrack_find_get(net, &zone, &otuple); h = nf_conntrack_find_get(info->net, &zone, &otuple);
else if (cda[CTA_TUPLE_REPLY]) else if (cda[CTA_TUPLE_REPLY])
h = nf_conntrack_find_get(net, &zone, &rtuple); h = nf_conntrack_find_get(info->net, &zone, &rtuple);
if (h == NULL) { if (h == NULL) {
err = -ENOENT; err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE) { if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
enum ip_conntrack_events events; enum ip_conntrack_events events;
if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY]) if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY])
@ -2421,8 +2414,8 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
if (otuple.dst.protonum != rtuple.dst.protonum) if (otuple.dst.protonum != rtuple.dst.protonum)
return -EINVAL; return -EINVAL;
ct = ctnetlink_create_conntrack(net, &zone, cda, &otuple, ct = ctnetlink_create_conntrack(info->net, &zone, cda,
&rtuple, u3); &otuple, &rtuple, u3);
if (IS_ERR(ct)) if (IS_ERR(ct))
return PTR_ERR(ct); return PTR_ERR(ct);
@ -2445,7 +2438,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_SYNPROXY) | (1 << IPCT_SYNPROXY) |
events, events,
ct, NETLINK_CB(skb).portid, ct, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(info->nlh));
nf_ct_put(ct); nf_ct_put(ct);
} }
@ -2455,7 +2448,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
err = -EEXIST; err = -EEXIST;
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { if (!(info->nlh->nlmsg_flags & NLM_F_EXCL)) {
err = ctnetlink_change_conntrack(ct, cda); err = ctnetlink_change_conntrack(ct, cda);
if (err == 0) { if (err == 0) {
nf_conntrack_eventmask_report((1 << IPCT_REPLY) | nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
@ -2467,7 +2460,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_MARK) | (1 << IPCT_MARK) |
(1 << IPCT_SYNPROXY), (1 << IPCT_SYNPROXY),
ct, NETLINK_CB(skb).portid, ct, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(info->nlh));
} }
} }
@ -2539,17 +2532,15 @@ ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl, static int ctnetlink_stat_ct_cpu(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_ct_stat_cpu_dump, .dump = ctnetlink_ct_stat_cpu_dump,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
return 0; return 0;
@ -2585,10 +2576,8 @@ ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
return -1; return -1;
} }
static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl, static int ctnetlink_stat_ct(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
int err; int err;
@ -2598,13 +2587,14 @@ static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
return -ENOMEM; return -ENOMEM;
err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).portid, err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_TYPE(info->nlh->nlmsg_type),
sock_net(skb->sk)); sock_net(skb->sk));
if (err <= 0) if (err <= 0)
goto free; goto free;
err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (err < 0) if (err < 0)
goto out; goto out;
@ -3284,29 +3274,29 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
return err; return err;
} }
static int ctnetlink_get_expect(struct net *net, struct sock *ctnl, static int ctnetlink_get_expect(struct sk_buff *skb,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nfnl_info *info,
const struct nlattr * const cda[], const struct nlattr * const cda[])
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
struct sk_buff *skb2;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone; struct nf_conntrack_zone zone;
struct sk_buff *skb2;
int err; int err;
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
if (cda[CTA_EXPECT_MASTER]) if (cda[CTA_EXPECT_MASTER])
return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda, return ctnetlink_dump_exp_ct(info->net, info->sk, skb,
extack); info->nlh, cda,
info->extack);
else { else {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_exp_dump_table, .dump = ctnetlink_exp_dump_table,
.done = ctnetlink_exp_done, .done = ctnetlink_exp_done,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
} }
@ -3326,7 +3316,7 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
if (err < 0) if (err < 0)
return err; return err;
exp = nf_ct_expect_find_get(net, &zone, &tuple); exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
if (!exp) if (!exp)
return -ENOENT; return -ENOENT;
@ -3348,13 +3338,15 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
rcu_read_lock(); rcu_read_lock();
err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid, err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp); info->nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
exp);
rcu_read_unlock(); rcu_read_unlock();
nf_ct_expect_put(exp); nf_ct_expect_put(exp);
if (err <= 0) if (err <= 0)
goto free; goto free;
err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (err < 0) if (err < 0)
goto out; goto out;
@ -3382,15 +3374,14 @@ static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
return true; return true;
} }
static int ctnetlink_del_expect(struct net *net, struct sock *ctnl, static int ctnetlink_del_expect(struct sk_buff *skb,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nfnl_info *info,
const struct nlattr * const cda[], const struct nlattr * const cda[])
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone; struct nf_conntrack_zone zone;
int err; int err;
@ -3406,7 +3397,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
return err; return err;
/* bump usage count to 2 */ /* bump usage count to 2 */
exp = nf_ct_expect_find_get(net, &zone, &tuple); exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
if (!exp) if (!exp)
return -ENOENT; return -ENOENT;
@ -3422,7 +3413,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
spin_lock_bh(&nf_conntrack_expect_lock); spin_lock_bh(&nf_conntrack_expect_lock);
if (del_timer(&exp->timeout)) { if (del_timer(&exp->timeout)) {
nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(info->nlh));
nf_ct_expect_put(exp); nf_ct_expect_put(exp);
} }
spin_unlock_bh(&nf_conntrack_expect_lock); spin_unlock_bh(&nf_conntrack_expect_lock);
@ -3432,14 +3423,14 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
} else if (cda[CTA_EXPECT_HELP_NAME]) { } else if (cda[CTA_EXPECT_HELP_NAME]) {
char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]); char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
nf_ct_expect_iterate_net(net, expect_iter_name, name, nf_ct_expect_iterate_net(info->net, expect_iter_name, name,
NETLINK_CB(skb).portid, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(info->nlh));
} else { } else {
/* This basically means we have to flush everything*/ /* This basically means we have to flush everything*/
nf_ct_expect_iterate_net(net, expect_iter_all, NULL, nf_ct_expect_iterate_net(info->net, expect_iter_all, NULL,
NETLINK_CB(skb).portid, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(info->nlh));
} }
return 0; return 0;
@ -3635,15 +3626,14 @@ ctnetlink_create_expect(struct net *net,
return err; return err;
} }
static int ctnetlink_new_expect(struct net *net, struct sock *ctnl, static int ctnetlink_new_expect(struct sk_buff *skb,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nfnl_info *info,
const struct nlattr * const cda[], const struct nlattr * const cda[])
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone; struct nf_conntrack_zone zone;
int err; int err;
@ -3662,20 +3652,20 @@ static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
return err; return err;
spin_lock_bh(&nf_conntrack_expect_lock); spin_lock_bh(&nf_conntrack_expect_lock);
exp = __nf_ct_expect_find(net, &zone, &tuple); exp = __nf_ct_expect_find(info->net, &zone, &tuple);
if (!exp) { if (!exp) {
spin_unlock_bh(&nf_conntrack_expect_lock); spin_unlock_bh(&nf_conntrack_expect_lock);
err = -ENOENT; err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE) { if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
err = ctnetlink_create_expect(net, &zone, cda, u3, err = ctnetlink_create_expect(info->net, &zone, cda, u3,
NETLINK_CB(skb).portid, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(info->nlh));
} }
return err; return err;
} }
err = -EEXIST; err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) if (!(info->nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_expect(exp, cda); err = ctnetlink_change_expect(exp, cda);
spin_unlock_bh(&nf_conntrack_expect_lock); spin_unlock_bh(&nf_conntrack_expect_lock);
@ -3736,17 +3726,15 @@ ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl, static int ctnetlink_stat_exp_cpu(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_exp_stat_cpu_dump, .dump = ctnetlink_exp_stat_cpu_dump,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
return 0; return 0;
@ -3763,35 +3751,71 @@ static struct nf_exp_event_notifier ctnl_notifier_exp = {
#endif #endif
static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, [IPCTNL_MSG_CT_NEW] = {
.call = ctnetlink_new_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX, .attr_count = CTA_MAX,
.policy = ct_nla_policy }, .policy = ct_nla_policy
[IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, },
[IPCTNL_MSG_CT_GET] = {
.call = ctnetlink_get_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX, .attr_count = CTA_MAX,
.policy = ct_nla_policy }, .policy = ct_nla_policy
[IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, },
[IPCTNL_MSG_CT_DELETE] = {
.call = ctnetlink_del_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX, .attr_count = CTA_MAX,
.policy = ct_nla_policy }, .policy = ct_nla_policy
[IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, },
[IPCTNL_MSG_CT_GET_CTRZERO] = {
.call = ctnetlink_get_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX, .attr_count = CTA_MAX,
.policy = ct_nla_policy }, .policy = ct_nla_policy
[IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu }, },
[IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct }, [IPCTNL_MSG_CT_GET_STATS_CPU] = {
[IPCTNL_MSG_CT_GET_DYING] = { .call = ctnetlink_get_ct_dying }, .call = ctnetlink_stat_ct_cpu,
[IPCTNL_MSG_CT_GET_UNCONFIRMED] = { .call = ctnetlink_get_ct_unconfirmed }, .type = NFNL_CB_MUTEX,
},
[IPCTNL_MSG_CT_GET_STATS] = {
.call = ctnetlink_stat_ct,
.type = NFNL_CB_MUTEX,
},
[IPCTNL_MSG_CT_GET_DYING] = {
.call = ctnetlink_get_ct_dying,
.type = NFNL_CB_MUTEX,
},
[IPCTNL_MSG_CT_GET_UNCONFIRMED] = {
.call = ctnetlink_get_ct_unconfirmed,
.type = NFNL_CB_MUTEX,
},
}; };
static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
[IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, [IPCTNL_MSG_EXP_GET] = {
.call = ctnetlink_get_expect,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_EXPECT_MAX, .attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy }, .policy = exp_nla_policy
[IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, },
[IPCTNL_MSG_EXP_NEW] = {
.call = ctnetlink_new_expect,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_EXPECT_MAX, .attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy }, .policy = exp_nla_policy
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, },
[IPCTNL_MSG_EXP_DELETE] = {
.call = ctnetlink_del_expect,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_EXPECT_MAX, .attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy }, .policy = exp_nla_policy
[IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu }, },
[IPCTNL_MSG_EXP_GET_STATS_CPU] = {
.call = ctnetlink_stat_exp_cpu,
.type = NFNL_CB_MUTEX,
},
}; };
static const struct nfnetlink_subsystem ctnl_subsys = { static const struct nfnetlink_subsystem ctnl_subsys = {

View file

@ -536,15 +536,19 @@ static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
mutex_lock(&nf_ct_proto_mutex); mutex_lock(&nf_ct_proto_mutex);
switch (nfproto) { switch (nfproto) {
case NFPROTO_IPV4: case NFPROTO_IPV4:
if (cnet->users4 && (--cnet->users4 == 0)) if (cnet->users4 && (--cnet->users4 == 0)) {
nf_unregister_net_hooks(net, ipv4_conntrack_ops, nf_unregister_net_hooks(net, ipv4_conntrack_ops,
ARRAY_SIZE(ipv4_conntrack_ops)); ARRAY_SIZE(ipv4_conntrack_ops));
nf_defrag_ipv4_disable(net);
}
break; break;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case NFPROTO_IPV6: case NFPROTO_IPV6:
if (cnet->users6 && (--cnet->users6 == 0)) if (cnet->users6 && (--cnet->users6 == 0)) {
nf_unregister_net_hooks(net, ipv6_conntrack_ops, nf_unregister_net_hooks(net, ipv6_conntrack_ops,
ARRAY_SIZE(ipv6_conntrack_ops)); ARRAY_SIZE(ipv6_conntrack_ops));
nf_defrag_ipv6_disable(net);
}
break; break;
#endif #endif
case NFPROTO_BRIDGE: case NFPROTO_BRIDGE:

View file

@ -1011,6 +1011,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net)
nf_log_unset(net, &nf_arp_logger); nf_log_unset(net, &nf_arp_logger);
nf_log_unset(net, &nf_ip6_logger); nf_log_unset(net, &nf_ip6_logger);
nf_log_unset(net, &nf_netdev_logger); nf_log_unset(net, &nf_netdev_logger);
nf_log_unset(net, &nf_bridge_logger);
} }
static struct pernet_operations nf_log_syslog_net_ops = { static struct pernet_operations nf_log_syslog_net_ops = {

View file

@ -146,43 +146,6 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
return; return;
} }
} }
int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
{
struct flowi fl;
unsigned int hh_len;
struct dst_entry *dst;
struct sock *sk = skb->sk;
int err;
err = xfrm_decode_session(skb, &fl, family);
if (err < 0)
return err;
dst = skb_dst(skb);
if (dst->xfrm)
dst = ((struct xfrm_dst *)dst)->route;
if (!dst_hold_safe(dst))
return -EHOSTUNREACH;
if (sk && !net_eq(net, sock_net(sk)))
sk = NULL;
dst = xfrm_lookup(net, dst, &fl, sk, 0);
if (IS_ERR(dst))
return PTR_ERR(dst);
skb_dst_drop(skb);
skb_dst_set(skb, dst);
/* Change in oif may mean change in hh_len. */
hh_len = skb_dst(skb)->dev->hard_header_len;
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
return -ENOMEM;
return 0;
}
EXPORT_SYMBOL(nf_xfrm_me_harder);
#endif /* CONFIG_XFRM */ #endif /* CONFIG_XFRM */
/* We keep an extra hash for each conntrack, for fast searching. */ /* We keep an extra hash for each conntrack, for fast searching. */

View file

@ -659,6 +659,44 @@ nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb,
return ret; return ret;
} }
#ifdef CONFIG_XFRM
static int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
{
struct sock *sk = skb->sk;
struct dst_entry *dst;
unsigned int hh_len;
struct flowi fl;
int err;
err = xfrm_decode_session(skb, &fl, family);
if (err < 0)
return err;
dst = skb_dst(skb);
if (dst->xfrm)
dst = ((struct xfrm_dst *)dst)->route;
if (!dst_hold_safe(dst))
return -EHOSTUNREACH;
if (sk && !net_eq(net, sock_net(sk)))
sk = NULL;
dst = xfrm_lookup(net, dst, &fl, sk, 0);
if (IS_ERR(dst))
return PTR_ERR(dst);
skb_dst_drop(skb);
skb_dst_set(skb, dst);
/* Change in oif may mean change in hh_len. */
hh_len = skb_dst(skb)->dev->hard_header_len;
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
return -ENOMEM;
return 0;
}
#endif
static unsigned int static unsigned int
nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb, nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)

File diff suppressed because it is too large Load diff

View file

@ -7,8 +7,6 @@
#include <net/netfilter/nf_tables_offload.h> #include <net/netfilter/nf_tables_offload.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
extern unsigned int nf_tables_net_id;
static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions) static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
{ {
struct nft_flow_rule *flow; struct nft_flow_rule *flow;
@ -389,7 +387,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND, nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
basechain, &extack); basechain, &extack);
nft_net = net_generic(net, nf_tables_net_id); nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex); mutex_lock(&nft_net->commit_mutex);
list_del(&block_cb->driver_list); list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list); list_move(&block_cb->list, &bo.cb_list);
@ -490,7 +488,7 @@ static int nft_flow_offload_chain(struct nft_chain *chain, u8 *ppolicy,
static void nft_flow_rule_offload_abort(struct net *net, static void nft_flow_rule_offload_abort(struct net *net,
struct nft_trans *trans) struct nft_trans *trans)
{ {
struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); struct nftables_pernet *nft_net = nft_pernet(net);
int err = 0; int err = 0;
list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) { list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) {
@ -539,7 +537,7 @@ static void nft_flow_rule_offload_abort(struct net *net,
int nft_flow_rule_offload_commit(struct net *net) int nft_flow_rule_offload_commit(struct net *net)
{ {
struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans; struct nft_trans *trans;
int err = 0; int err = 0;
u8 policy; u8 policy;
@ -663,7 +661,7 @@ static int nft_offload_netdev_event(struct notifier_block *this,
if (event != NETDEV_UNREGISTER) if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE; return NOTIFY_DONE;
nft_net = net_generic(net, nf_tables_net_id); nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex); mutex_lock(&nft_net->commit_mutex);
chain = __nft_offload_get_chain(nft_net, dev); chain = __nft_offload_get_chain(nft_net, dev);
if (chain) if (chain)

View file

@ -252,6 +252,12 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *attr = (void *)nlh + min_len; struct nlattr *attr = (void *)nlh + min_len;
int attrlen = nlh->nlmsg_len - min_len; int attrlen = nlh->nlmsg_len - min_len;
__u8 subsys_id = NFNL_SUBSYS_ID(type); __u8 subsys_id = NFNL_SUBSYS_ID(type);
struct nfnl_info info = {
.net = net,
.sk = nfnlnet->nfnl,
.nlh = nlh,
.extack = extack,
};
/* Sanity-check NFNL_MAX_ATTR_COUNT */ /* Sanity-check NFNL_MAX_ATTR_COUNT */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) { if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
@ -267,24 +273,30 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
return err; return err;
} }
if (nc->call_rcu) { if (!nc->call) {
err = nc->call_rcu(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
extack);
rcu_read_unlock(); rcu_read_unlock();
} else { return -EINVAL;
}
switch (nc->type) {
case NFNL_CB_RCU:
err = nc->call(skb, &info, (const struct nlattr **)cda);
rcu_read_unlock();
break;
case NFNL_CB_MUTEX:
rcu_read_unlock(); rcu_read_unlock();
nfnl_lock(subsys_id); nfnl_lock(subsys_id);
if (nfnl_dereference_protected(subsys_id) != ss || if (nfnl_dereference_protected(subsys_id) != ss ||
nfnetlink_find_client(type, ss) != nc) nfnetlink_find_client(type, ss) != nc) {
err = -EAGAIN; err = -EAGAIN;
else if (nc->call) break;
err = nc->call(net, nfnlnet->nfnl, skb, nlh, }
(const struct nlattr **)cda, err = nc->call(skb, &info, (const struct nlattr **)cda);
extack);
else
err = -EINVAL;
nfnl_unlock(subsys_id); nfnl_unlock(subsys_id);
break;
default:
err = -EINVAL;
break;
} }
if (err == -EAGAIN) if (err == -EAGAIN)
goto replay; goto replay;
@ -462,12 +474,24 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
goto ack; goto ack;
} }
if (nc->type != NFNL_CB_BATCH) {
err = -EINVAL;
goto ack;
}
{ {
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); struct nfnl_net *nfnlnet = nfnl_pernet(net);
struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1]; struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
struct nlattr *attr = (void *)nlh + min_len; struct nlattr *attr = (void *)nlh + min_len;
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
int attrlen = nlh->nlmsg_len - min_len; int attrlen = nlh->nlmsg_len - min_len;
struct nfnl_info info = {
.net = net,
.sk = nfnlnet->nfnl,
.nlh = nlh,
.extack = &extack,
};
/* Sanity-check NFTA_MAX_ATTR */ /* Sanity-check NFTA_MAX_ATTR */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) { if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
@ -482,13 +506,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0) if (err < 0)
goto ack; goto ack;
if (nc->call_batch) { err = nc->call(skb, &info, (const struct nlattr **)cda);
struct nfnl_net *nfnlnet = nfnl_pernet(net);
err = nc->call_batch(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
&extack);
}
/* The lock was released to autoload some module, we /* The lock was released to autoload some module, we
* have to abort and start from scratch using the * have to abort and start from scratch using the

View file

@ -56,15 +56,13 @@ static inline struct nfnl_acct_net *nfnl_acct_pernet(struct net *net)
#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ #define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
static int nfnl_acct_new(struct net *net, struct sock *nfnl, static int nfnl_acct_new(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
struct nf_acct *nfacct, *matching = NULL; struct nf_acct *nfacct, *matching = NULL;
char *acct_name;
unsigned int size = 0; unsigned int size = 0;
char *acct_name;
u32 flags = 0; u32 flags = 0;
if (!tb[NFACCT_NAME]) if (!tb[NFACCT_NAME])
@ -78,7 +76,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0) if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
continue; continue;
if (nlh->nlmsg_flags & NLM_F_EXCL) if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST; return -EEXIST;
matching = nfacct; matching = nfacct;
@ -86,7 +84,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
} }
if (matching) { if (matching) {
if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
/* reset counters if you request a replacement. */ /* reset counters if you request a replacement. */
atomic64_set(&matching->pkts, 0); atomic64_set(&matching->pkts, 0);
atomic64_set(&matching->bytes, 0); atomic64_set(&matching->bytes, 0);
@ -273,17 +271,15 @@ static int nfnl_acct_start(struct netlink_callback *cb)
return 0; return 0;
} }
static int nfnl_acct_get(struct net *net, struct sock *nfnl, static int nfnl_acct_get(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
int ret = -ENOENT; int ret = -ENOENT;
struct nf_acct *cur; struct nf_acct *cur;
char *acct_name; char *acct_name;
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = nfnl_acct_dump, .dump = nfnl_acct_dump,
.start = nfnl_acct_start, .start = nfnl_acct_start,
@ -291,7 +287,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
.data = (void *)tb[NFACCT_FILTER], .data = (void *)tb[NFACCT_FILTER],
}; };
return netlink_dump_start(nfnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
if (!tb[NFACCT_NAME]) if (!tb[NFACCT_NAME])
@ -311,14 +307,14 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
} }
ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid, ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_ACCT_NEW, cur); NFNL_MSG_ACCT_NEW, cur);
if (ret <= 0) { if (ret <= 0) {
kfree_skb(skb2); kfree_skb(skb2);
break; break;
} }
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT); MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
@ -347,12 +343,10 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
return ret; return ret;
} }
static int nfnl_acct_del(struct net *net, struct sock *nfnl, static int nfnl_acct_del(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
struct nf_acct *cur, *tmp; struct nf_acct *cur, *tmp;
int ret = -ENOENT; int ret = -ENOENT;
char *acct_name; char *acct_name;
@ -388,18 +382,30 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
}; };
static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
[NFNL_MSG_ACCT_NEW] = { .call = nfnl_acct_new, [NFNL_MSG_ACCT_NEW] = {
.call = nfnl_acct_new,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX, .attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy }, .policy = nfnl_acct_policy
[NFNL_MSG_ACCT_GET] = { .call = nfnl_acct_get, },
[NFNL_MSG_ACCT_GET] = {
.call = nfnl_acct_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX, .attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy }, .policy = nfnl_acct_policy
[NFNL_MSG_ACCT_GET_CTRZERO] = { .call = nfnl_acct_get, },
[NFNL_MSG_ACCT_GET_CTRZERO] = {
.call = nfnl_acct_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX, .attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy }, .policy = nfnl_acct_policy
[NFNL_MSG_ACCT_DEL] = { .call = nfnl_acct_del, },
[NFNL_MSG_ACCT_DEL] = {
.call = nfnl_acct_del,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX, .attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy }, .policy = nfnl_acct_policy
},
}; };
static const struct nfnetlink_subsystem nfnl_acct_subsys = { static const struct nfnetlink_subsystem nfnl_acct_subsys = {

View file

@ -408,10 +408,8 @@ nfnl_cthelper_update(const struct nlattr * const tb[],
return 0; return 0;
} }
static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
const char *helper_name; const char *helper_name;
struct nf_conntrack_helper *cur, *helper = NULL; struct nf_conntrack_helper *cur, *helper = NULL;
@ -441,7 +439,7 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
tuple.dst.protonum != cur->tuple.dst.protonum)) tuple.dst.protonum != cur->tuple.dst.protonum))
continue; continue;
if (nlh->nlmsg_flags & NLM_F_EXCL) if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST; return -EEXIST;
helper = cur; helper = cur;
@ -607,10 +605,8 @@ nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
int ret = -ENOENT; int ret = -ENOENT;
struct nf_conntrack_helper *cur; struct nf_conntrack_helper *cur;
@ -623,11 +619,11 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = nfnl_cthelper_dump_table, .dump = nfnl_cthelper_dump_table,
}; };
return netlink_dump_start(nfnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
if (tb[NFCTH_NAME]) if (tb[NFCTH_NAME])
@ -659,15 +655,15 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
} }
ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid, ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_CTHELPER_NEW, cur); NFNL_MSG_CTHELPER_NEW, cur);
if (ret <= 0) { if (ret <= 0) {
kfree_skb(skb2); kfree_skb(skb2);
break; break;
} }
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT); MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
@ -678,10 +674,8 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
return ret; return ret;
} }
static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
char *helper_name = NULL; char *helper_name = NULL;
struct nf_conntrack_helper *cur; struct nf_conntrack_helper *cur;
@ -743,15 +737,24 @@ static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
}; };
static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = { static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
[NFNL_MSG_CTHELPER_NEW] = { .call = nfnl_cthelper_new, [NFNL_MSG_CTHELPER_NEW] = {
.call = nfnl_cthelper_new,
.type = NFNL_CB_MUTEX,
.attr_count = NFCTH_MAX, .attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy }, .policy = nfnl_cthelper_policy
[NFNL_MSG_CTHELPER_GET] = { .call = nfnl_cthelper_get, },
[NFNL_MSG_CTHELPER_GET] = {
.call = nfnl_cthelper_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFCTH_MAX, .attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy }, .policy = nfnl_cthelper_policy
[NFNL_MSG_CTHELPER_DEL] = { .call = nfnl_cthelper_del, },
[NFNL_MSG_CTHELPER_DEL] = {
.call = nfnl_cthelper_del,
.type = NFNL_CB_MUTEX,
.attr_count = NFCTH_MAX, .attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy }, .policy = nfnl_cthelper_policy
},
}; };
static const struct nfnetlink_subsystem nfnl_cthelper_subsys = { static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {

View file

@ -83,13 +83,11 @@ ctnl_timeout_parse_policy(void *timeout,
return ret; return ret;
} }
static int cttimeout_new_timeout(struct net *net, struct sock *ctnl, static int cttimeout_new_timeout(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net); struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
__u16 l3num; __u16 l3num;
__u8 l4num; __u8 l4num;
const struct nf_conntrack_l4proto *l4proto; const struct nf_conntrack_l4proto *l4proto;
@ -111,7 +109,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
continue; continue;
if (nlh->nlmsg_flags & NLM_F_EXCL) if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST; return -EEXIST;
matching = timeout; matching = timeout;
@ -119,7 +117,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
} }
if (matching) { if (matching) {
if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
/* You cannot replace one timeout policy by another of /* You cannot replace one timeout policy by another of
* different kind, sorry. * different kind, sorry.
*/ */
@ -129,7 +127,8 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
return ctnl_timeout_parse_policy(&matching->timeout.data, return ctnl_timeout_parse_policy(&matching->timeout.data,
matching->timeout.l4proto, matching->timeout.l4proto,
net, cda[CTA_TIMEOUT_DATA]); info->net,
cda[CTA_TIMEOUT_DATA]);
} }
return -EBUSY; return -EBUSY;
@ -150,8 +149,8 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
goto err_proto_put; goto err_proto_put;
} }
ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto, net, ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto,
cda[CTA_TIMEOUT_DATA]); info->net, cda[CTA_TIMEOUT_DATA]);
if (ret < 0) if (ret < 0)
goto err; goto err;
@ -248,22 +247,20 @@ ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static int cttimeout_get_timeout(struct net *net, struct sock *ctnl, static int cttimeout_get_timeout(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net); struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
int ret = -ENOENT; int ret = -ENOENT;
char *name; char *name;
struct ctnl_timeout *cur; struct ctnl_timeout *cur;
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnl_timeout_dump, .dump = ctnl_timeout_dump,
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
if (!cda[CTA_TIMEOUT_NAME]) if (!cda[CTA_TIMEOUT_NAME])
@ -283,14 +280,14 @@ static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
} }
ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid, ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_TYPE(info->nlh->nlmsg_type),
IPCTNL_MSG_TIMEOUT_NEW, cur); IPCTNL_MSG_TIMEOUT_NEW, cur);
if (ret <= 0) { if (ret <= 0) {
kfree_skb(skb2); kfree_skb(skb2);
break; break;
} }
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT); MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
@ -320,13 +317,11 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
return ret; return ret;
} }
static int cttimeout_del_timeout(struct net *net, struct sock *ctnl, static int cttimeout_del_timeout(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net); struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
struct ctnl_timeout *cur, *tmp; struct ctnl_timeout *cur, *tmp;
int ret = -ENOENT; int ret = -ENOENT;
char *name; char *name;
@ -334,7 +329,7 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
if (!cda[CTA_TIMEOUT_NAME]) { if (!cda[CTA_TIMEOUT_NAME]) {
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list, list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list,
head) head)
ctnl_timeout_try_del(net, cur); ctnl_timeout_try_del(info->net, cur);
return 0; return 0;
} }
@ -344,7 +339,7 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
continue; continue;
ret = ctnl_timeout_try_del(net, cur); ret = ctnl_timeout_try_del(info->net, cur);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -353,11 +348,9 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
return ret; return ret;
} }
static int cttimeout_default_set(struct net *net, struct sock *ctnl, static int cttimeout_default_set(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
const struct nf_conntrack_l4proto *l4proto; const struct nf_conntrack_l4proto *l4proto;
__u8 l4num; __u8 l4num;
@ -377,7 +370,7 @@ static int cttimeout_default_set(struct net *net, struct sock *ctnl,
goto err; goto err;
} }
ret = ctnl_timeout_parse_policy(NULL, l4proto, net, ret = ctnl_timeout_parse_policy(NULL, l4proto, info->net,
cda[CTA_TIMEOUT_DATA]); cda[CTA_TIMEOUT_DATA]);
if (ret < 0) if (ret < 0)
goto err; goto err;
@ -427,11 +420,9 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
return -1; return -1;
} }
static int cttimeout_default_get(struct net *net, struct sock *ctnl, static int cttimeout_default_get(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
{ {
const struct nf_conntrack_l4proto *l4proto; const struct nf_conntrack_l4proto *l4proto;
unsigned int *timeouts = NULL; unsigned int *timeouts = NULL;
@ -453,35 +444,35 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
switch (l4proto->l4proto) { switch (l4proto->l4proto) {
case IPPROTO_ICMP: case IPPROTO_ICMP:
timeouts = &nf_icmp_pernet(net)->timeout; timeouts = &nf_icmp_pernet(info->net)->timeout;
break; break;
case IPPROTO_TCP: case IPPROTO_TCP:
timeouts = nf_tcp_pernet(net)->timeouts; timeouts = nf_tcp_pernet(info->net)->timeouts;
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
case IPPROTO_UDPLITE: case IPPROTO_UDPLITE:
timeouts = nf_udp_pernet(net)->timeouts; timeouts = nf_udp_pernet(info->net)->timeouts;
break; break;
case IPPROTO_DCCP: case IPPROTO_DCCP:
#ifdef CONFIG_NF_CT_PROTO_DCCP #ifdef CONFIG_NF_CT_PROTO_DCCP
timeouts = nf_dccp_pernet(net)->dccp_timeout; timeouts = nf_dccp_pernet(info->net)->dccp_timeout;
#endif #endif
break; break;
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
timeouts = &nf_icmpv6_pernet(net)->timeout; timeouts = &nf_icmpv6_pernet(info->net)->timeout;
break; break;
case IPPROTO_SCTP: case IPPROTO_SCTP:
#ifdef CONFIG_NF_CT_PROTO_SCTP #ifdef CONFIG_NF_CT_PROTO_SCTP
timeouts = nf_sctp_pernet(net)->timeouts; timeouts = nf_sctp_pernet(info->net)->timeouts;
#endif #endif
break; break;
case IPPROTO_GRE: case IPPROTO_GRE:
#ifdef CONFIG_NF_CT_PROTO_GRE #ifdef CONFIG_NF_CT_PROTO_GRE
timeouts = nf_gre_pernet(net)->timeouts; timeouts = nf_gre_pernet(info->net)->timeouts;
#endif #endif
break; break;
case 255: case 255:
timeouts = &nf_generic_pernet(net)->timeout; timeouts = &nf_generic_pernet(info->net)->timeout;
break; break;
default: default:
WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto); WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto);
@ -497,9 +488,10 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
goto err; goto err;
} }
ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid, ret = cttimeout_default_fill_info(info->net, skb2,
nlh->nlmsg_seq, NETLINK_CB(skb).portid,
NFNL_MSG_TYPE(nlh->nlmsg_type), info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
IPCTNL_MSG_TIMEOUT_DEFAULT_SET, IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
l3num, l4proto, timeouts); l3num, l4proto, timeouts);
if (ret <= 0) { if (ret <= 0) {
@ -507,7 +499,8 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
err = -ENOMEM; err = -ENOMEM;
goto err; goto err;
} }
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
@ -553,21 +546,36 @@ static void ctnl_timeout_put(struct nf_ct_timeout *t)
} }
static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
[IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, [IPCTNL_MSG_TIMEOUT_NEW] = {
.call = cttimeout_new_timeout,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX, .attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy }, .policy = cttimeout_nla_policy
[IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, },
[IPCTNL_MSG_TIMEOUT_GET] = {
.call = cttimeout_get_timeout,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX, .attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy }, .policy = cttimeout_nla_policy
[IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, },
[IPCTNL_MSG_TIMEOUT_DELETE] = {
.call = cttimeout_del_timeout,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX, .attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy }, .policy = cttimeout_nla_policy
[IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set, },
[IPCTNL_MSG_TIMEOUT_DEFAULT_SET] = {
.call = cttimeout_default_set,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX, .attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy }, .policy = cttimeout_nla_policy
[IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get, },
[IPCTNL_MSG_TIMEOUT_DEFAULT_GET] = {
.call = cttimeout_default_get,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX, .attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy }, .policy = cttimeout_nla_policy
},
}; };
static const struct nfnetlink_subsystem cttimeout_subsys = { static const struct nfnetlink_subsystem cttimeout_subsys = {

View file

@ -845,10 +845,8 @@ static struct notifier_block nfulnl_rtnl_notifier = {
.notifier_call = nfulnl_rcv_nl_event, .notifier_call = nfulnl_rcv_nl_event,
}; };
static int nfulnl_recv_unsupp(struct net *net, struct sock *ctnl, static int nfulnl_recv_unsupp(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nfula[])
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
@ -869,18 +867,16 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = {
[NFULA_CFG_FLAGS] = { .type = NLA_U16 }, [NFULA_CFG_FLAGS] = { .type = NLA_U16 },
}; };
static int nfulnl_recv_config(struct net *net, struct sock *ctnl, static int nfulnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nfula[])
const struct nlattr * const nfula[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfnl_log_net *log = nfnl_log_pernet(info->net);
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int16_t group_num = ntohs(nfmsg->res_id); u_int16_t group_num = ntohs(nfmsg->res_id);
struct nfulnl_instance *inst;
struct nfulnl_msg_config_cmd *cmd = NULL; struct nfulnl_msg_config_cmd *cmd = NULL;
struct nfnl_log_net *log = nfnl_log_pernet(net); struct nfulnl_instance *inst;
int ret = 0;
u16 flags = 0; u16 flags = 0;
int ret = 0;
if (nfula[NFULA_CFG_CMD]) { if (nfula[NFULA_CFG_CMD]) {
u_int8_t pf = nfmsg->nfgen_family; u_int8_t pf = nfmsg->nfgen_family;
@ -889,9 +885,9 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
/* Commands without queue context */ /* Commands without queue context */
switch (cmd->command) { switch (cmd->command) {
case NFULNL_CFG_CMD_PF_BIND: case NFULNL_CFG_CMD_PF_BIND:
return nf_log_bind_pf(net, pf, &nfulnl_logger); return nf_log_bind_pf(info->net, pf, &nfulnl_logger);
case NFULNL_CFG_CMD_PF_UNBIND: case NFULNL_CFG_CMD_PF_UNBIND:
nf_log_unbind_pf(net, pf); nf_log_unbind_pf(info->net, pf);
return 0; return 0;
} }
} }
@ -932,7 +928,7 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
goto out_put; goto out_put;
} }
inst = instance_create(net, group_num, inst = instance_create(info->net, group_num,
NETLINK_CB(skb).portid, NETLINK_CB(skb).portid,
sk_user_ns(NETLINK_CB(skb).sk)); sk_user_ns(NETLINK_CB(skb).sk));
if (IS_ERR(inst)) { if (IS_ERR(inst)) {
@ -993,11 +989,17 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
} }
static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = { static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
[NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp, [NFULNL_MSG_PACKET] = {
.attr_count = NFULA_MAX, }, .call = nfulnl_recv_unsupp,
[NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config, .type = NFNL_CB_MUTEX,
.attr_count = NFULA_MAX,
},
[NFULNL_MSG_CONFIG] = {
.call = nfulnl_recv_config,
.type = NFNL_CB_MUTEX,
.attr_count = NFULA_CFG_MAX, .attr_count = NFULA_CFG_MAX,
.policy = nfula_cfg_policy }, .policy = nfula_cfg_policy
},
}; };
static const struct nfnetlink_subsystem nfulnl_subsys = { static const struct nfnetlink_subsystem nfulnl_subsys = {

View file

@ -292,10 +292,9 @@ static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = {
[OSF_ATTR_FINGER] = { .len = sizeof(struct nf_osf_user_finger) }, [OSF_ATTR_FINGER] = { .len = sizeof(struct nf_osf_user_finger) },
}; };
static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, static int nfnl_osf_add_callback(struct sk_buff *skb,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nfnl_info *info,
const struct nlattr * const osf_attrs[], const struct nlattr * const osf_attrs[])
struct netlink_ext_ack *extack)
{ {
struct nf_osf_user_finger *f; struct nf_osf_user_finger *f;
struct nf_osf_finger *kf = NULL, *sf; struct nf_osf_finger *kf = NULL, *sf;
@ -307,7 +306,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
if (!osf_attrs[OSF_ATTR_FINGER]) if (!osf_attrs[OSF_ATTR_FINGER])
return -EINVAL; return -EINVAL;
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
return -EINVAL; return -EINVAL;
f = nla_data(osf_attrs[OSF_ATTR_FINGER]); f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
@ -325,7 +324,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
kfree(kf); kfree(kf);
kf = NULL; kf = NULL;
if (nlh->nlmsg_flags & NLM_F_EXCL) if (info->nlh->nlmsg_flags & NLM_F_EXCL)
err = -EEXIST; err = -EEXIST;
break; break;
} }
@ -339,11 +338,9 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
return err; return err;
} }
static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl, static int nfnl_osf_remove_callback(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const osf_attrs[])
const struct nlattr * const osf_attrs[],
struct netlink_ext_ack *extack)
{ {
struct nf_osf_user_finger *f; struct nf_osf_user_finger *f;
struct nf_osf_finger *sf; struct nf_osf_finger *sf;
@ -377,11 +374,13 @@ static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl,
static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = { static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = {
[OSF_MSG_ADD] = { [OSF_MSG_ADD] = {
.call = nfnl_osf_add_callback, .call = nfnl_osf_add_callback,
.type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX, .attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy, .policy = nfnl_osf_policy,
}, },
[OSF_MSG_REMOVE] = { [OSF_MSG_REMOVE] = {
.call = nfnl_osf_remove_callback, .call = nfnl_osf_remove_callback,
.type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX, .attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy, .policy = nfnl_osf_policy,
}, },

View file

@ -1046,20 +1046,18 @@ static int nfq_id_after(unsigned int id, unsigned int max)
return (int)(id - max) > 0; return (int)(id - max) > 0;
} }
static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl, static int nfqnl_recv_verdict_batch(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const nfqa[])
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u16 queue_num = ntohs(nfmsg->res_id);
struct nf_queue_entry *entry, *tmp; struct nf_queue_entry *entry, *tmp;
unsigned int verdict, maxid;
struct nfqnl_msg_verdict_hdr *vhdr; struct nfqnl_msg_verdict_hdr *vhdr;
struct nfqnl_instance *queue; struct nfqnl_instance *queue;
unsigned int verdict, maxid;
LIST_HEAD(batch_list); LIST_HEAD(batch_list);
u16 queue_num = ntohs(nfmsg->res_id);
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
queue = verdict_instance_lookup(q, queue_num, queue = verdict_instance_lookup(q, queue_num,
NETLINK_CB(skb).portid); NETLINK_CB(skb).portid);
@ -1158,22 +1156,19 @@ static int nfqa_parse_bridge(struct nf_queue_entry *entry,
return 0; return 0;
} }
static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl, static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlattr * const nfqa[])
const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id); u_int16_t queue_num = ntohs(nfmsg->res_id);
struct nfqnl_msg_verdict_hdr *vhdr; struct nfqnl_msg_verdict_hdr *vhdr;
struct nfqnl_instance *queue;
unsigned int verdict;
struct nf_queue_entry *entry;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nfqnl_instance *queue;
struct nf_queue_entry *entry;
struct nfnl_ct_hook *nfnl_ct; struct nfnl_ct_hook *nfnl_ct;
struct nf_conn *ct = NULL; struct nf_conn *ct = NULL;
struct nfnl_queue_net *q = nfnl_queue_pernet(net); unsigned int verdict;
int err; int err;
queue = verdict_instance_lookup(q, queue_num, queue = verdict_instance_lookup(q, queue_num,
@ -1196,7 +1191,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
if (nfqa[NFQA_CT]) { if (nfqa[NFQA_CT]) {
if (nfnl_ct != NULL) if (nfnl_ct != NULL)
ct = nfqnl_ct_parse(nfnl_ct, nlh, nfqa, entry, &ctinfo); ct = nfqnl_ct_parse(nfnl_ct, info->nlh, nfqa, entry,
&ctinfo);
} }
if (entry->state.pf == PF_BRIDGE) { if (entry->state.pf == PF_BRIDGE) {
@ -1224,10 +1220,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
return 0; return 0;
} }
static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl, static int nfqnl_recv_unsupp(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[])
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
@ -1245,16 +1239,14 @@ static const struct nf_queue_handler nfqh = {
.nf_hook_drop = nfqnl_nf_hook_drop, .nf_hook_drop = nfqnl_nf_hook_drop,
}; };
static int nfqnl_recv_config(struct net *net, struct sock *ctnl, static int nfqnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nfqa[])
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
{ {
struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id); u_int16_t queue_num = ntohs(nfmsg->res_id);
struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL; struct nfqnl_msg_config_cmd *cmd = NULL;
struct nfnl_queue_net *q = nfnl_queue_pernet(net); struct nfqnl_instance *queue;
__u32 flags = 0, mask = 0; __u32 flags = 0, mask = 0;
int ret = 0; int ret = 0;
@ -1373,17 +1365,29 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
} }
static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
[NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp, [NFQNL_MSG_PACKET] = {
.attr_count = NFQA_MAX, }, .call = nfqnl_recv_unsupp,
[NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict, .type = NFNL_CB_RCU,
.attr_count = NFQA_MAX, .attr_count = NFQA_MAX,
.policy = nfqa_verdict_policy }, },
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, [NFQNL_MSG_VERDICT] = {
.call = nfqnl_recv_verdict,
.type = NFNL_CB_RCU,
.attr_count = NFQA_MAX,
.policy = nfqa_verdict_policy
},
[NFQNL_MSG_CONFIG] = {
.call = nfqnl_recv_config,
.type = NFNL_CB_MUTEX,
.attr_count = NFQA_CFG_MAX, .attr_count = NFQA_CFG_MAX,
.policy = nfqa_cfg_policy }, .policy = nfqa_cfg_policy
[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch, },
[NFQNL_MSG_VERDICT_BATCH] = {
.call = nfqnl_recv_verdict_batch,
.type = NFNL_CB_RCU,
.attr_count = NFQA_MAX, .attr_count = NFQA_MAX,
.policy = nfqa_verdict_batch_policy }, .policy = nfqa_verdict_batch_policy
},
}; };
static const struct nfnetlink_subsystem nfqnl_subsys = { static const struct nfnetlink_subsystem nfqnl_subsys = {

View file

@ -2,7 +2,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
@ -11,8 +10,6 @@
#include <net/netfilter/nf_tables_ipv4.h> #include <net/netfilter/nf_tables_ipv4.h>
#include <net/netfilter/nf_tables_ipv6.h> #include <net/netfilter/nf_tables_ipv6.h>
extern unsigned int nf_tables_net_id;
#ifdef CONFIG_NF_TABLES_IPV4 #ifdef CONFIG_NF_TABLES_IPV4
static unsigned int nft_do_chain_ipv4(void *priv, static unsigned int nft_do_chain_ipv4(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
@ -369,7 +366,7 @@ static int nf_tables_netdev_event(struct notifier_block *this,
event != NETDEV_CHANGENAME) event != NETDEV_CHANGENAME)
return NOTIFY_DONE; return NOTIFY_DONE;
nft_net = net_generic(ctx.net, nf_tables_net_id); nft_net = nft_pernet(ctx.net);
mutex_lock(&nft_net->commit_mutex); mutex_lock(&nft_net->commit_mutex);
list_for_each_entry(table, &nft_net->tables, list) { list_for_each_entry(table, &nft_net->tables, list) {
if (table->family != NFPROTO_NETDEV) if (table->family != NFPROTO_NETDEV)

View file

@ -613,17 +613,15 @@ nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
return -1; return -1;
} }
static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl, static int nfnl_compat_get_rcu(struct sk_buff *skb,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nfnl_info *info,
const struct nlattr * const tb[], const struct nlattr * const tb[])
struct netlink_ext_ack *extack)
{ {
int ret = 0, target;
struct nfgenmsg *nfmsg; struct nfgenmsg *nfmsg;
const char *fmt; const char *name, *fmt;
const char *name;
u32 rev;
struct sk_buff *skb2; struct sk_buff *skb2;
int ret = 0, target;
u32 rev;
if (tb[NFTA_COMPAT_NAME] == NULL || if (tb[NFTA_COMPAT_NAME] == NULL ||
tb[NFTA_COMPAT_REV] == NULL || tb[NFTA_COMPAT_REV] == NULL ||
@ -634,7 +632,7 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
nfmsg = nlmsg_data(nlh); nfmsg = nlmsg_data(info->nlh);
switch(nfmsg->nfgen_family) { switch(nfmsg->nfgen_family) {
case AF_INET: case AF_INET:
@ -673,8 +671,8 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
/* include the best revision for this extension in the message */ /* include the best revision for this extension in the message */
if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid, if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_COMPAT_GET, NFNL_MSG_COMPAT_GET,
nfmsg->nfgen_family, nfmsg->nfgen_family,
name, ret, target) <= 0) { name, ret, target) <= 0) {
@ -682,7 +680,7 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
goto out_put; goto out_put;
} }
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT); MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
@ -700,9 +698,12 @@ static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
}; };
static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = { static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
[NFNL_MSG_COMPAT_GET] = { .call_rcu = nfnl_compat_get_rcu, [NFNL_MSG_COMPAT_GET] = {
.call = nfnl_compat_get_rcu,
.type = NFNL_CB_RCU,
.attr_count = NFTA_COMPAT_MAX, .attr_count = NFTA_COMPAT_MAX,
.policy = nfnl_compat_policy_get }, .policy = nfnl_compat_policy_get
},
}; };
static const struct nfnetlink_subsystem nfnl_compat_subsys = { static const struct nfnetlink_subsystem nfnl_compat_subsys = {

View file

@ -11,9 +11,6 @@
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h> #include <net/netfilter/nf_tables_core.h>
#include <net/netns/generic.h>
extern unsigned int nf_tables_net_id;
struct nft_dynset { struct nft_dynset {
struct nft_set *set; struct nft_set *set;
@ -164,7 +161,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
const struct nft_expr *expr, const struct nft_expr *expr,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct nft_dynset *priv = nft_expr_priv(expr); struct nft_dynset *priv = nft_expr_priv(expr);
u8 genmask = nft_genmask_next(ctx->net); u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set; struct nft_set *set;

View file

@ -9,6 +9,7 @@
struct nft_socket { struct nft_socket {
enum nft_socket_keys key:8; enum nft_socket_keys key:8;
u8 level;
union { union {
u8 dreg; u8 dreg;
}; };
@ -33,6 +34,26 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt,
} }
} }
#ifdef CONFIG_CGROUPS
static noinline bool
nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level)
{
struct sock *sk = skb_to_full_sk(pkt->skb);
struct cgroup *cgrp;
if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
return false;
cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
if (level > cgrp->level)
return false;
memcpy(dest, &cgrp->ancestor_ids[level], sizeof(u64));
return true;
}
#endif
static void nft_socket_eval(const struct nft_expr *expr, static void nft_socket_eval(const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_pktinfo *pkt) const struct nft_pktinfo *pkt)
@ -85,6 +106,14 @@ static void nft_socket_eval(const struct nft_expr *expr,
} }
nft_socket_wildcard(pkt, regs, sk, dest); nft_socket_wildcard(pkt, regs, sk, dest);
break; break;
#ifdef CONFIG_CGROUPS
case NFT_SOCKET_CGROUPV2:
if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) {
regs->verdict.code = NFT_BREAK;
return;
}
break;
#endif
default: default:
WARN_ON(1); WARN_ON(1);
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
@ -97,6 +126,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = { static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
[NFTA_SOCKET_KEY] = { .type = NLA_U32 }, [NFTA_SOCKET_KEY] = { .type = NLA_U32 },
[NFTA_SOCKET_DREG] = { .type = NLA_U32 }, [NFTA_SOCKET_DREG] = { .type = NLA_U32 },
[NFTA_SOCKET_LEVEL] = { .type = NLA_U32 },
}; };
static int nft_socket_init(const struct nft_ctx *ctx, static int nft_socket_init(const struct nft_ctx *ctx,
@ -104,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_socket *priv = nft_expr_priv(expr); struct nft_socket *priv = nft_expr_priv(expr);
unsigned int len; unsigned int len, level;
if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY]) if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
return -EINVAL; return -EINVAL;
@ -129,6 +159,19 @@ static int nft_socket_init(const struct nft_ctx *ctx,
case NFT_SOCKET_MARK: case NFT_SOCKET_MARK:
len = sizeof(u32); len = sizeof(u32);
break; break;
#ifdef CONFIG_CGROUPS
case NFT_SOCKET_CGROUPV2:
if (!tb[NFTA_SOCKET_LEVEL])
return -EINVAL;
level = ntohl(nla_get_u32(tb[NFTA_SOCKET_LEVEL]));
if (level > 255)
return -EOPNOTSUPP;
priv->level = level;
len = sizeof(u64);
break;
#endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -146,6 +189,9 @@ static int nft_socket_dump(struct sk_buff *skb,
return -1; return -1;
if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg)) if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
return -1; return -1;
if (priv->key == NFT_SOCKET_CGROUPV2 &&
nla_put_u32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level)))
return -1;
return 0; return 0;
} }

View file

@ -263,6 +263,29 @@ static int nft_tproxy_init(const struct nft_ctx *ctx,
return 0; return 0;
} }
static void nft_tproxy_destroy(const struct nft_ctx *ctx,
const struct nft_expr *expr)
{
const struct nft_tproxy *priv = nft_expr_priv(expr);
switch (priv->family) {
case NFPROTO_IPV4:
nf_defrag_ipv4_disable(ctx->net);
break;
#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
case NFPROTO_IPV6:
nf_defrag_ipv6_disable(ctx->net);
break;
#endif
case NFPROTO_UNSPEC:
nf_defrag_ipv4_disable(ctx->net);
#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
nf_defrag_ipv6_disable(ctx->net);
#endif
break;
}
}
static int nft_tproxy_dump(struct sk_buff *skb, static int nft_tproxy_dump(struct sk_buff *skb,
const struct nft_expr *expr) const struct nft_expr *expr)
{ {
@ -288,6 +311,7 @@ static const struct nft_expr_ops nft_tproxy_ops = {
.size = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)), .size = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)),
.eval = nft_tproxy_eval, .eval = nft_tproxy_eval,
.init = nft_tproxy_init, .init = nft_tproxy_init,
.destroy = nft_tproxy_destroy,
.dump = nft_tproxy_dump, .dump = nft_tproxy_dump,
}; };

View file

@ -52,7 +52,7 @@ struct xt_af {
struct mutex mutex; struct mutex mutex;
struct list_head match; struct list_head match;
struct list_head target; struct list_head target;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct mutex compat_mutex; struct mutex compat_mutex;
struct compat_delta *compat_tab; struct compat_delta *compat_tab;
unsigned int number; /* number of slots in compat_tab[] */ unsigned int number; /* number of slots in compat_tab[] */
@ -647,7 +647,7 @@ static bool error_tg_ok(unsigned int usersize, unsigned int kernsize,
return usersize == kernsize && strnlen(msg, msglen) < msglen; return usersize == kernsize && strnlen(msg, msglen) < msglen;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
{ {
struct xt_af *xp = &xt[af]; struct xt_af *xp = &xt[af];
@ -850,7 +850,7 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
__alignof__(struct compat_xt_entry_match)); __alignof__(struct compat_xt_entry_match));
} }
EXPORT_SYMBOL(xt_compat_check_entry_offsets); EXPORT_SYMBOL(xt_compat_check_entry_offsets);
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
/** /**
* xt_check_entry_offsets - validate arp/ip/ip6t_entry * xt_check_entry_offsets - validate arp/ip/ip6t_entry
@ -868,7 +868,7 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
* match structures are aligned, and that the last structure ends where * match structures are aligned, and that the last structure ends where
* the target structure begins. * the target structure begins.
* *
* Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. * Also see xt_compat_check_entry_offsets for CONFIG_NETFILTER_XTABLES_COMPAT version.
* *
* The arp/ip/ip6t_entry structure @base must have passed following tests: * The arp/ip/ip6t_entry structure @base must have passed following tests:
* - it must point to a valid memory location * - it must point to a valid memory location
@ -1059,7 +1059,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
void *mem; void *mem;
u64 size; u64 size;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) { if (in_compat_syscall()) {
/* structures only differ in size due to alignment */ /* structures only differ in size due to alignment */
struct compat_xt_counters_info compat_tmp; struct compat_xt_counters_info compat_tmp;
@ -1106,7 +1106,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
} }
EXPORT_SYMBOL_GPL(xt_copy_counters); EXPORT_SYMBOL_GPL(xt_copy_counters);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
int xt_compat_target_offset(const struct xt_target *target) int xt_compat_target_offset(const struct xt_target *target)
{ {
u_int16_t csize = target->compatsize ? : target->targetsize; u_int16_t csize = target->compatsize ? : target->targetsize;
@ -1199,6 +1199,23 @@ void xt_free_table_info(struct xt_table_info *info)
} }
EXPORT_SYMBOL(xt_free_table_info); EXPORT_SYMBOL(xt_free_table_info);
struct xt_table *xt_find_table(struct net *net, u8 af, const char *name)
{
struct xt_pernet *xt_net = net_generic(net, xt_pernet_id);
struct xt_table *t;
mutex_lock(&xt[af].mutex);
list_for_each_entry(t, &xt_net->tables[af], list) {
if (strcmp(t->name, name) == 0) {
mutex_unlock(&xt[af].mutex);
return t;
}
}
mutex_unlock(&xt[af].mutex);
return NULL;
}
EXPORT_SYMBOL(xt_find_table);
/* Find table by name, grabs mutex & ref. Returns ERR_PTR on error. */ /* Find table by name, grabs mutex & ref. Returns ERR_PTR on error. */
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)
@ -1276,7 +1293,7 @@ void xt_table_unlock(struct xt_table *table)
} }
EXPORT_SYMBOL_GPL(xt_table_unlock); EXPORT_SYMBOL_GPL(xt_table_unlock);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
void xt_compat_lock(u_int8_t af) void xt_compat_lock(u_int8_t af)
{ {
mutex_lock(&xt[af].compat_mutex); mutex_lock(&xt[af].compat_mutex);
@ -1481,6 +1498,7 @@ void *xt_unregister_table(struct xt_table *table)
mutex_unlock(&xt[table->af].mutex); mutex_unlock(&xt[table->af].mutex);
audit_log_nfcfg(table->name, table->af, private->number, audit_log_nfcfg(table->name, table->af, private->number,
AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); AUDIT_XT_OP_UNREGISTER, GFP_KERNEL);
kfree(table->ops);
kfree(table); kfree(table);
return private; return private;
@ -1913,7 +1931,7 @@ static int __init xt_init(void)
for (i = 0; i < NFPROTO_NUMPROTO; i++) { for (i = 0; i < NFPROTO_NUMPROTO; i++) {
mutex_init(&xt[i].mutex); mutex_init(&xt[i].mutex);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
mutex_init(&xt[i].compat_mutex); mutex_init(&xt[i].compat_mutex);
xt[i].compat_tab = NULL; xt[i].compat_tab = NULL;
#endif #endif

View file

@ -200,6 +200,11 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
pr_info_ratelimited("Can be used only with -p tcp or -p udp\n"); pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
return -EINVAL; return -EINVAL;
} }
static void tproxy_tg6_destroy(const struct xt_tgdtor_param *par)
{
nf_defrag_ipv6_disable(par->net);
}
#endif #endif
static int tproxy_tg4_check(const struct xt_tgchk_param *par) static int tproxy_tg4_check(const struct xt_tgchk_param *par)
@ -219,6 +224,11 @@ static int tproxy_tg4_check(const struct xt_tgchk_param *par)
return -EINVAL; return -EINVAL;
} }
static void tproxy_tg4_destroy(const struct xt_tgdtor_param *par)
{
nf_defrag_ipv4_disable(par->net);
}
static struct xt_target tproxy_tg_reg[] __read_mostly = { static struct xt_target tproxy_tg_reg[] __read_mostly = {
{ {
.name = "TPROXY", .name = "TPROXY",
@ -228,6 +238,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 0, .revision = 0,
.targetsize = sizeof(struct xt_tproxy_target_info), .targetsize = sizeof(struct xt_tproxy_target_info),
.checkentry = tproxy_tg4_check, .checkentry = tproxy_tg4_check,
.destroy = tproxy_tg4_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING, .hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE, .me = THIS_MODULE,
}, },
@ -239,6 +250,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 1, .revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1), .targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg4_check, .checkentry = tproxy_tg4_check,
.destroy = tproxy_tg4_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING, .hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE, .me = THIS_MODULE,
}, },
@ -251,6 +263,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 1, .revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1), .targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg6_check, .checkentry = tproxy_tg6_check,
.destroy = tproxy_tg6_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING, .hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE, .me = THIS_MODULE,
}, },

View file

@ -134,7 +134,7 @@ static void limit_mt_destroy(const struct xt_mtdtor_param *par)
kfree(info->master); kfree(info->master);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_xt_rateinfo { struct compat_xt_rateinfo {
u_int32_t avg; u_int32_t avg;
u_int32_t burst; u_int32_t burst;
@ -176,7 +176,7 @@ static int limit_mt_compat_to_user(void __user *dst, const void *src)
}; };
return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
} }
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_match limit_mt_reg __read_mostly = { static struct xt_match limit_mt_reg __read_mostly = {
.name = "limit", .name = "limit",
@ -186,7 +186,7 @@ static struct xt_match limit_mt_reg __read_mostly = {
.checkentry = limit_mt_check, .checkentry = limit_mt_check,
.destroy = limit_mt_destroy, .destroy = limit_mt_destroy,
.matchsize = sizeof(struct xt_rateinfo), .matchsize = sizeof(struct xt_rateinfo),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_xt_rateinfo), .compatsize = sizeof(struct compat_xt_rateinfo),
.compat_from_user = limit_mt_compat_from_user, .compat_from_user = limit_mt_compat_from_user,
.compat_to_user = limit_mt_compat_to_user, .compat_to_user = limit_mt_compat_to_user,

View file

@ -216,6 +216,14 @@ static int socket_mt_v3_check(const struct xt_mtchk_param *par)
return 0; return 0;
} }
static void socket_mt_destroy(const struct xt_mtdtor_param *par)
{
if (par->family == NFPROTO_IPV4)
nf_defrag_ipv4_disable(par->net);
else if (par->family == NFPROTO_IPV6)
nf_defrag_ipv4_disable(par->net);
}
static struct xt_match socket_mt_reg[] __read_mostly = { static struct xt_match socket_mt_reg[] __read_mostly = {
{ {
.name = "socket", .name = "socket",
@ -231,6 +239,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.revision = 1, .revision = 1,
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3, .match = socket_mt4_v1_v2_v3,
.destroy = socket_mt_destroy,
.checkentry = socket_mt_v1_check, .checkentry = socket_mt_v1_check,
.matchsize = sizeof(struct xt_socket_mtinfo1), .matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
@ -245,6 +254,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.match = socket_mt6_v1_v2_v3, .match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v1_check, .checkentry = socket_mt_v1_check,
.matchsize = sizeof(struct xt_socket_mtinfo1), .matchsize = sizeof(struct xt_socket_mtinfo1),
.destroy = socket_mt_destroy,
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE, .me = THIS_MODULE,
@ -256,6 +266,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3, .match = socket_mt4_v1_v2_v3,
.checkentry = socket_mt_v2_check, .checkentry = socket_mt_v2_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1), .matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),
@ -268,6 +279,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
.match = socket_mt6_v1_v2_v3, .match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v2_check, .checkentry = socket_mt_v2_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1), .matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),
@ -280,6 +292,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3, .match = socket_mt4_v1_v2_v3,
.checkentry = socket_mt_v3_check, .checkentry = socket_mt_v3_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1), .matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),
@ -292,6 +305,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
.match = socket_mt6_v1_v2_v3, .match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v3_check, .checkentry = socket_mt_v3_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1), .matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),