2011-08-04 07:50:44 +04:00
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/cryptohash.h>
# include <linux/module.h>
# include <linux/cache.h>
# include <linux/random.h>
# include <linux/hrtimer.h>
# include <linux/ktime.h>
# include <linux/string.h>
2013-10-19 23:48:59 +04:00
# include <linux/net.h>
2011-08-04 07:50:44 +04:00
# include <net/secure_seq.h>
2013-10-06 00:56:59 +04:00
# if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
2013-09-24 17:19:57 +04:00
# define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
2011-08-04 07:50:44 +04:00
2013-09-24 17:19:57 +04:00
static u32 net_secret [ NET_SECRET_SIZE ] ____cacheline_aligned ;
2013-10-23 10:44:50 +04:00
static __always_inline void net_secret_init ( void )
2011-08-04 07:50:44 +04:00
{
2013-10-19 23:48:59 +04:00
net_get_random_once ( net_secret , sizeof ( net_secret ) ) ;
2011-08-04 07:50:44 +04:00
}
2013-10-06 00:56:59 +04:00
# endif
2011-08-04 07:50:44 +04:00
2011-12-06 12:04:40 +04:00
# ifdef CONFIG_INET
2011-08-04 07:50:44 +04:00
static u32 seq_scale ( u32 seq )
{
/*
* As close as possible to RFC 793 , which
* suggests using a 250 kHz clock .
* Further reading shows this assumes 2 Mb / s networks .
* For 10 Mb / s Ethernet , a 1 MHz clock is appropriate .
* For 10 Gb / s Ethernet , a 1 GHz clock should be ok , but
* we also need to limit the resolution so that the u32 seq
* overlaps less than one time per MSL ( 2 minutes ) .
* Choosing a clock of 64 ns period is OK . ( period of 274 s )
*/
2014-08-23 05:32:09 +04:00
return seq + ( ktime_get_real_ns ( ) > > 6 ) ;
2011-08-04 07:50:44 +04:00
}
2011-12-06 12:04:40 +04:00
# endif
2011-08-04 07:50:44 +04:00
2011-12-10 13:48:31 +04:00
# if IS_ENABLED(CONFIG_IPV6)
2011-10-21 13:22:42 +04:00
__u32 secure_tcpv6_sequence_number ( const __be32 * saddr , const __be32 * daddr ,
2011-08-04 07:50:44 +04:00
__be16 sport , __be16 dport )
{
u32 secret [ MD5_MESSAGE_BYTES / 4 ] ;
u32 hash [ MD5_DIGEST_WORDS ] ;
u32 i ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2011-08-04 07:50:44 +04:00
memcpy ( hash , saddr , 16 ) ;
for ( i = 0 ; i < 4 ; i + + )
2012-01-16 23:27:39 +04:00
secret [ i ] = net_secret [ i ] + ( __force u32 ) daddr [ i ] ;
2011-08-04 07:50:44 +04:00
secret [ 4 ] = net_secret [ 4 ] +
( ( ( __force u16 ) sport < < 16 ) + ( __force u16 ) dport ) ;
for ( i = 5 ; i < MD5_MESSAGE_BYTES / 4 ; i + + )
secret [ i ] = net_secret [ i ] ;
md5_transform ( hash , secret ) ;
return seq_scale ( hash [ 0 ] ) ;
}
EXPORT_SYMBOL ( secure_tcpv6_sequence_number ) ;
u32 secure_ipv6_port_ephemeral ( const __be32 * saddr , const __be32 * daddr ,
__be16 dport )
{
u32 secret [ MD5_MESSAGE_BYTES / 4 ] ;
u32 hash [ MD5_DIGEST_WORDS ] ;
u32 i ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2011-08-04 07:50:44 +04:00
memcpy ( hash , saddr , 16 ) ;
for ( i = 0 ; i < 4 ; i + + )
secret [ i ] = net_secret [ i ] + ( __force u32 ) daddr [ i ] ;
secret [ 4 ] = net_secret [ 4 ] + ( __force u32 ) dport ;
for ( i = 5 ; i < MD5_MESSAGE_BYTES / 4 ; i + + )
secret [ i ] = net_secret [ i ] ;
md5_transform ( hash , secret ) ;
return hash [ 0 ] ;
}
2012-08-26 21:14:12 +04:00
EXPORT_SYMBOL ( secure_ipv6_port_ephemeral ) ;
2011-08-04 07:50:44 +04:00
# endif
# ifdef CONFIG_INET
__u32 secure_tcp_sequence_number ( __be32 saddr , __be32 daddr ,
__be16 sport , __be16 dport )
{
u32 hash [ MD5_DIGEST_WORDS ] ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2011-08-04 07:50:44 +04:00
hash [ 0 ] = ( __force u32 ) saddr ;
hash [ 1 ] = ( __force u32 ) daddr ;
hash [ 2 ] = ( ( __force u16 ) sport < < 16 ) + ( __force u16 ) dport ;
hash [ 3 ] = net_secret [ 15 ] ;
md5_transform ( hash , net_secret ) ;
return seq_scale ( hash [ 0 ] ) ;
}
u32 secure_ipv4_port_ephemeral ( __be32 saddr , __be32 daddr , __be16 dport )
{
u32 hash [ MD5_DIGEST_WORDS ] ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2011-08-04 07:50:44 +04:00
hash [ 0 ] = ( __force u32 ) saddr ;
hash [ 1 ] = ( __force u32 ) daddr ;
hash [ 2 ] = ( __force u32 ) dport ^ net_secret [ 14 ] ;
hash [ 3 ] = net_secret [ 15 ] ;
md5_transform ( hash , net_secret ) ;
return hash [ 0 ] ;
}
EXPORT_SYMBOL_GPL ( secure_ipv4_port_ephemeral ) ;
# endif
2011-12-12 06:58:22 +04:00
# if IS_ENABLED(CONFIG_IP_DCCP)
2011-08-04 07:50:44 +04:00
u64 secure_dccp_sequence_number ( __be32 saddr , __be32 daddr ,
__be16 sport , __be16 dport )
{
u32 hash [ MD5_DIGEST_WORDS ] ;
u64 seq ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2011-08-04 07:50:44 +04:00
hash [ 0 ] = ( __force u32 ) saddr ;
hash [ 1 ] = ( __force u32 ) daddr ;
hash [ 2 ] = ( ( __force u16 ) sport < < 16 ) + ( __force u16 ) dport ;
hash [ 3 ] = net_secret [ 15 ] ;
md5_transform ( hash , net_secret ) ;
seq = hash [ 0 ] | ( ( ( u64 ) hash [ 1 ] ) < < 32 ) ;
2014-08-23 05:32:09 +04:00
seq + = ktime_get_real_ns ( ) ;
2011-08-04 07:50:44 +04:00
seq & = ( 1ull < < 48 ) - 1 ;
return seq ;
}
EXPORT_SYMBOL ( secure_dccp_sequence_number ) ;
2011-12-10 13:48:31 +04:00
# if IS_ENABLED(CONFIG_IPV6)
2011-08-04 07:50:44 +04:00
u64 secure_dccpv6_sequence_number ( __be32 * saddr , __be32 * daddr ,
__be16 sport , __be16 dport )
{
u32 secret [ MD5_MESSAGE_BYTES / 4 ] ;
u32 hash [ MD5_DIGEST_WORDS ] ;
u64 seq ;
u32 i ;
2013-09-24 17:19:57 +04:00
net_secret_init ( ) ;
2011-08-04 07:50:44 +04:00
memcpy ( hash , saddr , 16 ) ;
for ( i = 0 ; i < 4 ; i + + )
2015-05-26 04:55:48 +03:00
secret [ i ] = net_secret [ i ] + ( __force u32 ) daddr [ i ] ;
2011-08-04 07:50:44 +04:00
secret [ 4 ] = net_secret [ 4 ] +
( ( ( __force u16 ) sport < < 16 ) + ( __force u16 ) dport ) ;
for ( i = 5 ; i < MD5_MESSAGE_BYTES / 4 ; i + + )
secret [ i ] = net_secret [ i ] ;
md5_transform ( hash , secret ) ;
seq = hash [ 0 ] | ( ( ( u64 ) hash [ 1 ] ) < < 32 ) ;
2014-08-23 05:32:09 +04:00
seq + = ktime_get_real_ns ( ) ;
2011-08-04 07:50:44 +04:00
seq & = ( 1ull < < 48 ) - 1 ;
return seq ;
}
EXPORT_SYMBOL ( secure_dccpv6_sequence_number ) ;
# endif
# endif