Don't expose the uptime via the TCP timestamps.
The TCP client side or the TCP server side when not using SYN-cookies used the uptime as the TCP timestamp value. This patch uses in all cases an offset, which is the result of a keyed hash function taking the source and destination addresses and port numbers into account. The keyed hash function is the same a used for the initial TSN. Reviewed by: rrs@ MFC after: 1 month Sponsored by: Netflix, Inc. Differential Revision: https://reviews.freebsd.org/D16636
This commit is contained in:
parent
63d8b6ea21
commit
8e02b4e00c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=338053
@ -233,6 +233,9 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone);
|
||||
VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
|
||||
#endif
|
||||
|
||||
VNET_DEFINE_STATIC(u_char, ts_offset_secret[32]);
|
||||
#define V_ts_offset_secret VNET(ts_offset_secret)
|
||||
|
||||
static int tcp_default_fb_init(struct tcpcb *tp);
|
||||
static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged);
|
||||
static int tcp_default_handoff_ok(struct tcpcb *tp);
|
||||
@ -1092,6 +1095,7 @@ tcp_init(void)
|
||||
/* Initialize the TCP logging data. */
|
||||
tcp_log_init();
|
||||
#endif
|
||||
read_random(&V_ts_offset_secret, sizeof(V_ts_offset_secret));
|
||||
|
||||
if (tcp_soreceive_stream) {
|
||||
#ifdef INET
|
||||
@ -2603,6 +2607,40 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
static uint32_t
|
||||
tcp_keyed_hash(struct in_conninfo *inc, u_char *key)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
uint32_t hash[4];
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, &inc->inc_fport, sizeof(uint16_t));
|
||||
MD5Update(&ctx, &inc->inc_lport, sizeof(uint16_t));
|
||||
switch (inc->inc_flags & INC_ISIPV6) {
|
||||
#ifdef INET
|
||||
case 0:
|
||||
MD5Update(&ctx, &inc->inc_faddr, sizeof(struct in_addr));
|
||||
MD5Update(&ctx, &inc->inc_laddr, sizeof(struct in_addr));
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case INC_ISIPV6:
|
||||
MD5Update(&ctx, &inc->inc6_faddr, sizeof(struct in6_addr));
|
||||
MD5Update(&ctx, &inc->inc6_laddr, sizeof(struct in6_addr));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
MD5Update(&ctx, key, 32);
|
||||
MD5Final((unsigned char *)hash, &ctx);
|
||||
|
||||
return (hash[0]);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
tcp_new_ts_offset(struct in_conninfo *inc)
|
||||
{
|
||||
return (tcp_keyed_hash(inc, V_ts_offset_secret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Following is where TCP initial sequence number generation occurs.
|
||||
@ -2644,7 +2682,7 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
* as reseeding should not be necessary.
|
||||
*
|
||||
* Locking of the global variables isn_secret, isn_last_reseed, isn_offset,
|
||||
* isn_offset_old, and isn_ctx is performed using the TCP pcbinfo lock. In
|
||||
* isn_offset_old, and isn_ctx is performed using the ISN lock. In
|
||||
* general, this means holding an exclusive (write) lock.
|
||||
*/
|
||||
|
||||
@ -2665,15 +2703,11 @@ VNET_DEFINE_STATIC(u_int32_t, isn_offset_old);
|
||||
#define V_isn_offset_old VNET(isn_offset_old)
|
||||
|
||||
tcp_seq
|
||||
tcp_new_isn(struct tcpcb *tp)
|
||||
tcp_new_isn(struct in_conninfo *inc)
|
||||
{
|
||||
MD5_CTX isn_ctx;
|
||||
u_int32_t md5_buffer[4];
|
||||
tcp_seq new_isn;
|
||||
u_int32_t projected_offset;
|
||||
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
ISN_LOCK();
|
||||
/* Seed if this is the first use, reseed if requested. */
|
||||
if ((V_isn_last_reseed == 0) || ((V_tcp_isn_reseed_interval > 0) &&
|
||||
@ -2684,26 +2718,7 @@ tcp_new_isn(struct tcpcb *tp)
|
||||
}
|
||||
|
||||
/* Compute the md5 hash and return the ISN. */
|
||||
MD5Init(&isn_ctx);
|
||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short));
|
||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short));
|
||||
#ifdef INET6
|
||||
if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) {
|
||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr,
|
||||
sizeof(struct in6_addr));
|
||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr,
|
||||
sizeof(struct in6_addr));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr,
|
||||
sizeof(struct in_addr));
|
||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr,
|
||||
sizeof(struct in_addr));
|
||||
}
|
||||
MD5Update(&isn_ctx, (u_char *) &V_isn_secret, sizeof(V_isn_secret));
|
||||
MD5Final((u_char *) &md5_buffer, &isn_ctx);
|
||||
new_isn = (tcp_seq) md5_buffer[0];
|
||||
new_isn = (tcp_seq)tcp_keyed_hash(inc, V_isn_secret);
|
||||
V_isn_offset += ISN_STATIC_INCREMENT +
|
||||
(arc4random() & ISN_RANDOM_INCREMENT);
|
||||
if (ticks != V_isn_last) {
|
||||
|
@ -1497,6 +1497,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
|
||||
if (to->to_flags & TOF_TS) {
|
||||
sc->sc_tsreflect = to->to_tsval;
|
||||
sc->sc_flags |= SCF_TIMESTAMP;
|
||||
sc->sc_tsoff = tcp_new_ts_offset(inc);
|
||||
}
|
||||
if (to->to_flags & TOF_SCALE) {
|
||||
int wscale = 0;
|
||||
@ -2035,11 +2036,6 @@ syncookie_generate(struct syncache_head *sch, struct syncache *sc)
|
||||
iss = hash & ~0xff;
|
||||
iss |= cookie.cookie ^ (hash >> 24);
|
||||
|
||||
/* Randomize the timestamp. */
|
||||
if (sc->sc_flags & SCF_TIMESTAMP) {
|
||||
sc->sc_tsoff = arc4random() - tcp_ts_getticks();
|
||||
}
|
||||
|
||||
TCPSTAT_INC(tcps_sc_sendcookie);
|
||||
return (iss);
|
||||
}
|
||||
@ -2126,7 +2122,7 @@ syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
|
||||
if (to->to_flags & TOF_TS) {
|
||||
sc->sc_flags |= SCF_TIMESTAMP;
|
||||
sc->sc_tsreflect = to->to_tsval;
|
||||
sc->sc_tsoff = to->to_tsecr - tcp_ts_getticks();
|
||||
sc->sc_tsoff = tcp_new_ts_offset(inc);
|
||||
}
|
||||
|
||||
if (to->to_flags & TOF_SIGNATURE)
|
||||
|
@ -1439,7 +1439,9 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
soisconnecting(so);
|
||||
TCPSTAT_INC(tcps_connattempt);
|
||||
tcp_state_change(tp, TCPS_SYN_SENT);
|
||||
tp->iss = tcp_new_isn(tp);
|
||||
tp->iss = tcp_new_isn(&inp->inp_inc);
|
||||
if (tp->t_flags & TF_REQ_TSTMP)
|
||||
tp->ts_offset = tcp_new_ts_offset(&inp->inp_inc);
|
||||
tcp_sendseqinit(tp);
|
||||
|
||||
return 0;
|
||||
@ -1478,7 +1480,9 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
soisconnecting(inp->inp_socket);
|
||||
TCPSTAT_INC(tcps_connattempt);
|
||||
tcp_state_change(tp, TCPS_SYN_SENT);
|
||||
tp->iss = tcp_new_isn(tp);
|
||||
tp->iss = tcp_new_isn(&inp->inp_inc);
|
||||
if (tp->t_flags & TF_REQ_TSTMP)
|
||||
tp->ts_offset = tcp_new_ts_offset(&inp->inp_inc);
|
||||
tcp_sendseqinit(tp);
|
||||
|
||||
return 0;
|
||||
|
@ -923,7 +923,9 @@ void tcp_hc_updatemtu(struct in_conninfo *, uint32_t);
|
||||
void tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
|
||||
|
||||
extern struct pr_usrreqs tcp_usrreqs;
|
||||
tcp_seq tcp_new_isn(struct tcpcb *);
|
||||
|
||||
uint32_t tcp_new_ts_offset(struct in_conninfo *);
|
||||
tcp_seq tcp_new_isn(struct in_conninfo *);
|
||||
|
||||
int tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq);
|
||||
void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);
|
||||
|
Loading…
Reference in New Issue
Block a user