* [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection
@ 2016-11-30 12:28 Florian Westphal
2016-11-30 12:28 ` [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off Florian Westphal
2016-12-01 7:05 ` [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection Yuchung Cheng
0 siblings, 2 replies; 5+ messages in thread
From: Florian Westphal @ 2016-11-30 12:28 UTC (permalink / raw)
To: netdev; +Cc: Florian Westphal
jiffies based timestamps allow for easy inference of number of devices
behind NAT translators and also makes tracking of hosts simpler.
commit ceaa1fef65a7c2e ("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>
---
No changes since v1, preserved Erics ack.
include/linux/tcp.h | 1 +
include/net/secure_seq.h | 8 ++++----
include/net/tcp.h | 2 +-
net/core/secure_seq.c | 10 ++++++----
net/ipv4/syncookies.c | 1 +
net/ipv4/tcp_input.c | 7 ++++++-
net/ipv4/tcp_ipv4.c | 9 +++++----
net/ipv4/tcp_minisocks.c | 4 +++-
net/ipv4/tcp_output.c | 2 +-
net/ipv6/syncookies.c | 1 +
net/ipv6/tcp_ipv6.c | 10 ++++++----
11 files changed, 35 insertions(+), 20 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 32a7c7e35b71..2408bcc579f1 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -123,6 +123,7 @@ struct tcp_request_sock {
u32 txhash;
u32 rcv_isn;
u32 snt_isn;
+ u32 ts_off;
u32 last_oow_ack_time; /* last SYNACK */
u32 rcv_nxt; /* the ack # by SYNACK. For
* FastOpen it's the seq#
diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
index 3f36d45b714a..0caee631a836 100644
--- a/include/net/secure_seq.h
+++ b/include/net/secure_seq.h
@@ -6,10 +6,10 @@
u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
__be16 dport);
-__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport);
-__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
- __be16 sport, __be16 dport);
+u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport, u32 *tsoff);
+u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
+ __be16 sport, __be16 dport, u32 *tsoff);
u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport);
u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 7de80739adab..1c09d909bd43 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1809,7 +1809,7 @@ struct tcp_request_sock_ops {
struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl,
const struct request_sock *req,
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,
struct flowi *fl, struct request_sock *req,
struct tcp_fastopen_cookie *foc,
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
index fd3ce461fbe6..a8d6062cbb4a 100644
--- a/net/core/secure_seq.c
+++ b/net/core/secure_seq.c
@@ -40,8 +40,8 @@ static u32 seq_scale(u32 seq)
#endif
#if IS_ENABLED(CONFIG_IPV6)
-__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
- __be16 sport, __be16 dport)
+u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
+ __be16 sport, __be16 dport, u32 *tsoff)
{
u32 secret[MD5_MESSAGE_BYTES / 4];
u32 hash[MD5_DIGEST_WORDS];
@@ -58,6 +58,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
md5_transform(hash, secret);
+ *tsoff = hash[1];
return seq_scale(hash[0]);
}
EXPORT_SYMBOL(secure_tcpv6_sequence_number);
@@ -86,8 +87,8 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#ifdef CONFIG_INET
-__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport)
+u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport, u32 *tsoff)
{
u32 hash[MD5_DIGEST_WORDS];
@@ -99,6 +100,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
md5_transform(hash, net_secret);
+ *tsoff = hash[1];
return seq_scale(hash[0]);
}
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 0dc6286272aa..3e88467d70ee 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -334,6 +334,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
treq = tcp_rsk(req);
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;
+ treq->ts_off = 0;
req->mss = mss;
ireq->ir_num = ntohs(th->dest);
ireq->ir_rmt_port = th->source;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 22e6a2097ff6..1b1921c71f7c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6301,6 +6301,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
goto drop;
tcp_rsk(req)->af_specific = af_ops;
+ tcp_rsk(req)->ts_off = 0;
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = af_ops->mss_clamp;
@@ -6322,6 +6323,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
if (security_inet_conn_request(sk, skb, req))
goto drop_and_free;
+ if (isn && tmp_opt.tstamp_ok)
+ af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
+
if (!want_cookie && !isn) {
/* VJ's idea. We save last timestamp seen
* from the destination in peer table, when entering
@@ -6362,7 +6366,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
goto drop_and_release;
}
- isn = af_ops->init_seq(skb);
+ isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
}
if (!dst) {
dst = af_ops->route_req(sk, &fl, req, NULL);
@@ -6374,6 +6378,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
if (want_cookie) {
isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
+ tcp_rsk(req)->ts_off = 0;
req->cookie_ts = tmp_opt.tstamp_ok;
if (!tmp_opt.tstamp_ok)
inet_rsk(req)->ecn_ok = 0;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 5555eb86e549..b50f05905ced 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -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;
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,
ip_hdr(skb)->saddr,
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)
@@ -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,
inet->inet_daddr,
inet->inet_sport,
- usin->sin_port);
+ usin->sin_port,
+ &tp->tsoffset);
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,
tcp_v4_send_ack(sk, skb, seq,
tcp_rsk(req)->rcv_nxt,
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
- tcp_time_stamp,
+ tcp_time_stamp + tcp_rsk(req)->ts_off,
req->ts_recent,
0,
tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr,
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 6234ebaa7db1..28ce5ee831f5 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -532,7 +532,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
newtp->rx_opt.ts_recent_stamp = 0;
newtp->tcp_header_len = sizeof(struct tcphdr);
}
- newtp->tsoffset = 0;
+ newtp->tsoffset = treq->ts_off;
#ifdef CONFIG_TCP_MD5SIG
newtp->md5sig_info = NULL; /*XXX*/
if (newtp->af_specific->md5_lookup(sk, newsk))
@@ -581,6 +581,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (tmp_opt.saw_tstamp) {
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,
* it can be estimated (approximately)
* from another data.
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 19105b46a304..1b6d5f34bf45 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -640,7 +640,7 @@ static unsigned int tcp_synack_options(struct request_sock *req,
}
if (likely(ireq->tstamp_ok)) {
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;
remaining -= TCPOLEN_TSTAMP_ALIGNED;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 97830a6a9cbb..a4d49760bf43 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -209,6 +209,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
treq->snt_synack.v64 = 0;
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;
+ treq->ts_off = 0;
/*
* We need to lookup the dst_entry to get the correct window size.
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 28ec0a2e7b72..a2185a214abc 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -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,
ipv6_hdr(skb)->saddr.s6_addr32,
tcp_hdr(skb)->dest,
- tcp_hdr(skb)->source);
+ tcp_hdr(skb)->source, tsoff);
}
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,
sk->sk_v6_daddr.s6_addr32,
inet->inet_sport,
- inet->inet_dport);
+ inet->inet_dport,
+ &tp->tsoffset);
err = tcp_connect(sk);
if (err)
@@ -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)->rcv_nxt,
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),
0, 0);
}
--
2.7.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off
2016-11-30 12:28 [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection Florian Westphal
@ 2016-11-30 12:28 ` Florian Westphal
2016-12-01 7:12 ` Yuchung Cheng
2016-12-01 7:05 ` [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection Yuchung Cheng
1 sibling, 1 reply; 5+ messages in thread
From: Florian Westphal @ 2016-11-30 12:28 UTC (permalink / raw)
To: netdev; +Cc: Florian Westphal
Eric says: "By looking at tcpdump, and TS val of xmit packets of multiple
flows, we can deduct the relative qdisc delays (think of fq pacing).
This should work even if we have one flow per remote peer."
Having random per flow (or host) offsets doesn't allow that anymore so add
a way to turn this off.
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
change since v2: do check in secure_tcpv4/6_sequence_number so outgoing
syn packets won't have a random offset either in if randomization is off.
Tested:
sysctl_tcp_timestamps==1, tcpdump on lo, both ends have same values.
Documentation/networking/ip-sysctl.txt | 9 +++++++--
net/core/secure_seq.c | 5 +++--
net/ipv4/tcp_input.c | 3 ++-
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 5af48dd7c5fc..de2448313799 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -610,8 +610,13 @@ tcp_syn_retries - INTEGER
with the current initial RTO of 1second. With this the final timeout
for an active TCP connection attempt will happen after 127seconds.
-tcp_timestamps - BOOLEAN
- Enable timestamps as defined in RFC1323.
+tcp_timestamps - INTEGER
+Enable timestamps as defined in RFC1323.
+ 0: Disabled.
+ 1: Enable timestamps as defined in RFC1323.
+ 2: Like 1, but also use a random offset for each connection
+ rather than only using the current time.
+ Default: 2
tcp_min_tso_segs - INTEGER
Minimal number of segments per TSO frame.
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
index a8d6062cbb4a..36addd3d9633 100644
--- a/net/core/secure_seq.c
+++ b/net/core/secure_seq.c
@@ -12,6 +12,7 @@
#include <net/secure_seq.h>
#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
+#include <net/tcp.h>
#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
@@ -58,7 +59,7 @@ u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
md5_transform(hash, secret);
- *tsoff = hash[1];
+ *tsoff = sysctl_tcp_timestamps == 2 ? hash[1] : 0;
return seq_scale(hash[0]);
}
EXPORT_SYMBOL(secure_tcpv6_sequence_number);
@@ -100,7 +101,7 @@ u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
md5_transform(hash, net_secret);
- *tsoff = hash[1];
+ *tsoff = sysctl_tcp_timestamps == 2 ? hash[1] : 0;
return seq_scale(hash[0]);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1b1921c71f7c..5f6d4efd2551 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -76,7 +76,7 @@
#include <asm/unaligned.h>
#include <linux/errqueue.h>
-int sysctl_tcp_timestamps __read_mostly = 1;
+int sysctl_tcp_timestamps __read_mostly = 2;
int sysctl_tcp_window_scaling __read_mostly = 1;
int sysctl_tcp_sack __read_mostly = 1;
int sysctl_tcp_fack __read_mostly = 1;
@@ -85,6 +85,7 @@ int sysctl_tcp_dsack __read_mostly = 1;
int sysctl_tcp_app_win __read_mostly = 31;
int sysctl_tcp_adv_win_scale __read_mostly = 1;
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
+EXPORT_SYMBOL(sysctl_tcp_timestamps);
/* rfc5961 challenge ack rate limiting */
int sysctl_tcp_challenge_ack_limit = 1000;
--
2.7.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection
2016-11-30 12:28 [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection Florian Westphal
2016-11-30 12:28 ` [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off Florian Westphal
@ 2016-12-01 7:05 ` Yuchung Cheng
1 sibling, 0 replies; 5+ messages in thread
From: Yuchung Cheng @ 2016-12-01 7:05 UTC (permalink / raw)
To: Florian Westphal; +Cc: netdev
On Wed, Nov 30, 2016 at 4:28 AM, Florian Westphal <fw@strlen.de> wrote:
>
> jiffies based timestamps allow for easy inference of number of devices
> behind NAT translators and also makes tracking of hosts simpler.
>
> commit ceaa1fef65a7c2e ("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>
Nice feature!
>
> No changes since v1, preserved Erics ack.
>
> include/linux/tcp.h | 1 +
> include/net/secure_seq.h | 8 ++++----
> include/net/tcp.h | 2 +-
> net/core/secure_seq.c | 10 ++++++----
> net/ipv4/syncookies.c | 1 +
> net/ipv4/tcp_input.c | 7 ++++++-
> net/ipv4/tcp_ipv4.c | 9 +++++----
> net/ipv4/tcp_minisocks.c | 4 +++-
> net/ipv4/tcp_output.c | 2 +-
> net/ipv6/syncookies.c | 1 +
> net/ipv6/tcp_ipv6.c | 10 ++++++----
> 11 files changed, 35 insertions(+), 20 deletions(-)
>
> diff --git a/include/linux/tcp.h b/include/linux/tcp.h
> index 32a7c7e35b71..2408bcc579f1 100644
> --- a/include/linux/tcp.h
> +++ b/include/linux/tcp.h
> @@ -123,6 +123,7 @@ struct tcp_request_sock {
> u32 txhash;
> u32 rcv_isn;
> u32 snt_isn;
> + u32 ts_off;
> u32 last_oow_ack_time; /* last SYNACK */
> u32 rcv_nxt; /* the ack # by SYNACK. For
> * FastOpen it's the seq#
> diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
> index 3f36d45b714a..0caee631a836 100644
> --- a/include/net/secure_seq.h
> +++ b/include/net/secure_seq.h
> @@ -6,10 +6,10 @@
> u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
> u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
> __be16 dport);
> -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
> - __be16 sport, __be16 dport);
> -__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
> - __be16 sport, __be16 dport);
> +u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
> + __be16 sport, __be16 dport, u32 *tsoff);
> +u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
> + __be16 sport, __be16 dport, u32 *tsoff);
> u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
> __be16 sport, __be16 dport);
> u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 7de80739adab..1c09d909bd43 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -1809,7 +1809,7 @@ struct tcp_request_sock_ops {
> struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl,
> const struct request_sock *req,
> 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,
> struct flowi *fl, struct request_sock *req,
> struct tcp_fastopen_cookie *foc,
> diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
> index fd3ce461fbe6..a8d6062cbb4a 100644
> --- a/net/core/secure_seq.c
> +++ b/net/core/secure_seq.c
> @@ -40,8 +40,8 @@ static u32 seq_scale(u32 seq)
> #endif
>
> #if IS_ENABLED(CONFIG_IPV6)
> -__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
> - __be16 sport, __be16 dport)
> +u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
> + __be16 sport, __be16 dport, u32 *tsoff)
> {
> u32 secret[MD5_MESSAGE_BYTES / 4];
> u32 hash[MD5_DIGEST_WORDS];
> @@ -58,6 +58,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
>
> md5_transform(hash, secret);
>
> + *tsoff = hash[1];
> return seq_scale(hash[0]);
> }
> EXPORT_SYMBOL(secure_tcpv6_sequence_number);
> @@ -86,8 +87,8 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
>
> #ifdef CONFIG_INET
>
> -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
> - __be16 sport, __be16 dport)
> +u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
> + __be16 sport, __be16 dport, u32 *tsoff)
> {
> u32 hash[MD5_DIGEST_WORDS];
>
> @@ -99,6 +100,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
>
> md5_transform(hash, net_secret);
>
> + *tsoff = hash[1];
> return seq_scale(hash[0]);
> }
>
> diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
> index 0dc6286272aa..3e88467d70ee 100644
> --- a/net/ipv4/syncookies.c
> +++ b/net/ipv4/syncookies.c
> @@ -334,6 +334,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
> treq = tcp_rsk(req);
> treq->rcv_isn = ntohl(th->seq) - 1;
> treq->snt_isn = cookie;
> + treq->ts_off = 0;
> req->mss = mss;
> ireq->ir_num = ntohs(th->dest);
> ireq->ir_rmt_port = th->source;
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 22e6a2097ff6..1b1921c71f7c 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -6301,6 +6301,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
> goto drop;
>
> tcp_rsk(req)->af_specific = af_ops;
> + tcp_rsk(req)->ts_off = 0;
>
> tcp_clear_options(&tmp_opt);
> tmp_opt.mss_clamp = af_ops->mss_clamp;
> @@ -6322,6 +6323,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
> if (security_inet_conn_request(sk, skb, req))
> goto drop_and_free;
>
> + if (isn && tmp_opt.tstamp_ok)
> + af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
> +
> if (!want_cookie && !isn) {
> /* VJ's idea. We save last timestamp seen
> * from the destination in peer table, when entering
> @@ -6362,7 +6366,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
> goto drop_and_release;
> }
>
> - isn = af_ops->init_seq(skb);
> + isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
> }
> if (!dst) {
> dst = af_ops->route_req(sk, &fl, req, NULL);
> @@ -6374,6 +6378,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
>
> if (want_cookie) {
> isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
> + tcp_rsk(req)->ts_off = 0;
> req->cookie_ts = tmp_opt.tstamp_ok;
> if (!tmp_opt.tstamp_ok)
> inet_rsk(req)->ecn_ok = 0;
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index 5555eb86e549..b50f05905ced 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -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;
> 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,
> ip_hdr(skb)->saddr,
> 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)
> @@ -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,
> inet->inet_daddr,
> inet->inet_sport,
> - usin->sin_port);
> + usin->sin_port,
> + &tp->tsoffset);
>
> 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,
> tcp_v4_send_ack(sk, skb, seq,
> tcp_rsk(req)->rcv_nxt,
> req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
> - tcp_time_stamp,
> + tcp_time_stamp + tcp_rsk(req)->ts_off,
> req->ts_recent,
> 0,
> tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr,
> diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
> index 6234ebaa7db1..28ce5ee831f5 100644
> --- a/net/ipv4/tcp_minisocks.c
> +++ b/net/ipv4/tcp_minisocks.c
> @@ -532,7 +532,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
> newtp->rx_opt.ts_recent_stamp = 0;
> newtp->tcp_header_len = sizeof(struct tcphdr);
> }
> - newtp->tsoffset = 0;
> + newtp->tsoffset = treq->ts_off;
> #ifdef CONFIG_TCP_MD5SIG
> newtp->md5sig_info = NULL; /*XXX*/
> if (newtp->af_specific->md5_lookup(sk, newsk))
> @@ -581,6 +581,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
>
> if (tmp_opt.saw_tstamp) {
> 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,
> * it can be estimated (approximately)
> * from another data.
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> index 19105b46a304..1b6d5f34bf45 100644
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
> @@ -640,7 +640,7 @@ static unsigned int tcp_synack_options(struct request_sock *req,
> }
> if (likely(ireq->tstamp_ok)) {
> 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;
> remaining -= TCPOLEN_TSTAMP_ALIGNED;
> }
> diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
> index 97830a6a9cbb..a4d49760bf43 100644
> --- a/net/ipv6/syncookies.c
> +++ b/net/ipv6/syncookies.c
> @@ -209,6 +209,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
> treq->snt_synack.v64 = 0;
> treq->rcv_isn = ntohl(th->seq) - 1;
> treq->snt_isn = cookie;
> + treq->ts_off = 0;
>
> /*
> * We need to lookup the dst_entry to get the correct window size.
> diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
> index 28ec0a2e7b72..a2185a214abc 100644
> --- a/net/ipv6/tcp_ipv6.c
> +++ b/net/ipv6/tcp_ipv6.c
> @@ -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,
> ipv6_hdr(skb)->saddr.s6_addr32,
> tcp_hdr(skb)->dest,
> - tcp_hdr(skb)->source);
> + tcp_hdr(skb)->source, tsoff);
> }
>
> 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,
> sk->sk_v6_daddr.s6_addr32,
> inet->inet_sport,
> - inet->inet_dport);
> + inet->inet_dport,
> + &tp->tsoffset);
>
> err = tcp_connect(sk);
> if (err)
> @@ -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)->rcv_nxt,
> 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),
> 0, 0);
> }
> --
> 2.7.3
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off
2016-11-30 12:28 ` [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off Florian Westphal
@ 2016-12-01 7:12 ` Yuchung Cheng
2016-12-01 9:40 ` Florian Westphal
0 siblings, 1 reply; 5+ messages in thread
From: Yuchung Cheng @ 2016-12-01 7:12 UTC (permalink / raw)
To: Florian Westphal; +Cc: netdev
On Wed, Nov 30, 2016 at 4:28 AM, Florian Westphal <fw@strlen.de> wrote:
> Eric says: "By looking at tcpdump, and TS val of xmit packets of multiple
> flows, we can deduct the relative qdisc delays (think of fq pacing).
> This should work even if we have one flow per remote peer."
>
> Having random per flow (or host) offsets doesn't allow that anymore so add
> a way to turn this off.
>
> Suggested-by: Eric Dumazet <edumazet@google.com>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
> change since v2: do check in secure_tcpv4/6_sequence_number so outgoing
> syn packets won't have a random offset either in if randomization is off.
>
> Tested:
> sysctl_tcp_timestamps==1, tcpdump on lo, both ends have same values.
>
> Documentation/networking/ip-sysctl.txt | 9 +++++++--
> net/core/secure_seq.c | 5 +++--
> net/ipv4/tcp_input.c | 3 ++-
> 3 files changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
> index 5af48dd7c5fc..de2448313799 100644
> --- a/Documentation/networking/ip-sysctl.txt
> +++ b/Documentation/networking/ip-sysctl.txt
> @@ -610,8 +610,13 @@ tcp_syn_retries - INTEGER
> with the current initial RTO of 1second. With this the final timeout
> for an active TCP connection attempt will happen after 127seconds.
>
> -tcp_timestamps - BOOLEAN
> - Enable timestamps as defined in RFC1323.
> +tcp_timestamps - INTEGER
> +Enable timestamps as defined in RFC1323.
> + 0: Disabled.
> + 1: Enable timestamps as defined in RFC1323.
> + 2: Like 1, but also use a random offset for each connection
> + rather than only using the current time.
> + Default: 2
Small suggestion: I suspect host/server configs manually set the knob
to 1. Perhaps swap 1 and 2 to maximize the coverage of this new
feature?
>
> tcp_min_tso_segs - INTEGER
> Minimal number of segments per TSO frame.
> diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
> index a8d6062cbb4a..36addd3d9633 100644
> --- a/net/core/secure_seq.c
> +++ b/net/core/secure_seq.c
> @@ -12,6 +12,7 @@
> #include <net/secure_seq.h>
>
> #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
> +#include <net/tcp.h>
> #define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
>
> static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
> @@ -58,7 +59,7 @@ u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
>
> md5_transform(hash, secret);
>
> - *tsoff = hash[1];
> + *tsoff = sysctl_tcp_timestamps == 2 ? hash[1] : 0;
> return seq_scale(hash[0]);
> }
> EXPORT_SYMBOL(secure_tcpv6_sequence_number);
> @@ -100,7 +101,7 @@ u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
>
> md5_transform(hash, net_secret);
>
> - *tsoff = hash[1];
> + *tsoff = sysctl_tcp_timestamps == 2 ? hash[1] : 0;
> return seq_scale(hash[0]);
> }
>
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 1b1921c71f7c..5f6d4efd2551 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -76,7 +76,7 @@
> #include <asm/unaligned.h>
> #include <linux/errqueue.h>
>
> -int sysctl_tcp_timestamps __read_mostly = 1;
> +int sysctl_tcp_timestamps __read_mostly = 2;
> int sysctl_tcp_window_scaling __read_mostly = 1;
> int sysctl_tcp_sack __read_mostly = 1;
> int sysctl_tcp_fack __read_mostly = 1;
> @@ -85,6 +85,7 @@ int sysctl_tcp_dsack __read_mostly = 1;
> int sysctl_tcp_app_win __read_mostly = 31;
> int sysctl_tcp_adv_win_scale __read_mostly = 1;
> EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
> +EXPORT_SYMBOL(sysctl_tcp_timestamps);
>
> /* rfc5961 challenge ack rate limiting */
> int sysctl_tcp_challenge_ack_limit = 1000;
> --
> 2.7.3
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off
2016-12-01 7:12 ` Yuchung Cheng
@ 2016-12-01 9:40 ` Florian Westphal
0 siblings, 0 replies; 5+ messages in thread
From: Florian Westphal @ 2016-12-01 9:40 UTC (permalink / raw)
To: Yuchung Cheng; +Cc: Florian Westphal, netdev
Yuchung Cheng <ycheng@google.com> wrote:
> > +tcp_timestamps - INTEGER
> > +Enable timestamps as defined in RFC1323.
> > + 0: Disabled.
> > + 1: Enable timestamps as defined in RFC1323.
> > + 2: Like 1, but also use a random offset for each connection
> > + rather than only using the current time.
> > + Default: 2
> Small suggestion: I suspect host/server configs manually set the knob
> to 1. Perhaps swap 1 and 2 to maximize the coverage of this new
> feature?
You mean:
1 (default): randomize
2: don't randomize?
I think its good idea, will send v3. Thanks!
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2016-12-01 9:43 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-30 12:28 [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection Florian Westphal
2016-11-30 12:28 ` [PATCH net-next v2 2/2] tcp: allow to turn tcp timestamp randomization off Florian Westphal
2016-12-01 7:12 ` Yuchung Cheng
2016-12-01 9:40 ` Florian Westphal
2016-12-01 7:05 ` [PATCH net-next v2 1/2] tcp: randomize tcp timestamp offsets for each connection Yuchung Cheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).