Commit 95a22cae authored by Florian Westphal's avatar Florian Westphal Committed by David S. Miller

tcp: randomize tcp timestamp offsets for each connection

jiffies based timestamps allow for easy inference of number of devices
behind NAT translators and also makes tracking of hosts simpler.

commit ceaa1fef ("tcp: adding a per-socket timestamp offset")
added the main infrastructure that is needed for per-connection ts
randomization, in particular writing/reading the on-wire tcp header
format takes the offset into account so rest of stack can use normal
tcp_time_stamp (jiffies).

So only two items are left:
 - add a tsoffset for request sockets
 - extend the tcp isn generator to also return another 32bit number
   in addition to the ISN.

Re-use of ISN generator also means timestamps are still monotonically
increasing for same connection quadruple, i.e. PAWS will still work.

Includes fixes from Eric Dumazet.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarYuchung Cheng <ycheng@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7df5358d
...@@ -123,6 +123,7 @@ struct tcp_request_sock { ...@@ -123,6 +123,7 @@ struct tcp_request_sock {
u32 txhash; u32 txhash;
u32 rcv_isn; u32 rcv_isn;
u32 snt_isn; u32 snt_isn;
u32 ts_off;
u32 last_oow_ack_time; /* last SYNACK */ u32 last_oow_ack_time; /* last SYNACK */
u32 rcv_nxt; /* the ack # by SYNACK. For u32 rcv_nxt; /* the ack # by SYNACK. For
* FastOpen it's the seq# * FastOpen it's the seq#
......
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
__be16 dport); __be16 dport);
__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport); __be16 sport, __be16 dport, u32 *tsoff);
__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
__be16 sport, __be16 dport); __be16 sport, __be16 dport, u32 *tsoff);
u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport); __be16 sport, __be16 dport);
u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
......
...@@ -1827,7 +1827,7 @@ struct tcp_request_sock_ops { ...@@ -1827,7 +1827,7 @@ struct tcp_request_sock_ops {
struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl,
const struct request_sock *req, const struct request_sock *req,
bool *strict); bool *strict);
__u32 (*init_seq)(const struct sk_buff *skb); __u32 (*init_seq)(const struct sk_buff *skb, u32 *tsoff);
int (*send_synack)(const struct sock *sk, struct dst_entry *dst, int (*send_synack)(const struct sock *sk, struct dst_entry *dst,
struct flowi *fl, struct request_sock *req, struct flowi *fl, struct request_sock *req,
struct tcp_fastopen_cookie *foc, struct tcp_fastopen_cookie *foc,
......
...@@ -40,8 +40,8 @@ static u32 seq_scale(u32 seq) ...@@ -40,8 +40,8 @@ static u32 seq_scale(u32 seq)
#endif #endif
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
__be16 sport, __be16 dport) __be16 sport, __be16 dport, u32 *tsoff)
{ {
u32 secret[MD5_MESSAGE_BYTES / 4]; u32 secret[MD5_MESSAGE_BYTES / 4];
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
...@@ -58,6 +58,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, ...@@ -58,6 +58,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
md5_transform(hash, secret); md5_transform(hash, secret);
*tsoff = hash[1];
return seq_scale(hash[0]); return seq_scale(hash[0]);
} }
EXPORT_SYMBOL(secure_tcpv6_sequence_number); EXPORT_SYMBOL(secure_tcpv6_sequence_number);
...@@ -86,8 +87,8 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); ...@@ -86,8 +87,8 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#ifdef CONFIG_INET #ifdef CONFIG_INET
__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport) __be16 sport, __be16 dport, u32 *tsoff)
{ {
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
...@@ -99,6 +100,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, ...@@ -99,6 +100,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
md5_transform(hash, net_secret); md5_transform(hash, net_secret);
*tsoff = hash[1];
return seq_scale(hash[0]); return seq_scale(hash[0]);
} }
......
...@@ -334,6 +334,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ...@@ -334,6 +334,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
treq = tcp_rsk(req); treq = tcp_rsk(req);
treq->rcv_isn = ntohl(th->seq) - 1; treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie; treq->snt_isn = cookie;
treq->ts_off = 0;
req->mss = mss; req->mss = mss;
ireq->ir_num = ntohs(th->dest); ireq->ir_num = ntohs(th->dest);
ireq->ir_rmt_port = th->source; ireq->ir_rmt_port = th->source;
......
...@@ -6307,6 +6307,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, ...@@ -6307,6 +6307,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
goto drop; goto drop;
tcp_rsk(req)->af_specific = af_ops; tcp_rsk(req)->af_specific = af_ops;
tcp_rsk(req)->ts_off = 0;
tcp_clear_options(&tmp_opt); tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = af_ops->mss_clamp; tmp_opt.mss_clamp = af_ops->mss_clamp;
...@@ -6328,6 +6329,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, ...@@ -6328,6 +6329,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
if (security_inet_conn_request(sk, skb, req)) if (security_inet_conn_request(sk, skb, req))
goto drop_and_free; goto drop_and_free;
if (isn && tmp_opt.tstamp_ok)
af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
if (!want_cookie && !isn) { if (!want_cookie && !isn) {
/* VJ's idea. We save last timestamp seen /* VJ's idea. We save last timestamp seen
* from the destination in peer table, when entering * from the destination in peer table, when entering
...@@ -6368,7 +6372,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, ...@@ -6368,7 +6372,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
goto drop_and_release; goto drop_and_release;
} }
isn = af_ops->init_seq(skb); isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
} }
if (!dst) { if (!dst) {
dst = af_ops->route_req(sk, &fl, req, NULL); dst = af_ops->route_req(sk, &fl, req, NULL);
...@@ -6380,6 +6384,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, ...@@ -6380,6 +6384,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
if (want_cookie) { if (want_cookie) {
isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
tcp_rsk(req)->ts_off = 0;
req->cookie_ts = tmp_opt.tstamp_ok; req->cookie_ts = tmp_opt.tstamp_ok;
if (!tmp_opt.tstamp_ok) if (!tmp_opt.tstamp_ok)
inet_rsk(req)->ecn_ok = 0; inet_rsk(req)->ecn_ok = 0;
......
...@@ -95,12 +95,12 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, ...@@ -95,12 +95,12 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
struct inet_hashinfo tcp_hashinfo; struct inet_hashinfo tcp_hashinfo;
EXPORT_SYMBOL(tcp_hashinfo); EXPORT_SYMBOL(tcp_hashinfo);
static __u32 tcp_v4_init_sequence(const struct sk_buff *skb) static u32 tcp_v4_init_sequence(const struct sk_buff *skb, u32 *tsoff)
{ {
return secure_tcp_sequence_number(ip_hdr(skb)->daddr, return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr, ip_hdr(skb)->saddr,
tcp_hdr(skb)->dest, tcp_hdr(skb)->dest,
tcp_hdr(skb)->source); tcp_hdr(skb)->source, tsoff);
} }
int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
...@@ -237,7 +237,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -237,7 +237,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr, tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
inet->inet_daddr, inet->inet_daddr,
inet->inet_sport, inet->inet_sport,
usin->sin_port); usin->sin_port,
&tp->tsoffset);
inet->inet_id = tp->write_seq ^ jiffies; inet->inet_id = tp->write_seq ^ jiffies;
...@@ -824,7 +825,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ...@@ -824,7 +825,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
tcp_v4_send_ack(sk, skb, seq, tcp_v4_send_ack(sk, skb, seq,
tcp_rsk(req)->rcv_nxt, tcp_rsk(req)->rcv_nxt,
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
tcp_time_stamp, tcp_time_stamp + tcp_rsk(req)->ts_off,
req->ts_recent, req->ts_recent,
0, 0,
tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr,
......
...@@ -532,7 +532,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, ...@@ -532,7 +532,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
newtp->rx_opt.ts_recent_stamp = 0; newtp->rx_opt.ts_recent_stamp = 0;
newtp->tcp_header_len = sizeof(struct tcphdr); newtp->tcp_header_len = sizeof(struct tcphdr);
} }
newtp->tsoffset = 0; newtp->tsoffset = treq->ts_off;
#ifdef CONFIG_TCP_MD5SIG #ifdef CONFIG_TCP_MD5SIG
newtp->md5sig_info = NULL; /*XXX*/ newtp->md5sig_info = NULL; /*XXX*/
if (newtp->af_specific->md5_lookup(sk, newsk)) if (newtp->af_specific->md5_lookup(sk, newsk))
...@@ -581,6 +581,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -581,6 +581,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (tmp_opt.saw_tstamp) { if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = req->ts_recent; tmp_opt.ts_recent = req->ts_recent;
if (tmp_opt.rcv_tsecr)
tmp_opt.rcv_tsecr -= tcp_rsk(req)->ts_off;
/* We do not store true stamp, but it is not required, /* We do not store true stamp, but it is not required,
* it can be estimated (approximately) * it can be estimated (approximately)
* from another data. * from another data.
......
...@@ -640,7 +640,7 @@ static unsigned int tcp_synack_options(struct request_sock *req, ...@@ -640,7 +640,7 @@ static unsigned int tcp_synack_options(struct request_sock *req,
} }
if (likely(ireq->tstamp_ok)) { if (likely(ireq->tstamp_ok)) {
opts->options |= OPTION_TS; opts->options |= OPTION_TS;
opts->tsval = tcp_skb_timestamp(skb); opts->tsval = tcp_skb_timestamp(skb) + tcp_rsk(req)->ts_off;
opts->tsecr = req->ts_recent; opts->tsecr = req->ts_recent;
remaining -= TCPOLEN_TSTAMP_ALIGNED; remaining -= TCPOLEN_TSTAMP_ALIGNED;
} }
......
...@@ -209,6 +209,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ...@@ -209,6 +209,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
treq->snt_synack.v64 = 0; treq->snt_synack.v64 = 0;
treq->rcv_isn = ntohl(th->seq) - 1; treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie; treq->snt_isn = cookie;
treq->ts_off = 0;
/* /*
* We need to lookup the dst_entry to get the correct window size. * We need to lookup the dst_entry to get the correct window size.
......
...@@ -101,12 +101,12 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) ...@@ -101,12 +101,12 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
} }
} }
static __u32 tcp_v6_init_sequence(const struct sk_buff *skb) static u32 tcp_v6_init_sequence(const struct sk_buff *skb, u32 *tsoff)
{ {
return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
ipv6_hdr(skb)->saddr.s6_addr32, ipv6_hdr(skb)->saddr.s6_addr32,
tcp_hdr(skb)->dest, tcp_hdr(skb)->dest,
tcp_hdr(skb)->source); tcp_hdr(skb)->source, tsoff);
} }
static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
...@@ -283,7 +283,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -283,7 +283,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
sk->sk_v6_daddr.s6_addr32, sk->sk_v6_daddr.s6_addr32,
inet->inet_sport, inet->inet_sport,
inet->inet_dport); inet->inet_dport,
&tp->tsoffset);
err = tcp_connect(sk); err = tcp_connect(sk);
if (err) if (err)
...@@ -956,7 +957,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ...@@ -956,7 +957,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
tcp_rsk(req)->rcv_nxt, tcp_rsk(req)->rcv_nxt,
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if, tcp_time_stamp + tcp_rsk(req)->ts_off,
req->ts_recent, sk->sk_bound_dev_if,
tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
0, 0); 0, 0);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment