@ -22,22 +22,22 @@ bool IsHttp(const uint8_t *data, size_t len)
}
bool HttpExtractHost ( const uint8_t * data , size_t len , char * host , size_t len_host )
{
const uint8_t * p , * s , * e = data + len ;
const uint8_t * p , * s , * e = data + len ;
p = ( uint8_t * ) strncasestr ( ( char * ) data , " \n Host: " , len ) ;
if ( ! p ) return false ;
p + = 6 ;
while ( p < e & & ( * p = = ' ' | | * p = = ' \t ' ) ) p + + ;
s = p ;
while ( s < e & & ( * s ! = ' \r ' & & * s ! = ' \n ' & & * s ! = ' ' & & * s ! = ' \t ' ) ) s + + ;
if ( s > p )
p + = 6 ;
while ( p < e & & ( * p = = ' ' | | * p = = ' \t ' ) ) p + + ;
s = p ;
while ( s < e & & ( * s ! = ' \r ' & & * s ! = ' \n ' & & * s ! = ' ' & & * s ! = ' \t ' ) ) s + + ;
if ( s > p )
{
size_t slen = s - p ;
size_t slen = s - p ;
if ( host & & len_host )
{
if ( slen > = len_host ) slen = len_host - 1 ;
for ( size_t i = 0 ; i < slen ; i + + ) host [ i ] = tolower ( p [ i ] ) ;
host [ slen ] = 0 ;
if ( slen > = len_host ) slen = len_host - 1 ;
for ( size_t i = 0 ; i < slen ; i + + ) host [ i ] = tolower ( p [ i ] ) ;
host [ slen ] = 0 ;
}
return true ;
}
@ -45,7 +45,7 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
}
bool IsTLSClientHello ( const uint8_t * data , size_t len )
{
return len > = 6 & & data [ 0 ] = = 0x16 & & data [ 1 ] = = 0x03 & & data [ 2 ] > = 0x01 & & data [ 2 ] < = 0x03 & & data [ 5 ] = = 0x01 & & ( ntohs ( * ( uint16_t * ) ( data + 3 ) ) + 5 ) < = len ;
return len > = 6 & & data [ 0 ] = = 0x16 & & data [ 1 ] = = 0x03 & & data [ 2 ] > = 0x01 & & data [ 2 ] < = 0x03 & & data [ 5 ] = = 0x01 & & ( ntohs ( * ( uint16_t * ) ( data + 3 ) ) + 5 ) < = len ;
}
bool TLSFindExt ( const uint8_t * data , size_t len , uint16_t type , const uint8_t * * ext , size_t * len_ext )
{
@ -66,36 +66,36 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
// <CompressionMethods>
// u16 ExtensionsLength
size_t l , ll ;
size_t l , ll ;
l = 1 + 2 + 2 + 1 + 3 + 2 + 32 ;
l = 1 + 2 + 2 + 1 + 3 + 2 + 32 ;
// SessionIDLength
if ( len < ( l + 1 ) ) return false ;
ll = data [ 6 ] < < 16 | data [ 7 ] < < 8 | data [ 8 ] ; // HandshakeProtocol length
if ( len < ( ll + 9 ) ) return false ;
l + = data [ l ] + 1 ;
if ( len < ( l + 1 ) ) return false ;
ll = data [ 6 ] < < 16 | data [ 7 ] < < 8 | data [ 8 ] ; // HandshakeProtocol length
if ( len < ( ll + 9 ) ) return false ;
l + = data [ l ] + 1 ;
// CipherSuitesLength
if ( len < ( l + 2 ) ) return false ;
l + = ntohs ( * ( uint16_t * ) ( data + l ) ) + 2 ;
if ( len < ( l + 2 ) ) return false ;
l + = ntohs ( * ( uint16_t * ) ( data + l ) ) + 2 ;
// CompressionMethodsLength
if ( len < ( l + 1 ) ) return false ;
l + = data [ l ] + 1 ;
if ( len < ( l + 1 ) ) return false ;
l + = data [ l ] + 1 ;
// ExtensionsLength
if ( len < ( l + 2 ) ) return false ;
if ( len < ( l + 2 ) ) return false ;
data + = l ; len - = l ;
l = ntohs ( * ( uint16_t * ) data ) ;
data + = 2 ; len - = 2 ;
if ( l < len ) return false ;
data + = l ; len - = l ;
l = ntohs ( * ( uint16_t * ) data ) ;
data + = 2 ; len - = 2 ;
if ( l < len ) return false ;
uint16_t ntype = htons ( type ) ;
while ( l > = 4 )
uint16_t ntype = htons ( type ) ;
while ( l > = 4 )
{
uint16_t etype = * ( uint16_t * ) data ;
size_t elen = ntohs ( * ( uint16_t * ) ( data + 2 ) ) ;
data + = 4 ; l - = 4 ;
if ( l < elen ) break ;
if ( etype = = ntype )
uint16_t etype = * ( uint16_t * ) data ;
size_t elen = ntohs ( * ( uint16_t * ) ( data + 2 ) ) ;
data + = 4 ; l - = 4 ;
if ( l < elen ) break ;
if ( etype = = ntype )
{
if ( ext & & len_ext )
{
@ -104,7 +104,7 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
}
return true ;
}
data + = elen ; l - = elen ;
data + = elen ; l - = elen ;
}
return false ;
@ -114,19 +114,76 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
const uint8_t * ext ;
size_t elen ;
if ( ! TLSFindExt ( data , len , 0 , & ext , & elen ) ) return false ;
if ( ! TLSFindExt ( data , len , 0 , & ext , & elen ) ) return false ;
// u16 data+0 - name list length
// u8 data+2 - server name type. 0=host_name
// u16 data+3 - server name length
if ( elen < 5 | | ext [ 2 ] ! = 0 ) return false ;
size_t slen = ntohs ( * ( uint16_t * ) ( ext + 3 ) ) ;
ext + = 5 ; elen - = 5 ;
if ( slen < elen ) return false ;
if ( elen < 5 | | ext [ 2 ] ! = 0 ) return false ;
size_t slen = ntohs ( * ( uint16_t * ) ( ext + 3 ) ) ;
ext + = 5 ; elen - = 5 ;
if ( slen < elen ) return false ;
if ( ext & & len_host )
{
if ( slen > = len_host ) slen = len_host - 1 ;
for ( size_t i = 0 ; i < slen ; i + + ) host [ i ] = tolower ( ext [ i ] ) ;
host [ slen ] = 0 ;
if ( slen > = len_host ) slen = len_host - 1 ;
for ( size_t i = 0 ; i < slen ; i + + ) host [ i ] = tolower ( ext [ i ] ) ;
host [ slen ] = 0 ;
}
return true ;
}
# define QUIC_MAX_CID_LENGTH 20
/* Returns the QUIC draft version or 0 if not applicable. */
static inline uint8_t quic_draft_version ( uint32_t version ) {
/* IETF Draft versions */
if ( ( version > > 8 ) = = 0xff0000 ) {
return ( uint8_t ) version ;
}
/* Facebook mvfst, based on draft -22. */
if ( version = = 0xfaceb001 ) {
return 22 ;
}
/* Facebook mvfst, based on draft -27. */
if ( version = = 0xfaceb002 | | version = = 0xfaceb00e ) {
return 27 ;
}
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
* but we must return a sensible value */
if ( version = = 0x51303530 | |
version = = 0x54303530 | |
version = = 0x54303531 ) {
return 27 ;
}
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
" Versions that follow the pattern 0x?a?a?a?a are reserved for use in
forcing version negotiation to be exercised "
It is tricky to return a correct draft version : such number is primarily
used to select a proper salt ( which depends on the version itself ) , but
we don ' t have a real version here ! Let ' s hope that we need to handle
only latest drafts . . . */
if ( ( version & 0x0F0F0F0F ) = = 0x0a0a0a0a ) {
return 29 ;
}
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
final draft version */
if ( version = = 0x00000001 ) {
return 34 ;
}
/* QUIC Version 2 */
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
if ( version = = 0x709A50C4 ) {
return 100 ;
}
return 0 ;
}
bool IsQUICInitial ( uint8_t * data , size_t len )
{
// long header, fixed bit, type=initial
if ( len < 512 | | ( data [ 0 ] & 0xF0 ) ! = 0xC0 ) return false ;
uint8_t * p = data + 1 ;
uint32_t ver = ntohl ( * ( uint32_t * ) p ) ;
if ( quic_draft_version ( ver ) < 11 ) return false ;
p + = 4 ;
if ( ! * p | | * p > QUIC_MAX_CID_LENGTH ) return false ;
return true ;
}