forked from Minki/linux
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:
commit
eb43c081a6
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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 = {
|
||||
|
@ -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:
|
||||
|
@ -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 = {
|
||||
|
@ -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. */
|
||||
|
@ -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
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user