diff options
-rw-r--r-- | net/netfilter/xt_ecn.c | 106 |
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 | ||
21 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | 24 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
22 | MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4"); | 25 | MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match"); |
23 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
24 | MODULE_ALIAS("ipt_ecn"); | 27 | MODULE_ALIAS("ipt_ecn"); |
28 | MODULE_ALIAS("ip6t_ecn"); | ||
25 | 29 | ||
26 | static inline bool match_ip(const struct sk_buff *skb, | 30 | static 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 | |||
33 | static 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 | ||
72 | static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par) | 67 | static 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 | |||
74 | static 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 | ||
88 | static int ecn_mt_check(const struct xt_mtchk_param *par) | 90 | static 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 | ||
108 | static struct xt_match ecn_mt_reg __read_mostly = { | 110 | static 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 | |||
118 | static 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 | |||
132 | static 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 | |||
152 | static 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 | ||
117 | static int __init ecn_mt_init(void) | 171 | static 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 | ||
122 | static void __exit ecn_mt_exit(void) | 176 | static 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 | ||
127 | module_init(ecn_mt_init); | 181 | module_init(ecn_mt_init); |