From d446a8202c81d95f91b1682fc67e7fadd9a31389 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 9 Jun 2011 21:03:07 +0200 Subject: netfilter: xtables: move ipt_ecn to xt_ecn Prepare the ECN match for augmentation by an IPv6 counterpart. Since no symbol dependencies to ipv6.ko are added, having a single ecn match module is the more so welcome. Signed-off-by: Jan Engelhardt Signed-off-by: Pablo Neira Ayuso --- net/netfilter/Kconfig | 9 ++++ net/netfilter/Makefile | 1 + net/netfilter/xt_ecn.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 net/netfilter/xt_ecn.c (limited to 'net/netfilter') diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index bac93ba6077..20388a97df6 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -778,6 +778,15 @@ config NETFILTER_XT_MATCH_DSCP To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_ECN + tristate '"ecn" match support' + depends on NETFILTER_ADVANCED + ---help--- + This option adds an "ECN" match, which allows you to match against + the IPv4 and TCP header ECN fields. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_MATCH_ESP tristate '"esp" match support' depends on NETFILTER_ADVANCED diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index b2eee4df816..40f4c3d636c 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o obj-$(CONFIG_NETFILTER_XT_MATCH_DEVGROUP) += xt_devgroup.o obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o +obj-$(CONFIG_NETFILTER_XT_MATCH_ECN) += xt_ecn.o obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o diff --git a/net/netfilter/xt_ecn.c b/net/netfilter/xt_ecn.c new file mode 100644 index 00000000000..2c198f5e3ef --- /dev/null +++ b/net/netfilter/xt_ecn.c @@ -0,0 +1,128 @@ +/* IP tables module for matching the value of the IPv4 and TCP ECN bits + * + * (C) 2002 by Harald Welte + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_ecn"); + +static inline bool match_ip(const struct sk_buff *skb, + const struct ipt_ecn_info *einfo) +{ + return ((ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect) ^ + !!(einfo->invert & IPT_ECN_OP_MATCH_IP); +} + +static inline bool match_tcp(const struct sk_buff *skb, + const struct ipt_ecn_info *einfo, + bool *hotdrop) +{ + struct tcphdr _tcph; + const struct tcphdr *th; + + /* In practice, TCP match does this, so can't fail. But let's + * be good citizens. + */ + th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); + if (th == NULL) { + *hotdrop = false; + return false; + } + + if (einfo->operation & IPT_ECN_OP_MATCH_ECE) { + if (einfo->invert & IPT_ECN_OP_MATCH_ECE) { + if (th->ece == 1) + return false; + } else { + if (th->ece == 0) + return false; + } + } + + if (einfo->operation & IPT_ECN_OP_MATCH_CWR) { + if (einfo->invert & IPT_ECN_OP_MATCH_CWR) { + if (th->cwr == 1) + return false; + } else { + if (th->cwr == 0) + return false; + } + } + + return true; +} + +static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct ipt_ecn_info *info = par->matchinfo; + + if (info->operation & IPT_ECN_OP_MATCH_IP) + if (!match_ip(skb, info)) + return false; + + if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) { + if (!match_tcp(skb, info, &par->hotdrop)) + return false; + } + + return true; +} + +static int ecn_mt_check(const struct xt_mtchk_param *par) +{ + const struct ipt_ecn_info *info = par->matchinfo; + const struct ipt_ip *ip = par->entryinfo; + + if (info->operation & IPT_ECN_OP_MATCH_MASK) + return -EINVAL; + + if (info->invert & IPT_ECN_OP_MATCH_MASK) + return -EINVAL; + + if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) && + (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) { + pr_info("cannot match TCP bits in rule for non-tcp packets\n"); + return -EINVAL; + } + + return 0; +} + +static struct xt_match ecn_mt_reg __read_mostly = { + .name = "ecn", + .family = NFPROTO_IPV4, + .match = ecn_mt, + .matchsize = sizeof(struct ipt_ecn_info), + .checkentry = ecn_mt_check, + .me = THIS_MODULE, +}; + +static int __init ecn_mt_init(void) +{ + return xt_register_match(&ecn_mt_reg); +} + +static void __exit ecn_mt_exit(void) +{ + xt_unregister_match(&ecn_mt_reg); +} + +module_init(ecn_mt_init); +module_exit(ecn_mt_exit); -- cgit v1.2.3