diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 545c2536e81e..a7d4f462a470 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -241,5 +241,6 @@ struct netns_ipv4 { atomic_t rt_genid; siphash_key_t ip_id_key; + int sysctl_tcp_wan_timestamps; }; #endif diff --git a/include/net/tcp.h b/include/net/tcp.h index 5957b5b0a542..f6bd5be10dd7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1188,6 +1188,24 @@ void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost, bool is_sack_reneg, struct rate_sample *rs); void tcp_rate_check_app_limited(struct sock *sk); +static inline int is_private_ip(__be32 daddr) { + __u8 i, j; +#if defined(__LITTLE_ENDIAN) + i = daddr & 0xFF; + j = (daddr >> 8) & 0xFF; +#elif defined(__BIG_ENDIAN) + i = (daddr >> 24) & 0xFF; + j = (daddr >> 16) & 0xFF; +#else +#error Unknown Endian +#endif + return i == 11 || i == 30 || i == 9 || i == 127 || i == 10 || + i == 21 || i == 22 || i == 26 || i == 28 || i == 29 || + (i == 172 && j >= 16 && j < 32) || + (i == 192 && j == 168) || + (i == 100 && j >= 64 && j <= 127 ); +} + static inline bool tcp_skb_sent_after(u64 t1, u64 t2, u32 seq1, u32 seq2) { return t1 > t2 || (t1 == t2 && after(seq1, seq2)); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index b66e564483c3..ee9f81edd36d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -580,6 +580,13 @@ static struct ctl_table ipv4_table[] = { .extra1 = &sysctl_fib_sync_mem_min, .extra2 = &sysctl_fib_sync_mem_max, }, + { + .procname = "tcp_wan_timestamps", + .data = &init_net.ipv4.sysctl_tcp_wan_timestamps, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .procname = "tcp_tw_ignore_syn_tsval_zero", .data = &sysctl_tcp_tw_ignore_syn_tsval_zero, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f6f6806ed55b..cb4c60341191 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4070,6 +4070,7 @@ void tcp_parse_options(const struct net *net, { const unsigned char *ptr; const struct tcphdr *th = tcp_hdr(skb); + struct iphdr *iph = ip_hdr(skb); int length = (th->doff * 4) - sizeof(struct tcphdr); ptr = (const unsigned char *)(th + 1); @@ -4124,7 +4125,8 @@ void tcp_parse_options(const struct net *net, case TCPOPT_TIMESTAMP: if ((opsize == TCPOLEN_TIMESTAMP) && ((estab && opt_rx->tstamp_ok) || - (!estab && READ_ONCE(net->ipv4.sysctl_tcp_timestamps)))) { + (!estab && READ_ONCE(net->ipv4.sysctl_tcp_timestamps) && + (net->ipv4.sysctl_tcp_wan_timestamps || is_private_ip(iph->saddr))))) { opt_rx->saw_tstamp = 1; opt_rx->rcv_tsval = get_unaligned_be32(ptr); opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);