|
@@ -52,7 +52,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|
|
{
|
|
|
const struct xt_tcpmss_info *info = par->targinfo;
|
|
|
struct tcphdr *tcph;
|
|
|
- unsigned int tcplen, i;
|
|
|
+ int len, tcp_hdrlen;
|
|
|
+ unsigned int i;
|
|
|
__be16 oldval;
|
|
|
u16 newmss;
|
|
|
u8 *opt;
|
|
@@ -64,11 +65,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|
|
if (!skb_make_writable(skb, skb->len))
|
|
|
return -1;
|
|
|
|
|
|
- tcplen = skb->len - tcphoff;
|
|
|
+ len = skb->len - tcphoff;
|
|
|
+ if (len < (int)sizeof(struct tcphdr))
|
|
|
+ return -1;
|
|
|
+
|
|
|
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
|
|
|
+ tcp_hdrlen = tcph->doff * 4;
|
|
|
|
|
|
- /* Header cannot be larger than the packet */
|
|
|
- if (tcplen < tcph->doff*4)
|
|
|
+ if (len < tcp_hdrlen)
|
|
|
return -1;
|
|
|
|
|
|
if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
|
|
@@ -87,9 +91,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|
|
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) {
|
|
|
+ for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
|
|
|
+ if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
|
|
|
u_int16_t oldmss;
|
|
|
|
|
|
oldmss = (opt[i+2] << 8) | opt[i+3];
|
|
@@ -112,9 +115,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|
|
}
|
|
|
|
|
|
/* There is data after the header so the option can't be added
|
|
|
- without moving it, and doing so may make the SYN packet
|
|
|
- itself too large. Accept the packet unmodified instead. */
|
|
|
- if (tcplen > tcph->doff*4)
|
|
|
+ * without moving it, and doing so may make the SYN packet
|
|
|
+ * itself too large. Accept the packet unmodified instead.
|
|
|
+ */
|
|
|
+ if (len > tcp_hdrlen)
|
|
|
return 0;
|
|
|
|
|
|
/*
|
|
@@ -143,10 +147,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|
|
newmss = min(newmss, (u16)1220);
|
|
|
|
|
|
opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
|
|
|
- memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
|
|
|
+ memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));
|
|
|
|
|
|
inet_proto_csum_replace2(&tcph->check, skb,
|
|
|
- htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
|
|
|
+ htons(len), htons(len + TCPOLEN_MSS), 1);
|
|
|
opt[0] = TCPOPT_MSS;
|
|
|
opt[1] = TCPOLEN_MSS;
|
|
|
opt[2] = (newmss & 0xff00) >> 8;
|