src/payload.c
static int
smp_fetch_ssl_hello_sni(struct proxy *px, struct session *s, void *l7, unsigned int opt,
                        const struct arg *args, struct sample *smp)
{
	int hs_len, ext_len, bleft;
	struct channel *chn;
	unsigned char *data;

	if (!s)
		goto not_ssl_hello;

	chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;

	bleft = chn->buf->i;
	data = (unsigned char *)chn->buf->p;

	/* Check for SSL/TLS Handshake */
	if (!bleft)
		goto too_short;
	if (*data != 0x16)
		goto not_ssl_hello;

	/* Check for TLSv1 or later (SSL version >= 3.1) */
	if (bleft < 3)
		goto too_short;
	if (data[1] < 0x03 || data[2] < 0x01)
		goto not_ssl_hello;

	if (bleft < 5)
		goto too_short;
	hs_len = (data[3] << 8) + data[4];
	if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
		goto not_ssl_hello; /* too short to have an extension */

	data += 5; /* enter TLS handshake */
	bleft -= 5;

	/* Check for a complete client hello starting at <data> */
	if (bleft < 1)
		goto too_short;
	if (data[0] != 0x01) /* msg_type = Client Hello */
		goto not_ssl_hello;

	/* Check the Hello's length */
	if (bleft < 4)
		goto too_short;
	hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
	if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
		goto not_ssl_hello; /* too short to have an extension */

	/* We want the full handshake here */
	if (bleft < hs_len)
		goto too_short;

	data += 4;
	/* Start of the ClientHello message */
	if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
		goto not_ssl_hello;

	ext_len = data[34]; /* session_id_len */
	if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
		goto not_ssl_hello;

	/* Jump to cipher suite */
	hs_len -= 35 + ext_len;
	data   += 35 + ext_len;

	if (hs_len < 4 ||                               /* minimum one cipher */
	    (ext_len = (data[0] << 8) + data[1]) < 2 || /* minimum 2 bytes for a cipher */
	    ext_len > hs_len)
		goto not_ssl_hello;

	/* Jump to the compression methods */
	hs_len -= 2 + ext_len;
	data   += 2 + ext_len;

	if (hs_len < 2 ||                       /* minimum one compression method */
	    data[0] < 1 || data[0] > hs_len)    /* minimum 1 bytes for a method */
		goto not_ssl_hello;

	/* Jump to the extensions */
	hs_len -= 1 + data[0];
	data   += 1 + data[0];

	if (hs_len < 2 ||                       /* minimum one extension list length */
	    (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) /* list too long */
		goto not_ssl_hello;

	hs_len = ext_len; /* limit ourselves to the extension length */
	data += 2;

	while (hs_len >= 4) {
		int ext_type, name_type, srv_len, name_len;

		ext_type = (data[0] << 8) + data[1];
		ext_len  = (data[2] << 8) + data[3];

		if (ext_len > hs_len - 4) /* Extension too long */
			goto not_ssl_hello;

		if (ext_type == 0) { /* Server name */
			if (ext_len < 2) /* need one list length */
				goto not_ssl_hello;

			srv_len = (data[4] << 8) + data[5];
			if (srv_len < 4 || srv_len > hs_len - 6)
				goto not_ssl_hello; /* at least 4 bytes per server name */

			name_type = data[6];
			name_len = (data[7] << 8) + data[8];

			if (name_type == 0) { /* hostname */
				smp->type = SMP_T_CSTR;
				smp->data.str.str = (char *)data + 9;
				smp->data.str.len = name_len;
				smp->flags = SMP_F_VOLATILE;
				return 1;
			}
		}

		hs_len -= 4 + ext_len;
		data   += 4 + ext_len;
	}
	/* server name not found */
	goto not_ssl_hello;

 too_short:
	smp->flags = SMP_F_MAY_CHANGE;

 not_ssl_hello:

	return 0;
}
/* Try to extract the Server Name Indication that may be presented in a TLS
 * client hello handshake message. The format of the message is the following
 * (cf RFC5246 + RFC6066) :
 * TLS frame :
 *   - uint8  type                            = 0x16   (Handshake)
 *   - uint16 version                        >= 0x0301 (TLSv1)
 *   - uint16 length                                   (frame length)
 *   - TLS handshake :
 *     - uint8  msg_type                      = 0x01   (ClientHello)
 *     - uint24 length                                 (handshake message length)
 *     - ClientHello :
 *       - uint16 client_version             >= 0x0301 (TLSv1)
 *       - uint8 Random[32]                  (4 first ones are timestamp)
 *       - SessionID :
 *         - uint8 session_id_len (0..32)              (SessionID len in bytes)
 *         - uint8 session_id[session_id_len]
 *       - CipherSuite :
 *         - uint16 cipher_len               >= 2      (Cipher length in bytes)
 *         - uint16 ciphers[cipher_len/2]
 *       - CompressionMethod :
 *         - uint8 compression_len           >= 1      (# of supported methods)
 *         - uint8 compression_methods[compression_len]
 *       - optional client_extension_len               (in bytes)
 *       - optional sequence of ClientHelloExtensions  (as many bytes as above):
 *         - uint16 extension_type            = 0 for server_name
 *         - uint16 extension_len
 *         - opaque extension_data[extension_len]
 *           - uint16 server_name_list_len             (# of bytes here)
 *           - opaque server_names[server_name_list_len bytes]
 *             - uint8 name_type              = 0 for host_name
 *             - uint16 name_len
 *             - opaque hostname[name_len bytes]
 */
Try to extract the Server Name Indication that may be presented in a TLS
client hello handshake message.
Try to extract the Server Name Indication that may be presented in a TLS client hello handshake message .
static int
smp_fetch_ssl_hello_sni(struct proxy *px, struct session *s, void *l7, unsigned int opt,
                        const struct arg *args, struct sample *smp)
{
	int hs_len, ext_len, bleft;
	struct channel *chn;
	unsigned char *data;
	if (!s)
		goto not_ssl_hello;
	chn = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? s->rep : s->req;
	bleft = chn->buf->i;
	data = (unsigned char *)chn->buf->p;
	if (!bleft)
		goto too_short;
	if (*data != 0x16)
		goto not_ssl_hello;
	if (bleft < 3)
		goto too_short;
	if (data[1] < 0x03 || data[2] < 0x01)
		goto not_ssl_hello;
	if (bleft < 5)
		goto too_short;
	hs_len = (data[3] << 8) + data[4];
	if (hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
		goto not_ssl_hello; 
	data += 5; 
	bleft -= 5;
	if (bleft < 1)
		goto too_short;
	if (data[0] != 0x01) 
		goto not_ssl_hello;
	if (bleft < 4)
		goto too_short;
	hs_len = (data[1] << 16) + (data[2] << 8) + data[3];
	if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
		goto not_ssl_hello; 
	if (bleft < hs_len)
		goto too_short;
	data += 4;
	if (data[0] < 0x03 || data[1] < 0x01) 
		goto not_ssl_hello;
	ext_len = data[34]; 
	if (ext_len > 32 || ext_len > (hs_len - 35)) 
		goto not_ssl_hello;
	hs_len -= 35 + ext_len;
	data   += 35 + ext_len;
	if (hs_len < 4 ||                               
	    (ext_len = (data[0] << 8) + data[1]) < 2 || 
	    ext_len > hs_len)
		goto not_ssl_hello;
	hs_len -= 2 + ext_len;
	data   += 2 + ext_len;
	if (hs_len < 2 ||                       
	    data[0] < 1 || data[0] > hs_len)    
		goto not_ssl_hello;
	hs_len -= 1 + data[0];
	data   += 1 + data[0];
	if (hs_len < 2 ||                       
	    (ext_len = (data[0] << 8) + data[1]) > hs_len - 2) 
		goto not_ssl_hello;
	hs_len = ext_len; 
	data += 2;
	while (hs_len >= 4) {
		int ext_type, name_type, srv_len, name_len;
		ext_type = (data[0] << 8) + data[1];
		ext_len  = (data[2] << 8) + data[3];
		if (ext_len > hs_len - 4) 
			goto not_ssl_hello;
		if (ext_type == 0) { 
			if (ext_len < 2) 
				goto not_ssl_hello;
			srv_len = (data[4] << 8) + data[5];
			if (srv_len < 4 || srv_len > hs_len - 6)
				goto not_ssl_hello; 
			name_type = data[6];
			name_len = (data[7] << 8) + data[8];
			if (name_type == 0) { 
				smp->type = SMP_T_CSTR;
				smp->data.str.str = (char *)data + 9;
				smp->data.str.len = name_len;
				smp->flags = SMP_F_VOLATILE;
				return 1;
			}
		}
		hs_len -= 4 + ext_len;
		data   += 4 + ext_len;
	}
	goto not_ssl_hello;
 too_short:
	smp->flags = SMP_F_MAY_CHANGE;
 not_ssl_hello:
	return 0;
}
static int smp_fetch_ssl_hello_sni ( struct proxy * px , struct session * s , void * l7 , unsigned int opt , const struct arg * args , struct sample * smp ) { int hs_len , ext_len , bleft ; struct channel * chn ; unsigned char * data ; if ( ! s ) goto not_ssl_hello ; chn = ( ( opt & SMP_OPT_DIR ) == SMP_OPT_DIR_RES ) ? s -> rep : s -> req ; bleft = chn -> buf -> i ; data = ( unsigned char * ) chn -> buf -> p ; if ( ! bleft ) goto too_short ; if ( * data != 0x16 ) goto not_ssl_hello ; if ( bleft < 3 ) goto too_short ; if ( data [ 1 ] < 0x03 || data [ 2 ] < 0x01 ) goto not_ssl_hello ; if ( bleft < 5 ) goto too_short ; hs_len = ( data [ 3 ] << 8 ) + data [ 4 ] ; if ( hs_len < 1 + 3 + 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2 ) goto not_ssl_hello ; data += 5 ; bleft -= 5 ; if ( bleft < 1 ) goto too_short ; if ( data [ 0 ] != 0x01 ) goto not_ssl_hello ; if ( bleft < 4 ) goto too_short ; hs_len = ( data [ 1 ] << 16 ) + ( data [ 2 ] << 8 ) + data [ 3 ] ; if ( hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2 ) goto not_ssl_hello ; if ( bleft < hs_len ) goto too_short ; data += 4 ; if ( data [ 0 ] < 0x03 || data [ 1 ] < 0x01 ) goto not_ssl_hello ; ext_len = data [ 34 ] ; if ( ext_len > 32 || ext_len > ( hs_len - 35 ) ) goto not_ssl_hello ; hs_len -= 35 + ext_len ; data += 35 + ext_len ; if ( hs_len < 4 || ( ext_len = ( data [ 0 ] << 8 ) + data [ 1 ] ) < 2 || ext_len > hs_len ) goto not_ssl_hello ; hs_len -= 2 + ext_len ; data += 2 + ext_len ; if ( hs_len < 2 || data [ 0 ] < 1 || data [ 0 ] > hs_len ) goto not_ssl_hello ; hs_len -= 1 + data [ 0 ] ; data += 1 + data [ 0 ] ; if ( hs_len < 2 || ( ext_len = ( data [ 0 ] << 8 ) + data [ 1 ] ) > hs_len - 2 ) goto not_ssl_hello ; hs_len = ext_len ; data += 2 ; while ( hs_len >= 4 ) { int ext_type , name_type , srv_len , name_len ; ext_type = ( data [ 0 ] << 8 ) + data [ 1 ] ; ext_len = ( data [ 2 ] << 8 ) + data [ 3 ] ; if ( ext_len > hs_len - 4 ) goto not_ssl_hello ; if ( ext_type == 0 ) { if ( ext_len < 2 ) goto not_ssl_hello ; srv_len = ( data [ 4 ] << 8 ) + data [ 5 ] ; if ( srv_len < 4 || srv_len > hs_len - 6 ) goto not_ssl_hello ; name_type = data [ 6 ] ; name_len = ( data [ 7 ] << 8 ) + data [ 8 ] ; if ( name_type == 0 ) { smp -> type = SMP_T_CSTR ; smp -> data . str . str = ( char * ) data + 9 ; smp -> data . str . len = name_len ; smp -> flags = SMP_F_VOLATILE ; return 1 ; } } hs_len -= 4 + ext_len ; data += 4 + ext_len ; } goto not_ssl_hello ; too_short : smp -> flags = SMP_F_MAY_CHANGE ; not_ssl_hello : return 0 ; }
Try to extract the Server Name Indication that may be presented in a TLS
 client hello handshake message.
Try to extract the Server Name Indication that may be presented in a TLS client hello handshake message .
/* Check for SSL/TLS Handshake */ /* Check for TLSv1 or later (SSL version >= 3.1) */ /* too short to have an extension */ /* enter TLS handshake */ /* Check for a complete client hello starting at <data> */ /* msg_type = Client Hello */ /* Check the Hello's length */ /* too short to have an extension */ /* We want the full handshake here */ /* Start of the ClientHello message */ /* TLSv1 minimum */ /* session_id_len */ /* check for correct session_id len */ /* Jump to cipher suite */ /* minimum one cipher */ /* minimum 2 bytes for a cipher */ /* Jump to the compression methods */ /* minimum one compression method */ /* minimum 1 bytes for a method */ /* Jump to the extensions */ /* minimum one extension list length */ /* list too long */ /* limit ourselves to the extension length */ /* Extension too long */ /* Server name */ /* need one list length */ /* at least 4 bytes per server name */ /* hostname */ /* server name not found */