#include <arpa/inet.h>
#include "app_l7_protocol.h"

#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

//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

#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 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


/**************************************************************************/
/*                      Message tag                                       */
/**************************************************************************/
#define CHLO 0x43484C4F
#define SHLO 0x53484C4F
#define REJ  0x52454A00
#define PRST 0x50525354


/**************************************************************************/
/*                      Tag                                               */
/**************************************************************************/
#define TAG_PAD  0x50414400
#define TAG_SNI  0x534E4900
#define TAG_VER  0x56455200
#define TAG_CCS  0x43435300
#define TAG_UAID 0x55414944
#define TAG_PDMD 0x50444d44
#define TAG_STK  0x53544b00
#define TAG_SNO  0x534E4F00
#define TAG_PROF 0x50524F46
#define TAG_SCFG 0x53434647
#define TAG_RREJ 0x5252454A
#define TAG_CRT  0x435254FF
#define TAG_AEAD 0x41454144
#define TAG_SCID 0x53434944
#define TAG_PUBS 0x50554253
#define TAG_KEXS 0x4B455853
#define TAG_OBIT 0x4F424954
#define TAG_EXPY 0x45585059
#define TAG_NONC 0x4E4F4E43
#define TAG_MSPC 0x4D535043
#define TAG_TCID 0x54434944
#define TAG_SRBF 0x53524246
#define TAG_ICSL 0x4943534C
#define TAG_SCLS 0x53434C53
#define TAG_COPT 0x434F5054
#define TAG_CCRT 0x43435254
#define TAG_IRTT 0x49525454
#define TAG_CFCW 0x43464357
#define TAG_SFCW 0x53464357
#define TAG_CETV 0x43455456
#define TAG_XLCT 0x584C4354
#define TAG_NONP 0x4E4F4E50
#define TAG_CSCT 0x43534354
#define TAG_CTIM 0x4354494D
#define TAG_MIDS 0x4D494453
#define TAG_FHOL 0x46484F4C
#define TAG_STTL 0x5354544C
#define TAG_SMHL 0x534D484C
#define TAG_TBKP 0x54424B50

/* Public Reset Tag */
#define TAG_RNON 0x524E4F4E
#define TAG_RSEQ 0x52534551
#define TAG_CADR 0x43414452

#define	EXTENSION_SERVER_NAME	0x0000
#define	EXTENSION_SUPPORT_GROUP	0x000A
#define	EXTENSION_APP_PROT_NEGO	0x0010	//application layer protocol negotiation
#define	EXTENSION_SIG_ALGORITHM	0x000D
#define	EXTENSION_KEY_SHARE		0x0033
#define	EXTENSION_PSK_EXCHANGE	0x002D
#define	EXTENSION_SUPP_SSL_VER	0x002B
#define	EXTENSION_QUIC_PARAM	0xFFA5
#define	EXTENSION_COMPRESS_CERT	0x001B

#define	EXT_QUIC_PARAM_MAX_IDLE_TIMEOUT			0x01
#define	EXT_QUIC_PARAM_MAX_UDP_PAYLOAD			0x03
#define	EXT_QUIC_PARAM_MAX_INIT_DATA			0x04
#define	EXT_QUIC_PARAM_MAX_STREAM_BIDI_LOCAL	0x05
#define	EXT_QUIC_PARAM_MAX_STREAM_BIDI_REMOTE	0x06
#define	EXT_QUIC_PARAM_MAX_STREAM_UNI			0x07
#define	EXT_QUIC_PARAM_MAX_STREAMS_BIDI			0x08
#define	EXT_QUIC_PARAM_MAX_STREAMS_UNI			0x09
#define	EXT_QUIC_PARAM_MAX_FRAME_SIZE			0x20
#define	EXT_QUIC_PARAM_INIT_SRC_CONN_ID			0x0F
#define	EXT_QUIC_PARAM_USER_AGENT				0x7129
#define	EXT_QUIC_PARAM_NOT_YET_SUPPORTED		0x712B
#define	EXT_QUIC_PARAM_QUIC_VERSION				0x80004752
#define	EXT_QUIC_PARAM_GREASE_LOW4				0x91D24E9B
#define	EXT_QUIC_PARAM_GREASE_HIGH4				0xEA666DE7

