2014-10-15 5 views
5

Я читал некоторый пример фрагмента кода для модуля Net::Pcap::Easy, и я наткнулся на этот кусок кодаPerl побитового И и побитовое смещение

my $l3protlen = ord substr $raw_bytes, 14, 1; 
my $l3prot = $l3protlen & 0xf0 >> 2; # the protocol part 
return unless $l3prot == 4; # return unless IPv4 
my $l4prot = ord substr $packet, 23, 1; 
return unless $l4prot == '7'; 

После выполнения полного дампа необработанного пакетов $ raw_bytes, я может видеть, что это кадр ethernet, а не пакет TCP/UDP. Может кто-нибудь объяснить, что делает этот код?

ответ

7

Для разбора рамы я поднял голову this page.

Теперь на Perl ...

my $l3protlen = ord substr $raw_bytes, 14, 1; 

Извлечение 15 байт (символов) с $raw_bytes, и преобразовать его порядкового значения (например, символ «A» будет преобразовано в целое число 65 (0x41), предполагая, что набор символов - ASCII). Так Perl может обрабатывать двоичные данные, как если бы они были строкой (например, передавали ее substr), но затем вы можете вернуть двоичные значения и обрабатывать их как числа. (Но помните TMTOWTDI.)

В кадре IPv4 первые 14 байтов представляют собой заголовок MAC (по 6 байт для адресата и MAC-адреса источника, а затем 2-байтовый Ethertype, который, вероятно, 0x8000 - вы могли бы проверить это). После этого 15-й байт является началом полезной нагрузки данных Ethernet: первый байт содержит версию (верхние 4 байта) и длину заголовка в DWORD (более низкие 4 байта).

Теперь мне кажется, что в следующей строке этого примера кода есть ошибка, но, возможно, это нормально работает на случайности!

my $l3prot = $l3protlen & 0xf0 >> 2; # the protocol part 

В Perl >> имеет более высокий приоритет, чем &, так что это будет эквивалентно

my $l3prot = $l3protlen & (0xf0 >> 2); 

или, если вы предпочитаете

my $l3prot = $l3protlen & 0x3c; 

Итак, извлекает биты 2 - 5 из $l3prot Значение: значение маски 0x3c равно 0011 1100 в двоичном формате. Так, например, значение 0x86 (в двоичном выражении, 1000 0110) станет 0x04 (двоичное 0000 0100). Фактически, «нормальное» значение IPv4 равно 0x45, то есть тип протокола 4, длина заголовка 5 слов. Маска, которая с 0x3c и вы получите ... 4! Но только от fluke: вы проверили верхние 2 бита длины, а не тип протокола!

Эта линия должна быть, конечно,

my $l3prot = ($l3protlen & 0xf0) >> 4; 

(примечание кронштейны для старшинства и сдвиг 4 бита, а не 2). (Я нашел эту же ошибку в CPAN documentation, так что я предполагаю, что это, вероятно, довольно широко распространено.)

return unless $l3prot == 4; # return unless IPv4 

Для IPv4, мы ожидаем, что это значение будет 4 - если это не так, выскочить из функции сразу. (Таким образом, неверный код выше, дает результат, который позволяет это можно интерпретировать как пакеты IPv4, но только по счастливой случайности.)

my $l4prot = ord substr $packet, 23, 1; 

Теперь извлечь 24-й байт и преобразовать в значение порядкового таким же образом.Это протокол байт из заголовка IP:

return unless $l4prot == '7'; 

Мы ожидаем, что это будет 7 - если он не выскочит из функции сразу. (Согласно IANA, 7 - «Основы на основе ядра» ... но я думаю, вы знаете, какие протоколы вам интересны!)

+0

Очень хорошо объяснено. Да, я смотрел специально для udp, поэтому 7. – nohup

+1

@nohup - Спасибо! но UDP - 17, а не 7 ... Также вы пробовали это с моей предложенной коррекцией к строке '' & 0xf0'? – AAT

+0

Отлично и хорошо объяснено. Хорошая работа, определяющая эти ошибки –

 Смежные вопросы

  • Нет связанных вопросов^_^