summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2007-06-15 18:23:08 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2007-06-15 18:23:08 +0000
commitf436c78cb6491d8683072efdb5f8859e0f47fbc2 (patch)
tree047d89a7652636c7822d9e6028689289e70bcbf7 /sys/netinet
parent0bc06951a0d06a0401b4b4079f71d9299e8449b5 (diff)
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')
-rw-r--r--sys/netinet/tcp_input.c46
-rw-r--r--sys/netinet/tcp_seq.h3
-rw-r--r--sys/netinet/tcp_subr.c78
-rw-r--r--sys/netinet/tcp_timer.c4
-rw-r--r--sys/netinet/tcp_usrreq.c6
-rw-r--r--sys/netinet/tcp_var.h6
6 files changed, 111 insertions, 32 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 ?
diff --git a/sys/netinet/tcp_seq.h b/sys/netinet/tcp_seq.h
index 95d97d45c21..70ab75ff9a5 100644
--- a/sys/netinet/tcp_seq.h
+++ b/sys/netinet/tcp_seq.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_seq.h,v 1.5 2003/06/02 23:28:14 millert Exp $ */
+/* $OpenBSD: tcp_seq.h,v 1.6 2007/06/15 18:23:06 markus Exp $ */
/* $NetBSD: tcp_seq.h,v 1.6 1995/03/26 20:32:35 jtc Exp $ */
/*
@@ -58,6 +58,7 @@
(tp)->iss
#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */
+#define TCP_ISSINCR2 (1*1024*1024) /* increment for tcp_iss each second */
#ifdef _KERNEL
extern tcp_seq tcp_iss; /* tcp initial send seq # */
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 013efcdf795..38dfeea0a56 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_subr.c,v 1.96 2007/06/01 00:52:38 henning Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.97 2007/06/15 18:23:06 markus Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
@@ -99,9 +99,7 @@
#include <netinet6/ip6protosw.h>
#endif /* INET6 */
-#ifdef TCP_SIGNATURE
#include <crypto/md5.h>
-#endif /* TCP_SIGNATURE */
/* patchable/settable parameters for tcp */
int tcp_mssdflt = TCP_MSS;
@@ -149,9 +147,7 @@ struct pool sackhl_pool;
#endif
struct tcpstat tcpstat; /* tcp statistics */
-#ifdef TCP_COMPAT_42
tcp_seq tcp_iss;
-#endif
/*
* Tcp initialization
@@ -159,9 +155,7 @@ tcp_seq tcp_iss;
void
tcp_init()
{
-#ifdef TCP_COMPAT_42
tcp_iss = 1; /* wrong */
-#endif /* TCP_COMPAT_42 */
pool_init(&tcpcb_pool, sizeof(struct tcpcb), 0, 0, 0, "tcpcbpl",
NULL);
pool_init(&tcpqe_pool, sizeof(struct tcpqent), 0, 0, 0, "tcpqepl",
@@ -1016,6 +1010,76 @@ tcp_mtudisc_increase(inp, errno)
}
}
+#define TCP_ISS_CONN_INC 4096
+int tcp_iss_init;
+static u_char tcp_iss_secret[128];
+MD5_CTX tcp_iss_ctx;
+
+void
+tcp_set_iss(struct tcpcb *tp)
+{
+ MD5_CTX ctx;
+ tcp_seq digest[4];
+
+ if (tcp_iss_init == 0) {
+ arc4random_bytes(tcp_iss_secret, sizeof(tcp_iss_secret));
+ MD5Init(&tcp_iss_ctx);
+ MD5Update(&tcp_iss_ctx, tcp_iss_secret, sizeof(tcp_iss_secret));
+ tcp_iss_init = 1;
+ }
+ ctx = tcp_iss_ctx;
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_lport, sizeof(u_short));
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_fport, sizeof(u_short));
+ if (tp->pf == AF_INET6) {
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_laddr6,
+ sizeof(struct in6_addr));
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_faddr6,
+ sizeof(struct in6_addr));
+ } else {
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_laddr,
+ sizeof(struct in_addr));
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_faddr,
+ sizeof(struct in_addr));
+ }
+ MD5Final((u_char *)digest, &ctx);
+ tcp_iss += TCP_ISS_CONN_INC;
+ tp->iss = digest[0] + tcp_iss;
+}
+
+int tcp_tsm_init;
+static u_char tcp_tsm_secret[128];
+MD5_CTX tcp_tsm_ctx;
+
+void
+tcp_set_tsm(struct tcpcb *tp)
+{
+ MD5_CTX ctx;
+ u_int32_t digest[4];
+
+ if (tcp_tsm_init == 0) {
+ arc4random_bytes(tcp_tsm_secret, sizeof(tcp_tsm_secret));
+ MD5Init(&tcp_tsm_ctx);
+ MD5Update(&tcp_tsm_ctx, tcp_tsm_secret, sizeof(tcp_tsm_secret));
+ tcp_tsm_init = 1;
+ }
+ ctx = tcp_tsm_ctx;
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_lport, sizeof(u_short));
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_fport, sizeof(u_short));
+ if (tp->pf == AF_INET6) {
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_laddr6,
+ sizeof(struct in6_addr));
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_faddr6,
+ sizeof(struct in6_addr));
+ } else {
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_laddr,
+ sizeof(struct in_addr));
+ MD5Update(&ctx, (char *)&tp->t_inpcb->inp_faddr,
+ sizeof(struct in_addr));
+ }
+ MD5Final((u_char *)digest, &ctx);
+ tp->ts_modulate = digest[0];
+}
+
#ifdef TCP_SIGNATURE
int
tcp_signature_tdb_attach()
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 7265e503970..e3add336a5a 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_timer.c,v 1.38 2005/11/15 21:09:46 miod Exp $ */
+/* $OpenBSD: tcp_timer.c,v 1.39 2007/06/15 18:23:07 markus Exp $ */
/* $NetBSD: tcp_timer.c,v 1.14 1996/02/13 23:44:09 christos Exp $ */
/*
@@ -138,6 +138,8 @@ tcp_slowtimo()
tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */
if ((int)tcp_iss < 0)
tcp_iss = 0; /* XXX */
+#else
+ tcp_iss += TCP_ISSINCR2/PR_SLOWHZ; /* increment iss */
#endif /* TCP_COMPAT_42 */
tcp_now++; /* for timestamps */
splx(s);
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 0fef0fbebbe..ed1f701976e 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_usrreq.c,v 1.89 2005/03/04 13:21:42 markus Exp $ */
+/* $OpenBSD: tcp_usrreq.c,v 1.90 2007/06/15 18:23:07 markus Exp $ */
/* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
/*
@@ -324,7 +324,7 @@ tcp_usrreq(so, req, m, nam, control)
/* initialise the timestamp modulator */
if (tp->t_flags & TF_REQ_TSTMP)
- tp->ts_modulate = arc4random();
+ tcp_set_tsm(tp);
/* Compute window scaling to request. */
tcp_rscale(tp, so->so_rcv.sb_hiwat);
@@ -337,7 +337,7 @@ tcp_usrreq(so, req, m, nam, control)
tp->iss = tcp_iss;
tcp_iss += TCP_ISSINCR/2;
#else /* TCP_COMPAT_42 */
- tp->iss = tcp_rndiss_next();
+ tcp_set_iss(tp);
#endif /* !TCP_COMPAT_42 */
tcp_sendseqinit(tp);
#if defined(TCP_SACK)
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index d639001a425..755690d44e0 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_var.h,v 1.81 2007/02/01 19:55:37 jmc Exp $ */
+/* $OpenBSD: tcp_var.h,v 1.82 2007/06/15 18:23:07 markus Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@@ -657,10 +657,12 @@ void tcp_rndiss_init(void);
tcp_seq tcp_rndiss_next(void);
u_int16_t
tcp_rndiss_encrypt(u_int16_t);
+void tcp_set_iss(struct tcpcb *);
+void tcp_set_tsm(struct tcpcb *);
int syn_cache_add(struct sockaddr *, struct sockaddr *,
struct tcphdr *, unsigned int, struct socket *,
- struct mbuf *, u_char *, int, struct tcp_opt_info *);
+ struct mbuf *, u_char *, int, struct tcp_opt_info *, tcp_seq *);
void syn_cache_unreach(struct sockaddr *, struct sockaddr *,
struct tcphdr *);
struct socket *syn_cache_get(struct sockaddr *, struct sockaddr *,