diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2007-06-15 18:23:08 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2007-06-15 18:23:08 +0000 |
commit | f436c78cb6491d8683072efdb5f8859e0f47fbc2 (patch) | |
tree | 047d89a7652636c7822d9e6028689289e70bcbf7 /sys/netinet | |
parent | 0bc06951a0d06a0401b4b4079f71d9299e8449b5 (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.c | 46 | ||||
-rw-r--r-- | sys/netinet/tcp_seq.h | 3 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 78 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.c | 4 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 6 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 6 |
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 *, |