diff options
author | andre <andre@FreeBSD.org> | 2005-08-22 14:12:18 +0000 |
---|---|---|
committer | andre <andre@FreeBSD.org> | 2005-08-22 14:12:18 +0000 |
commit | ef76245e903c6da9b4359edf312f385c9d1ab002 (patch) | |
tree | 6d02cf583643fd60d47a0eb7f6db6ec5bb608d94 /sys/netinet/ip_icmp.c | |
parent | 1afbca0a454d70fc5eb818a4eb3a654cdc571f72 (diff) | |
download | FreeBSD-src-ef76245e903c6da9b4359edf312f385c9d1ab002.zip FreeBSD-src-ef76245e903c6da9b4359edf312f385c9d1ab002.tar.gz |
Always quote the entire TCP header when responding and allocate an mbuf
cluster if needed.
Fixes the TCP issues raised in I-D draft-gont-icmp-payload-00.txt.
This aids in-the-wild debugging a lot and allows the receiver to do
more elaborate checks on the validity of the response.
MFC after: 2 weeks
Sponsored by: TCP/IP Optimization Fundraise 2005
Diffstat (limited to 'sys/netinet/ip_icmp.c')
-rw-r--r-- | sys/netinet/ip_icmp.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index a6d04af..12ff814 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -183,7 +183,7 @@ icmp_error(n, type, code, dest, mtu) /* * First, formulate icmp message */ - m = m_gethdr(M_DONTWAIT, MT_HEADER); + MGETHDR(m, M_DONTWAIT, MT_HEADER); if (m == NULL) goto freeit; #ifdef MAC @@ -193,11 +193,31 @@ icmp_error(n, type, code, dest, mtu) * Calculate length to quote from original packet and * prevent the ICMP mbuf from overflowing. */ - icmplen = min(oiplen + max(8, icmp_quotelen), oip->ip_len); - icmplen = min(icmplen, M_TRAILINGSPACE(m) - - (ICMP_MINLEN + sizeof(struct ip))); + if (oip->ip_p == IPPROTO_TCP) { + struct tcphdr *th; + int tcphlen; + + if (n->m_len < oiplen + sizeof(struct tcphdr) && + ((n = m_pullup(n, oiplen + sizeof(struct tcphdr))) == NULL)) + goto freeit; + th = (struct tcphdr *)((caddr_t)oip + oiplen); + tcphlen = th->th_off << 2; + if (tcphlen < sizeof(struct tcphdr)) + goto freeit; + if (oip->ip_len < oiplen + tcphlen) + goto freeit; + if (n->m_len < oiplen + tcphlen && + ((n = m_pullup(n, oiplen + tcphlen)) == NULL)) + goto freeit; + icmplen = max(oiplen + tcphlen, min(icmp_quotelen, oip->ip_len)); + } else + icmplen = min(oiplen + max(8, icmp_quotelen), oip->ip_len); if (icmplen < sizeof(struct ip)) panic("icmp_error: bad length"); + if (icmplen + ICMP_MINLEN + sizeof(struct ip) > MHLEN) + MCLGET(m, M_DONTWAIT); + if (!(m->m_flags & M_EXT)) + goto freeit; m->m_len = icmplen + ICMP_MINLEN; MH_ALIGN(m, m->m_len); icp = mtod(m, struct icmp *); |