diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2005-06-30 08:51:32 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2005-06-30 08:51:32 +0000 |
commit | d0da6045c3473c63c2c5ebcb604695383312ac92 (patch) | |
tree | 47b24d0d2ccf633ec13c5ec6181e8098952eea3e /sys/netinet/tcp_subr.c | |
parent | 9a113f7cb87a9e2074ec670f5a343663a903c767 (diff) |
implement PMTU checks from
http://www.gont.com.ar/drafts/icmp-attacks-against-tcp.html
i.e. don't act on ICMP-need-frag immediately if adhoc checks on the
advertised mtu fail. the mtu update is delayed until a tcp retransmit
happens. initial patch by Fernando Gont, tested by many.
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r-- | sys/netinet/tcp_subr.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 35964b0bf71..b39678cc7fb 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_subr.c,v 1.89 2005/05/24 00:02:37 fgont Exp $ */ +/* $OpenBSD: tcp_subr.c,v 1.90 2005/06/30 08:51:31 markus Exp $ */ /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */ /* @@ -519,6 +519,10 @@ tcp_newtcpcb(struct inpcb *inp) TCPTV_MIN, TCPTV_REXMTMAX); tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + + tp->t_pmtud_mtu_sent = 0; + tp->t_pmtud_mss_acked = 0; + #ifdef INET6 /* we disallow IPv4 mapped address completely. */ if ((inp->inp_flags & INP_IPV6) == 0) @@ -829,6 +833,7 @@ tcp_ctlinput(cmd, sa, v) struct inpcb *inp; struct in_addr faddr; tcp_seq seq; + u_int mtu; extern int inetctlerrmap[]; void (*notify)(struct inpcb *, int) = tcp_notify; int errno; @@ -866,8 +871,40 @@ tcp_ctlinput(cmd, sa, v) icp = (struct icmp *)((caddr_t)ip - offsetof(struct icmp, icmp_ip)); - /* Calculate new mtu and create corresponding route */ - icmp_mtudisc(icp); + /* + * If the ICMP message advertises a Next-Hop MTU + * equal or larger than the maximum packet size we have + * ever sent, drop the message. + */ + mtu = (u_int)ntohs(icp->icmp_nextmtu); + if (mtu >= tp->t_pmtud_mtu_sent) + return NULL; + if (mtu >= tcp_hdrsz(tp) + tp->t_pmtud_mss_acked) { + /* + * Calculate new MTU, and create corresponding + * route (traditional PMTUD). + */ + tp->t_flags &= ~TF_PMTUD_PEND; + icmp_mtudisc(icp); + } else { + /* + * Record the information got in the ICMP + * message; act on it later. + * If we had already recorded an ICMP message, + * replace the old one only if the new message + * refers to an older TCP segment + */ + if (tp->t_flags & TF_PMTUD_PEND) { + if (SEQ_LT(tp->t_pmtud_th_seq, seq)) + return NULL; + } else + tp->t_flags |= TF_PMTUD_PEND; + tp->t_pmtud_th_seq = seq; + tp->t_pmtud_nextmtu = icp->icmp_nextmtu; + tp->t_pmtud_ip_len = icp->icmp_ip.ip_len; + tp->t_pmtud_ip_hl = icp->icmp_ip.ip_hl; + return NULL; + } } else { /* ignore if we don't have a matching connection */ return NULL; |