1cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy/* 2cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * This is a module which is used for setting the MSS option in TCP packets. 3cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * 4cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca> 5f229f6ce481ceb33a966311722b8ef0cb6c25de7Patrick McHardy * Copyright (C) 2007 Patrick McHardy <kaber@trash.net> 6cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * 7cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * This program is free software; you can redistribute it and/or modify 8cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * it under the terms of the GNU General Public License version 2 as 9cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * published by the Free Software Foundation. 10cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy */ 118bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/module.h> 13cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/skbuff.h> 14cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/ip.h> 155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 16cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/ipv6.h> 17cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/tcp.h> 1837c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt#include <net/dst.h> 1937c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt#include <net/flow.h> 20cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <net/ipv6.h> 2137c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt#include <net/route.h> 22cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <net/tcp.h> 23cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 24cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/netfilter_ipv4/ip_tables.h> 25cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/netfilter_ipv6/ip6_tables.h> 26cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/netfilter/x_tables.h> 27cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/netfilter/xt_tcpudp.h> 28cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#include <linux/netfilter/xt_TCPMSS.h> 29cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 30cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardyMODULE_LICENSE("GPL"); 31cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardyMODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); 322ae15b64e6a1608c840c60df38e8e5eef7b2b8c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment"); 33cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardyMODULE_ALIAS("ipt_TCPMSS"); 34cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardyMODULE_ALIAS("ip6t_TCPMSS"); 35cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 36cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardystatic inline unsigned int 37cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardyoptlen(const u_int8_t *opt, unsigned int offset) 38cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 39cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy /* Beware zero-length options: make finite progress */ 40cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) 41cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return 1; 42cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy else 43cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return opt[offset+1]; 44cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 45cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 46cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardystatic int 473db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xutcpmss_mangle_packet(struct sk_buff *skb, 4870d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester const struct xt_action_param *par, 4937c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt unsigned int in_mtu, 50cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy unsigned int tcphoff, 51cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy unsigned int minlen) 52cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 5370d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester const struct xt_tcpmss_info *info = par->targinfo; 54cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy struct tcphdr *tcph; 55cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy unsigned int tcplen, i; 56cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy __be16 oldval; 57cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy u16 newmss; 58cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy u8 *opt; 59cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 60b396966c4688522863572927cb30aa874b3ec504Phil Oester /* This is a fragment, no TCP header is available */ 61b396966c4688522863572927cb30aa874b3ec504Phil Oester if (par->fragoff != 0) 62b396966c4688522863572927cb30aa874b3ec504Phil Oester return XT_CONTINUE; 63b396966c4688522863572927cb30aa874b3ec504Phil Oester 643db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu if (!skb_make_writable(skb, skb->len)) 65cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return -1; 66cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 673db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu tcplen = skb->len - tcphoff; 683db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); 69cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 7010a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott /* Header cannot be larger than the packet */ 7110a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott if (tcplen < tcph->doff*4) 72cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return -1; 73cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 74cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (info->mss == XT_TCPMSS_CLAMP_PMTU) { 75adf30907d63893e4208dfe3f5c88ae12bc2f25d5Eric Dumazet if (dst_mtu(skb_dst(skb)) <= minlen) { 76e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches net_err_ratelimited("unknown or invalid path-MTU (%u)\n", 77e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches dst_mtu(skb_dst(skb))); 78cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return -1; 79cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 8037c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt if (in_mtu <= minlen) { 81e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches net_err_ratelimited("unknown or invalid path-MTU (%u)\n", 82e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches in_mtu); 8337c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt return -1; 8437c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt } 85adf30907d63893e4208dfe3f5c88ae12bc2f25d5Eric Dumazet newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; 86cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } else 87cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy newmss = info->mss; 88cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 89cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt = (u_int8_t *)tcph; 90cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { 91cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && 92cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt[i+1] == TCPOLEN_MSS) { 93cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy u_int16_t oldmss; 94cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 95cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy oldmss = (opt[i+2] << 8) | opt[i+3]; 96cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 97170080645dac61816455afad807ffeb326ce79e8Benjamin LaHaise /* Never increase MSS, even when setting it, as 98170080645dac61816455afad807ffeb326ce79e8Benjamin LaHaise * doing so results in problems for hosts that rely 99170080645dac61816455afad807ffeb326ce79e8Benjamin LaHaise * on MSS being set correctly. 100170080645dac61816455afad807ffeb326ce79e8Benjamin LaHaise */ 101170080645dac61816455afad807ffeb326ce79e8Benjamin LaHaise if (oldmss <= newmss) 102cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return 0; 103cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 104cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt[i+2] = (newmss & 0xff00) >> 8; 1057c4e36bc172ae1accde835b880fdc4a2c2a3df57Jan Engelhardt opt[i+3] = newmss & 0x00ff; 106cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 107be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy inet_proto_csum_replace2(&tcph->check, skb, 108be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy htons(oldmss), htons(newmss), 109be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy 0); 110cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return 0; 111cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 112cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 113cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 11410a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott /* There is data after the header so the option can't be added 11510a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott without moving it, and doing so may make the SYN packet 11610a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott itself too large. Accept the packet unmodified instead. */ 11710a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott if (tcplen > tcph->doff*4) 11810a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott return 0; 11910a199394b8f9b4c4e0be6e14a61109a7d891b1bSimon Arlott 120cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy /* 121cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy * MSS Option not found ?! add it.. 122cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy */ 1233db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu if (skb_tailroom(skb) < TCPOLEN_MSS) { 1243db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu if (pskb_expand_head(skb, 0, 1253db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu TCPOLEN_MSS - skb_tailroom(skb), 1262ca7b0ac022aa0158599178fe1056b1ba9ec8b97Herbert Xu GFP_ATOMIC)) 127cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return -1; 1283db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); 129cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 130cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 1313db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu skb_put(skb, TCPOLEN_MSS); 132cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 13370d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester /* 13470d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester * IPv4: RFC 1122 states "If an MSS option is not received at 13570d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester * connection setup, TCP MUST assume a default send MSS of 536". 13670d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum 13770d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester * length IPv6 header of 60, ergo the default MSS value is 1220 13870d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester * Since no MSS was provided, we must use the default values 139409b545ac10d9548929557a75ad86540f59a2c83Phil Oester */ 14070d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester if (par->family == NFPROTO_IPV4) 14170d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester newmss = min(newmss, (u16)536); 14270d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester else 14370d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester newmss = min(newmss, (u16)1220); 144409b545ac10d9548929557a75ad86540f59a2c83Phil Oester 145cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt = (u_int8_t *)tcph + sizeof(struct tcphdr); 146cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); 147cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 148be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy inet_proto_csum_replace2(&tcph->check, skb, 149be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); 150cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt[0] = TCPOPT_MSS; 151cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt[1] = TCPOLEN_MSS; 152cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy opt[2] = (newmss & 0xff00) >> 8; 1537c4e36bc172ae1accde835b880fdc4a2c2a3df57Jan Engelhardt opt[3] = newmss & 0x00ff; 154cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 155be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0); 156cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 157cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy oldval = ((__be16 *)tcph)[6]; 158cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy tcph->doff += TCPOLEN_MSS/4; 159be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy inet_proto_csum_replace2(&tcph->check, skb, 160be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy oldval, ((__be16 *)tcph)[6], 0); 161cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return TCPOLEN_MSS; 162cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 163cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 164db1a75bdcc1766dc7e1fae9201ae287dcbcb6c66Jan Engelhardtstatic u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb, 165db1a75bdcc1766dc7e1fae9201ae287dcbcb6c66Jan Engelhardt unsigned int family) 16637c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt{ 167a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller struct flowi fl; 16837c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt const struct nf_afinfo *ai; 16937c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt struct rtable *rt = NULL; 17037c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt u_int32_t mtu = ~0U; 17137c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt 172a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller if (family == PF_INET) { 173a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller struct flowi4 *fl4 = &fl.u.ip4; 174a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller memset(fl4, 0, sizeof(*fl4)); 175a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller fl4->daddr = ip_hdr(skb)->saddr; 176a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller } else { 177a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller struct flowi6 *fl6 = &fl.u.ip6; 178db1a75bdcc1766dc7e1fae9201ae287dcbcb6c66Jan Engelhardt 179a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller memset(fl6, 0, sizeof(*fl6)); 1804e3fd7a06dc20b2d8ec6892233ad2012968fe7b6Alexey Dobriyan fl6->daddr = ipv6_hdr(skb)->saddr; 181a1bbb0e698b4ba18c6356564923bb395bed0e576David S. Miller } 18237c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt rcu_read_lock(); 183db1a75bdcc1766dc7e1fae9201ae287dcbcb6c66Jan Engelhardt ai = nf_get_afinfo(family); 18437c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt if (ai != NULL) 1850fae2e7740aca7e384c5f337f458897e7e337d58Florian Westphal ai->route(&init_net, (struct dst_entry **)&rt, &fl, false); 18637c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt rcu_read_unlock(); 18737c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt 18837c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt if (rt != NULL) { 189d8d1f30b95a635dbd610dcc5eb641aca8f4768cfChangli Gao mtu = dst_mtu(&rt->dst); 190d8d1f30b95a635dbd610dcc5eb641aca8f4768cfChangli Gao dst_release(&rt->dst); 19137c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt } 19237c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt return mtu; 19337c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt} 19437c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt 195cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardystatic unsigned int 1964b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardttcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) 197cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 1983db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu struct iphdr *iph = ip_hdr(skb); 199cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy __be16 newlen; 200cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy int ret; 201cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 20270d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester ret = tcpmss_mangle_packet(skb, par, 203db1a75bdcc1766dc7e1fae9201ae287dcbcb6c66Jan Engelhardt tcpmss_reverse_mtu(skb, PF_INET), 20437c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt iph->ihl * 4, 205cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy sizeof(*iph) + sizeof(struct tcphdr)); 206cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (ret < 0) 207cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return NF_DROP; 208cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (ret > 0) { 2093db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu iph = ip_hdr(skb); 210cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy newlen = htons(ntohs(iph->tot_len) + ret); 211be0ea7d5da3d99140bde7e5cea328eb111731700Patrick McHardy csum_replace2(&iph->check, iph->tot_len, newlen); 212cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy iph->tot_len = newlen; 213cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 214cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return XT_CONTINUE; 215cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 216cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 217c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 218cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardystatic unsigned int 2194b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardttcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par) 220cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 2213db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu struct ipv6hdr *ipv6h = ipv6_hdr(skb); 222cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy u8 nexthdr; 22375f2811c6460ccc59d83c66059943ce9c9f81a18Jesse Gross __be16 frag_off; 224cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy int tcphoff; 225cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy int ret; 226cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 227cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy nexthdr = ipv6h->nexthdr; 22875f2811c6460ccc59d83c66059943ce9c9f81a18Jesse Gross tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off); 2299dc0564e862b1b9a4677dec2c736b12169e03e99Patrick McHardy if (tcphoff < 0) 230cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return NF_DROP; 23170d19f805f8c047fc0a28dec9306b3773971c8d9Phil Oester ret = tcpmss_mangle_packet(skb, par, 232db1a75bdcc1766dc7e1fae9201ae287dcbcb6c66Jan Engelhardt tcpmss_reverse_mtu(skb, PF_INET6), 23337c08387fc31a0fe7a570664c93be4f1c1bc0c94Jan Engelhardt tcphoff, 234cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy sizeof(*ipv6h) + sizeof(struct tcphdr)); 235cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (ret < 0) 236cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return NF_DROP; 237cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (ret > 0) { 2383db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu ipv6h = ipv6_hdr(skb); 239cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret); 240cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 241cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy return XT_CONTINUE; 242cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 243cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#endif 244cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 245cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy/* Must specify -p tcp --syn */ 246e1931b784a8de324abf310fa3b5e3f25d3988233Jan Engelhardtstatic inline bool find_syn_match(const struct xt_entry_match *m) 247cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 248cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data; 249cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 250cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (strcmp(m->u.kernel.match->name, "tcp") == 0 && 251a3433f35a55f7604742cae620c6dc6edfc70db6aChangli Gao tcpinfo->flg_cmp & TCPHDR_SYN && 252cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy !(tcpinfo->invflags & XT_TCP_INV_FLAGS)) 253e1931b784a8de324abf310fa3b5e3f25d3988233Jan Engelhardt return true; 254cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 255e1931b784a8de324abf310fa3b5e3f25d3988233Jan Engelhardt return false; 256cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 257cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 258135367b8f6a18507af6b9a6910a14b5699415309Jan Engelhardtstatic int tcpmss_tg4_check(const struct xt_tgchk_param *par) 259cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 260af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt const struct xt_tcpmss_info *info = par->targinfo; 261af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt const struct ipt_entry *e = par->entryinfo; 262dcea992aca82cb08b4674c4c783e325835408d1eJan Engelhardt const struct xt_entry_match *ematch; 263cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 264cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (info->mss == XT_TCPMSS_CLAMP_PMTU && 265af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt (par->hook_mask & ~((1 << NF_INET_FORWARD) | 2666e23ae2a48750bda407a4a58f52a4865d7308bf5Patrick McHardy (1 << NF_INET_LOCAL_OUT) | 2676e23ae2a48750bda407a4a58f52a4865d7308bf5Patrick McHardy (1 << NF_INET_POST_ROUTING))) != 0) { 2688bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("path-MTU clamping only supported in " 2698bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt "FORWARD, OUTPUT and POSTROUTING hooks\n"); 270d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return -EINVAL; 271cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 272dcea992aca82cb08b4674c4c783e325835408d1eJan Engelhardt xt_ematch_foreach(ematch, e) 273dcea992aca82cb08b4674c4c783e325835408d1eJan Engelhardt if (find_syn_match(ematch)) 274d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return 0; 2758bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("Only works on TCP SYN packets\n"); 276d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return -EINVAL; 277cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 278cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 279c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 280135367b8f6a18507af6b9a6910a14b5699415309Jan Engelhardtstatic int tcpmss_tg6_check(const struct xt_tgchk_param *par) 281cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 282af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt const struct xt_tcpmss_info *info = par->targinfo; 283af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt const struct ip6t_entry *e = par->entryinfo; 284dcea992aca82cb08b4674c4c783e325835408d1eJan Engelhardt const struct xt_entry_match *ematch; 285cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 286cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy if (info->mss == XT_TCPMSS_CLAMP_PMTU && 287af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt (par->hook_mask & ~((1 << NF_INET_FORWARD) | 2886e23ae2a48750bda407a4a58f52a4865d7308bf5Patrick McHardy (1 << NF_INET_LOCAL_OUT) | 2896e23ae2a48750bda407a4a58f52a4865d7308bf5Patrick McHardy (1 << NF_INET_POST_ROUTING))) != 0) { 2908bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("path-MTU clamping only supported in " 2918bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt "FORWARD, OUTPUT and POSTROUTING hooks\n"); 292d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return -EINVAL; 293cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy } 294dcea992aca82cb08b4674c4c783e325835408d1eJan Engelhardt xt_ematch_foreach(ematch, e) 295dcea992aca82cb08b4674c4c783e325835408d1eJan Engelhardt if (find_syn_match(ematch)) 296d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return 0; 2978bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("Only works on TCP SYN packets\n"); 298d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return -EINVAL; 299cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 300cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#endif 301cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 302d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic struct xt_target tcpmss_tg_reg[] __read_mostly = { 303cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy { 304ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt .family = NFPROTO_IPV4, 305cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .name = "TCPMSS", 306d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .checkentry = tcpmss_tg4_check, 307d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .target = tcpmss_tg4, 308cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .targetsize = sizeof(struct xt_tcpmss_info), 309cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .proto = IPPROTO_TCP, 310cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .me = THIS_MODULE, 311cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy }, 312c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 313cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy { 314ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt .family = NFPROTO_IPV6, 315cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .name = "TCPMSS", 316d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .checkentry = tcpmss_tg6_check, 317d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .target = tcpmss_tg6, 318cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .targetsize = sizeof(struct xt_tcpmss_info), 319cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .proto = IPPROTO_TCP, 320cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy .me = THIS_MODULE, 321cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy }, 322cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy#endif 323cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy}; 324cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 325d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic int __init tcpmss_tg_init(void) 326cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 327d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg)); 328cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 329cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 330d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic void __exit tcpmss_tg_exit(void) 331cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy{ 332d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg)); 333cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy} 334cdd289a2f833b93e65b9a09a02c37f47a58140a8Patrick McHardy 335d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_init(tcpmss_tg_init); 336d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_exit(tcpmss_tg_exit); 337