Реконструкция HTTP-пакета

Если у меня есть большой HTTP-пакет, разделенный на несколько TCP-пакетов, как я могу преобразовать их обратно в один HTTP-пакет? По сути, где в пакете я могу узнать, когда HTTP-пакет начинается/заканчивается? Кажется, я не вижу никаких флагов/полей в заголовке TCP, которые обозначают начало или конец HTTP-пакета.

EDIT: В ответ на ответы. Если TCP управляет потоком, как он узнает, когда поток начинается и заканчивается? Это определяется открытием и закрытием сокета? Какой-то протокол на каком-то уровне должен знать, когда поток/пакет HTTP начался и закончился. Вот что я хотел бы знать.

Ситуация, в которой я нахожусь, заключается в том, что я использую анализатор пакетов на С#, который читает TCP-пакеты, и я хотел бы иметь возможность реконструировать HTTP-запросы/ответы/и т. д. прохождение через интерфейс, подобное тому, как это удается wireshark и другим снифферам. В качестве альтернативы существуют ли какие-либо библиотеки C #, которые позволяют вам подключаться к потокам HTTP на более высоком уровне, избавляя меня от необходимости самостоятельно восстанавливать поток/пакеты HTTP?

Спасибо.


person mike    schedule 07.10.2009    source источник


Ответы (6)


ОК, я придумал, как это сделать (хитрый, но он выполняет свою работу).

Легко удалить заголовки Ethernet, IP и TCP, оставив вам сообщение с «сырыми» данными. Заглянув внутрь сообщения, легко определить, является ли оно началом HTTP-пакета, ища "HTTP/1.1..." в начале пакета. Это указывает на то, что пакет является началом потока HTTP/более крупного пакета/чего-либо. Вы также можете выполнить простой синтаксический анализ, чтобы прочитать поле Content-Length, которое представляет собой общую длину всего HTTP-пакета.

Вы также можете использовать IP-адрес и номер порта источника/назначения для формирования уникального идентификатора ссылки. Итак, после получения пакета заголовка обратите внимание на эти 4 вещи (SRCIP, SRCPORT, DESTIP, DESTPORT). В следующий раз, когда вы получите пакет, соответствующий этой комбинации порт/IP, вы можете проверить, является ли он следующей частью HTTP-пакета. Вы можете использовать порядковые номера для некоторой проверки и, возможно, других вещей, но обычно пакеты идут по порядку, так что все в порядке. Я думаю, что новый порт открывается для каждого потока HTTP, поэтому вы не должны получать случайные пакеты, которые не являются частью потока, но это может быть областью, подверженной ошибкам.

В любом случае, как только вы получили этот пакет, еще раз удалите заголовки и получите необработанное сообщение. Добавьте его к уже известной части сообщения. Если длина всего полученного сообщения равна длине, считанной из поля «Content-Length», пакет считается завершенным!

Этот метод, очевидно, подвержен огромному количеству ошибок, но мне не нужен чрезвычайно надежный способ сделать это. Я думал, что отвечу на свой вопрос, если кто-то еще столкнется с этой же проблемой в будущем! Удачи в нюхании :D

person mike    schedule 08.10.2009
comment
Если поле Content-Length не указано, существуют и другие способы определения длины. например http://www.httpwatch.com/httpgallery/chunked/ - person mike; 09.10.2009
comment
Может быть немного поздно, но заголовок Content-Length НЕ указывает общую длину пакета. Он просто указывает размер содержимого, то есть тела, которое идет после заголовков. Заголовки и тело разделены \r\n\r\n. - person Swen Kooij; 07.12.2013

Вы не должны использовать какую-либо информацию с уровня TCP для определения границ HTTP-запросов. TCP обеспечивает надежную службу потока байтов; вы не можете увидеть какие-либо поля или флаги в TCP, которые помогают в этом, потому что их там нет.

Чтобы определить, где находятся границы в HTTP-запросе, вы должны следовать RFC 2616. Границы четко определены, и вы можете определить их, анализируя полученные данные.

person janm    schedule 07.10.2009

В каждом TCP-пакете данные полезной нагрузки начинаются сразу после заголовка TCP, а конец данных полезной нагрузки совпадает с концом IP-пакета.

Конец заголовка TCP легко найти — Data Offset — это 4-битное поле в заголовке, которое содержит длину заголовка в 32-битных словах (поэтому умножьте его на 4, чтобы получить длину в 8-битных байтах).

Используйте порядковые номера TCP из поля Sequence, чтобы объединить полезные данные в правильном порядке. Обратите внимание, что в случае повторной передачи могут быть дубликаты.

person caf    schedule 07.10.2009

TCP – это протокол потока, а не пакетного протокола. Прикладной уровень (то есть вы) получает поток данных, а не кучу пакетов. Вы просто продолжаете считывать байты из потока, и вы получите всю полезную нагрузку http, в то время как TCP выполняет проверку ошибок, повторную отправку и т. Д. Ниже.

person Roatin Marth    schedule 07.10.2009

Вы можете использовать код проекта с открытым исходным кодом под названием Xplico: http://www.xplico.org

person Antony    schedule 23.06.2010

Пришлось работать над решением той же проблемы. Мы смогли извлечь некоторые основные функции из проекта с открытым исходным кодом.

http://code.google.com/p/pcap-reconst/

Пожалуйста, проверьте это и дайте мне знать, если это поможет вам.

person Community    schedule 12.11.2009
comment
Я заинтересован в использовании вашего кода. Без необходимости слишком глубоко копаться в исходном коде, обрабатывает ли ваш проект: а) распаковку сжатых данных на основе заголовка Content-Encoding, б) преобразование в общую текстовую кодировку на основе charset в заголовке Content-Type и в) работу с фрагментированным кодированием, когда Заголовок Transfer-Encoding установлен на chunked? - person Bryce Thomas; 17.01.2012