secure_seq.c (5213B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 4 */ 5 6#include <linux/kernel.h> 7#include <linux/init.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_aligned_key_t net_secret; 23static siphash_aligned_key_t ts_secret; 24 25#define EPHEMERAL_PORT_SHUFFLE_PERIOD (10 * HZ) 26 27static __always_inline void net_secret_init(void) 28{ 29 net_get_random_once(&net_secret, sizeof(net_secret)); 30} 31 32static __always_inline void ts_secret_init(void) 33{ 34 net_get_random_once(&ts_secret, sizeof(ts_secret)); 35} 36#endif 37 38#ifdef CONFIG_INET 39static u32 seq_scale(u32 seq) 40{ 41 /* 42 * As close as possible to RFC 793, which 43 * suggests using a 250 kHz clock. 44 * Further reading shows this assumes 2 Mb/s networks. 45 * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. 46 * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but 47 * we also need to limit the resolution so that the u32 seq 48 * overlaps less than one time per MSL (2 minutes). 49 * Choosing a clock of 64 ns period is OK. (period of 274 s) 50 */ 51 return seq + (ktime_get_real_ns() >> 6); 52} 53#endif 54 55#if IS_ENABLED(CONFIG_IPV6) 56u32 secure_tcpv6_ts_off(const struct net *net, 57 const __be32 *saddr, const __be32 *daddr) 58{ 59 const struct { 60 struct in6_addr saddr; 61 struct in6_addr daddr; 62 } __aligned(SIPHASH_ALIGNMENT) combined = { 63 .saddr = *(struct in6_addr *)saddr, 64 .daddr = *(struct in6_addr *)daddr, 65 }; 66 67 if (net->ipv4.sysctl_tcp_timestamps != 1) 68 return 0; 69 70 ts_secret_init(); 71 return siphash(&combined, offsetofend(typeof(combined), daddr), 72 &ts_secret); 73} 74EXPORT_SYMBOL(secure_tcpv6_ts_off); 75 76u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr, 77 __be16 sport, __be16 dport) 78{ 79 const struct { 80 struct in6_addr saddr; 81 struct in6_addr daddr; 82 __be16 sport; 83 __be16 dport; 84 } __aligned(SIPHASH_ALIGNMENT) combined = { 85 .saddr = *(struct in6_addr *)saddr, 86 .daddr = *(struct in6_addr *)daddr, 87 .sport = sport, 88 .dport = dport 89 }; 90 u32 hash; 91 92 net_secret_init(); 93 hash = siphash(&combined, offsetofend(typeof(combined), dport), 94 &net_secret); 95 return seq_scale(hash); 96} 97EXPORT_SYMBOL(secure_tcpv6_seq); 98 99u64 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, 100 __be16 dport) 101{ 102 const struct { 103 struct in6_addr saddr; 104 struct in6_addr daddr; 105 unsigned int timeseed; 106 __be16 dport; 107 } __aligned(SIPHASH_ALIGNMENT) combined = { 108 .saddr = *(struct in6_addr *)saddr, 109 .daddr = *(struct in6_addr *)daddr, 110 .timeseed = jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD, 111 .dport = dport, 112 }; 113 net_secret_init(); 114 return siphash(&combined, offsetofend(typeof(combined), dport), 115 &net_secret); 116} 117EXPORT_SYMBOL(secure_ipv6_port_ephemeral); 118#endif 119 120#ifdef CONFIG_INET 121u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr) 122{ 123 if (net->ipv4.sysctl_tcp_timestamps != 1) 124 return 0; 125 126 ts_secret_init(); 127 return siphash_2u32((__force u32)saddr, (__force u32)daddr, 128 &ts_secret); 129} 130 131/* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), 132 * but fortunately, `sport' cannot be 0 in any circumstances. If this changes, 133 * it would be easy enough to have the former function use siphash_4u32, passing 134 * the arguments as separate u32. 135 */ 136u32 secure_tcp_seq(__be32 saddr, __be32 daddr, 137 __be16 sport, __be16 dport) 138{ 139 u32 hash; 140 141 net_secret_init(); 142 hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, 143 (__force u32)sport << 16 | (__force u32)dport, 144 &net_secret); 145 return seq_scale(hash); 146} 147EXPORT_SYMBOL_GPL(secure_tcp_seq); 148 149u64 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) 150{ 151 net_secret_init(); 152 return siphash_4u32((__force u32)saddr, (__force u32)daddr, 153 (__force u16)dport, 154 jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD, 155 &net_secret); 156} 157EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); 158#endif 159 160#if IS_ENABLED(CONFIG_IP_DCCP) 161u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, 162 __be16 sport, __be16 dport) 163{ 164 u64 seq; 165 net_secret_init(); 166 seq = siphash_3u32((__force u32)saddr, (__force u32)daddr, 167 (__force u32)sport << 16 | (__force u32)dport, 168 &net_secret); 169 seq += ktime_get_real_ns(); 170 seq &= (1ull << 48) - 1; 171 return seq; 172} 173EXPORT_SYMBOL(secure_dccp_sequence_number); 174 175#if IS_ENABLED(CONFIG_IPV6) 176u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, 177 __be16 sport, __be16 dport) 178{ 179 const struct { 180 struct in6_addr saddr; 181 struct in6_addr daddr; 182 __be16 sport; 183 __be16 dport; 184 } __aligned(SIPHASH_ALIGNMENT) combined = { 185 .saddr = *(struct in6_addr *)saddr, 186 .daddr = *(struct in6_addr *)daddr, 187 .sport = sport, 188 .dport = dport 189 }; 190 u64 seq; 191 net_secret_init(); 192 seq = siphash(&combined, offsetofend(typeof(combined), dport), 193 &net_secret); 194 seq += ktime_get_real_ns(); 195 seq &= (1ull << 48) - 1; 196 return seq; 197} 198EXPORT_SYMBOL(secure_dccpv6_sequence_number); 199#endif 200#endif