* [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