#define	EXTENSION_QUIC_PARAM_UA			0x7129
#define	EXTENSION_QUIC_PARAM_VERSION	0x4752

enum _QUIC_VERSION app_identify_get_quic_protocol(int curdir_is_c2s, const unsigned char *payload, const int payload_len)
{
	enum _QUIC_VERSION quic_version = QUIC_VERSION_UNKNOWN;

	if(payload_len<5)
	{
		return QUIC_VERSION_UNKNOWN;
	}
	
	// Q001~Q043: 0x80 is currently unused, and must be set to 0

	// The most significant bit (0x80) of byte 0 (the first byte) is set to 1 for long headers
	(payload[0] & 0x80) ? (quic_version = (enum _QUIC_VERSION)ntohl(*(unsigned int *)(payload + 1))) : QUIC_VERSION_UNKNOWN;
	if (
	    (quic_version == GQUIC_VERSION_Q099) ||
	    (quic_version == PICOQUIC_VERSION_30) ||
	    (quic_version == PQUIC_VERSION_PROX) ||
	    (quic_version == GQUIC_VERSION_T099) ||
	    (quic_version >= GQUIC_VERSION_Q044 && quic_version <= GQUIC_VERSION_Q050) ||
	    (quic_version >= GQUIC_VERSION_Q051 && quic_version <= GQUIC_VERSION_Q059) ||
	    (quic_version >= GQUIC_VERSION_T048 && quic_version <= GQUIC_VERSION_T049) ||
	    (quic_version >= GQUIC_VERSION_T050 && quic_version <= GQUIC_VERSION_T059) ||
	    (quic_version >= QUANT_VERSION_00 && quic_version <= QUANT_VERSION_FF) ||
	    (quic_version >= QUIC_GO_VERSION_00 && quic_version <= QUIC_GO_VERSION_FF) ||
	    (quic_version >= QUICLY_VERSION_00 && quic_version <= QUICLY_VERSION_FF) ||
	    (quic_version >= MSQUIC_VERSION_00 && quic_version <= MSQUIC_VERSION_0F) ||
	    (quic_version >= MOZQUIC_VERSION_00 && quic_version <= MOZQUIC_VERSION_0F) ||
	    (quic_version >= MVFST_VERSION_00 && quic_version <= MVFST_VERSION_0F) ||
	    (quic_version >= IQUIC_VERSION_I001 && quic_version <= IQUIC_VERSION_I032) ||
	    (quic_version == IQUIC_VERSION_RFC9000))
	{
		return quic_version;
	}

	char public_flags=payload[0];
	int used_len = 1;
	if(curdir_is_c2s==0 && public_flags & GQUIC_PUBLIC_FLAG_VERSION)
	{
		return QUIC_VERSION_UNKNOWN;
	}
	if((!public_flags)&GQUIC_PUBLIC_FLAG_PKT_NUM)
	{
		if(public_flags&GQUIC_PUBLIC_FLAG_VERSION) //Public Reset Packet
		{
			return QUIC_VERSION_UNKNOWN;// todo
		}
		else // Version Negotiation Packet
		{
			return QUIC_VERSION_UNKNOWN;
		}
	}
	if(public_flags&GQUIC_PUBLIC_FLAG_CID)
	{
		used_len+=sizeof(unsigned long long); // CID length
	}
	
	if(payload_len>=(int)(used_len+sizeof(int)) && public_flags&GQUIC_PUBLIC_FLAG_VERSION && (*(unsigned char *)(payload+used_len)==0x51))
	{
		quic_version=(enum _QUIC_VERSION)ntohl(*(unsigned int *)(payload+used_len));
		used_len+=sizeof(int); // skip version
	}
	
	if(quic_version<GQUIC_VERSION_Q001 || quic_version>GQUIC_VERSION_Q043)
	{
		return QUIC_VERSION_UNKNOWN;
	}
	
	return quic_version;
}

