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 <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 {
int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb,
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 */
int (*call)(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const cda[]);
const struct nla_policy *policy;
enum nfnl_callback_type type;
__u16 attr_count;
};
enum nfnl_abort_action {

View File

@ -158,7 +158,7 @@ struct xt_match {
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_mtdtor_param *);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
@ -169,7 +169,7 @@ struct xt_match {
const char *table;
unsigned int matchsize;
unsigned int usersize;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
@ -199,7 +199,7 @@ struct xt_target {
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_tgdtor_param *);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
@ -210,7 +210,7 @@ struct xt_target {
const char *table;
unsigned int targetsize;
unsigned int usersize;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
@ -229,6 +229,9 @@ struct xt_table {
/* Man behind the curtain... */
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 */
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 *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,
const char *name);
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 *);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
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 next_offset);
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
#endif /* _X_TABLES_H */

View File

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

View File

@ -100,6 +100,7 @@ struct ebt_table {
unsigned int valid_hooks);
/* the data used by the kernel */
struct ebt_table_info *private;
struct nf_hook_ops *ops;
struct module *me;
};
@ -108,11 +109,9 @@ struct ebt_table {
extern int ebt_register_table(struct net *net,
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,
const struct nf_hook_state *state,
struct ebt_table *table);

View File

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

View File

@ -3,6 +3,7 @@
#define _NF_DEFRAG_IPV4_H
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 */

View File

@ -5,7 +5,8 @@
#include <linux/skbuff.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);
void nf_ct_frag6_cleanup(void);

View File

@ -104,8 +104,6 @@ unsigned int
nf_nat_inet_fn(void *priv, struct sk_buff *skb,
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,
enum nf_nat_manip_type manip)
{

View File

@ -13,6 +13,7 @@
#include <net/netfilter/nf_flow_table.h>
#include <net/netlink.h>
#include <net/flow_offload.h>
#include <net/netns/generic.h>
#define NFT_MAX_HOOKS (NF_INET_INGRESS + 1)
@ -1580,4 +1581,11 @@ struct nftables_pernet {
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 */

View File

@ -76,16 +76,6 @@ struct netns_ipv4 {
struct inet_peer_base *peers;
struct sock * __percpu *tcp_sk;
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_enable_probe;

View File

@ -63,15 +63,6 @@ struct netns_ipv6 {
struct ipv6_devconf *devconf_dflt;
struct inet_peer_base *peers;
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 rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats;

View File

@ -5,16 +5,8 @@
#include <linux/list.h>
#include <linux/netfilter_defs.h>
struct ebt_table;
struct netns_xt {
bool notrack_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

View File

@ -1014,11 +1014,13 @@ enum nft_rt_attributes {
*
* @NFTA_SOCKET_KEY: socket key to match
* @NFTA_SOCKET_DREG: destination register
* @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
*/
enum nft_socket_attributes {
NFTA_SOCKET_UNSPEC,
NFTA_SOCKET_KEY,
NFTA_SOCKET_DREG,
NFTA_SOCKET_LEVEL,
__NFTA_SOCKET_MAX
};
#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_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_CGROUPV2: Match on cgroups version 2
*/
enum nft_socket_keys {
NFT_SOCKET_TRANSPARENT,
NFT_SOCKET_MARK,
NFT_SOCKET_WILDCARD,
NFT_SOCKET_CGROUPV2,
__NFT_SOCKET_MAX
};
#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 --
* 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,
.matchsize = sizeof(struct ebt_limit_info),
.usersize = offsetof(struct ebt_limit_info, prev),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct ebt_compat_limit_info),
#endif
.me = THIS_MODULE,

View File

@ -53,7 +53,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
return 0;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_t_info {
compat_ulong_t mark;
compat_uint_t target;
@ -87,7 +87,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check,
.targetsize = sizeof(struct ebt_mark_t_info),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_t_info),
.compat_from_user = mark_tg_compat_from_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 {
compat_ulong_t mark, mask;
uint8_t invert, bitmask;
@ -75,7 +75,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check,
.matchsize = sizeof(struct ebt_mark_m_info),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_m_info),
.compat_from_user = mark_mt_compat_from_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,
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)
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)
{
return ebt_register_table(net, &broute_table, &ebt_ops_broute,
&net->xt.broute_table);
return ebt_register_table(net, &broute_table, &ebt_ops_broute);
}
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)
{
ebt_unregister_table(net, net->xt.broute_table);
ebt_unregister_table(net, "broute");
}
static struct pernet_operations broute_net_ops = {

View File

@ -59,34 +59,27 @@ static const struct ebt_table frame_filter = {
};
static unsigned int
ebt_in_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
ebt_filter_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 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);
return ebt_do_table(skb, state, priv);
}
static const struct nf_hook_ops ebt_ops_filter[] = {
{
.hook = ebt_in_hook,
.hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_IN,
.priority = NF_BR_PRI_FILTER_BRIDGED,
},
{
.hook = ebt_in_hook,
.hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_FORWARD,
.priority = NF_BR_PRI_FILTER_BRIDGED,
},
{
.hook = ebt_out_hook,
.hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT,
.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)
{
return ebt_register_table(net, &frame_filter, ebt_ops_filter,
&net->xt.frame_filter);
return ebt_register_table(net, &frame_filter, ebt_ops_filter);
}
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)
{
ebt_unregister_table(net, net->xt.frame_filter);
ebt_unregister_table(net, "filter");
}
static struct pernet_operations frame_filter_net_ops = {

View File

@ -58,35 +58,27 @@ static const struct ebt_table frame_nat = {
.me = THIS_MODULE,
};
static unsigned int
ebt_nat_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
static unsigned int ebt_nat_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
return ebt_do_table(skb, state, state->net->xt.frame_nat);
}
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);
return ebt_do_table(skb, state, priv);
}
static const struct nf_hook_ops ebt_ops_nat[] = {
{
.hook = ebt_nat_out,
.hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_NAT_DST_OTHER,
},
{
.hook = ebt_nat_out,
.hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_POST_ROUTING,
.priority = NF_BR_PRI_NAT_SRC,
},
{
.hook = ebt_nat_in,
.hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_PRE_ROUTING,
.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)
{
return ebt_register_table(net, &frame_nat, ebt_ops_nat,
&net->xt.frame_nat);
return ebt_register_table(net, &frame_nat, ebt_ops_nat);
}
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)
{
ebt_unregister_table(net, net->xt.frame_nat);
ebt_unregister_table(net, "nat");
}
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 DEFINE_MUTEX(ebt_mutex);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void ebt_standard_compat_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@ -73,7 +73,7 @@ static struct xt_target ebt_standard_target = {
.revision = 0,
.family = NFPROTO_BRIDGE,
.targetsize = sizeof(int),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = ebt_standard_compat_from_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);
ebt_free_table_info(table->private);
vfree(table->private);
kfree(table->ops);
kfree(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_table_info *newinfo;
struct ebt_table *t, *table;
struct nf_hook_ops *ops;
unsigned int num_ops;
struct ebt_replace_kernel *repl;
int ret, i, countersize;
void *p;
@ -1213,15 +1216,31 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
ret = -ENOENT;
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);
mutex_unlock(&ebt_mutex);
WRITE_ONCE(*res, table);
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
if (ret) {
table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret)
__ebt_unregister_table(net, table);
*res = NULL;
}
audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries,
AUDIT_XT_OP_REGISTER, GFP_KERNEL);
@ -1257,18 +1276,21 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
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);
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);
void ebt_unregister_table(struct net *net, struct ebt_table *table)
void ebt_unregister_table(struct net *net, const char *name)
{
__ebt_unregister_table(net, table);
struct ebt_table *table = __ebt_find_table(net, name);
if (table)
__ebt_unregister_table(net, table);
}
/* userspace just supplied us with counters */
@ -1480,7 +1502,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
ebt_entry_to_user, entries, tmp.entries);
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* 32 bit-userspace compatibility definitions. */
struct compat_ebt_replace {
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))
return -EPERM;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* try real handler in case userland supplied needed padding */
if (in_compat_syscall() &&
((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) {
case EBT_SO_SET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(net, arg, len);
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);
break;
case EBT_SO_SET_COUNTERS:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_update_counters(net, arg, len);
else

View File

@ -713,7 +713,7 @@ static int copy_entries_to_user(unsigned int total_size,
return ret;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *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;
name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(NFPROTO_ARP);
#endif
@ -808,7 +808,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) {
struct arpt_getinfo info;
const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;
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);
} else
ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(NFPROTO_ARP);
#endif
@ -1044,7 +1044,7 @@ static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_arpt_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
@ -1412,7 +1412,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) {
case ARPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
@ -1444,7 +1444,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break;
case ARPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
else
@ -1499,10 +1499,11 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table)
int arpt_register_table(struct net *net,
const struct xt_table *table,
const struct arpt_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 bootstrap = {0};
void *loc_cpu_entry;
@ -1516,41 +1517,61 @@ int arpt_register_table(struct net *net,
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
if (ret != 0) {
xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_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;
}
/* 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) {
__arpt_unregister_table(net, new_table);
*res = NULL;
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:
xt_free_table_info(newinfo);
__arpt_unregister_table(net, new_table);
return ret;
}
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)
{
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
if (table)
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
}
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)
{
__arpt_unregister_table(net, table);
struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
if (table)
__arpt_unregister_table(net, table);
}
/* The built-in targets: standard (NULL) and error. */
@ -1559,7 +1580,7 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_ARP,
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_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,
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;
@ -44,31 +44,22 @@ static int __net_init arptable_filter_table_init(struct net *net)
struct arpt_replace *repl;
int err;
if (net->ipv4.arptable_filter)
return 0;
repl = arpt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops,
&net->ipv4.arptable_filter);
err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops);
kfree(repl);
return err;
}
static void __net_exit arptable_filter_net_pre_exit(struct net *net)
{
if (net->ipv4.arptable_filter)
arpt_unregister_table_pre_exit(net, net->ipv4.arptable_filter,
arpfilter_ops);
arpt_unregister_table_pre_exit(net, "filter", arpfilter_ops);
}
static void __net_exit arptable_filter_net_exit(struct net *net)
{
if (!net->ipv4.arptable_filter)
return;
arpt_unregister_table(net, net->ipv4.arptable_filter);
net->ipv4.arptable_filter = NULL;
arpt_unregister_table(net, "filter");
}
static struct pernet_operations arptable_filter_net_ops = {

View File

@ -868,7 +868,7 @@ copy_entries_to_user(unsigned int total_size,
return ret;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *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;
name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(AF_INET);
#endif
@ -965,7 +965,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) {
struct ipt_getinfo info;
const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;
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);
} else
ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(AF_INET);
#endif
@ -1199,7 +1199,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
@ -1621,7 +1621,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) {
case IPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
@ -1654,7 +1654,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break;
case IPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
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,
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 bootstrap = {0};
void *loc_cpu_entry;
@ -1732,50 +1734,65 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
if (ret != 0) {
xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table);
xt_free_table_info(newinfo);
return PTR_ERR(new_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.
*/
if (!template_ops)
return 0;
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
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) {
__ipt_unregister_table(net, new_table);
*res = NULL;
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:
xt_free_table_info(newinfo);
__ipt_unregister_table(net, new_table);
return ret;
}
void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops)
void ipt_unregister_table_pre_exit(struct net *net, const char *name)
{
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
if (table)
nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
void ipt_unregister_table_exit(struct net *net, struct xt_table *table)
void ipt_unregister_table_exit(struct net *net, const char *name)
{
__ipt_unregister_table(net, table);
}
struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
void ipt_unregister_table(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops)
{
if (ops)
ipt_unregister_table_pre_exit(net, table, ops);
__ipt_unregister_table(net, table);
if (table)
__ipt_unregister_table(net, table);
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
@ -1829,7 +1846,7 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV4,
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_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_unregister_table);
EXPORT_SYMBOL(ipt_unregister_table_pre_exit);
EXPORT_SYMBOL(ipt_unregister_table_exit);
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);
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_clusterip_tgt_info
{
u_int32_t flags;
@ -553,7 +553,7 @@ struct compat_ipt_clusterip_tgt_info
u_int32_t hash_initval;
compat_uptr_t config;
};
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_target clusterip_tg_reg __read_mostly = {
.name = "CLUSTERIP",
@ -563,9 +563,9 @@ static struct xt_target clusterip_tg_reg __read_mostly = {
.destroy = clusterip_tg_destroy,
.targetsize = sizeof(struct ipt_clusterip_tgt_info),
.usersize = offsetof(struct ipt_clusterip_tgt_info, config),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ipt_clusterip_tgt_info),
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
.me = THIS_MODULE
};

