2005-04-17 02:20:36 +04:00
/*
* Syncookies implementation for the Linux kernel
*
* Copyright ( C ) 1997 Andi Kleen
2007-02-09 17:24:47 +03:00
* Based on ideas by D . J . Bernstein and Eric Schenk .
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
2007-02-09 17:24:47 +03:00
*
2005-04-17 02:20:36 +04:00
* $ Id : syncookies . c , v 1.18 2002 / 02 / 01 22 : 01 : 04 davem Exp $
*
2007-02-09 17:24:47 +03:00
* Missing : IPv6 support .
2005-04-17 02:20:36 +04:00
*/
# include <linux/tcp.h>
# include <linux/slab.h>
# include <linux/random.h>
# include <linux/cryptohash.h>
# include <linux/kernel.h>
# include <net/tcp.h>
extern int sysctl_tcp_syncookies ;
static __u32 syncookie_secret [ 2 ] [ 16 - 3 + SHA_DIGEST_WORDS ] ;
static __init int init_syncookies ( void )
{
get_random_bytes ( syncookie_secret , sizeof ( syncookie_secret ) ) ;
return 0 ;
}
module_init ( init_syncookies ) ;
# define COOKIEBITS 24 /* Upper bits store count */
# define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
2006-11-15 07:51:49 +03:00
static u32 cookie_hash ( __be32 saddr , __be32 daddr , __be16 sport , __be16 dport ,
2005-04-17 02:20:36 +04:00
u32 count , int c )
{
__u32 tmp [ 16 + 5 + SHA_WORKSPACE_WORDS ] ;
memcpy ( tmp + 3 , syncookie_secret [ c ] , sizeof ( syncookie_secret [ c ] ) ) ;
2006-11-15 07:51:49 +03:00
tmp [ 0 ] = ( __force u32 ) saddr ;
tmp [ 1 ] = ( __force u32 ) daddr ;
tmp [ 2 ] = ( ( __force u32 ) sport < < 16 ) + ( __force u32 ) dport ;
2005-04-17 02:20:36 +04:00
tmp [ 3 ] = count ;
sha_transform ( tmp + 16 , ( __u8 * ) tmp , tmp + 16 + 5 ) ;
return tmp [ 17 ] ;
}
2006-11-15 07:51:49 +03:00
static __u32 secure_tcp_syn_cookie ( __be32 saddr , __be32 daddr , __be16 sport ,
__be16 dport , __u32 sseq , __u32 count ,
2005-04-17 02:20:36 +04:00
__u32 data )
{
/*
* Compute the secure sequence number .
* The output should be :
2007-02-09 17:24:47 +03:00
* HASH ( sec1 , saddr , sport , daddr , dport , sec1 ) + sseq + ( count * 2 ^ 24 )
2005-04-17 02:20:36 +04:00
* + ( HASH ( sec2 , saddr , sport , daddr , dport , count , sec2 ) % 2 ^ 24 ) .
* Where sseq is their sequence number and count increases every
* minute by 1.
* As an extra hack , we add a small " data " value that encodes the
* MSS into the second hash value .
*/
return ( cookie_hash ( saddr , daddr , sport , dport , 0 , 0 ) +
sseq + ( count < < COOKIEBITS ) +
( ( cookie_hash ( saddr , daddr , sport , dport , count , 1 ) + data )
& COOKIEMASK ) ) ;
}
/*
* This retrieves the small " data " value from the syncookie .
* If the syncookie is bad , the data returned will be out of
* range . This must be checked by the caller .
*
* The count value used to generate the cookie must be within
* " maxdiff " if the current ( passed - in ) " count " . The return value
* is ( __u32 ) - 1 if this test fails .
*/
2006-11-15 07:51:49 +03:00
static __u32 check_tcp_syn_cookie ( __u32 cookie , __be32 saddr , __be32 daddr ,
__be16 sport , __be16 dport , __u32 sseq ,
2005-04-17 02:20:36 +04:00
__u32 count , __u32 maxdiff )
{
__u32 diff ;
/* Strip away the layers from the cookie */
cookie - = cookie_hash ( saddr , daddr , sport , dport , 0 , 0 ) + sseq ;
/* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */
diff = ( count - ( cookie > > COOKIEBITS ) ) & ( ( __u32 ) - 1 > > COOKIEBITS ) ;
if ( diff > = maxdiff )
return ( __u32 ) - 1 ;
return ( cookie -
cookie_hash ( saddr , daddr , sport , dport , count - diff , 1 ) )
& COOKIEMASK ; /* Leaving the data behind */
}
2007-02-09 17:24:47 +03:00
/*
2005-04-17 02:20:36 +04:00
* This table has to be sorted and terminated with ( __u16 ) - 1.
* XXX generate a better table .
* Unresolved Issues : HIPPI with a 64 k MSS is not well supported .
*/
static __u16 const msstab [ ] = {
64 - 1 ,
2007-02-09 17:24:47 +03:00
256 - 1 ,
2005-04-17 02:20:36 +04:00
512 - 1 ,
536 - 1 ,
2007-02-09 17:24:47 +03:00
1024 - 1 ,
2005-04-17 02:20:36 +04:00
1440 - 1 ,
1460 - 1 ,
4312 - 1 ,
( __u16 ) - 1
} ;
/* The number doesn't include the -1 terminator */
# define NUM_MSS (ARRAY_SIZE(msstab) - 1)
/*
* Generate a syncookie . mssp points to the mss , which is returned
* rounded down to the value encoded in the cookie .
*/
__u32 cookie_v4_init_sequence ( struct sock * sk , struct sk_buff * skb , __u16 * mssp )
{
struct tcp_sock * tp = tcp_sk ( sk ) ;
2007-04-11 08:04:22 +04:00
const struct iphdr * iph = ip_hdr ( skb ) ;
const struct tcphdr * th = tcp_hdr ( skb ) ;
2005-04-17 02:20:36 +04:00
int mssind ;
const __u16 mss = * mssp ;
tp - > last_synq_overflow = jiffies ;
/* XXX sort msstab[] by probability? Binary search? */
for ( mssind = 0 ; mss > msstab [ mssind + 1 ] ; mssind + + )
;
* mssp = msstab [ mssind ] + 1 ;
NET_INC_STATS_BH ( LINUX_MIB_SYNCOOKIESSENT ) ;
2007-04-11 08:04:22 +04:00
return secure_tcp_syn_cookie ( iph - > saddr , iph - > daddr ,
th - > source , th - > dest , ntohl ( th - > seq ) ,
2005-04-17 02:20:36 +04:00
jiffies / ( HZ * 60 ) , mssind ) ;
}
2007-02-09 17:24:47 +03:00
/*
2005-04-17 02:20:36 +04:00
* This ( misnamed ) value is the age of syncookie which is permitted .
* Its ideal value should be dependent on TCP_TIMEOUT_INIT and
* sysctl_tcp_retries1 . It ' s a rather complicated formula ( exponential
* backoff ) to compute at runtime so it ' s currently hardcoded here .
*/
# define COUNTER_TRIES 4
2007-02-09 17:24:47 +03:00
/*
* Check if a ack sequence number is a valid syncookie .
2005-04-17 02:20:36 +04:00
* Return the decoded mss if it is , or 0 if not .
*/
static inline int cookie_check ( struct sk_buff * skb , __u32 cookie )
{
2007-04-11 08:04:22 +04:00
const struct iphdr * iph = ip_hdr ( skb ) ;
const struct tcphdr * th = tcp_hdr ( skb ) ;
__u32 seq = ntohl ( th - > seq ) - 1 ;
__u32 mssind = check_tcp_syn_cookie ( cookie , iph - > saddr , iph - > daddr ,
th - > source , th - > dest , seq ,
jiffies / ( HZ * 60 ) ,
COUNTER_TRIES ) ;
2005-04-17 02:20:36 +04:00
return mssind < NUM_MSS ? msstab [ mssind ] + 1 : 0 ;
}
static inline struct sock * get_cookie_sock ( struct sock * sk , struct sk_buff * skb ,
2005-06-19 09:47:21 +04:00
struct request_sock * req ,
2005-04-17 02:20:36 +04:00
struct dst_entry * dst )
{
2005-12-14 10:15:52 +03:00
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
2005-04-17 02:20:36 +04:00
struct sock * child ;
2005-12-14 10:15:52 +03:00
child = icsk - > icsk_af_ops - > syn_recv_sock ( sk , skb , req , dst ) ;
2005-04-17 02:20:36 +04:00
if ( child )
2005-08-10 07:10:42 +04:00
inet_csk_reqsk_queue_add ( sk , req , child ) ;
2005-04-17 02:20:36 +04:00
else
2005-06-19 09:47:21 +04:00
reqsk_free ( req ) ;
2005-04-17 02:20:36 +04:00
return child ;
}
struct sock * cookie_v4_check ( struct sock * sk , struct sk_buff * skb ,
struct ip_options * opt )
{
[NET] Generalise TCP's struct open_request minisock infrastructure
Kept this first changeset minimal, without changing existing names to
ease peer review.
Basicaly tcp_openreq_alloc now receives the or_calltable, that in turn
has two new members:
->slab, that replaces tcp_openreq_cachep
->obj_size, to inform the size of the openreq descendant for
a specific protocol
The protocol specific fields in struct open_request were moved to a
class hierarchy, with the things that are common to all connection
oriented PF_INET protocols in struct inet_request_sock, the TCP ones
in tcp_request_sock, that is an inet_request_sock, that is an
open_request.
I.e. this uses the same approach used for the struct sock class
hierarchy, with sk_prot indicating if the protocol wants to use the
open_request infrastructure by filling in sk_prot->rsk_prot with an
or_calltable.
Results? Performance is improved and TCP v4 now uses only 64 bytes per
open request minisock, down from 96 without this patch :-)
Next changeset will rename some of the structs, fields and functions
mentioned above, struct or_calltable is way unclear, better name it
struct request_sock_ops, s/struct open_request/struct request_sock/g,
etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-06-19 09:46:52 +04:00
struct inet_request_sock * ireq ;
struct tcp_request_sock * treq ;
2005-04-17 02:20:36 +04:00
struct tcp_sock * tp = tcp_sk ( sk ) ;
2007-04-11 08:04:22 +04:00
const struct tcphdr * th = tcp_hdr ( skb ) ;
__u32 cookie = ntohl ( th - > ack_seq ) - 1 ;
2005-04-17 02:20:36 +04:00
struct sock * ret = sk ;
2007-02-09 17:24:47 +03:00
struct request_sock * req ;
int mss ;
struct rtable * rt ;
2005-04-17 02:20:36 +04:00
__u8 rcv_wscale ;
2007-04-11 08:04:22 +04:00
if ( ! sysctl_tcp_syncookies | | ! th - > ack )
2005-04-17 02:20:36 +04:00
goto out ;
2007-02-09 17:24:47 +03:00
if ( time_after ( jiffies , tp - > last_synq_overflow + TCP_TIMEOUT_INIT ) | |
2005-04-17 02:20:36 +04:00
( mss = cookie_check ( skb , cookie ) ) = = 0 ) {
2007-02-09 17:24:47 +03:00
NET_INC_STATS_BH ( LINUX_MIB_SYNCOOKIESFAILED ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
NET_INC_STATS_BH ( LINUX_MIB_SYNCOOKIESRECV ) ;
ret = NULL ;
2005-06-19 09:47:21 +04:00
req = reqsk_alloc ( & tcp_request_sock_ops ) ; /* for safety */
2005-04-17 02:20:36 +04:00
if ( ! req )
goto out ;
2006-07-25 10:32:50 +04:00
if ( security_inet_conn_request ( sk , skb , req ) ) {
reqsk_free ( req ) ;
goto out ;
}
[NET] Generalise TCP's struct open_request minisock infrastructure
Kept this first changeset minimal, without changing existing names to
ease peer review.
Basicaly tcp_openreq_alloc now receives the or_calltable, that in turn
has two new members:
->slab, that replaces tcp_openreq_cachep
->obj_size, to inform the size of the openreq descendant for
a specific protocol
The protocol specific fields in struct open_request were moved to a
class hierarchy, with the things that are common to all connection
oriented PF_INET protocols in struct inet_request_sock, the TCP ones
in tcp_request_sock, that is an inet_request_sock, that is an
open_request.
I.e. this uses the same approach used for the struct sock class
hierarchy, with sk_prot indicating if the protocol wants to use the
open_request infrastructure by filling in sk_prot->rsk_prot with an
or_calltable.
Results? Performance is improved and TCP v4 now uses only 64 bytes per
open request minisock, down from 96 without this patch :-)
Next changeset will rename some of the structs, fields and functions
mentioned above, struct or_calltable is way unclear, better name it
struct request_sock_ops, s/struct open_request/struct request_sock/g,
etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-06-19 09:46:52 +04:00
ireq = inet_rsk ( req ) ;
treq = tcp_rsk ( req ) ;
2007-04-11 08:04:22 +04:00
treq - > rcv_isn = ntohl ( th - > seq ) - 1 ;
2007-02-09 17:24:47 +03:00
treq - > snt_isn = cookie ;
2005-04-17 02:20:36 +04:00
req - > mss = mss ;
2007-04-11 08:04:22 +04:00
ireq - > rmt_port = th - > source ;
2007-04-21 09:47:35 +04:00
ireq - > loc_addr = ip_hdr ( skb ) - > daddr ;
ireq - > rmt_addr = ip_hdr ( skb ) - > saddr ;
[NET] Generalise TCP's struct open_request minisock infrastructure
Kept this first changeset minimal, without changing existing names to
ease peer review.
Basicaly tcp_openreq_alloc now receives the or_calltable, that in turn
has two new members:
->slab, that replaces tcp_openreq_cachep
->obj_size, to inform the size of the openreq descendant for
a specific protocol
The protocol specific fields in struct open_request were moved to a
class hierarchy, with the things that are common to all connection
oriented PF_INET protocols in struct inet_request_sock, the TCP ones
in tcp_request_sock, that is an inet_request_sock, that is an
open_request.
I.e. this uses the same approach used for the struct sock class
hierarchy, with sk_prot indicating if the protocol wants to use the
open_request infrastructure by filling in sk_prot->rsk_prot with an
or_calltable.
Results? Performance is improved and TCP v4 now uses only 64 bytes per
open request minisock, down from 96 without this patch :-)
Next changeset will rename some of the structs, fields and functions
mentioned above, struct or_calltable is way unclear, better name it
struct request_sock_ops, s/struct open_request/struct request_sock/g,
etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-06-19 09:46:52 +04:00
ireq - > opt = NULL ;
2005-04-17 02:20:36 +04:00
/* We throwed the options of the initial SYN away, so we hope
* the ACK carries the same options again ( see RFC1122 4.2 .3 .8 )
*/
if ( opt & & opt - > optlen ) {
int opt_size = sizeof ( struct ip_options ) + opt - > optlen ;
[NET] Generalise TCP's struct open_request minisock infrastructure
Kept this first changeset minimal, without changing existing names to
ease peer review.
Basicaly tcp_openreq_alloc now receives the or_calltable, that in turn
has two new members:
->slab, that replaces tcp_openreq_cachep
->obj_size, to inform the size of the openreq descendant for
a specific protocol
The protocol specific fields in struct open_request were moved to a
class hierarchy, with the things that are common to all connection
oriented PF_INET protocols in struct inet_request_sock, the TCP ones
in tcp_request_sock, that is an inet_request_sock, that is an
open_request.
I.e. this uses the same approach used for the struct sock class
hierarchy, with sk_prot indicating if the protocol wants to use the
open_request infrastructure by filling in sk_prot->rsk_prot with an
or_calltable.
Results? Performance is improved and TCP v4 now uses only 64 bytes per
open request minisock, down from 96 without this patch :-)
Next changeset will rename some of the structs, fields and functions
mentioned above, struct or_calltable is way unclear, better name it
struct request_sock_ops, s/struct open_request/struct request_sock/g,
etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-06-19 09:46:52 +04:00
ireq - > opt = kmalloc ( opt_size , GFP_ATOMIC ) ;
if ( ireq - > opt ! = NULL & & ip_options_echo ( ireq - > opt , skb ) ) {
kfree ( ireq - > opt ) ;
ireq - > opt = NULL ;
2005-04-17 02:20:36 +04:00
}
}
[NET] Generalise TCP's struct open_request minisock infrastructure
Kept this first changeset minimal, without changing existing names to
ease peer review.
Basicaly tcp_openreq_alloc now receives the or_calltable, that in turn
has two new members:
->slab, that replaces tcp_openreq_cachep
->obj_size, to inform the size of the openreq descendant for
a specific protocol
The protocol specific fields in struct open_request were moved to a
class hierarchy, with the things that are common to all connection
oriented PF_INET protocols in struct inet_request_sock, the TCP ones
in tcp_request_sock, that is an inet_request_sock, that is an
open_request.
I.e. this uses the same approach used for the struct sock class
hierarchy, with sk_prot indicating if the protocol wants to use the
open_request infrastructure by filling in sk_prot->rsk_prot with an
or_calltable.
Results? Performance is improved and TCP v4 now uses only 64 bytes per
open request minisock, down from 96 without this patch :-)
Next changeset will rename some of the structs, fields and functions
mentioned above, struct or_calltable is way unclear, better name it
struct request_sock_ops, s/struct open_request/struct request_sock/g,
etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-06-19 09:46:52 +04:00
ireq - > snd_wscale = ireq - > rcv_wscale = ireq - > tstamp_ok = 0 ;
2007-02-09 17:24:47 +03:00
ireq - > wscale_ok = ireq - > sack_ok = 0 ;
req - > expires = 0UL ;
req - > retrans = 0 ;
2005-04-17 02:20:36 +04:00
/*
* We need to lookup the route here to get at the correct
* window size . We should better make sure that the window size
* hasn ' t changed since we received the original syn , but I see
2007-02-09 17:24:47 +03:00
* no easy way to do this .
2005-04-17 02:20:36 +04:00
*/
{
struct flowi fl = { . nl_u = { . ip4_u =
{ . daddr = ( ( opt & & opt - > srr ) ?
opt - > faddr :
[NET] Generalise TCP's struct open_request minisock infrastructure
Kept this first changeset minimal, without changing existing names to
ease peer review.
Basicaly tcp_openreq_alloc now receives the or_calltable, that in turn
has two new members:
->slab, that replaces tcp_openreq_cachep
->obj_size, to inform the size of the openreq descendant for
a specific protocol
The protocol specific fields in struct open_request were moved to a
class hierarchy, with the things that are common to all connection
oriented PF_INET protocols in struct inet_request_sock, the TCP ones
in tcp_request_sock, that is an inet_request_sock, that is an
open_request.
I.e. this uses the same approach used for the struct sock class
hierarchy, with sk_prot indicating if the protocol wants to use the
open_request infrastructure by filling in sk_prot->rsk_prot with an
or_calltable.
Results? Performance is improved and TCP v4 now uses only 64 bytes per
open request minisock, down from 96 without this patch :-)
Next changeset will rename some of the structs, fields and functions
mentioned above, struct or_calltable is way unclear, better name it
struct request_sock_ops, s/struct open_request/struct request_sock/g,
etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-06-19 09:46:52 +04:00
ireq - > rmt_addr ) ,
. saddr = ireq - > loc_addr ,
2005-04-17 02:20:36 +04:00
. tos = RT_CONN_FLAGS ( sk ) } } ,
. proto = IPPROTO_TCP ,
. uli_u = { . ports =
2007-04-11 08:04:22 +04:00
{ . sport = th - > dest ,
. dport = th - > source } } } ;
2006-07-25 10:32:50 +04:00
security_req_classify_flow ( req , & fl ) ;
2008-01-23 09:07:34 +03:00
if ( ip_route_output_key ( & init_net , & rt , & fl ) ) {
2005-06-19 09:47:21 +04:00
reqsk_free ( req ) ;
2007-02-09 17:24:47 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
}
}
/* Try to redo what tcp_v4_send_synack did. */
req - > window_clamp = dst_metric ( & rt - > u . dst , RTAX_WINDOW ) ;
tcp_select_initial_window ( tcp_full_space ( sk ) , req - > mss ,
2007-02-09 17:24:47 +03:00
& req - > rcv_wnd , & req - > window_clamp ,
2005-04-17 02:20:36 +04:00
0 , & rcv_wscale ) ;
/* BTW win scale with syncookies is 0 by definition */
2007-02-09 17:24:47 +03:00
ireq - > rcv_wscale = rcv_wscale ;
2005-04-17 02:20:36 +04:00
ret = get_cookie_sock ( sk , skb , req , & rt - > u . dst ) ;
out : return ret ;
}