Skip to content

Commit 95a22ca

Browse files
Florian Westphaldavem330
authored andcommitted
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 ceaa1fe ("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: Florian Westphal <fw@strlen.de> Acked-by: Eric Dumazet <edumazet@google.com> Acked-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 7df5358 commit 95a22ca

File tree

11 files changed

+35
-20
lines changed

11 files changed

+35
-20
lines changed

include/linux/tcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ struct tcp_request_sock {
123123
u32 txhash;
124124
u32 rcv_isn;
125125
u32 snt_isn;
126+
u32 ts_off;
126127
u32 last_oow_ack_time; /* last SYNACK */
127128
u32 rcv_nxt; /* the ack # by SYNACK. For
128129
* FastOpen it's the seq#

include/net/secure_seq.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
77
u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
88
__be16 dport);
9-
__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
10-
__be16 sport, __be16 dport);
11-
__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
12-
__be16 sport, __be16 dport);
9+
u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
10+
__be16 sport, __be16 dport, u32 *tsoff);
11+
u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
12+
__be16 sport, __be16 dport, u32 *tsoff);
1313
u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
1414
__be16 sport, __be16 dport);
1515
u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,

include/net/tcp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,7 @@ struct tcp_request_sock_ops {
18271827
struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl,
18281828
const struct request_sock *req,
18291829
bool *strict);
1830-
__u32 (*init_seq)(const struct sk_buff *skb);
1830+
__u32 (*init_seq)(const struct sk_buff *skb, u32 *tsoff);
18311831
int (*send_synack)(const struct sock *sk, struct dst_entry *dst,
18321832
struct flowi *fl, struct request_sock *req,
18331833
struct tcp_fastopen_cookie *foc,

net/core/secure_seq.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ static u32 seq_scale(u32 seq)
4040
#endif
4141

4242
#if IS_ENABLED(CONFIG_IPV6)
43-
__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
44-
__be16 sport, __be16 dport)
43+
u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
44+
__be16 sport, __be16 dport, u32 *tsoff)
4545
{
4646
u32 secret[MD5_MESSAGE_BYTES / 4];
4747
u32 hash[MD5_DIGEST_WORDS];
@@ -58,6 +58,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
5858

5959
md5_transform(hash, secret);
6060

61+
*tsoff = hash[1];
6162
return seq_scale(hash[0]);
6263
}
6364
EXPORT_SYMBOL(secure_tcpv6_sequence_number);
@@ -86,8 +87,8 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
8687

8788
#ifdef CONFIG_INET
8889

89-
__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
90-
__be16 sport, __be16 dport)
90+
u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
91+
__be16 sport, __be16 dport, u32 *tsoff)
9192
{
9293
u32 hash[MD5_DIGEST_WORDS];
9394

@@ -99,6 +100,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
99100

100101
md5_transform(hash, net_secret);
101102

103+
*tsoff = hash[1];
102104
return seq_scale(hash[0]);
103105
}
104106

net/ipv4/syncookies.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
334334
treq = tcp_rsk(req);
335335
treq->rcv_isn = ntohl(th->seq) - 1;
336336
treq->snt_isn = cookie;
337+
treq->ts_off = 0;
337338
req->mss = mss;
338339
ireq->ir_num = ntohs(th->dest);
339340
ireq->ir_rmt_port = th->source;

net/ipv4/tcp_input.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6307,6 +6307,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
63076307
goto drop;
63086308

63096309
tcp_rsk(req)->af_specific = af_ops;
6310+
tcp_rsk(req)->ts_off = 0;
63106311

63116312
tcp_clear_options(&tmp_opt);
63126313
tmp_opt.mss_clamp = af_ops->mss_clamp;
@@ -6328,6 +6329,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
63286329
if (security_inet_conn_request(sk, skb, req))
63296330
goto drop_and_free;
63306331

6332+
if (isn && tmp_opt.tstamp_ok)
6333+
af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
6334+
63316335
if (!want_cookie && !isn) {
63326336
/* VJ's idea. We save last timestamp seen
63336337
* from the destination in peer table, when entering
@@ -6368,7 +6372,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
63686372
goto drop_and_release;
63696373
}
63706374

6371-
isn = af_ops->init_seq(skb);
6375+
isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
63726376
}
63736377
if (!dst) {
63746378
dst = af_ops->route_req(sk, &fl, req, NULL);
@@ -6380,6 +6384,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
63806384

63816385
if (want_cookie) {
63826386
isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
6387+
tcp_rsk(req)->ts_off = 0;
63836388
req->cookie_ts = tmp_opt.tstamp_ok;
63846389
if (!tmp_opt.tstamp_ok)
63856390
inet_rsk(req)->ecn_ok = 0;

net/ipv4/tcp_ipv4.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
9595
struct inet_hashinfo tcp_hashinfo;
9696
EXPORT_SYMBOL(tcp_hashinfo);
9797

98-
static __u32 tcp_v4_init_sequence(const struct sk_buff *skb)
98+
static u32 tcp_v4_init_sequence(const struct sk_buff *skb, u32 *tsoff)
9999
{
100100
return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
101101
ip_hdr(skb)->saddr,
102102
tcp_hdr(skb)->dest,
103-
tcp_hdr(skb)->source);
103+
tcp_hdr(skb)->source, tsoff);
104104
}
105105

106106
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)
237237
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
238238
inet->inet_daddr,
239239
inet->inet_sport,
240-
usin->sin_port);
240+
usin->sin_port,
241+
&tp->tsoffset);
241242

242243
inet->inet_id = tp->write_seq ^ jiffies;
243244

@@ -824,7 +825,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
824825
tcp_v4_send_ack(sk, skb, seq,
825826
tcp_rsk(req)->rcv_nxt,
826827
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
827-
tcp_time_stamp,
828+
tcp_time_stamp + tcp_rsk(req)->ts_off,
828829
req->ts_recent,
829830
0,
830831
tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr,

net/ipv4/tcp_minisocks.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
532532
newtp->rx_opt.ts_recent_stamp = 0;
533533
newtp->tcp_header_len = sizeof(struct tcphdr);
534534
}
535-
newtp->tsoffset = 0;
535+
newtp->tsoffset = treq->ts_off;
536536
#ifdef CONFIG_TCP_MD5SIG
537537
newtp->md5sig_info = NULL; /*XXX*/
538538
if (newtp->af_specific->md5_lookup(sk, newsk))
@@ -581,6 +581,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
581581

582582
if (tmp_opt.saw_tstamp) {
583583
tmp_opt.ts_recent = req->ts_recent;
584+
if (tmp_opt.rcv_tsecr)
585+
tmp_opt.rcv_tsecr -= tcp_rsk(req)->ts_off;
584586
/* We do not store true stamp, but it is not required,
585587
* it can be estimated (approximately)
586588
* from another data.

net/ipv4/tcp_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ static unsigned int tcp_synack_options(struct request_sock *req,
640640
}
641641
if (likely(ireq->tstamp_ok)) {
642642
opts->options |= OPTION_TS;
643-
opts->tsval = tcp_skb_timestamp(skb);
643+
opts->tsval = tcp_skb_timestamp(skb) + tcp_rsk(req)->ts_off;
644644
opts->tsecr = req->ts_recent;
645645
remaining -= TCPOLEN_TSTAMP_ALIGNED;
646646
}

net/ipv6/syncookies.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
209209
treq->snt_synack.v64 = 0;
210210
treq->rcv_isn = ntohl(th->seq) - 1;
211211
treq->snt_isn = cookie;
212+
treq->ts_off = 0;
212213

213214
/*
214215
* We need to lookup the dst_entry to get the correct window size.

net/ipv6/tcp_ipv6.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
101101
}
102102
}
103103

104-
static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
104+
static u32 tcp_v6_init_sequence(const struct sk_buff *skb, u32 *tsoff)
105105
{
106106
return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
107107
ipv6_hdr(skb)->saddr.s6_addr32,
108108
tcp_hdr(skb)->dest,
109-
tcp_hdr(skb)->source);
109+
tcp_hdr(skb)->source, tsoff);
110110
}
111111

112112
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,
283283
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
284284
sk->sk_v6_daddr.s6_addr32,
285285
inet->inet_sport,
286-
inet->inet_dport);
286+
inet->inet_dport,
287+
&tp->tsoffset);
287288

288289
err = tcp_connect(sk);
289290
if (err)
@@ -956,7 +957,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
956957
tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
957958
tcp_rsk(req)->rcv_nxt,
958959
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
959-
tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
960+
tcp_time_stamp + tcp_rsk(req)->ts_off,
961+
req->ts_recent, sk->sk_bound_dev_if,
960962
tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
961963
0, 0);
962964
}

0 commit comments

Comments
 (0)