View File

@ -34,7 +34,7 @@ static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
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;
@ -48,9 +48,6 @@ static int __net_init iptable_filter_table_init(struct net *net)
struct ipt_replace *repl;
int err;
if (net->ipv4.iptable_filter)
return 0;
repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL)
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 =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ipt_register_table(net, &packet_filter, repl, filter_ops,
&net->ipv4.iptable_filter);
err = ipt_register_table(net, &packet_filter, repl, filter_ops);
kfree(repl);
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)
{
if (net->ipv4.iptable_filter)
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_filter,
filter_ops);
ipt_unregister_table_pre_exit(net, "filter");
}
static void __net_exit iptable_filter_net_exit(struct net *net)
{
if (!net->ipv4.iptable_filter)
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_filter);
net->ipv4.iptable_filter = NULL;
ipt_unregister_table_exit(net, "filter");
}
static struct pernet_operations iptable_filter_net_ops = {

View File

@ -37,7 +37,7 @@ static const struct xt_table packet_mangler = {
};
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;
const struct iphdr *iph;
@ -53,7 +53,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
daddr = iph->daddr;
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. */
if (ret != NF_DROP && ret != NF_STOLEN) {
iph = ip_hdr(skb);
@ -78,8 +78,8 @@ iptable_mangle_hook(void *priv,
const struct nf_hook_state *state)
{
if (state->hook == NF_INET_LOCAL_OUT)
return ipt_mangle_out(skb, state);
return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
return ipt_mangle_out(skb, state, priv);
return ipt_do_table(skb, state, priv);
}
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;
int ret;
if (net->ipv4.iptable_mangle)
return 0;
repl = ipt_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
&net->ipv4.iptable_mangle);
ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops);
kfree(repl);
return ret;
}
static void __net_exit iptable_mangle_net_pre_exit(struct net *net)
{
if (net->ipv4.iptable_mangle)
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_mangle,
mangle_ops);
ipt_unregister_table_pre_exit(net, "mangle");
}
static void __net_exit iptable_mangle_net_exit(struct net *net)
{
if (!net->ipv4.iptable_mangle)
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_mangle);
net->ipv4.iptable_mangle = NULL;
ipt_unregister_table_exit(net, "mangle");
}
static struct pernet_operations iptable_mangle_net_ops = {

View File

@ -13,8 +13,14 @@
#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 unsigned int iptable_nat_net_id __read_mostly;
static const struct xt_table nf_nat_ipv4_table = {
.name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) |
@ -30,7 +36,7 @@ static unsigned int iptable_nat_do_chain(void *priv,
struct sk_buff *skb,
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[] = {
@ -62,27 +68,49 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
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;
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++) {
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) {
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;
}
}
xt_nat_net->nf_nat_ops = ops;
return 0;
}
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;
if (!ops)
return;
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)
@ -90,24 +118,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
struct ipt_replace *repl;
int ret;
if (net->ipv4.nat_table)
return 0;
repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
if (repl == NULL)
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) {
kfree(repl);
return ret;
}
ret = ipt_nat_register_lookups(net);
if (ret < 0) {
ipt_unregister_table(net, net->ipv4.nat_table, NULL);
net->ipv4.nat_table = NULL;
}
if (ret < 0)
ipt_unregister_table_exit(net, "nat");
kfree(repl);
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)
{
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)
{
if (!net->ipv4.nat_table)
return;
ipt_unregister_table_exit(net, net->ipv4.nat_table);
net->ipv4.nat_table = NULL;
ipt_unregister_table_exit(net, "nat");
}
static struct pernet_operations iptable_nat_net_ops = {
.pre_exit = iptable_nat_net_pre_exit,
.exit = iptable_nat_net_exit,
.id = &iptable_nat_net_id,
.size = sizeof(struct iptable_nat_pernet),
};
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,
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;
@ -55,31 +55,22 @@ static int __net_init iptable_raw_table_init(struct net *net)
if (raw_before_defrag)
table = &packet_raw_before_defrag;
if (net->ipv4.iptable_raw)
return 0;
repl = ipt_alloc_initial_table(table);
if (repl == NULL)
return -ENOMEM;
ret = ipt_register_table(net, table, repl, rawtable_ops,
&net->ipv4.iptable_raw);
ret = ipt_register_table(net, table, repl, rawtable_ops);
kfree(repl);
return ret;
}
static void __net_exit iptable_raw_net_pre_exit(struct net *net)
{
if (net->ipv4.iptable_raw)
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_raw,
rawtable_ops);
ipt_unregister_table_pre_exit(net, "raw");
}
static void __net_exit iptable_raw_net_exit(struct net *net)
{
if (!net->ipv4.iptable_raw)
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_raw);
net->ipv4.iptable_raw = NULL;
ipt_unregister_table_exit(net, "raw");
}
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,
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;
@ -50,31 +50,22 @@ static int __net_init iptable_security_table_init(struct net *net)
struct ipt_replace *repl;
int ret;
if (net->ipv4.iptable_security)
return 0;
repl = ipt_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
ret = ipt_register_table(net, &security_table, repl, sectbl_ops,
&net->ipv4.iptable_security);
ret = ipt_register_table(net, &security_table, repl, sectbl_ops);
kfree(repl);
return ret;
}
static void __net_exit iptable_security_net_pre_exit(struct net *net)
{
if (net->ipv4.iptable_security)
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_security,
sectbl_ops);
ipt_unregister_table_pre_exit(net, "security");
}
static void __net_exit iptable_security_net_exit(struct net *net)
{
if (!net->ipv4.iptable_security)
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_security);
net->ipv4.iptable_security = NULL;
ipt_unregister_table_exit(net, "security");
}
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);
int err = 0;
might_sleep();
if (nf_defrag->users)
return 0;
mutex_lock(&defrag4_mutex);
if (nf_defrag->users)
if (nf_defrag->users == UINT_MAX) {
err = -EOVERFLOW;
goto out_unlock;
}
if (nf_defrag->users) {
nf_defrag->users++;
goto out_unlock;
}
err = nf_register_net_hooks(net, 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);
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_exit(nf_defrag_fini);

View File

@ -884,7 +884,7 @@ copy_entries_to_user(unsigned int total_size,
return ret;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *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;
name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(AF_INET6);
#endif
@ -981,7 +981,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) {
struct ip6t_getinfo info;
const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;
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);
} else
ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(AF_INET6);
#endif
@ -1215,7 +1215,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ip6t_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
@ -1630,7 +1630,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) {
case IP6T_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
@ -1663,7 +1663,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break;
case IP6T_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
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,
const struct ip6t_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 bootstrap = {0};
void *loc_cpu_entry;
@ -1742,50 +1743,62 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0)
goto out_free;
if (ret != 0) {
xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table);
xt_free_table_info(newinfo);
return PTR_ERR(new_table);
}
if (!template_ops)
return 0;
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
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) {
__ip6t_unregister_table(net, new_table);
*res = NULL;
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:
xt_free_table_info(newinfo);
__ip6t_unregister_table(net, new_table);
return ret;
}
void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops)
void ip6t_unregister_table_pre_exit(struct net *net, const char *name)
{
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
if (table)
nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
void ip6t_unregister_table_exit(struct net *net, struct xt_table *table)
void ip6t_unregister_table_exit(struct net *net, const char *name)
{
__ip6t_unregister_table(net, table);
}
struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
void ip6t_unregister_table(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops)
{
if (ops)
ip6t_unregister_table_pre_exit(net, table, ops);
__ip6t_unregister_table(net, table);
if (table)
__ip6t_unregister_table(net, table);
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
@ -1840,7 +1853,7 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV6,
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_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_unregister_table);
EXPORT_SYMBOL(ip6t_unregister_table_pre_exit);
EXPORT_SYMBOL(ip6t_unregister_table_exit);
EXPORT_SYMBOL(ip6t_do_table);

View File

@ -35,7 +35,7 @@ static unsigned int
ip6table_filter_hook(void *priv, struct sk_buff *skb,
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;
@ -49,9 +49,6 @@ static int __net_init ip6table_filter_table_init(struct net *net)
struct ip6t_replace *repl;
int err;
if (net->ipv6.ip6table_filter)
return 0;
repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL)
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 =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ip6t_register_table(net, &packet_filter, repl, filter_ops,
&net->ipv6.ip6table_filter);
err = ip6t_register_table(net, &packet_filter, repl, filter_ops);
kfree(repl);
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)
{
if (net->ipv6.ip6table_filter)
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_filter,
filter_ops);
ip6t_unregister_table_pre_exit(net, "filter");
}
static void __net_exit ip6table_filter_net_exit(struct net *net)
{
if (!net->ipv6.ip6table_filter)
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_filter);
net->ipv6.ip6table_filter = NULL;
ip6t_unregister_table_exit(net, "filter");
}
static struct pernet_operations ip6table_filter_net_ops = {

View File

@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = {
};
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;
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 = *((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 &&
(!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)
{
if (state->hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, state);
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle);
return ip6t_mangle_out(skb, state, priv);
return ip6t_do_table(skb, state, priv);
}
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;
int ret;
if (net->ipv6.ip6table_mangle)
return 0;
repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops,
&net->ipv6.ip6table_mangle);
ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops);
kfree(repl);
return ret;
}
static void __net_exit ip6table_mangle_net_pre_exit(struct net *net)
{
if (net->ipv6.ip6table_mangle)
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_mangle,
mangle_ops);
ip6t_unregister_table_pre_exit(net, "mangle");
}
static void __net_exit ip6table_mangle_net_exit(struct net *net)
{
if (!net->ipv6.ip6table_mangle)
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_mangle);
net->ipv6.ip6table_mangle = NULL;
ip6t_unregister_table_exit(net, "mangle");
}
static struct pernet_operations ip6table_mangle_net_ops = {

View File

@ -15,8 +15,14 @@
#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 unsigned int ip6table_nat_net_id __read_mostly;
static const struct xt_table nf_nat_ipv6_table = {
.name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) |
@ -32,7 +38,7 @@ static unsigned int ip6table_nat_do_chain(void *priv,
struct sk_buff *skb,
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[] = {
@ -64,27 +70,49 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
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;
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++) {
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) {
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;
}
}
xt_nat_net->nf_nat_ops = ops;
return 0;
}
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;
if (!ops)
return;
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)
@ -92,45 +120,39 @@ static int __net_init ip6table_nat_table_init(struct net *net)
struct ip6t_replace *repl;
int ret;
if (net->ipv6.ip6table_nat)
return 0;
repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
if (repl == NULL)
return -ENOMEM;
ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
NULL, &net->ipv6.ip6table_nat);
NULL);
if (ret < 0) {
kfree(repl);
return ret;
}
ret = ip6t_nat_register_lookups(net);
if (ret < 0) {
ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL);
net->ipv6.ip6table_nat = NULL;
}
if (ret < 0)
ip6t_unregister_table_exit(net, "nat");
kfree(repl);
return ret;
}
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)
{
if (!net->ipv6.ip6table_nat)
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_nat);
net->ipv6.ip6table_nat = NULL;
ip6t_unregister_table_exit(net, "nat");
}
static struct pernet_operations ip6table_nat_net_ops = {
.pre_exit = ip6table_nat_net_pre_exit,
.exit = ip6table_nat_net_exit,
.id = &ip6table_nat_net_id,
.size = sizeof(struct ip6table_nat_pernet),
};
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,
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;
@ -54,31 +54,22 @@ static int __net_init ip6table_raw_table_init(struct net *net)
if (raw_before_defrag)
table = &packet_raw_before_defrag;
if (net->ipv6.ip6table_raw)
return 0;
repl = ip6t_alloc_initial_table(table);
if (repl == NULL)
return -ENOMEM;
ret = ip6t_register_table(net, table, repl, rawtable_ops,
&net->ipv6.ip6table_raw);
ret = ip6t_register_table(net, table, repl, rawtable_ops);
kfree(repl);
return ret;
}
static void __net_exit ip6table_raw_net_pre_exit(struct net *net)
{
if (net->ipv6.ip6table_raw)
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_raw,
rawtable_ops);
ip6t_unregister_table_pre_exit(net, "raw");
}
static void __net_exit ip6table_raw_net_exit(struct net *net)
{
if (!net->ipv6.ip6table_raw)
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_raw);
net->ipv6.ip6table_raw = NULL;
ip6t_unregister_table_exit(net, "raw");
}
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,
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;
@ -49,31 +49,22 @@ static int __net_init ip6table_security_table_init(struct net *net)
struct ip6t_replace *repl;
int ret;
if (net->ipv6.ip6table_security)
return 0;
repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
ret = ip6t_register_table(net, &security_table, repl, sectbl_ops,
&net->ipv6.ip6table_security);
ret = ip6t_register_table(net, &security_table, repl, sectbl_ops);
kfree(repl);
return ret;
}
static void __net_exit ip6table_security_net_pre_exit(struct net *net)
{
if (net->ipv6.ip6table_security)
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_security,
sectbl_ops);
ip6t_unregister_table_pre_exit(net, "security");
}
static void __net_exit ip6table_security_net_exit(struct net *net)
{
if (!net->ipv6.ip6table_security)
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_security);
net->ipv6.ip6table_security = NULL;
ip6t_unregister_table_exit(net, "security");
}
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);
int err = 0;
might_sleep();
if (nf_frag->users)
return 0;
mutex_lock(&defrag6_mutex);
if (nf_frag->users)
if (nf_frag->users == UINT_MAX) {
err = -EOVERFLOW;
goto out_unlock;
}
if (nf_frag->users) {
nf_frag->users++;
goto out_unlock;
}
err = nf_register_net_hooks(net, 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);
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_exit(nf_defrag_fini);

View File

@ -728,6 +728,16 @@ config 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"
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;
}
static int ip_set_none(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_none(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
return -EOPNOTSUPP;
}
static int ip_set_create(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_create(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
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;
ip_set_id_t index = IPSET_INVALID_ID;
struct nlattr *tb[IPSET_ATTR_CREATE_MAX + 1] = {};
const char *name, *typename;
u8 family, revision;
u32 flags = flag_exist(nlh);
u32 flags = flag_exist(info->nlh);
int ret = 0;
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->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)
goto put_out;
@ -1183,12 +1179,10 @@ ip_set_destroy_set(struct ip_set *set)
kfree(set);
}
static int ip_set_destroy(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *s;
ip_set_id_t i;
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 */
inst->is_destroyed = false;
} else {
u32 flags = flag_exist(nlh);
u32 flags = flag_exist(info->nlh);
s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
&i);
if (!s) {
@ -1264,12 +1258,10 @@ ip_set_flush_set(struct ip_set *set)
ip_set_unlock(set);
}
static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_flush(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *s;
ip_set_id_t i;
@ -1304,12 +1296,10 @@ ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = {
.len = IPSET_MAXNAMELEN - 1 },
};
static int ip_set_rename(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_rename(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set, *s;
const char *name2;
ip_set_id_t i;
@ -1354,12 +1344,10 @@ out:
* 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,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *from, *to;
ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN];
@ -1669,10 +1657,8 @@ out:
return ret < 0 ? ret : skb->len;
}
static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_dump(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
if (unlikely(protocol_min_failed(attr)))
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,
.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;
}
static int ip_set_uadd(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_uadd(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
return ip_set_ad(net, ctnl, skb,
IPSET_ADD, nlh, attr, extack);
return ip_set_ad(info->net, info->sk, skb,
IPSET_ADD, info->nlh, attr, info->extack);
}
static int ip_set_udel(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_udel(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
return ip_set_ad(net, ctnl, skb,
IPSET_DEL, nlh, attr, extack);
return ip_set_ad(info->net, info->sk, skb,
IPSET_DEL, info->nlh, attr, info->extack);
}
static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_utest(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
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 */
static int ip_set_header(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_header(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
const struct ip_set *set;
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@ -1895,7 +1873,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
if (!skb2)
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);
if (!nlh2)
goto nlmsg_failure;
@ -1907,7 +1885,8 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
goto nla_put_failure;
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)
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 },
};
static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_type(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@ -1955,7 +1932,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
if (!skb2)
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);
if (!nlh2)
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);
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)
return ret;
@ -1988,10 +1966,8 @@ ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
};
static int ip_set_protocol(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_protocol(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@ -2004,7 +1980,7 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
if (!skb2)
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);
if (!nlh2)
goto nlmsg_failure;
@ -2014,7 +1990,8 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
goto nla_put_failure;
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)
return ret;
@ -2029,12 +2006,10 @@ nlmsg_failure:
/* Get set by name or index, from userspace */
static int ip_set_byname(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_byname(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
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)
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);
if (!nlh2)
goto nlmsg_failure;
@ -2063,7 +2038,8 @@ static int ip_set_byname(struct net *net, struct sock *ctnl,
goto nla_put_failure;
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)
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 },
};
static int ip_set_byindex(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
static int ip_set_byindex(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const attr[])
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set_net *inst = ip_set_pernet(info->net);
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
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)
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);
if (!nlh2)
goto nlmsg_failure;
@ -2117,7 +2091,8 @@ static int ip_set_byindex(struct net *net, struct sock *ctnl,
goto nla_put_failure;
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)
return ret;
@ -2133,80 +2108,96 @@ nlmsg_failure:
static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
[IPSET_CMD_NONE] = {
.call = ip_set_none,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
},
[IPSET_CMD_CREATE] = {
.call = ip_set_create,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_create_policy,
},
[IPSET_CMD_DESTROY] = {
.call = ip_set_destroy,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_FLUSH] = {
.call = ip_set_flush,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_RENAME] = {
.call = ip_set_rename,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname2_policy,
},
[IPSET_CMD_SWAP] = {
.call = ip_set_swap,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname2_policy,
},
[IPSET_CMD_LIST] = {
.call = ip_set_dump,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_dump_policy,
},
[IPSET_CMD_SAVE] = {
.call = ip_set_dump,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_ADD] = {
.call = ip_set_uadd,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy,
},
[IPSET_CMD_DEL] = {
.call = ip_set_udel,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy,
},
[IPSET_CMD_TEST] = {
.call = ip_set_utest,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy,
},
[IPSET_CMD_HEADER] = {
.call = ip_set_header,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_TYPE] = {
.call = ip_set_type,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_type_policy,
},
[IPSET_CMD_PROTOCOL] = {
.call = ip_set_protocol,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_protocol_policy,
},
[IPSET_CMD_GET_BYNAME] = {
.call = ip_set_byname,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_GET_BYINDEX] = {
.call = ip_set_byindex,
.type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_index_policy,
},

