diff --git a/include/linux/netfilter/xt_route.h b/include/linux/netfilter/xt_route.h new file mode 100644 index 0000000..0c90494 --- /dev/null +++ b/include/linux/netfilter/xt_route.h @@ -0,0 +1,21 @@ +#ifndef _XT_ROUTE_H +#define _XT_ROUTE_H + +enum { + XT_ROUTE_SRC_EXISTS = 0, + XT_ROUTE_SRC_EQ, + XT_ROUTE_SRC_GT, + XT_ROUTE_SRC_LT, + XT_ROUTE_DST_EXISTS, + XT_ROUTE_DST_EQ, + XT_ROUTE_DST_GT, + XT_ROUTE_DST_LT, +}; + +struct xt_route_info { + u_int8_t invert; + u_int8_t mode; + u_int8_t prefixlen; +}; + +#endif /*_XT_ROUTE_H*/ diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 0d4d728..22bbdd5 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -156,6 +156,8 @@ void free_fib_info(struct fib_info *fi) kfree(fi); } +EXPORT_SYMBOL_GPL(free_fib_info); + void fib_release_info(struct fib_info *fi) { spin_lock_bh(&fib_info_lock); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index aa8d80c..128b186 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -724,6 +724,16 @@ config NETFILTER_XT_MATCH_REALM If you want to compile it as a module, say M here and read . If unsure, say `N'. +config NETFILTER_XT_MATCH_ROUTE + tristate '"route" match support' + depends on NETFILTER_XTABLES + depends on NETFILTER_ADVANCED + help + This option adds a `route' match, which allows you to match on + the kernel routing table. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_MATCH_SCTP tristate '"sctp" protocol match support (EXPERIMENTAL)' depends on NETFILTER_XTABLES && EXPERIMENTAL diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 5c4b183..1035372 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o +obj-$(CONFIG_NETFILTER_XT_MATCH_ROUTE) += xt_route.o obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o diff --git a/net/netfilter/xt_route.c b/net/netfilter/xt_route.c new file mode 100644 index 0000000..c6e9f94 --- /dev/null +++ b/net/netfilter/xt_route.c @@ -0,0 +1,141 @@ +/* Kernel module to match against the kernel routing table. */ +/* (C) 2008 Phil Oester + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Phil Oester "); +MODULE_DESCRIPTION("Xtables: Routing table match"); +MODULE_LICENSE("GPL"); + +static bool +route_mt(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const struct xt_match *match, + const void *matchinfo, int offset, unsigned int protoff, + bool *hotdrop) +{ + const struct xt_route_info *info = matchinfo; + const struct iphdr *iph = ip_hdr(skb); + struct fib_result res = {0}; + struct flowi fl = {0}; + int ret; + + switch (info->mode) { + case XT_ROUTE_SRC_EXISTS: + fl.nl_u.ip4_u.daddr = iph->saddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen != 0) { + fib_res_put(&res); + return true ^ info->invert; + } + case XT_ROUTE_SRC_EQ: + fl.nl_u.ip4_u.daddr = iph->saddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen == info->prefixlen) { + fib_res_put(&res); + return true; + } + break; + case XT_ROUTE_SRC_GT: + fl.nl_u.ip4_u.daddr = iph->saddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen > info->prefixlen) { + fib_res_put(&res); + return true; + } + break; + case XT_ROUTE_SRC_LT: + fl.nl_u.ip4_u.daddr = iph->saddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen < info->prefixlen) { + fib_res_put(&res); + return true; + } + break; + case XT_ROUTE_DST_EXISTS: + fl.nl_u.ip4_u.daddr = iph->daddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen != 0) { + fib_res_put(&res); + return true ^ info->invert; + } + break; + case XT_ROUTE_DST_EQ: + fl.nl_u.ip4_u.daddr = iph->daddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen == info->prefixlen) { + fib_res_put(&res); + return true; + } + break; + case XT_ROUTE_DST_GT: + fl.nl_u.ip4_u.daddr = iph->daddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen > info->prefixlen) { + fib_res_put(&res); + return true; + } + break; + case XT_ROUTE_DST_LT: + fl.nl_u.ip4_u.daddr = iph->daddr; + ret = fib_lookup(dev_net(in), &fl, &res); + if (ret == 0 && res.prefixlen < info->prefixlen) { + fib_res_put(&res); + return true; + } + break; + } + + return false; +} + +static bool +route_mt6(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const struct xt_match *match, + const void *matchinfo, int offset, unsigned int protoff, + bool *hotdrop) +{ + return 1; +} + +static struct xt_match route_mt_reg[] __read_mostly = { + { + .name = "route", + .family = AF_INET, + .match = route_mt, + .matchsize = sizeof(struct xt_route_info), + .me = THIS_MODULE, + }, + { + .name = "route", + .family = AF_INET6, + .match = route_mt6, + .matchsize = sizeof(struct xt_route_info), + .me = THIS_MODULE, + }, +}; + +static int __init route_mt_init(void) +{ + return xt_register_matches(route_mt_reg, ARRAY_SIZE(route_mt_reg)); +} + +static void __exit route_mt_exit(void) +{ + xt_unregister_matches(route_mt_reg, ARRAY_SIZE(route_mt_reg)); +} + +module_init(route_mt_init); +module_exit(route_mt_exit);