2014-10-15 11 views
5

czytałem jakiś przykład fragment kodu dla modułu Net::Pcap::Easy, i natknąłem się na ten kawałek koduPerl bitowe AND i bitowe przesunięcie

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

Po wykonaniu całkowitą hex zrzut surowych pakietów $ raw_bytes, ja widać, że jest to ramka ethernetowa, a nie pakiet TCP/UDP. Czy ktoś może wyjaśnić, co robi powyższy kod?

Odpowiedz

7

Podczas analizy ramki, przejrzałem this page.

teraz na Perl ...

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

Ekstrakt 15. bajcie (znaku) ze $raw_bytes i konwersji do jego wartości porządkowej (np postaci „A” powinno być przekształcony w całkowitej 65 (0x41), zakładając, że zestaw znaków to ASCII). W ten sposób Perl może przetwarzać dane binarne tak, jakby były ciągiem znaków (np. Przekazywać je do substr), ale potem pozwala wycofać wartości binarne i obsłużyć je jako liczby. (Ale pamiętaj o TMTOWTDI.)

W ramce IPv4 pierwsze 14 bajtów to nagłówek MAC (6 bajtów każdy dla docelowego i źródłowego adresu MAC, a następnie 2-bajtowy Ethertype, który prawdopodobnie był 0x8000 - mogłeś to sprawdzić). Po tym, 15 bajt jest początkiem ładunku danych Ethernet: pierwszy bajt zawiera wersję (4 górne bajty) i długość nagłówka w DWORD (4 bajty niższe).

Teraz wygląda na to, że w następnym wierszu tego przykładowego kodu jest błąd, ale normalnie może działać fluke!

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

W Perl >> ma wyższy priorytet niż &, więc będzie to równoznaczne z

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

lub jeśli wolisz

my $l3prot = $l3protlen & 0x3c; 

Więc ten wydobywa bity 2 - 5 Z $l3prot wartość: wartość maski 0x3c wynosi 0011 1100 w binarnym. Na przykład wartość 0x86 (w binarnym, 1000 0110) będzie wynosić 0x04 (binarny 0000 0100). W rzeczywistości "normalna" wartość IPv4 to 0x45, tj. Protokół typu 4, długość nagłówka 5 dwordów. Maskuj to za pomocą 0x3c, a otrzymasz ... 4! Ale tylko przez Fuksa: przetestowałeś 2 pierwsze bity długości, a nie typ protokołu!

Linia ta powinna być na pewno

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

(wsporniki note dla pierwszeństwa i przesunięcie 4 bity, a nie 2). (Uważam, że ten sam błąd w CPAN documentation więc myślę, że to prawdopodobnie dość szeroko rozpowszechniony.)

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

Dla IPv4 oczekujemy wartość ta będzie 4 - jeśli tak nie jest, wyskoczyć z funkcji od razu. (Tak zły kod powyżej daje wynik, który pozwala to być interpretowane jako pakiet IPv4, ale tylko dzięki szczęściu.)

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

Teraz wyodrębnić 24 bajtów i konwertować do wartości porządkowej w ten sam sposób.Jest to bajt Protokół z nagłówka IP:

return unless $l4prot == '7'; 

Oczekujemy, że jest to 7 - jeśli nie jest wyskoczyć z funkcji od razu. (Zgodnie z IANA, 7 to "drzewa bazowe" ... ale domyślam się, że znasz protokoły, którymi jesteś zainteresowany!)

+0

Bardzo dobrze wyjaśniony. Tak, szukałem specjalnie dla udp, więc 7. – nohup

+1

@nohup - Dzięki! ale UDP ma 17, a nie 7 ... Czy próbowałeś tego z moją sugerowaną poprawką do linii '' & 0xf0'? – AAT

+0

Doskonałe i dobrze wyjaśnione. Dobra robota dostrzegając te błędy –