|
@@ -23,6 +23,7 @@ MODULE_DESCRIPTION("iptables filter table");
|
|
#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
|
|
#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
|
|
(1 << NF_INET_FORWARD) | \
|
|
(1 << NF_INET_FORWARD) | \
|
|
(1 << NF_INET_LOCAL_OUT))
|
|
(1 << NF_INET_LOCAL_OUT))
|
|
|
|
+static int __net_init iptable_filter_table_init(struct net *net);
|
|
|
|
|
|
static const struct xt_table packet_filter = {
|
|
static const struct xt_table packet_filter = {
|
|
.name = "filter",
|
|
.name = "filter",
|
|
@@ -30,6 +31,7 @@ static const struct xt_table packet_filter = {
|
|
.me = THIS_MODULE,
|
|
.me = THIS_MODULE,
|
|
.af = NFPROTO_IPV4,
|
|
.af = NFPROTO_IPV4,
|
|
.priority = NF_IP_PRI_FILTER,
|
|
.priority = NF_IP_PRI_FILTER,
|
|
|
|
+ .table_init = iptable_filter_table_init,
|
|
};
|
|
};
|
|
|
|
|
|
static unsigned int
|
|
static unsigned int
|
|
@@ -48,14 +50,17 @@ iptable_filter_hook(void *priv, struct sk_buff *skb,
|
|
static struct nf_hook_ops *filter_ops __read_mostly;
|
|
static struct nf_hook_ops *filter_ops __read_mostly;
|
|
|
|
|
|
/* Default to forward because I got too much mail already. */
|
|
/* Default to forward because I got too much mail already. */
|
|
-static bool forward = true;
|
|
|
|
|
|
+static bool forward __read_mostly = true;
|
|
module_param(forward, bool, 0000);
|
|
module_param(forward, bool, 0000);
|
|
|
|
|
|
-static int __net_init iptable_filter_net_init(struct net *net)
|
|
|
|
|
|
+static int __net_init iptable_filter_table_init(struct net *net)
|
|
{
|
|
{
|
|
struct ipt_replace *repl;
|
|
struct ipt_replace *repl;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
|
|
+ if (net->ipv4.iptable_filter)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
repl = ipt_alloc_initial_table(&packet_filter);
|
|
repl = ipt_alloc_initial_table(&packet_filter);
|
|
if (repl == NULL)
|
|
if (repl == NULL)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
@@ -69,9 +74,20 @@ static int __net_init iptable_filter_net_init(struct net *net)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int __net_init iptable_filter_net_init(struct net *net)
|
|
|
|
+{
|
|
|
|
+ if (net == &init_net || !forward)
|
|
|
|
+ return iptable_filter_table_init(net);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static void __net_exit iptable_filter_net_exit(struct net *net)
|
|
static void __net_exit iptable_filter_net_exit(struct net *net)
|
|
{
|
|
{
|
|
|
|
+ if (!net->ipv4.iptable_filter)
|
|
|
|
+ return;
|
|
ipt_unregister_table(net, net->ipv4.iptable_filter, filter_ops);
|
|
ipt_unregister_table(net, net->ipv4.iptable_filter, filter_ops);
|
|
|
|
+ net->ipv4.iptable_filter = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static struct pernet_operations iptable_filter_net_ops = {
|
|
static struct pernet_operations iptable_filter_net_ops = {
|
|
@@ -83,24 +99,21 @@ static int __init iptable_filter_init(void)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
+ filter_ops = xt_hook_ops_alloc(&packet_filter, iptable_filter_hook);
|
|
|
|
+ if (IS_ERR(filter_ops))
|
|
|
|
+ return PTR_ERR(filter_ops);
|
|
|
|
+
|
|
ret = register_pernet_subsys(&iptable_filter_net_ops);
|
|
ret = register_pernet_subsys(&iptable_filter_net_ops);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
- return ret;
|
|
|
|
-
|
|
|
|
- /* Register hooks */
|
|
|
|
- filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook);
|
|
|
|
- if (IS_ERR(filter_ops)) {
|
|
|
|
- ret = PTR_ERR(filter_ops);
|
|
|
|
- unregister_pernet_subsys(&iptable_filter_net_ops);
|
|
|
|
- }
|
|
|
|
|
|
+ kfree(filter_ops);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static void __exit iptable_filter_fini(void)
|
|
static void __exit iptable_filter_fini(void)
|
|
{
|
|
{
|
|
- xt_hook_unlink(&packet_filter, filter_ops);
|
|
|
|
unregister_pernet_subsys(&iptable_filter_net_ops);
|
|
unregister_pernet_subsys(&iptable_filter_net_ops);
|
|
|
|
+ kfree(filter_ops);
|
|
}
|
|
}
|
|
|
|
|
|
module_init(iptable_filter_init);
|
|
module_init(iptable_filter_init);
|