in bpf/include/protocol_analyzer.h [77:153]
static __inline __u32 infer_http2_message(const char* buf, size_t count) {
static const __u8 kFrameBasicSize = 0x9; // including Length, Type, Flags, Reserved, Stream Identity
static const __u8 kFrameTypeHeader = 0x1; // the type of the frame: https://www.rfc-editor.org/rfc/rfc7540.html#section-6.2
static const __u8 kFrameLoopCount = 5;
static const __u8 kStaticTableMaxSize = 61;// https://www.rfc-editor.org/rfc/rfc7541#appendix-A
static const __u8 kStaticTableAuth = 1;
static const __u8 kStaticTableGet = 2;
static const __u8 kStaticTablePost = 3;
static const __u8 kStaticTablePath1 = 4;
static const __u8 kStaticTablePath2 = 5;
// the buffer size must bigger than basic frame size
if (count < kFrameBasicSize) {
return CONNECTION_MESSAGE_TYPE_UNKNOWN;
}
// frame info
__u8 frame[21] = { 0 };
__u32 frameOffset = 0;
// header info
__u8 staticInx, headerBlockFragmentOffset;
// each all frame
#pragma unroll
for (__u8 i = 0; i < kFrameLoopCount; i++) {
if (frameOffset >= count) {
break;
}
// read frame
bpf_probe_read(frame, sizeof(frame), buf + frameOffset);
frameOffset += (bpf_ntohl(*(__u32 *) frame) >> 8) + kFrameBasicSize;
// is header frame
if (frame[3] != kFrameTypeHeader) {
continue;
}
// validate the header(unset): not HTTP2 protocol
// this frame must is a send request
if ((frame[4] & 0xd2) || frame[5] & 0x01) {
return CONNECTION_MESSAGE_TYPE_UNKNOWN;
}
// locate the header block fragment offset
headerBlockFragmentOffset = kFrameBasicSize;
if (frame[4] & 0x20) { // PADDED flag is set
headerBlockFragmentOffset += 1;
}
if (frame[4] & 0x20) { // PRIORITY flag is set
headerBlockFragmentOffset += 5;
}
#pragma unroll
for (__u8 j = 0; j <= kStaticTablePath2; j++) {
if (headerBlockFragmentOffset > count) {
return CONNECTION_MESSAGE_TYPE_UNKNOWN;
}
staticInx = frame[headerBlockFragmentOffset] & 0x7f;
if (staticInx <= kStaticTableMaxSize && staticInx > 0) {
if (staticInx == kStaticTableAuth ||
staticInx == kStaticTableGet ||
staticInx == kStaticTablePost ||
staticInx == kStaticTablePath1 ||
staticInx == kStaticTablePath2) {
return CONNECTION_MESSAGE_TYPE_REQUEST;
} else {
return CONNECTION_MESSAGE_TYPE_RESPONSE;
}
}
headerBlockFragmentOffset++;
}
}
return CONNECTION_MESSAGE_TYPE_UNKNOWN;
}