View File

@ -1524,17 +1524,15 @@ static int ctnetlink_flush_conntrack(struct net *net,
return 0;
}
static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_del_conntrack(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
struct nf_conn *ct;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nf_conntrack_zone zone;
struct nf_conn *ct;
int err;
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@ -1550,15 +1548,15 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
else {
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,
nlmsg_report(nlh), u3);
nlmsg_report(info->nlh), u3);
}
if (err < 0)
return err;
h = nf_conntrack_find_get(net, &zone, &tuple);
h = nf_conntrack_find_get(info->net, &zone, &tuple);
if (!h)
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);
return 0;
}
static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_get_conntrack(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple_hash *h;
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 sk_buff *skb2;
struct nf_conn *ct;
int err;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = ctnetlink_start,
.dump = ctnetlink_dump_table,
@ -1607,7 +1603,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
.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);
@ -1626,7 +1622,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
if (err < 0)
return err;
h = nf_conntrack_find_get(net, &zone, &tuple);
h = nf_conntrack_find_get(info->net, &zone, &tuple);
if (!h)
return -ENOENT;
@ -1639,13 +1635,16 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
return -ENOMEM;
}
err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), ct, true, 0);
err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type), ct,
true, 0);
nf_ct_put(ct);
if (err <= 0)
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)
goto out;
@ -1743,18 +1742,16 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
return ctnetlink_dump_list(skb, cb, true);
}
static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_get_ct_dying(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_dump_dying,
.done = ctnetlink_done_list,
};
return netlink_dump_start(ctnl, skb, nlh, &c);
return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
return -EOPNOTSUPP;
@ -1766,18 +1763,16 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
return ctnetlink_dump_list(skb, cb, false);
}
static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_get_ct_unconfirmed(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_dump_unconfirmed,
.done = ctnetlink_done_list,
};
return netlink_dump_start(ctnl, skb, nlh, &c);
return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
return -EOPNOTSUPP;
@ -2374,18 +2369,16 @@ err1:
return ERR_PTR(err);
}
static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_new_conntrack(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_tuple_hash *h = NULL;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nf_conn *ct;
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
struct nf_conn *ct;
int err;
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])
h = nf_conntrack_find_get(net, &zone, &otuple);
h = nf_conntrack_find_get(info->net, &zone, &otuple);
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) {
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE) {
if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
enum ip_conntrack_events events;
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)
return -EINVAL;
ct = ctnetlink_create_conntrack(net, &zone, cda, &otuple,
&rtuple, u3);
ct = ctnetlink_create_conntrack(info->net, &zone, cda,
&otuple, &rtuple, u3);
if (IS_ERR(ct))
return PTR_ERR(ct);
@ -2445,7 +2438,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_SYNPROXY) |
events,
ct, NETLINK_CB(skb).portid,
nlmsg_report(nlh));
nlmsg_report(info->nlh));
nf_ct_put(ct);
}
@ -2455,7 +2448,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
err = -EEXIST;
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);
if (err == 0) {
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_SYNPROXY),
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;
}
static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_stat_ct_cpu(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.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;
@ -2585,10 +2576,8 @@ nlmsg_failure:
return -1;
}
static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_stat_ct(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct sk_buff *skb2;
int err;
@ -2598,13 +2587,14 @@ static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
return -ENOMEM;
err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
sock_net(skb->sk));
if (err <= 0)
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)
goto out;
@ -3284,29 +3274,29 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
return err;
}
static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_get_expect(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple tuple;
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 sk_buff *skb2;
int err;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
if (cda[CTA_EXPECT_MASTER])
return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda,
extack);
return ctnetlink_dump_exp_ct(info->net, info->sk, skb,
info->nlh, cda,
info->extack);
else {
struct netlink_dump_control c = {
.dump = ctnetlink_exp_dump_table,
.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)
return err;
exp = nf_ct_expect_find_get(net, &zone, &tuple);
exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
if (!exp)
return -ENOENT;
@ -3348,13 +3338,15 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
rcu_read_lock();
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();
nf_ct_expect_put(exp);
if (err <= 0)
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)
goto out;
@ -3382,15 +3374,14 @@ static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
return true;
}
static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_del_expect(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple tuple;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
int err;
@ -3406,7 +3397,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
return err;
/* 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)
return -ENOENT;
@ -3422,7 +3413,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
spin_lock_bh(&nf_conntrack_expect_lock);
if (del_timer(&exp->timeout)) {
nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
nlmsg_report(nlh));
nlmsg_report(info->nlh));
nf_ct_expect_put(exp);
}
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]) {
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,
nlmsg_report(nlh));
nlmsg_report(info->nlh));
} else {
/* 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,
nlmsg_report(nlh));
nlmsg_report(info->nlh));
}
return 0;
@ -3635,15 +3626,14 @@ err_ct:
return err;
}
static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_new_expect(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
int err;
@ -3662,20 +3652,20 @@ static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
return err;
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) {
spin_unlock_bh(&nf_conntrack_expect_lock);
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE) {
err = ctnetlink_create_expect(net, &zone, cda, u3,
if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
err = ctnetlink_create_expect(info->net, &zone, cda, u3,
NETLINK_CB(skb).portid,
nlmsg_report(nlh));
nlmsg_report(info->nlh));
}
return err;
}
err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL))
if (!(info->nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_expect(exp, cda);
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;
}
static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int ctnetlink_stat_exp_cpu(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.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;
@ -3763,35 +3751,71 @@ static struct nf_exp_event_notifier ctnl_notifier_exp = {
#endif
static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
.attr_count = CTA_MAX,
.policy = ct_nla_policy },
[IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
.attr_count = CTA_MAX,
.policy = ct_nla_policy },
[IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
.attr_count = CTA_MAX,
.policy = ct_nla_policy },
[IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
.attr_count = CTA_MAX,
.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_DYING] = { .call = ctnetlink_get_ct_dying },
[IPCTNL_MSG_CT_GET_UNCONFIRMED] = { .call = ctnetlink_get_ct_unconfirmed },
[IPCTNL_MSG_CT_NEW] = {
.call = ctnetlink_new_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX,
.policy = ct_nla_policy
},
[IPCTNL_MSG_CT_GET] = {
.call = ctnetlink_get_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX,
.policy = ct_nla_policy
},
[IPCTNL_MSG_CT_DELETE] = {
.call = ctnetlink_del_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX,
.policy = ct_nla_policy
},
[IPCTNL_MSG_CT_GET_CTRZERO] = {
.call = ctnetlink_get_conntrack,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_MAX,
.policy = ct_nla_policy
},
[IPCTNL_MSG_CT_GET_STATS_CPU] = {
.call = ctnetlink_stat_ct_cpu,
.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] = {
[IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy },
[IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy },
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy },
[IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu },
[IPCTNL_MSG_EXP_GET] = {
.call = ctnetlink_get_expect,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy
},
[IPCTNL_MSG_EXP_NEW] = {
.call = ctnetlink_new_expect,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy
},
[IPCTNL_MSG_EXP_DELETE] = {
.call = ctnetlink_del_expect,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy
},
[IPCTNL_MSG_EXP_GET_STATS_CPU] = {
.call = ctnetlink_stat_exp_cpu,
.type = NFNL_CB_MUTEX,
},
};
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);
switch (nfproto) {
case NFPROTO_IPV4:
if (cnet->users4 && (--cnet->users4 == 0))
if (cnet->users4 && (--cnet->users4 == 0)) {
nf_unregister_net_hooks(net, ipv4_conntrack_ops,
ARRAY_SIZE(ipv4_conntrack_ops));
nf_defrag_ipv4_disable(net);
}
break;
#if IS_ENABLED(CONFIG_IPV6)
case NFPROTO_IPV6:
if (cnet->users6 && (--cnet->users6 == 0))
if (cnet->users6 && (--cnet->users6 == 0)) {
nf_unregister_net_hooks(net, ipv6_conntrack_ops,
ARRAY_SIZE(ipv6_conntrack_ops));
nf_defrag_ipv6_disable(net);
}
break;
#endif
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_ip6_logger);
nf_log_unset(net, &nf_netdev_logger);
nf_log_unset(net, &nf_bridge_logger);
}
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;
}
}
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 */
/* 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;
}
#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
nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb,
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/pkt_cls.h>
extern unsigned int nf_tables_net_id;
static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
{
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,
basechain, &extack);
nft_net = net_generic(net, nf_tables_net_id);
nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
list_del(&block_cb->driver_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,
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;
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)
{
struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans;
int err = 0;
u8 policy;
@ -663,7 +661,7 @@ static int nft_offload_netdev_event(struct notifier_block *this,
if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE;
nft_net = net_generic(net, nf_tables_net_id);
nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
chain = __nft_offload_get_chain(nft_net, dev);
if (chain)

View File

@ -252,6 +252,12 @@ replay:
struct nlattr *attr = (void *)nlh + min_len;
int attrlen = nlh->nlmsg_len - min_len;
__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 */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
@ -267,24 +273,30 @@ replay:
return err;
}
if (nc->call_rcu) {
err = nc->call_rcu(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
extack);
if (!nc->call) {
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();
nfnl_lock(subsys_id);
if (nfnl_dereference_protected(subsys_id) != ss ||
nfnetlink_find_client(type, ss) != nc)
nfnetlink_find_client(type, ss) != nc) {
err = -EAGAIN;
else if (nc->call)
err = nc->call(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
extack);
else
err = -EINVAL;
break;
}
err = nc->call(skb, &info, (const struct nlattr **)cda);
nfnl_unlock(subsys_id);
break;
default:
err = -EINVAL;
break;
}
if (err == -EAGAIN)
goto replay;
@ -462,12 +474,24 @@ replay_abort:
goto ack;
}
if (nc->type != NFNL_CB_BATCH) {
err = -EINVAL;
goto ack;
}
{
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 *attr = (void *)nlh + min_len;
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
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 */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
@ -482,13 +506,7 @@ replay_abort:
if (err < 0)
goto ack;
if (nc->call_batch) {
struct nfnl_net *nfnlnet = nfnl_pernet(net);
err = nc->call_batch(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
&extack);
}
err = nc->call(skb, &info, (const struct nlattr **)cda);
/* The lock was released to autoload some module, we
* 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_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
static int nfnl_acct_new(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_acct_new(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const tb[])
{
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;
char *acct_name;
unsigned int size = 0;
char *acct_name;
u32 flags = 0;
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)
continue;
if (nlh->nlmsg_flags & NLM_F_EXCL)
if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
matching = nfacct;
@ -86,7 +84,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
}
if (matching) {
if (nlh->nlmsg_flags & NLM_F_REPLACE) {
if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
/* reset counters if you request a replacement. */
atomic64_set(&matching->pkts, 0);
atomic64_set(&matching->bytes, 0);
@ -273,17 +271,15 @@ static int nfnl_acct_start(struct netlink_callback *cb)
return 0;
}
static int nfnl_acct_get(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_acct_get(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const tb[])
{
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;
struct nf_acct *cur;
char *acct_name;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = nfnl_acct_dump,
.start = nfnl_acct_start,
@ -291,7 +287,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
.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])
@ -311,15 +307,15 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
}
ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
NFNL_MSG_ACCT_NEW, cur);
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_ACCT_NEW, cur);
if (ret <= 0) {
kfree_skb(skb2);
break;
}
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret > 0)
ret = 0;
@ -347,12 +343,10 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
return ret;
}
static int nfnl_acct_del(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_acct_del(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const tb[])
{
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;
int ret = -ENOENT;
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] = {
[NFNL_MSG_ACCT_NEW] = { .call = nfnl_acct_new,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy },
[NFNL_MSG_ACCT_GET] = { .call = nfnl_acct_get,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy },
[NFNL_MSG_ACCT_GET_CTRZERO] = { .call = nfnl_acct_get,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy },
[NFNL_MSG_ACCT_DEL] = { .call = nfnl_acct_del,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy },
[NFNL_MSG_ACCT_NEW] = {
.call = nfnl_acct_new,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy
},
[NFNL_MSG_ACCT_GET] = {
.call = nfnl_acct_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy
},
[NFNL_MSG_ACCT_GET_CTRZERO] = {
.call = nfnl_acct_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy
},
[NFNL_MSG_ACCT_DEL] = {
.call = nfnl_acct_del,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy
},
};
static const struct nfnetlink_subsystem nfnl_acct_subsys = {

View File

@ -408,10 +408,8 @@ nfnl_cthelper_update(const struct nlattr * const tb[],
return 0;
}
static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const tb[])
{
const char *helper_name;
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))
continue;
if (nlh->nlmsg_flags & NLM_F_EXCL)
if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
helper = cur;
@ -607,10 +605,8 @@ out:
return skb->len;
}
static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const tb[])
{
int ret = -ENOENT;
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))
return -EPERM;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.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])
@ -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,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_CTHELPER_NEW, cur);
if (ret <= 0) {
kfree_skb(skb2);
break;
}
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret > 0)
ret = 0;
@ -678,10 +674,8 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
return ret;
}
static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const tb[])
{
char *helper_name = NULL;
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] = {
[NFNL_MSG_CTHELPER_NEW] = { .call = nfnl_cthelper_new,
.attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy },
[NFNL_MSG_CTHELPER_GET] = { .call = nfnl_cthelper_get,
.attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy },
[NFNL_MSG_CTHELPER_DEL] = { .call = nfnl_cthelper_del,
.attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy },
[NFNL_MSG_CTHELPER_NEW] = {
.call = nfnl_cthelper_new,
.type = NFNL_CB_MUTEX,
.attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy
},
[NFNL_MSG_CTHELPER_GET] = {
.call = nfnl_cthelper_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy
},
[NFNL_MSG_CTHELPER_DEL] = {
.call = nfnl_cthelper_del,
.type = NFNL_CB_MUTEX,
.attr_count = NFCTH_MAX,
.policy = nfnl_cthelper_policy
},
};
static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {

View File

@ -83,13 +83,11 @@ err:
return ret;
}
static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int cttimeout_new_timeout(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
__u16 l3num;
__u8 l4num;
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)
continue;
if (nlh->nlmsg_flags & NLM_F_EXCL)
if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
matching = timeout;
@ -119,7 +117,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
}
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
* 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,
matching->timeout.l4proto,
net, cda[CTA_TIMEOUT_DATA]);
info->net,
cda[CTA_TIMEOUT_DATA]);
}
return -EBUSY;
@ -150,8 +149,8 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
goto err_proto_put;
}
ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto, net,
cda[CTA_TIMEOUT_DATA]);
ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto,
info->net, cda[CTA_TIMEOUT_DATA]);
if (ret < 0)
goto err;
@ -248,22 +247,20 @@ ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int cttimeout_get_timeout(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
int ret = -ENOENT;
char *name;
struct ctnl_timeout *cur;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.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])
@ -283,15 +280,15 @@ static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
}
ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
IPCTNL_MSG_TIMEOUT_NEW, cur);
if (ret <= 0) {
kfree_skb(skb2);
break;
}
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)
ret = 0;
@ -320,13 +317,11 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
return ret;
}
static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int cttimeout_del_timeout(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
struct ctnl_timeout *cur, *tmp;
int ret = -ENOENT;
char *name;
@ -334,7 +329,7 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
if (!cda[CTA_TIMEOUT_NAME]) {
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list,
head)
ctnl_timeout_try_del(net, cur);
ctnl_timeout_try_del(info->net, cur);
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)
continue;
ret = ctnl_timeout_try_del(net, cur);
ret = ctnl_timeout_try_del(info->net, cur);
if (ret < 0)
return ret;
@ -353,11 +348,9 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
return ret;
}
static int cttimeout_default_set(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int cttimeout_default_set(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
const struct nf_conntrack_l4proto *l4proto;
__u8 l4num;
@ -377,7 +370,7 @@ static int cttimeout_default_set(struct net *net, struct sock *ctnl,
goto err;
}
ret = ctnl_timeout_parse_policy(NULL, l4proto, net,
ret = ctnl_timeout_parse_policy(NULL, l4proto, info->net,
cda[CTA_TIMEOUT_DATA]);
if (ret < 0)
goto err;
@ -427,11 +420,9 @@ nla_put_failure:
return -1;
}
static int cttimeout_default_get(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack)
static int cttimeout_default_get(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const cda[])
{
const struct nf_conntrack_l4proto *l4proto;
unsigned int *timeouts = NULL;
@ -453,35 +444,35 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
switch (l4proto->l4proto) {
case IPPROTO_ICMP:
timeouts = &nf_icmp_pernet(net)->timeout;
timeouts = &nf_icmp_pernet(info->net)->timeout;
break;
case IPPROTO_TCP:
timeouts = nf_tcp_pernet(net)->timeouts;
timeouts = nf_tcp_pernet(info->net)->timeouts;
break;
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
timeouts = nf_udp_pernet(net)->timeouts;
timeouts = nf_udp_pernet(info->net)->timeouts;
break;
case IPPROTO_DCCP:
#ifdef CONFIG_NF_CT_PROTO_DCCP
timeouts = nf_dccp_pernet(net)->dccp_timeout;
timeouts = nf_dccp_pernet(info->net)->dccp_timeout;
#endif
break;
case IPPROTO_ICMPV6:
timeouts = &nf_icmpv6_pernet(net)->timeout;
timeouts = &nf_icmpv6_pernet(info->net)->timeout;
break;
case IPPROTO_SCTP:
#ifdef CONFIG_NF_CT_PROTO_SCTP
timeouts = nf_sctp_pernet(net)->timeouts;
timeouts = nf_sctp_pernet(info->net)->timeouts;
#endif
break;
case IPPROTO_GRE:
#ifdef CONFIG_NF_CT_PROTO_GRE
timeouts = nf_gre_pernet(net)->timeouts;
timeouts = nf_gre_pernet(info->net)->timeouts;
#endif
break;
case 255:
timeouts = &nf_generic_pernet(net)->timeout;
timeouts = &nf_generic_pernet(info->net)->timeout;
break;
default:
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;
}
ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
ret = cttimeout_default_fill_info(info->net, skb2,
NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
l3num, l4proto, timeouts);
if (ret <= 0) {
@ -507,7 +499,8 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
err = -ENOMEM;
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)
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] = {
[IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy },
[IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy },
[IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy },
[IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy },
[IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy },
[IPCTNL_MSG_TIMEOUT_NEW] = {
.call = cttimeout_new_timeout,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy
},
[IPCTNL_MSG_TIMEOUT_GET] = {
.call = cttimeout_get_timeout,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy
},
[IPCTNL_MSG_TIMEOUT_DELETE] = {
.call = cttimeout_del_timeout,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy
},
[IPCTNL_MSG_TIMEOUT_DEFAULT_SET] = {
.call = cttimeout_default_set,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy
},
[IPCTNL_MSG_TIMEOUT_DEFAULT_GET] = {
.call = cttimeout_default_get,
.type = NFNL_CB_MUTEX,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy
},
};
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,
};
static int nfulnl_recv_unsupp(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
static int nfulnl_recv_unsupp(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const nfula[])
{
return -ENOTSUPP;
}
@ -869,18 +867,16 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = {
[NFULA_CFG_FLAGS] = { .type = NLA_U16 },
};
static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfula[],
struct netlink_ext_ack *extack)
static int nfulnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const nfula[])
{
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);
struct nfulnl_instance *inst;
struct nfulnl_msg_config_cmd *cmd = NULL;
struct nfnl_log_net *log = nfnl_log_pernet(net);
int ret = 0;
struct nfulnl_instance *inst;
u16 flags = 0;
int ret = 0;
if (nfula[NFULA_CFG_CMD]) {
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 */
switch (cmd->command) {
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:
nf_log_unbind_pf(net, pf);
nf_log_unbind_pf(info->net, pf);
return 0;
}
}
@ -932,7 +928,7 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
goto out_put;
}
inst = instance_create(net, group_num,
inst = instance_create(info->net, group_num,
NETLINK_CB(skb).portid,
sk_user_ns(NETLINK_CB(skb).sk));
if (IS_ERR(inst)) {
@ -993,11 +989,17 @@ out:
}
static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
[NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp,
.attr_count = NFULA_MAX, },
[NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config,
.attr_count = NFULA_CFG_MAX,
.policy = nfula_cfg_policy },
[NFULNL_MSG_PACKET] = {
.call = nfulnl_recv_unsupp,
.type = NFNL_CB_MUTEX,
.attr_count = NFULA_MAX,
},
[NFULNL_MSG_CONFIG] = {
.call = nfulnl_recv_config,
.type = NFNL_CB_MUTEX,
.attr_count = NFULA_CFG_MAX,
.policy = nfula_cfg_policy
},
};
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) },
};
static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const osf_attrs[],
struct netlink_ext_ack *extack)
static int nfnl_osf_add_callback(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const osf_attrs[])
{
struct nf_osf_user_finger *f;
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])
return -EINVAL;
if (!(nlh->nlmsg_flags & NLM_F_CREATE))
if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
return -EINVAL;
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);
kf = NULL;
if (nlh->nlmsg_flags & NLM_F_EXCL)
if (info->nlh->nlmsg_flags & NLM_F_EXCL)
err = -EEXIST;
break;
}
@ -339,11 +338,9 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
return err;
}
static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const osf_attrs[],
struct netlink_ext_ack *extack)
static int nfnl_osf_remove_callback(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const osf_attrs[])
{
struct nf_osf_user_finger *f;
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] = {
[OSF_MSG_ADD] = {
.call = nfnl_osf_add_callback,
.type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy,
},
[OSF_MSG_REMOVE] = {
.call = nfnl_osf_remove_callback,
.type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX,
.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;
}
static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
static int nfqnl_recv_verdict_batch(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const nfqa[])
{
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;
unsigned int verdict, maxid;
struct nfqnl_msg_verdict_hdr *vhdr;
struct nfqnl_instance *queue;
unsigned int verdict, maxid;
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,
NETLINK_CB(skb).portid);
@ -1158,22 +1156,19 @@ static int nfqa_parse_bridge(struct nf_queue_entry *entry,
return 0;
}
static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const nfqa[])
{
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);
struct nfqnl_msg_verdict_hdr *vhdr;
struct nfqnl_instance *queue;
unsigned int verdict;
struct nf_queue_entry *entry;
enum ip_conntrack_info ctinfo;
struct nfqnl_instance *queue;
struct nf_queue_entry *entry;
struct nfnl_ct_hook *nfnl_ct;
struct nf_conn *ct = NULL;
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
unsigned int verdict;
int err;
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 (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) {
@ -1224,10 +1220,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
return 0;
}
static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
static int nfqnl_recv_unsupp(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const cda[])
{
return -ENOTSUPP;
}
@ -1245,16 +1239,14 @@ static const struct nf_queue_handler nfqh = {
.nf_hook_drop = nfqnl_nf_hook_drop,
};
static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nfqa[],
struct netlink_ext_ack *extack)
static int nfqnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const nfqa[])
{
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);
struct nfqnl_instance *queue;
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;
int ret = 0;
@ -1373,17 +1365,29 @@ err_out_unlock:
}
static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
[NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp,
.attr_count = NFQA_MAX, },
[NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict,
.attr_count = NFQA_MAX,
.policy = nfqa_verdict_policy },
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
.attr_count = NFQA_CFG_MAX,
.policy = nfqa_cfg_policy },
[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
.attr_count = NFQA_MAX,
.policy = nfqa_verdict_batch_policy },
[NFQNL_MSG_PACKET] = {
.call = nfqnl_recv_unsupp,
.type = NFNL_CB_RCU,
.attr_count = NFQA_MAX,
},
[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,
.policy = nfqa_cfg_policy
},
[NFQNL_MSG_VERDICT_BATCH] = {
.call = nfqnl_recv_verdict_batch,
.type = NFNL_CB_RCU,
.attr_count = NFQA_MAX,
.policy = nfqa_verdict_batch_policy
},
};
static const struct nfnetlink_subsystem nfqnl_subsys = {

View File

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

View File

@ -613,17 +613,15 @@ nla_put_failure:
return -1;
}
static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
static int nfnl_compat_get_rcu(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const tb[])
{
int ret = 0, target;
struct nfgenmsg *nfmsg;
const char *fmt;
const char *name;
u32 rev;
const char *name, *fmt;
struct sk_buff *skb2;
int ret = 0, target;
u32 rev;
if (tb[NFTA_COMPAT_NAME] == 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]));
target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
nfmsg = nlmsg_data(nlh);
nfmsg = nlmsg_data(info->nlh);
switch(nfmsg->nfgen_family) {
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 */
if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_COMPAT_GET,
nfmsg->nfgen_family,
name, ret, target) <= 0) {
@ -682,8 +680,8 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
goto out_put;
}
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret > 0)
ret = 0;
out_put:
@ -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] = {
[NFNL_MSG_COMPAT_GET] = { .call_rcu = nfnl_compat_get_rcu,
.attr_count = NFTA_COMPAT_MAX,
.policy = nfnl_compat_policy_get },
[NFNL_MSG_COMPAT_GET] = {
.call = nfnl_compat_get_rcu,
.type = NFNL_CB_RCU,
.attr_count = NFTA_COMPAT_MAX,
.policy = nfnl_compat_policy_get
},
};
static const struct nfnetlink_subsystem nfnl_compat_subsys = {

View File

@ -11,9 +11,6 @@
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.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_set *set;
@ -164,7 +161,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
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);
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set;

