aboutsummaryrefslogtreecommitdiff
path: root/net/ipv4/netfilter
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/netfilter')
-rw-r--r--net/ipv4/netfilter/Kconfig10
-rw-r--r--net/ipv4/netfilter/Makefile4
-rw-r--r--net/ipv4/netfilter/arp_tables.c73
-rw-r--r--net/ipv4/netfilter/arptable_filter.c17
-rw-r--r--net/ipv4/netfilter/ip_tables.c86
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c8
-rw-r--r--net/ipv4/netfilter/iptable_filter.c17
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c23
-rw-r--r--net/ipv4/netfilter/iptable_nat.c59
-rw-r--r--net/ipv4/netfilter/iptable_raw.c17
-rw-r--r--net/ipv4/netfilter/iptable_security.c17
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c46
-rw-r--r--net/ipv4/netfilter/nf_log_arp.c172
-rw-r--r--net/ipv4/netfilter/nf_log_ipv4.c395
14 files changed, 210 insertions, 734 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index a2f4f894be2b..63cb953bd019 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -76,12 +76,18 @@ config NF_DUP_IPV4
config NF_LOG_ARP
tristate "ARP packet logging"
default m if NETFILTER_ADVANCED=n
- select NF_LOG_COMMON
+ select NF_LOG_SYSLOG
+ help
+ This is a backwards-compat option for the user's convenience
+ (e.g. when running oldconfig). It selects CONFIG_NF_LOG_SYSLOG.
config NF_LOG_IPV4
tristate "IPv4 packet logging"
default m if NETFILTER_ADVANCED=n
- select NF_LOG_COMMON
+ select NF_LOG_SYSLOG
+ help
+ This is a backwards-compat option for the user's convenience
+ (e.g. when running oldconfig). It selects CONFIG_NF_LOG_SYSLOG.
config NF_REJECT_IPV4
tristate "IPv4 packet rejection"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 7c497c78105f..f38fb1368ddb 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -9,10 +9,6 @@ obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
obj-$(CONFIG_NF_SOCKET_IPV4) += nf_socket_ipv4.o
obj-$(CONFIG_NF_TPROXY_IPV4) += nf_tproxy_ipv4.o
-# logging
-obj-$(CONFIG_NF_LOG_ARP) += nf_log_arp.o
-obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o
-
# reject
obj-$(CONFIG_NF_REJECT_IPV4) += nf_reject_ipv4.o
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index d6d45d820d79..cf20316094d0 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -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);
- goto out_free;
+ xt_free_table_info(newinfo);
+ return PTR_ERR(new_table);
}
- /* set res now, will see skbs right after nf_register_net_hooks */
- WRITE_ONCE(*res, new_table);
+ num_ops = hweight32(table->valid_hooks);
+ if (num_ops == 0) {
+ ret = -EINVAL;
+ goto out_free;
+ }
- 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,
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 6c300ba5634e..b8f45e9bbec8 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -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 = {
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index f77ea0dbe656..13acb687c19a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -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);
- goto out_free;
+ xt_free_table_info(newinfo);
+ return PTR_ERR(new_table);
}
- /* set res now, will see skbs right after nf_register_net_hooks */
- WRITE_ONCE(*res, new_table);
- if (!ops)
+ /* 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;
- ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
- if (ret != 0) {
- __ipt_unregister_table(net, new_table);
- *res = NULL;
+ num_ops = hweight32(table->valid_hooks);
+ if (num_ops == 0) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
+ if (!ops) {
+ ret = -ENOMEM;
+ goto out_free;
}
+ for (i = 0; i < num_ops; i++)
+ ops[i].priv = new_table;
+
+ new_table->ops = ops;
+
+ ret = nf_register_net_hooks(net, ops, num_ops);
+ if (ret != 0)
+ goto out_free;
+
return ret;
out_free:
- 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);
-void ipt_unregister_table_exit(struct net *net, struct xt_table *table)
-{
- __ipt_unregister_table(net, table);
+ if (table)
+ nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
-void ipt_unregister_table(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops)
+void ipt_unregister_table_exit(struct net *net, const char *name)
{
- if (ops)
- ipt_unregister_table_pre_exit(net, table, ops);
- __ipt_unregister_table(net, table);
+ struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
+
+ 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);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index a8b980ad11d4..8f7ca67475b7 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -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
};
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 8f7bc1ee7453..8272df7c6ad5 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -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 = {
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 833079589273..2abc3836f391 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -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 = {
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index b0143b109f25..a9913842ef18 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -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)
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 9abfe6bf2cb9..ceef397c1f5f 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -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 = {
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index 415c1975d770..77973f5fd8f6 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -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 = {
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index 8115611aa47d..613432a36f0a 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -20,8 +20,13 @@
#endif
#include <net/netfilter/nf_conntrack_zones.h>
+static unsigned int defrag4_pernet_id __read_mostly;
static DEFINE_MUTEX(defrag4_mutex);
+struct defrag4_pernet {
+ unsigned int users;
+};
+
static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
u_int32_t user)
{
@@ -106,15 +111,19 @@ static const struct nf_hook_ops ipv4_defrag_ops[] = {
static void __net_exit defrag4_net_exit(struct net *net)
{
- if (net->nf.defrag_ipv4) {
+ struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
+
+ if (nf_defrag->users) {
nf_unregister_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops));
- net->nf.defrag_ipv4 = false;
+ nf_defrag->users = 0;
}
}
static struct pernet_operations defrag4_net_ops = {
.exit = defrag4_net_exit,
+ .id = &defrag4_pernet_id,
+ .size = sizeof(struct defrag4_pernet),
};
static int __init nf_defrag_init(void)
@@ -129,21 +138,24 @@ static void __exit nf_defrag_fini(void)
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 (net->nf.defrag_ipv4)
- return 0;
-
mutex_lock(&defrag4_mutex);
- if (net->nf.defrag_ipv4)
+ 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));
if (err == 0)
- net->nf.defrag_ipv4 = true;
+ nf_defrag->users = 1;
out_unlock:
mutex_unlock(&defrag4_mutex);
@@ -151,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);
diff --git a/net/ipv4/netfilter/nf_log_arp.c b/net/ipv4/netfilter/nf_log_arp.c
deleted file mode 100644
index 136030ad2e54..000000000000
--- a/net/ipv4/netfilter/nf_log_arp.c
+++ /dev/null
@@ -1,172 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>
- *
- * Based on code from ebt_log from:
- *
- * Bart De Schuymer <bdschuym@pandora.be>
- * Harald Welte <laforge@netfilter.org>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <net/route.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter/xt_LOG.h>
-#include <net/netfilter/nf_log.h>
-
-static const struct nf_loginfo default_loginfo = {
- .type = NF_LOG_TYPE_LOG,
- .u = {
- .log = {
- .level = LOGLEVEL_NOTICE,
- .logflags = NF_LOG_DEFAULT_MASK,
- },
- },
-};
-
-struct arppayload {
- unsigned char mac_src[ETH_ALEN];
- unsigned char ip_src[4];
- unsigned char mac_dst[ETH_ALEN];
- unsigned char ip_dst[4];
-};
-
-static void dump_arp_packet(struct nf_log_buf *m,
- const struct nf_loginfo *info,
- const struct sk_buff *skb, unsigned int nhoff)
-{
- const struct arppayload *ap;
- struct arppayload _arpp;
- const struct arphdr *ah;
- unsigned int logflags;
- struct arphdr _arph;
-
- ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
- if (ah == NULL) {
- nf_log_buf_add(m, "TRUNCATED");
- return;
- }
-
- if (info->type == NF_LOG_TYPE_LOG)
- logflags = info->u.log.logflags;
- else
- logflags = NF_LOG_DEFAULT_MASK;
-
- if (logflags & NF_LOG_MACDECODE) {
- nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ",
- eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest);
- nf_log_dump_vlan(m, skb);
- nf_log_buf_add(m, "MACPROTO=%04x ",
- ntohs(eth_hdr(skb)->h_proto));
- }
-
- nf_log_buf_add(m, "ARP HTYPE=%d PTYPE=0x%04x OPCODE=%d",
- ntohs(ah->ar_hrd), ntohs(ah->ar_pro), ntohs(ah->ar_op));
-
- /* If it's for Ethernet and the lengths are OK, then log the ARP
- * payload.
- */
- if (ah->ar_hrd != htons(ARPHRD_ETHER) ||
- ah->ar_hln != ETH_ALEN ||
- ah->ar_pln != sizeof(__be32))
- return;
-
- ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp);
- if (ap == NULL) {
- nf_log_buf_add(m, " INCOMPLETE [%zu bytes]",
- skb->len - sizeof(_arph));
- return;
- }
- nf_log_buf_add(m, " MACSRC=%pM IPSRC=%pI4 MACDST=%pM IPDST=%pI4",
- ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst);
-}
-
-static void nf_log_arp_packet(struct net *net, u_int8_t pf,
- unsigned int hooknum, const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct nf_loginfo *loginfo,
- const char *prefix)
-{
- struct nf_log_buf *m;
-
- /* FIXME: Disabled from containers until syslog ns is supported */
- if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns)
- return;
-
- m = nf_log_buf_open();
-
- if (!loginfo)
- loginfo = &default_loginfo;
-
- nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
- prefix);
- dump_arp_packet(m, loginfo, skb, 0);
-
- nf_log_buf_close(m);
-}
-
-static struct nf_logger nf_arp_logger __read_mostly = {
- .name = "nf_log_arp",
- .type = NF_LOG_TYPE_LOG,
- .logfn = nf_log_arp_packet,
- .me = THIS_MODULE,
-};
-
-static int __net_init nf_log_arp_net_init(struct net *net)
-{
- return nf_log_set(net, NFPROTO_ARP, &nf_arp_logger);
-}
-
-static void __net_exit nf_log_arp_net_exit(struct net *net)
-{
- nf_log_unset(net, &nf_arp_logger);
-}
-
-static struct pernet_operations nf_log_arp_net_ops = {
- .init = nf_log_arp_net_init,
- .exit = nf_log_arp_net_exit,
-};
-
-static int __init nf_log_arp_init(void)
-{
- int ret;
-
- ret = register_pernet_subsys(&nf_log_arp_net_ops);
- if (ret < 0)
- return ret;
-
- ret = nf_log_register(NFPROTO_ARP, &nf_arp_logger);
- if (ret < 0) {
- pr_err("failed to register logger\n");
- goto err1;
- }
-
- return 0;
-
-err1:
- unregister_pernet_subsys(&nf_log_arp_net_ops);
- return ret;
-}
-
-static void __exit nf_log_arp_exit(void)
-{
- unregister_pernet_subsys(&nf_log_arp_net_ops);
- nf_log_unregister(&nf_arp_logger);
-}
-
-module_init(nf_log_arp_init);
-module_exit(nf_log_arp_exit);
-
-MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
-MODULE_DESCRIPTION("Netfilter ARP packet logging");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NF_LOGGER(3, 0);
diff --git a/net/ipv4/netfilter/nf_log_ipv4.c b/net/ipv4/netfilter/nf_log_ipv4.c
deleted file mode 100644
index d07583fac8f8..000000000000
--- a/net/ipv4/netfilter/nf_log_ipv4.c
+++ /dev/null
@@ -1,395 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <net/ipv6.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/tcp.h>
-#include <net/route.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter/xt_LOG.h>
-#include <net/netfilter/nf_log.h>
-
-static const struct nf_loginfo default_loginfo = {
- .type = NF_LOG_TYPE_LOG,
- .u = {
- .log = {
- .level = LOGLEVEL_NOTICE,
- .logflags = NF_LOG_DEFAULT_MASK,
- },
- },
-};
-
-/* One level of recursion won't kill us */
-static void dump_ipv4_packet(struct net *net, struct nf_log_buf *m,
- const struct nf_loginfo *info,
- const struct sk_buff *skb, unsigned int iphoff)
-{
- struct iphdr _iph;
- const struct iphdr *ih;
- unsigned int logflags;
-
- if (info->type == NF_LOG_TYPE_LOG)
- logflags = info->u.log.logflags;
- else
- logflags = NF_LOG_DEFAULT_MASK;
-
- ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
- if (ih == NULL) {
- nf_log_buf_add(m, "TRUNCATED");
- return;
- }
-
- /* Important fields:
- * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
- /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
- nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr);
-
- /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
- nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
- ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
- ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
-
- /* Max length: 6 "CE DF MF " */
- if (ntohs(ih->frag_off) & IP_CE)
- nf_log_buf_add(m, "CE ");
- if (ntohs(ih->frag_off) & IP_DF)
- nf_log_buf_add(m, "DF ");
- if (ntohs(ih->frag_off) & IP_MF)
- nf_log_buf_add(m, "MF ");
-
- /* Max length: 11 "FRAG:65535 " */
- if (ntohs(ih->frag_off) & IP_OFFSET)
- nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
-
- if ((logflags & NF_LOG_IPOPT) &&
- ih->ihl * 4 > sizeof(struct iphdr)) {
- const unsigned char *op;
- unsigned char _opt[4 * 15 - sizeof(struct iphdr)];
- unsigned int i, optsize;
-
- optsize = ih->ihl * 4 - sizeof(struct iphdr);
- op = skb_header_pointer(skb, iphoff+sizeof(_iph),
- optsize, _opt);
- if (op == NULL) {
- nf_log_buf_add(m, "TRUNCATED");
- return;
- }
-
- /* Max length: 127 "OPT (" 15*4*2chars ") " */
- nf_log_buf_add(m, "OPT (");
- for (i = 0; i < optsize; i++)
- nf_log_buf_add(m, "%02X", op[i]);
- nf_log_buf_add(m, ") ");
- }
-
- switch (ih->protocol) {
- case IPPROTO_TCP:
- if (nf_log_dump_tcp_header(m, skb, ih->protocol,
- ntohs(ih->frag_off) & IP_OFFSET,
- iphoff+ih->ihl*4, logflags))
- return;
- break;
- case IPPROTO_UDP:
- case IPPROTO_UDPLITE:
- if (nf_log_dump_udp_header(m, skb, ih->protocol,
- ntohs(ih->frag_off) & IP_OFFSET,
- iphoff+ih->ihl*4))
- return;
- break;
- case IPPROTO_ICMP: {
- struct icmphdr _icmph;
- const struct icmphdr *ich;
- static const size_t required_len[NR_ICMP_TYPES+1]
- = { [ICMP_ECHOREPLY] = 4,
- [ICMP_DEST_UNREACH]
- = 8 + sizeof(struct iphdr),
- [ICMP_SOURCE_QUENCH]
- = 8 + sizeof(struct iphdr),
- [ICMP_REDIRECT]
- = 8 + sizeof(struct iphdr),
- [ICMP_ECHO] = 4,
- [ICMP_TIME_EXCEEDED]
- = 8 + sizeof(struct iphdr),
- [ICMP_PARAMETERPROB]
- = 8 + sizeof(struct iphdr),
- [ICMP_TIMESTAMP] = 20,
- [ICMP_TIMESTAMPREPLY] = 20,
- [ICMP_ADDRESS] = 12,
- [ICMP_ADDRESSREPLY] = 12 };
-
- /* Max length: 11 "PROTO=ICMP " */
- nf_log_buf_add(m, "PROTO=ICMP ");
-
- if (ntohs(ih->frag_off) & IP_OFFSET)
- break;
-
- /* Max length: 25 "INCOMPLETE [65535 bytes] " */
- ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
- sizeof(_icmph), &_icmph);
- if (ich == NULL) {
- nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
- skb->len - iphoff - ih->ihl*4);
- break;
- }
-
- /* Max length: 18 "TYPE=255 CODE=255 " */
- nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
-
- /* Max length: 25 "INCOMPLETE [65535 bytes] " */
- if (ich->type <= NR_ICMP_TYPES &&
- required_len[ich->type] &&
- skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
- nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
- skb->len - iphoff - ih->ihl*4);
- break;
- }
-
- switch (ich->type) {
- case ICMP_ECHOREPLY:
- case ICMP_ECHO:
- /* Max length: 19 "ID=65535 SEQ=65535 " */
- nf_log_buf_add(m, "ID=%u SEQ=%u ",
- ntohs(ich->un.echo.id),
- ntohs(ich->un.echo.sequence));
- break;
-
- case ICMP_PARAMETERPROB:
- /* Max length: 14 "PARAMETER=255 " */
- nf_log_buf_add(m, "PARAMETER=%u ",
- ntohl(ich->un.gateway) >> 24);
- break;
- case ICMP_REDIRECT:
- /* Max length: 24 "GATEWAY=255.255.255.255 " */
- nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
- fallthrough;
- case ICMP_DEST_UNREACH:
- case ICMP_SOURCE_QUENCH:
- case ICMP_TIME_EXCEEDED:
- /* Max length: 3+maxlen */
- if (!iphoff) { /* Only recurse once. */
- nf_log_buf_add(m, "[");
- dump_ipv4_packet(net, m, info, skb,
- iphoff + ih->ihl*4+sizeof(_icmph));
- nf_log_buf_add(m, "] ");
- }
-
- /* Max length: 10 "MTU=65535 " */
- if (ich->type == ICMP_DEST_UNREACH &&
- ich->code == ICMP_FRAG_NEEDED) {
- nf_log_buf_add(m, "MTU=%u ",
- ntohs(ich->un.frag.mtu));
- }
- }
- break;
- }
- /* Max Length */
- case IPPROTO_AH: {
- struct ip_auth_hdr _ahdr;
- const struct ip_auth_hdr *ah;
-
- if (ntohs(ih->frag_off) & IP_OFFSET)
- break;
-
- /* Max length: 9 "PROTO=AH " */
- nf_log_buf_add(m, "PROTO=AH ");
-
- /* Max length: 25 "INCOMPLETE [65535 bytes] " */
- ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
- sizeof(_ahdr), &_ahdr);
- if (ah == NULL) {
- nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
- skb->len - iphoff - ih->ihl*4);
- break;
- }
-
- /* Length: 15 "SPI=0xF1234567 " */
- nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi));
- break;
- }
- case IPPROTO_ESP: {
- struct ip_esp_hdr _esph;
- const struct ip_esp_hdr *eh;
-
- /* Max length: 10 "PROTO=ESP " */
- nf_log_buf_add(m, "PROTO=ESP ");
-
- if (ntohs(ih->frag_off) & IP_OFFSET)
- break;
-
- /* Max length: 25 "INCOMPLETE [65535 bytes] " */
- eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
- sizeof(_esph), &_esph);
- if (eh == NULL) {
- nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
- skb->len - iphoff - ih->ihl*4);
- break;
- }
-
- /* Length: 15 "SPI=0xF1234567 " */
- nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi));
- break;
- }
- /* Max length: 10 "PROTO 255 " */
- default:
- nf_log_buf_add(m, "PROTO=%u ", ih->protocol);
- }
-
- /* Max length: 15 "UID=4294967295 " */
- if ((logflags & NF_LOG_UID) && !iphoff)
- nf_log_dump_sk_uid_gid(net, m, skb->sk);
-
- /* Max length: 16 "MARK=0xFFFFFFFF " */
- if (!iphoff && skb->mark)
- nf_log_buf_add(m, "MARK=0x%x ", skb->mark);
-
- /* Proto Max log string length */
- /* IP: 40+46+6+11+127 = 230 */
- /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */
- /* UDP: 10+max(25,20) = 35 */
- /* UDPLITE: 14+max(25,20) = 39 */
- /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
- /* ESP: 10+max(25)+15 = 50 */
- /* AH: 9+max(25)+15 = 49 */
- /* unknown: 10 */
-
- /* (ICMP allows recursion one level deep) */
- /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */
- /* maxlen = 230+ 91 + 230 + 252 = 803 */
-}
-
-static void dump_ipv4_mac_header(struct nf_log_buf *m,
- const struct nf_loginfo *info,
- const struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- unsigned int logflags = 0;
-
- if (info->type == NF_LOG_TYPE_LOG)
- logflags = info->u.log.logflags;
-
- if (!(logflags & NF_LOG_MACDECODE))
- goto fallback;
-
- switch (dev->type) {
- case ARPHRD_ETHER:
- nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ",
- eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest);
- nf_log_dump_vlan(m, skb);
- nf_log_buf_add(m, "MACPROTO=%04x ",
- ntohs(eth_hdr(skb)->h_proto));
- return;
- default:
- break;
- }
-
-fallback:
- nf_log_buf_add(m, "MAC=");
- if (dev->hard_header_len &&
- skb->mac_header != skb->network_header) {
- const unsigned char *p = skb_mac_header(skb);
- unsigned int i;
-
- nf_log_buf_add(m, "%02x", *p++);
- for (i = 1; i < dev->hard_header_len; i++, p++)
- nf_log_buf_add(m, ":%02x", *p);
- }
- nf_log_buf_add(m, " ");
-}
-
-static void nf_log_ip_packet(struct net *net, u_int8_t pf,
- unsigned int hooknum, const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct nf_loginfo *loginfo,
- const char *prefix)
-{
- struct nf_log_buf *m;
-
- /* FIXME: Disabled from containers until syslog ns is supported */
- if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns)
- return;
-
- m = nf_log_buf_open();
-
- if (!loginfo)
- loginfo = &default_loginfo;
-
- nf_log_dump_packet_common(m, pf, hooknum, skb, in,
- out, loginfo, prefix);
-
- if (in != NULL)
- dump_ipv4_mac_header(m, loginfo, skb);
-
- dump_ipv4_packet(net, m, loginfo, skb, 0);
-
- nf_log_buf_close(m);
-}
-
-static struct nf_logger nf_ip_logger __read_mostly = {
- .name = "nf_log_ipv4",
- .type = NF_LOG_TYPE_LOG,
- .logfn = nf_log_ip_packet,
- .me = THIS_MODULE,
-};
-
-static int __net_init nf_log_ipv4_net_init(struct net *net)
-{
- return nf_log_set(net, NFPROTO_IPV4, &nf_ip_logger);
-}
-
-static void __net_exit nf_log_ipv4_net_exit(struct net *net)
-{
- nf_log_unset(net, &nf_ip_logger);
-}
-
-static struct pernet_operations nf_log_ipv4_net_ops = {
- .init = nf_log_ipv4_net_init,
- .exit = nf_log_ipv4_net_exit,
-};
-
-static int __init nf_log_ipv4_init(void)
-{
- int ret;
-
- ret = register_pernet_subsys(&nf_log_ipv4_net_ops);
- if (ret < 0)
- return ret;
-
- ret = nf_log_register(NFPROTO_IPV4, &nf_ip_logger);
- if (ret < 0) {
- pr_err("failed to register logger\n");
- goto err1;
- }
-
- return 0;
-
-err1:
- unregister_pernet_subsys(&nf_log_ipv4_net_ops);
- return ret;
-}
-
-static void __exit nf_log_ipv4_exit(void)
-{
- unregister_pernet_subsys(&nf_log_ipv4_net_ops);
- nf_log_unregister(&nf_ip_logger);
-}
-
-module_init(nf_log_ipv4_init);
-module_exit(nf_log_ipv4_exit);
-
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("Netfilter IPv4 packet logging");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NF_LOGGER(AF_INET, 0);