diff --git a/demo/correct.txt b/demo/correct.txt new file mode 100644 index 0000000..9579c66 Binary files /dev/null and b/demo/correct.txt differ diff --git a/demo/demo.cpp b/demo/demo.cpp new file mode 100644 index 0000000..e69845b --- /dev/null +++ b/demo/demo.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gquic_process.h" +#include "quic_analysis.h" +#include "parser_quic.h" + +static int check_length(int last_len, int field_len) +{ + return ((last_len-field_len>0) ? 1 : 0); +} + + +int get_quic_tlv(char *start_pos, quic_tlv_t *tlv, int len, int type, int thread_seq) +{ + if(tlv->value==NULL && len>0) + { + tlv->value=(char *)calloc(1, len+1); + memset(tlv->value, 0, len+1); + tlv->length=len; + tlv->type=type; + memcpy(tlv->value, start_pos, tlv->length); + } + + return 0; +} + +static int get_value(unsigned char *payload, int *offset, int len) +{ + switch(len) + { + case 1: + return (int)(payload[(*offset)++]); + break; + case 2: + (*offset)+=len; + return (int)ntohs(*(unsigned short *)(payload+*offset-len)); + break; + case 3: + (*offset)+=len; + return ((int)*(payload-2+*offset)<<16| + (int)*(payload-1+*offset)<<8| + (int)*(payload+*offset)<<0); + break; + case 4: + (*offset)+=len; + return (int)ntohl(*(unsigned int *)(payload+*offset-len)); + break; + case 32: + (*offset)+=len; + return 0; + break; + default: + break; + } + + return 0; +} + +int parse_encrypt_parameter(struct _quic_stream *quic_stream, unsigned char *payload, int payload_len, int thread_seq) +{ + int used_len=0,length=0; + while(payload_len>used_len) + { + if(payload[used_len]> 0x00 && payload[used_len]<=0x20) + { + get_value(payload, &used_len, 1); //type=1 + length=get_value(payload, &used_len, 1); // length=1 + used_len+=length; + + continue; + } + + if((*(unsigned short *)(payload+used_len)) == htons(EXT_QUIC_PARAM_USER_AGENT)) + { + quic_stream->ua_idx=quic_stream->ext_tag_num++; + get_value(payload, &used_len, 2); //type=2 + length=get_value(payload, &used_len, 1); // length=1 + get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->ua_idx]), length, EXT_QUIC_PARAM_USER_AGENT, thread_seq); + used_len+=length; + + continue; + } + + if(*(unsigned int *)(payload+used_len) == htonl(EXT_QUIC_PARAM_QUIC_VERSION)) + { + quic_stream->ver_idx=quic_stream->ext_tag_num++; + get_value(payload, &used_len, 4); //type=4 + length=get_value(payload, &used_len, 1); // length=1 + get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->ver_idx]), length, EXT_QUIC_PARAM_QUIC_VERSION, thread_seq); + *(unsigned int *)quic_stream->ext_tags[quic_stream->ver_idx].value=(unsigned int)htonl(*(unsigned int *)quic_stream->ext_tags[quic_stream->ver_idx].value); + used_len+=length; + + continue; + } + + if((*(unsigned int *)(payload+used_len))== htonl(EXT_QUIC_PARAM_GREASE_HIGH4) && (*(unsigned int *)(payload+used_len+4))== htonl(EXT_QUIC_PARAM_GREASE_LOW4)) + { + used_len+=8; //type=8 + length=get_value(payload, &used_len, 1); // length=1 + used_len+=length; + + continue; + } + + break; + } + + return 0; +} + +int parse_encrypt_server_name(struct _quic_stream *quic_stream, unsigned char *payload, int payload_len, int thread_seq) +{ + int ext_len=0,used_len=0; + + quic_stream->sni_idx=quic_stream->ext_tag_num++; + get_value(payload, &used_len, 2); //Server Name List length + if(get_value(payload, &used_len, 1)==0) //Server Name type + { + ext_len=get_value(payload, &used_len, 2); //Server Name length + get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->sni_idx]), ext_len, EXTENSION_SERVER_NAME, thread_seq); + } + + return 1; +} + +int parse_encrypt_client_hello(void *pstream, struct _quic_stream *quic_stream, void *a_packet, unsigned char *payload, int payload_len) +{ + int used_len=0; + int flags=0; + int skip_len=0,client_hello_len=0; + int ext_type=0, extension_total_len=0; + + get_value(payload, &used_len, 1); //handshake type + client_hello_len=get_value(payload, &used_len, 3); //client hello length + get_value(payload, &used_len, 2); //ssl_version + + get_value(payload, &used_len, 32); //Random + + skip_len=(int)get_value(payload, &used_len, 1); //Session ID length + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } + used_len+=skip_len; + + skip_len=(int)get_value(payload, &used_len, 2); //Ciper Suites length + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } + used_len+=skip_len; + + skip_len=(int)get_value(payload, &used_len, 1); //Compression Methods + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } + used_len+=skip_len; + + extension_total_len=(int)get_value(payload, &used_len, 2); //Extension length + if(!check_length(payload_len-used_len, extension_total_len)) + { + return flags; + } + + quic_stream->ext_tags=(quic_tlv_t *)calloc(1, sizeof(quic_tlv_t)*3); + memset(quic_stream->ext_tags, 0, sizeof(quic_tlv_t)*3); + + while(extension_total_len>used_len) + { + ext_type=get_value(payload, &used_len, 2); //Extension type + skip_len=get_value(payload, &used_len, 2); //length + if(!check_length(payload_len-used_len, skip_len) || skip_len==0) + { + return flags; + } + + switch(ext_type) + { + case EXTENSION_SERVER_NAME: + parse_encrypt_server_name(quic_stream, payload+used_len, skip_len, 0); + flags=1; + break; + case EXTENSION_QUIC_PARAM: + parse_encrypt_parameter(quic_stream, payload+used_len, skip_len, 0); + break; + case EXTENSION_SUPPORT_GROUP: + case EXTENSION_APP_PROT_NEGO: + case EXTENSION_SIG_ALGORITHM: + case EXTENSION_KEY_SHARE: + case EXTENSION_PSK_EXCHANGE: + case EXTENSION_SUPP_SSL_VER: + case EXTENSION_COMPRESS_CERT: + break; + default: + break; + } + + used_len+=skip_len; + } + + return flags; +} + + +int main(int argc, char *argv[]) +{ + if(argc<1) + { + return -1; + } + + struct stat statbuf; + if (stat(argv[1], &statbuf) == -1) + { + return -1; + } + + unsigned char *payload=(unsigned char *)calloc(1, statbuf.st_size); + FILE *fp=fopen(argv[1], "rb"); + if(fp) + { + int size=fread(payload, 1, 1315, fp); + assert(size==1315); + //assert(size==statbuf.st_size); + + struct _quic_stream * quic_stream=(struct _quic_stream *)calloc(1, sizeof(struct _quic_stream)); + parse_encrypt_client_hello(NULL, quic_stream, NULL, payload+4, 1314)-4; + + fclose(fp); + fp=NULL; + + free(quic_stream); + quic_stream=NULL; + + free(payload); + payload=NULL; + + } + + return 0; +} diff --git a/demo/error.txt b/demo/error.txt new file mode 100644 index 0000000..42e9bd9 Binary files /dev/null and b/demo/error.txt differ diff --git a/src/gquic_process.cpp b/src/gquic_process.cpp index bce6600..f74ec57 100644 --- a/src/gquic_process.cpp +++ b/src/gquic_process.cpp @@ -15,6 +15,7 @@ #include "quic_analysis.h" #include "parser_quic.h" + int is_iquic(enum _QUIC_VERSION quic_version) { switch(quic_version) @@ -707,7 +708,7 @@ int gquic_frame_type_stream(struct streaminfo *pstream, struct _quic_context* _c { case GQUIC_VERSION_Q041: *used_len+=1; // unknown - case GQUIC_VERSION_Q044: + //case GQUIC_VERSION_Q044: message_tag=(unsigned int)ntohl(*(unsigned int *)(payload+*used_len)); *used_len+=4; @@ -1056,15 +1057,31 @@ int parse_encrypt_client_hello(struct streaminfo *pstream, struct _quic_stream * get_value(payload, &used_len, 32); //Random skip_len=(int)get_value(payload, &used_len, 1); //Session ID length + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } used_len+=skip_len; skip_len=(int)get_value(payload, &used_len, 2); //Ciper Suites length + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } used_len+=skip_len; skip_len=(int)get_value(payload, &used_len, 1); //Compression Methods + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } used_len+=skip_len; extension_total_len=(int)get_value(payload, &used_len, 2); //Extension length + if(!check_length(payload_len-used_len, extension_total_len)) + { + return flags; + } quic_stream->ext_tags=(quic_tlv_t *)dictator_malloc(pstream->threadnum, sizeof(quic_tlv_t)*3); memset(quic_stream->ext_tags, 0, sizeof(quic_tlv_t)*3); @@ -1073,6 +1090,11 @@ int parse_encrypt_client_hello(struct streaminfo *pstream, struct _quic_stream * { ext_type=get_value(payload, &used_len, 2); //Extension type skip_len=get_value(payload, &used_len, 2); //length + if(!check_length(payload_len-used_len, skip_len)) + { + return flags; + } + switch(ext_type) { case EXTENSION_SERVER_NAME: @@ -1120,7 +1142,7 @@ int parse_decrypt_quic(struct streaminfo *pstream, struct _quic_context* _contex _context->quic_info.client_hello=(struct _quic_stream *)dictator_malloc(pstream->threadnum, sizeof(struct _quic_stream)); memset(_context->quic_info.client_hello, 0, sizeof(struct _quic_stream)); } - ret=parse_encrypt_client_hello(pstream, _context->quic_info.client_hello, a_packet, payload+*used_len, payload_len); //Frame Type=1, offset=1, length=2 + ret=parse_encrypt_client_hello(pstream, _context->quic_info.client_hello, a_packet, payload+*used_len, payload_len-*used_len); //Frame Type=1, offset=1, length=2 if(ret>0 && _context->call_business) { state=quic_callPlugins(pstream, _context, (void *)(_context->quic_info.client_hello), sizeof(void *), QUIC_CLIENT_HELLO_MASK, a_packet); @@ -1183,7 +1205,7 @@ int quic_process(struct streaminfo *pstream, struct _quic_context* _context, int ret=parse_gquic_Q046(pstream, _context, a_packet, (char *)udp_detail->pdata, udp_detail->datalen, &used_len); break; default: - if(is_gquic>=GQUIC_VERSION_Q001 && is_gquic<=GQUIC_VERSION_Q043) + if(is_gquic>=GQUIC_VERSION_Q001 && is_gquic<=GQUIC_VERSION_Q046) { ret=gquic_proc_unencrypt(pstream, _context, a_packet, (char *)udp_detail->pdata, udp_detail->datalen, &used_len); }