View File

@ -9,6 +9,7 @@
struct nft_socket {
enum nft_socket_keys key:8;
u8 level;
union {
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,
struct nft_regs *regs,
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);
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:
WARN_ON(1);
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] = {
[NFTA_SOCKET_KEY] = { .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,
@ -104,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[])
{
struct nft_socket *priv = nft_expr_priv(expr);
unsigned int len;
unsigned int len, level;
if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
return -EINVAL;
@ -129,6 +159,19 @@ static int nft_socket_init(const struct nft_ctx *ctx,
case NFT_SOCKET_MARK:
len = sizeof(u32);
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:
return -EOPNOTSUPP;
}
@ -146,6 +189,9 @@ static int nft_socket_dump(struct sk_buff *skb,
return -1;
if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
return -1;
if (priv->key == NFT_SOCKET_CGROUPV2 &&
nla_put_u32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level)))
return -1;
return 0;
}

View File

@ -263,6 +263,29 @@ static int nft_tproxy_init(const struct nft_ctx *ctx,
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,
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)),
.eval = nft_tproxy_eval,
.init = nft_tproxy_init,
.destroy = nft_tproxy_destroy,
.dump = nft_tproxy_dump,
};

View File

@ -52,7 +52,7 @@ struct xt_af {
struct mutex mutex;
struct list_head match;
struct list_head target;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct mutex compat_mutex;
struct compat_delta *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;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
{
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));
}
EXPORT_SYMBOL(xt_compat_check_entry_offsets);
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
/**
* 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
* 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:
* - it must point to a valid memory location
@ -1059,7 +1059,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
void *mem;
u64 size;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) {
/* structures only differ in size due to alignment */
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);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
int xt_compat_target_offset(const struct xt_target *target)
{
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);
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. */
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name)
@ -1276,7 +1293,7 @@ void xt_table_unlock(struct xt_table *table)
}
EXPORT_SYMBOL_GPL(xt_table_unlock);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
void xt_compat_lock(u_int8_t af)
{
mutex_lock(&xt[af].compat_mutex);
@ -1481,6 +1498,7 @@ void *xt_unregister_table(struct xt_table *table)
mutex_unlock(&xt[table->af].mutex);
audit_log_nfcfg(table->name, table->af, private->number,
AUDIT_XT_OP_UNREGISTER, GFP_KERNEL);
kfree(table->ops);
kfree(table);
return private;
@ -1913,7 +1931,7 @@ static int __init xt_init(void)
for (i = 0; i < NFPROTO_NUMPROTO; i++) {
mutex_init(&xt[i].mutex);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
mutex_init(&xt[i].compat_mutex);
xt[i].compat_tab = NULL;
#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");
return -EINVAL;
}
static void tproxy_tg6_destroy(const struct xt_tgdtor_param *par)
{
nf_defrag_ipv6_disable(par->net);
}
#endif
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;
}
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 = {
{
.name = "TPROXY",
@ -228,6 +238,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 0,
.targetsize = sizeof(struct xt_tproxy_target_info),
.checkentry = tproxy_tg4_check,
.destroy = tproxy_tg4_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},
@ -239,6 +250,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg4_check,
.destroy = tproxy_tg4_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},
@ -251,6 +263,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg6_check,
.destroy = tproxy_tg6_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},

View File

@ -134,7 +134,7 @@ static void limit_mt_destroy(const struct xt_mtdtor_param *par)
kfree(info->master);
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_xt_rateinfo {
u_int32_t avg;
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;
}
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_match limit_mt_reg __read_mostly = {
.name = "limit",
@ -186,7 +186,7 @@ static struct xt_match limit_mt_reg __read_mostly = {
.checkentry = limit_mt_check,
.destroy = limit_mt_destroy,
.matchsize = sizeof(struct xt_rateinfo),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_xt_rateinfo),
.compat_from_user = limit_mt_compat_from_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;
}
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 = {
{
.name = "socket",
@ -231,6 +239,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.revision = 1,
.family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3,
.destroy = socket_mt_destroy,
.checkentry = socket_mt_v1_check,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.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,
.checkentry = socket_mt_v1_check,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.destroy = socket_mt_destroy,
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
@ -256,6 +266,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3,
.checkentry = socket_mt_v2_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
@ -268,6 +279,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6,
.match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v2_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
@ -280,6 +292,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3,
.checkentry = socket_mt_v3_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
@ -292,6 +305,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6,
.match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v3_check,
.destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),