2020-05-12 12:18:02 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* gquic_process.c
|
|
|
|
|
|
*
|
|
|
|
|
|
* Created on: 2019<EFBFBD><EFBFBD>4<EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>
|
|
|
|
|
|
* Author: root
|
|
|
|
|
|
*/
|
|
|
|
|
|
#include "gquic_process.h"
|
|
|
|
|
|
#include "quic_analysis.h"
|
|
|
|
|
|
#include "quic_callback.h"
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include<assert.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define C2S 0x01
|
|
|
|
|
|
#define S2C 0x02
|
|
|
|
|
|
#define GQUIC_HANDSHAKE_LEN 12+1+1+4+4
|
|
|
|
|
|
#define DIVERSIFICATION_NONCE_LEN 32
|
|
|
|
|
|
|
|
|
|
|
|
enum gquic_type {
|
|
|
|
|
|
GQUIC=1, UNKNOWN_QUIC_TYPE
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum gquic_handshake_type {
|
|
|
|
|
|
QUIC_Crypto=1, UNKNOWN_HANDSHAKE_TYPE
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//QUIC_DATA:is quic data pcap;QUIC_TRUE:is handshake pcap;QUIC_RETURN_DROPME:not quic protocol;
|
|
|
|
|
|
UCHAR is_handshake_pkt(struct quic_stream* a_quic_stream,uint32_t pkt_num_len,
|
|
|
|
|
|
char * quic_data, UINT32 quic_data_len, UINT32 offset){
|
|
|
|
|
|
UINT8 frame_type = 0, num_timestamp, num_ranges, num_revived, num_blocks;
|
|
|
|
|
|
UINT32 len_stream = 0, len_offset = 0, len_data = 0, len_largest_observed = 0, len_missing_packet = 0;
|
|
|
|
|
|
if(!a_canRead(GQUIC_HANDSHAKE_LEN, quic_data_len, offset)){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
//message authentication hash
|
|
|
|
|
|
if(!a_canRead(MSG_AUTH_HASH_LEN, quic_data_len, offset)){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
offset += MSG_AUTH_HASH_LEN;
|
|
|
|
|
|
|
|
|
|
|
|
//private flags
|
|
|
|
|
|
if(a_quic_stream->version > 0 && a_quic_stream->version < 34){
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(offset < quic_data_len){
|
|
|
|
|
|
frame_type = quic_data[offset];
|
|
|
|
|
|
//offset+=1;
|
|
|
|
|
|
if(!(frame_type & FRAM_SPECIAL)){
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
UINT16 len_reason;
|
|
|
|
|
|
switch(frame_type){
|
|
|
|
|
|
case PADDING:
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case RST_STREAM:
|
|
|
|
|
|
//stream id
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
//Byte Offset
|
|
|
|
|
|
offset += 8;
|
|
|
|
|
|
//Error Code
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CONNECTION_CLOSE:
|
|
|
|
|
|
len_reason = 0;
|
|
|
|
|
|
//Error Code
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
//Reason Phrase Length
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 2){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
len_reason = a_pntoh16(quic_data, offset);
|
|
|
|
|
|
offset += 2;
|
|
|
|
|
|
//Reason Phrase,If length remaining == len_reason, it is Connection Close
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) == len_reason){
|
|
|
|
|
|
return QUIC_DATA;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case GOAWAY:{
|
|
|
|
|
|
len_reason = 0;
|
|
|
|
|
|
//Error Code
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
//Last Good Stream ID
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
//Reason Phrase Length
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 2){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
len_reason = a_pntoh16(quic_data, offset);
|
|
|
|
|
|
offset += 2;
|
|
|
|
|
|
//Reason Phrase
|
|
|
|
|
|
offset += len_reason;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case WINDOW_UPDATE:
|
|
|
|
|
|
//Stream ID
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
//Byte Offset
|
|
|
|
|
|
offset += 8;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case BLOCKED:
|
|
|
|
|
|
//Stream ID
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case STOP_WAITING:
|
|
|
|
|
|
//No longer Entropy after Q034
|
|
|
|
|
|
if(a_quic_stream->version > 0 && a_quic_stream->version < 34){
|
|
|
|
|
|
// Send Entropy
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
//Least Unacked Delta
|
|
|
|
|
|
offset += pkt_num_len;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case PING: //No Payload
|
|
|
|
|
|
default:
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
if(frame_type & STREAM){
|
|
|
|
|
|
if(frame_type & STREAM_D){
|
|
|
|
|
|
len_data = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
len_offset = read_offset_len(frame_type);
|
|
|
|
|
|
len_stream = read_stream_len(frame_type);
|
|
|
|
|
|
offset+=1;
|
|
|
|
|
|
offset+=len_stream;
|
|
|
|
|
|
offset+=len_offset;
|
|
|
|
|
|
offset+=len_data;
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 4){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
UINT32 message_tag;
|
|
|
|
|
|
strncpy((char*)&message_tag, quic_data+offset, 4);
|
|
|
|
|
|
if(ntohl(message_tag) == CHLO || ntohl(message_tag) == SHLO || ntohl(message_tag) == REJ){
|
|
|
|
|
|
return QUIC_TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else if(frame_type & ACK){
|
|
|
|
|
|
offset+=1;
|
|
|
|
|
|
len_largest_observed = read_largest_observed_len(frame_type);
|
|
|
|
|
|
len_missing_packet = read_missing_packet_len(frame_type);
|
|
|
|
|
|
//No longer Entropy after Q034
|
|
|
|
|
|
if(a_quic_stream->version < 34 && a_quic_stream->version > 0){
|
|
|
|
|
|
//Send Entropy
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
offset += len_largest_observed;
|
|
|
|
|
|
offset += 2; //ack delay time
|
|
|
|
|
|
if(get_remaining_len(quic_data_len, offset) <= 1){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
strncpy((char*)&num_timestamp, quic_data+offset,1);
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
if(num_timestamp > 0){
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
offset += 4; //first timestamp
|
|
|
|
|
|
offset += (num_timestamp - 1)*(1+2);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(frame_type & ACK_N){
|
|
|
|
|
|
//Num Ranges
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 1){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
strncpy((char*)&num_ranges, quic_data+offset,1);
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
|
|
|
|
|
|
//Num Range x (Missing Packet + Range Length)
|
|
|
|
|
|
offset += num_ranges*(len_missing_packet+1);
|
|
|
|
|
|
|
|
|
|
|
|
//Num Revived
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 1){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
strncpy((char*)&num_revived, quic_data+offset,1);
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
//Num Revived x Length Largest Observed
|
|
|
|
|
|
offset += num_revived*len_largest_observed;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//Largest Acked
|
|
|
|
|
|
offset += len_largest_observed;
|
|
|
|
|
|
//Largest Acked Delta Time
|
|
|
|
|
|
offset += 2;
|
|
|
|
|
|
//Ack Block
|
|
|
|
|
|
if(frame_type & ACK_N){
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 1){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
strncpy((char*)&num_blocks, quic_data+offset,1);
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
//First Ack Block Length
|
|
|
|
|
|
offset += len_missing_packet;
|
|
|
|
|
|
if(num_blocks){
|
|
|
|
|
|
//Gap to next block
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
num_blocks -= 1;
|
|
|
|
|
|
offset += (num_blocks - 1)*len_missing_packet;
|
|
|
|
|
|
}
|
|
|
|
|
|
//Timestamp
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, offset) <= 1){
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
strncpy((char*)&num_timestamp, quic_data+offset,1);
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
if(num_timestamp > 0){
|
|
|
|
|
|
//Delta Largest Acked
|
|
|
|
|
|
offset += 1;
|
|
|
|
|
|
//Time Since Largest Acked
|
|
|
|
|
|
offset += 4;
|
|
|
|
|
|
//Num Timestamp x (Delta Largest Acked + Time Since Previous Timestamp)
|
|
|
|
|
|
offset += (num_timestamp - 1)*(1+2);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
offset +=1;
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return QUIC_FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void gquic_proc_tag(struct streaminfo *pstream, struct quic_stream *a_quic_stream, UINT16 tag_num, UINT8 direction,
|
|
|
|
|
|
unsigned long long region_flag, int thread_seq, void* a_packet, char * quic_data, UINT32 quic_data_len, UINT32 g_pos_t){
|
|
|
|
|
|
UINT32 total_tag_len = 0, tag_len = 0;
|
|
|
|
|
|
UINT32 tag_value_start = tag_num * 4 * 2 + g_pos_t;
|
|
|
|
|
|
UINT32 tag_offset_end = 0, pre_tag_offset_end = 0;
|
|
|
|
|
|
UCHAR return_val;
|
|
|
|
|
|
int tag_type_len = 4, tag_offset_len = 4, num = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while(tag_num > 0 && a_canRead(tag_type_len + tag_offset_len, quic_data_len, g_pos_t)){
|
|
|
|
|
|
UINT32 tag_type;
|
|
|
|
|
|
if(!a_canRead(tag_type_len, quic_data_len, g_pos_t)){
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tag_type = a_pntoh32(quic_data, g_pos_t);
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
if(!a_canRead(tag_type_len, quic_data_len, g_pos_t)){
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
tag_offset_end = a_pletoh32(quic_data, g_pos_t);
|
|
|
|
|
|
if(tag_offset_end < pre_tag_offset_end){
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(tag_offset_end >= quic_data_len) {
|
|
|
|
|
|
return ;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
tag_len = tag_offset_end - pre_tag_offset_end;
|
|
|
|
|
|
if(!a_canRead(tag_len, quic_data_len, tag_value_start)){
|
|
|
|
|
|
return ;
|
|
|
|
|
|
}
|
|
|
|
|
|
total_tag_len += tag_len;
|
|
|
|
|
|
if(tag_len == 0){
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(tag_type == TAG_PAD){
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
//common_cert
|
|
|
|
|
|
if(tag_type == TAG_CCS){
|
|
|
|
|
|
if(a_quic_stream->common_cert.ptr_value == NULL){
|
|
|
|
|
|
a_quic_stream->common_cert.ptr_value = (char *)dictator_malloc(thread_seq, sizeof(char)*tag_len);
|
|
|
|
|
|
memset(a_quic_stream->common_cert.ptr_value, 0, tag_len);
|
|
|
|
|
|
a_quic_stream->common_cert.length = tag_len;
|
|
|
|
|
|
memcpy(a_quic_stream->common_cert.ptr_value, quic_data + tag_value_start, tag_len);
|
|
|
|
|
|
if(a_quic_stream->common_cert.ptr_value != NULL){
|
|
|
|
|
|
return_val = quic_proc_interest_region(QUIC_COMM_CERT_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
//cached_cert
|
|
|
|
|
|
if(tag_type == TAG_CCRT){
|
|
|
|
|
|
if(a_quic_stream->cached_cert.ptr_value == NULL){
|
|
|
|
|
|
a_quic_stream->cached_cert.ptr_value = (char *)dictator_malloc(thread_seq, sizeof(char)*tag_len);
|
|
|
|
|
|
memset(a_quic_stream->cached_cert.ptr_value, 0, tag_len);
|
|
|
|
|
|
a_quic_stream->cached_cert.length = tag_len;
|
|
|
|
|
|
memcpy(a_quic_stream->cached_cert.ptr_value, quic_data + tag_value_start, tag_len);
|
|
|
|
|
|
if(a_quic_stream->cached_cert.ptr_value != NULL){
|
|
|
|
|
|
return_val = quic_proc_interest_region(QUIC_CACHED_CERT_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
//cert_chain?????length need change
|
|
|
|
|
|
if(tag_type == TAG_CRT){
|
|
|
|
|
|
if(a_quic_stream->cert_chain.length == 0 && a_quic_stream->cert_chain.ptr_value == NULL){
|
|
|
|
|
|
a_quic_stream->cert_chain.length = tag_len > (quic_data_len-tag_value_start+1) ? (quic_data_len-tag_value_start+1) : tag_len;
|
|
|
|
|
|
a_quic_stream->cert_chain.ptr_value = (char *)dictator_malloc(thread_seq, a_quic_stream->cert_chain.length);
|
|
|
|
|
|
memset(a_quic_stream->cert_chain.ptr_value, 0, a_quic_stream->cert_chain.length);
|
|
|
|
|
|
memcpy(a_quic_stream->cert_chain.ptr_value, quic_data + tag_value_start, a_quic_stream->cert_chain.length);
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += a_quic_stream->cert_chain.length;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
if(a_quic_stream->cert_chain.ptr_value != NULL){
|
|
|
|
|
|
return_val = quic_proc_interest_region(QUIC_CERT_CHAIN_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
}
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(tag_type == TAG_SNI){
|
|
|
|
|
|
if(a_quic_stream->st_client_hello.server_name_len ==0){
|
|
|
|
|
|
assert(tag_len < SERVER_NAME_LEN);
|
|
|
|
|
|
a_quic_stream->st_client_hello.server_name_len = tag_len > SERVER_NAME_LEN ? SERVER_NAME_LEN : tag_len;
|
|
|
|
|
|
strncpy(a_quic_stream->st_client_hello.server_name, quic_data + tag_value_start, tag_len);
|
|
|
|
|
|
a_quic_stream->st_client_hello.server_name_len = tag_len;
|
|
|
|
|
|
// printf("SNI:%s\n",a_quic_stream->st_client_hello.server_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(tag_type == TAG_UAID){
|
|
|
|
|
|
assert(tag_len < USER_AGENT_LEN);
|
|
|
|
|
|
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;
|
|
|
|
|
|
strncpy(a_quic_stream->st_client_hello.user_agent, quic_data + tag_value_start, a_quic_stream->st_client_hello.user_agent_len);
|
|
|
|
|
|
|
|
|
|
|
|
// printf("UA:%s\n",a_quic_stream->st_client_hello.user_agent);
|
|
|
|
|
|
}
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(direction == 0x01 && num < a_quic_stream->st_client_hello.ext_tag_num){
|
|
|
|
|
|
a_quic_stream->st_client_hello.ext_tags[num]->type = tag_type;
|
|
|
|
|
|
a_quic_stream->st_client_hello.ext_tags[num]->length = tag_len > MAX_TAG_VALUE_LEN-1 ? tag_len > MAX_TAG_VALUE_LEN-1 : tag_len;
|
|
|
|
|
|
memcpy(a_quic_stream->st_client_hello.ext_tags[num]->ptr_value, quic_data+tag_value_start, a_quic_stream->st_client_hello.ext_tags[num]->length);
|
|
|
|
|
|
// a_readBytes(a_quic_stream->st_client_hello.ext_tags[num]->ptr_value,
|
|
|
|
|
|
// a_quic_stream->st_client_hello.ext_tags[num]->length, quic_data, quic_data_len, &tag_value_start);
|
|
|
|
|
|
((unsigned char*)(a_quic_stream->st_client_hello.ext_tags[num]->ptr_value))[MAX_TAG_VALUE_LEN-1] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
}else if(num < a_quic_stream->st_server_hello.ext_tag_num){
|
|
|
|
|
|
a_quic_stream->st_server_hello.ext_tags[num]->type = tag_type;
|
|
|
|
|
|
a_quic_stream->st_server_hello.ext_tags[num]->length = tag_len > MAX_TAG_VALUE_LEN-1 ? tag_len > MAX_TAG_VALUE_LEN-1 : tag_len;
|
|
|
|
|
|
memcpy(a_quic_stream->st_server_hello.ext_tags[num]->ptr_value, quic_data+tag_value_start, a_quic_stream->st_server_hello.ext_tags[num]->length);
|
|
|
|
|
|
// a_readBytes(a_quic_stream->st_server_hello.ext_tags[num]->ptr_value,
|
|
|
|
|
|
// a_quic_stream->st_server_hello.ext_tags[num]->length, quic_data, quic_data_len, &tag_value_start);
|
|
|
|
|
|
((unsigned char*)(a_quic_stream->st_server_hello.ext_tags[num]->ptr_value))[MAX_TAG_VALUE_LEN-1] = '\0';
|
|
|
|
|
|
}
|
|
|
|
|
|
num++;
|
|
|
|
|
|
tag_num--;
|
|
|
|
|
|
tag_value_start += tag_len;
|
|
|
|
|
|
pre_tag_offset_end = tag_offset_end;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pos_t = tag_value_start;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//frame type->stream->offset->data length
|
|
|
|
|
|
void gquic_proc_unencrypt(struct streaminfo *pstream, struct quic_stream* a_quic_stream, uint32_t pkt_num_len,
|
|
|
|
|
|
unsigned long long region_flag, int thread_seq, void* a_packet, char * quic_data, UINT32 quic_data_len, UINT32 g_pos_t){
|
|
|
|
|
|
UINT8 frame_type, num_timestamp, num_ranges, num_revived, num_blocks;
|
|
|
|
|
|
UINT32 len_largest_observed = 0, len_missing_packet = 0;
|
|
|
|
|
|
|
|
|
|
|
|
g_pos_t += MSG_AUTH_HASH_LEN;
|
|
|
|
|
|
//private flags
|
|
|
|
|
|
if(a_quic_stream->version <34){
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
while(g_pos_t < quic_data_len){
|
|
|
|
|
|
a_readUInt8(&frame_type, quic_data, quic_data_len, &g_pos_t);
|
|
|
|
|
|
if(!(frame_type & FRAM_SPECIAL)){
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
UINT16 len_reason;
|
|
|
|
|
|
switch(frame_type){
|
|
|
|
|
|
case PADDING:
|
|
|
|
|
|
return;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case RST_STREAM:
|
|
|
|
|
|
//stream id
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
//Byte Offset
|
|
|
|
|
|
g_pos_t += 8;
|
|
|
|
|
|
//Error Code
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
a_quic_stream->fin_flag = QUIC_TRUE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CONNECTION_CLOSE:
|
|
|
|
|
|
len_reason = 0;
|
|
|
|
|
|
//Error Code
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
//Reason Phrase Length
|
|
|
|
|
|
len_reason = a_pntoh16(quic_data, g_pos_t);
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
//Reason Phrase,If length remaining == len_reason, it is Connection Close
|
|
|
|
|
|
if (get_remaining_len(quic_data_len, g_pos_t) == len_reason){
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(a_quic_stream->fin_flag == QUIC_FALSE){
|
|
|
|
|
|
a_quic_stream->fin_flag = QUIC_HALF_CLOSE;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
a_quic_stream->fin_flag = QUIC_TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case GOAWAY:{
|
|
|
|
|
|
len_reason = 0;
|
|
|
|
|
|
//Error Code
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
//Last Good Stream ID
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
//Reason Phrase Length
|
|
|
|
|
|
len_reason = a_pntoh16(quic_data, g_pos_t);
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
//Reason Phrase
|
|
|
|
|
|
g_pos_t += len_reason;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case WINDOW_UPDATE:
|
|
|
|
|
|
//Stream ID
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
//Byte Offset
|
|
|
|
|
|
g_pos_t += 8;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case BLOCKED:
|
|
|
|
|
|
//Stream ID
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case STOP_WAITING:
|
|
|
|
|
|
//No longer Entropy after Q034
|
|
|
|
|
|
if(a_quic_stream->version < 34){
|
|
|
|
|
|
// Send Entropy
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
//Least Unacked Delta
|
|
|
|
|
|
g_pos_t += pkt_num_len;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case PING: //No Payload
|
|
|
|
|
|
default:
|
|
|
|
|
|
return;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//special packet
|
|
|
|
|
|
if(frame_type & STREAM){
|
|
|
|
|
|
UINT8 len_data = 0, len_stream = 0, len_offset = 0, return_val;
|
|
|
|
|
|
UINT16 tag_num = 0;
|
|
|
|
|
|
UINT32 stream_id, message_tag;
|
|
|
|
|
|
if(frame_type & STREAM_F){
|
|
|
|
|
|
a_quic_stream->fin_flag = QUIC_TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(frame_type & STREAM_D){
|
|
|
|
|
|
len_data = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
len_stream = read_stream_len(frame_type);
|
|
|
|
|
|
stream_id = get_stream_id(quic_data, g_pos_t, len_stream);
|
|
|
|
|
|
g_pos_t += len_stream;
|
|
|
|
|
|
|
|
|
|
|
|
len_offset = read_offset_len(frame_type);
|
|
|
|
|
|
g_pos_t += len_offset;
|
|
|
|
|
|
|
|
|
|
|
|
g_pos_t += len_data;
|
|
|
|
|
|
//handshake
|
|
|
|
|
|
if(stream_id == 1){
|
|
|
|
|
|
message_tag = a_pntoh32((void *)quic_data, g_pos_t);
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
tag_num = a_pletoh16(quic_data, g_pos_t);
|
|
|
|
|
|
g_pos_t += 2; //tag_num
|
|
|
|
|
|
g_pos_t += 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 = (struct quic_client_hello*)dictator_malloc(thread_seq,sizeof(struct quic_client_hello));
|
|
|
|
|
|
// memset(a_quic_stream->st_client_hello, 0, sizeof(struct quic_client_hello));
|
|
|
|
|
|
quic_init_clientHello(&a_quic_stream->st_client_hello, tag_num, thread_seq);
|
|
|
|
|
|
}else if(a_quic_stream->st_server_hello.ext_tag_num){
|
|
|
|
|
|
if(tag_num > a_quic_stream->st_client_hello.ext_tag_num){
|
|
|
|
|
|
// a_quic_stream->is_0rtt = QUIC_TRUE;
|
|
|
|
|
|
quic_release_clientHello(thread_seq, &a_quic_stream->st_client_hello);
|
|
|
|
|
|
quic_init_clientHello(&a_quic_stream->st_client_hello, tag_num, thread_seq);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_proc_tag(pstream, a_quic_stream, tag_num, C2S, region_flag, thread_seq, a_packet, quic_data, quic_data_len, g_pos_t);
|
|
|
|
|
|
if(a_quic_stream->st_client_hello.server_name_len > 0 || a_quic_stream->st_client_hello.user_agent_len > 0){
|
|
|
|
|
|
quic_proc_interest_region(QUIC_CLIENT_HELLO_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if(return_val != QUIC_RETURN_NORM){
|
|
|
|
|
|
// return return_val;
|
|
|
|
|
|
// }
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SHLO:
|
|
|
|
|
|
//MTAG_SHLO;
|
|
|
|
|
|
if(a_quic_stream->st_server_hello.ext_tags == NULL){
|
|
|
|
|
|
// a_quic_stream->st_server_hello = (struct quic_server_hello*)dictator_malloc(thread_seq,sizeof(struct quic_server_hello));
|
|
|
|
|
|
// memset(a_quic_stream->st_server_hello, 0, sizeof(struct quic_server_hello));
|
|
|
|
|
|
quic_init_serverHello(&a_quic_stream->st_server_hello, tag_num, thread_seq);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_proc_tag(pstream, a_quic_stream, tag_num, S2C, region_flag, thread_seq, a_packet, quic_data, quic_data_len, g_pos_t);
|
|
|
|
|
|
|
|
|
|
|
|
if(a_quic_stream->st_server_hello.ext_tags != NULL){
|
|
|
|
|
|
quic_proc_interest_region(QUIC_SERVER_HELLO_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
// if(return_val != QUIC_RETURN_NORM){
|
|
|
|
|
|
// return return_val;
|
|
|
|
|
|
// }
|
|
|
|
|
|
break;
|
|
|
|
|
|
case REJ:
|
|
|
|
|
|
//MTAG_REJ;
|
|
|
|
|
|
if(a_quic_stream->st_server_hello.ext_tags == NULL){
|
|
|
|
|
|
// a_quic_stream->st_server_hello = (struct quic_server_hello*)dictator_malloc(thread_seq,sizeof(struct quic_server_hello));
|
|
|
|
|
|
// memset(a_quic_stream->st_server_hello, 0, sizeof(struct quic_server_hello));
|
|
|
|
|
|
quic_init_serverHello(&a_quic_stream->st_server_hello, tag_num, thread_seq);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_proc_tag(pstream, a_quic_stream, tag_num, S2C, region_flag, thread_seq, a_packet, quic_data, quic_data_len, g_pos_t);
|
|
|
|
|
|
if(a_quic_stream->st_server_hello.ext_tags != NULL){
|
|
|
|
|
|
quic_proc_interest_region(QUIC_SERVER_HELLO_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
// if(return_val != QUIC_RETURN_NORM){
|
|
|
|
|
|
// return return_val;
|
|
|
|
|
|
// }
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}else if(frame_type & ACK){
|
|
|
|
|
|
g_pos_t+=1;
|
|
|
|
|
|
len_largest_observed = read_largest_observed_len(frame_type);
|
|
|
|
|
|
len_missing_packet = read_missing_packet_len(frame_type);
|
|
|
|
|
|
//No longer Entropy after Q034
|
|
|
|
|
|
if(a_quic_stream->version < 34){
|
|
|
|
|
|
//Send Entropy
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
g_pos_t += len_largest_observed;
|
|
|
|
|
|
g_pos_t += 2; //ack delay time
|
|
|
|
|
|
strncpy((char*)&num_timestamp, quic_data+g_pos_t,1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
if(num_timestamp > 0){
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
g_pos_t += (num_timestamp - 1)*(1+2);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(frame_type & ACK_N){
|
|
|
|
|
|
strncpy((char*)&num_ranges, quic_data+g_pos_t,1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
g_pos_t += num_ranges*(len_missing_packet+1);
|
|
|
|
|
|
strncpy((char*)&num_revived, quic_data+g_pos_t,1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
//Num Revived x Length Largest Observed
|
|
|
|
|
|
g_pos_t += num_revived*len_largest_observed;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//Largest Acked
|
|
|
|
|
|
g_pos_t += len_largest_observed;
|
|
|
|
|
|
//Largest Acked Delta Time
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
//Ack Block
|
|
|
|
|
|
if(frame_type & ACK_N){
|
|
|
|
|
|
strncpy((char*)&num_blocks, quic_data+g_pos_t,1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
//First Ack Block Length
|
|
|
|
|
|
g_pos_t += len_missing_packet;
|
|
|
|
|
|
if(num_blocks){
|
|
|
|
|
|
//Gap to next block
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
num_blocks -= 1;
|
|
|
|
|
|
g_pos_t += (num_blocks - 1)*len_missing_packet;
|
|
|
|
|
|
}
|
|
|
|
|
|
//Timestamp
|
|
|
|
|
|
strncpy((char*)&num_timestamp, quic_data+g_pos_t,1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
if(num_timestamp > 0){
|
|
|
|
|
|
//Delta Largest Acked
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
//Time Since Largest Acked
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
//Num Timestamp x (Delta Largest Acked + Time Since Previous Timestamp)
|
|
|
|
|
|
g_pos_t += (num_timestamp - 1)*(1+2);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
g_pos_t +=1;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT8 parse_gquic_Q046(struct streaminfo *pstream, unsigned long long region_flag, void* a_packet,
|
2020-05-20 14:52:44 +08:00
|
|
|
|
int thread_seq, char * payload, uint32_t payload_len, struct quic_stream* a_quic_stream){
|
2020-05-12 12:18:02 +08:00
|
|
|
|
uint32_t g_pos_t = 0;
|
|
|
|
|
|
if (!a_canRead(5, payload_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
uint32_t version;
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
strncpy((char*)&version, payload+g_pos_t, 4);
|
|
|
|
|
|
if(ntohl(version) != VER_Q046){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
a_quic_stream->version = (payload[g_pos_t] & 0x0f) * 10 + (payload[g_pos_t+1] & 0x0f);
|
|
|
|
|
|
a_quic_stream->is_quic_stream = QUIC_TRUE;
|
|
|
|
|
|
quic_proc_interest_region(QUIC_VERSION_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
if (!a_canRead(25, payload_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pos_t += 25;
|
|
|
|
|
|
uint8_t frame_type;
|
|
|
|
|
|
while(g_pos_t < payload_len){
|
|
|
|
|
|
a_readUInt8(&frame_type, payload, payload_len, &g_pos_t);
|
|
|
|
|
|
if(frame_type & STREAM){
|
|
|
|
|
|
uint8_t len_data = 0, len_stream = 0, len_offset = 0;
|
|
|
|
|
|
uint16_t tag_num = 0;
|
|
|
|
|
|
uint32_t stream_id, message_tag;
|
|
|
|
|
|
if(frame_type & STREAM_D){
|
|
|
|
|
|
len_data = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
len_stream = read_stream_len(frame_type);
|
|
|
|
|
|
stream_id = get_stream_id(payload, g_pos_t, len_stream);
|
|
|
|
|
|
g_pos_t += len_stream;
|
|
|
|
|
|
|
|
|
|
|
|
len_offset = read_offset_len(frame_type);
|
|
|
|
|
|
g_pos_t += len_offset;
|
|
|
|
|
|
|
|
|
|
|
|
g_pos_t += len_data;
|
|
|
|
|
|
if(stream_id == 1){
|
|
|
|
|
|
message_tag = a_pntoh32((void *)payload, g_pos_t);
|
|
|
|
|
|
g_pos_t += 4;
|
|
|
|
|
|
tag_num = a_pletoh16(payload, g_pos_t);
|
|
|
|
|
|
g_pos_t += 2; //tag_num
|
|
|
|
|
|
g_pos_t += 2; //padding
|
|
|
|
|
|
char sni[1024];
|
|
|
|
|
|
uint32_t sni_len = 0;
|
|
|
|
|
|
char uaid[1024];
|
|
|
|
|
|
uint32_t uaid_len = 0;
|
|
|
|
|
|
switch(message_tag){
|
|
|
|
|
|
case CHLO:
|
|
|
|
|
|
//MTAG_CHLO;
|
|
|
|
|
|
if(a_quic_stream->st_client_hello.ext_tags == NULL){
|
|
|
|
|
|
quic_init_clientHello(&a_quic_stream->st_client_hello, tag_num, thread_seq);
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_proc_tag(pstream, a_quic_stream, tag_num, C2S, region_flag, thread_seq, a_packet, payload, payload_len, g_pos_t);
|
|
|
|
|
|
if(a_quic_stream->st_client_hello.server_name_len > 0 || a_quic_stream->st_client_hello.user_agent_len > 0){
|
|
|
|
|
|
quic_proc_interest_region(QUIC_CLIENT_HELLO_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
// *chello = (struct quic_pme *)malloc(sizeof(struct quic_pme) + sni_len + uaid_len + 2);
|
|
|
|
|
|
// memset(*chello, 0, sizeof(struct quic_pme) + sni_len + uaid_len + 2);
|
|
|
|
|
|
|
|
|
|
|
|
// *chello = (struct quic_pme *)malloc(sizeof(struct quic_pme));
|
|
|
|
|
|
// memset(*chello, 0, sizeof(struct quic_pme));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if(sni_len > 128){
|
|
|
|
|
|
// sni_len = GQUIC_SNI_LEN;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// a_quic_stream->st_client_hello->server_name_len = sni_len;
|
|
|
|
|
|
// memcpy((chello)->sni, sni, sni_len);
|
|
|
|
|
|
// (chello)->sni[127] = '\0';
|
|
|
|
|
|
// if(uaid_len > 512){
|
|
|
|
|
|
// uaid_len = GQUIC_UAID_LEN;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// (chello)->user_agent_len = uaid_len;
|
|
|
|
|
|
// memcpy((chello)->user_agent, uaid, uaid_len);
|
|
|
|
|
|
// (chello)->user_agent[511] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
// char * p, *q;
|
|
|
|
|
|
// p = (char*)(*chello) + sizeof(struct quic_pme);
|
|
|
|
|
|
// q = (char*)(*chello) + sizeof(struct quic_pme) + sni_len + 1;
|
|
|
|
|
|
// memcpy(p, sni, sni_len);
|
|
|
|
|
|
// memset(p+sni_len, '\0', 1);
|
|
|
|
|
|
// (*chello)->sni = p;
|
|
|
|
|
|
// memcpy(q, uaid, uaid_len);
|
|
|
|
|
|
// memset(q+uaid_len, '\0', 1);
|
|
|
|
|
|
// (*chello)->user_agent = q;
|
|
|
|
|
|
// printf("46 chello_sni_len:%d, chello_sni:%s\n",(*chello)->sni_len, (*chello)->sni);
|
|
|
|
|
|
// printf("46 chello_uaid_len:%d, chello_uaid:%s\n",(*chello)->user_agent_len, (*chello)->user_agent);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return QUIC_RETURN_NORM;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT8 parse_gquic(struct streaminfo *pstream, unsigned long long region_flag, void* a_packet,
|
2020-05-20 14:52:44 +08:00
|
|
|
|
int thread_seq, char * payload, uint32_t payload_len, struct quic_stream* a_quic_stream){
|
2020-05-12 12:18:02 +08:00
|
|
|
|
uint8_t pub_flags = 0;
|
|
|
|
|
|
uint8_t nonce_flag = 0;
|
|
|
|
|
|
uint8_t reset_flag = 0;
|
|
|
|
|
|
uint8_t version_flag = 0;
|
|
|
|
|
|
int ret = QUIC_RETURN_DROPME;
|
|
|
|
|
|
uint32_t g_pos_t = 0;
|
|
|
|
|
|
uint64_t connection_id = 0;
|
|
|
|
|
|
int connection_id_len = 0;
|
|
|
|
|
|
uint32_t pkt_num = 0;
|
|
|
|
|
|
uint32_t pkt_num_len = 0;
|
|
|
|
|
|
uint32_t version;
|
|
|
|
|
|
strncpy((char *)&pub_flags, payload + g_pos_t, 1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
if (pub_flags > PACKET_PUBLIC_FLAGS_MAX) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
nonce_flag = (pub_flags & PUBLIC_FLAG_NONCE) != 0;
|
|
|
|
|
|
reset_flag = (pub_flags & PUBLIC_FLAG_RST) != 0;
|
|
|
|
|
|
version_flag = (pub_flags & PUBLIC_FLAG_VER) != 0;
|
|
|
|
|
|
if (reset_flag && version_flag) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(reset_flag){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
connection_id_len = read_conn_id_len(pub_flags);
|
|
|
|
|
|
if(connection_id_len == -1){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}else if(connection_id_len == 0){
|
|
|
|
|
|
connection_id = 0;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
if (!a_canRead(connection_id_len, payload_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
connection_id = a_pntoh64((void *)payload, g_pos_t);
|
|
|
|
|
|
g_pos_t += connection_id_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
pkt_num_len = read_seq_num_len(pub_flags);
|
|
|
|
|
|
if (!a_canRead(VERSION_LEN, payload_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(payload[g_pos_t] != PUBLIC_FLAG_VER_FST_BYTE){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
version = (payload[g_pos_t] & 0x0f) * 10 + (payload[g_pos_t+1] & 0x0f);
|
|
|
|
|
|
a_quic_stream->version = version;
|
|
|
|
|
|
quic_proc_interest_region(QUIC_VERSION_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
if (!a_canRead(pkt_num_len, payload_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
pkt_num = get_pkn(payload, g_pos_t, pkt_num_len);
|
|
|
|
|
|
g_pos_t += pkt_num_len;
|
|
|
|
|
|
//version Э<><D0AD>
|
|
|
|
|
|
if(!version_flag && a_quic_stream->version && !a_quic_stream->version_cfm){
|
|
|
|
|
|
a_quic_stream->version_cfm = QUIC_TRUE;
|
|
|
|
|
|
quic_proc_interest_region(QUIC_VERSION_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}
|
|
|
|
|
|
ret = is_handshake_pkt(a_quic_stream, pkt_num_len, payload, payload_len, g_pos_t);
|
|
|
|
|
|
|
|
|
|
|
|
if(ret == QUIC_TRUE){
|
|
|
|
|
|
//handshake
|
|
|
|
|
|
if(!a_quic_stream->is_quic_stream){
|
|
|
|
|
|
a_quic_stream->is_quic_stream = QUIC_TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_proc_unencrypt(pstream, a_quic_stream, pkt_num_len, region_flag, thread_seq, a_packet, payload, payload_len, g_pos_t);
|
|
|
|
|
|
ret = QUIC_RETURN_NORM;
|
|
|
|
|
|
}else if(ret == QUIC_DATA){
|
|
|
|
|
|
//ack or special stream
|
|
|
|
|
|
a_quic_stream->is_quic_stream = QUIC_TRUE;
|
|
|
|
|
|
ret = QUIC_RETURN_NORM;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//gquic data or not gquic packet
|
|
|
|
|
|
if(a_quic_stream->is_quic_stream){
|
|
|
|
|
|
quic_proc_interest_region(QUIC_APPLICATION_DATA_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
ret = QUIC_RETURN_NORM;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
ret = QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//cid->version->nounce->pkt num->ahn hash(12)
|
|
|
|
|
|
UINT8 gquic_process(struct streaminfo *pstream, struct quic_stream* a_quic_stream,
|
|
|
|
|
|
unsigned long long region_flag, int thread_seq, void* a_packet, char* quic_data, UINT32 quic_data_len) {
|
|
|
|
|
|
|
|
|
|
|
|
int ret = parse_gquic(pstream, region_flag, a_packet, thread_seq, quic_data, quic_data_len, a_quic_stream);
|
|
|
|
|
|
if(ret == QUIC_RETURN_DROPME){
|
|
|
|
|
|
ret = parse_gquic_Q046(pstream, region_flag, a_packet, thread_seq, quic_data, quic_data_len, a_quic_stream);
|
|
|
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
UINT8 pub_flags;
|
|
|
|
|
|
UCHAR return_val = QUIC_RETURN_NORM;
|
|
|
|
|
|
UINT32 g_pos_t = 0;
|
|
|
|
|
|
strncpy((char *)&pub_flags, quic_data + g_pos_t, 1);
|
|
|
|
|
|
g_pos_t += 1;
|
|
|
|
|
|
if (pub_flags > PACKET_PUBLIC_FLAGS_MAX) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
struct gquic_pkt_hdr gquic_hdr = {};
|
|
|
|
|
|
memset(&gquic_hdr, 0, sizeof(struct gquic_pkt_hdr));
|
|
|
|
|
|
gquic_hdr.nonce_flag = (pub_flags & PUBLIC_FLAG_NONCE) != 0;
|
|
|
|
|
|
gquic_hdr.reset_flag = (pub_flags & PUBLIC_FLAG_RST) != 0;
|
|
|
|
|
|
gquic_hdr.version_flag = (pub_flags & PUBLIC_FLAG_VER) != 0;
|
|
|
|
|
|
if (gquic_hdr.reset_flag && gquic_hdr.version_flag) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(gquic_hdr.reset_flag){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_hdr.connection_id_len = read_conn_id_len(pub_flags);
|
|
|
|
|
|
if(gquic_hdr.connection_id_len == -1){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}else if(gquic_hdr.connection_id_len == 0){
|
|
|
|
|
|
gquic_hdr.connection_id = 0;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
if (!a_canRead(gquic_hdr.connection_id_len, quic_data_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(a_quic_stream->gquic_cID == 0){
|
|
|
|
|
|
gquic_hdr.connection_id = a_pntoh64((void *)quic_data, g_pos_t);
|
|
|
|
|
|
a_quic_stream->gquic_cID = gquic_hdr.connection_id;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
g_pos_t+=gquic_hdr.connection_id_len;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(gquic_hdr.nonce_flag && pstream->curdir == 0x02){
|
|
|
|
|
|
g_pos_t+=DIVERSIFICATION_NONCE_LEN;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_hdr.packet_number_len = read_seq_num_len(pub_flags);
|
|
|
|
|
|
if (gquic_hdr.version_flag) {
|
|
|
|
|
|
//c2s
|
|
|
|
|
|
if(pstream->curdir == 0x01){
|
|
|
|
|
|
if (!a_canRead(4, quic_data_len, g_pos_t)) {
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(quic_data[g_pos_t] != PUBLIC_FLAG_VER_FST_BYTE){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
a_quic_stream->version_flag = QUIC_TRUE;
|
|
|
|
|
|
gquic_hdr.version = (quic_data[g_pos_t] & 0x0f) * 10 + (quic_data[g_pos_t+1] & 0x0f);
|
|
|
|
|
|
g_pos_t += 2;
|
|
|
|
|
|
a_quic_stream->version = gquic_hdr.version;
|
|
|
|
|
|
printf("VERSION:%d\n",a_quic_stream->version);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(!gquic_hdr.version_flag && pstream->curdir == 0x02 && a_quic_stream->version_flag == QUIC_TRUE){
|
|
|
|
|
|
a_quic_stream->version_flag = QUIC_FALSE;
|
|
|
|
|
|
return_val = quic_proc_interest_region(QUIC_VERSION_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
// if(return_val != QUIC_RETURN_NORM){
|
|
|
|
|
|
// char info[256];
|
|
|
|
|
|
// sprintf(info, "VERSION CALLBACK ERROR\t%s_%s_%d\t", __FILE__, __FUNCTION__, __LINE__);
|
|
|
|
|
|
// printf("%s\n", info);
|
|
|
|
|
|
// return return_val;
|
|
|
|
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
|
|
if(!a_canRead(gquic_hdr.packet_number_len, quic_data_len, g_pos_t)){
|
|
|
|
|
|
return QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
UINT32 pkt_num = get_pkn(quic_data, g_pos_t, gquic_hdr.packet_number_len);
|
|
|
|
|
|
gquic_hdr.packet_number = pkt_num;
|
|
|
|
|
|
g_pos_t += gquic_hdr.packet_number_len;
|
|
|
|
|
|
|
|
|
|
|
|
char sip[32],dip[32];
|
|
|
|
|
|
memset(sip, 0, sizeof(sip));
|
|
|
|
|
|
memset(dip, 0, sizeof(dip));
|
|
|
|
|
|
a_ntoa(pstream->addr.tuple4_v4->saddr, sip);
|
|
|
|
|
|
a_ntoa(pstream->addr.tuple4_v4->daddr, dip);
|
|
|
|
|
|
|
|
|
|
|
|
return_val = is_handshake_pkt(a_quic_stream, &gquic_hdr, quic_data, quic_data_len, g_pos_t);
|
|
|
|
|
|
if(return_val == QUIC_TRUE){
|
|
|
|
|
|
//handshake
|
|
|
|
|
|
if(!a_quic_stream->is_quic_stream){
|
|
|
|
|
|
a_quic_stream->is_quic_stream = QUIC_TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
gquic_proc_unencrypt(pstream, &gquic_hdr, a_quic_stream, region_flag, thread_seq, a_packet, quic_data, quic_data_len, g_pos_t);
|
|
|
|
|
|
return_val = QUIC_RETURN_NORM;
|
|
|
|
|
|
}else if(return_val == QUIC_DATA){
|
|
|
|
|
|
//ack or special stream
|
|
|
|
|
|
if(!a_quic_stream->is_quic_stream){
|
|
|
|
|
|
a_quic_stream->is_quic_stream = QUIC_TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//gquic data or not gquic packet
|
|
|
|
|
|
if(a_quic_stream->is_quic_stream){
|
|
|
|
|
|
return_val = quic_proc_interest_region(QUIC_APPLICATION_DATA_MASK, &a_quic_stream, pstream, region_flag, thread_seq, a_packet);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
return_val = QUIC_RETURN_DROPME;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if(a_quic_stream->type == GQUIC){
|
|
|
|
|
|
// if(pstream->curdir == 0x01){
|
|
|
|
|
|
// printf("QUIC\tC2S\tSIP=%s\tDIP=%s\tPKN=%d\tVERSION=%d\tthread_seq=%d\n",sip,dip,pkt_num,gquic_hdr.version,thread_seq);
|
|
|
|
|
|
// }else{
|
|
|
|
|
|
// printf("QUIC\tS2C\tSIP=%s\tDIP=%s\tPKN=%d\tVERSION=%d\tthread_seq=%d\n",sip,dip,pkt_num,gquic_hdr.version,thread_seq);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else{
|
|
|
|
|
|
// if(pstream->curdir == 0x01){
|
|
|
|
|
|
// printf("UNKN\tC2S\tSIP=%s\tDIP=%s\tPKN=%d\tVERSION=%d\tthread_seq=%d\n",sip,dip,pkt_num,gquic_hdr.version,thread_seq);
|
|
|
|
|
|
// }else{
|
|
|
|
|
|
// printf("UNKN\tS2C\tSIP=%s\tDIP=%s\tPKN=%d\tVERSION=%d\tthread_seq=%d\n",sip,dip,pkt_num,gquic_hdr.version,thread_seq);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
return return_val;
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 -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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UINT32 get_stream_id(char* g_data_t, UINT32 offset, UINT8 stream_id_len){
|
|
|
|
|
|
if(stream_id_len == 1){
|
|
|
|
|
|
return g_data_t[offset];
|
|
|
|
|
|
}else if(stream_id_len == 2){
|
|
|
|
|
|
return a_pletoh16((void *)g_data_t, offset);
|
|
|
|
|
|
}else if(stream_id_len == 3){
|
|
|
|
|
|
return a_pletoh24((void *)g_data_t, offset);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
return a_pletoh32((void *)g_data_t, offset);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT32 get_pkn(char* g_data_t, UINT32 offset, UINT8 pkn_len){
|
|
|
|
|
|
if(pkn_len == 1){
|
|
|
|
|
|
return g_data_t[offset];
|
|
|
|
|
|
}else if(pkn_len == 2){
|
|
|
|
|
|
return a_pletoh16((void *)g_data_t, offset);
|
|
|
|
|
|
}else if(pkn_len == 4){
|
|
|
|
|
|
return a_pletoh32((void *)g_data_t, offset);
|
|
|
|
|
|
}else{//6
|
|
|
|
|
|
return a_pletoh48((void *)g_data_t, offset);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|