diff --git a/README.md b/README.md index 96ee241..d592b56 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # gquic gquic protocol parse plugin + + + +Chromium currently support two kinds of QUIC versions, GoogleQUIC and IETF QUIC. + +https://quiche.googlesource.com/quiche/+/refs/heads/master/quic/core/quic_versions.h \ No newline at end of file diff --git a/src/gquic.h b/src/gquic.h index 2349548..6cbcdf5 100644 --- a/src/gquic.h +++ b/src/gquic.h @@ -8,24 +8,6 @@ #ifndef SRC_GQUIC_H_ #define SRC_GQUIC_H_ -enum GQUIC_VERSION -{ - GQUIC_UNKNOWN=0, - GQUIC_OTHERS, - GQUIC_Q046 -}; - - -#include -#define MAX_EXTENSION_NUM 128 -#define MAX_TAG_VALUE_LEN 257 -#define SERVER_NAME_LEN 128 -//add in 20191207 -#define USER_AGENT_LEN 512 -#define RANDOM_LEN 32 -#define QUIC_VERSION_LEN 4 - - #define QUIC_INTEREST_KEY (1< + #include -#include +#include +#include +#include #include +#include "gquic_process.h" +#include "quic_analysis.h" -#define C2S 0x01 -#define S2C 0x02 -#define GQUIC_HANDSHAKE_LEN 12+1+1+4+4 -#define DIVERSIFICATION_NONCE_LEN 32 - -extern struct quic_param_t g_quic_param; - -enum gquic_type +int quic_getLinkState(struct _quic_context *_context) { - GQUIC=1, - UNKNOWN_QUIC_TYPE -}; + UCHAR state = 0; + + if(0==_context->link_state) + { + state=SESSION_STATE_PENDING|SESSION_STATE_DATA; + } + else + { + state=SESSION_STATE_DATA; + } + + return state; +} -enum gquic_handshake_type +char quic_callPlugins(struct streaminfo *pstream, struct _quic_context *_context, void *buff, int buff_len, enum quic_interested_region region_mask, void *a_packet) { - QUIC_Crypto=1, - UNKNOWN_HANDSHAKE_TYPE -}; + char state=PROT_STATE_GIVEME; + char app_state=APP_STATE_GIVEME; + stSessionInfo session_info={0}; + + session_info.plugid=g_quic_param.quic_plugid; + session_info.prot_flag=(((unsigned long long)1)<quic_info); + session_info.buf=buff; + session_info.buflen=buff_len; + + state=PROT_PROCESS(&session_info, &(_context->business_pme), pstream->threadnum, pstream, a_packet); + if(state&PROT_STATE_DROPPKT) + { + app_state=APP_STATE_DROPPKT; + } + + if(state&PROT_STATE_DROPME) + { + if(app_state&APP_STATE_DROPPKT) + { + app_state|=APP_STATE_DROPME; + } + else + { + app_state=APP_STATE_DROPME; + } + } + + if(state&PROT_STATE_GIVEME) + { + app_state=APP_STATE_GIVEME; + } + + return app_state; +} + + +unsigned long long get_variable_length(char *p, int offset, int v_len) +{ + switch(v_len) + { + case 1: + return (unsigned long long)(p[offset]); + break; + case 2: + return (unsigned long long)ntohs(*(unsigned short *)((char *)p+offset)); + break; + case 3: + return (unsigned long long)*(p+0+offset)<<16| + (unsigned long long)*(p+1+offset)<<8| + (unsigned long long)*(p+2+offset)<<0; + break; + case 4: + return (unsigned long long)ntohl(*(unsigned int *)(p+offset)); + break; + case 5: + return (unsigned long long)*((unsigned char *)(p)+0+offset)<<32| + (unsigned long long)*((unsigned char *)(p)+1+offset)<<24| + (unsigned long long)*((unsigned char *)(p)+2+offset)<<16| + (unsigned long long)*((unsigned char *)(p)+3+offset)<<8| + (unsigned long long)*((unsigned char *)(p)+4+offset)<<0; + break; + case 6: + return (unsigned long long)*((unsigned char *)(p)+0+offset)<<40| + (unsigned long long)*((unsigned char *)(p)+1+offset)<<32| + (unsigned long long)*((unsigned char *)(p)+2+offset)<<24| + (unsigned long long)*((unsigned char *)(p)+3+offset)<<16| + (unsigned long long)*((unsigned char *)(p)+4+offset)<<8| + (unsigned long long)*((unsigned char *)(p)+5+offset)<<0; + break; + case 7: + return (unsigned long long)*((unsigned char *)(p)+0+offset)<<56| + (unsigned long long)*((unsigned char *)(p)+1+offset)<<40| + (unsigned long long)*((unsigned char *)(p)+2+offset)<<32| + (unsigned long long)*((unsigned char *)(p)+3+offset)<<24| + (unsigned long long)*((unsigned char *)(p)+4+offset)<<16| + (unsigned long long)*((unsigned char *)(p)+5+offset)<<8; + (unsigned long long)*((unsigned char *)(p)+6+offset)<<0; + break; + case 8: + return (unsigned long long)*((unsigned char *)(p)+0+offset)<<56| + (unsigned long long)*((unsigned char *)(p)+1+offset)<<48| + (unsigned long long)*((unsigned char *)(p)+2+offset)<<40| + (unsigned long long)*((unsigned char *)(p)+3+offset)<<32| + (unsigned long long)*((unsigned char *)(p)+4+offset)<<24| + (unsigned long long)*((unsigned char *)(p)+5+offset)<<16| + (unsigned long long)*((unsigned char *)(p)+6+offset)<<8| + (unsigned long long)*((unsigned char *)(p)+7+offset)<<0; + break; + default: + break; + } + + return 0; +} int get_quic_tlv(char *start_pos, quic_tlv_t *tlv, int len, int type, int thread_seq) { - if(tlv->ptr_value==NULL && len>0) + if(tlv->value==NULL && len>0) { - tlv->ptr_value=(char *)dictator_malloc(thread_seq, len); - memset(tlv->ptr_value, 0, len); + tlv->value=(char *)dictator_malloc(thread_seq, len+1); + memset(tlv->value, 0, len+1); tlv->length=len; tlv->type=type; - memcpy(tlv->ptr_value, start_pos, tlv->length); + memcpy(tlv->value, start_pos, tlv->length); } return 0; } -UINT32 get_stream_id(struct streaminfo *pstream, char* quic_data, UINT8 frame_type, UINT32 *skip_len) +int get_stream_id(struct streaminfo *pstream, struct _quic_context* _context, char* payload, unsigned char frame_type, int *used_len) { - UINT16 data_length=0; - UINT32 stream_id=0; - UINT8 stream_id_len=0; - UINT8 len_data=0,len_stream=0, len_offset=0; - - len_stream = read_stream_len(frame_type); - switch(len_stream) - { - case 1: - stream_id=quic_data[*skip_len]; - break; - case 2: - stream_id=a_pletoh16((void *)quic_data, *skip_len); - break; - case 3: - stream_id=a_pletoh24((void *)quic_data, *skip_len); - break; - default: - stream_id=a_pletoh32((void *)quic_data, *skip_len); - break; - } - - *skip_len+=len_stream; // stream ID length + int stream_len=0,offset_len=0; - if(frame_type&STREAM_D) + _context->quic_info.frame_hdr.frame_type=frame_type; + + stream_len=(frame_type&GQUIC_SPECIAL_FRAME_STREAM_ID)+1; + _context->quic_info.frame_hdr.stream_id=(unsigned int)get_variable_length(payload, *used_len, stream_len); + *used_len+=stream_len; // stream ID length + + if(frame_type&GQUIC_SPECIAL_FRAME_STREAM_DLEN) { - data_length=ntohs(a_pletoh16((void *)quic_data, *skip_len)); - *skip_len+=2; //data length + _context->quic_info.frame_hdr.data_len=ntohs(*(unsigned short *)(payload+*used_len)); + *used_len+=2; //data length } - len_offset=read_offset_len(frame_type); - *skip_len+=len_offset; + offset_len=(frame_type&GQUIC_SPECIAL_FRAME_STREAM_OFFSET) ? (frame_type&GQUIC_SPECIAL_FRAME_STREAM_ID)+1 : 0; + _context->quic_info.frame_hdr.offset=get_variable_length(payload, *used_len, offset_len); + *used_len+=offset_len; MESA_handle_runtime_log(g_quic_param.logger, RLOG_LV_DEBUG, "QUIC_FRAME", - "stream_id: %u data length: %u offset length: %u addr: %s", - stream_id, - data_length, - len_offset, + "frame_type: 0X%02X stream_id: %u data length: %u offset length: %u addr: %s", + frame_type, + _context->quic_info.frame_hdr.stream_id, + _context->quic_info.frame_hdr.data_len, + offset_len, printaddr(&pstream->addr, pstream->threadnum)); - return stream_id; + return _context->quic_info.frame_hdr.stream_id; } -UINT32 get_packet_number(char* g_data_t, UINT32 offset, UINT8 pkn_len) +unsigned long long get_packet_number(char* data, int offset, char pkn_len) { switch(pkn_len) { case 1: - return g_data_t[offset]; + return (unsigned long long)data[offset]; break; case 2: - return ntohs(a_pletoh16((void *)g_data_t, offset)); + return (unsigned long long)ntohs(*(unsigned short *)(data+offset)); break; case 4: - return a_pletoh32((void *)g_data_t, offset); + return (unsigned long long)ntohl(*(unsigned int *)(data+offset)); break; - default: - return a_pletoh48((void *)g_data_t, offset); + case 8: + return get_variable_length(data, offset, 8);; break; } return 0; } -enum GQUIC_VERSION is_gquic_protocol(struct streaminfo *pstream, char *payload, uint32_t payload_len, uint8_t *pub_flags, uint32_t *version, uint32_t *skip_len) +// GQUIC version from 0 to 43 +static enum _QUIC_VERSION parse_q0to43_header(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len) { - uint32_t is_q064=0; - uint64_t connection_id = 0; - int connection_id_len = 0; - enum GQUIC_VERSION quic_version=GQUIC_UNKNOWN; + int i=0,len=0; + char public_flags=0; - if(a_canRead(5, payload_len, *skip_len)) + struct _quic_public_header *gquic_hdr=&(_context->quic_info.quic_hdr); + if(gquic_hdr==NULL) { - *skip_len+=1; - strncpy((char*)&is_q064, payload+(*skip_len), 4); - if(ntohl(is_q064)==VER_Q046) - { - *skip_len += 2; - *version=(payload[*skip_len]&0x0f)*10 + (payload[*skip_len+1]&0x0f); - *skip_len += 2; + gquic_hdr=(struct _quic_public_header *)dictator_malloc(pstream->threadnum, sizeof(struct _quic_public_header)); + memset(gquic_hdr, 0, sizeof(struct _quic_public_header)); + } - MESA_handle_runtime_log(g_quic_param.logger, - RLOG_LV_DEBUG, - "QUIC_PUB_FLAGS", - "version: Q0%u addr: %s", - *version, - printaddr(&pstream->addr, pstream->threadnum)); - - return GQUIC_Q046; + public_flags=payload[*used_len]; + *used_len+=1; + + //For Public Reset and Version Negotiation Packets (sent by the server) which don't have a packet number + if(!public_flags&GQUIC_PUBLIC_FLAG_PKT_NUM) + { + if(public_flags&GQUIC_PUBLIC_FLAG_VERSION) //Public Reset Packet + { + return QUIC_VERSION_UNKNOWN;// todo } - - *skip_len-=1; - } - - *pub_flags=payload[*skip_len]; // public flags - *skip_len+=1; - - if(*pub_flags>PACKET_PUBLIC_FLAGS_MAX) - { - return quic_version; - } - - connection_id_len=read_conn_id_len(*pub_flags); - connection_id=(connection_id_len==0) ? 0 : (a_pntoh64((void *)payload, *skip_len)); - *skip_len+=connection_id_len; // CID length - - if(payload[*skip_len]==PUBLIC_FLAG_VER_FST_BYTE && *pub_flags&PUBLIC_FLAG_VER) - { - *skip_len += 2; - *version=(payload[*skip_len]&0x0f)*10 + (payload[*skip_len+1]&0x0f); - *skip_len += 2; - quic_version=GQUIC_OTHERS; - } - - if(*pub_flags==PUBLIC_FLAG_NONCE) - { - *skip_len+=32; //diversification nonce - } - - UINT8 pkt_seq_len=read_seq_num_len(*pub_flags); - UINT32 pkt_seq=get_packet_number(payload, *skip_len, pkt_seq_len); - *skip_len+=pkt_seq_len; // skip pkt_num - - if(*pub_flags&PUBLIC_FLAG_VER) - { - //message authentication hash - *skip_len+=MSG_AUTH_HASH_LEN; - - if(*version>0 && *version<34) + else // Version Negotiation Packet { - *skip_len+=1; //private flags + return QUIC_VERSION_UNKNOWN; } } + gquic_hdr->public_flags=public_flags; + + if(gquic_hdr->public_flags&GQUIC_PUBLIC_FLAG_CID) + { + *(unsigned long long *)gquic_hdr->server_CID=get_variable_length(payload, *used_len, sizeof(gquic_hdr->server_CID)); + *used_len+=sizeof(unsigned long long); // CID length + } + + if(gquic_hdr->public_flags&GQUIC_PUBLIC_FLAG_VERSION && ntohs(*(unsigned short *)(payload+*used_len))==0x5130) + { + gquic_hdr->quic_version=(unsigned int)ntohl(*(unsigned int *)(payload+*used_len)); + *used_len+=sizeof(int); // skip version + } + else + { + return QUIC_VERSION_UNKNOWN; + } + + switch(gquic_hdr->public_flags&0x30) // packet number + { + case 0x30: // 6 bytes + gquic_hdr->packet_number=get_variable_length(payload, *used_len, 6); + *used_len+=6; + break; + case 0x20: // 4 bytes + gquic_hdr->packet_number=(unsigned long long)ntohl(*(unsigned int *)(payload+*used_len)); + *used_len+=4; + break; + case 0x10: // 2bytes + gquic_hdr->packet_number=(unsigned long long)ntohs(*(unsigned short *)(payload+*used_len)); + *used_len+=2; + break; + default: // 1 byte + gquic_hdr->packet_number=payload[*used_len]; + *used_len+=1; + break; + } + + if(gquic_hdr->public_flags==GQUIC_PUBLIC_FLAG_NONCE) + { + *used_len+=32; //diversification nonce + } + + if(gquic_hdr->public_flags&GQUIC_PUBLIC_FLAG_VERSION) + { + // Version 11 reduced the length of null encryption authentication tag from 16 to 12 bytes + if(gquic_hdr->quic_version > GQUIC_VERSION_Q010) + { + *used_len+=12; + } + else + { + *used_len+=16; + } + + // Version 34 removed entropy bits from packets and ACK frames, + // removed private flag from packet header and changed the ACK format to specify ranges of packets acknowledged rather than missing ranges. + if(gquic_hdr->quic_version < GQUIC_VERSION_Q034) + { + *used_len+=1; //private flags + } + } + + _context->is_quic==QUIC_TRUE; + MESA_handle_runtime_log(g_quic_param.logger, RLOG_LV_DEBUG, "QUIC_IDETIFY", - "pub_flags: 0X%02X connection_id: %llu version: Q%03u packet number: %u dir(1: C2S;2: S2C): %d addr: %s", - *pub_flags, - connection_id, - *version, - pkt_seq, + "pub_flags: 0X%02X conection ID:[ destination: %llu ] version: Q%03u packet number: %llu dir(1: C2S;2: S2C): %d addr: %s", + gquic_hdr->public_flags, + *(unsigned long long *)gquic_hdr->server_CID, + (((gquic_hdr->quic_version>>8)&0x0000000F)*10) + ((gquic_hdr->quic_version)&0x0000000F), + gquic_hdr->packet_number, pstream->curdir, printaddr(&pstream->addr, pstream->threadnum)); - return quic_version; + return (enum _QUIC_VERSION)gquic_hdr->quic_version; } -void gquic_proc_tag(struct streaminfo *pstream, struct quic_stream *a_quic_stream, UINT16 tag_num, UINT8 direction, void* a_packet, char * quic_data, UINT32 quic_data_len, UINT32 *used_len) +enum _QUIC_VERSION parse_quic_header(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len) { - UCHAR return_val; - UINT32 tag_type; - UINT32 total_tag_len=0, tag_len=0; - UINT32 tag_value_start=tag_num*4*2+(*used_len); // skip length of type and offset, type(offset)=szieof(int) - UINT32 tag_offset_end=0, pre_tag_offset_end=0; - int tag_type_len=4, tag_offset_len=4,num=0; - enum quic_interested_region region_mask=QUIC_INTEREST_KEY_MASK; + int i=0,len=0; + char client_CID[MAX_CONNECT_ID_LEN*2]={0}; + char server_CID[MAX_CONNECT_ID_LEN*2]={0}; + + struct _quic_public_header *long_hdr=&(_context->quic_info.quic_hdr); - while(tag_num > 0 && a_canRead(tag_type_len+tag_offset_len, quic_data_len, *used_len)) + long_hdr->public_flags=payload[*used_len]; + *used_len+=1; //skip public flags + + if(long_hdr->public_flags&0x80) { - tag_type=a_pntoh32(quic_data, *used_len); - *used_len+=4; + long_hdr->quic_version=(unsigned int)ntohl(*(unsigned int *)(payload+*used_len)); + *used_len+=sizeof(int); // skip version - tag_offset_end=a_pletoh32(quic_data, *used_len); - *used_len+=4; + long_hdr->client_CID_len=(payload[*used_len]&0xF) ? (payload[*used_len]&0xF)+3 : 0; + long_hdr->server_CID_len=((payload[*used_len]>>4)&0xF) ? ((payload[*used_len]>>4)&0xF)+3 : 0; + *used_len+=sizeof(char); // both connection_id length + + memcpy(long_hdr->server_CID, (void *)(payload+*used_len), long_hdr->server_CID_len); + *used_len+=long_hdr->server_CID_len; // Destination connection_id length + memcpy(long_hdr->client_CID, (void *)(payload+*used_len), long_hdr->client_CID_len); + *used_len+=long_hdr->client_CID_len; // source connection_id length + } + else + { + if(pstream->curdir==DIR_C2S)// short header only destination connection ID + { + *used_len+=long_hdr->server_CID_len; // every packet destination connection ID is same + } + } + + len=(long_hdr->public_flags&0x03)+1; + long_hdr->packet_number=get_packet_number(payload, *used_len, len); + *used_len+=len; + + *used_len+=12; //message authentication hash + + _context->is_quic==QUIC_TRUE; + + for(i=0,len=0;iserver_CID_len; i++) + { + len+=snprintf(server_CID+len, sizeof(server_CID)-len, "%02X", long_hdr->server_CID[i]); + } + + for(i=0,len=0;iclient_CID_len; i++) + { + len+=snprintf(client_CID+len, sizeof(client_CID)-len, "%02X", long_hdr->client_CID[i]); + } + + MESA_handle_runtime_log(g_quic_param.logger, + RLOG_LV_DEBUG, + "QUIC_IDETIFY", + "pub_flags: 0X%02X conection ID:[ destination: %s source: %s ] version: Q%03u packet number: %llu dir(1: C2S;2: S2C): %d addr: %s", + long_hdr->public_flags, + server_CID, + client_CID, + (((long_hdr->quic_version>>8)&0x0000000F)*10) + ((long_hdr->quic_version)&0x0000000F), + long_hdr->packet_number, + pstream->curdir, + printaddr(&pstream->addr, pstream->threadnum)); + + return (enum _QUIC_VERSION)long_hdr->quic_version; +} + +enum _QUIC_VERSION is_quic_protocol(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len) +{ + int i=0,len=0; + size_t s_id_len=0,d_id_len=0; + char d_CID[128]={0}, s_CID[128]={0}; + unsigned char s_connection_id[MAX_CONNECT_ID_LEN]={0}; + unsigned char d_connection_id[MAX_CONNECT_ID_LEN]={0}; + enum _QUIC_VERSION quic_version=QUIC_VERSION_UNKNOWN; + + if(_context->quic_info.quic_hdr.quic_version!=QUIC_VERSION_UNKNOWN) + { + // + quic_version=(enum _QUIC_VERSION)(_context->quic_info.quic_hdr.quic_version); + } + else + { + // The most significant bit (0x80) of byte 0 (the first byte) is set to 1 for long headers + (payload[*used_len]&0x80) ? (quic_version=(enum _QUIC_VERSION)ntohl(*(unsigned int *)(payload+(*used_len+1)))) : QUIC_VERSION_UNKNOWN; + } + + switch(quic_version) // +1 meaning: skip public flags + { + case GQUIC_VERSION_Q046: + quic_version=parse_quic_header(pstream, _context, payload, payload_len, used_len); + return quic_version; + break; + //case IETF: unsupport + break; + default: + break; + } + + // Q001~Q043: 0x80 is currently unused, and must be set to 0 + if(payload[*used_len]>0x80) + { + return QUIC_VERSION_UNKNOWN; + } + + return parse_q0to43_header(pstream, _context, payload, payload_len, used_len); +} + +int parse_extension_tag(struct streaminfo *pstream, struct _quic_stream **quic_stream, void *a_packet, char *payload, int payload_len, int *used_len, int tag_num) +{ + int ret=0,tag_used_num=0; + int tag_type,skip_tsg=0; + int total_tag_len=0,tag_len=0; + int tag_offset_end=0,pre_tag_offset_end=0; + + struct _quic_stream *stream=*quic_stream; + int tag_value_start=tag_num*4*2+(*used_len); // skip length of type and offset, type(offset)=szieof(int) + + if(stream==NULL) + { + stream=(struct _quic_stream *)dictator_malloc(pstream->threadnum, sizeof(struct _quic_stream)); + memset(stream, 0, sizeof(struct _quic_stream)); + stream->ext_tags=(quic_tlv_t *)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t)); + memset(stream->ext_tags, 0, tag_num*sizeof(quic_tlv_t)); + *quic_stream=stream; + } + else + { + quic_release_exts(pstream->threadnum, stream->ext_tags, stream->ext_tag_num); + stream->ext_tags=(quic_tlv_t *)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t)); + memset(stream->ext_tags, 0, tag_num*sizeof(quic_tlv_t)); + *quic_stream=stream; + stream->ext_tag_num=0; + stream->count++; + } + + while(tag_num>tag_used_num) + { + tag_type=ntohl(*(unsigned int *)(payload+*used_len)); + *used_len+=sizeof(int); + + tag_offset_end=*(unsigned int *)(payload+*used_len); + *used_len+=sizeof(int); tag_len=tag_offset_end-pre_tag_offset_end; - if(tag_len<0 || (tag_offset_end>=quic_data_len) || (tag_len>quic_data_len-tag_value_start)) + if(tag_len<0 || (tag_offset_end>=payload_len) || (tag_len>payload_len-tag_value_start)) { - return ; + return -1; } switch(tag_type) { case TAG_PAD: break; - case TAG_CCS: //common_cert - region_mask=QUIC_COMM_CERT_MASK; - get_quic_tlv(quic_data+tag_value_start, &a_quic_stream->common_cert, tag_len, tag_type, pstream->threadnum); + case TAG_VER: + stream->ver_idx=stream->ext_tag_num; + get_quic_tlv(payload+tag_value_start, &stream->ext_tags[stream->ext_tag_num], tag_len, tag_type, pstream->threadnum); + *(unsigned int *)(stream->ext_tags[stream->ext_tag_num].value)=(unsigned int)ntohl(*(unsigned int *)(stream->ext_tags[stream->ext_tag_num].value)); + MESA_handle_runtime_log(g_quic_param.logger, + RLOG_LV_DEBUG, + "QUIC_VERSION", + "Quic version: 0X%X addr: %s", + *(unsigned int *)(stream->ext_tags[stream->ext_tag_num].value), + printaddr(&pstream->addr, pstream->threadnum)); break; - case TAG_CCRT: //cached_cert - region_mask=QUIC_CACHED_CERT_MASK; - get_quic_tlv(quic_data+tag_value_start, &a_quic_stream->cached_cert, tag_len, tag_type, pstream->threadnum); - break; - case TAG_CRT: //cert_chain ????? length need change - if(a_quic_stream->cert_chain.length==0) - { - //tag_value_start += a_quic_stream->cert_chain.length; - tag_len=(tag_len>(quic_data_len-tag_value_start+1) ? (quic_data_len-tag_value_start+1) : tag_len); - get_quic_tlv(quic_data+tag_value_start, &a_quic_stream->cached_cert, tag_len, tag_type, pstream->threadnum); - region_mask=QUIC_CERT_CHAIN_MASK; - } + case TAG_UAID: + stream->ua_idx=stream->ext_tag_num; + get_quic_tlv(payload+tag_value_start, &stream->ext_tags[stream->ext_tag_num], tag_len, tag_type, pstream->threadnum); + MESA_handle_runtime_log(g_quic_param.logger, + RLOG_LV_DEBUG, + "QUIC_UA", + "User Agent: %s addr: %s", + stream->ext_tags[stream->ext_tag_num].value, + printaddr(&pstream->addr, pstream->threadnum)); + stream->ext_tag_num++; break; case TAG_SNI: - if(a_quic_stream->st_client_hello.server_name_len==0) - { - a_quic_stream->st_client_hello.server_name_len=(tag_len>SERVER_NAME_LEN ? SERVER_NAME_LEN : tag_len); - memcpy(a_quic_stream->st_client_hello.server_name, quic_data + tag_value_start, tag_len); - MESA_handle_runtime_log(g_quic_param.logger, + stream->sni_idx=stream->ext_tag_num; + get_quic_tlv(payload+tag_value_start, &stream->ext_tags[stream->ext_tag_num], tag_len, tag_type, pstream->threadnum); + MESA_handle_runtime_log(g_quic_param.logger, RLOG_LV_DEBUG, "QUIC_SNI", "SNI: %s addr: %s", - a_quic_stream->st_client_hello.server_name, + stream->ext_tags[stream->ext_tag_num].value, printaddr(&pstream->addr, pstream->threadnum)); - - } - break; - case TAG_UAID: - if(a_quic_stream->st_client_hello.user_agent_len==0) - { - a_quic_stream->st_client_hello.user_agent_len=(tag_len>USER_AGENT_LEN ? USER_AGENT_LEN : tag_len); - memcpy(a_quic_stream->st_client_hello.user_agent, quic_data + tag_value_start, a_quic_stream->st_client_hello.user_agent_len); - } + stream->ext_tag_num++; break; default: - if(direction == 0x01 && num < a_quic_stream->st_client_hello.ext_tag_num) - { - a_quic_stream->st_client_hello.ext_tags[num]=(quic_tlv_t *)dictator_malloc(pstream->threadnum, sizeof(quic_tlv_t)); - get_quic_tlv(quic_data+tag_value_start, a_quic_stream->st_client_hello.ext_tags[num], (tag_len>MAX_TAG_VALUE_LEN-1 ? MAX_TAG_VALUE_LEN-1 : tag_len), tag_type, pstream->threadnum); - } - else if(num < a_quic_stream->st_server_hello.ext_tag_num) - { - a_quic_stream->st_server_hello.ext_tags[num]=(quic_tlv_t *)dictator_malloc(pstream->threadnum, sizeof(quic_tlv_t)); - get_quic_tlv(quic_data+tag_value_start, a_quic_stream->st_server_hello.ext_tags[num], (tag_len>MAX_TAG_VALUE_LEN-1 ? MAX_TAG_VALUE_LEN-1 : tag_len), tag_type, pstream->threadnum); - } - num++; + get_quic_tlv(payload+tag_value_start, &stream->ext_tags[stream->ext_tag_num], tag_len, tag_type, pstream->threadnum); + stream->ext_tag_num++; break; } - tag_num--; + tag_used_num++; tag_value_start+=tag_len; total_tag_len+=tag_len; pre_tag_offset_end=tag_offset_end; - - return_val=quic_callPlugins(a_quic_stream, pstream, region_mask, pstream->threadnum, a_packet); - region_mask=QUIC_INTEREST_KEY_MASK; } *used_len += total_tag_len; - return; + return ret; } +#if 0 int gquic_frame_type_ack(struct quic_stream* a_quic_stream, char * quic_data, UINT32 quic_data_len, UINT8 frame_type, UINT32 *used_len) { UINT8 num_timestamp, num_ranges, num_revived, num_blocks; @@ -369,7 +585,7 @@ int gquic_frame_type_ack(struct quic_stream* a_quic_stream, char * quic_data, UI // return value: Have no meaning, only numerical value int gquic_frame_type_control(struct quic_stream* a_quic_stream, char * quic_data, UINT32 quic_data_len, UINT8 frame_type, uint32_t pkt_num_len, UINT32 *used_len) { - UINT16 len_reason; + int len_reason; *used_len+=1; switch(frame_type) @@ -425,476 +641,183 @@ int gquic_frame_type_control(struct quic_stream* a_quic_stream, char * quic_data return QUIC_TRUE; } +#endif -int gquic_frame_type_stream(struct streaminfo *pstream, struct quic_stream* a_quic_stream, char *quic_data, UINT32 quic_data_len, UINT8 frame_type, UINT32 *used_len, void* a_packet) +int gquic_frame_type_stream(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len, char frame_type, void *a_packet) { - UINT8 return_val; - UINT16 tag_num = 0; - UINT32 stream_id, message_tag; - if(frame_type&STREAM_F) + int ret=0; + unsigned short tag_num = 0; + unsigned int stream_id, message_tag; + + stream_id=get_stream_id(pstream, _context, payload, frame_type, used_len); + + message_tag=(unsigned int)ntohl(*(unsigned int *)(payload+*used_len)); + *used_len+=4; + + tag_num=*(unsigned short *)(payload+*used_len); + *used_len+=2; //tag_num + *used_len+=2; //padding + + switch(message_tag) { - a_quic_stream->fin_flag=QUIC_TRUE; + case CHLO: //MTAG_CHLO; + ret=parse_extension_tag(pstream, &_context->quic_info.client_hello, a_packet, payload, payload_len, used_len, tag_num); + if(ret>=0) + { + ret=quic_callPlugins(pstream, _context, (void *)(_context->quic_info.client_hello), sizeof(void *), QUIC_CLIENT_HELLO_MASK, a_packet); + } + break; + case SHLO: //MTAG_SHLO; + ret=parse_extension_tag(pstream, &_context->quic_info.server_hello, a_packet, payload, payload_len, used_len, tag_num); + if(ret>=0) + { + ret=quic_callPlugins(pstream, _context, (void *)(_context->quic_info.server_hello), sizeof(void *), QUIC_SERVER_HELLO_MASK, a_packet); + } + break; + case REJ: //MTAG_REJ; + ret=parse_extension_tag(pstream, &_context->quic_info.rej, a_packet, payload, payload_len, used_len, tag_num); + if(ret>=0) + { + ret=quic_callPlugins(pstream, _context, (void *)(_context->quic_info.rej), sizeof(void *), QUIC_SERVER_HELLO_MASK, a_packet); + } + break; + default: + break; } - stream_id=get_stream_id(pstream, quic_data, frame_type, used_len); - - if(stream_id==1) //handshake - { - message_tag = a_pntoh32((void *)quic_data, *used_len); - *used_len += 4; - tag_num = a_pletoh16(quic_data, *used_len); - *used_len += 2; //tag_num - *used_len += 2; //padding - switch(message_tag) - { - case CHLO: //MTAG_CHLO; - if(a_quic_stream->st_client_hello.ext_tags==NULL) - { - a_quic_stream->st_client_hello.ext_tags=(quic_tlv_t **)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t*)); - a_quic_stream->st_client_hello.ext_tag_num = tag_num; - } - else - { - if(a_quic_stream->st_server_hello.ext_tag_num && tag_num>a_quic_stream->st_client_hello.ext_tag_num) - { - quic_release_exts(pstream->threadnum, a_quic_stream->st_client_hello.ext_tags, a_quic_stream->st_client_hello.ext_tag_num); - a_quic_stream->st_client_hello.ext_tags=(quic_tlv_t **)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t*)); - a_quic_stream->st_client_hello.ext_tag_num = tag_num; - } - else - { - return -1; - } - } - gquic_proc_tag(pstream, a_quic_stream, tag_num, C2S, a_packet, quic_data, quic_data_len, used_len); - if(a_quic_stream->st_client_hello.server_name_len>0 || a_quic_stream->st_client_hello.user_agent_len>0) - { - quic_callPlugins(a_quic_stream, pstream, QUIC_CLIENT_HELLO_MASK, pstream->threadnum, a_packet); - } - break; - case SHLO: //MTAG_SHLO; - if(a_quic_stream->st_server_hello.ext_tags==NULL) - { - return -2; - } - - a_quic_stream->st_server_hello.ext_tags=(quic_tlv_t **)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t*)); - a_quic_stream->st_server_hello.ext_tag_num=tag_num; - - gquic_proc_tag(pstream, a_quic_stream, tag_num, S2C, a_packet, quic_data, quic_data_len, used_len); - - if(a_quic_stream->st_server_hello.ext_tags != NULL) - { - quic_callPlugins(a_quic_stream, pstream, QUIC_SERVER_HELLO_MASK, pstream->threadnum, a_packet); - } - break; - case REJ: //MTAG_REJ; - if(a_quic_stream->st_server_hello.ext_tags!=NULL) - { - return -3; - - } - - a_quic_stream->st_server_hello.ext_tags=(quic_tlv_t **)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t*)); - a_quic_stream->st_server_hello.ext_tag_num=tag_num; - - gquic_proc_tag(pstream, a_quic_stream, tag_num, S2C, a_packet, quic_data, quic_data_len, used_len); - if(a_quic_stream->st_server_hello.ext_tags != NULL) - { - quic_callPlugins(a_quic_stream, pstream, QUIC_SERVER_HELLO_MASK, pstream->threadnum, a_packet); - } - break; - default: - break; - } - } - - return 0; + return (ret>=0) ? ret : APP_STATE_GIVEME; } //frame type->stream->offset->data length -void gquic_proc_unencrypt(struct streaminfo *pstream, struct quic_stream* a_quic_stream, uint32_t pkt_num_len, void* a_packet, char * quic_data, UINT32 quic_data_len, UINT32 *used_len) +int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _context, void *a_packet, char * payload, int payload_len, int *used_len) { - UINT8 frame_type; - UINT32 ret=0; - - while(*used_lenfin_flag=QUIC_FALSE; // is_handshake_pkt don't identify QUIC; but function set QUIC_TRUE - if(ret!=QUIC_TRUE) + gquic_frame_type_stream(pstream, _context, payload, payload_len, used_len, frame_type, a_packet); + } + else + { + return 0; //todo + } + } + + return QUIC_RETURN_NORM; +} + +//cid->version->nounce->pkt num->ahn hash(12) +int quic_process(struct streaminfo *pstream, struct _quic_context* _context, int thread_seq, void* a_packet) +{ + int used_len=0; + int ret=APP_STATE_GIVEME; + enum _QUIC_VERSION is_gquic=QUIC_VERSION_UNKNOWN; + struct udpdetail *udp_detail=pstream->pudpdetail; + + if(udp_detail->pdata==NULL || udp_detail->datalen<=0) + { + return APP_STATE_GIVEME; + } + + is_gquic=is_quic_protocol(pstream, _context, (char *)udp_detail->pdata, udp_detail->datalen, &used_len); + if(is_gquic!=QUIC_VERSION_UNKNOWN) + { + if(_context->quic_info.quic_hdr.packet_number==1) + { + ret=quic_callPlugins(pstream, _context, &(_context->quic_info.quic_hdr.quic_version), sizeof(_context->quic_info.quic_hdr.quic_version), QUIC_VERSION_MASK, a_packet); + if(ret&APP_STATE_DROPME | ret&APP_STATE_DROPPKT) { return ret; } } - else - { - if(frame_type&STREAM) - { - if(frame_type&STREAM_D) - { - *used_len+=2; - } - *used_len+=1; - *used_len+=read_stream_len(frame_type); - *used_len+=read_offset_len(frame_type); - - if((quic_data_len-*used_len)<=4) - { - return QUIC_FALSE; - } - - strncpy((char*)&message_tag, quic_data+*used_len, 4); - if(ntohl(message_tag)==CHLO || ntohl(message_tag)==SHLO || ntohl(message_tag)==REJ) - { - return QUIC_TRUE; - } - } - else if(frame_type&ACK) - { - gquic_frame_type_ack(a_quic_stream, quic_data, quic_data_len, frame_type, used_len); - } - else - { - *used_len +=1; - return QUIC_FALSE; - } - } - } - - return QUIC_FALSE; -} - -UINT8 parse_gquic_Q046(struct streaminfo *pstream, void* a_packet, char * payload, uint32_t payload_len, uint32_t *used_len, struct quic_stream* a_quic_stream, uint8_t pub_flags) -{ - uint8_t frame_type; - uint16_t tag_num=0; - uint32_t stream_id, message_tag; - - if(!a_canRead(25, payload_len, *used_len)) - { - return QUIC_RETURN_DROPME; - } - - *used_len += 25; - - while(*used_len < payload_len) - { - a_readUInt8(&frame_type, payload, payload_len, used_len); - if(frame_type & STREAM) - { - stream_id=get_stream_id(pstream, payload, frame_type, used_len); - if(stream_id==1) - { - message_tag = a_pntoh32((void *)payload, *used_len); - *used_len += 4; - tag_num = a_pletoh16(payload, *used_len); - *used_len += 2; //tag_num - *used_len += 2; //padding - switch(message_tag) - { - case CHLO: //MTAG_CHLO; - if(a_quic_stream->st_client_hello.ext_tags==NULL && tag_num>0) - { - a_quic_stream->st_client_hello.ext_tags=(quic_tlv_t **)dictator_malloc(pstream->threadnum, tag_num*sizeof(quic_tlv_t*)); - a_quic_stream->st_client_hello.ext_tag_num = tag_num; - } - - gquic_proc_tag(pstream, a_quic_stream, tag_num, C2S, a_packet, payload, payload_len, used_len); - - if(a_quic_stream->st_client_hello.server_name_len > 0 || a_quic_stream->st_client_hello.user_agent_len > 0) - { - quic_callPlugins(a_quic_stream, pstream, QUIC_CLIENT_HELLO_MASK, pstream->threadnum, a_packet); - } - break; - default: - break; - } - } - } - } - - return QUIC_RETURN_NORM; -} - -UINT8 parse_gquic(struct streaminfo *pstream, void* a_packet, char * payload, uint32_t payload_len, uint32_t *used_len, struct quic_stream* a_quic_stream, uint8_t pub_flags) -{ - int is_handshake=0; - uint32_t pkt_num_len = 0; - uint32_t skip_len=0; - pkt_num_len=read_seq_num_len(pub_flags); - - //version 协商 - if(!(PUBLIC_FLAG_VER&pub_flags!=0) && a_quic_stream->version && !a_quic_stream->version_cfm) - { - a_quic_stream->version_cfm = QUIC_TRUE; - quic_callPlugins(a_quic_stream, pstream, QUIC_VERSION_MASK, pstream->threadnum, a_packet); - MESA_handle_runtime_log(g_quic_param.logger, RLOG_LV_DEBUG, "QUIC_VERSION", "version: %u addr: %s", a_quic_stream->version, printaddr(&pstream->addr, pstream->threadnum)); - } - - skip_len=*used_len; - is_handshake=is_handshake_pkt(a_quic_stream, pkt_num_len, payload, payload_len, &skip_len); // just identify - switch(is_handshake) - { - case QUIC_TRUE: //handshake - a_quic_stream->is_quic_stream = QUIC_TRUE; - gquic_proc_unencrypt(pstream, a_quic_stream, pkt_num_len, a_packet, payload, payload_len, used_len); - break; - case QUIC_DATA: //ack or special stream - a_quic_stream->is_quic_stream = QUIC_TRUE; - break; - default: //gquic data or not gquic packet - if(!a_quic_stream->is_quic_stream) - { - return QUIC_RETURN_DROPME; - } - - quic_callPlugins(a_quic_stream, pstream, QUIC_APPLICATION_DATA_MASK, pstream->threadnum, a_packet); - break; - } - - return QUIC_RETURN_NORM; -} - - -//cid->version->nounce->pkt num->ahn hash(12) -UINT8 gquic_process(struct streaminfo *pstream, struct quic_stream* a_quic_stream, int thread_seq, void* a_packet) -{ - uint8_t pub_flags = 0; - uint32_t used_len = 0; - int ret=QUIC_RETURN_DROPME; - enum GQUIC_VERSION is_gquic=GQUIC_UNKNOWN; - struct udpdetail *udp_detail=(struct udpdetail *)pstream->pdetail; - - if(!a_quic_stream->is_quic_stream && udp_detail->datalen<=GQUIC_HEADER_LEN) - { - MESA_handle_runtime_log(g_quic_param.logger, - RLOG_LV_DEBUG, - "QUIC", - "This is not quic (!a_quic_stream->is_quic_stream)=%d, or packet length is litter udp_detail->datalen<=GQUIC_HEADER_LEN(%d<=%d) addr: %s", - !a_quic_stream->is_quic_stream, - udp_detail->datalen, - GQUIC_HEADER_LEN, - printaddr(&pstream->addr, thread_seq)); - return QUIC_RETURN_DROPME; - } - - if(udp_detail->pdata==NULL || udp_detail->datalen<=0) - { - return QUIC_RETURN_NORM; - } - - is_gquic=is_gquic_protocol(pstream, (char *)udp_detail->pdata, udp_detail->datalen, &pub_flags, &a_quic_stream->version, &used_len); - if(is_gquic!=GQUIC_UNKNOWN) - { - a_quic_stream->is_quic_stream=QUIC_TRUE; - quic_callPlugins(a_quic_stream, pstream, QUIC_VERSION_MASK, thread_seq, a_packet); - switch(is_gquic) { - case GQUIC_OTHERS: - ret=parse_gquic(pstream, a_packet, (char *)udp_detail->pdata, udp_detail->datalen, &used_len, a_quic_stream, pub_flags); + case GQUIC_VERSION_Q043: + ret=gquic_proc_unencrypt(pstream, _context, a_packet, (char *)udp_detail->pdata, udp_detail->datalen, &used_len); break; - case GQUIC_Q046: - ret=parse_gquic_Q046(pstream, a_packet, (char *)udp_detail->pdata, udp_detail->datalen, &used_len, a_quic_stream, pub_flags); + case GQUIC_VERSION_Q046: + ret=parse_gquic_Q046(pstream, _context, a_packet, (char *)udp_detail->pdata, udp_detail->datalen, &used_len); break; default: break; } } - if(a_quic_stream->is_quic_stream==QUIC_TRUE) + if(_context->is_quic==QUIC_TRUE) { - return QUIC_RETURN_NORM; + return APP_STATE_GIVEME; } - return ret; -} - - -UINT32 read_offset_len(UINT8 frame_type) -{ - switch((frame_type&STREAM_OOO)>>2) - { - case 0: - return 0; - break; - case 1: - return 2; - break; - case 2: - return 3; - break; - case 3: - return 4; - break; - case 4: - return 5; - break; - case 5: - return 6; - break; - case 6: - return 7; - break; - case 7: - return 8; - break; - default: - break; - } - - return 0; -} - -UINT32 read_stream_len(UINT8 frame_type) -{ - UINT32 stream_len = 0; - switch(frame_type&STREAM_SS) - { - case STREAM_ID_1BYTE: - stream_len = 1; - break; - case STREAM_ID_2BYTE: - stream_len = 2; - break; - case STREAM_ID_3BYTE: - stream_len = 3; - break; - case STREAM_ID_4BYTE: - stream_len = 4; - break; - default: - break; - } - - return stream_len; -} - -int read_conn_id_len(UINT8 flags) -{ - switch (flags&BYTE_CNTID_8) - { - case BYTE_CNTID_8: - return 8; - case BYTE_CNTID_0: - return 0; - default: - return 0; // modify by liuxueli 20200522 - //return -1; - } -} - -UINT32 read_seq_num_len(UINT8 flags) -{ - switch (flags & PKT_NUM_6) - { - case PKT_NUM_6: - return 6; - case PKT_NUM_4: - return 4; - case PKT_NUM_2: - return 2; - case PKT_NUM_1: - return 1; - default: - break; - } - - return 1; -} - - -UINT32 read_largest_observed_len(UINT8 frame_type) -{ - switch((frame_type & ACK_LL) >> 2) - { - case 0: - return 1; - break; - case 1: - return 2; - break; - case 2: - return 4; - break; - case 3: - return 6; - break; - default: - break; - } - - return 1; -} - -UINT32 read_missing_packet_len(UINT8 frame_type) -{ - switch(frame_type & ACK_MM) - { - case 0: - return 1; - break; - case 1: - return 2; - break; - case 2: - return 4; - break; - case 3: - return 6; - break; - default: - break; - } - - return 1; + return APP_STATE_DROPME;; } diff --git a/src/gquic_process.h b/src/gquic_process.h index b7d3f0c..be68d42 100644 --- a/src/gquic_process.h +++ b/src/gquic_process.h @@ -1,5 +1,5 @@ /* - * gquic_process.h + * quic_process.h * * Created on: 2019锟斤拷4锟斤拷2锟斤拷 * Author: root @@ -14,94 +14,177 @@ #include "gquic.h" -#define VERSION_LEN 4 -#define VER_Q046 0x51303436 -/**************************************************************************/ -/* Public flag */ -/**************************************************************************/ +//#define VERSION_LEN 4 +//#define VER_Q046 +#define GQUIC_PUBLIC_FLAG_VERSION 0x01 +#define GQUIC_PUBLIC_FLAG_RST 0x02 +#define GQUIC_PUBLIC_FLAG_NONCE 0x04 +#define GQUIC_PUBLIC_FLAG_CID 0x08 +#define GQUIC_PUBLIC_FLAG_PKT_NUM 0x30 + +//https://github.com/quicwg/base-drafts/wiki/QUIC-Versions + +enum _QUIC_VERSION +{ + QUIC_VERSION_UNKNOWN=0, + //google + GQUIC_VERSION_Q001=0x51303031, + GQUIC_VERSION_Q002=0x51303032, + GQUIC_VERSION_Q003=0x51303033, + GQUIC_VERSION_Q004=0x51303034, + GQUIC_VERSION_Q005=0x51303035, + GQUIC_VERSION_Q006=0x51303036, + GQUIC_VERSION_Q007=0x51303037, + GQUIC_VERSION_Q008=0x51303038, + GQUIC_VERSION_Q009=0x51303039, + + GQUIC_VERSION_Q010=0x51303130, + GQUIC_VERSION_Q011=0x51303131, + GQUIC_VERSION_Q012=0x51303132, + GQUIC_VERSION_Q013=0x51303133, + GQUIC_VERSION_Q014=0x51303134, + GQUIC_VERSION_Q015=0x51303135, + GQUIC_VERSION_Q016=0x51303136, + GQUIC_VERSION_Q017=0x51303137, + GQUIC_VERSION_Q018=0x51303138, + GQUIC_VERSION_Q019=0x51303139, + + GQUIC_VERSION_Q020=0x51303230, + GQUIC_VERSION_Q021=0x51303231, + GQUIC_VERSION_Q022=0x51303332, + GQUIC_VERSION_Q023=0x51303333, + GQUIC_VERSION_Q024=0x51303234, + GQUIC_VERSION_Q025=0x51303235, + GQUIC_VERSION_Q026=0x51303236, + GQUIC_VERSION_Q027=0x51303237, + GQUIC_VERSION_Q028=0x51303238, + GQUIC_VERSION_Q029=0x51303239, + + GQUIC_VERSION_Q030=0x51303330, + GQUIC_VERSION_Q031=0x51303331, + GQUIC_VERSION_Q032=0x51303332, + GQUIC_VERSION_Q033=0x51303333, + GQUIC_VERSION_Q034=0x51303334, + GQUIC_VERSION_Q035=0x51303335, + GQUIC_VERSION_Q036=0x51303336, + GQUIC_VERSION_Q037=0x51303337, + GQUIC_VERSION_Q038=0x51303338, + GQUIC_VERSION_Q039=0x51303339, + + GQUIC_VERSION_Q040=0x51303430, + GQUIC_VERSION_Q041=0x51303431, + GQUIC_VERSION_Q042=0x51303432, + GQUIC_VERSION_Q043=0x51303433, + GQUIC_VERSION_Q044=0x51303434, + GQUIC_VERSION_Q045=0x51303435, + GQUIC_VERSION_Q046=0x51303436, + GQUIC_VERSION_Q047=0x51303437, + GQUIC_VERSION_Q048=0x51303438, //Google QUIC with TLS + GQUIC_VERSION_Q049=0x51303439, //Google QUIC with TLS + + GQUIC_VERSION_Q050=0x51303530, + GQUIC_VERSION_Q051=0x51303531, + GQUIC_VERSION_Q052=0x51303532, + GQUIC_VERSION_Q053=0x51303533, + GQUIC_VERSION_Q054=0x51303534, + GQUIC_VERSION_Q055=0x51303535, + GQUIC_VERSION_Q056=0x51303536, + GQUIC_VERSION_Q057=0x51303537, + GQUIC_VERSION_Q058=0x51303538, + GQUIC_VERSION_Q059=0x51303539, + + GQUIC_VERSION_Q099=0x51303939, + + //Google Proxied QUIC + PQUIC_VERSION_PROX=0x50524f58 + //GOQUIC_VERSION_GO=0x51474f[0-255], + //quicly + //QUICKLY_VERSION_QUICLY=0x91c170[0-255] + + //IETF + //IQUIC_VERSION_=0xf10000 -#define PACKET_PUBLIC_FLAGS_MAX 0x7f -#define PUBLIC_FLAG_VER_FST_BYTE 0x51 -#define PUBLIC_FLAG_VER 0x01 -#define PUBLIC_FLAG_RST 0x02 -#define PUBLIC_FLAG_NONCE 0x04 -#define BYTE_CNTID_8 0x08 -#define BYTE_CNTID_0 0x00 -enum gquic_connid_len { - PACKET_0BYTE_CONNECTION_ID = 0, - PACKET_8BYTE_CONNECTION_ID = 8 }; -#define PKT_NUM_6 0x30 -#define PKT_NUM_4 0x20 -#define PKT_NUM_2 0x10 -#define PKT_NUM_1 0x00 - -//enum gquic_pkt_num_len { -// PACKET_1BYTE_PACKET_NUMBER = 1, -// PACKET_2BYTE_PACKET_NUMBER = 2, -// PACKET_4BYTE_PACKET_NUMBER = 4, -// PACKET_6BYTE_PACKET_NUMBER = 6 -//}; - -// Used to indicate a QuicSequenceNumberLength using two flag bits. -enum gquic_pkt_num_len_flags { - PACKET_FLAGS_1BYTE_PACKET = 0, // 00 - PACKET_FLAGS_2BYTE_PACKET = 1, // 01 - PACKET_FLAGS_4BYTE_PACKET = 1 << 1, // 10 - PACKET_FLAGS_6BYTE_PACKET = 1 << 1 | 1, // 11 +struct _gquic_reset_public_header +{ + unsigned char public_flags; + unsigned long long connection_id; + unsigned int tag; }; -//#define PUBLIC_FLAG_MULTIPATH 0x40 -#define UNUSE 0x80 -#define MSG_AUTH_HASH_LEN 12 -#define PUB_HEAD_SEQ_SFT 4 +//GQIIC Frame type +#define GQUIC_SPECIAL_FRAME_FLAG 0xE0 // Special Frame Types +#define GQUIC_SPECIAL_FRAME_STREAM 0x80 +#define GQUIC_SPECIAL_FRAME_ACK 0x40 +#define GQUIC_SPECIAL_FRAME_CONGEST_FB 0x20 -/**************************************************************************/ -/* Frame type */ -/**************************************************************************/ -#define FRAM_SPECIAL 0xE0 -#define STREAM 0x80 -#define STREAM_F 0x40 //fin -#define STREAM_D 0x20 //data length -#define STREAM_OOO 0x1C //offset length -#define STREAM_SS 0x03 //stream length -#define ACK 0x40 -#define ACK_LL 0x0c -#define ACK_MM 0x03 -#define ACK_N 0x20 -#define CONGESTION_FEEDBACK 0x20 -#define PADDING 0x00 -#define RST_STREAM 0x01 -#define CONNECTION_CLOSE 0x02 -#define GOAWAY 0x03 -#define WINDOW_UPDATE 0x04 -#define BLOCKED 0x05 -#define STOP_WAITING 0x06 -#define PING 0x07 +#define GQUIC_SPECIAL_FRAME_STREAM_FIN 0x40 // FIN +#define GQUIC_SPECIAL_FRAME_STREAM_DLEN 0x20 //stream length +#define GQUIC_SPECIAL_FRAME_STREAM_OFFSET 0x1C //offset header field +#define GQUIC_SPECIAL_FRAME_STREAM_ID 0x03 //offset header field +#define GQUIC_REGULAR_FRAME_PADDING 0x00 +#define GQUIC_REGULAR_FRAME_RST_STREAM 0x01 +#define GQUIC_REGULAR_FRAME_CONNECTION_CLOSE 0x02 +#define GQUIC_REGULAR_FRAME_GOAWAY 0x03 +#define GQUIC_REGULAR_FRAME_WINDOW_UPDATE 0x04 +#define GQUIC_REGULAR_FRAME_BLOCKED 0x05 +#define GQUIC_REGULAR_FRAME_STOP_WAITING 0x06 +#define GQUIC_REGULAR_FRAME_PING 0x07 -#define STREAM_ID_1BYTE 0x00 -#define STREAM_ID_2BYTE 0x01 -#define STREAM_ID_3BYTE 0x02 -#define STREAM_ID_4BYTE 0x03 +#define GQUIC_SPECIAL_FRAME_FLAG 0xE0 // Special Frame Types +#define GQUIC_SPECIAL_FRAME_STREAM 0x80 +#define GQUIC_SPECIAL_FRAME_ACK 0x40 +#define GQUIC_SPECIAL_FRAME_CONGEST_FB 0x20 +#define GQUIC_SPECIAL_FRAME_STREAM_FIN 0x40 // FIN +#define GQUIC_SPECIAL_FRAME_STREAM_DLEN 0x20 //stream length +#define GQUIC_SPECIAL_FRAME_STREAM_OFFSET 0x1C //offset header field +#define GQUIC_SPECIAL_FRAME_STREAM_ID 0x03 //offset header field + +#define GQUIC_REGULAR_FRAME_PADDING 0x00 +#define GQUIC_REGULAR_FRAME_RST_STREAM 0x01 +#define GQUIC_REGULAR_FRAME_CONNECTION_CLOSE 0x02 +#define GQUIC_REGULAR_FRAME_GOAWAY 0x03 +#define GQUIC_REGULAR_FRAME_WINDOW_UPDATE 0x04 +#define GQUIC_REGULAR_FRAME_BLOCKED 0x05 +#define GQUIC_REGULAR_FRAME_STOP_WAITING 0x06 +#define GQUIC_REGULAR_FRAME_PING 0x07 + +//IQIIC Frame type (GQUIC_Q046 is iQUIC 17) +#define IQUIC_FRAME_PADDING 0x00 +#define IQUIC_FRAME_PING 0x10 +#define IQUIC_FRAME_ACK_HEX02 0x20 +#define IQUIC_FRAME_ACK_HEX03 0x30 +#define IQUIC_FRAME_RESET_STREAM 0x40 +#define IQUIC_FRAME_STOP_SENDING 0x50 +#define IQUIC_FRAME_CRYPTO 0x60 +#define IQUIC_FRAME_NEW_TOKEN 0x70 +#define IQUIC_FRAME_STREAM_HEX08 0x80 +#define IQUIC_FRAME_STREAM_HEX09 0x90 +#define IQUIC_FRAME_STREAM_HEX0A 0xA0 +#define IQUIC_FRAME_STREAM_HEX0B 0xB0 +#define IQUIC_FRAME_STREAM_HEX0C 0xC0 +#define IQUIC_FRAME_STREAM_HEX0D 0xD0 +#define IQUIC_FRAME_STREAM_HEX0E 0xE0 +#define IQUIC_FRAME_STREAM_HEX0F 0xF0 +#define IQUIC_FRAME_MAX_DATA 0x01 +#define IQUIC_FRAME_MAX_STREAM_DATA 0x11 +#define IQUIC_FRAME_MAX_STREAMS_HEX12 0x21 +#define IQUIC_FRAME_MAX_STREAMS_HEX13 0x31 +#define IQUIC_FRAME_DATA_BLOCKED 0x41 +#define IQUIC_FRAME_STREAM_DATA_BLOCKED 0x51 +#define IQUIC_FRAME_STREAMS_BLOCKED_HEX16 0x61 +#define IQUIC_FRAME_STREAMS_BLOCKED_HEX17 0x71 +#define IQUIC_FRAME_NEW_CONNECTION_ID 0x81 +#define IQUIC_FRAME_RETIRE_CONNECTION_ID 0x91 +#define IQUIC_FRAME_PATH_CHALLENGE 0xA1 +#define IQUIC_FRAME_PATH_RESPONSE 0xB1 +#define IQUIC_FRAME_CONNECTION_CLOSE_HEX1C 0xC1 +#define IQUIC_FRAME_CONNECTION_CLOSE_HEX1D 0xD1 -enum frame_type_t{ - FRAME_UNKNOWN = 0, - FRAME_STREAM, - FRAME_ACK, - FRAME_CONGESTION_FEEDBACK, - FRAME_PADDING, - FRAME_RST_STREAM, - FRAME_CONNECTION_CLOSE, - FRAME_GOAWAY, - FRAME_WINDOW_UPDATE, - FRAME_BLOCKED, - FRAME_STOP_WAITING, - FRAME_PING -}; /**************************************************************************/ /* Message tag */ @@ -111,40 +194,6 @@ enum frame_type_t{ #define REJ 0x52454A00 #define PRST 0x50525354 -enum message_tag_t{ - MTAG_UNKNOWN = 0, - MTAG_CHLO, - MTAG_SHLO, - MTAG_REJ, - MTAG_PRST -}; - -struct gquic_frame_hdr{ - enum frame_type_t frame_type; - UCHAR is_fin; - UCHAR data_len_byte; - UCHAR offset_len; - UCHAR stream_id_len; - UINT8 stream_id; - UINT16 data_len; - UCHAR padding_len; - enum message_tag_t tag; - UINT32 tag_num; -}; - -struct gquic_pkt_hdr{ - UINT64 connection_id; - int connection_id_len; - UINT8 nonce_flag; - UINT8 reset_flag; - UINT8 version_flag; - UINT32 packet_number_len; - UINT32 version; - UINT8 version_int8; - UINT32 packet_number; - UCHAR auth_hash[MSG_AUTH_HASH_LEN]; -// struct gquic_frame_hdr* frame_hdr; -}; /**************************************************************************/ /* Tag */ @@ -196,15 +245,7 @@ struct gquic_pkt_hdr{ -UINT8 gquic_process(struct streaminfo *pstream, struct quic_stream* a_quic_stream, int thread_seq, void* a_packet); -UINT32 read_offset_len(UINT8 frame_type); -UINT32 read_stream_len(UINT8 frame_type); -UINT32 read_largest_observed_len(UINT8 frame_type); -UINT32 read_missing_packet_len(UINT8 frame_type); - -UINT32 get_stream_id(char* g_data_t, UINT8 frame_type, UINT32 *skip_len); -UINT32 read_seq_num_len(UINT8 flags); -int read_conn_id_len(UINT8 flags); +int quic_process(struct streaminfo *pstream, struct _quic_context* _context, int thread_seq, void* a_packet); #endif diff --git a/src/quic_analysis.c b/src/quic_analysis.c index 59cd4bd..f0b20be 100644 --- a/src/quic_analysis.c +++ b/src/quic_analysis.c @@ -12,7 +12,7 @@ #include #include -struct quic_param_t g_quic_param; +struct _quic_param_t g_quic_param; const char *g_quic_proto_conffile="./conf/quic/main.conf"; const char *g_quic_regionname_conffile="./conf/quic/quic.conf"; @@ -39,47 +39,19 @@ static __attribute__((__used__)) const char * GIT_VERSION_UNKNOWN = NULL; const char QUIC_VERSION_20200522=0; - int quic_init_stream(void **pme, int thread_seq) { - struct quic_stream *a_quic_stream=(struct quic_stream *)*pme; + struct _quic_context *_context=(struct _quic_context *)*pme; - a_quic_stream=(struct quic_stream *)dictator_malloc(thread_seq, sizeof(struct quic_stream)); - memset(a_quic_stream,0,sizeof(struct quic_stream)); + _context=(struct _quic_context *)dictator_malloc(thread_seq, sizeof(struct _quic_context)); + memset(_context, 0, sizeof(struct _quic_context)); - a_quic_stream->output_region_flag = g_quic_param.quic_interested_region_flag; - a_quic_stream->output_region_mask = QUIC_INTEREST_KEY_MASK; - - a_quic_stream->is_quic_stream = QUIC_FALSE; - a_quic_stream->version_cfm = QUIC_FALSE; - a_quic_stream->version = 0; - a_quic_stream->link_state = QUIC_FALSE; - a_quic_stream->fin_flag = QUIC_FALSE; - a_quic_stream->business = (struct quic_business_info *)dictator_malloc(thread_seq,sizeof(struct quic_business_info)); - a_quic_stream->business->param = NULL; - a_quic_stream->business->return_value = PROT_STATE_GIVEME; - - *pme = (void*)a_quic_stream; + *pme=(void*)_context; return 0; } -void quic_release_clientHello(int thread_seq, struct quic_client_hello* st_client_hello) -{ - if(st_client_hello!=NULL) - { - if(st_client_hello->ext_tags!=NULL) - { - quic_release_exts(thread_seq, st_client_hello->ext_tags, st_client_hello->ext_tag_num); - dictator_free(thread_seq, st_client_hello->ext_tags); - st_client_hello->ext_tags = NULL; - } - } - - return; -} - -void quic_release_exts(int thread_seq, quic_tlv_t** ext_tags, UINT16 ext_tag_num) +void quic_release_exts(int thread_seq, quic_tlv_t *ext_tags, int ext_tag_num) { int i=0; @@ -87,62 +59,48 @@ void quic_release_exts(int thread_seq, quic_tlv_t** ext_tags, UINT16 ext_tag_num { for(i=0; iptr_value != NULL) - { - dictator_free(thread_seq, ext_tags[i]->ptr_value); - ext_tags[i]->ptr_value = NULL; - } - - dictator_free(thread_seq, ext_tags[i]); - ext_tags[i] = NULL; + dictator_free(thread_seq, ext_tags[i].value); + ext_tags[i].value=NULL; } } dictator_free(thread_seq, ext_tags); ext_tags=NULL; } + } void quic_release_stream(struct streaminfo *a_tcp, void** pme, int thread_seq) { - struct quic_stream *a_quic_stream = (struct quic_stream *)*pme; - if(NULL!=a_quic_stream) - { - a_quic_stream->fin_flag = QUIC_TRUE; + struct _quic_context *_context = (struct _quic_context *)*pme; + if(NULL!=_context) + { + if(_context->quic_info.client_hello!=NULL) + { + quic_release_exts(thread_seq, _context->quic_info.client_hello->ext_tags, _context->quic_info.client_hello->ext_tag_num); + dictator_free(thread_seq, _context->quic_info.client_hello); + _context->quic_info.client_hello=NULL; + } - if(NULL!=a_quic_stream->business) + if(_context->quic_info.server_hello!=NULL) { - if(a_quic_stream->business->param!=NULL) - { - dictator_free(thread_seq,a_quic_stream->business->param); - a_quic_stream->business->param = NULL; - } - dictator_free(thread_seq,a_quic_stream->business); - a_quic_stream->business = NULL; + quic_release_exts(thread_seq, _context->quic_info.server_hello->ext_tags, _context->quic_info.server_hello->ext_tag_num); + dictator_free(thread_seq, _context->quic_info.server_hello); + _context->quic_info.server_hello=NULL; } - if(NULL!=a_quic_stream->cert_chain.ptr_value) + + if(_context->quic_info.rej!=NULL) { - dictator_free(thread_seq,a_quic_stream->cert_chain.ptr_value); - a_quic_stream->cert_chain.ptr_value = NULL; + quic_release_exts(thread_seq, _context->quic_info.rej->ext_tags, _context->quic_info.rej->ext_tag_num); + dictator_free(thread_seq, _context->quic_info.rej); + _context->quic_info.rej=NULL; } - if(NULL!=a_quic_stream->common_cert.ptr_value) - { - dictator_free(thread_seq,a_quic_stream->common_cert.ptr_value); - a_quic_stream->common_cert.ptr_value = NULL; - } - if(NULL!=a_quic_stream->cached_cert.ptr_value) - { - dictator_free(thread_seq,a_quic_stream->cached_cert.ptr_value); - a_quic_stream->cached_cert.ptr_value = NULL; - } - - quic_release_exts(thread_seq, a_quic_stream->st_client_hello.ext_tags, a_quic_stream->st_client_hello.ext_tag_num); - quic_release_exts(thread_seq, a_quic_stream->st_server_hello.ext_tags, a_quic_stream->st_server_hello.ext_tag_num); - dictator_free(thread_seq,a_quic_stream); - a_quic_stream = NULL; + dictator_free(thread_seq, _context); + _context=NULL; + *pme=NULL; } return; @@ -157,7 +115,7 @@ extern "C" int QUIC_INIT(void) int region_id=0; char region_name[REGION_NAME_LEN]={0}; - memset(&g_quic_param,0,sizeof(struct quic_param_t)); + memset(&g_quic_param,0,sizeof(struct _quic_param_t)); MESA_load_profile_int_def(g_quic_proto_conffile, "QUIC", "LOG_LEVEL", &level, RLOG_LV_FATAL); MESA_load_profile_string_def(g_quic_proto_conffile, "QUIC", "LOG_PATH", log_path, sizeof(log_path), "./log/quic/quic"); @@ -278,8 +236,8 @@ extern "C" long long QUIC_FLAG_CHANGE(char* flag_str) extern "C" char QUIC_ENTRY(struct streaminfo *pstream, void**pme, int thread_seq, void *a_packet) { - uint8_t return_val=0; - struct quic_stream *a_quic_stream=(struct quic_stream *)*pme; + int ret=0; + struct _quic_context *_context=(struct _quic_context *)*pme; if(g_quic_param.quic_interested_region_flagopstate) { case OP_STATE_PENDING: case OP_STATE_DATA: - return_val=gquic_process(pstream, a_quic_stream, thread_seq, a_packet); + ret=quic_process(pstream, _context, thread_seq, a_packet); break; case OP_STATE_CLOSE: - a_quic_stream->fin_flag=QUIC_TRUE; - return_val=gquic_process(pstream, a_quic_stream, thread_seq, a_packet); + ret=quic_process(pstream, _context, thread_seq, a_packet); break; default: break; } - if(return_val==QUIC_RETURN_DROPME || pstream->opstate==OP_STATE_CLOSE) + if(ret&APP_STATE_DROPME|| pstream->opstate==OP_STATE_CLOSE) { quic_release_stream(pstream, pme, thread_seq); *pme=NULL; - return APP_STATE_DROPME; + return ret; } return APP_STATE_GIVEME; diff --git a/src/quic_analysis.h b/src/quic_analysis.h index 7423504..51ccd57 100644 --- a/src/quic_analysis.h +++ b/src/quic_analysis.h @@ -1,15 +1,7 @@ -/* - * quic_analysis.h - * - * Created on: 2019年4月2日 - * Author: root - */ +#ifndef _QUIC_ANALYSIS_H_ +#define _QUIC_ANALYSIS_H_ -#ifndef SRC_QUIC_ANALYSIS_H_ -#define SRC_QUIC_ANALYSIS_H_ - -#include -#include "quic_util.h" +#include "gquic.h" #define QUIC_TRUE 0x01 #define QUIC_FALSE 0x00 @@ -17,24 +9,14 @@ #define QUIC_WHOLE_CLOSE 0x02 #define QUIC_DATA 0x03 #define QUIC_KEY 1 -#define CT_GNUC_SO_EXPORT __attribute__ ((visibility("default"))) //符号导出本so文件 -#define CT_GNUC_SO_LOCAL __attribute__ ((visibility("hidden"))) //符号隐藏于本so文件中 #define QUIC_RETURN_NORM 0x60 #define QUIC_RETURN_UNNORM 0x61 #define QUIC_RETURN_RESET_BUFFER 0x62 #define QUIC_RETURN_DROPME 0x63 #define MAX_REGION_NUM 15 #define REGION_NAME_LEN 32 -#define GQUIC_HEADER_LEN 1+8+1 -#define IQUIC_HEADER_LEN 1+8+1 -#define ENC_BIG_ENDIAN 0x00000000 -#define ENC_LITTLE_ENDIAN 0x80000000 -#define DIR_C2S 0x01 -#define DIR_S2C 0x02 -#define DIR_DOUBLE 0x03 - -struct quic_param_t +struct _quic_param_t { unsigned long long quic_interested_region_flag; unsigned long long quic_region_cnt; @@ -54,7 +36,18 @@ enum quic_mes_type{ MSG_UNKNOWN = 255 }; -void quic_release_exts(int thread_seq, quic_tlv_t** ext_tags, UINT16 ext_tag_num); +struct _quic_context +{ + int is_quic; + int link_state; + void *business_pme; + struct _quic_info quic_info; +}; + + +extern struct _quic_param_t g_quic_param; + +void quic_release_exts(int thread_seq, quic_tlv_t *ext_tags, int ext_tag_num); #endif /* SRC_QUIC_ANALYSIS_H_ */ diff --git a/src/quic_callback.c b/src/quic_callback.c index 81824c5..b28b04f 100644 --- a/src/quic_callback.c +++ b/src/quic_callback.c @@ -1,64 +1,3 @@ -/* - * quic_callback.c - * - * Created on: 2019年4月13日 - * Author: root - */ -#include "gquic.h" -#include "quic_analysis.h" -extern struct quic_param_t g_quic_param; -int quic_getLinkState(struct quic_stream *a_quic_stream) -{ - UCHAR state = 0; - - if(QUIC_FALSE==a_quic_stream->link_state) - { - if(QUIC_TRUE==a_quic_stream->fin_flag) - { - state=SESSION_STATE_CLOSE|SESSION_STATE_PENDING; - } - else - { - state=SESSION_STATE_PENDING; - } - } - else - { - if(QUIC_TRUE==(a_quic_stream)->fin_flag) - { - state=SESSION_STATE_CLOSE; - } - else - { - state=SESSION_STATE_DATA; - } - } - - a_quic_stream->link_state=QUIC_TRUE; - - return state; -} -UCHAR quic_callPlugins(struct quic_stream *a_quic_stream, struct streaminfo *pstream, enum quic_interested_region region_mask, int thread_seq, void *a_packet) -{ - stSessionInfo session_info; - unsigned long long region_flag=a_quic_stream->output_region_flag; - - region_flag = (region_flag >> region_mask) % 2; - - if(QUIC_TRUE==region_flag || a_quic_stream->fin_flag==QUIC_TRUE) - { - if (PROT_STATE_DROPME != a_quic_stream->business->return_value) - { - session_info.plugid = g_quic_param.quic_plugid; - session_info.prot_flag = (((unsigned long long)1)<business->return_value = PROT_PROCESS(&session_info, &(a_quic_stream->business->param),thread_seq,pstream, a_packet); - } - } - - return QUIC_RETURN_NORM; -} diff --git a/src/quic_callback.h b/src/quic_callback.h index 4402146..7fccf7f 100644 --- a/src/quic_callback.h +++ b/src/quic_callback.h @@ -7,12 +7,5 @@ #ifndef SRC_QUIC_CALLBACK_H_ #define SRC_QUIC_CALLBACK_H_ -#include "gquic.h" -UCHAR quic_callPlugins(struct quic_stream *a_quic_stream, struct streaminfo *pstream, enum quic_interested_region region_mask, int thread_seq, void *a_packet); - -//UCHAR quic_doWithVersion(struct quic_stream** a_quic_stream, struct streaminfo *pstream, -// unsigned long long region_flag, int thread_seq, void *a_packet); -//UCHAR quic_doWithApplicationData(char *pc_quic_data, int data_len, struct quic_stream **a_quic_stream, struct streaminfo *pstream, -// unsigned long long region_flag, int thread_seq, void *a_packet); #endif /* SRC_QUIC_CALLBACK_H_ */ diff --git a/src/quic_version.cpp b/src/quic_version.cpp new file mode 100644 index 0000000..569172f --- /dev/null +++ b/src/quic_version.cpp @@ -0,0 +1,17 @@ +#include +#include + +#include "gquic.h" +#include "gquic_process.h" + +int quic_version_int2string(unsigned int version, char *buff, int buff_len) +{ + if(version>0 && version<=GQUIC_VERSION_Q099) + { + snprintf(buff, buff_len, "Google QUIC %02d", (((version>>8)&0x0000000F)*10) + (version&0x0000000F)); + return 0; + } + + return -1; +} +