aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-02-07 18:09:46 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-02-08 15:39:16 -0500
commitcdd289a2f833b93e65b9a09a02c37f47a58140a8 (patch)
treeed5172808cdd5b24605205732aca724a0fb9910d /net/ipv4
parenta8d0f9526ff8510d6fa5e708ef5386af19503299 (diff)
[NETFILTER]: add IPv6-capable TCPMSS target
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/Kconfig26
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/ipt_TCPMSS.c207
3 files changed, 0 insertions, 234 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 47bd3ad18b71..9b08e7ad71bc 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -361,32 +361,6 @@ config IP_NF_TARGET_ULOG
361 361
362 To compile it as a module, choose M here. If unsure, say N. 362 To compile it as a module, choose M here. If unsure, say N.
363 363
364config IP_NF_TARGET_TCPMSS
365 tristate "TCPMSS target support"
366 depends on IP_NF_IPTABLES
367 ---help---
368 This option adds a `TCPMSS' target, which allows you to alter the
369 MSS value of TCP SYN packets, to control the maximum size for that
370 connection (usually limiting it to your outgoing interface's MTU
371 minus 40).
372
373 This is used to overcome criminally braindead ISPs or servers which
374 block ICMP Fragmentation Needed packets. The symptoms of this
375 problem are that everything works fine from your Linux
376 firewall/router, but machines behind it can never exchange large
377 packets:
378 1) Web browsers connect, then hang with no data received.
379 2) Small mail works fine, but large emails hang.
380 3) ssh works fine, but scp hangs after initial handshaking.
381
382 Workaround: activate this option and add a rule to your firewall
383 configuration like:
384
385 iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
386 -j TCPMSS --clamp-mss-to-pmtu
387
388 To compile it as a module, choose M here. If unsure, say N.
389
390# NAT + specific targets: ip_conntrack 364# NAT + specific targets: ip_conntrack
391config IP_NF_NAT 365config IP_NF_NAT
392 tristate "Full NAT" 366 tristate "Full NAT"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 16d177b71bf8..6625ec68180c 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -103,7 +103,6 @@ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
103obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o 103obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
104obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o 104obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
105obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o 105obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
106obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
107obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o 106obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
108obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o 107obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
109 108
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
deleted file mode 100644
index 93eb5c3c1884..000000000000
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ /dev/null
@@ -1,207 +0,0 @@
1/*
2 * This is a module which is used for setting the MSS option in TCP packets.
3 *
4 * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/skbuff.h>
13
14#include <linux/ip.h>
15#include <net/tcp.h>
16
17#include <linux/netfilter_ipv4/ip_tables.h>
18#include <linux/netfilter_ipv4/ipt_TCPMSS.h>
19
20MODULE_LICENSE("GPL");
21MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
22MODULE_DESCRIPTION("iptables TCP MSS modification module");
23
24static inline unsigned int
25optlen(const u_int8_t *opt, unsigned int offset)
26{
27 /* Beware zero-length options: make finite progress */
28 if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
29 return 1;
30 else
31 return opt[offset+1];
32}
33
34static unsigned int
35ipt_tcpmss_target(struct sk_buff **pskb,
36 const struct net_device *in,
37 const struct net_device *out,
38 unsigned int hooknum,
39 const struct xt_target *target,
40 const void *targinfo)
41{
42 const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
43 struct tcphdr *tcph;
44 struct iphdr *iph;
45 u_int16_t tcplen, newmss;
46 __be16 newtotlen, oldval;
47 unsigned int i;
48 u_int8_t *opt;
49
50 if (!skb_make_writable(pskb, (*pskb)->len))
51 return NF_DROP;
52
53 iph = (*pskb)->nh.iph;
54 tcplen = (*pskb)->len - iph->ihl*4;
55 tcph = (void *)iph + iph->ihl*4;
56
57 /* Since it passed flags test in tcp match, we know it is is
58 not a fragment, and has data >= tcp header length. SYN
59 packets should not contain data: if they did, then we risk
60 running over MTU, sending Frag Needed and breaking things
61 badly. --RR */
62 if (tcplen != tcph->doff*4) {
63 if (net_ratelimit())
64 printk(KERN_ERR
65 "ipt_tcpmss_target: bad length (%d bytes)\n",
66 (*pskb)->len);
67 return NF_DROP;
68 }
69
70 if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
71 if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) +
72 sizeof(struct tcphdr)) {
73 if (net_ratelimit())
74 printk(KERN_ERR "ipt_tcpmss_target: "
75 "unknown or invalid path-MTU (%d)\n",
76 dst_mtu((*pskb)->dst));
77 return NF_DROP; /* or IPT_CONTINUE ?? */
78 }
79
80 newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) -
81 sizeof(struct tcphdr);
82 } else
83 newmss = tcpmssinfo->mss;
84
85 opt = (u_int8_t *)tcph;
86 for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
87 if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
88 opt[i+1] == TCPOLEN_MSS) {
89 u_int16_t oldmss;
90
91 oldmss = (opt[i+2] << 8) | opt[i+3];
92
93 if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
94 oldmss <= newmss)
95 return IPT_CONTINUE;
96
97 opt[i+2] = (newmss & 0xff00) >> 8;
98 opt[i+3] = (newmss & 0x00ff);
99
100 nf_proto_csum_replace2(&tcph->check, *pskb,
101 htons(oldmss), htons(newmss), 0);
102 return IPT_CONTINUE;
103 }
104 }
105
106 /*
107 * MSS Option not found ?! add it..
108 */
109 if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
110 struct sk_buff *newskb;
111
112 newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
113 TCPOLEN_MSS, GFP_ATOMIC);
114 if (!newskb)
115 return NF_DROP;
116 kfree_skb(*pskb);
117 *pskb = newskb;
118 iph = (*pskb)->nh.iph;
119 tcph = (void *)iph + iph->ihl*4;
120 }
121
122 skb_put((*pskb), TCPOLEN_MSS);
123
124 opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
125 memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
126
127 nf_proto_csum_replace2(&tcph->check, *pskb,
128 htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
129 opt[0] = TCPOPT_MSS;
130 opt[1] = TCPOLEN_MSS;
131 opt[2] = (newmss & 0xff00) >> 8;
132 opt[3] = (newmss & 0x00ff);
133
134 nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
135
136 oldval = ((__be16 *)tcph)[6];
137 tcph->doff += TCPOLEN_MSS/4;
138 nf_proto_csum_replace2(&tcph->check, *pskb,
139 oldval, ((__be16 *)tcph)[6], 0);
140
141 newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
142 nf_csum_replace2(&iph->check, iph->tot_len, newtotlen);
143 iph->tot_len = newtotlen;
144 return IPT_CONTINUE;
145}
146
147#define TH_SYN 0x02
148
149static inline int find_syn_match(const struct ipt_entry_match *m)
150{
151 const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
152
153 if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
154 tcpinfo->flg_cmp & TH_SYN &&
155 !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
156 return 1;
157
158 return 0;
159}
160
161/* Must specify -p tcp --syn/--tcp-flags SYN */
162static int
163ipt_tcpmss_checkentry(const char *tablename,
164 const void *e_void,
165 const struct xt_target *target,
166 void *targinfo,
167 unsigned int hook_mask)
168{
169 const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
170 const struct ipt_entry *e = e_void;
171
172 if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
173 (hook_mask & ~((1 << NF_IP_FORWARD) |
174 (1 << NF_IP_LOCAL_OUT) |
175 (1 << NF_IP_POST_ROUTING))) != 0) {
176 printk("TCPMSS: path-MTU clamping only supported in "
177 "FORWARD, OUTPUT and POSTROUTING hooks\n");
178 return 0;
179 }
180
181 if (IPT_MATCH_ITERATE(e, find_syn_match))
182 return 1;
183 printk("TCPMSS: Only works on TCP SYN packets\n");
184 return 0;
185}
186
187static struct ipt_target ipt_tcpmss_reg = {
188 .name = "TCPMSS",
189 .target = ipt_tcpmss_target,
190 .targetsize = sizeof(struct ipt_tcpmss_info),
191 .proto = IPPROTO_TCP,
192 .checkentry = ipt_tcpmss_checkentry,
193 .me = THIS_MODULE,
194};
195
196static int __init ipt_tcpmss_init(void)
197{
198 return ipt_register_target(&ipt_tcpmss_reg);
199}
200
201static void __exit ipt_tcpmss_fini(void)
202{
203 ipt_unregister_target(&ipt_tcpmss_reg);
204}
205
206module_init(ipt_tcpmss_init);
207module_exit(ipt_tcpmss_fini);