summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
authormarkus <markus@openbsd.org>2007-06-15 18:23:06 +0000
committermarkus <markus@openbsd.org>2007-06-15 18:23:06 +0000
commit16193b2ba7bc3e2cbde4514c36576e5ba91dccb4 (patch)
tree20189f285844778846aabcbd6a91edf14522d5ef /sys/netinet/tcp_input.c
parentIn power_match(), make sure oa_irq is correctly initialized. (diff)
downloadwireguard-openbsd-16193b2ba7bc3e2cbde4514c36576e5ba91dccb4.tar.xz
wireguard-openbsd-16193b2ba7bc3e2cbde4514c36576e5ba91dccb4.zip
Drop the current random timestamps and the current ISN generation
code and replace both with a RFC1948 based method, so TCP clients now have monotonic ISN/timestamps. The server side uses completely random ISN/timestamps and does time-wait recycling (on port reuse). ok djm@, mcbride@; thanks to lots of testers
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 32a322220bc..b2a9a3bb20a 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.206 2007/06/11 11:29:35 henning Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.207 2007/06/15 18:23:06 markus Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -378,7 +378,7 @@ tcp_input(struct mbuf *m, ...)
int todrop, acked, ourfinisacked, needoutput = 0;
int hdroptlen = 0;
short ostate = 0;
- int iss = 0;
+ tcp_seq iss, *reuse = NULL;
u_long tiwin;
struct tcp_opt_info opti;
int iphlen;
@@ -846,7 +846,7 @@ findpcb:
*/
if (so->so_qlen <= so->so_qlimit &&
syn_cache_add(&src.sa, &dst.sa, th, iphlen,
- so, m, optp, optlen, &opti))
+ so, m, optp, optlen, &opti, reuse))
m = NULL;
}
goto drop;
@@ -1268,6 +1268,28 @@ trimthenstep6:
tp->snd_wl1 = th->th_seq - 1;
tp->rcv_up = th->th_seq;
goto step6;
+ /*
+ * If a new connection request is received while in TIME_WAIT,
+ * drop the old connection and start over if the if the
+ * timestamp or the sequence numbers are above the previous
+ * ones.
+ */
+ case TCPS_TIME_WAIT:
+ if (((tiflags & (TH_SYN|TH_ACK)) == TH_SYN) &&
+ ((opti.ts_present &&
+ TSTMP_LT(tp->ts_recent, opti.ts_val)) ||
+ SEQ_GT(th->th_seq, tp->rcv_nxt))) {
+ /*
+ * Advance the iss by at least 32768, but
+ * clear the msb in order to make sure
+ * that SEG_LT(snd_nxt, iss).
+ */
+ iss = tp->snd_nxt +
+ ((arc4random() & 0x7fffffff) | 0x8000);
+ reuse = &iss;
+ tp = tcp_close(tp);
+ goto findpcb;
+ }
}
/*
@@ -1367,19 +1389,6 @@ trimthenstep6:
if (todrop >= tlen) {
tcpstat.tcps_rcvbyteafterwin += tlen;
/*
- * If a new connection request is received
- * while in TIME_WAIT, drop the old connection
- * and start over if the sequence numbers
- * are above the previous ones.
- */
- if (tiflags & TH_SYN &&
- tp->t_state == TCPS_TIME_WAIT &&
- SEQ_GT(th->th_seq, tp->rcv_nxt)) {
- iss = tp->snd_nxt + TCP_ISSINCR;
- tp = tcp_close(tp);
- goto findpcb;
- }
- /*
* If window is closed can only take segments at
* window edge, and have to drop data and PUSH from
* incoming segments. Continue processing, but
@@ -3950,7 +3959,7 @@ syn_cache_unreach(src, dst, th)
*/
int
-syn_cache_add(src, dst, th, iphlen, so, m, optp, optlen, oi)
+syn_cache_add(src, dst, th, iphlen, so, m, optp, optlen, oi, issp)
struct sockaddr *src;
struct sockaddr *dst;
struct tcphdr *th;
@@ -3960,6 +3969,7 @@ syn_cache_add(src, dst, th, iphlen, so, m, optp, optlen, oi)
u_char *optp;
int optlen;
struct tcp_opt_info *oi;
+ tcp_seq *issp;
{
struct tcpcb tb, *tp;
long win;
@@ -4062,7 +4072,7 @@ syn_cache_add(src, dst, th, iphlen, so, m, optp, optlen, oi)
tcp_iss += TCP_ISSINCR/2;
sc->sc_iss = tcp_iss;
#else
- sc->sc_iss = tcp_rndiss_next();
+ sc->sc_iss = issp ? *issp : arc4random();
#endif
sc->sc_peermaxseg = oi->maxseg;
sc->sc_ourmaxseg = tcp_mss_adv(m->m_flags & M_PKTHDR ?