blob: 7232274de334bbd0852b80fc286ee316e22946d7 [file] [log] [blame]
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +01001/*
2 * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
3 */
4
David S. Miller6e5714e2011-08-03 20:50:44 -07005#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/cryptohash.h>
8#include <linux/module.h>
9#include <linux/cache.h>
10#include <linux/random.h>
11#include <linux/hrtimer.h>
12#include <linux/ktime.h>
13#include <linux/string.h>
Hannes Frederic Sowae34c9a62013-10-19 21:48:59 +020014#include <linux/net.h>
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010015#include <linux/siphash.h>
David S. Miller6e5714e2011-08-03 20:50:44 -070016#include <net/secure_seq.h>
17
Fabio Estevamcb03db92013-10-05 17:56:59 -030018#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010019#include <linux/in6.h>
Florian Westphal25429d72016-12-01 11:32:07 +010020#include <net/tcp.h>
David S. Miller6e5714e2011-08-03 20:50:44 -070021
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010022static siphash_key_t net_secret __read_mostly;
Florian Westphal28ee1b72017-03-24 19:42:37 +010023static siphash_key_t ts_secret __read_mostly;
Eric Dumazet9a3bab62013-09-24 06:19:57 -070024
Hannes Frederic Sowa34d92d52013-10-23 08:44:50 +020025static __always_inline void net_secret_init(void)
David S. Miller6e5714e2011-08-03 20:50:44 -070026{
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010027 net_get_random_once(&net_secret, sizeof(net_secret));
David S. Miller6e5714e2011-08-03 20:50:44 -070028}
Eric Dumazet84b114b2017-05-05 06:56:54 -070029
30static __always_inline void ts_secret_init(void)
31{
32 net_get_random_once(&ts_secret, sizeof(ts_secret));
33}
Fabio Estevamcb03db92013-10-05 17:56:59 -030034#endif
David S. Miller6e5714e2011-08-03 20:50:44 -070035
Stephen Boyd681090902011-12-06 08:04:40 +000036#ifdef CONFIG_INET
David S. Miller6e5714e2011-08-03 20:50:44 -070037static u32 seq_scale(u32 seq)
38{
39 /*
40 * As close as possible to RFC 793, which
41 * suggests using a 250 kHz clock.
42 * Further reading shows this assumes 2 Mb/s networks.
43 * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
44 * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
45 * we also need to limit the resolution so that the u32 seq
46 * overlaps less than one time per MSL (2 minutes).
47 * Choosing a clock of 64 ns period is OK. (period of 274 s)
48 */
Eric Dumazetd2de8752014-08-22 18:32:09 -070049 return seq + (ktime_get_real_ns() >> 6);
David S. Miller6e5714e2011-08-03 20:50:44 -070050}
Stephen Boyd681090902011-12-06 08:04:40 +000051#endif
David S. Miller6e5714e2011-08-03 20:50:44 -070052
Eric Dumazetdfd56b82011-12-10 09:48:31 +000053#if IS_ENABLED(CONFIG_IPV6)
Eric Dumazet5d2ed052017-06-07 10:34:39 -070054u32 secure_tcpv6_ts_off(const struct net *net,
55 const __be32 *saddr, const __be32 *daddr)
Florian Westphal28ee1b72017-03-24 19:42:37 +010056{
57 const struct {
58 struct in6_addr saddr;
59 struct in6_addr daddr;
60 } __aligned(SIPHASH_ALIGNMENT) combined = {
61 .saddr = *(struct in6_addr *)saddr,
62 .daddr = *(struct in6_addr *)daddr,
63 };
64
Eric Dumazet5d2ed052017-06-07 10:34:39 -070065 if (net->ipv4.sysctl_tcp_timestamps != 1)
Florian Westphal28ee1b72017-03-24 19:42:37 +010066 return 0;
67
Eric Dumazet84b114b2017-05-05 06:56:54 -070068 ts_secret_init();
Florian Westphal28ee1b72017-03-24 19:42:37 +010069 return siphash(&combined, offsetofend(typeof(combined), daddr),
70 &ts_secret);
71}
Eric Dumazet84b114b2017-05-05 06:56:54 -070072EXPORT_SYMBOL(secure_tcpv6_ts_off);
Florian Westphal28ee1b72017-03-24 19:42:37 +010073
Eric Dumazet84b114b2017-05-05 06:56:54 -070074u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
75 __be16 sport, __be16 dport)
David S. Miller6e5714e2011-08-03 20:50:44 -070076{
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010077 const struct {
78 struct in6_addr saddr;
79 struct in6_addr daddr;
80 __be16 sport;
81 __be16 dport;
82 } __aligned(SIPHASH_ALIGNMENT) combined = {
83 .saddr = *(struct in6_addr *)saddr,
84 .daddr = *(struct in6_addr *)daddr,
85 .sport = sport,
86 .dport = dport
87 };
Eric Dumazet84b114b2017-05-05 06:56:54 -070088 u32 hash;
89
Eric Dumazet9a3bab62013-09-24 06:19:57 -070090 net_secret_init();
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010091 hash = siphash(&combined, offsetofend(typeof(combined), dport),
92 &net_secret);
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +010093 return seq_scale(hash);
David S. Miller6e5714e2011-08-03 20:50:44 -070094}
Eric Dumazet84b114b2017-05-05 06:56:54 -070095EXPORT_SYMBOL(secure_tcpv6_seq);
David S. Miller6e5714e2011-08-03 20:50:44 -070096
97u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
98 __be16 dport)
99{
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100100 const struct {
101 struct in6_addr saddr;
102 struct in6_addr daddr;
103 __be16 dport;
104 } __aligned(SIPHASH_ALIGNMENT) combined = {
105 .saddr = *(struct in6_addr *)saddr,
106 .daddr = *(struct in6_addr *)daddr,
107 .dport = dport
108 };
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700109 net_secret_init();
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100110 return siphash(&combined, offsetofend(typeof(combined), dport),
111 &net_secret);
David S. Miller6e5714e2011-08-03 20:50:44 -0700112}
Patrick McHardy58a317f2012-08-26 19:14:12 +0200113EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
David S. Miller6e5714e2011-08-03 20:50:44 -0700114#endif
115
116#ifdef CONFIG_INET
Eric Dumazet5d2ed052017-06-07 10:34:39 -0700117u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
Florian Westphal28ee1b72017-03-24 19:42:37 +0100118{
Eric Dumazet5d2ed052017-06-07 10:34:39 -0700119 if (net->ipv4.sysctl_tcp_timestamps != 1)
Florian Westphal28ee1b72017-03-24 19:42:37 +0100120 return 0;
121
Eric Dumazet84b114b2017-05-05 06:56:54 -0700122 ts_secret_init();
Florian Westphal28ee1b72017-03-24 19:42:37 +0100123 return siphash_2u32((__force u32)saddr, (__force u32)daddr,
124 &ts_secret);
125}
David S. Miller6e5714e2011-08-03 20:50:44 -0700126
Alexey Kodaneva30aad52017-03-09 13:53:55 +0300127/* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d),
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100128 * but fortunately, `sport' cannot be 0 in any circumstances. If this changes,
129 * it would be easy enough to have the former function use siphash_4u32, passing
130 * the arguments as separate u32.
131 */
Eric Dumazet84b114b2017-05-05 06:56:54 -0700132u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
133 __be16 sport, __be16 dport)
David S. Miller6e5714e2011-08-03 20:50:44 -0700134{
Eric Dumazet84b114b2017-05-05 06:56:54 -0700135 u32 hash;
136
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700137 net_secret_init();
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100138 hash = siphash_3u32((__force u32)saddr, (__force u32)daddr,
139 (__force u32)sport << 16 | (__force u32)dport,
140 &net_secret);
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100141 return seq_scale(hash);
David S. Miller6e5714e2011-08-03 20:50:44 -0700142}
143
144u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
145{
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700146 net_secret_init();
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100147 return siphash_3u32((__force u32)saddr, (__force u32)daddr,
148 (__force u16)dport, &net_secret);
David S. Miller6e5714e2011-08-03 20:50:44 -0700149}
150EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
151#endif
152
Igor Maravića3bf7ae2011-12-12 02:58:22 +0000153#if IS_ENABLED(CONFIG_IP_DCCP)
David S. Miller6e5714e2011-08-03 20:50:44 -0700154u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
155 __be16 sport, __be16 dport)
156{
David S. Miller6e5714e2011-08-03 20:50:44 -0700157 u64 seq;
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700158 net_secret_init();
Eric Dumazetc1ce1562017-01-11 18:10:37 -0800159 seq = siphash_3u32((__force u32)saddr, (__force u32)daddr,
160 (__force u32)sport << 16 | (__force u32)dport,
161 &net_secret);
Eric Dumazetd2de8752014-08-22 18:32:09 -0700162 seq += ktime_get_real_ns();
David S. Miller6e5714e2011-08-03 20:50:44 -0700163 seq &= (1ull << 48) - 1;
David S. Miller6e5714e2011-08-03 20:50:44 -0700164 return seq;
165}
166EXPORT_SYMBOL(secure_dccp_sequence_number);
167
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000168#if IS_ENABLED(CONFIG_IPV6)
David S. Miller6e5714e2011-08-03 20:50:44 -0700169u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
170 __be16 sport, __be16 dport)
171{
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100172 const struct {
173 struct in6_addr saddr;
174 struct in6_addr daddr;
175 __be16 sport;
176 __be16 dport;
177 } __aligned(SIPHASH_ALIGNMENT) combined = {
178 .saddr = *(struct in6_addr *)saddr,
179 .daddr = *(struct in6_addr *)daddr,
180 .sport = sport,
181 .dport = dport
182 };
David S. Miller6e5714e2011-08-03 20:50:44 -0700183 u64 seq;
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700184 net_secret_init();
Jason A. Donenfeld7cd23e52017-01-08 13:54:02 +0100185 seq = siphash(&combined, offsetofend(typeof(combined), dport),
186 &net_secret);
Eric Dumazetd2de8752014-08-22 18:32:09 -0700187 seq += ktime_get_real_ns();
David S. Miller6e5714e2011-08-03 20:50:44 -0700188 seq &= (1ull << 48) - 1;
David S. Miller6e5714e2011-08-03 20:50:44 -0700189 return seq;
190}
191EXPORT_SYMBOL(secure_dccpv6_sequence_number);
192#endif
193#endif