Diff markup
1 /* 1 /*
2 * This is a module which is used for setting 2 * This is a module which is used for setting the MSS option in TCP packets.
3 * 3 *
4 * Copyright (C) 2000 Marc Boucher <marc@mbsi. 4 * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
5 * 5 *
6 * This program is free software; you can redi 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Publi 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11 #include <linux/module.h> 11 #include <linux/module.h>
12 #include <linux/skbuff.h> 12 #include <linux/skbuff.h>
13 #include <linux/ip.h> 13 #include <linux/ip.h>
14 #include <linux/ipv6.h> 14 #include <linux/ipv6.h>
15 #include <linux/tcp.h> 15 #include <linux/tcp.h>
16 #include <net/dst.h> 16 #include <net/dst.h>
17 #include <net/flow.h> 17 #include <net/flow.h>
18 #include <net/ipv6.h> 18 #include <net/ipv6.h>
19 #include <net/route.h> 19 #include <net/route.h>
20 #include <net/tcp.h> 20 #include <net/tcp.h>
21 21
22 #include <linux/netfilter_ipv4/ip_tables.h> 22 #include <linux/netfilter_ipv4/ip_tables.h>
23 #include <linux/netfilter_ipv6/ip6_tables.h> 23 #include <linux/netfilter_ipv6/ip6_tables.h>
24 #include <linux/netfilter/x_tables.h> 24 #include <linux/netfilter/x_tables.h>
25 #include <linux/netfilter/xt_tcpudp.h> 25 #include <linux/netfilter/xt_tcpudp.h>
26 #include <linux/netfilter/xt_TCPMSS.h> 26 #include <linux/netfilter/xt_TCPMSS.h>
27 27
28 MODULE_LICENSE("GPL"); 28 MODULE_LICENSE("GPL");
29 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); 29 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
30 MODULE_DESCRIPTION("Xtables: TCP Maximum Segme 30 MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment");
31 MODULE_ALIAS("ipt_TCPMSS"); 31 MODULE_ALIAS("ipt_TCPMSS");
32 MODULE_ALIAS("ip6t_TCPMSS"); 32 MODULE_ALIAS("ip6t_TCPMSS");
33 33
34 static inline unsigned int 34 static inline unsigned int
35 optlen(const u_int8_t *opt, unsigned int offse 35 optlen(const u_int8_t *opt, unsigned int offset)
36 { 36 {
37 /* Beware zero-length options: make fi 37 /* Beware zero-length options: make finite progress */
38 if (opt[offset] <= TCPOPT_NOP || opt[o 38 if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
39 return 1; 39 return 1;
40 else 40 else
41 return opt[offset+1]; 41 return opt[offset+1];
42 } 42 }
43 43
44 static int 44 static int
45 tcpmss_mangle_packet(struct sk_buff *skb, 45 tcpmss_mangle_packet(struct sk_buff *skb,
46 const struct xt_tcpmss_in 46 const struct xt_tcpmss_info *info,
47 unsigned int in_mtu, 47 unsigned int in_mtu,
48 unsigned int tcphoff, 48 unsigned int tcphoff,
49 unsigned int minlen) 49 unsigned int minlen)
50 { 50 {
51 struct tcphdr *tcph; 51 struct tcphdr *tcph;
52 unsigned int tcplen, i; 52 unsigned int tcplen, i;
53 __be16 oldval; 53 __be16 oldval;
54 u16 newmss; 54 u16 newmss;
55 u8 *opt; 55 u8 *opt;
56 56
57 if (!skb_make_writable(skb, skb->len)) 57 if (!skb_make_writable(skb, skb->len))
58 return -1; 58 return -1;
59 59
60 tcplen = skb->len - tcphoff; 60 tcplen = skb->len - tcphoff;
61 tcph = (struct tcphdr *)(skb_network_h 61 tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
62 62
63 /* Since it passed flags test in tcp m 63 /* Since it passed flags test in tcp match, we know it is is
64 not a fragment, and has data >= tcp 64 not a fragment, and has data >= tcp header length. SYN
65 packets should not contain data: if 65 packets should not contain data: if they did, then we risk
66 running over MTU, sending Frag Need 66 running over MTU, sending Frag Needed and breaking things
67 badly. --RR */ 67 badly. --RR */
68 if (tcplen != tcph->doff*4) { 68 if (tcplen != tcph->doff*4) {
69 if (net_ratelimit()) 69 if (net_ratelimit())
70 printk(KERN_ERR "xt_TC 70 printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n",
71 skb->len); 71 skb->len);
72 return -1; 72 return -1;
73 } 73 }
74 74
75 if (info->mss == XT_TCPMSS_CLAMP_PMTU) 75 if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
76 if (dst_mtu(skb->dst) <= minle !! 76 if (dst_mtu(skb_dst(skb)) <= minlen) {
77 if (net_ratelimit()) 77 if (net_ratelimit())
78 printk(KERN_ER 78 printk(KERN_ERR "xt_TCPMSS: "
79 "unknow 79 "unknown or invalid path-MTU (%u)\n",
80 dst_mtu !! 80 dst_mtu(skb_dst(skb)));
81 return -1; 81 return -1;
82 } 82 }
83 if (in_mtu <= minlen) { 83 if (in_mtu <= minlen) {
84 if (net_ratelimit()) 84 if (net_ratelimit())
85 printk(KERN_ER 85 printk(KERN_ERR "xt_TCPMSS: unknown or "
86 "invali 86 "invalid path-MTU (%u)\n", in_mtu);
87 return -1; 87 return -1;
88 } 88 }
89 newmss = min(dst_mtu(skb->dst) !! 89 newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
90 } else 90 } else
91 newmss = info->mss; 91 newmss = info->mss;
92 92
93 opt = (u_int8_t *)tcph; 93 opt = (u_int8_t *)tcph;
94 for (i = sizeof(struct tcphdr); i < tc 94 for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
95 if (opt[i] == TCPOPT_MSS && tc 95 if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
96 opt[i+1] == TCPOLEN_MSS) { 96 opt[i+1] == TCPOLEN_MSS) {
97 u_int16_t oldmss; 97 u_int16_t oldmss;
98 98
99 oldmss = (opt[i+2] << 99 oldmss = (opt[i+2] << 8) | opt[i+3];
100 100
101 /* Never increase MSS, 101 /* Never increase MSS, even when setting it, as
102 * doing so results in 102 * doing so results in problems for hosts that rely
103 * on MSS being set co 103 * on MSS being set correctly.
104 */ 104 */
105 if (oldmss <= newmss) 105 if (oldmss <= newmss)
106 return 0; 106 return 0;
107 107
108 opt[i+2] = (newmss & 0 108 opt[i+2] = (newmss & 0xff00) >> 8;
109 opt[i+3] = newmss & 0x 109 opt[i+3] = newmss & 0x00ff;
110 110
111 inet_proto_csum_replac 111 inet_proto_csum_replace2(&tcph->check, skb,
112 112 htons(oldmss), htons(newmss),
113 113 0);
114 return 0; 114 return 0;
115 } 115 }
116 } 116 }
117 117
118 /* 118 /*
119 * MSS Option not found ?! add it.. 119 * MSS Option not found ?! add it..
120 */ 120 */
121 if (skb_tailroom(skb) < TCPOLEN_MSS) { 121 if (skb_tailroom(skb) < TCPOLEN_MSS) {
122 if (pskb_expand_head(skb, 0, 122 if (pskb_expand_head(skb, 0,
123 TCPOLEN_M 123 TCPOLEN_MSS - skb_tailroom(skb),
124 GFP_ATOMI 124 GFP_ATOMIC))
125 return -1; 125 return -1;
126 tcph = (struct tcphdr *)(skb_n 126 tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
127 } 127 }
128 128
129 skb_put(skb, TCPOLEN_MSS); 129 skb_put(skb, TCPOLEN_MSS);
130 130
131 opt = (u_int8_t *)tcph + sizeof(struct 131 opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
132 memmove(opt + TCPOLEN_MSS, opt, tcplen 132 memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
133 133
134 inet_proto_csum_replace2(&tcph->check, 134 inet_proto_csum_replace2(&tcph->check, skb,
135 htons(tcplen) 135 htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
136 opt[0] = TCPOPT_MSS; 136 opt[0] = TCPOPT_MSS;
137 opt[1] = TCPOLEN_MSS; 137 opt[1] = TCPOLEN_MSS;
138 opt[2] = (newmss & 0xff00) >> 8; 138 opt[2] = (newmss & 0xff00) >> 8;
139 opt[3] = newmss & 0x00ff; 139 opt[3] = newmss & 0x00ff;
140 140
141 inet_proto_csum_replace4(&tcph->check, 141 inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0);
142 142
143 oldval = ((__be16 *)tcph)[6]; 143 oldval = ((__be16 *)tcph)[6];
144 tcph->doff += TCPOLEN_MSS/4; 144 tcph->doff += TCPOLEN_MSS/4;
145 inet_proto_csum_replace2(&tcph->check, 145 inet_proto_csum_replace2(&tcph->check, skb,
146 oldval, ((__b 146 oldval, ((__be16 *)tcph)[6], 0);
147 return TCPOLEN_MSS; 147 return TCPOLEN_MSS;
148 } 148 }
149 149
150 static u_int32_t tcpmss_reverse_mtu4(const str !! 150 static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
>> 151 unsigned int family)
151 { 152 {
152 struct flowi fl = { !! 153 struct flowi fl = {};
153 .fl4_dst = iph->saddr, <<
154 }; <<
155 const struct nf_afinfo *ai; 154 const struct nf_afinfo *ai;
156 struct rtable *rt = NULL; 155 struct rtable *rt = NULL;
157 u_int32_t mtu = ~0U; 156 u_int32_t mtu = ~0U;
158 157
>> 158 if (family == PF_INET)
>> 159 fl.fl4_dst = ip_hdr(skb)->saddr;
>> 160 else
>> 161 fl.fl6_dst = ipv6_hdr(skb)->saddr;
>> 162
159 rcu_read_lock(); 163 rcu_read_lock();
160 ai = nf_get_afinfo(AF_INET); !! 164 ai = nf_get_afinfo(family);
161 if (ai != NULL) 165 if (ai != NULL)
162 ai->route((struct dst_entry ** 166 ai->route((struct dst_entry **)&rt, &fl);
163 rcu_read_unlock(); 167 rcu_read_unlock();
164 168
165 if (rt != NULL) { 169 if (rt != NULL) {
166 mtu = dst_mtu(&rt->u.dst); 170 mtu = dst_mtu(&rt->u.dst);
167 dst_release(&rt->u.dst); 171 dst_release(&rt->u.dst);
168 } 172 }
169 return mtu; 173 return mtu;
170 } 174 }
171 175
172 static unsigned int 176 static unsigned int
173 tcpmss_tg4(struct sk_buff *skb, const struct n !! 177 tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par)
174 const struct net_device *out, unsig <<
175 const struct xt_target *target, con <<
176 { 178 {
177 struct iphdr *iph = ip_hdr(skb); 179 struct iphdr *iph = ip_hdr(skb);
178 __be16 newlen; 180 __be16 newlen;
179 int ret; 181 int ret;
180 182
181 ret = tcpmss_mangle_packet(skb, targin !! 183 ret = tcpmss_mangle_packet(skb, par->targinfo,
>> 184 tcpmss_reverse_mtu(skb, PF_INET),
182 iph->ihl * 185 iph->ihl * 4,
183 sizeof(*iph 186 sizeof(*iph) + sizeof(struct tcphdr));
184 if (ret < 0) 187 if (ret < 0)
185 return NF_DROP; 188 return NF_DROP;
186 if (ret > 0) { 189 if (ret > 0) {
187 iph = ip_hdr(skb); 190 iph = ip_hdr(skb);
188 newlen = htons(ntohs(iph->tot_ 191 newlen = htons(ntohs(iph->tot_len) + ret);
189 csum_replace2(&iph->check, iph 192 csum_replace2(&iph->check, iph->tot_len, newlen);
190 iph->tot_len = newlen; 193 iph->tot_len = newlen;
191 } 194 }
192 return XT_CONTINUE; 195 return XT_CONTINUE;
193 } 196 }
194 197
195 #if defined(CONFIG_IP6_NF_IPTABLES) || defined 198 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
196 static u_int32_t tcpmss_reverse_mtu6(const str <<
197 { <<
198 struct flowi fl = { <<
199 .fl6_dst = iph->saddr, <<
200 }; <<
201 const struct nf_afinfo *ai; <<
202 struct rtable *rt = NULL; <<
203 u_int32_t mtu = ~0U; <<
204 <<
205 rcu_read_lock(); <<
206 ai = nf_get_afinfo(AF_INET6); <<
207 if (ai != NULL) <<
208 ai->route((struct dst_entry ** <<
209 rcu_read_unlock(); <<
210 <<
211 if (rt != NULL) { <<
212 mtu = dst_mtu(&rt->u.dst); <<
213 dst_release(&rt->u.dst); <<
214 } <<
215 return mtu; <<
216 } <<
217 <<
218 static unsigned int 199 static unsigned int
219 tcpmss_tg6(struct sk_buff *skb, const struct n !! 200 tcpmss_tg6(struct sk_buff *skb, const struct xt_target_param *par)
220 const struct net_device *out, unsig <<
221 const struct xt_target *target, con <<
222 { 201 {
223 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 202 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
224 u8 nexthdr; 203 u8 nexthdr;
225 int tcphoff; 204 int tcphoff;
226 int ret; 205 int ret;
227 206
228 nexthdr = ipv6h->nexthdr; 207 nexthdr = ipv6h->nexthdr;
229 tcphoff = ipv6_skip_exthdr(skb, sizeof 208 tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
230 if (tcphoff < 0) 209 if (tcphoff < 0)
231 return NF_DROP; 210 return NF_DROP;
232 ret = tcpmss_mangle_packet(skb, targin !! 211 ret = tcpmss_mangle_packet(skb, par->targinfo,
>> 212 tcpmss_reverse_mtu(skb, PF_INET6),
233 tcphoff, 213 tcphoff,
234 sizeof(*ipv 214 sizeof(*ipv6h) + sizeof(struct tcphdr));
235 if (ret < 0) 215 if (ret < 0)
236 return NF_DROP; 216 return NF_DROP;
237 if (ret > 0) { 217 if (ret > 0) {
238 ipv6h = ipv6_hdr(skb); 218 ipv6h = ipv6_hdr(skb);
239 ipv6h->payload_len = htons(nto 219 ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
240 } 220 }
241 return XT_CONTINUE; 221 return XT_CONTINUE;
242 } 222 }
243 #endif 223 #endif
244 224
245 #define TH_SYN 0x02 225 #define TH_SYN 0x02
246 226
247 /* Must specify -p tcp --syn */ 227 /* Must specify -p tcp --syn */
248 static inline bool find_syn_match(const struct 228 static inline bool find_syn_match(const struct xt_entry_match *m)
249 { 229 {
250 const struct xt_tcp *tcpinfo = (const 230 const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
251 231
252 if (strcmp(m->u.kernel.match->name, "t 232 if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
253 tcpinfo->flg_cmp & TH_SYN && 233 tcpinfo->flg_cmp & TH_SYN &&
254 !(tcpinfo->invflags & XT_TCP_INV_F 234 !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
255 return true; 235 return true;
256 236
257 return false; 237 return false;
258 } 238 }
259 239
260 static bool !! 240 static bool tcpmss_tg4_check(const struct xt_tgchk_param *par)
261 tcpmss_tg4_check(const char *tablename, const <<
262 const struct xt_target *targe <<
263 unsigned int hook_mask) <<
264 { 241 {
265 const struct xt_tcpmss_info *info = ta !! 242 const struct xt_tcpmss_info *info = par->targinfo;
266 const struct ipt_entry *e = entry; !! 243 const struct ipt_entry *e = par->entryinfo;
267 244
268 if (info->mss == XT_TCPMSS_CLAMP_PMTU 245 if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
269 (hook_mask & ~((1 << NF_INET_FORWA !! 246 (par->hook_mask & ~((1 << NF_INET_FORWARD) |
270 (1 << NF_INET_LOCAL 247 (1 << NF_INET_LOCAL_OUT) |
271 (1 << NF_INET_POST_ 248 (1 << NF_INET_POST_ROUTING))) != 0) {
272 printk("xt_TCPMSS: path-MTU cl 249 printk("xt_TCPMSS: path-MTU clamping only supported in "
273 "FORWARD, OUTPUT and PO 250 "FORWARD, OUTPUT and POSTROUTING hooks\n");
274 return false; 251 return false;
275 } 252 }
276 if (IPT_MATCH_ITERATE(e, find_syn_matc 253 if (IPT_MATCH_ITERATE(e, find_syn_match))
277 return true; 254 return true;
278 printk("xt_TCPMSS: Only works on TCP S 255 printk("xt_TCPMSS: Only works on TCP SYN packets\n");
279 return false; 256 return false;
280 } 257 }
281 258
282 #if defined(CONFIG_IP6_NF_IPTABLES) || defined 259 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
283 static bool !! 260 static bool tcpmss_tg6_check(const struct xt_tgchk_param *par)
284 tcpmss_tg6_check(const char *tablename, const <<
285 const struct xt_target *targe <<
286 unsigned int hook_mask) <<
287 { 261 {
288 const struct xt_tcpmss_info *info = ta !! 262 const struct xt_tcpmss_info *info = par->targinfo;
289 const struct ip6t_entry *e = entry; !! 263 const struct ip6t_entry *e = par->entryinfo;
290 264
291 if (info->mss == XT_TCPMSS_CLAMP_PMTU 265 if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
292 (hook_mask & ~((1 << NF_INET_FORWA !! 266 (par->hook_mask & ~((1 << NF_INET_FORWARD) |
293 (1 << NF_INET_LOCAL 267 (1 << NF_INET_LOCAL_OUT) |
294 (1 << NF_INET_POST_ 268 (1 << NF_INET_POST_ROUTING))) != 0) {
295 printk("xt_TCPMSS: path-MTU cl 269 printk("xt_TCPMSS: path-MTU clamping only supported in "
296 "FORWARD, OUTPUT and PO 270 "FORWARD, OUTPUT and POSTROUTING hooks\n");
297 return false; 271 return false;
298 } 272 }
299 if (IP6T_MATCH_ITERATE(e, find_syn_mat 273 if (IP6T_MATCH_ITERATE(e, find_syn_match))
300 return true; 274 return true;
301 printk("xt_TCPMSS: Only works on TCP S 275 printk("xt_TCPMSS: Only works on TCP SYN packets\n");
302 return false; 276 return false;
303 } 277 }
304 #endif 278 #endif
305 279
306 static struct xt_target tcpmss_tg_reg[] __read 280 static struct xt_target tcpmss_tg_reg[] __read_mostly = {
307 { 281 {
308 .family = AF_INET, !! 282 .family = NFPROTO_IPV4,
309 .name = "TCPMSS", 283 .name = "TCPMSS",
310 .checkentry = tcpmss_tg4_c 284 .checkentry = tcpmss_tg4_check,
311 .target = tcpmss_tg4, 285 .target = tcpmss_tg4,
312 .targetsize = sizeof(struc 286 .targetsize = sizeof(struct xt_tcpmss_info),
313 .proto = IPPROTO_TCP, 287 .proto = IPPROTO_TCP,
314 .me = THIS_MODULE, 288 .me = THIS_MODULE,
315 }, 289 },
316 #if defined(CONFIG_IP6_NF_IPTABLES) || defined 290 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
317 { 291 {
318 .family = AF_INET6, !! 292 .family = NFPROTO_IPV6,
319 .name = "TCPMSS", 293 .name = "TCPMSS",
320 .checkentry = tcpmss_tg6_c 294 .checkentry = tcpmss_tg6_check,
321 .target = tcpmss_tg6, 295 .target = tcpmss_tg6,
322 .targetsize = sizeof(struc 296 .targetsize = sizeof(struct xt_tcpmss_info),
323 .proto = IPPROTO_TCP, 297 .proto = IPPROTO_TCP,
324 .me = THIS_MODULE, 298 .me = THIS_MODULE,
325 }, 299 },
326 #endif 300 #endif
327 }; 301 };
328 302
329 static int __init tcpmss_tg_init(void) 303 static int __init tcpmss_tg_init(void)
330 { 304 {
331 return xt_register_targets(tcpmss_tg_r 305 return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
332 } 306 }
333 307
334 static void __exit tcpmss_tg_exit(void) 308 static void __exit tcpmss_tg_exit(void)
335 { 309 {
336 xt_unregister_targets(tcpmss_tg_reg, A 310 xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
337 } 311 }
338 312
339 module_init(tcpmss_tg_init); 313 module_init(tcpmss_tg_init);
340 module_exit(tcpmss_tg_exit); 314 module_exit(tcpmss_tg_exit);
341 315
|
This page was automatically generated by the
LXR engine.
|