diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 6c7ae760b529..036f675d7068 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1110,9 +1110,14 @@ findpcb: tcp_dooptions(tp, optp, optlen, th, &to); if (iss) tp->iss = iss; - else + else { +#ifdef TCP_COMPAT_42 + tcp_iss += TCP_ISSINCR/2; tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR/4; +#else + tp->iss = tcp_rndiss_next(); +#endif /* TCP_COMPAT_42 */ + } tp->irs = th->th_seq; tcp_sendseqinit(tp); tcp_rcvseqinit(tp); @@ -1643,7 +1648,11 @@ trimthenstep6: if (thflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(th->th_seq, tp->rcv_nxt)) { +#ifdef TCP_COMPAT_42 iss = tp->snd_nxt + TCP_ISSINCR; +#else + iss = tcp_rndiss_next(); +#endif /* TCP_COMPAT_42 */ tp = tcp_close(tp); goto findpcb; } diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 6c7ae760b529..036f675d7068 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -1110,9 +1110,14 @@ findpcb: tcp_dooptions(tp, optp, optlen, th, &to); if (iss) tp->iss = iss; - else + else { +#ifdef TCP_COMPAT_42 + tcp_iss += TCP_ISSINCR/2; tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR/4; +#else + tp->iss = tcp_rndiss_next(); +#endif /* TCP_COMPAT_42 */ + } tp->irs = th->th_seq; tcp_sendseqinit(tp); tcp_rcvseqinit(tp); @@ -1643,7 +1648,11 @@ trimthenstep6: if (thflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(th->th_seq, tp->rcv_nxt)) { +#ifdef TCP_COMPAT_42 iss = tp->snd_nxt + TCP_ISSINCR; +#else + iss = tcp_rndiss_next(); +#endif /* TCP_COMPAT_42 */ tp = tcp_close(tp); goto findpcb; } diff --git a/sys/netinet/tcp_seq.h b/sys/netinet/tcp_seq.h index 49b714ac5633..021f7aadf9fd 100644 --- a/sys/netinet/tcp_seq.h +++ b/sys/netinet/tcp_seq.h @@ -81,6 +81,7 @@ #ifdef _KERNEL extern tcp_cc tcp_ccgen; /* global connection count */ +#ifdef TCP_COMPAT_42 /* * Increment for tcp_iss each second. * This is designed to increment at the standard 250 KB/s, @@ -96,6 +97,7 @@ extern tcp_cc tcp_ccgen; /* global connection count */ #define TCP_ISSINCR (122*1024 + tcp_random18()) extern tcp_seq tcp_iss; /* tcp initial send seq # */ +#endif /* TCP_COMPAT_42 */ #else #define TCP_ISSINCR (250*1024) /* increment for tcp_iss each second */ #endif /* _KERNEL */ diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 2afff532c449..64f4c06b51d5 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -181,7 +182,9 @@ tcp_init() { int hashsize; - tcp_iss = arc4random(); /* wrong, but better than a constant */ +#ifdef TCP_COMPAT_42 + tcp_iss = 1; /* wrong */ +#endif /* TCP_COMPAT_42 */ tcp_ccgen = 1; tcp_cleartaocache(); @@ -1100,6 +1103,63 @@ tcp6_ctlinput(cmd, sa, d) } #endif /* INET6 */ +#define TCP_RNDISS_ROUNDS 16 +#define TCP_RNDISS_OUT 7200 +#define TCP_RNDISS_MAX 30000 + +u_int8_t tcp_rndiss_sbox[128]; +u_int16_t tcp_rndiss_msb; +u_int16_t tcp_rndiss_cnt; +long tcp_rndiss_reseed; + +u_int16_t +tcp_rndiss_encrypt(val) + u_int16_t val; +{ + u_int16_t sum = 0, i; + + for (i = 0; i < TCP_RNDISS_ROUNDS; i++) { + sum += 0x79b9; + val ^= ((u_int16_t)tcp_rndiss_sbox[(val^sum) & 0x7f]) << 7; + val = ((val & 0xff) << 7) | (val >> 8); + } + + return val; +} + +void +tcp_rndiss_init() +{ + struct timeval time; + + getmicrotime(&time); + read_random(tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox)); + + tcp_rndiss_reseed = time.tv_sec + TCP_RNDISS_OUT; + tcp_rndiss_msb = tcp_rndiss_msb == 0x8000 ? 0 : 0x8000; + tcp_rndiss_cnt = 0; +} + +tcp_seq +tcp_rndiss_next() +{ + u_int16_t tmp; + struct timeval time; + + getmicrotime(&time); + + if (tcp_rndiss_cnt >= TCP_RNDISS_MAX || + time.tv_sec > tcp_rndiss_reseed) + tcp_rndiss_init(); + + read_random(&tmp, sizeof(tmp)); + + /* (tmp & 0x7fff) ensures a 32768 byte gap between ISS */ + return ((tcp_rndiss_encrypt(tcp_rndiss_cnt++) | tcp_rndiss_msb) <<16) | + (tmp & 0x7fff); +} + + /* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 094729593543..2013c2305f10 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -132,8 +132,8 @@ tcp_slowtimo() tcp_maxidle = tcp_keepcnt * tcp_keepintvl; - tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ #ifdef TCP_COMPAT_42 + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ if ((int)tcp_iss < 0) tcp_iss = TCP_ISSINCR; /* XXX */ #endif diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 2afff532c449..64f4c06b51d5 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -181,7 +182,9 @@ tcp_init() { int hashsize; - tcp_iss = arc4random(); /* wrong, but better than a constant */ +#ifdef TCP_COMPAT_42 + tcp_iss = 1; /* wrong */ +#endif /* TCP_COMPAT_42 */ tcp_ccgen = 1; tcp_cleartaocache(); @@ -1100,6 +1103,63 @@ tcp6_ctlinput(cmd, sa, d) } #endif /* INET6 */ +#define TCP_RNDISS_ROUNDS 16 +#define TCP_RNDISS_OUT 7200 +#define TCP_RNDISS_MAX 30000 + +u_int8_t tcp_rndiss_sbox[128]; +u_int16_t tcp_rndiss_msb; +u_int16_t tcp_rndiss_cnt; +long tcp_rndiss_reseed; + +u_int16_t +tcp_rndiss_encrypt(val) + u_int16_t val; +{ + u_int16_t sum = 0, i; + + for (i = 0; i < TCP_RNDISS_ROUNDS; i++) { + sum += 0x79b9; + val ^= ((u_int16_t)tcp_rndiss_sbox[(val^sum) & 0x7f]) << 7; + val = ((val & 0xff) << 7) | (val >> 8); + } + + return val; +} + +void +tcp_rndiss_init() +{ + struct timeval time; + + getmicrotime(&time); + read_random(tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox)); + + tcp_rndiss_reseed = time.tv_sec + TCP_RNDISS_OUT; + tcp_rndiss_msb = tcp_rndiss_msb == 0x8000 ? 0 : 0x8000; + tcp_rndiss_cnt = 0; +} + +tcp_seq +tcp_rndiss_next() +{ + u_int16_t tmp; + struct timeval time; + + getmicrotime(&time); + + if (tcp_rndiss_cnt >= TCP_RNDISS_MAX || + time.tv_sec > tcp_rndiss_reseed) + tcp_rndiss_init(); + + read_random(&tmp, sizeof(tmp)); + + /* (tmp & 0x7fff) ensures a 32768 byte gap between ISS */ + return ((tcp_rndiss_encrypt(tcp_rndiss_cnt++) | tcp_rndiss_msb) <<16) | + (tmp & 0x7fff); +} + + /* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index ecd84a92479e..07e1b9021fa8 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -761,7 +761,12 @@ tcp_connect(tp, nam, p) tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp); - tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; +#ifdef TCP_COMPAT_42 + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; +#else /* TCP_COMPAT_42 */ + tp->iss = tcp_rndiss_next(); +#endif /* !TCP_COMPAT_42 */ tcp_sendseqinit(tp); /* @@ -853,7 +858,11 @@ tcp6_connect(tp, nam, p) tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp); +#ifdef TCP_COMPAT_42 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; +#else + tp->iss = tcp_rndiss_next(); +#endif /* TCP_COMPAT_42 */ tcp_sendseqinit(tp); /* diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index e361caf57756..ecac45120e00 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -409,6 +409,10 @@ void tcp_trace __P((int, int, struct tcpcb *, void *, struct tcphdr *, extern struct pr_usrreqs tcp_usrreqs; extern u_long tcp_sendspace; extern u_long tcp_recvspace; +void tcp_rndiss_init __P((void)); +tcp_seq tcp_rndiss_next __P((void)); +u_int16_t + tcp_rndiss_encrypt __P((u_int16_t)); #endif /* _KERNEL */