Commit 6f45933d authored by David S. Miller's avatar David S. Miller

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) Use nfnetlink_unicast() instead of netlink_unicast() in nft_compat.

2) Remove call to nf_ct_l4proto_find() in flowtable offload timeout
   fixup.

3) CLUSTERIP registers ARP hook on demand, from Florian.

4) Use clusterip_net to store pernet warning, also from Florian.

5) Remove struct netns_xt, from Florian Westphal.

6) Enable ebtables hooks in initns on demand, from Florian.

7) Allow to filter conntrack netlink dump per status bits,
   from Florian Westphal.

8) Register x_tables hooks in initns on demand, from Florian.

9) Remove queue_handler from per-netns structure, again from Florian.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d3432bf1 87029970
......@@ -238,9 +238,6 @@ struct xt_table {
u_int8_t af; /* address/protocol family */
int priority; /* hook order */
/* called when table is needed in the given netns */
int (*table_init)(struct net *net);
/* A unique name... */
const char name[XT_TABLE_MAXNAMELEN];
};
......@@ -452,6 +449,9 @@ 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 *);
int xt_register_template(const struct xt_table *t, int(*table_init)(struct net *net));
void xt_unregister_template(const struct xt_table *t);
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
......
......@@ -127,4 +127,6 @@ static inline bool ebt_invalid_target(int target)
return (target < -NUM_STANDARD_TARGETS || target >= 0);
}
int ebt_register_template(const struct ebt_table *t, int(*table_init)(struct net *net));
void ebt_unregister_template(const struct ebt_table *t);
#endif
......@@ -23,7 +23,6 @@
#include <net/netns/ieee802154_6lowpan.h>
#include <net/netns/sctp.h>
#include <net/netns/netfilter.h>
#include <net/netns/x_tables.h>
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
#include <net/netns/conntrack.h>
#endif
......@@ -133,7 +132,6 @@ struct net {
#endif
#ifdef CONFIG_NETFILTER
struct netns_nf nf;
struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
#endif
......
......@@ -33,8 +33,8 @@ struct nf_queue_handler {
void (*nf_hook_drop)(struct net *net);
};
void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
void nf_unregister_queue_handler(struct net *net);
void nf_register_queue_handler(const struct nf_queue_handler *qh);
void nf_unregister_queue_handler(void);
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
......
......@@ -12,7 +12,6 @@ struct netns_nf {
#if defined CONFIG_PROC_FS
struct proc_dir_entry *proc_netfilter;
#endif
const struct nf_queue_handler __rcu *queue_handler;
const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
#ifdef CONFIG_SYSCTL
struct ctl_table_header *nf_log_dir_header;
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NETNS_X_TABLES_H
#define __NETNS_X_TABLES_H
#include <linux/list.h>
#include <linux/netfilter_defs.h>
struct netns_xt {
bool notrack_deprecated_warning;
bool clusterip_deprecated_warning;
};
#endif
......@@ -56,6 +56,7 @@ enum ctattr_type {
CTA_LABELS_MASK,
CTA_SYNPROXY,
CTA_FILTER,
CTA_STATUS_MASK,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
......
......@@ -98,7 +98,7 @@ static const struct nf_hook_ops ebt_ops_broute = {
.priority = NF_BR_PRI_FIRST,
};
static int __net_init broute_net_init(struct net *net)
static int broute_table_init(struct net *net)
{
return ebt_register_table(net, &broute_table, &ebt_ops_broute);
}
......@@ -114,19 +114,30 @@ static void __net_exit broute_net_exit(struct net *net)
}
static struct pernet_operations broute_net_ops = {
.init = broute_net_init,
.exit = broute_net_exit,
.pre_exit = broute_net_pre_exit,
};
static int __init ebtable_broute_init(void)
{
return register_pernet_subsys(&broute_net_ops);
int ret = ebt_register_template(&broute_table, broute_table_init);
if (ret)
return ret;
ret = register_pernet_subsys(&broute_net_ops);
if (ret) {
ebt_unregister_template(&broute_table);
return ret;
}
return 0;
}
static void __exit ebtable_broute_fini(void)
{
unregister_pernet_subsys(&broute_net_ops);
ebt_unregister_template(&broute_table);
}
module_init(ebtable_broute_init);
......
......@@ -86,7 +86,7 @@ static const struct nf_hook_ops ebt_ops_filter[] = {
},
};
static int __net_init frame_filter_net_init(struct net *net)
static int frame_filter_table_init(struct net *net)
{
return ebt_register_table(net, &frame_filter, ebt_ops_filter);
}
......@@ -102,19 +102,30 @@ static void __net_exit frame_filter_net_exit(struct net *net)
}
static struct pernet_operations frame_filter_net_ops = {
.init = frame_filter_net_init,
.exit = frame_filter_net_exit,
.pre_exit = frame_filter_net_pre_exit,
};
static int __init ebtable_filter_init(void)
{
return register_pernet_subsys(&frame_filter_net_ops);
int ret = ebt_register_template(&frame_filter, frame_filter_table_init);
if (ret)
return ret;
ret = register_pernet_subsys(&frame_filter_net_ops);
if (ret) {
ebt_unregister_template(&frame_filter);
return ret;
}
return 0;
}
static void __exit ebtable_filter_fini(void)
{
unregister_pernet_subsys(&frame_filter_net_ops);
ebt_unregister_template(&frame_filter);
}
module_init(ebtable_filter_init);
......
......@@ -85,7 +85,7 @@ static const struct nf_hook_ops ebt_ops_nat[] = {
},
};
static int __net_init frame_nat_net_init(struct net *net)
static int frame_nat_table_init(struct net *net)
{
return ebt_register_table(net, &frame_nat, ebt_ops_nat);
}
......@@ -101,19 +101,30 @@ static void __net_exit frame_nat_net_exit(struct net *net)
}
static struct pernet_operations frame_nat_net_ops = {
.init = frame_nat_net_init,
.exit = frame_nat_net_exit,
.pre_exit = frame_nat_net_pre_exit,
};
static int __init ebtable_nat_init(void)
{
return register_pernet_subsys(&frame_nat_net_ops);
int ret = ebt_register_template(&frame_nat, frame_nat_table_init);
if (ret)
return ret;
ret = register_pernet_subsys(&frame_nat_net_ops);
if (ret) {
ebt_unregister_template(&frame_nat);
return ret;
}
return ret;
}
static void __exit ebtable_nat_fini(void)
{
unregister_pernet_subsys(&frame_nat_net_ops);
ebt_unregister_template(&frame_nat);
}
module_init(ebtable_nat_init);
......
......@@ -44,7 +44,16 @@ struct ebt_pernet {
struct list_head tables;
};
struct ebt_template {
struct list_head list;
char name[EBT_TABLE_MAXNAMELEN];
struct module *owner;
/* called when table is needed in the given netns */
int (*table_init)(struct net *net);
};
static unsigned int ebt_pernet_id __read_mostly;
static LIST_HEAD(template_tables);
static DEFINE_MUTEX(ebt_mutex);
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
......@@ -309,30 +318,57 @@ unsigned int ebt_do_table(struct sk_buff *skb,
/* If it succeeds, returns element and locks mutex */
static inline void *
find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
find_inlist_lock_noload(struct net *net, const char *name, int *error,
struct mutex *mutex)
{
struct {
struct list_head list;
char name[EBT_FUNCTION_MAXNAMELEN];
} *e;
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
struct ebt_template *tmpl;
struct ebt_table *table;
mutex_lock(mutex);
list_for_each_entry(e, head, list) {
if (strcmp(e->name, name) == 0)
return e;
list_for_each_entry(table, &ebt_net->tables, list) {
if (strcmp(table->name, name) == 0)
return table;
}
list_for_each_entry(tmpl, &template_tables, list) {
if (strcmp(name, tmpl->name) == 0) {
struct module *owner = tmpl->owner;
if (!try_module_get(owner))
goto out;
mutex_unlock(mutex);
*error = tmpl->table_init(net);
if (*error) {
module_put(owner);
return NULL;
}
mutex_lock(mutex);
module_put(owner);
break;
}
}
list_for_each_entry(table, &ebt_net->tables, list) {
if (strcmp(table->name, name) == 0)
return table;
}
out:
*error = -ENOENT;
mutex_unlock(mutex);
return NULL;
}
static void *
find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
find_inlist_lock(struct net *net, const char *name, const char *prefix,
int *error, struct mutex *mutex)
{
return try_then_request_module(
find_inlist_lock_noload(head, name, error, mutex),
find_inlist_lock_noload(net, name, error, mutex),
"%s%s", prefix, name);
}
......@@ -340,10 +376,7 @@ static inline struct ebt_table *
find_table_lock(struct net *net, const char *name, int *error,
struct mutex *mutex)
{
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
return find_inlist_lock(&ebt_net->tables, name,
"ebtable_", error, mutex);
return find_inlist_lock(net, name, "ebtable_", error, mutex);
}
static inline void ebt_free_table_info(struct ebt_table_info *info)
......@@ -1258,6 +1291,54 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
return ret;
}
int ebt_register_template(const struct ebt_table *t, int (*table_init)(struct net *net))
{
struct ebt_template *tmpl;
mutex_lock(&ebt_mutex);
list_for_each_entry(tmpl, &template_tables, list) {
if (WARN_ON_ONCE(strcmp(t->name, tmpl->name) == 0)) {
mutex_unlock(&ebt_mutex);
return -EEXIST;
}
}
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
if (!tmpl) {
mutex_unlock(&ebt_mutex);
return -ENOMEM;
}
tmpl->table_init = table_init;
strscpy(tmpl->name, t->name, sizeof(tmpl->name));
tmpl->owner = t->me;
list_add(&tmpl->list, &template_tables);
mutex_unlock(&ebt_mutex);
return 0;
}
EXPORT_SYMBOL(ebt_register_template);
void ebt_unregister_template(const struct ebt_table *t)
{
struct ebt_template *tmpl;
mutex_lock(&ebt_mutex);
list_for_each_entry(tmpl, &template_tables, list) {
if (strcmp(t->name, tmpl->name))
continue;
list_del(&tmpl->list);
mutex_unlock(&ebt_mutex);
kfree(tmpl);
return;
}
mutex_unlock(&ebt_mutex);
WARN_ON_ONCE(1);
}
EXPORT_SYMBOL(ebt_unregister_template);
static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
{
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
......
......@@ -18,15 +18,12 @@ MODULE_DESCRIPTION("arptables filter table");
#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
(1 << NF_ARP_FORWARD))
static int __net_init arptable_filter_table_init(struct net *net);
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_ARP,
.priority = NF_IP_PRI_FILTER,
.table_init = arptable_filter_table_init,
};
/* The work comes in here from netfilter.c */
......@@ -39,7 +36,7 @@ arptable_filter_hook(void *priv, struct sk_buff *skb,
static struct nf_hook_ops *arpfilter_ops __read_mostly;
static int __net_init arptable_filter_table_init(struct net *net)
static int arptable_filter_table_init(struct net *net)
{
struct arpt_replace *repl;
int err;
......@@ -69,30 +66,32 @@ static struct pernet_operations arptable_filter_net_ops = {
static int __init arptable_filter_init(void)
{
int ret;
int ret = xt_register_template(&packet_filter,
arptable_filter_table_init);
if (ret < 0)
return ret;
arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arptable_filter_hook);
if (IS_ERR(arpfilter_ops))
if (IS_ERR(arpfilter_ops)) {
xt_unregister_template(&packet_filter);
return PTR_ERR(arpfilter_ops);
}
ret = register_pernet_subsys(&arptable_filter_net_ops);
if (ret < 0) {
xt_unregister_template(&packet_filter);
kfree(arpfilter_ops);
return ret;
}
ret = arptable_filter_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&arptable_filter_net_ops);
kfree(arpfilter_ops);
}
return ret;
}
static void __exit arptable_filter_fini(void)
{
unregister_pernet_subsys(&arptable_filter_net_ops);
xt_unregister_template(&packet_filter);
kfree(arpfilter_ops);
}
......
......@@ -66,11 +66,22 @@ struct clusterip_net {
/* lock protects the configs list */
spinlock_t lock;
bool clusterip_deprecated_warning;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *procdir;
/* mutex protects the config->pde*/
struct mutex mutex;
#endif
unsigned int hook_users;
};
static unsigned int clusterip_arp_mangle(void *priv, struct sk_buff *skb, const struct nf_hook_state *state);
static const struct nf_hook_ops cip_arp_ops = {
.hook = clusterip_arp_mangle,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_OUT,
.priority = -1
};
static unsigned int clusterip_net_id __read_mostly;
......@@ -458,6 +469,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int clusterip_tg_check(const struct xt_tgchk_param *par)
{
struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
struct clusterip_net *cn = clusterip_pernet(par->net);
const struct ipt_entry *e = par->entryinfo;
struct clusterip_config *config;
int ret, i;
......@@ -467,6 +479,9 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
return -EOPNOTSUPP;
}
if (cn->hook_users == UINT_MAX)
return -EOVERFLOW;
if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
......@@ -517,10 +532,23 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
return ret;
}
if (!par->net->xt.clusterip_deprecated_warning) {
if (cn->hook_users == 0) {
ret = nf_register_net_hook(par->net, &cip_arp_ops);
if (ret < 0) {
clusterip_config_entry_put(config);
clusterip_config_put(config);
nf_ct_netns_put(par->net, par->family);
return ret;
}
}
cn->hook_users++;
if (!cn->clusterip_deprecated_warning) {
pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, "
"use xt_cluster instead\n");
par->net->xt.clusterip_deprecated_warning = true;
cn->clusterip_deprecated_warning = true;
}
cipinfo->config = config;
......@@ -531,6 +559,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
{
const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
struct clusterip_net *cn = clusterip_pernet(par->net);
/* if no more entries are referencing the config, remove it
* from the list and destroy the proc entry */
......@@ -539,6 +568,10 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
clusterip_config_put(cipinfo->config);
nf_ct_netns_put(par->net, par->family);
cn->hook_users--;
if (cn->hook_users == 0)
nf_unregister_net_hook(par->net, &cip_arp_ops);
}
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
......@@ -602,9 +635,8 @@ static void arp_print(struct arp_payload *payload)
#endif
static unsigned int
arp_mangle(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
clusterip_arp_mangle(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct arphdr *arp = arp_hdr(skb);
struct arp_payload *payload;
......@@ -654,13 +686,6 @@ arp_mangle(void *priv,
return NF_ACCEPT;
}
static const struct nf_hook_ops cip_arp_ops = {
.hook = arp_mangle,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_OUT,
.priority = -1
};
/***********************************************************************
* PROC DIR HANDLING
***********************************************************************/
......@@ -817,20 +842,14 @@ static const struct proc_ops clusterip_proc_ops = {
static int clusterip_net_init(struct net *net)
{
struct clusterip_net *cn = clusterip_pernet(net);
int ret;
INIT_LIST_HEAD(&cn->configs);
spin_lock_init(&cn->lock);
ret = nf_register_net_hook(net, &cip_arp_ops);
if (ret < 0)
return ret;
#ifdef CONFIG_PROC_FS
cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net);
if (!cn->procdir) {
nf_unregister_net_hook(net, &cip_arp_ops);
pr_err("Unable to proc dir entry\n");
return -ENOMEM;
}
......@@ -850,7 +869,6 @@ static void clusterip_net_exit(struct net *net)
cn->procdir = NULL;
mutex_unlock(&cn->mutex);
#endif
nf_unregister_net_hook(net, &cip_arp_ops);
}
static struct pernet_operations clusterip_net_ops = {
......
......@@ -19,7 +19,6 @@ MODULE_DESCRIPTION("iptables filter table");
#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT))
static int __net_init iptable_filter_table_init(struct net *net);
static const struct xt_table packet_filter = {
.name = "filter",
......@@ -27,7 +26,6 @@ static const struct xt_table packet_filter = {
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_FILTER,
.table_init = iptable_filter_table_init,
};
static unsigned int
......@@ -43,7 +41,7 @@ static struct nf_hook_ops *filter_ops __read_mostly;
static bool forward __read_mostly = true;
module_param(forward, bool, 0000);
static int __net_init iptable_filter_table_init(struct net *net)
static int iptable_filter_table_init(struct net *net)
{
struct ipt_replace *repl;
int err;
......@@ -62,7 +60,7 @@ static int __net_init iptable_filter_table_init(struct net *net)
static int __net_init iptable_filter_net_init(struct net *net)
{
if (net == &init_net || !forward)
if (!forward)
return iptable_filter_table_init(net);
return 0;
......@@ -86,22 +84,32 @@ static struct pernet_operations iptable_filter_net_ops = {
static int __init iptable_filter_init(void)
{
int ret;
int ret = xt_register_template(&packet_filter,
iptable_filter_table_init);
if (ret < 0)
return ret;
filter_ops = xt_hook_ops_alloc(&packet_filter, iptable_filter_hook);
if (IS_ERR(filter_ops))
if (IS_ERR(filter_ops)) {
xt_unregister_template(&packet_filter);
return PTR_ERR(filter_ops);
}
ret = register_pernet_subsys(&iptable_filter_net_ops);
if (ret < 0)
if (ret < 0) {
xt_unregister_template(&packet_filter);
kfree(filter_ops);
return ret;
}
return ret;
return 0;
}
static void __exit iptable_filter_fini(void)
{
unregister_pernet_subsys(&iptable_filter_net_ops);
xt_unregister_template(&packet_filter);
kfree(filter_ops);
}
......
......@@ -25,15 +25,12 @@ MODULE_DESCRIPTION("iptables mangle table");
(1 << NF_INET_LOCAL_OUT) | \
(1 << NF_INET_POST_ROUTING))
static int __net_init iptable_mangle_table_init(struct net *net);
static const struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_MANGLE,
.table_init = iptable_mangle_table_init,
};
static unsigned int
......@@ -83,7 +80,7 @@ iptable_mangle_hook(void *priv,
}
static struct nf_hook_ops *mangle_ops __read_mostly;
static int __net_init iptable_mangle_table_init(struct net *net)
static int iptable_mangle_table_init(struct net *net)
{
struct ipt_replace *repl;
int ret;
......@@ -113,32 +110,30 @@ static struct pernet_operations iptable_mangle_net_ops = {
static int __init iptable_mangle_init(void)
{
int ret;
int ret = xt_register_template(&packet_mangler,
iptable_mangle_table_init);
mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook);
if (IS_ERR(mangle_ops)) {
xt_unregister_template(&packet_mangler);
ret = PTR_ERR(mangle_ops);
return ret;
}
ret = register_pernet_subsys(&iptable_mangle_net_ops);
if (ret < 0) {
xt_unregister_template(&packet_mangler);
kfree(mangle_ops);
return ret;
}
ret = iptable_mangle_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&iptable_mangle_net_ops);
kfree(mangle_ops);
}
return ret;
}
static void __exit iptable_mangle_fini(void)
{
unregister_pernet_subsys(&iptable_mangle_net_ops);
xt_unregister_template(&packet_mangler);
kfree(mangle_ops);
}
......
......@@ -17,8 +17,6 @@ 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 = {
......@@ -29,7 +27,6 @@ static const struct xt_table nf_nat_ipv4_table = {
(1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.table_init = iptable_nat_table_init,
};
static unsigned int iptable_nat_do_chain(void *priv,
......@@ -113,7 +110,7 @@ static void ipt_nat_unregister_lookups(struct net *net)
kfree(ops);
}
static int __net_init iptable_nat_table_init(struct net *net)
static int iptable_nat_table_init(struct net *net)
{
struct ipt_replace *repl;
int ret;
......@@ -155,20 +152,25 @@ static struct pernet_operations iptable_nat_net_ops = {
static int __init iptable_nat_init(void)
{
int ret = register_pernet_subsys(&iptable_nat_net_ops);
int ret = xt_register_template(&nf_nat_ipv4_table,
iptable_nat_table_init);
if (ret < 0)
return ret;
if (ret)
ret = register_pernet_subsys(&iptable_nat_net_ops);
if (ret < 0) {
xt_unregister_template(&nf_nat_ipv4_table);
return ret;
}
ret = iptable_nat_table_init(&init_net);
if (ret)
unregister_pernet_subsys(&iptable_nat_net_ops);
return ret;
}
static void __exit iptable_nat_exit(void)
{
unregister_pernet_subsys(&iptable_nat_net_ops);
xt_unregister_template(&nf_nat_ipv4_table);
}
module_init(iptable_nat_init);
......
......@@ -12,8 +12,6 @@
#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
static int __net_init iptable_raw_table_init(struct net *net);
static bool raw_before_defrag __read_mostly;
MODULE_PARM_DESC(raw_before_defrag, "Enable raw table before defrag");
module_param(raw_before_defrag, bool, 0000);
......@@ -24,7 +22,6 @@ static const struct xt_table packet_raw = {
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_RAW,
.table_init = iptable_raw_table_init,
};
static const struct xt_table packet_raw_before_defrag = {
......@@ -33,7 +30,6 @@ static const struct xt_table packet_raw_before_defrag = {
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_RAW_BEFORE_DEFRAG,
.table_init = iptable_raw_table_init,
};
/* The work comes in here from netfilter.c. */
......@@ -89,22 +85,24 @@ static int __init iptable_raw_init(void)
pr_info("Enabling raw table before defrag\n");
}
ret = xt_register_template(table,
iptable_raw_table_init);
if (ret < 0)
return ret;
rawtable_ops = xt_hook_ops_alloc(table, iptable_raw_hook);
if (IS_ERR(rawtable_ops))
if (IS_ERR(rawtable_ops)) {
xt_unregister_template(table);
return PTR_ERR(rawtable_ops);
}
ret = register_pernet_subsys(&iptable_raw_net_ops);
if (ret < 0) {
xt_unregister_template(table);
kfree(rawtable_ops);
return ret;
}
ret = iptable_raw_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&iptable_raw_net_ops);
kfree(rawtable_ops);
}
return ret;
}
......@@ -112,6 +110,7 @@ static void __exit iptable_raw_fini(void)
{
unregister_pernet_subsys(&iptable_raw_net_ops);
kfree(rawtable_ops);
xt_unregister_template(&packet_raw);
}
module_init(iptable_raw_init);
......
......@@ -25,15 +25,12 @@ MODULE_DESCRIPTION("iptables security table, for MAC rules");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT)
static int __net_init iptable_security_table_init(struct net *net);
static const struct xt_table security_table = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_SECURITY,
.table_init = iptable_security_table_init,
};
static unsigned int
......@@ -45,7 +42,7 @@ iptable_security_hook(void *priv, struct sk_buff *skb,
static struct nf_hook_ops *sectbl_ops __read_mostly;
static int __net_init iptable_security_table_init(struct net *net)
static int iptable_security_table_init(struct net *net)
{
struct ipt_replace *repl;
int ret;
......@@ -75,24 +72,25 @@ static struct pernet_operations iptable_security_net_ops = {
static int __init iptable_security_init(void)
{
int ret;
int ret = xt_register_template(&security_table,
iptable_security_table_init);
if (ret < 0)
return ret;
sectbl_ops = xt_hook_ops_alloc(&security_table, iptable_security_hook);
if (IS_ERR(sectbl_ops))
if (IS_ERR(sectbl_ops)) {
xt_unregister_template(&security_table);
return PTR_ERR(sectbl_ops);
}
ret = register_pernet_subsys(&iptable_security_net_ops);
if (ret < 0) {
xt_unregister_template(&security_table);
kfree(sectbl_ops);
return ret;
}
ret = iptable_security_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&iptable_security_net_ops);
kfree(sectbl_ops);
}
return ret;
}
......@@ -100,6 +98,7 @@ static void __exit iptable_security_fini(void)
{
unregister_pernet_subsys(&iptable_security_net_ops);
kfree(sectbl_ops);
xt_unregister_template(&security_table);
}
module_init(iptable_security_init);
......
......@@ -19,15 +19,12 @@ MODULE_DESCRIPTION("ip6tables filter table");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT))
static int __net_init ip6table_filter_table_init(struct net *net);
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_FILTER,
.table_init = ip6table_filter_table_init,
};
/* The work comes in here from netfilter.c. */
......@@ -44,7 +41,7 @@ static struct nf_hook_ops *filter_ops __read_mostly;
static bool forward = true;
module_param(forward, bool, 0000);
static int __net_init ip6table_filter_table_init(struct net *net)
static int ip6table_filter_table_init(struct net *net)
{
struct ip6t_replace *repl;
int err;
......@@ -63,7 +60,7 @@ static int __net_init ip6table_filter_table_init(struct net *net)
static int __net_init ip6table_filter_net_init(struct net *net)
{
if (net == &init_net || !forward)
if (!forward)
return ip6table_filter_table_init(net);
return 0;
......@@ -87,15 +84,24 @@ static struct pernet_operations ip6table_filter_net_ops = {
static int __init ip6table_filter_init(void)
{
int ret;
int ret = xt_register_template(&packet_filter,
ip6table_filter_table_init);
if (ret < 0)
return ret;
filter_ops = xt_hook_ops_alloc(&packet_filter, ip6table_filter_hook);
if (IS_ERR(filter_ops))
if (IS_ERR(filter_ops)) {
xt_unregister_template(&packet_filter);
return PTR_ERR(filter_ops);
}
ret = register_pernet_subsys(&ip6table_filter_net_ops);
if (ret < 0)
if (ret < 0) {
xt_unregister_template(&packet_filter);
kfree(filter_ops);
return ret;
}
return ret;
}
......@@ -103,6 +109,7 @@ static int __init ip6table_filter_init(void)
static void __exit ip6table_filter_fini(void)
{
unregister_pernet_subsys(&ip6table_filter_net_ops);
xt_unregister_template(&packet_filter);
kfree(filter_ops);
}
......
......@@ -20,15 +20,12 @@ MODULE_DESCRIPTION("ip6tables mangle table");
(1 << NF_INET_LOCAL_OUT) | \
(1 << NF_INET_POST_ROUTING))
static int __net_init ip6table_mangle_table_init(struct net *net);
static const struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_MANGLE,
.table_init = ip6table_mangle_table_init,
};
static unsigned int
......@@ -76,7 +73,7 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
}
static struct nf_hook_ops *mangle_ops __read_mostly;
static int __net_init ip6table_mangle_table_init(struct net *net)
static int ip6table_mangle_table_init(struct net *net)
{
struct ip6t_replace *repl;
int ret;
......@@ -106,29 +103,32 @@ static struct pernet_operations ip6table_mangle_net_ops = {
static int __init ip6table_mangle_init(void)
{
int ret;
int ret = xt_register_template(&packet_mangler,
ip6table_mangle_table_init);
if (ret < 0)
return ret;
mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook);
if (IS_ERR(mangle_ops))
if (IS_ERR(mangle_ops)) {
xt_unregister_template(&packet_mangler);
return PTR_ERR(mangle_ops);
}
ret = register_pernet_subsys(&ip6table_mangle_net_ops);
if (ret < 0) {
xt_unregister_template(&packet_mangler);
kfree(mangle_ops);
return ret;
}
ret = ip6table_mangle_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&ip6table_mangle_net_ops);
kfree(mangle_ops);
}
return ret;
}
static void __exit ip6table_mangle_fini(void)
{
unregister_pernet_subsys(&ip6table_mangle_net_ops);
xt_unregister_template(&packet_mangler);
kfree(mangle_ops);
}
......
......@@ -19,8 +19,6 @@ 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 = {
......@@ -31,7 +29,6 @@ static const struct xt_table nf_nat_ipv6_table = {
(1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.table_init = ip6table_nat_table_init,
};
static unsigned int ip6table_nat_do_chain(void *priv,
......@@ -115,7 +112,7 @@ static void ip6t_nat_unregister_lookups(struct net *net)
kfree(ops);
}
static int __net_init ip6table_nat_table_init(struct net *net)
static int ip6table_nat_table_init(struct net *net)
{
struct ip6t_replace *repl;
int ret;
......@@ -157,20 +154,23 @@ static struct pernet_operations ip6table_nat_net_ops = {
static int __init ip6table_nat_init(void)
{
int ret = register_pernet_subsys(&ip6table_nat_net_ops);
int ret = xt_register_template(&nf_nat_ipv6_table,
ip6table_nat_table_init);
if (ret)
if (ret < 0)
return ret;
ret = ip6table_nat_table_init(&init_net);
ret = register_pernet_subsys(&ip6table_nat_net_ops);
if (ret)
unregister_pernet_subsys(&ip6table_nat_net_ops);
xt_unregister_template(&nf_nat_ipv6_table);
return ret;
}
static void __exit ip6table_nat_exit(void)
{
unregister_pernet_subsys(&ip6table_nat_net_ops);
xt_unregister_template(&nf_nat_ipv6_table);
}
module_init(ip6table_nat_init);
......
......@@ -11,8 +11,6 @@
#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
static int __net_init ip6table_raw_table_init(struct net *net);
static bool raw_before_defrag __read_mostly;
MODULE_PARM_DESC(raw_before_defrag, "Enable raw table before defrag");
module_param(raw_before_defrag, bool, 0000);
......@@ -23,7 +21,6 @@ static const struct xt_table packet_raw = {
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_RAW,
.table_init = ip6table_raw_table_init,
};
static const struct xt_table packet_raw_before_defrag = {
......@@ -32,7 +29,6 @@ static const struct xt_table packet_raw_before_defrag = {
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_RAW_BEFORE_DEFRAG,
.table_init = ip6table_raw_table_init,
};
/* The work comes in here from netfilter.c. */
......@@ -45,7 +41,7 @@ ip6table_raw_hook(void *priv, struct sk_buff *skb,
static struct nf_hook_ops *rawtable_ops __read_mostly;
static int __net_init ip6table_raw_table_init(struct net *net)
static int ip6table_raw_table_init(struct net *net)
{
struct ip6t_replace *repl;
const struct xt_table *table = &packet_raw;
......@@ -79,37 +75,39 @@ static struct pernet_operations ip6table_raw_net_ops = {
static int __init ip6table_raw_init(void)
{
int ret;
const struct xt_table *table = &packet_raw;
int ret;
if (raw_before_defrag) {
table = &packet_raw_before_defrag;
pr_info("Enabling raw table before defrag\n");
}
ret = xt_register_template(table, ip6table_raw_table_init);
if (ret < 0)
return ret;
/* Register hooks */
rawtable_ops = xt_hook_ops_alloc(table, ip6table_raw_hook);
if (IS_ERR(rawtable_ops))
if (IS_ERR(rawtable_ops)) {
xt_unregister_template(table);
return PTR_ERR(rawtable_ops);
}
ret = register_pernet_subsys(&ip6table_raw_net_ops);
if (ret < 0) {
kfree(rawtable_ops);
xt_unregister_template(table);
return ret;
}
ret = ip6table_raw_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&ip6table_raw_net_ops);
kfree(rawtable_ops);
}
return ret;
}
static void __exit ip6table_raw_fini(void)
{
unregister_pernet_subsys(&ip6table_raw_net_ops);
xt_unregister_template(&packet_raw);
kfree(rawtable_ops);
}
......
......@@ -24,15 +24,12 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT)
static int __net_init ip6table_security_table_init(struct net *net);
static const struct xt_table security_table = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_SECURITY,
.table_init = ip6table_security_table_init,
};
static unsigned int
......@@ -44,7 +41,7 @@ ip6table_security_hook(void *priv, struct sk_buff *skb,
static struct nf_hook_ops *sectbl_ops __read_mostly;
static int __net_init ip6table_security_table_init(struct net *net)
static int ip6table_security_table_init(struct net *net)
{
struct ip6t_replace *repl;
int ret;
......@@ -74,29 +71,32 @@ static struct pernet_operations ip6table_security_net_ops = {
static int __init ip6table_security_init(void)
{
int ret;
int ret = xt_register_template(&security_table,
ip6table_security_table_init);
if (ret < 0)
return ret;
sectbl_ops = xt_hook_ops_alloc(&security_table, ip6table_security_hook);
if (IS_ERR(sectbl_ops))
if (IS_ERR(sectbl_ops)) {
xt_unregister_template(&security_table);
return PTR_ERR(sectbl_ops);
}
ret = register_pernet_subsys(&ip6table_security_net_ops);
if (ret < 0) {
kfree(sectbl_ops);
xt_unregister_template(&security_table);
return ret;
}
ret = ip6table_security_table_init(&init_net);
if (ret) {
unregister_pernet_subsys(&ip6table_security_net_ops);
kfree(sectbl_ops);
}
return ret;
}
static void __exit ip6table_security_fini(void)
{
unregister_pernet_subsys(&ip6table_security_net_ops);
xt_unregister_template(&security_table);
kfree(sectbl_ops);
}
......
......@@ -852,6 +852,11 @@ static int ctnetlink_done(struct netlink_callback *cb)
return 0;
}
struct ctnetlink_filter_u32 {
u32 val;
u32 mask;
};
struct ctnetlink_filter {
u8 family;
......@@ -862,10 +867,8 @@ struct ctnetlink_filter {
struct nf_conntrack_tuple reply;
struct nf_conntrack_zone zone;
struct {
u_int32_t val;
u_int32_t mask;
} mark;
struct ctnetlink_filter_u32 mark;
struct ctnetlink_filter_u32 status;
};
static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {
......@@ -907,6 +910,46 @@ static int ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
struct nf_conntrack_zone *zone,
u_int32_t flags);
static int ctnetlink_filter_parse_mark(struct ctnetlink_filter_u32 *mark,
const struct nlattr * const cda[])
{
#ifdef CONFIG_NF_CONNTRACK_MARK
if (cda[CTA_MARK]) {
mark->val = ntohl(nla_get_be32(cda[CTA_MARK]));
if (cda[CTA_MARK_MASK])
mark->mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
else
mark->mask = 0xffffffff;
} else if (cda[CTA_MARK_MASK]) {
return -EINVAL;
}
#endif
return 0;
}
static int ctnetlink_filter_parse_status(struct ctnetlink_filter_u32 *status,
const struct nlattr * const cda[])
{
if (cda[CTA_STATUS]) {
status->val = ntohl(nla_get_be32(cda[CTA_STATUS]));
if (cda[CTA_STATUS_MASK])
status->mask = ntohl(nla_get_be32(cda[CTA_STATUS_MASK]));
else
status->mask = status->val;
/* status->val == 0? always true, else always false. */
if (status->mask == 0)
return -EINVAL;
} else if (cda[CTA_STATUS_MASK]) {
return -EINVAL;
}
/* CTA_STATUS is NLA_U32, if this fires UAPI needs to be extended */
BUILD_BUG_ON(__IPS_MAX_BIT >= 32);
return 0;
}
static struct ctnetlink_filter *
ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
{
......@@ -924,18 +967,14 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
filter->family = family;
#ifdef CONFIG_NF_CONNTRACK_MARK
if (cda[CTA_MARK]) {
filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
if (cda[CTA_MARK_MASK])
filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
else
filter->mark.mask = 0xffffffff;
} else if (cda[CTA_MARK_MASK]) {
err = -EINVAL;
err = ctnetlink_filter_parse_mark(&filter->mark, cda);
if (err)
goto err_filter;
}
#endif
err = ctnetlink_filter_parse_status(&filter->status, cda);
if (err)
goto err_filter;
if (!cda[CTA_FILTER])
return filter;
......@@ -989,7 +1028,7 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
static bool ctnetlink_needs_filter(u8 family, const struct nlattr * const *cda)
{
return family || cda[CTA_MARK] || cda[CTA_FILTER];
return family || cda[CTA_MARK] || cda[CTA_FILTER] || cda[CTA_STATUS];
}
static int ctnetlink_start(struct netlink_callback *cb)
......@@ -1082,6 +1121,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
{
struct ctnetlink_filter *filter = data;
struct nf_conntrack_tuple *tuple;
u32 status;
if (filter == NULL)
goto out;
......@@ -1113,6 +1153,9 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
if ((ct->mark & filter->mark.mask) != filter->mark.val)
goto ignore_entry;
#endif
status = (u32)READ_ONCE(ct->status);
if ((status & filter->status.mask) != filter->status.val)
goto ignore_entry;
out:
return 1;
......@@ -1495,6 +1538,7 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
[CTA_LABELS_MASK] = { .type = NLA_BINARY,
.len = NF_CT_LABELS_MAX_SIZE },
[CTA_FILTER] = { .type = NLA_NESTED },
[CTA_STATUS_MASK] = { .type = NLA_U32 },
};
static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)
......
......@@ -180,15 +180,10 @@ static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
{
const struct nf_conntrack_l4proto *l4proto;
struct net *net = nf_ct_net(ct);
int l4num = nf_ct_protonum(ct);
unsigned int timeout;
l4proto = nf_ct_l4proto_find(l4num);
if (!l4proto)
return;
if (l4num == IPPROTO_TCP) {
struct nf_tcp_net *tn = nf_tcp_pernet(net);
......@@ -273,15 +268,10 @@ static const struct rhashtable_params nf_flow_offload_rhash_params = {
unsigned long flow_offload_get_timeout(struct flow_offload *flow)
{
const struct nf_conntrack_l4proto *l4proto;
unsigned long timeout = NF_FLOW_TIMEOUT;
struct net *net = nf_ct_net(flow->ct);
int l4num = nf_ct_protonum(flow->ct);
l4proto = nf_ct_l4proto_find(l4num);
if (!l4proto)
return timeout;
if (l4num == IPPROTO_TCP) {
struct nf_tcp_net *tn = nf_tcp_pernet(net);
......
......@@ -21,6 +21,8 @@
#include "nf_internals.h"
static const struct nf_queue_handler __rcu *nf_queue_handler;
/*
* Hook for nfnetlink_queue to register its queue handler.
* We do this so that most of the NFQUEUE code can be modular.
......@@ -29,20 +31,18 @@
* receives, no matter what.
*/
/* return EBUSY when somebody else is registered, return EEXIST if the
* same handler is registered, return 0 in case of success. */
void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh)
void nf_register_queue_handler(const struct nf_queue_handler *qh)
{
/* should never happen, we only have one queueing backend in kernel */
WARN_ON(rcu_access_pointer(net->nf.queue_handler));
rcu_assign_pointer(net->nf.queue_handler, qh);
WARN_ON(rcu_access_pointer(nf_queue_handler));
rcu_assign_pointer(nf_queue_handler, qh);
}
EXPORT_SYMBOL(nf_register_queue_handler);
/* The caller must flush their queue before this */
void nf_unregister_queue_handler(struct net *net)
void nf_unregister_queue_handler(void)
{
RCU_INIT_POINTER(net->nf.queue_handler, NULL);
RCU_INIT_POINTER(nf_queue_handler, NULL);
}
EXPORT_SYMBOL(nf_unregister_queue_handler);
......@@ -108,7 +108,7 @@ void nf_queue_nf_hook_drop(struct net *net)
const struct nf_queue_handler *qh;
rcu_read_lock();
qh = rcu_dereference(net->nf.queue_handler);
qh = rcu_dereference(nf_queue_handler);
if (qh)
qh->nf_hook_drop(net);
rcu_read_unlock();
......@@ -149,12 +149,11 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
{
struct nf_queue_entry *entry = NULL;
const struct nf_queue_handler *qh;
struct net *net = state->net;
unsigned int route_key_size;
int status;
/* QUEUE == DROP if no one is waiting, to be safe. */
qh = rcu_dereference(net->nf.queue_handler);
qh = rcu_dereference(nf_queue_handler);
if (!qh)
return -ESRCH;
......
......@@ -951,6 +951,16 @@ static void nfqnl_nf_hook_drop(struct net *net)
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
int i;
/* This function is also called on net namespace error unwind,
* when pernet_ops->init() failed and ->exit() functions of the
* previous pernet_ops gets called.
*
* This may result in a call to nfqnl_nf_hook_drop() before
* struct nfnl_queue_net was allocated.
*/
if (!q)
return;
for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct nfqnl_instance *inst;
struct hlist_head *head = &q->instance_table[i];
......@@ -1502,7 +1512,6 @@ static int __net_init nfnl_queue_net_init(struct net *net)
&nfqnl_seq_ops, sizeof(struct iter_state)))
return -ENOMEM;
#endif
nf_register_queue_handler(net, &nfqh);
return 0;
}
......@@ -1511,7 +1520,6 @@ static void __net_exit nfnl_queue_net_exit(struct net *net)
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
unsigned int i;
nf_unregister_queue_handler(net);
#ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
#endif
......@@ -1555,6 +1563,8 @@ static int __init nfnetlink_queue_init(void)
goto cleanup_netlink_subsys;
}
nf_register_queue_handler(&nfqh);
return status;
cleanup_netlink_subsys:
......@@ -1568,6 +1578,7 @@ static int __init nfnetlink_queue_init(void)
static void __exit nfnetlink_queue_fini(void)
{
nf_unregister_queue_handler();
unregister_netdevice_notifier(&nfqnl_dev_notifier);
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
......
......@@ -683,14 +683,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
goto out_put;
}
ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret > 0)
ret = 0;
ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
out_put:
rcu_read_lock();
module_put(THIS_MODULE);
return ret == -EAGAIN ? -ENOBUFS : ret;
return ret;
}
static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
......
......@@ -39,6 +39,20 @@ MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
#define XT_PCPU_BLOCK_SIZE 4096
#define XT_MAX_TABLE_SIZE (512 * 1024 * 1024)
struct xt_template {
struct list_head list;
/* called when table is needed in the given netns */
int (*table_init)(struct net *net);
struct module *me;
/* A unique name... */
char name[XT_TABLE_MAXNAMELEN];
};
static struct list_head xt_templates[NFPROTO_NUMPROTO];
struct xt_pernet {
struct list_head tables[NFPROTO_NUMPROTO];
};
......@@ -1221,48 +1235,43 @@ struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name)
{
struct xt_pernet *xt_net = net_generic(net, xt_pernet_id);
struct xt_table *t, *found = NULL;
struct module *owner = NULL;
struct xt_template *tmpl;
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 && try_module_get(t->me))
return t;
if (net == &init_net)
goto out;
/* Table doesn't exist in this netns, re-try init */
xt_net = net_generic(&init_net, xt_pernet_id);
list_for_each_entry(t, &xt_net->tables[af], list) {
/* Table doesn't exist in this netns, check larval list */
list_for_each_entry(tmpl, &xt_templates[af], list) {
int err;
if (strcmp(t->name, name))
if (strcmp(tmpl->name, name))
continue;
if (!try_module_get(t->me))
if (!try_module_get(tmpl->me))
goto out;
owner = tmpl->me;
mutex_unlock(&xt[af].mutex);
err = t->table_init(net);
err = tmpl->table_init(net);
if (err < 0) {
module_put(t->me);
module_put(owner);
return ERR_PTR(err);
}
found = t;
mutex_lock(&xt[af].mutex);
break;
}
if (!found)
goto out;
xt_net = net_generic(net, xt_pernet_id);
/* and once again: */
list_for_each_entry(t, &xt_net->tables[af], list)
if (strcmp(t->name, name) == 0)
return t;
module_put(found->me);
module_put(owner);
out:
mutex_unlock(&xt[af].mutex);
return ERR_PTR(-ENOENT);
......@@ -1749,6 +1758,58 @@ xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn)
}
EXPORT_SYMBOL_GPL(xt_hook_ops_alloc);
int xt_register_template(const struct xt_table *table,
int (*table_init)(struct net *net))
{
int ret = -EEXIST, af = table->af;
struct xt_template *t;
mutex_lock(&xt[af].mutex);
list_for_each_entry(t, &xt_templates[af], list) {
if (WARN_ON_ONCE(strcmp(table->name, t->name) == 0))
goto out_unlock;
}
ret = -ENOMEM;
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
goto out_unlock;
BUILD_BUG_ON(sizeof(t->name) != sizeof(table->name));
strscpy(t->name, table->name, sizeof(t->name));
t->table_init = table_init;
t->me = table->me;
list_add(&t->list, &xt_templates[af]);
ret = 0;
out_unlock:
mutex_unlock(&xt[af].mutex);
return ret;
}
EXPORT_SYMBOL_GPL(xt_register_template);
void xt_unregister_template(const struct xt_table *table)
{
struct xt_template *t;
int af = table->af;
mutex_lock(&xt[af].mutex);
list_for_each_entry(t, &xt_templates[af], list) {
if (strcmp(table->name, t->name))
continue;
list_del(&t->list);
mutex_unlock(&xt[af].mutex);
kfree(t);
return;
}
mutex_unlock(&xt[af].mutex);
WARN_ON_ONCE(1);
}
EXPORT_SYMBOL_GPL(xt_unregister_template);
int xt_proto_init(struct net *net, u_int8_t af)
{
#ifdef CONFIG_PROC_FS
......@@ -1937,6 +1998,7 @@ static int __init xt_init(void)
#endif
INIT_LIST_HEAD(&xt[i].target);
INIT_LIST_HEAD(&xt[i].match);
INIT_LIST_HEAD(&xt_templates[i]);
}
rv = register_pernet_subsys(&xt_net_ops);
if (rv < 0)
......
......@@ -351,21 +351,10 @@ notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
return XT_CONTINUE;
}
static int notrack_chk(const struct xt_tgchk_param *par)
{
if (!par->net->xt.notrack_deprecated_warning) {
pr_info("netfilter: NOTRACK target is deprecated, "
"use CT instead or upgrade iptables\n");
par->net->xt.notrack_deprecated_warning = true;
}
return 0;
}
static struct xt_target notrack_tg_reg __read_mostly = {
.name = "NOTRACK",
.revision = 0,
.family = NFPROTO_UNSPEC,
.checkentry = notrack_chk,
.target = notrack_tg,
.table = "raw",
.me = THIS_MODULE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment