0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/cache.h>
0010 #include <linux/random.h>
0011 #include <linux/hrtimer.h>
0012 #include <linux/ktime.h>
0013 #include <linux/string.h>
0014 #include <linux/net.h>
0015 #include <linux/siphash.h>
0016 #include <net/secure_seq.h>
0017
0018 #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
0019 #include <linux/in6.h>
0020 #include <net/tcp.h>
0021
0022 static siphash_aligned_key_t net_secret;
0023 static siphash_aligned_key_t ts_secret;
0024
0025 #define EPHEMERAL_PORT_SHUFFLE_PERIOD (10 * HZ)
0026
0027 static __always_inline void net_secret_init(void)
0028 {
0029 net_get_random_once(&net_secret, sizeof(net_secret));
0030 }
0031
0032 static __always_inline void ts_secret_init(void)
0033 {
0034 net_get_random_once(&ts_secret, sizeof(ts_secret));
0035 }
0036 #endif
0037
0038 #ifdef CONFIG_INET
0039 static u32 seq_scale(u32 seq)
0040 {
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 return seq + (ktime_get_real_ns() >> 6);
0052 }
0053 #endif
0054
0055 #if IS_ENABLED(CONFIG_IPV6)
0056 u32 secure_tcpv6_ts_off(const struct net *net,
0057 const __be32 *saddr, const __be32 *daddr)
0058 {
0059 const struct {
0060 struct in6_addr saddr;
0061 struct in6_addr daddr;
0062 } __aligned(SIPHASH_ALIGNMENT) combined = {
0063 .saddr = *(struct in6_addr *)saddr,
0064 .daddr = *(struct in6_addr *)daddr,
0065 };
0066
0067 if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
0068 return 0;
0069
0070 ts_secret_init();
0071 return siphash(&combined, offsetofend(typeof(combined), daddr),
0072 &ts_secret);
0073 }
0074 EXPORT_SYMBOL(secure_tcpv6_ts_off);
0075
0076 u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
0077 __be16 sport, __be16 dport)
0078 {
0079 const struct {
0080 struct in6_addr saddr;
0081 struct in6_addr daddr;
0082 __be16 sport;
0083 __be16 dport;
0084 } __aligned(SIPHASH_ALIGNMENT) combined = {
0085 .saddr = *(struct in6_addr *)saddr,
0086 .daddr = *(struct in6_addr *)daddr,
0087 .sport = sport,
0088 .dport = dport
0089 };
0090 u32 hash;
0091
0092 net_secret_init();
0093 hash = siphash(&combined, offsetofend(typeof(combined), dport),
0094 &net_secret);
0095 return seq_scale(hash);
0096 }
0097 EXPORT_SYMBOL(secure_tcpv6_seq);
0098
0099 u64 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
0100 __be16 dport)
0101 {
0102 const struct {
0103 struct in6_addr saddr;
0104 struct in6_addr daddr;
0105 unsigned int timeseed;
0106 __be16 dport;
0107 } __aligned(SIPHASH_ALIGNMENT) combined = {
0108 .saddr = *(struct in6_addr *)saddr,
0109 .daddr = *(struct in6_addr *)daddr,
0110 .timeseed = jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD,
0111 .dport = dport,
0112 };
0113 net_secret_init();
0114 return siphash(&combined, offsetofend(typeof(combined), dport),
0115 &net_secret);
0116 }
0117 EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
0118 #endif
0119
0120 #ifdef CONFIG_INET
0121 u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
0122 {
0123 if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
0124 return 0;
0125
0126 ts_secret_init();
0127 return siphash_2u32((__force u32)saddr, (__force u32)daddr,
0128 &ts_secret);
0129 }
0130
0131
0132
0133
0134
0135
0136 u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
0137 __be16 sport, __be16 dport)
0138 {
0139 u32 hash;
0140
0141 net_secret_init();
0142 hash = siphash_3u32((__force u32)saddr, (__force u32)daddr,
0143 (__force u32)sport << 16 | (__force u32)dport,
0144 &net_secret);
0145 return seq_scale(hash);
0146 }
0147 EXPORT_SYMBOL_GPL(secure_tcp_seq);
0148
0149 u64 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
0150 {
0151 net_secret_init();
0152 return siphash_4u32((__force u32)saddr, (__force u32)daddr,
0153 (__force u16)dport,
0154 jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD,
0155 &net_secret);
0156 }
0157 EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
0158 #endif
0159
0160 #if IS_ENABLED(CONFIG_IP_DCCP)
0161 u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
0162 __be16 sport, __be16 dport)
0163 {
0164 u64 seq;
0165 net_secret_init();
0166 seq = siphash_3u32((__force u32)saddr, (__force u32)daddr,
0167 (__force u32)sport << 16 | (__force u32)dport,
0168 &net_secret);
0169 seq += ktime_get_real_ns();
0170 seq &= (1ull << 48) - 1;
0171 return seq;
0172 }
0173 EXPORT_SYMBOL(secure_dccp_sequence_number);
0174
0175 #if IS_ENABLED(CONFIG_IPV6)
0176 u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
0177 __be16 sport, __be16 dport)
0178 {
0179 const struct {
0180 struct in6_addr saddr;
0181 struct in6_addr daddr;
0182 __be16 sport;
0183 __be16 dport;
0184 } __aligned(SIPHASH_ALIGNMENT) combined = {
0185 .saddr = *(struct in6_addr *)saddr,
0186 .daddr = *(struct in6_addr *)daddr,
0187 .sport = sport,
0188 .dport = dport
0189 };
0190 u64 seq;
0191 net_secret_init();
0192 seq = siphash(&combined, offsetofend(typeof(combined), dport),
0193 &net_secret);
0194 seq += ktime_get_real_ns();
0195 seq &= (1ull << 48) - 1;
0196 return seq;
0197 }
0198 EXPORT_SYMBOL(secure_dccpv6_sequence_number);
0199 #endif
0200 #endif