* [PATCH RFC 0/3] netfilter reverse path filter matches
@ 2011-08-26 9:21 Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 1/3] netfilter: add reverse path filter match Florian Westphal
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Florian Westphal @ 2011-08-26 9:21 UTC (permalink / raw)
To: netfilter-devel
Here are the ipv4/ipv6 reverse path filter matches that
were discussed briefly at the workshop.
These are not ready for merging at this time, but I think
sending current status is helpful in moving things forward.
There are 3 matches:
xt_rpfilter, ipt_rpfilter, ip6t_rpfilter.
Obviously, it will be either xt_rpfilter or the latter two.
At the moment, xt_rpfilter has too many issues: it does not behave
the same as current ip4-builtin rp_filter, because output route resolution
is used for validation.
Depending on the routes this may result in different route lookup results
than what a real reply packet would see.
It also breaks with ipv4 multipath setups when there are several matching
routes.
As ipv4 and ipv6 need different treatment anyway, using different modules
does not seem to be a problem. (This also avoids extra module dependency
issues)
The ipv4-only match (ipt_rpfilter) tries to do exactly what the current
fib_validate_source does. Known remaining Problems are:
- additional fib lookup to get oif (will be used in reverse lookup as iif)
- using match in PREROUTING may do the wrong thing when
policy routing is used via mangle PREROUTING (we may perform
fib lookup with wrong nfmark)
- using it in FORWARD is problematic because stack could send out
icmp errors (ttl exceeded, PMTU, ...) before the packet would
have been rpf-tested.
We seemed to have consesus on the following:
- no special treatment of ipsec-protected packets (users can use policy match)
- packets from IFF_LOOPBACK should always match
- result caching can be implemented later on, if needed.
Userspace part is stored in my iptables repository on
http://git.breakpoint.cc/cgi-bin/gitweb.cgi?p=fw/iptables.git (branch 'rpfilter').
Kernel patches are located in the 'xt_rpfilter' branch on
http://git.breakpoint.cc/cgi-bin/gitweb.cgi?p=fw/nf-next.git (i'll send the relevant patches
as followup to this email).
Please let me know if I forgot any remaing issues, or if you spot any
additional issues that have not been raised so far.
Thanks,
Florian
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC 1/3] netfilter: add reverse path filter match
2011-08-26 9:21 [PATCH RFC 0/3] netfilter reverse path filter matches Florian Westphal
@ 2011-08-26 9:21 ` Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 2/3] netfilter: add ipv4 " Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 3/3] ip6t_rpf: initial version Florian Westphal
2 siblings, 0 replies; 12+ messages in thread
From: Florian Westphal @ 2011-08-26 9:21 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
More flexible replacement for the reverse path filter
built into the ipv4 network stack; also supports ipv6.
Unlike the current builtin ipv4 rpfilter, packets subject to ipsec
transformation are not automatically excluded; if you want this
combine with policy match.
---
include/linux/netfilter/xt_rpfilter.h | 21 ++++
net/netfilter/Kconfig | 10 ++
net/netfilter/Makefile | 1 +
net/netfilter/xt_rpfilter.c | 175 +++++++++++++++++++++++++++++++++
4 files changed, 207 insertions(+), 0 deletions(-)
create mode 100644 include/linux/netfilter/xt_rpfilter.h
create mode 100644 net/netfilter/xt_rpfilter.c
diff --git a/include/linux/netfilter/xt_rpfilter.h b/include/linux/netfilter/xt_rpfilter.h
new file mode 100644
index 0000000..8d2d3f8
--- /dev/null
+++ b/include/linux/netfilter/xt_rpfilter.h
@@ -0,0 +1,21 @@
+#ifndef _XT_RPATH_H
+#define _XT_RPATH_H
+
+#include <linux/types.h>
+
+enum {
+ XT_RPFILTER_LOOSE = 1 << 0,
+ XT_RPFILTER_VALID_MARK = 1 << 1,
+ XT_RPFILTER_ACCEPT_LOCAL = 1 << 2,
+#ifdef __KERNEL__
+ XT_RPFILTER_OPTION_MASK = XT_RPFILTER_LOOSE |
+ XT_RPFILTER_VALID_MARK |
+ XT_RPFILTER_ACCEPT_LOCAL,
+#endif
+};
+
+struct xt_rpfilter_info {
+ __u8 flags;
+};
+
+#endif
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 32bff6d..2e746e5 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -881,6 +881,16 @@ config NETFILTER_XT_MATCH_MULTIPORT
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_RPFILTER
+ tristate '"rpfilter" reverse path filter match support'
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This option allows you to match packets whose replies would
+ go out via the interface the packet came in.
+
+ To compile it as a module, choose M here. If unsure, say N.
+ The module will be called xt_rpfilter.
+
config NETFILTER_XT_MATCH_OSF
tristate '"osf" Passive OS fingerprint match'
depends on NETFILTER_ADVANCED && NETFILTER_NETLINK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 1a02853..c69d9fb 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_RPFILTER) += xt_rpfilter.o
obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o
obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
diff --git a/net/netfilter/xt_rpfilter.c b/net/netfilter/xt_rpfilter.c
new file mode 100644
index 0000000..edb6e8e
--- /dev/null
+++ b/net/netfilter/xt_rpfilter.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <net/route.h>
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/ip6_fib.h>
+#endif
+
+#include <linux/netfilter/xt_rpfilter.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Xtables: reverse path filter match");
+MODULE_ALIAS("ipt_rpfilter");
+MODULE_ALIAS("ip6t_rpfilter");
+
+static bool rpfilter_lookup(struct net *net, u8 nfproto, struct dst_entry **dst,
+ struct flowi *flow)
+{
+ const struct nf_afinfo *afinfo;
+ int route_err;
+ bool strict = nfproto == NFPROTO_IPV6;
+
+ rcu_read_lock();
+
+ afinfo = nf_get_afinfo(nfproto);
+ if (afinfo != NULL)
+ route_err = afinfo->route(net, dst, flow, strict);
+ else
+ route_err = 1;
+
+ rcu_read_unlock();
+
+ return route_err == 0;
+}
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static struct dst_entry* rpfilter_mt6(struct net *net,
+ const struct sk_buff *skb, u32 mark)
+{
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct rt6_info *rt;
+ struct flowi6 flow = {
+ .daddr = iph->daddr,
+ .saddr = iph->saddr,
+ .flowi6_proto = iph->nexthdr,
+ .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
+ .flowi6_mark = mark,
+ .flowi6_flags = FLOWI_FLAG_ANYSRC,
+ };
+
+ if (rpfilter_lookup(net, NFPROTO_IPV6,
+ (struct dst_entry **)&rt, flowi6_to_flowi(&flow)))
+ return &rt->dst;
+ return NULL;
+}
+#endif
+
+static __be32 rpfilter_get_saddr(__be32 addr)
+{
+ if (ipv4_is_multicast(addr) ||
+ ipv4_is_lbcast(addr) ||
+ ipv4_is_zeronet(addr))
+ return 0;
+ return addr;
+}
+
+static struct dst_entry* rpfilter_mt4(const struct sk_buff *skb,
+ const struct net_device *indev, u32 mark)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ struct flowi4 flow;
+ struct rtable *rt;
+ __be32 daddr = iph->saddr;
+ __be32 saddr = rpfilter_get_saddr(iph->daddr);
+
+ flowi4_init_output(&flow, 0, mark, RT_TOS(iph->tos), RT_SCOPE_UNIVERSE,
+ iph->protocol, FLOWI_FLAG_ANYSRC, daddr, saddr, 0, 0);
+
+ printk(KERN_INFO "got saddr %pI4, daddr %pI4 on dev %s\n",&iph->saddr,&iph->daddr,indev->name);
+ if (rpfilter_lookup(dev_net(indev), NFPROTO_IPV4,
+ (struct dst_entry **)&rt, flowi4_to_flowi(&flow))) {
+ printk(KERN_INFO "found rt->rt_iif %d, %d flags 0x%x\n", rt->rt_iif, rt->rt_oif, rt->rt_flags);
+ return &rt->dst;
+ }
+ return NULL;
+}
+
+static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_rpfilter_info *info;
+ struct dst_entry *dst;
+ bool matches;
+ u32 mark;
+ struct net *net;
+
+ if (par->in->flags & IFF_LOOPBACK)
+ return true;
+
+ info = par->matchinfo;
+ net = dev_net(par->in);
+ mark = info->flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
+
+ switch (par->family) {
+ case NFPROTO_IPV4:
+ dst = rpfilter_mt4(skb, par->in, mark);
+ break;
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+ case NFPROTO_IPV6:
+ dst = rpfilter_mt6(net, skb, mark);
+ break;
+#endif
+ default:
+ return false;
+ }
+
+ matches = false;
+ if (dst) {
+ bool loose = info->flags & XT_RPFILTER_LOOSE;
+ printk("got dest->dev %p, %s\n", dst->dev, dst->dev ? dst->dev->name : "(null)");
+ matches = loose ? dst->dev : dst->dev == par->in;
+ dst_release(dst);
+ } else
+ printk("no result\n");
+ return matches;
+}
+
+static int rpfilter_check(const struct xt_mtchk_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+ unsigned int options = ~XT_RPFILTER_OPTION_MASK;
+
+ if (info->flags & options) {
+ pr_info("unknown options encountered");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct xt_match rpfilter_mt_reg __read_mostly = {
+ .name = "rpfilter",
+ .family = NFPROTO_UNSPEC,
+ .checkentry = rpfilter_check,
+ .match = rpfilter_mt,
+ .matchsize = sizeof(struct xt_rpfilter_info),
+ .hooks = 1 << NF_INET_PRE_ROUTING,
+ .me = THIS_MODULE
+};
+
+static int __init rpfilter_mt_init(void)
+{
+ return xt_register_match(&rpfilter_mt_reg);
+}
+
+static void __exit rpfilter_mt_exit(void)
+{
+ xt_unregister_match(&rpfilter_mt_reg);
+}
+
+module_init(rpfilter_mt_init);
+module_exit(rpfilter_mt_exit);
--
1.7.3.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-26 9:21 [PATCH RFC 0/3] netfilter reverse path filter matches Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 1/3] netfilter: add reverse path filter match Florian Westphal
@ 2011-08-26 9:21 ` Florian Westphal
2011-08-30 12:34 ` Patrick McHardy
2011-08-26 9:21 ` [PATCH RFC 3/3] ip6t_rpf: initial version Florian Westphal
2 siblings, 1 reply; 12+ messages in thread
From: Florian Westphal @ 2011-08-26 9:21 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
This tries to mimic behaviour of fib_validate_source.
main drawback:
- additional fib lookup to get oif (used as flow key in reverse lookup)
- no result caching so far
Other issues:
- can't use FORWARD chain because by the time FORWARD is invoked
ipv4 forward path may have already sent icmp messages is response
to to-be-discarded-via-rpfilter packets
- using it in PREROUTING may do the wrong thing (e.g. when using
policy routing via mangle PREROUTING)
---
net/ipv4/netfilter/Kconfig | 10 ++
net/ipv4/netfilter/Makefile | 1 +
net/ipv4/netfilter/ipt_rpfilter.c | 172 +++++++++++++++++++++++++++++++++++++
3 files changed, 183 insertions(+), 0 deletions(-)
create mode 100644 net/ipv4/netfilter/ipt_rpfilter.c
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 1dfc18a..ef8c1ab 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -82,6 +82,16 @@ config IP_NF_MATCH_ECN
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_MATCH_RPFILTER
+ tristate '"rpfilter" reverse path filter match support'
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This option allows you to match packets whose replies would
+ go out via the interface the packet came in.
+
+ To compile it as a module, choose M here. If unsure, say N.
+ The module will be called ipt_rpfilter.
+
config IP_NF_MATCH_TTL
tristate '"ttl" match support'
depends on NETFILTER_ADVANCED
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index dca2082..123dd88 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
# matches
obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
# targets
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
new file mode 100644
index 0000000..889f705
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * based on fib_frontend.c; Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <net/ip_fib.h>
+#include <net/route.h>
+
+#include <linux/netfilter/xt_rpfilter.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("iptables: ipv4 reverse path filter match");
+
+/* don't try to find route from mcast/bcast/zeronet */
+static __be32 rpfilter_get_saddr(__be32 addr)
+{
+ if (ipv4_is_multicast(addr) || ipv4_is_lbcast(addr) ||
+ ipv4_is_zeronet(addr))
+ return 0;
+ return addr;
+}
+
+static bool rpfilter_lookup_reverse(struct flowi4 *fl4,
+ const struct net_device *dev, u8 flags)
+{
+ struct fib_result res;
+ bool dev_match;
+ struct net *net = dev_net(dev);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ int ret;
+#endif
+ if (fib_lookup(net, fl4, &res))
+ return false;
+
+ if (res.type != RTN_UNICAST) {
+ if (res.type != RTN_LOCAL || !(flags & XT_RPFILTER_ACCEPT_LOCAL))
+ return false;
+ }
+ dev_match = false;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ for (ret = 0; ret < res.fi->fib_nhs; ret++) {
+ struct fib_nh *nh = &res.fi->fib_nh[ret];
+
+ if (nh->nh_dev == dev) {
+ dev_match = true;
+ break;
+ }
+ }
+#else
+ if (FIB_RES_DEV(res) == dev)
+ dev_match = true;
+#endif
+ if (dev_match || flags & XT_RPFILTER_LOOSE)
+ return FIB_RES_NH(res).nh_scope <= RT_SCOPE_HOST;
+ return dev_match;
+}
+
+static bool rpfilter_lookup(struct flowi4 *fl4, const struct net_device *dev,
+ const struct xt_rpfilter_info *info)
+{
+ int err, oif;
+ struct fib_result res;
+ struct net *net;
+ __be32 addr;
+
+ if (ipv4_is_multicast(fl4->daddr)) {
+ if (ipv4_is_zeronet(fl4->saddr))
+ return ipv4_is_local_multicast(fl4->daddr);
+ oif = 0;
+ goto validate;
+ }
+
+ net = dev_net(dev);
+ err = fib_lookup(net, fl4, &res);
+ if (err)
+ return false;
+
+ switch (res.type) {
+ case RTN_BROADCAST:
+ if (ipv4_is_zeronet(fl4->saddr))
+ return true;
+ oif = 0;
+ break;
+ case RTN_LOCAL:
+ oif = net->loopback_dev->ifindex;
+ break;
+ default:
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (res.fi && res.fi->fib_nhs > 1)
+ fib_select_multipath(&res);
+#endif
+ oif = FIB_RES_OIF(res);
+ break;
+ }
+
+ validate:
+ addr = fl4->saddr;
+ fl4->saddr = rpfilter_get_saddr(fl4->daddr);
+ fl4->daddr = addr;
+ fl4->flowi4_iif = oif;
+ if (!(info->flags & XT_RPFILTER_VALID_MARK))
+ fl4->flowi4_mark = 0;
+ return rpfilter_lookup_reverse(fl4, dev, info->flags);
+}
+
+static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_rpfilter_info *info;
+ const struct iphdr *iph;
+ struct flowi4 flow;
+
+ if (par->in->flags & IFF_LOOPBACK)
+ return true;
+
+ iph = ip_hdr(skb);
+ info = par->matchinfo;
+
+ flow.flowi4_oif = 0;
+ flow.flowi4_iif = par->in->ifindex;
+ flow.flowi4_mark = skb->mark;
+ flow.flowi4_tos = RT_TOS(iph->tos);
+ flow.flowi4_scope = RT_SCOPE_UNIVERSE;
+ flow.daddr = iph->daddr;
+ flow.saddr = iph->saddr;
+
+ return rpfilter_lookup(&flow, par->in, info);
+}
+
+static int rpfilter_check(const struct xt_mtchk_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+ unsigned int options = ~XT_RPFILTER_OPTION_MASK;
+ if (info->flags & options) {
+ pr_info("unknown options encountered");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct xt_match rpfilter_mt_reg __read_mostly = {
+ .name = "rpfilter",
+ .family = NFPROTO_IPV4,
+ .checkentry = rpfilter_check,
+ .match = rpfilter_mt,
+ .matchsize = sizeof(struct xt_rpfilter_info),
+ .hooks = (1 << NF_INET_PRE_ROUTING),
+ .me = THIS_MODULE
+};
+
+static int __init rpfilter_mt_init(void)
+{
+ return xt_register_match(&rpfilter_mt_reg);
+}
+
+static void __exit rpfilter_mt_exit(void)
+{
+ xt_unregister_match(&rpfilter_mt_reg);
+}
+
+module_init(rpfilter_mt_init);
+module_exit(rpfilter_mt_exit);
--
1.7.3.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH RFC 3/3] ip6t_rpf: initial version
2011-08-26 9:21 [PATCH RFC 0/3] netfilter reverse path filter matches Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 1/3] netfilter: add reverse path filter match Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 2/3] netfilter: add ipv4 " Florian Westphal
@ 2011-08-26 9:21 ` Florian Westphal
2011-08-26 9:58 ` Jan Engelhardt
2 siblings, 1 reply; 12+ messages in thread
From: Florian Westphal @ 2011-08-26 9:21 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
compile tested only.
Differs significantly from ipv4 version, as the oif will
not be used as flow key (we use the iif).
Also, multicast probably needs special handling, too.
---
net/ipv6/netfilter/Kconfig | 10 +++
net/ipv6/netfilter/Makefile | 1 +
net/ipv6/netfilter/ip6t_rpfilter.c | 116 ++++++++++++++++++++++++++++++++++++
3 files changed, 127 insertions(+), 0 deletions(-)
create mode 100644 net/ipv6/netfilter/ip6t_rpfilter.c
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 4484648..49ec98b 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -125,6 +125,16 @@ config IP6_NF_MATCH_MH
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_MATCH_RPFILTER
+ tristate '"rpfilter" reverse path filter match support'
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This option allows you to match packets whose replies would
+ go out via the interface the packet came in.
+
+ To compile it as a module, choose M here. If unsure, say N.
+ The module will be called ip6t_rpfilter.
+
config IP6_NF_MATCH_RT
tristate '"rt" Routing header match support'
depends on NETFILTER_ADVANCED
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index abfee91..2eaed96 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
+obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
# targets
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c
new file mode 100644
index 0000000..bc5075d
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_rpfilter.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
+#include <net/dsfield.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+
+#include <linux/netfilter/xt_rpfilter.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Xtables: IPv6 reverse path filter match");
+
+/* don't try to find route from mcast/bcast/zeronet */
+static bool rpfilter_addr_unicast(const struct in6_addr *addr)
+{
+ int addr_type = ipv6_addr_type(addr);
+ return addr_type & IPV6_ADDR_UNICAST;
+}
+
+static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,
+ const struct net_device *dev, u8 flags)
+{
+ struct rt6_info *rt;
+ struct dst_entry *dst;
+ bool ret = false;
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct flowi6 fl6 = {
+ .flowi6_oif = dev->ifindex,
+ .daddr = iph->daddr,
+ .flowi6_proto = iph->nexthdr,
+ };
+
+ fl6.flowlabel = ipv6_get_dsfield(iph);
+ fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
+
+ if (rpfilter_addr_unicast(&iph->daddr))
+ ipv6_addr_copy(&fl6.saddr, &iph->daddr);
+
+ dst = ip6_route_output(dev_net(dev), NULL, &fl6);
+ if (dst->error)
+ goto out;
+
+ rt = (void *) dst;
+
+ if (rt->rt6i_flags & (RTF_REJECT|RTF_ANYCAST))
+ goto out;
+
+ if (rt->rt6i_flags & RTF_LOCAL) {
+ ret = flags & XT_RPFILTER_ACCEPT_LOCAL;
+ goto out;
+ }
+
+ if (rt->rt6i_idev->dev == dev)
+ ret = true;
+ else
+ ret = flags & XT_RPFILTER_LOOSE;
+ out:
+ dst_release(&rt->dst);
+ return ret;
+}
+
+static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+
+ if (par->in->flags & IFF_LOOPBACK)
+ return true;
+
+ return rpfilter_lookup_reverse6(skb, par->in, info->flags);
+}
+
+static int rpfilter_check(const struct xt_mtchk_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+ unsigned int options = ~XT_RPFILTER_OPTION_MASK;
+
+ if (info->flags & options) {
+ pr_info("unknown options encountered");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct xt_match rpfilter_mt_reg __read_mostly = {
+ .name = "rpfilter",
+ .family = NFPROTO_IPV6,
+ .checkentry = rpfilter_check,
+ .match = rpfilter_mt,
+ .matchsize = sizeof(struct xt_rpfilter_info),
+ .hooks = (1 << NF_INET_PRE_ROUTING),
+ .me = THIS_MODULE
+};
+
+static int __init rpfilter_mt_init(void)
+{
+ return xt_register_match(&rpfilter_mt_reg);
+}
+
+static void __exit rpfilter_mt_exit(void)
+{
+ xt_unregister_match(&rpfilter_mt_reg);
+}
+
+module_init(rpfilter_mt_init);
+module_exit(rpfilter_mt_exit);
--
1.7.3.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 3/3] ip6t_rpf: initial version
2011-08-26 9:21 ` [PATCH RFC 3/3] ip6t_rpf: initial version Florian Westphal
@ 2011-08-26 9:58 ` Jan Engelhardt
0 siblings, 0 replies; 12+ messages in thread
From: Jan Engelhardt @ 2011-08-26 9:58 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Friday 2011-08-26 11:21, Florian Westphal wrote:
>compile tested only.
>Differs significantly from ipv4 version, as the oif will
>not be used as flow key (we use the iif).
>
>Also, multicast probably needs special handling, too.
>---
> net/ipv6/netfilter/Kconfig | 10 +++
> net/ipv6/netfilter/Makefile | 1 +
> net/ipv6/netfilter/ip6t_rpfilter.c | 116 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 127 insertions(+), 0 deletions(-)
> create mode 100644 net/ipv6/netfilter/ip6t_rpfilter.c
>
>diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
>index 4484648..49ec98b 100644
>--- a/net/ipv6/netfilter/Kconfig
>+++ b/net/ipv6/netfilter/Kconfig
>@@ -125,6 +125,16 @@ config IP6_NF_MATCH_MH
>
> To compile it as a module, choose M here. If unsure, say N.
>
>+config IP6_NF_MATCH_RPFILTER
>+ tristate '"rpfilter" reverse path filter match support'
>+ depends on NETFILTER_ADVANCED
>+ ---help---
>+ This option allows you to match packets whose replies would
>+ go out via the interface the packet came in.
>+
>+ To compile it as a module, choose M here. If unsure, say N.
>+ The module will be called ip6t_rpfilter.
>+
> config IP6_NF_MATCH_RT
> tristate '"rt" Routing header match support'
> depends on NETFILTER_ADVANCED
>diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
>index abfee91..2eaed96 100644
>--- a/net/ipv6/netfilter/Makefile
>+++ b/net/ipv6/netfilter/Makefile
>@@ -27,6 +27,7 @@ obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
> obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
> obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
> obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
>+obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
> obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
>
> # targets
>diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c
>new file mode 100644
>index 0000000..bc5075d
>--- /dev/null
>+++ b/net/ipv6/netfilter/ip6t_rpfilter.c
>@@ -0,0 +1,116 @@
>+/*
>+ * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>+#include <linux/module.h>
>+#include <linux/skbuff.h>
>+#include <linux/netdevice.h>
>+#include <linux/route.h>
>+#include <net/dsfield.h>
>+#include <net/ip6_fib.h>
>+#include <net/ip6_route.h>
>+
>+#include <linux/netfilter/xt_rpfilter.h>
>+#include <linux/netfilter/x_tables.h>
>+
>+MODULE_LICENSE("GPL");
>+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
>+MODULE_DESCRIPTION("Xtables: IPv6 reverse path filter match");
>+
>+/* don't try to find route from mcast/bcast/zeronet */
>+static bool rpfilter_addr_unicast(const struct in6_addr *addr)
>+{
>+ int addr_type = ipv6_addr_type(addr);
>+ return addr_type & IPV6_ADDR_UNICAST;
>+}
>+
>+static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,
>+ const struct net_device *dev, u8 flags)
>+{
>+ struct rt6_info *rt;
>+ struct dst_entry *dst;
>+ bool ret = false;
>+ struct ipv6hdr *iph = ipv6_hdr(skb);
>+ struct flowi6 fl6 = {
>+ .flowi6_oif = dev->ifindex,
>+ .daddr = iph->daddr,
>+ .flowi6_proto = iph->nexthdr,
>+ };
>+
>+ fl6.flowlabel = ipv6_get_dsfield(iph);
>+ fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
This looks weird. In xt_rpfilter, you used
+ .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
and now you are copying the traffic class into the flowlabel instead.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-26 9:21 ` [PATCH RFC 2/3] netfilter: add ipv4 " Florian Westphal
@ 2011-08-30 12:34 ` Patrick McHardy
2011-08-30 12:41 ` Florian Westphal
0 siblings, 1 reply; 12+ messages in thread
From: Patrick McHardy @ 2011-08-30 12:34 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On 26.08.2011 11:21, Florian Westphal wrote:
> This tries to mimic behaviour of fib_validate_source.
>
> main drawback:
> - additional fib lookup to get oif (used as flow key in reverse lookup)
As discussed during the workshop, we could just perform input routing
in the module to get the oif for free. That would require to take care
of statistics as currently done in ip_rcv_finish() though.
> - no result caching so far
>
> Other issues:
> - can't use FORWARD chain because by the time FORWARD is invoked
> ipv4 forward path may have already sent icmp messages is response
> to to-be-discarded-via-rpfilter packets
> - using it in PREROUTING may do the wrong thing (e.g. when using
> policy routing via mangle PREROUTING)
Not if you're setting up policy routing keys (marks) before doing
rp_filter, right? Would require using it in the mangle table of
course.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-30 12:34 ` Patrick McHardy
@ 2011-08-30 12:41 ` Florian Westphal
2011-08-30 12:45 ` Patrick McHardy
0 siblings, 1 reply; 12+ messages in thread
From: Florian Westphal @ 2011-08-30 12:41 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel
Patrick McHardy <kaber@trash.net> wrote:
> > main drawback:
> > - additional fib lookup to get oif (used as flow key in reverse lookup)
>
> As discussed during the workshop, we could just perform input routing
> in the module to get the oif for free. That would require to take care
> of statistics as currently done in ip_rcv_finish() though.
Right.
Any idea on how to solve the 'struct sk_buff *' (ip_route_input) vs.
'const struct sk_buff *' (matches) problem?
We'd have to modify all the match signatures...
> > Other issues:
> > - can't use FORWARD chain because by the time FORWARD is invoked
> > ipv4 forward path may have already sent icmp messages is response
> > to to-be-discarded-via-rpfilter packets
> > - using it in PREROUTING may do the wrong thing (e.g. when using
> > policy routing via mangle PREROUTING)
>
> Not if you're setting up policy routing keys (marks) before doing
> rp_filter, right? Would require using it in the mangle table of
> course.
Yes that should work as well.
It might be unexpected for some people, though (but this is just a
documentation issue).
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-30 12:41 ` Florian Westphal
@ 2011-08-30 12:45 ` Patrick McHardy
2011-08-30 12:57 ` Florian Westphal
0 siblings, 1 reply; 12+ messages in thread
From: Patrick McHardy @ 2011-08-30 12:45 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On 30.08.2011 14:41, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
>>> main drawback:
>>> - additional fib lookup to get oif (used as flow key in reverse lookup)
>>
>> As discussed during the workshop, we could just perform input routing
>> in the module to get the oif for free. That would require to take care
>> of statistics as currently done in ip_rcv_finish() though.
>
> Right.
> Any idea on how to solve the 'struct sk_buff *' (ip_route_input) vs.
> 'const struct sk_buff *' (matches) problem?
>
> We'd have to modify all the match signatures...
Some modules already remove the const by casting it away, not
pretty, but works. Since the kernel doesn't assume strict aliasing
this also shouldn't cause any problems in the future. Alternatively
we can change the function signatures of course, although that would
be a bit unfortunate just for this special case.
>>> Other issues:
>>> - can't use FORWARD chain because by the time FORWARD is invoked
>>> ipv4 forward path may have already sent icmp messages is response
>>> to to-be-discarded-via-rpfilter packets
>>> - using it in PREROUTING may do the wrong thing (e.g. when using
>>> policy routing via mangle PREROUTING)
>>
>> Not if you're setting up policy routing keys (marks) before doing
>> rp_filter, right? Would require using it in the mangle table of
>> course.
>
> Yes that should work as well.
> It might be unexpected for some people, though (but this is just a
> documentation issue).
I agree.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-30 12:45 ` Patrick McHardy
@ 2011-08-30 12:57 ` Florian Westphal
2011-08-30 13:03 ` Patrick McHardy
2011-08-30 13:53 ` Jan Engelhardt
0 siblings, 2 replies; 12+ messages in thread
From: Florian Westphal @ 2011-08-30 12:57 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel
Patrick McHardy <kaber@trash.net> wrote:
> On 30.08.2011 14:41, Florian Westphal wrote:
> > Patrick McHardy <kaber@trash.net> wrote:
> >>> main drawback:
> >>> - additional fib lookup to get oif (used as flow key in reverse lookup)
> >>
> >> As discussed during the workshop, we could just perform input routing
> >> in the module to get the oif for free. That would require to take care
> >> of statistics as currently done in ip_rcv_finish() though.
> >
> > Right.
> > Any idea on how to solve the 'struct sk_buff *' (ip_route_input) vs.
> > 'const struct sk_buff *' (matches) problem?
> >
> > We'd have to modify all the match signatures...
>
> Some modules already remove the const by casting it away, not
> pretty, but works. Since the kernel doesn't assume strict aliasing
> this also shouldn't cause any problems in the future. Alternatively
> we can change the function signatures of course, although that would
> be a bit unfortunate just for this special case.
Agreed, modifying the match function signature for this case would be
sad.
I'll wait a couple of days and will send an updated version
that uses the ugly cast + ip_route_input.
Thanks for your input!
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-30 12:57 ` Florian Westphal
@ 2011-08-30 13:03 ` Patrick McHardy
2011-08-30 13:53 ` Jan Engelhardt
1 sibling, 0 replies; 12+ messages in thread
From: Patrick McHardy @ 2011-08-30 13:03 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On 30.08.2011 14:57, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
>> On 30.08.2011 14:41, Florian Westphal wrote:
>>> Patrick McHardy <kaber@trash.net> wrote:
>>>>> main drawback:
>>>>> - additional fib lookup to get oif (used as flow key in reverse lookup)
>>>>
>>>> As discussed during the workshop, we could just perform input routing
>>>> in the module to get the oif for free. That would require to take care
>>>> of statistics as currently done in ip_rcv_finish() though.
>>>
>>> Right.
>>> Any idea on how to solve the 'struct sk_buff *' (ip_route_input) vs.
>>> 'const struct sk_buff *' (matches) problem?
>>>
>>> We'd have to modify all the match signatures...
>>
>> Some modules already remove the const by casting it away, not
>> pretty, but works. Since the kernel doesn't assume strict aliasing
>> this also shouldn't cause any problems in the future. Alternatively
>> we can change the function signatures of course, although that would
>> be a bit unfortunate just for this special case.
>
> Agreed, modifying the match function signature for this case would be
> sad.
>
> I'll wait a couple of days and will send an updated version
> that uses the ugly cast + ip_route_input.
Regarding the statistic update, I'd suggest to move those to
a new function and call it from your module to avoid duplication
and possibly getting out of sync in the future.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-30 12:57 ` Florian Westphal
2011-08-30 13:03 ` Patrick McHardy
@ 2011-08-30 13:53 ` Jan Engelhardt
2011-08-30 13:54 ` Patrick McHardy
1 sibling, 1 reply; 12+ messages in thread
From: Jan Engelhardt @ 2011-08-30 13:53 UTC (permalink / raw)
To: Florian Westphal; +Cc: Patrick McHardy, netfilter-devel
On Tuesday 2011-08-30 14:57, Florian Westphal wrote:
>>
>> Some modules already remove the const by casting it away, not
>> pretty, but works. Since the kernel doesn't assume strict aliasing
>> this also shouldn't cause any problems in the future. Alternatively
>> we can change the function signatures of course, although that would
>> be a bit unfortunate just for this special case.
>
>Agreed, modifying the match function signature for this case would be
>sad.
>
>I'll wait a couple of days and will send an updated version
>that uses the ugly cast + ip_route_input.
What could be done is:
struct xt_match {
union {
int (*match)(const struct sk_buff *, ...);
int (*match_nonc)(struct sk_buff *, ...);
};
};
falls into the same "ugh, what beauty" category :-)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/3] netfilter: add ipv4 reverse path filter match
2011-08-30 13:53 ` Jan Engelhardt
@ 2011-08-30 13:54 ` Patrick McHardy
0 siblings, 0 replies; 12+ messages in thread
From: Patrick McHardy @ 2011-08-30 13:54 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Florian Westphal, netfilter-devel
On 30.08.2011 15:53, Jan Engelhardt wrote:
>
> On Tuesday 2011-08-30 14:57, Florian Westphal wrote:
>>>
>>> Some modules already remove the const by casting it away, not
>>> pretty, but works. Since the kernel doesn't assume strict aliasing
>>> this also shouldn't cause any problems in the future. Alternatively
>>> we can change the function signatures of course, although that would
>>> be a bit unfortunate just for this special case.
>>
>> Agreed, modifying the match function signature for this case would be
>> sad.
>>
>> I'll wait a couple of days and will send an updated version
>> that uses the ugly cast + ip_route_input.
>
> What could be done is:
>
> struct xt_match {
> union {
> int (*match)(const struct sk_buff *, ...);
> int (*match_nonc)(struct sk_buff *, ...);
> };
> };
>
> falls into the same "ugh, what beauty" category :-)
Yes, I've considered that as well. But yeah, its not much better than
simply casting the const away.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2011-08-30 13:54 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-26 9:21 [PATCH RFC 0/3] netfilter reverse path filter matches Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 1/3] netfilter: add reverse path filter match Florian Westphal
2011-08-26 9:21 ` [PATCH RFC 2/3] netfilter: add ipv4 " Florian Westphal
2011-08-30 12:34 ` Patrick McHardy
2011-08-30 12:41 ` Florian Westphal
2011-08-30 12:45 ` Patrick McHardy
2011-08-30 12:57 ` Florian Westphal
2011-08-30 13:03 ` Patrick McHardy
2011-08-30 13:53 ` Jan Engelhardt
2011-08-30 13:54 ` Patrick McHardy
2011-08-26 9:21 ` [PATCH RFC 3/3] ip6t_rpf: initial version Florian Westphal
2011-08-26 9:58 ` Jan Engelhardt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).