aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/netfilter/xt_ecn.c106
1 files changed, 80 insertions, 26 deletions
diff --git a/net/netfilter/xt_ecn.c b/net/netfilter/xt_ecn.c
index 3ebb3dcace65..6ccc35d6cb11 100644
--- a/net/netfilter/xt_ecn.c
+++ b/net/netfilter/xt_ecn.c
@@ -1,6 +1,8 @@
1/* IP tables module for matching the value of the IPv4 and TCP ECN bits 1/*
2 * Xtables module for matching the value of the IPv4/IPv6 and TCP ECN bits
2 * 3 *
3 * (C) 2002 by Harald Welte <laforge@gnumonks.org> 4 * (C) 2002 by Harald Welte <laforge@gnumonks.org>
5 * (C) 2011 Patrick McHardy <kaber@trash.net>
4 * 6 *
5 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -17,32 +19,25 @@
17#include <linux/netfilter/x_tables.h> 19#include <linux/netfilter/x_tables.h>
18#include <linux/netfilter/xt_ecn.h> 20#include <linux/netfilter/xt_ecn.h>
19#include <linux/netfilter_ipv4/ip_tables.h> 21#include <linux/netfilter_ipv4/ip_tables.h>
22#include <linux/netfilter_ipv6/ip6_tables.h>
20 23
21MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 24MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
22MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4"); 25MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match");
23MODULE_LICENSE("GPL"); 26MODULE_LICENSE("GPL");
24MODULE_ALIAS("ipt_ecn"); 27MODULE_ALIAS("ipt_ecn");
28MODULE_ALIAS("ip6t_ecn");
25 29
26static inline bool match_ip(const struct sk_buff *skb, 30static bool match_tcp(const struct sk_buff *skb, struct xt_action_param *par)
27 const struct xt_ecn_info *einfo)
28{
29 return ((ip_hdr(skb)->tos & XT_ECN_IP_MASK) == einfo->ip_ect) ^
30 !!(einfo->invert & XT_ECN_OP_MATCH_IP);
31}
32
33static inline bool match_tcp(const struct sk_buff *skb,
34 const struct xt_ecn_info *einfo,
35 bool *hotdrop)
36{ 31{
32 const struct xt_ecn_info *einfo = par->matchinfo;
37 struct tcphdr _tcph; 33 struct tcphdr _tcph;
38 const struct tcphdr *th; 34 const struct tcphdr *th;
39 35
40 /* In practice, TCP match does this, so can't fail. But let's 36 /* In practice, TCP match does this, so can't fail. But let's
41 * be good citizens. 37 * be good citizens.
42 */ 38 */
43 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 39 th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
44 if (th == NULL) { 40 if (th == NULL) {
45 *hotdrop = false;
46 return false; 41 return false;
47 } 42 }
48 43
@@ -69,7 +64,14 @@ static inline bool match_tcp(const struct sk_buff *skb,
69 return true; 64 return true;
70} 65}
71 66
72static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par) 67static inline bool match_ip(const struct sk_buff *skb,
68 const struct xt_ecn_info *einfo)
69{
70 return ((ip_hdr(skb)->tos & XT_ECN_IP_MASK) == einfo->ip_ect) ^
71 !!(einfo->invert & XT_ECN_OP_MATCH_IP);
72}
73
74static bool ecn_mt4(const struct sk_buff *skb, struct xt_action_param *par)
73{ 75{
74 const struct xt_ecn_info *info = par->matchinfo; 76 const struct xt_ecn_info *info = par->matchinfo;
75 77
@@ -78,14 +80,14 @@ static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par)
78 return false; 80 return false;
79 81
80 if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR)) { 82 if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR)) {
81 if (!match_tcp(skb, info, &par->hotdrop)) 83 if (!match_tcp(skb, par))
82 return false; 84 return false;
83 } 85 }
84 86
85 return true; 87 return true;
86} 88}
87 89
88static int ecn_mt_check(const struct xt_mtchk_param *par) 90static int ecn_mt_check4(const struct xt_mtchk_param *par)
89{ 91{
90 const struct xt_ecn_info *info = par->matchinfo; 92 const struct xt_ecn_info *info = par->matchinfo;
91 const struct ipt_ip *ip = par->entryinfo; 93 const struct ipt_ip *ip = par->entryinfo;
@@ -105,23 +107,75 @@ static int ecn_mt_check(const struct xt_mtchk_param *par)
105 return 0; 107 return 0;
106} 108}
107 109
108static struct xt_match ecn_mt_reg __read_mostly = { 110static inline bool match_ipv6(const struct sk_buff *skb,
109 .name = "ecn", 111 const struct xt_ecn_info *einfo)
110 .family = NFPROTO_IPV4, 112{
111 .match = ecn_mt, 113 return (((ipv6_hdr(skb)->flow_lbl[0] >> 4) & XT_ECN_IP_MASK) ==
112 .matchsize = sizeof(struct xt_ecn_info), 114 einfo->ip_ect) ^
113 .checkentry = ecn_mt_check, 115 !!(einfo->invert & XT_ECN_OP_MATCH_IP);
114 .me = THIS_MODULE, 116}
117
118static bool ecn_mt6(const struct sk_buff *skb, struct xt_action_param *par)
119{
120 const struct xt_ecn_info *info = par->matchinfo;
121
122 if (info->operation & XT_ECN_OP_MATCH_IP && !match_ipv6(skb, info))
123 return false;
124
125 if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
126 !match_tcp(skb, par))
127 return false;
128
129 return true;
130}
131
132static int ecn_mt_check6(const struct xt_mtchk_param *par)
133{
134 const struct xt_ecn_info *info = par->matchinfo;
135 const struct ip6t_ip6 *ip = par->entryinfo;
136
137 if (info->operation & XT_ECN_OP_MATCH_MASK)
138 return -EINVAL;
139
140 if (info->invert & XT_ECN_OP_MATCH_MASK)
141 return -EINVAL;
142
143 if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
144 (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) {
145 pr_info("cannot match TCP bits in rule for non-tcp packets\n");
146 return -EINVAL;
147 }
148
149 return 0;
150}
151
152static struct xt_match ecn_mt_reg[] __read_mostly = {
153 {
154 .name = "ecn",
155 .family = NFPROTO_IPV4,
156 .match = ecn_mt4,
157 .matchsize = sizeof(struct xt_ecn_info),
158 .checkentry = ecn_mt_check4,
159 .me = THIS_MODULE,
160 },
161 {
162 .name = "ecn",
163 .family = NFPROTO_IPV6,
164 .match = ecn_mt6,
165 .matchsize = sizeof(struct xt_ecn_info),
166 .checkentry = ecn_mt_check6,
167 .me = THIS_MODULE,
168 },
115}; 169};
116 170
117static int __init ecn_mt_init(void) 171static int __init ecn_mt_init(void)
118{ 172{
119 return xt_register_match(&ecn_mt_reg); 173 return xt_register_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
120} 174}
121 175
122static void __exit ecn_mt_exit(void) 176static void __exit ecn_mt_exit(void)
123{ 177{
124 xt_unregister_match(&ecn_mt_reg); 178 xt_unregister_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
125} 179}
126 180
127module_init(ecn_mt_init); 181module_init(ecn_mt_init);