#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; ext_len=get_value(payload, &used_len, 2); //Server Name List length if(ext_len>0 && ext_len>payload_len) { return 0; } if(get_value(payload, &used_len, 1)==0) //Server Name type { ext_len=get_value(payload, &used_len, 2); //Server Name length if(ext_len<0 || ext_len>payload_len) { return 0; } quic_stream->sni_idx=quic_stream->ext_tag_num++; get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->sni_idx]), ext_len, EXTENSION_SERVER_NAME, thread_seq); } else { return 0; } 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,ret=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) && (extension_total_len!=payload_len-used_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: ret=parse_encrypt_server_name(quic_stream, payload+used_len, skip_len, 0); if(ret==0) { break; } 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; }