Cách đăng ký bộ phân tích giao thức trong Wireshark: Hàm proto_register

Trong kiến trúc mở rộng của Wireshark, việc đăng ký bộ phân tích (dissector) là bước thiết yếu để tích hợp hỗ trợ cho giao thức tùy chỉnh. Quá trình này không chỉ khai báo thông tin giao thức mà còn thiết lập cấu trúc hiển thị, định nghĩa trường dữ liệu và liên kết logic xử lý gói tin — tất cả đều xoay quanh nhóm hàm proto_register_*.

Khởi tạo giao thức với proto_register_protocol

Hàm nền tảng đầu tiên là proto_register_protocol(), được gọi trong hàm khởi tạo cụ thể như proto_register_dns() hoặc proto_register_mqtt(). Hàm này trả về một giá trị nguyên duy nhất — gọi là protocol identifier — dùng làm khóa tham chiếu xuyên suốt toàn bộ chuỗi đăng ký.

int proto_dns = -1;

void proto_register_dns(void) {
    proto_dns = proto_register_protocol(
        "Domain Name System",  // Tên đầy đủ
        "DNS",                 // Tên viết tắt hiển thị trong UI
        "dns"                  // Tên bộ lọc (filter name)
    );
}

Giá trị trả về phải được lưu vào biến toàn cục có phạm vi file để sử dụng ở các bước tiếp theo. Nếu hàm trả về giá trị âm, quá trình đăng ký thất bại — thường do xung đột tên hoặc thiếu tài nguyên.

Định nghĩa và đăng ký trường dữ liệu

Mỗi giao thức cần mô tả chi tiết các thành phần bên trong gói tin (header fields), ví dụ như "Query Type", "Response Code", hay "Transaction ID". Các trường này được khai báo tĩnh trong mảng kiểu hf_register_info:

static hf_register_info field_definitions[] = {
    { &hf_dns_query_type,
      { "Query Type", "dns.qry.type",
        FT_UINT16, BASE_DEC, VALS(dns_qtype_vals), 0x0,
        "Type of DNS query", HFILL }
    },
    { &hf_dns_response_code,
      { "Response Code", "dns.flags.rcode",
        FT_UINT8, BASE_DEC, VALS(dns_rcode_vals), 0xC0,
        "DNS response status", HFILL }
    }
};

Sau khi khai báo, mảng được truyền vào hàm đăng ký:

proto_register_field_array(proto_dns, field_definitions, G_N_ELEMENTS(field_definitions));

Lưu ý rằng mỗi trường phải gắn với một biến toàn cục (ví dụ hf_dns_query_type) để đảm bảo ánh xạ đúng giữa dữ liệu nhị phân và biểu diễn người dùng.

Thiết lập cây phân tích (protocol tree)

Wireshark hiển thị kết quả phân tích dưới dạng cây phân cấp. Mỗi nút con đại diện cho một lớp logic (ví dụ: "DNS Header", "Question Section"). Việc khai báo các nút này sử dụng mảng con trỏ kiểu gint*:

static gint ett_dns = -1;
static gint ett_dns_question = -1;
static gint ett_dns_answer = -1;

static gint *subtree_ids[] = {
    &ett_dns,
    &ett_dns_question,
    &ett_dns_answer
};

Hàm đăng ký tương ứng là:

proto_register_subtree_array(subtree_ids, G_N_ELEMENTS(subtree_ids));

Các giá trị ett_* sẽ được khởi tạo tự động bởi hệ thống và sau đó được dùng trong hàm phân tích chính để thêm nhánh vào cây hiện tại.

Liên kết bộ phân tích với luồng mạng

Giai đoạn cuối cùng — gọi là handoff — xác định cách Wireshark kích hoạt bộ phân tích khi gặp gói tin phù hợp. Đây là nơi gắn bộ phân tích với bảng phân giải (dissector table), chẳng hạn như "tcp.port", "udp.port", hoặc "ip.proto".

void proto_reg_handoff_dns(void) {
    static dissector_handle_t dns_handle = NULL;

    if (!dns_handle) {
        dns_handle = create_dissector_handle(dissect_dns, proto_dns);
    }

    dissector_add_uint("udp.port", 53, dns_handle);
    dissector_add_uint("tcp.port", 53, dns_handle);
}

Với các giao thức không có cổng cố định (như SSDP hay mDNS), ta dùng cơ chế heuristic:

heur_dissector_add("udp", dissect_dns_heuristic, proto_dns);

Hàm dissect_dns_heuristic() phải kiểm tra nội dung gói và trả về TRUE nếu xác định được giao thức — điều này cho phép nhiều bộ phân tích cạnh tranh trên cùng một cổng.

Tổng quan luồng thực thi

Toàn bộ quy trình đăng ký tuân theo thứ tự nghiêm ngặt:

  1. Gọi proto_register_protocol() → nhận proto_id
  2. Khai báo và đăng ký mảng hf_register_info → tạo metadata trường
  3. Khai báo và đăng ký mảng ett_* → xây dựng cấu trúc cây
  4. Gọi proto_reg_handoff_* → gắn bộ phân tích vào bảng phân giải hoặc heuristic chain

Bất kỳ sai sót nào trong thứ tự hoặc thiếu bước nào đều dẫn đến lỗi runtime hoặc không hiển thị dữ liệu phân tích.

Chuẩn bị môi trường phát triển

Wireshark cung cấp khuôn mẫu chuẩn trong thư mục doc/packet-TEMPLATE.c, bao gồm skeleton đầy đủ cho hàm đăng ký, handoff và hàm phân tích mẫu. Ngoài ra, tài liệu doc/README.dissectordoc/README.heuristic mô tả chi tiết ngữ nghĩa từng tham số và best practice xử lý bộ nhớ (sử dụng wmem thay vì malloc).

Thẻ: wireshark C dissector protocol-analysis packet-parsing

Đăng vào ngày 20 tháng 6 lúc 06:07