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
@ -233,6 +233,9 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone);
|
|||||||
VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
|
VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
|
||||||
#endif
|
#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 int tcp_default_fb_init(struct tcpcb *tp);
|
||||||
static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged);
|
static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged);
|
||||||
static int tcp_default_handoff_ok(struct tcpcb *tp);
|
static int tcp_default_handoff_ok(struct tcpcb *tp);
|
||||||
@ -1092,6 +1095,7 @@ tcp_init(void)
|
|||||||
/* Initialize the TCP logging data. */
|
/* Initialize the TCP logging data. */
|
||||||
tcp_log_init();
|
tcp_log_init();
|
||||||
#endif
|
#endif
|
||||||
|
read_random(&V_ts_offset_secret, sizeof(V_ts_offset_secret));
|
||||||
|
|
||||||
if (tcp_soreceive_stream) {
|
if (tcp_soreceive_stream) {
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
@ -2603,6 +2607,40 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
|||||||
}
|
}
|
||||||
#endif /* INET6 */
|
#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.
|
* 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.
|
* as reseeding should not be necessary.
|
||||||
*
|
*
|
||||||
* Locking of the global variables isn_secret, isn_last_reseed, isn_offset,
|
* 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.
|
* 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)
|
#define V_isn_offset_old VNET(isn_offset_old)
|
||||||
|
|
||||||
tcp_seq
|
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;
|
tcp_seq new_isn;
|
||||||
u_int32_t projected_offset;
|
u_int32_t projected_offset;
|
||||||
|
|
||||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
|
||||||
|
|
||||||
ISN_LOCK();
|
ISN_LOCK();
|
||||||
/* Seed if this is the first use, reseed if requested. */
|
/* Seed if this is the first use, reseed if requested. */
|
||||||
if ((V_isn_last_reseed == 0) || ((V_tcp_isn_reseed_interval > 0) &&
|
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. */
|
/* Compute the md5 hash and return the ISN. */
|
||||||
MD5Init(&isn_ctx);
|
new_isn = (tcp_seq)tcp_keyed_hash(inc, V_isn_secret);
|
||||||
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];
|
|
||||||
V_isn_offset += ISN_STATIC_INCREMENT +
|
V_isn_offset += ISN_STATIC_INCREMENT +
|
||||||
(arc4random() & ISN_RANDOM_INCREMENT);
|
(arc4random() & ISN_RANDOM_INCREMENT);
|
||||||
if (ticks != V_isn_last) {
|
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) {
|
if (to->to_flags & TOF_TS) {
|
||||||
sc->sc_tsreflect = to->to_tsval;
|
sc->sc_tsreflect = to->to_tsval;
|
||||||
sc->sc_flags |= SCF_TIMESTAMP;
|
sc->sc_flags |= SCF_TIMESTAMP;
|
||||||
|
sc->sc_tsoff = tcp_new_ts_offset(inc);
|
||||||
}
|
}
|
||||||
if (to->to_flags & TOF_SCALE) {
|
if (to->to_flags & TOF_SCALE) {
|
||||||
int wscale = 0;
|
int wscale = 0;
|
||||||
@ -2035,11 +2036,6 @@ syncookie_generate(struct syncache_head *sch, struct syncache *sc)
|
|||||||
iss = hash & ~0xff;
|
iss = hash & ~0xff;
|
||||||
iss |= cookie.cookie ^ (hash >> 24);
|
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);
|
TCPSTAT_INC(tcps_sc_sendcookie);
|
||||||
return (iss);
|
return (iss);
|
||||||
}
|
}
|
||||||
@ -2126,7 +2122,7 @@ syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
|
|||||||
if (to->to_flags & TOF_TS) {
|
if (to->to_flags & TOF_TS) {
|
||||||
sc->sc_flags |= SCF_TIMESTAMP;
|
sc->sc_flags |= SCF_TIMESTAMP;
|
||||||
sc->sc_tsreflect = to->to_tsval;
|
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)
|
if (to->to_flags & TOF_SIGNATURE)
|
||||||
|
@ -1439,7 +1439,9 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
|||||||
soisconnecting(so);
|
soisconnecting(so);
|
||||||
TCPSTAT_INC(tcps_connattempt);
|
TCPSTAT_INC(tcps_connattempt);
|
||||||
tcp_state_change(tp, TCPS_SYN_SENT);
|
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);
|
tcp_sendseqinit(tp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1478,7 +1480,9 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
|||||||
soisconnecting(inp->inp_socket);
|
soisconnecting(inp->inp_socket);
|
||||||
TCPSTAT_INC(tcps_connattempt);
|
TCPSTAT_INC(tcps_connattempt);
|
||||||
tcp_state_change(tp, TCPS_SYN_SENT);
|
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);
|
tcp_sendseqinit(tp);
|
||||||
|
|
||||||
return 0;
|
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 *);
|
void tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
|
||||||
|
|
||||||
extern struct pr_usrreqs tcp_usrreqs;
|
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);
|
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);
|
void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);
|
||||||
|
Loading…
Reference in New Issue
Block a user