at v4.13 5.0 kB view raw
1/* 2 * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 3 */ 4 5#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> 14#include <linux/net.h> 15#include <linux/siphash.h> 16#include <net/secure_seq.h> 17 18#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET) 19#include <linux/in6.h> 20#include <net/tcp.h> 21 22static siphash_key_t net_secret __read_mostly; 23static siphash_key_t ts_secret __read_mostly; 24 25static __always_inline void net_secret_init(void) 26{ 27 net_get_random_once(&net_secret, sizeof(net_secret)); 28} 29 30static __always_inline void ts_secret_init(void) 31{ 32 net_get_random_once(&ts_secret, sizeof(ts_secret)); 33} 34#endif 35 36#ifdef CONFIG_INET 37static 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 */ 49 return seq + (ktime_get_real_ns() >> 6); 50} 51#endif 52 53#if IS_ENABLED(CONFIG_IPV6) 54u32 secure_tcpv6_ts_off(const struct net *net, 55 const __be32 *saddr, const __be32 *daddr) 56{ 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 65 if (net->ipv4.sysctl_tcp_timestamps != 1) 66 return 0; 67 68 ts_secret_init(); 69 return siphash(&combined, offsetofend(typeof(combined), daddr), 70 &ts_secret); 71} 72EXPORT_SYMBOL(secure_tcpv6_ts_off); 73 74u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr, 75 __be16 sport, __be16 dport) 76{ 77 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 }; 88 u32 hash; 89 90 net_secret_init(); 91 hash = siphash(&combined, offsetofend(typeof(combined), dport), 92 &net_secret); 93 return seq_scale(hash); 94} 95EXPORT_SYMBOL(secure_tcpv6_seq); 96 97u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, 98 __be16 dport) 99{ 100 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 }; 109 net_secret_init(); 110 return siphash(&combined, offsetofend(typeof(combined), dport), 111 &net_secret); 112} 113EXPORT_SYMBOL(secure_ipv6_port_ephemeral); 114#endif 115 116#ifdef CONFIG_INET 117u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr) 118{ 119 if (net->ipv4.sysctl_tcp_timestamps != 1) 120 return 0; 121 122 ts_secret_init(); 123 return siphash_2u32((__force u32)saddr, (__force u32)daddr, 124 &ts_secret); 125} 126 127/* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), 128 * 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 */ 132u32 secure_tcp_seq(__be32 saddr, __be32 daddr, 133 __be16 sport, __be16 dport) 134{ 135 u32 hash; 136 137 net_secret_init(); 138 hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, 139 (__force u32)sport << 16 | (__force u32)dport, 140 &net_secret); 141 return seq_scale(hash); 142} 143 144u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) 145{ 146 net_secret_init(); 147 return siphash_3u32((__force u32)saddr, (__force u32)daddr, 148 (__force u16)dport, &net_secret); 149} 150EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); 151#endif 152 153#if IS_ENABLED(CONFIG_IP_DCCP) 154u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, 155 __be16 sport, __be16 dport) 156{ 157 u64 seq; 158 net_secret_init(); 159 seq = siphash_3u32((__force u32)saddr, (__force u32)daddr, 160 (__force u32)sport << 16 | (__force u32)dport, 161 &net_secret); 162 seq += ktime_get_real_ns(); 163 seq &= (1ull << 48) - 1; 164 return seq; 165} 166EXPORT_SYMBOL(secure_dccp_sequence_number); 167 168#if IS_ENABLED(CONFIG_IPV6) 169u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, 170 __be16 sport, __be16 dport) 171{ 172 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 }; 183 u64 seq; 184 net_secret_init(); 185 seq = siphash(&combined, offsetofend(typeof(combined), dport), 186 &net_secret); 187 seq += ktime_get_real_ns(); 188 seq &= (1ull << 48) - 1; 189 return seq; 190} 191EXPORT_SYMBOL(secure_dccpv6_sequence_number); 192#endif 193#endif