On Wed, 27 Jun 2001, Jonathan Lemon wrote:

> I don't object; while the security provided by the new scheme is nice,
> breaking TIME_WAIT assassination is a serious bug in some environments,
> and there should be a way to work around it now.
> --
> Jonathan

Ok, attached is a patch for 4.3-stable which makes the generation scheme
sysctl selectable.  You use the sysctl net.inet.tcp.tcp_seq_genscheme to
set which scheme you want.  0 is the old random positive increments
scheme, 1 is the more random OpenBSD scheme.  1 is the default setting, so
those encountering the TIME_WAIT problem will have to put something in a
boot script to set the variable to 0.

There's one slight difference in this implementation of the old scheme
versus the old implementation of it.  Before, we used TCP_ISSINCR/2 for
outgoing incrementations, and /4 for incoming.  We use /2 in both cases
now, for simplicity's sake.

Please review, especially if you're experiencing the TIME_WAIT problem.

Thanks,

Mike "Silby" Silbersack
diff -u -r netinet.old/tcp_input.c netinet/tcp_input.c
--- netinet.old/tcp_input.c     Sun Jul  1 20:44:50 2001
+++ netinet/tcp_input.c Sun Jul  1 21:17:58 2001
@@ -1080,7 +1080,7 @@
                if (iss)
                        tp->iss = iss;
                else {
-                       tp->iss = tcp_rndiss_next();
+                       tp->iss = tcp_new_isn();
                }
                tp->irs = th->th_seq;
                tcp_sendseqinit(tp);
@@ -1612,7 +1612,7 @@
                        if (thflags & TH_SYN &&
                            tp->t_state == TCPS_TIME_WAIT &&
                            SEQ_GT(th->th_seq, tp->rcv_nxt)) {
-                               iss = tcp_rndiss_next();
+                               iss = tcp_new_isn();
                                tp = tcp_close(tp);
                                goto findpcb;
                        }
diff -u -r netinet.old/tcp_seq.h netinet/tcp_seq.h
--- netinet.old/tcp_seq.h       Sun Jul  1 20:44:50 2001
+++ netinet/tcp_seq.h   Sun Jul  1 21:08:02 2001
@@ -81,6 +81,24 @@
 #ifdef _KERNEL
 extern tcp_cc  tcp_ccgen;              /* global connection count */
 
+/*
+ * Increment for tcp_iss each second.
+ * This is designed to increment at the standard 250 KB/s,
+ * but with a random component averaging 128 KB.
+ * We also increment tcp_iss by a quarter of this amount
+ * each time we use the value for a new connection.
+ * If defined, the tcp_random18() macro should produce a
+ * number in the range [0-0x3ffff] that is hard to predict.
+ * 
+ * The variable tcp_iss and tcp_random18() are only used
+ * by sequence number generation scheme 0.
+ */
+#ifndef tcp_random18
+#define        tcp_random18()  (arc4random() & 0x3ffff)
+#endif
+#define        TCP_ISSINCR     (122*1024 + tcp_random18())
+
+extern tcp_seq tcp_iss;
 #else
 #define        TCP_ISSINCR     (250*1024)      /* increment for tcp_iss each second 
*/
 #endif /* _KERNEL */
diff -u -r netinet.old/tcp_subr.c netinet/tcp_subr.c
--- netinet.old/tcp_subr.c      Sun Jul  1 20:44:50 2001
+++ netinet/tcp_subr.c  Sun Jul  1 21:35:14 2001
@@ -139,6 +139,10 @@
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_may_rst, CTLFLAG_RW, &icmp_may_rst, 0, 
     "Certain ICMP unreachable messages may abort connections in SYN_SENT");
 
+static int     tcp_seq_genscheme = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_seq_genscheme, CTLFLAG_RW,
+    &tcp_seq_genscheme, 0, "TCP ISN generation scheme");
+
 static void    tcp_cleartaocache __P((void));
 static void    tcp_notify __P((struct inpcb *, int));
 
@@ -182,6 +186,7 @@
 {
        int hashsize;
        
+       tcp_iss = arc4random(); /* wrong, but better than a constant */
        tcp_ccgen = 1;
        tcp_cleartaocache();
 
@@ -1086,6 +1091,26 @@
                              0, cmd, notify);
 }
 #endif /* INET6 */
+
+tcp_seq
+tcp_new_isn()
+{
+       if ((tcp_seq_genscheme > 1) || (tcp_seq_genscheme < 0))
+               tcp_seq_genscheme = 1;
+
+       switch (tcp_seq_genscheme) {
+               case 0: /*
+                        * Random positive increments
+                        */
+                       tcp_iss += TCP_ISSINCR/2;
+                       return tcp_iss;
+               case 1: /*
+                        * OpemBSD randomized scheme
+                        */
+                       return tcp_rndiss_next();
+       }
+
+}
 
 #define TCP_RNDISS_ROUNDS      16
 #define TCP_RNDISS_OUT 7200
diff -u -r netinet.old/tcp_timer.c netinet/tcp_timer.c
--- netinet.old/tcp_timer.c     Sun Jul  1 20:44:50 2001
+++ netinet/tcp_timer.c Sun Jul  1 21:12:16 2001
@@ -132,6 +132,8 @@
 
        tcp_maxidle = tcp_keepcnt * tcp_keepintvl;
 
+       tcp_iss += TCP_ISSINCR/PR_SLOWHZ;
+
        splx(s);
 }
 
diff -u -r netinet.old/tcp_usrreq.c netinet/tcp_usrreq.c
--- netinet.old/tcp_usrreq.c    Sun Jul  1 20:44:50 2001
+++ netinet/tcp_usrreq.c        Sun Jul  1 21:18:20 2001
@@ -759,7 +759,7 @@
        tcpstat.tcps_connattempt++;
        tp->t_state = TCPS_SYN_SENT;
        callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
-       tp->iss = tcp_rndiss_next();
+       tp->iss = tcp_new_isn();
        tcp_sendseqinit(tp);
 
        /*
@@ -851,7 +851,7 @@
        tcpstat.tcps_connattempt++;
        tp->t_state = TCPS_SYN_SENT;
        callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
-       tp->iss = tcp_rndiss_next();
+       tp->iss = tcp_new_isn();
        tcp_sendseqinit(tp);
 
        /*
diff -u -r netinet.old/tcp_var.h netinet/tcp_var.h
--- netinet.old/tcp_var.h       Sun Jul  1 20:44:50 2001
+++ netinet/tcp_var.h   Sun Jul  1 21:13:25 2001
@@ -413,6 +413,7 @@
 tcp_seq        tcp_rndiss_next __P((void));
 u_int16_t
        tcp_rndiss_encrypt __P((u_int16_t));
+tcp_seq tcp_new_isn __P((void));
 
 #endif /* _KERNEL */
 

Reply via email to