static __inline __u32 infer_http2_message()

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;
}