Merge tag 'v3.10.108' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / netfilter / xt_TCPMSS.c
CommitLineData
cdd289a2
PM
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>
f229f6ce 5 * Copyright (C) 2007 Patrick McHardy <kaber@trash.net>
cdd289a2
PM
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
8bee4bad 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
cdd289a2
PM
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/ip.h>
5a0e3ad6 15#include <linux/gfp.h>
cdd289a2
PM
16#include <linux/ipv6.h>
17#include <linux/tcp.h>
37c08387
JE
18#include <net/dst.h>
19#include <net/flow.h>
cdd289a2 20#include <net/ipv6.h>
37c08387 21#include <net/route.h>
cdd289a2
PM
22#include <net/tcp.h>
23
24#include <linux/netfilter_ipv4/ip_tables.h>
25#include <linux/netfilter_ipv6/ip6_tables.h>
26#include <linux/netfilter/x_tables.h>
27#include <linux/netfilter/xt_tcpudp.h>
28#include <linux/netfilter/xt_TCPMSS.h>
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
2ae15b64 32MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment");
cdd289a2
PM
33MODULE_ALIAS("ipt_TCPMSS");
34MODULE_ALIAS("ip6t_TCPMSS");
35
36static inline unsigned int
37optlen(const u_int8_t *opt, unsigned int offset)
38{
39 /* Beware zero-length options: make finite progress */
40 if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
41 return 1;
42 else
43 return opt[offset+1];
44}
45
46static int
3db05fea 47tcpmss_mangle_packet(struct sk_buff *skb,
70d19f80 48 const struct xt_action_param *par,
37c08387 49 unsigned int in_mtu,
cdd289a2
PM
50 unsigned int tcphoff,
51 unsigned int minlen)
52{
70d19f80 53 const struct xt_tcpmss_info *info = par->targinfo;
cdd289a2
PM
54 struct tcphdr *tcph;
55 unsigned int tcplen, i;
56 __be16 oldval;
57 u16 newmss;
58 u8 *opt;
59
b396966c
PO
60 /* This is a fragment, no TCP header is available */
61 if (par->fragoff != 0)
62 return XT_CONTINUE;
63
3db05fea 64 if (!skb_make_writable(skb, skb->len))
cdd289a2
PM
65 return -1;
66
3db05fea
HX
67 tcplen = skb->len - tcphoff;
68 tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
cdd289a2 69
10a19939 70 /* Header cannot be larger than the packet */
72d7b83a 71 if (tcplen < tcph->doff*4 || tcph->doff*4 < sizeof(struct tcphdr))
cdd289a2 72 return -1;
cdd289a2
PM
73
74 if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
adf30907 75 if (dst_mtu(skb_dst(skb)) <= minlen) {
e87cc472
JP
76 net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
77 dst_mtu(skb_dst(skb)));
cdd289a2
PM
78 return -1;
79 }
37c08387 80 if (in_mtu <= minlen) {
e87cc472
JP
81 net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
82 in_mtu);
37c08387
JE
83 return -1;
84 }
adf30907 85 newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
cdd289a2
PM
86 } else
87 newmss = info->mss;
88
89 opt = (u_int8_t *)tcph;
90 for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
91 if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
92 opt[i+1] == TCPOLEN_MSS) {
93 u_int16_t oldmss;
94
95 oldmss = (opt[i+2] << 8) | opt[i+3];
96
17008064
BL
97 /* Never increase MSS, even when setting it, as
98 * doing so results in problems for hosts that rely
99 * on MSS being set correctly.
100 */
101 if (oldmss <= newmss)
cdd289a2
PM
102 return 0;
103
104 opt[i+2] = (newmss & 0xff00) >> 8;
7c4e36bc 105 opt[i+3] = newmss & 0x00ff;
cdd289a2 106
be0ea7d5
PM
107 inet_proto_csum_replace2(&tcph->check, skb,
108 htons(oldmss), htons(newmss),
109 0);
cdd289a2
PM
110 return 0;
111 }
112 }
113
10a19939
SA
114 /* There is data after the header so the option can't be added
115 without moving it, and doing so may make the SYN packet
116 itself too large. Accept the packet unmodified instead. */
117 if (tcplen > tcph->doff*4)
118 return 0;
119
72d7b83a
ED
120 /* tcph->doff has 4 bits, do not wrap it to 0 */
121 if (tcph->doff >= 15)
122 return 0;
123
cdd289a2
PM
124 /*
125 * MSS Option not found ?! add it..
126 */
3db05fea
HX
127 if (skb_tailroom(skb) < TCPOLEN_MSS) {
128 if (pskb_expand_head(skb, 0,
129 TCPOLEN_MSS - skb_tailroom(skb),
2ca7b0ac 130 GFP_ATOMIC))
cdd289a2 131 return -1;
3db05fea 132 tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
cdd289a2
PM
133 }
134
3db05fea 135 skb_put(skb, TCPOLEN_MSS);
cdd289a2 136
70d19f80
PO
137 /*
138 * IPv4: RFC 1122 states "If an MSS option is not received at
139 * connection setup, TCP MUST assume a default send MSS of 536".
140 * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum
141 * length IPv6 header of 60, ergo the default MSS value is 1220
142 * Since no MSS was provided, we must use the default values
409b545a 143 */
70d19f80
PO
144 if (par->family == NFPROTO_IPV4)
145 newmss = min(newmss, (u16)536);
146 else
147 newmss = min(newmss, (u16)1220);
409b545a 148
cdd289a2
PM
149 opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
150 memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
151
be0ea7d5
PM
152 inet_proto_csum_replace2(&tcph->check, skb,
153 htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
cdd289a2
PM
154 opt[0] = TCPOPT_MSS;
155 opt[1] = TCPOLEN_MSS;
156 opt[2] = (newmss & 0xff00) >> 8;
7c4e36bc 157 opt[3] = newmss & 0x00ff;
cdd289a2 158
be0ea7d5 159 inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0);
cdd289a2
PM
160
161 oldval = ((__be16 *)tcph)[6];
162 tcph->doff += TCPOLEN_MSS/4;
be0ea7d5
PM
163 inet_proto_csum_replace2(&tcph->check, skb,
164 oldval, ((__be16 *)tcph)[6], 0);
cdd289a2
PM
165 return TCPOLEN_MSS;
166}
167
db1a75bd
JE
168static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
169 unsigned int family)
37c08387 170{
a1bbb0e6 171 struct flowi fl;
37c08387
JE
172 const struct nf_afinfo *ai;
173 struct rtable *rt = NULL;
174 u_int32_t mtu = ~0U;
175
a1bbb0e6
DM
176 if (family == PF_INET) {
177 struct flowi4 *fl4 = &fl.u.ip4;
178 memset(fl4, 0, sizeof(*fl4));
179 fl4->daddr = ip_hdr(skb)->saddr;
180 } else {
181 struct flowi6 *fl6 = &fl.u.ip6;
db1a75bd 182
a1bbb0e6 183 memset(fl6, 0, sizeof(*fl6));
4e3fd7a0 184 fl6->daddr = ipv6_hdr(skb)->saddr;
a1bbb0e6 185 }
37c08387 186 rcu_read_lock();
db1a75bd 187 ai = nf_get_afinfo(family);
37c08387 188 if (ai != NULL)
0fae2e77 189 ai->route(&init_net, (struct dst_entry **)&rt, &fl, false);
37c08387
JE
190 rcu_read_unlock();
191
192 if (rt != NULL) {
d8d1f30b
CG
193 mtu = dst_mtu(&rt->dst);
194 dst_release(&rt->dst);
37c08387
JE
195 }
196 return mtu;
197}
198
cdd289a2 199static unsigned int
4b560b44 200tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
cdd289a2 201{
3db05fea 202 struct iphdr *iph = ip_hdr(skb);
cdd289a2
PM
203 __be16 newlen;
204 int ret;
205
70d19f80 206 ret = tcpmss_mangle_packet(skb, par,
db1a75bd 207 tcpmss_reverse_mtu(skb, PF_INET),
37c08387 208 iph->ihl * 4,
cdd289a2
PM
209 sizeof(*iph) + sizeof(struct tcphdr));
210 if (ret < 0)
211 return NF_DROP;
212 if (ret > 0) {
3db05fea 213 iph = ip_hdr(skb);
cdd289a2 214 newlen = htons(ntohs(iph->tot_len) + ret);
be0ea7d5 215 csum_replace2(&iph->check, iph->tot_len, newlen);
cdd289a2
PM
216 iph->tot_len = newlen;
217 }
218 return XT_CONTINUE;
219}
220
c0cd1156 221#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
cdd289a2 222static unsigned int
4b560b44 223tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
cdd289a2 224{
3db05fea 225 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
cdd289a2 226 u8 nexthdr;
75f2811c 227 __be16 frag_off;
cdd289a2
PM
228 int tcphoff;
229 int ret;
230
231 nexthdr = ipv6h->nexthdr;
75f2811c 232 tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);
9dc0564e 233 if (tcphoff < 0)
cdd289a2 234 return NF_DROP;
70d19f80 235 ret = tcpmss_mangle_packet(skb, par,
db1a75bd 236 tcpmss_reverse_mtu(skb, PF_INET6),
37c08387 237 tcphoff,
cdd289a2
PM
238 sizeof(*ipv6h) + sizeof(struct tcphdr));
239 if (ret < 0)
240 return NF_DROP;
241 if (ret > 0) {
3db05fea 242 ipv6h = ipv6_hdr(skb);
cdd289a2
PM
243 ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
244 }
245 return XT_CONTINUE;
246}
247#endif
248
cdd289a2 249/* Must specify -p tcp --syn */
e1931b78 250static inline bool find_syn_match(const struct xt_entry_match *m)
cdd289a2
PM
251{
252 const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
253
254 if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
a3433f35 255 tcpinfo->flg_cmp & TCPHDR_SYN &&
cdd289a2 256 !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
e1931b78 257 return true;
cdd289a2 258
e1931b78 259 return false;
cdd289a2
PM
260}
261
135367b8 262static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
cdd289a2 263{
af5d6dc2
JE
264 const struct xt_tcpmss_info *info = par->targinfo;
265 const struct ipt_entry *e = par->entryinfo;
dcea992a 266 const struct xt_entry_match *ematch;
cdd289a2
PM
267
268 if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
af5d6dc2 269 (par->hook_mask & ~((1 << NF_INET_FORWARD) |
6e23ae2a
PM
270 (1 << NF_INET_LOCAL_OUT) |
271 (1 << NF_INET_POST_ROUTING))) != 0) {
8bee4bad
JE
272 pr_info("path-MTU clamping only supported in "
273 "FORWARD, OUTPUT and POSTROUTING hooks\n");
d6b00a53 274 return -EINVAL;
cdd289a2 275 }
dcea992a
JE
276 xt_ematch_foreach(ematch, e)
277 if (find_syn_match(ematch))
d6b00a53 278 return 0;
8bee4bad 279 pr_info("Only works on TCP SYN packets\n");
d6b00a53 280 return -EINVAL;
cdd289a2
PM
281}
282
c0cd1156 283#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
135367b8 284static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
cdd289a2 285{
af5d6dc2
JE
286 const struct xt_tcpmss_info *info = par->targinfo;
287 const struct ip6t_entry *e = par->entryinfo;
dcea992a 288 const struct xt_entry_match *ematch;
cdd289a2
PM
289
290 if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
af5d6dc2 291 (par->hook_mask & ~((1 << NF_INET_FORWARD) |
6e23ae2a
PM
292 (1 << NF_INET_LOCAL_OUT) |
293 (1 << NF_INET_POST_ROUTING))) != 0) {
8bee4bad
JE
294 pr_info("path-MTU clamping only supported in "
295 "FORWARD, OUTPUT and POSTROUTING hooks\n");
d6b00a53 296 return -EINVAL;
cdd289a2 297 }
dcea992a
JE
298 xt_ematch_foreach(ematch, e)
299 if (find_syn_match(ematch))
d6b00a53 300 return 0;
8bee4bad 301 pr_info("Only works on TCP SYN packets\n");
d6b00a53 302 return -EINVAL;
cdd289a2
PM
303}
304#endif
305
d3c5ee6d 306static struct xt_target tcpmss_tg_reg[] __read_mostly = {
cdd289a2 307 {
ee999d8b 308 .family = NFPROTO_IPV4,
cdd289a2 309 .name = "TCPMSS",
d3c5ee6d
JE
310 .checkentry = tcpmss_tg4_check,
311 .target = tcpmss_tg4,
cdd289a2
PM
312 .targetsize = sizeof(struct xt_tcpmss_info),
313 .proto = IPPROTO_TCP,
314 .me = THIS_MODULE,
315 },
c0cd1156 316#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
cdd289a2 317 {
ee999d8b 318 .family = NFPROTO_IPV6,
cdd289a2 319 .name = "TCPMSS",
d3c5ee6d
JE
320 .checkentry = tcpmss_tg6_check,
321 .target = tcpmss_tg6,
cdd289a2
PM
322 .targetsize = sizeof(struct xt_tcpmss_info),
323 .proto = IPPROTO_TCP,
324 .me = THIS_MODULE,
325 },
326#endif
327};
328
d3c5ee6d 329static int __init tcpmss_tg_init(void)
cdd289a2 330{
d3c5ee6d 331 return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
cdd289a2
PM
332}
333
d3c5ee6d 334static void __exit tcpmss_tg_exit(void)
cdd289a2 335{
d3c5ee6d 336 xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
cdd289a2
PM
337}
338
d3c5ee6d
JE
339module_init(tcpmss_tg_init);
340module_exit(tcpmss_tg_exit);