仅感知 Initial、Handshake QUIC部分协议,通常感知两者就知道是否在通过 QUIC协议载荷流量,然后该阻断的阻断,该警告的警告。
C++
inline Byte GetBitValueAt(Byte b, Byte offset, Byte length) {
return (Byte)((b >> offset) & ~(0xff << length));
}
inline Byte GetBitValueAt(Byte b, Byte offset) {
return GetBitValueAt(b, offset, 1);
}
inline Byte SetBitValueAt(Byte b, Byte offset, Byte length, Byte value) {
int mask = ~(0xff << length);
value = (Byte)(value & mask);
return (Byte)((value << offset) | (b & ~(mask << offset)));
}
inline Byte SetBitValueAt(Byte b, Byte offset, Byte value) {
return SetBitValueAt(b, offset, 1, value);
}
inline bool PacketIsQUIC(const IPEndPoint& destinationEP, Byte* p, int length) {
if (NULL == p || length < 1) {
return false;
}
if (destinationEP.Port != 443 && destinationEP.Port != 80) {
return false;
}
Byte* l = p + length; // QUIC IETF
Byte kf = *p++;
int F_Header_Form = GetBitValueAt(kf, 7);
int F_Fixed_Bit = GetBitValueAt(kf, 6);
int F_Packet_Type_Bit = GetBitValueAt(kf, 5) << 1 | GetBitValueAt(kf, 4);
if (F_Header_Form != 0x01 || F_Fixed_Bit != 0x01) {
return false;
}
if (F_Packet_Type_Bit == 0x00) { // Initial(0)
int F_Reserved_Bit = GetBitValueAt(kf, 3) << 1 | GetBitValueAt(kf, 3);
int F_Packet_Number_Length_Bit = GetBitValueAt(kf, 1) << 1 | GetBitValueAt(kf, 0);
if (F_Packet_Number_Length_Bit == 0x00 && F_Reserved_Bit == 0x00) {
return false;
}
}
else if (F_Packet_Type_Bit != 0x02) { // Handshake(2)
return false;
}
p += 0x04;
if (p > l) {
return false;
}
UInt32 Version = ntohl(((UInt32*)p)[-1]);
if (Version != 0x01) { // Version
return false;
}
int Destination_Connection_ID_Length = *p++;
p += Destination_Connection_ID_Length;
if (p > l || Destination_Connection_ID_Length < 0x01) {
return false;
}
int Source_Connection_ID_Length = *p++;
p += Source_Connection_ID_Length;
if (p > l) {
return false;
}
if (F_Packet_Type_Bit == 0x00) { // Initial(0)
int Token_Length = *p++;
p += Token_Length;
if (p > l || Token_Length < 0x01)
{
return false;
}
}
int Packet_Length = ntohs(*(UInt16*)p) & 0x3FFF;
p += 0x02;
if (p > l || Packet_Length < 0x01) {
return false;
}
p += Packet_Length;
return p == l;
}
C#
[SecurityCritical]
[SecuritySafeCritical]
public unsafe static bool PacketIsQUIC(IPEndPoint destinationEP, BufferSegment messages)
{
if (destinationEP == null || messages == null || messages.Length < 1)
{
return false;
}
if (destinationEP.Port != 443 && destinationEP.Port != 80)
{
return false;
}
try
{
fixed (byte* pinned = messages.Buffer) // QUIC IETF
{
byte* p = pinned + messages.Offset;
byte* l = p + messages.Length;
byte kf = *p++;
int F_Header_Form = Extension.GetBitValueAt(kf, 7);
int F_Fixed_Bit = Extension.GetBitValueAt(kf, 6);
int F_Packet_Type_Bit = Extension.GetBitValueAt(kf, 5) << 1 | Extension.GetBitValueAt(kf, 4);
if (F_Header_Form != 0x01 || F_Fixed_Bit != 0x01)
{
return false;
}
if (F_Packet_Type_Bit == 0x00) // Initial(0)
{
int F_Reserved_Bit = Extension.GetBitValueAt(kf, 3) << 1 | Extension.GetBitValueAt(kf, 3);
int F_Packet_Number_Length_Bit = Extension.GetBitValueAt(kf, 1) << 1 | Extension.GetBitValueAt(kf, 0);
if (F_Packet_Number_Length_Bit == 0x00 && F_Reserved_Bit == 0x00)
{
return false;
}
}
else if (F_Packet_Type_Bit != 0x02) // Handshake(2)
{
return false;
}
p += 0x04;
if (p > l)
{
return false;
}
uint Version = CheckSum.ntohl(((uint*)p)[-1]);
if (Version != 0x01) // Version
{
return false;
}
int Destination_Connection_ID_Length = *p++;
p += Destination_Connection_ID_Length;
if (p > l || Destination_Connection_ID_Length < 0x01)
{
return false;
}
int Source_Connection_ID_Length = *p++;
p += Source_Connection_ID_Length;
if (p > l)
{
return false;
}
if (F_Packet_Type_Bit == 0x00) // Initial(0)
{
int Token_Length = *p++;
p += Token_Length;
if (p > l || Token_Length < 0x01)
{
return false;
}
}
int Packet_Length = CheckSum.ntohs(*(ushort*)p) & 0x3FFF;
p += 0x02;
if (p > l || Packet_Length < 0x01)
{
return false;
}
p += Packet_Length;
return p == l;
}
}
catch (Exception)
{
return false;
}
}