Как узнать длину HTTP-заголовка пакета?
Я знаю, как сделать это вручную (глядя на шестнадцатеричный дамп). Как я могу получить то же самое автоматически? Нужно ли использовать API? У меня есть и wireshark, и сетевой монитор Microsoft.
4 ответа
Это может быть достигнуто просто с помощью диссектора Lua, который добавляет поле заголовка HTTP к дереву пакетов, позволяя фильтровать его, как показано на этом снимке экрана:
Скопируйте этот скрипт Lua в каталог плагинов (например, ${WIRESHARK_HOME}/plugins/1.4.6/http_extra.lua
) и перезапустите Wireshark (если он уже запущен).
do
local http_wrapper_proto = Proto("http_extra", "Extra analysis of the HTTP protocol");
http_wrapper_proto.fields.hdr_len = ProtoField.uint32("http.hdr_len", "Header length (bytes)")
-- HTTP frames that contain a header usually include the HTTP
-- request method or HTTP response code, so declare those here
-- so we can check for them later in the dissector.
local f_req_meth = Field.new("http.request.method")
local f_resp_code = Field.new("http.response.code")
local original_http_dissector
function http_wrapper_proto.dissector(tvbuffer, pinfo, treeitem)
-- We've replaced the original http dissector in the dissector table,
-- but we still want the original to run, especially because we need
-- to read its data. Let's wrap the call in a pcall in order to catch
-- any unhandled exceptions. We'll ignore those errors.
pcall(
function()
original_http_dissector:call(tvbuffer, pinfo, treeitem)
end
)
-- if the request method or response code is present,
-- the header must be in this frame
if f_req_meth() or f_resp_code() then
-- find the position of the header terminator (two new lines),
-- which indicates the length of the HTTP header, and then add
-- the field to the tree (allowing us to filter for it)
local hdr_str = tvbuffer():string()
local hdr_len = string.find(hdr_str, "\r\n\r\n") or string.find(hdr_str, "\n\n\n\n")
if hdr_len ~= nil then
treeitem:add(http_wrapper_proto.fields.hdr_len, hdr_len):set_generated()
end
end
end
local tcp_dissector_table = DissectorTable.get("tcp.port")
original_http_dissector = tcp_dissector_table:get_dissector(80) -- save the original dissector so we can still get to it
tcp_dissector_table:add(80, http_wrapper_proto) -- and take its place in the dissector table
end
Код, опубликованный пользователем 568493, вообще не работал для меня, поэтому я изменил его на почтовый диссектор, а также не правильно подсчитал количество байтов. Он также считал байты IP и Ethernet.
Это моя версия, которая работает на 1.8.2:
local http_wrapper_proto = Proto("http_extra", "Extra analysis of the HTTP protocol");
http_wrapper_proto.fields.hdr_len = ProtoField.uint32("http.hdr_len", "HTTP Header length (bytes)")
-- HTTP frames that contain a header usually include the HTTP
-- request method or HTTP response code, so declare those here
-- so we can check for them later in the dissector.
local f_req_meth = Field.new("http.request.method")
local f_resp_code = Field.new("http.response.code")
local original_http_dissector
function http_wrapper_proto.dissector(tvbuffer, pinfo, treeitem)
-- if the request method or response code is present,
-- the header must be in this frame
if f_req_meth() or f_resp_code() then
local start_offset = 0
local end_offset = 0
-- find the position of the header terminator (two new lines),
-- which indicates the length of the HTTP header, and then add
-- the field to the tree (allowing us to filter for it)
local hdr_str = tvbuffer():string()
if f_req_meth() then
start_offset = string.find(hdr_str, "GET")
end_offset = string.find(hdr_str, "\r\n\r\n")
end
if f_resp_code() then
start_offset = string.find(hdr_str, "HTTP")
end_offset = string.find(hdr_str, "\r\n\r\n")
end
local hdr_len = end_offset - start_offset + 4
-- 4 Bytes because the \r\n\r\n are not part of the HTTP Payload, hence should be counted in the header length.
if hdr_len ~= nil then
treeitem:add(http_wrapper_proto.fields.hdr_len, hdr_len):set_generated()
end
end
end
register_postdissector(http_wrapper_proto)
К сожалению, хотя вы можете создавать пользовательские столбцы, данные, которые вы хотите в этом столбце, в настоящее время не генерируются декодером протокола HTTP. Конечно, могут быть другие инструменты, с которыми я не знаком, которые могут сделать это сегодня, но что касается Wireshark, вам придется добавить эту функциональность.
Есть несколько хороших ресурсов по созданию плагинов Wireshark, например:
http://simeonpilgrim.com/blog/2008/04/29/how-to-build-a-wireshark-plug-in/
http://www.wireshark.org/docs/wsdg_html_chunked/ChDissectAdd.html
http://www.codeproject.com/KB/IP/custom_dissector.aspx
А вот видео, описывающее, как добавить поле, отображаемое декодером протокола, в качестве пользовательского столбца:
http://www.youtube.com/watch?v=XpUNXDkfkQg
Дело в том, что вы не хотите повторно реализовывать декодер протокола HTTP.
Что я хотел бы сделать, это найти исходный код для встроенного HTTP-декодера и посмотреть на добавление нового поля, такого как http.header_length
так же, как существующие http.content_length
:
Я не смотрел на код, но думаю, что это довольно легко добавить. Если вы отправите патч в команду Wireshark, он, вероятно, также включит ваше новое поле в следующую версию.
Я обнаружил, что этот способ вызова предыдущего диссектора в цепочке каким-то образом мешает повторной сборке HTTP-пакета, выполненного для кодирования передачи по частям. То есть, если ваш ответ имеет заголовок "Transfer-Encoding: chunked", исходный диссектор HTTP пытается пересобрать данные, и если вы подключите его с помощью такого http_wrapper, то повторная сборка завершится неудачно.
Например, это также приводит к сбою статистики http. Статистика /HTTP/ Счетчик пакетов даст вам, скажем, 6 запросов и 4 ответа, что не так =)
Лучше установить такого рода диссекторы с "добавленной стоимостью" с помощью вызова API "register_postdissector" или тщательно проверить тест на повторную сборку логики.