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>
# include <net/secure_seq.h>
static u32 net_secret [ MD5_MESSAGE_BYTES / 4 ] ____cacheline_aligned ;
static int __init net_secret_init ( void )
{
get_random_bytes ( net_secret , sizeof ( net_secret ) ) ;
return 0 ;
}
late_initcall ( net_secret_init ) ;
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 )
*/
return seq + ( ktime_to_ns ( ktime_get_real ( ) ) > > 6 ) ;
}
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 ;
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 ;
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_ip_id ( __be32 daddr )
{
u32 hash [ MD5_DIGEST_WORDS ] ;
hash [ 0 ] = ( __force __u32 ) daddr ;
hash [ 1 ] = net_secret [ 13 ] ;
hash [ 2 ] = net_secret [ 14 ] ;
hash [ 3 ] = net_secret [ 15 ] ;
md5_transform ( hash , net_secret ) ;
return hash [ 0 ] ;
}
__u32 secure_ipv6_id ( const __be32 daddr [ 4 ] )
{
__u32 hash [ 4 ] ;
memcpy ( hash , daddr , 16 ) ;
md5_transform ( hash , net_secret ) ;
return hash [ 0 ] ;
}
__u32 secure_tcp_sequence_number ( __be32 saddr , __be32 daddr ,
__be16 sport , __be16 dport )
{
u32 hash [ MD5_DIGEST_WORDS ] ;
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 ] ;
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 ;
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 ) ;
seq + = ktime_to_ns ( ktime_get_real ( ) ) ;
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 ;
memcpy ( hash , saddr , 16 ) ;
for ( i = 0 ; i < 4 ; i + + )
secret [ i ] = net_secret [ i ] + daddr [ i ] ;
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 ) ;
seq + = ktime_to_ns ( ktime_get_real ( ) ) ;
seq & = ( 1ull < < 48 ) - 1 ;
return seq ;
}
EXPORT_SYMBOL ( secure_dccpv6_sequence_number ) ;
# endif
# endif