iptables -A FORWARD -p tcp-
-tcp-flags SYN,RST SYN -j TCPMSS
--clamp-mss-to-pmtu
這條規則的目的就是改變TCP MSS以适應PMTU(Path
MTU)
iptables -A FORWARD -p tcp
--tcp-flags SYN,RST SYN- j TCPMSS --set-mss
1400
設定MSS為1400
6 核心對于TCP MSS的處理
那麼核心對于TCP
MSS的處理到底在哪邊呢? 主要是在net/netfilter/xt_TCPMSS.c裡面:
static
int
tcpmss_mangle_packet(struct
sk_buff **pskb,
const struct xt_tcpmss_info *info,
unsigned int tcphoff,
unsigned int minlen)
{
struct
tcphdr *tcph;
unsigned
int tcplen, i;
__be16
oldval;
u16
newmss;
u8
*opt;
if
(!skb_make_writable(pskb, (*pskb)->len))
return -1;
tcplen =
(*pskb)->len - tcphoff;
tcph =
(struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
if (tcplen
!= tcph->doff*4) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS:
bad length (%u bytes)\n",
(*pskb)->len);
return -1;
}
if
(info->mss == XT_TCPMSS_CLAMP_PMTU) {
if (dst_mtu((*pskb)->dst)
<= minlen) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS: "
"unknown or invalid path-MTU (%u)\n",
dst_mtu((*pskb)->dst));
return -1;
}
根據目的網卡的MTU進行newMSS的設定
newmss =
dst_mtu((*pskb)->dst) - minlen;
} else
newmss = info->mss;
opt =
(u_int8_t *)tcph;
for (i =
sizeof(struct tcphdr); i <
tcph->doff*4; i += optlen(opt, i)) {
if (opt[i] == TCPOPT_MSS
&& tcph->doff*4 - i
>= TCPOLEN_MSS
&&
opt[i+1]
== TCPOLEN_MSS) {
u_int16_t oldmss;
oldmss =
(opt[i+2] << 8) | opt[i+3];
if (info->mss
== XT_TCPMSS_CLAMP_PMTU &&
oldmss <= newmss)
return
0;
opt[i+2] = (newmss
& 0xff00) >> 8;
opt[i+3] = (newmss
& 0x00ff);
nf_proto_csum_replace2(&tcph->check,
*pskb,
htons(oldmss), htons(newmss),
0);
return 0;
}
}
if
(skb_tailroom((*pskb)) < TCPOLEN_MSS) {
struct sk_buff *newskb;
newskb = skb_copy_expand(*pskb,
skb_headroom(*pskb),
TCPOLEN_MSS, GFP_ATOMIC);
if (!newskb)
return -1;
kfree_skb(*pskb);
*pskb = newskb;
tcph = (struct tcphdr
*)(skb_network_header(*pskb) + tcphoff);
}
skb_put((*pskb), TCPOLEN_MSS);
opt =
(u_int8_t *)tcph + sizeof(struct tcphdr);
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct
tcphdr));
nf_proto_csum_replace2(&tcph->check,
*pskb,
htons(tcplen), htons(tcplen + TCPOLEN_MSS),
1);
opt[0] =
TCPOPT_MSS;
opt[1] =
TCPOLEN_MSS;
設定新的MSS值
opt[2] = (newmss &
0xff00) >> 8;
opt[3] = (newmss &
0x00ff);
nf_proto_csum_replace4(&tcph->check,
*pskb, 0, *((__be32 *)opt), 0);
oldval =
((__be16 *)tcph)[6];
tcph->doff += TCPOLEN_MSS/4;
nf_proto_csum_replace2(&tcph->check,
*pskb,
oldval,
((__be16 *)tcph)[6], 0);
return
TCPOLEN_MSS;
}