Hi, After changing tcp now tick to milliseconds, it will wrap around after 49 days of uptime. That may be a problem in some places of our stack. Better use a 64 bit counter.
As timestamp option is 32 bit in TCP protocol, we have to use the lower 32 bit there. There are casts to 32 bits that should behave correctly. More eyes to review would be helpful. As a bonus, start with random 63 bit offset to avoid uptime leakage. I am not aware that we leak anywhere, but more random is always good. 2^63 milliseconds gives us 2.9*10^8 years of possible uptime. ok? bluhm Index: netinet/tcp_input.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.388 diff -u -p -r1.388 tcp_input.c --- netinet/tcp_input.c 30 May 2023 19:32:57 -0000 1.388 +++ netinet/tcp_input.c 4 Jul 2023 08:49:47 -0000 @@ -130,8 +130,8 @@ struct timeval tcp_ackdrop_ppslim_last; #define TCP_PAWS_IDLE TCP_TIME(24 * 24 * 60 * 60) /* for modulo comparisons of timestamps */ -#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) -#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) +#define TSTMP_LT(a,b) ((int32_t)((a)-(b)) < 0) +#define TSTMP_GEQ(a,b) ((int32_t)((a)-(b)) >= 0) /* for TCP SACK comparisons */ #define SEQ_MIN(a,b) (SEQ_LT(a,b) ? (a) : (b)) @@ -190,7 +190,7 @@ void tcp_newreno_partialack(struct tcpc void syn_cache_put(struct syn_cache *); void syn_cache_rm(struct syn_cache *); -int syn_cache_respond(struct syn_cache *, struct mbuf *, uint32_t); +int syn_cache_respond(struct syn_cache *, struct mbuf *, uint64_t); void syn_cache_timer(void *); void syn_cache_reaper(void *); void syn_cache_insert(struct syn_cache *, struct tcpcb *); @@ -198,10 +198,10 @@ void syn_cache_reset(struct sockaddr *, struct tcphdr *, u_int); int syn_cache_add(struct sockaddr *, struct sockaddr *, struct tcphdr *, unsigned int, struct socket *, struct mbuf *, u_char *, int, - struct tcp_opt_info *, tcp_seq *, uint32_t); + struct tcp_opt_info *, tcp_seq *, uint64_t); struct socket *syn_cache_get(struct sockaddr *, struct sockaddr *, struct tcphdr *, unsigned int, unsigned int, struct socket *, - struct mbuf *, uint32_t); + struct mbuf *, uint64_t); struct syn_cache *syn_cache_lookup(struct sockaddr *, struct sockaddr *, struct syn_cache_head **, u_int); @@ -375,7 +375,7 @@ tcp_input(struct mbuf **mp, int *offp, i short ostate; caddr_t saveti; tcp_seq iss, *reuse = NULL; - uint32_t now; + uint64_t now; u_long tiwin; struct tcp_opt_info opti; struct tcphdr *th; @@ -885,7 +885,7 @@ findpcb: goto drop; if (opti.ts_present && opti.ts_ecr) { - int rtt_test; + int32_t rtt_test; /* subtract out the tcp timestamp modulator */ opti.ts_ecr -= tp->ts_modulate; @@ -1272,7 +1272,7 @@ trimthenstep6: TSTMP_LT(opti.ts_val, tp->ts_recent)) { /* Check to see if ts_recent is over 24 days old. */ - if ((int)(now - tp->ts_recent_age) > TCP_PAWS_IDLE) { + if (now - tp->ts_recent_age > TCP_PAWS_IDLE) { /* * Invalidate ts_recent. If this segment updates * ts_recent, the age will be reset later and ts_recent @@ -2120,7 +2120,7 @@ drop: int tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcphdr *th, struct mbuf *m, int iphlen, struct tcp_opt_info *oi, - u_int rtableid, uint32_t now) + u_int rtableid, uint64_t now) { u_int16_t mss = 0; int opt, optlen; @@ -2686,7 +2686,7 @@ tcp_pulloutofband(struct socket *so, u_i * and update averages and current timeout. */ void -tcp_xmit_timer(struct tcpcb *tp, int rtt) +tcp_xmit_timer(struct tcpcb *tp, int32_t rtt) { int delta, rttmin; @@ -3335,7 +3335,7 @@ void syn_cache_timer(void *arg) { struct syn_cache *sc = arg; - uint32_t now; + uint64_t now; NET_LOCK(); if (sc->sc_flags & SCF_DEAD) @@ -3469,7 +3469,7 @@ syn_cache_lookup(struct sockaddr *src, s */ struct socket * syn_cache_get(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th, - u_int hlen, u_int tlen, struct socket *so, struct mbuf *m, uint32_t now) + u_int hlen, u_int tlen, struct socket *so, struct mbuf *m, uint64_t now) { struct syn_cache *sc; struct syn_cache_head *scp; @@ -3744,7 +3744,7 @@ syn_cache_unreach(struct sockaddr *src, int syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th, u_int iphlen, struct socket *so, struct mbuf *m, u_char *optp, int optlen, - struct tcp_opt_info *oi, tcp_seq *issp, uint32_t now) + struct tcp_opt_info *oi, tcp_seq *issp, uint64_t now) { struct tcpcb tb, *tp; long win; @@ -3911,7 +3911,7 @@ syn_cache_add(struct sockaddr *src, stru } int -syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint32_t now) +syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint64_t now) { u_int8_t *optp; int optlen, error; Index: netinet/tcp_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_output.c,v retrieving revision 1.138 diff -u -p -r1.138 tcp_output.c --- netinet/tcp_output.c 15 May 2023 16:34:56 -0000 1.138 +++ netinet/tcp_output.c 4 Jul 2023 08:49:47 -0000 @@ -204,7 +204,7 @@ tcp_output(struct tcpcb *tp) int idle, sendalot = 0; int i, sack_rxmit = 0; struct sackhole *p; - uint32_t now; + uint64_t now; #ifdef TCP_SIGNATURE unsigned int sigoff; #endif /* TCP_SIGNATURE */ Index: netinet/tcp_subr.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_subr.c,v retrieving revision 1.191 diff -u -p -r1.191 tcp_subr.c --- netinet/tcp_subr.c 10 May 2023 12:07:16 -0000 1.191 +++ netinet/tcp_subr.c 4 Jul 2023 08:49:47 -0000 @@ -137,6 +137,7 @@ struct cpumem *tcpcounters; /* tcp stat u_char tcp_secret[16]; /* [I] */ SHA2_CTX tcp_secret_ctx; /* [I] */ tcp_seq tcp_iss; /* [T] updated by timer and connection */ +uint64_t tcp_starttime; /* [I] random offset for tcp_now() */ /* * Tcp initialization @@ -145,6 +146,9 @@ void tcp_init(void) { tcp_iss = 1; /* wrong */ + /* 0 is treated special so add 1, 63 bits to count is enough */ + arc4random_buf(&tcp_starttime, sizeof(tcp_starttime)); + tcp_starttime = 1ULL + (tcp_starttime / 2); pool_init(&tcpcb_pool, sizeof(struct tcpcb), 0, IPL_SOFTNET, 0, "tcpcb", NULL); pool_init(&tcpqe_pool, sizeof(struct tcpqent), 0, IPL_SOFTNET, 0, @@ -289,7 +293,7 @@ tcp_template(struct tcpcb *tp) */ void tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, - tcp_seq ack, tcp_seq seq, int flags, u_int rtableid, uint32_t now) + tcp_seq ack, tcp_seq seq, int flags, u_int rtableid, uint64_t now) { int tlen; int win = 0; Index: netinet/tcp_timer.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_timer.c,v retrieving revision 1.72 diff -u -p -r1.72 tcp_timer.c --- netinet/tcp_timer.c 14 Mar 2023 00:24:05 -0000 1.72 +++ netinet/tcp_timer.c 4 Jul 2023 08:49:47 -0000 @@ -394,7 +394,7 @@ tcp_timer_persist(void *arg) struct tcpcb *otp = NULL, *tp = arg; uint32_t rto; short ostate; - uint32_t now; + uint64_t now; NET_LOCK(); /* Ignore canceled timeouts or timeouts that have been rescheduled. */ @@ -463,7 +463,7 @@ tcp_timer_keep(void *arg) tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && tp->t_state <= TCPS_CLOSING) { int maxidle; - uint32_t now; + uint64_t now; maxidle = READ_ONCE(tcp_maxidle); now = tcp_now(); @@ -506,7 +506,7 @@ tcp_timer_2msl(void *arg) struct tcpcb *otp = NULL, *tp = arg; short ostate; int maxidle; - uint32_t now; + uint64_t now; NET_LOCK(); /* Ignore canceled timeouts or timeouts that have been rescheduled. */ Index: netinet/tcp_usrreq.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.220 diff -u -p -r1.220 tcp_usrreq.c --- netinet/tcp_usrreq.c 2 Jul 2023 19:59:15 -0000 1.220 +++ netinet/tcp_usrreq.c 4 Jul 2023 08:49:47 -0000 @@ -211,7 +211,7 @@ tcp_fill_info(struct tcpcb *tp, struct s struct proc *p = curproc; struct tcp_info *ti; u_int t = 1000; /* msec => usec */ - uint32_t now; + uint64_t now; if (sizeof(*ti) > MLEN) { MCLGETL(m, M_WAITOK, sizeof(*ti)); Index: netinet/tcp_var.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_var.h,v retrieving revision 1.168 diff -u -p -r1.168 tcp_var.h --- netinet/tcp_var.h 2 Jul 2023 19:59:15 -0000 1.168 +++ netinet/tcp_var.h 4 Jul 2023 08:49:47 -0000 @@ -150,8 +150,8 @@ struct tcpcb { */ /* auto-sizing variables */ + uint64_t rfbuf_ts; /* recv buffer autoscaling time stamp */ u_int rfbuf_cnt; /* recv buffer autoscaling byte count */ - u_int32_t rfbuf_ts; /* recv buffer autoscaling time stamp */ u_short t_maxopd; /* mss plus options */ u_short t_peermss; /* peer's maximum segment size */ @@ -160,11 +160,11 @@ struct tcpcb { * transmit timing stuff. See below for scale of srtt and rttvar. * "Variance" is actually smoothed difference. */ - uint32_t t_rcvtime; /* time last segment received */ - uint32_t t_rcvacktime; /* time last ack received */ - uint32_t t_sndtime; /* time last segment sent */ - uint32_t t_sndacktime; /* time last ack sent */ - uint32_t t_rtttime; /* time we started measuring rtt */ + uint64_t t_rcvtime; /* time last segment received */ + uint64_t t_rcvacktime; /* time last ack received */ + uint64_t t_sndtime; /* time last segment sent */ + uint64_t t_sndacktime; /* time last ack sent */ + uint64_t t_rtttime; /* time we started measuring rtt */ tcp_seq t_rtseq; /* sequence number being timed */ int t_srtt; /* smoothed round-trip time */ int t_rttvar; /* variance in round-trip time */ @@ -183,9 +183,9 @@ struct tcpcb { u_char rcv_scale; /* window scaling for recv window */ u_char request_r_scale; /* pending window scaling */ u_char requested_s_scale; - u_int32_t ts_recent; /* timestamp echo data */ - u_int32_t ts_modulate; /* modulation on timestamp */ - u_int32_t ts_recent_age; /* when last updated */ + uint32_t ts_recent; /* timestamp echo data */ + uint32_t ts_modulate; /* modulation on timestamp */ + uint64_t ts_recent_age; /* when last updated */ tcp_seq last_ack_sent; /* pointer for syn cache entries*/ @@ -250,12 +250,9 @@ struct syn_cache { long sc_win; /* advertised window */ struct syn_cache_head *sc_buckethead; /* our bucket index */ struct syn_cache_set *sc_set; /* our syn cache set */ + u_int64_t sc_timestamp; /* timestamp from SYN */ u_int32_t sc_hash; - u_int32_t sc_timestamp; /* timestamp from SYN */ u_int32_t sc_modulate; /* our timestamp modulator */ -#if 0 - u_int32_t sc_timebase; /* our local timebase */ -#endif union syn_cache_sa sc_src; union syn_cache_sa sc_dst; tcp_seq sc_irs; @@ -657,10 +654,13 @@ tcpstat_pkt(enum tcpstat_counters pcount counters_pkt(tcpcounters, pcounter, bcounter, v); } -static inline uint32_t +extern uint64_t tcp_starttime; + +static inline uint64_t tcp_now(void) { - return (getnsecruntime() / 1000000); + /* TCP time ticks in 63 bit milliseconds with 63 bit random offset. */ + return tcp_starttime + (getnsecruntime() / 1000000ULL); } #define TCP_TIME(_sec) ((_sec) * 1000) /* tcp_now() is in milliseconds */ @@ -712,7 +712,7 @@ struct tcpcb * struct tcpcb * tcp_drop(struct tcpcb *, int); int tcp_dooptions(struct tcpcb *, u_char *, int, struct tcphdr *, - struct mbuf *, int, struct tcp_opt_info *, u_int, uint32_t); + struct mbuf *, int, struct tcp_opt_info *, u_int, uint64_t); void tcp_init(void); int tcp_input(struct mbuf **, int *, int, int); int tcp_mss(struct tcpcb *, int); @@ -735,7 +735,7 @@ void tcp_pulloutofband(struct socket *, int tcp_reass(struct tcpcb *, struct tcphdr *, struct mbuf *, int *); void tcp_rscale(struct tcpcb *, u_long); void tcp_respond(struct tcpcb *, caddr_t, struct tcphdr *, tcp_seq, - tcp_seq, int, u_int, uint32_t); + tcp_seq, int, u_int, uint64_t); void tcp_setpersist(struct tcpcb *); void tcp_update_sndspace(struct tcpcb *); void tcp_update_rcvspace(struct tcpcb *); @@ -767,7 +767,7 @@ int tcp_sense(struct socket *, struct s int tcp_rcvoob(struct socket *, struct mbuf *, int); int tcp_sendoob(struct socket *, struct mbuf *, struct mbuf *, struct mbuf *); -void tcp_xmit_timer(struct tcpcb *, int); +void tcp_xmit_timer(struct tcpcb *, int32_t); void tcpdropoldhalfopen(struct tcpcb *, u_int16_t); void tcp_sack_option(struct tcpcb *,struct tcphdr *,u_char *,int); void tcp_update_sack_list(struct tcpcb *tp, tcp_seq, tcp_seq);