tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: TCP timestamp starting value
OK, I'm now running with the attached patch (against 6.1_STABLE, in case that
matters). It allows anyone to select and test his favourite or most hated
variant. I've implemeted every timebase initialization method that came to
my mind (minus joerg@'s variant with periodic re-keying, but that could be
added).
Default is the old behaviour (start counting from 1 for each connection).
Comments and reviews welcome, especially test results with real-world peers.
Index: tcp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v
retrieving revision 1.321.2.1
diff -u -p -r1.321.2.1 tcp_input.c
--- tcp_input.c 24 Jul 2015 07:40:17 -0000 1.321.2.1
+++ tcp_input.c 26 Jul 2016 14:57:55 -0000
@@ -4344,6 +4344,8 @@ syn_cache_add(struct sockaddr *src, stru
struct mbuf *ipopts;
struct tcp_opt_info opti;
int s;
+ /* if not set below, tcp_gettimebase() will not use them */
+ void *src_addr = NULL, *dst_addr = NULL;
tp = sototcpcb(so);
@@ -4445,6 +4447,9 @@ syn_cache_add(struct sockaddr *src, stru
struct sockaddr_in *srcin = (void *) src;
struct sockaddr_in *dstin = (void *) dst;
+ src_addr = &srcin->sin_addr;
+ dst_addr = &dstin->sin_addr;
+
sc->sc_iss = tcp_new_iss1(&dstin->sin_addr,
&srcin->sin_addr, dstin->sin_port,
srcin->sin_port, sizeof(dstin->sin_addr), 0);
@@ -4457,6 +4462,9 @@ syn_cache_add(struct sockaddr *src, stru
struct sockaddr_in6 *srcin6 = (void *) src;
struct sockaddr_in6 *dstin6 = (void *) dst;
+ src_addr = &srcin6->sin6_addr;
+ dst_addr = &dstin6->sin6_addr;
+
sc->sc_iss = tcp_new_iss1(&dstin6->sin6_addr,
&srcin6->sin6_addr, dstin6->sin6_port,
srcin6->sin6_port, sizeof(dstin6->sin6_addr), 0);
@@ -4469,7 +4477,7 @@ syn_cache_add(struct sockaddr *src, stru
m->m_pkthdr.rcvif : NULL,
sc->sc_src.sa.sa_family);
sc->sc_win = win;
- sc->sc_timebase = tcp_now - 1; /* see tcp_newtcpcb() */
+ sc->sc_timebase = tcp_gettimebase(src->sa_family, src_addr, dst_addr);
sc->sc_timestamp = tb.ts_recent;
if ((tb.t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP)) ==
(TF_REQ_TSTMP|TF_RCVD_TSTMP))
Index: tcp_subr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.246.2.1
diff -u -p -r1.246.2.1 tcp_subr.c
--- tcp_subr.c 31 Oct 2012 17:30:20 -0000 1.246.2.1
+++ tcp_subr.c 26 Jul 2016 14:57:55 -0000
@@ -112,6 +112,7 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_subr.c,v
#include <sys/pool.h>
#include <sys/md5.h>
#include <sys/cprng.h>
+#include <sys/time.h>
#include <net/route.h>
#include <net/if.h>
@@ -1011,6 +1012,7 @@ tcp_newtcpcb(int family, void *aux)
#endif
struct tcpcb *tp;
int i;
+ void *src, *dst;
/* XXX Consider using a pool_cache for speed. */
tp = pool_get(&tcpcb_pool, PR_NOWAIT); /* splsoftnet via tcp_usrreq */
@@ -1040,6 +1042,9 @@ tcp_newtcpcb(int family, void *aux)
tp->t_inpcb = inp;
tp->t_mtudisc = ip_mtudisc;
+
+ src = &inp->inp_ip.ip_src;
+ dst = &inp->inp_ip.ip_dst;
break;
}
#ifdef INET6
@@ -1056,6 +1061,9 @@ tcp_newtcpcb(int family, void *aux)
tp->t_in6pcb = in6p;
/* for IPv6, always try to run path MTU discovery */
tp->t_mtudisc = 1;
+
+ src = &in6p->in6p_ip6.ip6_src;
+ dst = &in6p->in6p_ip6.ip6_dst;
break;
}
#endif /* INET6 */
@@ -1067,18 +1075,7 @@ tcp_newtcpcb(int family, void *aux)
return (NULL);
}
- /*
- * Initialize our timebase. When we send timestamps, we take
- * the delta from tcp_now -- this means each connection always
- * gets a timebase of 1, which makes it, among other things,
- * more difficult to determine how long a system has been up,
- * and thus how many TCP sequence increments have occurred.
- *
- * We start with 1, because 0 doesn't work with linux, which
- * considers timestamp 0 in a SYN packet as a bug and disables
- * timestamps.
- */
- tp->ts_timebase = tcp_now - 1;
+ tp->ts_timebase = tcp_gettimebase(family, src, dst);
tcp_congctl_select(tp, tcp_congctl_global_name);
@@ -2430,3 +2427,96 @@ tcp_statadd(u_int stat, uint64_t val)
KASSERT(stat < TCP_NSTATS);
TCP_STATADD(stat, val);
}
+
+uint32_t
+tcp_gettimebase(int family, void *src, void *dst)
+{
+ /*
+ * Initialize our timebase. When we send timestamps, we take
+ * the delta from tcp_now.
+ * Provide different methods of chosing the initial value.
+ * Different methods provide different levels of privacy and
+ * compatibility with existing peers (which may reject perfectly
+ * legal timestamp values).
+ */
+ u_int32_t timebase;
+ struct timeval tv;
+ MD5_CTX md5_ctx;
+ unsigned char md5_hash[MD5_DIGEST_LENGTH];
+
+ switch (tcp_do_timestamps) {
+ case 0:
+ return 0;
+ default:
+ case 1: /*
+ * Start counting from 1 for each connection.
+ * This is the traditional behaviour, but is known
+ * to cause problems with certain peers getting upset
+ * by the repetitive use of the same value.
+ * Use 1, not 0, because Linux regards 0 as invalid.
+ */
+ return tcp_now - 1;
+ case 2: /*
+ * Start counting from 1 at system boot.
+ * This resembles Linux behaviour.
+ * However, it leaks system uptime.
+ */
+ return 0;
+ case 3: /*
+ * Start counting at a fixed point in real time
+ * (the time this code was written).
+ * This leaks the local perception of real time but
+ * is trasparent to re-boots.
+ */
+ getmicrotime(&tv);
+ timebase = (tv.tv_sec - 1469021566) * 2;
+ if (tv.tv_usec >= 500000) timebase++;
+ /*
+ * this will underflow, but subtracting it from an incremented
+ * tcp_now is guaranteed to DTRT.
+ */
+ return tcp_now - timebase;
+ case 4: /*
+ * Use a random (but constant) epoch obtained at boot.
+ * This resembles "hardened Linux" behaviour.
+ * It leaks information about re-boots due to
+ * the epoch changing.
+ */
+ return tcp_timebase_cookie & 0x3fffffff;
+ case 5: /*
+ * Use an individual per-connection random epoch.
+ * May cause problems with misbehaving peers due to
+ * timestamps decreasing.
+ */
+ return cprng_fast32() & 0x3fffffff;
+ case 6: /*
+ * Use a randomized per-address pseudo-random epoch,
+ * i.e. a hash of src/dst addresses and a random constant
+ * obtained at boot time. May cause problems with broken
+ * peers.
+ * Suggested by joerg@.
+ */
+ MD5Init(&md5_ctx);
+ switch (family) {
+#ifdef INET
+ case AF_INET:
+ MD5Update(&md5_ctx, (unsigned char *)src,
+ sizeof(struct in_addr));
+ MD5Update(&md5_ctx, (unsigned char *)dst,
+ sizeof(struct in_addr));
+#endif
+#ifdef INET6
+ case AF_INET6:
+ MD5Update(&md5_ctx, (unsigned char *)src,
+ sizeof(struct in6_addr));
+ MD5Update(&md5_ctx, (unsigned char *)dst,
+ sizeof(struct in6_addr));
+#endif
+ }
+ MD5Update(&md5_ctx, (unsigned char *)&tcp_timebase_cookie,
+ sizeof(tcp_timebase_cookie));
+ MD5Final(md5_hash, &md5_ctx);
+ memcpy(&timebase, md5_hash, sizeof(timebase));
+ return timebase & 0x3fffffff;
+ }
+}
Index: tcp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.162.2.3
diff -u -p -r1.162.2.3 tcp_usrreq.c
--- tcp_usrreq.c 14 Dec 2013 19:29:29 -0000 1.162.2.3
+++ tcp_usrreq.c 26 Jul 2016 14:57:55 -0000
@@ -118,6 +118,7 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c
#include <sys/sysctl.h>
#include <sys/kauth.h>
#include <sys/uidinfo.h>
+#include <sys/cprng.h>
#include <net/if.h>
#include <net/route.h>
@@ -157,6 +158,8 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c
#include <netinet6/ipsec.h>
#endif /*KAME_IPSEC*/
+u_int32_t tcp_timebase_cookie;
+
/*
* TCP protocol interface to socket abstraction.
*/
@@ -2146,4 +2149,6 @@ tcp_usrreq_init(void)
#ifdef INET6
sysctl_net_inet_tcp_setup2(NULL, PF_INET6, "inet6", "tcp6");
#endif
+
+ tcp_timebase_cookie = cprng_fast32();
}
Index: tcp_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_var.h,v
retrieving revision 1.169
diff -u -p -r1.169 tcp_var.h
--- tcp_var.h 2 Feb 2012 19:43:08 -0000 1.169
+++ tcp_var.h 26 Jul 2016 14:57:55 -0000
@@ -849,6 +849,8 @@ extern int tcp_do_autosndbuf;
extern int tcp_autosndbuf_inc;
extern int tcp_autosndbuf_max;
+extern u_int32_t tcp_timebase_cookie; /* random cookie for timebase initialization */
+
#define TCPCTL_VARIABLES { \
{ 0 }, \
@@ -993,6 +995,8 @@ void syn_cache_cleanup(struct tcpcb *);
int tcp_input_checksum(int, struct mbuf *, const struct tcphdr *, int, int,
int);
+
+uint32_t tcp_gettimebase(int, void *, void *);
#endif
#endif /* !_NETINET_TCP_VAR_H_ */
Home |
Main Index |
Thread Index |
Old Index