Фільтри захоплення для мережевих аналізаторів (tcpdump, Wireshark, Paketyzer), навчальний посібник
1. Фільтри захоплення
Аналізатори трафіку є корисним і ефективним інструментом у житті адміністратора мережі, вони дозволяють «побачити» те, що насправді передається в мережі, чим спрощують діагностику різноманітних проблем або вивчення принципів роботи тих чи інших протоколів та технологій. Однак у мережі часто передається досить багато різноманітних блоків даних, і якщо змусити вивести на екран все, що проходить через мережевий інтерфейс, виділити те, що дійсно потрібно, буває проблематично. Для вирішення цієї проблеми в аналізаторах трафіку реалізовано фільтри, які розділені на два типи: фільтри захвату та фільтри відображення. Сьогодні йтиметься про перший тип фільтрів — про фільтри захоплення. Фільтри захоплення, це різновид фільтрів, що дозволяє обмежити захоплення кадрів тільки тими, які необхідні для аналізу, зменшивши таким чином навантаження на обчислювальні ресурси комп'ютера, а також спростивши процес аналізу трафіку.
2. Синтаксис фільтрів захоплення
Вираз фільтра захоплення складається з набору спеціальних примітивів, які будуються із так званих класифікаторів та ідентифікаторів об'єкта (адреси, імена об'єктів мережі, номери портів).
Увага: всі класифікатори реєстрозалежні і повинні писати лише маленькими літерами.
Давайте розберемося з ними докладніше. Класифікатори можуть бути наступними різновидами:
— type – тип об'єкту
host – вузол (тип за замовчуванням, якщо тип не заданий, передбачається що це host) net – мережа port – порт
Наприклад: host 192.168.0.1 — захоплення трафіку в якому як адреса (відправника або одержувача) стоїть IP 192.168.0.1net 172.16.0.0/16 — захоплення трафіку в якому як адреса (відправника або одержувача) стоїть IP з мережі 172.16.0. /16 (точніше знаходиться в діапазоні від 172.16.0.0 до 172.16.255.255), при цьому, так як це всього лише фільтр пошуку збігаються адрес, абсолютно не важливо яка налаштована маска на інтерфейсі, і вас не повинно бентежити що 172.16.0.0 по масці /16 це номер мережі, ми абсолютно не знаємо яка маска налаштована на інтерфейсі, і формально, така адреса вузла допустимо. Як адреса (відправника або одержувача) стоїть IP 10.0.0.1, класифікатор host не вказаний, але він передбачається за умовчанням.
— dir — напрям по відношенню до об'єкта (direction)
src – об'єкт є відправником dst – об'єкт є одержувачем
-
Наприклад: src host 192.168.0.1 – захоплення трафіку в якому як адреса відправника (не одержувача) стоїть IP 192.168.0.1dst net 172.16.0.0/16 – захоплення трафіку в якому як адреса одержувача (не відправника) стоїть IP з мережі 172.16 .0.0/16 (точніше знаходиться в діапазоні від 172.16.0.0 до 172.16.255.255).
— proto – протокол взаємодії
ether – базова мережева технологія Ethernet, як правило вказує на те, що у фільтрі використовується апаратний MAC адресip – протокол IPv4ip6 – протокол IPv6arp – протокол ARPtcp – протокол TCPudp – протокол UDP якщо протокол не вказаний, то вважається що повинен захоплюватися весь трафік, сумісний з типом об'єкта
Наприклад: src ether host 00:11:22:33:44:55 – захоплення трафіку в якому як MAC адреса відправника використовується 00:11:22:33:44:55.ip icmp – захоплення ICMP пакетів.tcp port 80 – захоплення трафіку в якому є дані, що належать TCP порту 80
Крім ідентифікаторів і класифікаторів об'єкта фільтри можуть містити ключові слова gateway, broadcast, multicast, less, greater, а також арифметичні вирази.
Наприклад: ip multicast – захоплення ip пакетів, що містять адреси класу D.less 1000 – захоплення кадрів, які мають розмір менше 1000 байт.
Зв'язування кількох умов може відбуватися за допомогою логічних операцій:
— "І" — and (&&)
— «АБО» — or (||)
— «НЕ» – not (!) – інверсія значення
При цьому пріоритет цих операцій є наступним:
— найвищий пріоритет має операція інверсії
— потім логічне «І»
— Найменший пріоритет має операція «АБО».
Як і звичайних математичних висловлюваннях, пріоритет можна змінювати з допомогою круглих дужок (), дії у яких виконуються насамперед.
Наприклад: net 192.168.0.0/24 and tcp port 21 — захоплення трафіку належить мережі (діапазону) 192.168.0.0/24 (або відправник або одержувач) і передає дані протоколу TCP і використовує порт 21.host 192.168.1.2. 0.221 — захоплення трафіку що належить або хосту 192.168.0.1 або хосту 192.168.0.221 (при чому не важливо хто відправник, хто одержувач і так само достатньо виконання одна з двох умов, щоб хоча б один з цих адрес був присутній у кадрі) host 192.168. 0.1 or host 192.168.0.2 and tcp port 22 — захоплення або будь-якого трафіку, що належить хосту 192.168.0.1 або трафіку протоколу TCP і використовує порт 22, що належить хосту 192.168.0.2. cp port 22 – захоплення трафіку протоколу TCP і використовує порт 22 що належить хосту 192.168.0.1 або хосту 192.168.0.2 (будь-якому з них, або обом відразу).(host 192.168.0.1 || трафіку протоколу TCP і використовує порт 22 що належить хосту 192.168.0.1 або хосту 192.168.0.2 (будь-якому з них, або обом відразу).
Якщо у фільтрі є кілька однакових класифікаторів, що повторюються, то для скорочення запису їх можна не писати.
Наприклад:net 192.168.0.0/24 and (tcp port 21 or tcp port 20 or tcp port 25 or tcp port 80 or tcp port 110) можна скоротити до net 192.168.0.0/22 or 2 110)
Увага: Вираз виключає пакети, в яких є адреси 1.1.1.1 та 1.1.1.2:not (host 1.1.1.1 and host 1.1.1.2) Можна скоротити як:not (host 1.1.1.1 and 1.1.1.2) Але не як:not host 1.1.1.1 and 1.1.1.2 – у цьому випадку будуть показані пакети в яких немає першої адреси та є другою. І не такnot (host 1.1.1.1 or 1.1.1.2) — у цьому випадку будуть виключені пакети в яких є хоча б одна із зазначених двох адрес.
Список основних примітивів, які можна використовувати для написання фільтрів захоплення, показаний у таблиці 2-1. Таблиця 2-1. Список основних примітивів, які можна використовувати для написання фільтрів захоплення.
Примітив
Опис
dst host ip_address
Захоплювати кадри, у яких у полі адреси одержувача заголовка IPv4/IPv6 містить задану адресу вузла
src host ip_address
Захоплювати кадри, у яких у полі адреси відправника заголовка IPv4/IPv6 містить задану адресу вузла
host ip_address
Захоплювати кадри, у яких у полі адреси відправника чи одержувача заголовка IPv4/IPv6 містить задану адресу вузла.
Еквівалентний фільтру:
ether proto ip and host ip_address
ether dst mac_address
Захоплювати кадри, в яких в полі адреси одержувача заголовка канального рівня містить задану адресу MAC вузла
ether src mac_address
Захоплювати кадри, в яких в полі адреси відправника заголовка канального рівня містить задану адресу MAC вузла
ether host mac_address
Захоплювати кадри, в яких у полі адреси відправника або одержувача заголовка канального рівня містить задану адресу MAC вузла
dst net network
Захоплювати кадри, у яких у полі адреси одержувача заголовка IPv4/IPv6 містить задану адресу, що належить діапазону вказаної класової мережі
src net network
Захоплювати кадри, у яких у полі адреси відправника заголовка IPv4/IPv6 містить задану адресу, що належить діапазону вказаної класової мережі
net network
Вибирає всі пакети IPv4/IPv6, що містять адреси із вказаної мережі в полі відправника або одержувача
net network mask mask
Захоплювати кадри, в яких у полі адреси відправника або одержувача заголовка IPv4/IPv6 містить задану адресу, що належить діапазону вказаної мережі
net network/mask_length
Захоплювати кадри, в яких у полі адреси відправника або одержувача заголовка IPv4/IPv6 містить задану адресу, що належить діапазону вказаної мережі
dst port port
Захоплювати кадри, у яких у полі порт одержувача заголовка UDP чи TCP містить заданий номер порту
src port port
Захоплювати кадри, в яких порт відправника заголовка UDP або TCP містить заданий номер порту
port port
Захоплювати кадри, в яких порт відправника заголовка UDP або TCP містить заданий номер порту
less length
Захоплювати кадри, розмір яких не більший за вказане значення
greater length
Захоплювати кадри, розмір яких не менший від зазначеного значення
ip proto protocol
Захоплювати кадри, в яких у полі «Protocol» заголовка IPv4 міститься ідентифікатор зазначеного протоколу. При цьому можна вказувати не лише чисельні значення протоколів, а й їх стандартні імена (icmp, igmp, igrp, pim, ah, esp, vrrp, udp, tcp та інші). Однак слід враховувати, що tcp, udp та icmp використовуються також як ключові слова, тому перед цими символьними ідентифікаторами слід перешкодити символ зворотного слеша («\»)
ip6 proto protocol
Захоплювати кадри, в яких у полі «Protocol» заголовка IPv4 міститься ідентифікатор зазначеного протоколу. При цьому можна вказувати не лише чисельні значення протоколів, а й їх стандартні імена (icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, tcp та інші). Однак слід враховувати, що tcp, udp та icmp6 використовуються також як ключові слова, тому перед цими символьними ідентифікаторами слід перешкодити символ зворотного слеша («\»)
ether broadcast
Захоплювати всі широкомовні кадри Ethernet. Ключове слово ether може бути опущене
ip broadcast
Захоплювати кадри, що містять широкомовні адреси в заголовку IPv4. При цьому для визначення, чи адреса широкомовною, використовується маски підмережі для інтерфейсу, який використовується для захоплення пакетів. Також захоплює пакети, відправлені на обмежену широкомовну адресу
ether multicast
Захоплювати усі групові кадри Ethernet. Ключове слово ether може бути опущене
ip multicast
Захоплювати кадри, які містять групові адреси в заголовку IPv4
ip6 multicast
Захоплювати кадри, які містять групові адреси в заголовку IPv6
ether proto protocol_type
Захоплювати кадри Ethernet із заданим типом протоколу. Протокол може бути вказаний за номером або ім'ям (ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, netbeui)
ip, ip6, arp, rarp, atalk, aarp, decnet, iso, stp, ipx, netbeui, tcp, udp, icmp
Захоплювати кадри, що передають дані зазначеного протоколу. Використовуються як скорочення для:
ether proto protocol
vlan [vlan_id]
Захоплювати кадри відповідно до стандарту IEEE 802.1Q. Якщо при цьому вказано номер vlan_id, то за
3. Розширені приклади фільтрів захоплення
Крім простих вказівок адрес і протоколів у фільтрах захоплення можна використовувати і складніші конструкції, що дозволяють робити більш тонкий аналіз заголовків. Для цього використовуються вирази, що повертає логічне значення наступного формату:
expression операція expression
В якому як expression можуть бути константи, результати арифметичних (+, -, *, /) або двійкових побітових операцій (& — "І", | — «АБО», << — зсув вліво, >> — зсув вправо), оператор довжини offset, дані або поля заголовків кадру. Як операцію можуть бути застосовані символи «>» (більше), «<» (менше), «>=» (більше рівно), «<=» (менше рівно), «=» (рівно), «!=» (не дорівнює). Таким чином, можна виконувати перевірку на збіг або не збіг певних полів або байт кадру з не
обхідними значеннями, порівнювати різні поля заголовків між собою, а також виконувати над ними деякі арифметичні та логічні операції та порівнювати результати цих операцій з певними значеннями. Найпростішим прикладом використання розширеного фільтра буде «5 = 3+1», де «5» і «3+1» — expression, а "=" — операція. В результаті обчислення цього рядка буде повернено логічне значення, у даному випадку false. Для отримання даних або заголовків кадру використовується примітив proto[offset: size].
Увага: квадратні дужки в даному випадку є елементом синтаксису, а не ознакою необов'язкового поля.
Параметр proto містить назву протоколу, із заголовка якого необхідно вибрати певні дані (ether, fddi, tr, wlan, ppp, slip, link, ip, arp, rarp, tcp, udp, icmp, ip6 та інші). Параметр offset вказує на усунення в байтах щодо початку заголовка зазначеного протоколу, нумерація байт починається з нуля: ip[0] – перший байт від початку IP пакета, tcp[1] – другий байт від початку TCP сегмента, ether[3] – четвертий байт від початку кадру Ethernet. Параметр size вказує на кількість байт, яку необхідно взяти, починаючи з байта, вказаного у зміщенні (offset), поле size є не обов'язковим, і якщо воно відсутнє, то вважається, що необхідно взяти 1 байт: ip[2:2] – третій і четвертий байти з початку IP пакета, tcp[4] – п'ятий байт з початку TCP сегмента, ether[6-6]– байти з сьомого по дванадцятий, від початку Ethernet кадру. Якщо в полі offset встановити негативне значення, то будуть вибрані байти попереднього заголовка, що йдуть до заголовка протоколу, вказаного в параметрі proto. Але при цьому обов'язково буде потрібна наявність у кадрі заголовка протоколу, зазначеного у примітиві proto. Таким чином, фільтри ether[11]=0x37 (взяти 12-й байт кадру Ethernet і порівняти його зі значенням 0x37) та ip[-3] = 0x37 (взяти 3-й байт з кінця заголовка, що йде перед заголовком IP, і порівняти його зі значенням 0x37) є ідентичними. У першому будуть пропускатися всі кадри, в яких MAC адреса відправника закінчується на 37, а в другому так само буде потрібно наявність протоколу IP, а кадри, що не містять IP протокол, наприклад, кадри ARP, захоплюватися не будуть.
Наприклад: Вирази ip[1:1] та ip[1] приведуть до одного й того самого результату – буде вибрано значення другого байта заголовка IPv4 Вираз tcp[8:2] вибере дев'ятий та десятий байти (поле Source Port) заголовка TCP. Вираз ip[-3] = 0x37 вибере всі IPv4 пакети, MAC адреса відправника яких закінчується на «0x37».
Слід враховувати, що з виборі даних з допомогою конструкції proto [offset:size] для протоколів TCP і UDP, враховується фрагментація IP пакетів. У результаті tcp[0] завжди означатиме перший байт заголовка TCP, і ніколи не призведе до вибору першого байта даних пакетів, що передають не перший фрагмент з ланцюжка фрагментів. Для деяких протоколів певні поля та значення зсувів можуть задаватися не лише числами, а й іменами. Наприклад, для протоколу ICMP підтримується параметр icmptype, який може приймати значення icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, ic -tstamp, icmp-tstam-preply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply. Для аналізу прапорів TCP можна використовувати параметр tcpflags ідентифікатори tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack і tcp-urg.
Наприклад: Вираз tcp[tcpflags]&(tcp-syn|tcp-fin) != 0 вибере всі кадри, що містять TCP сегменти, в яких відкривається або завершується сесія. Вираз icmp[icmptype]!=icmp-echo and icmp[icmptype]!=icmp-echoreply вибере всі кадри, що містять протокол ICMP, окрім відлуння запитів та відлуння відповідей.
Можуть бути ситуації, у яких необхідно аналізувати лише частину біт, певного байта. Для вирішення цих завдань використовується бітова операція "І" (&). З її допомогою можна зберегти лише певні біти байта, а решту обнулити. Наприклад, нам необхідно виділити лише ті кадри, які передаються на канальному рівні широкомовними чи груповими кадрами. Ми знаємо, що визначити тип MAC адреси можна за його старшим байтом:
Тип адреса
Значение старшего байта в 16-й системе
Значение старшего байта в 2-й системе
Направленные\Unicast
00
00000000
Групповые\Multicast
01
00000001
Административно назначенные\Admin ID
01
00000010
Широковещательные\Broadcast
FF
11111111
З цієї інформації, можна дійти невтішного висновку у тому, то широкомовних чи групових адресах молодший біт старшого байта адреси дорівнює одиниці, а інших – нулю. Якщо ми візьмемо старший байта адреси, обнулимо всі його біти крім наймолодшого, і при цьому значення байта стане рівним одиниці, то ця адреса була або широкомовною, або груповою, якщо значення байта стане рівним нулю, то ця адреса була або спрямована, або адміністративно заданим. В результаті для виконання цієї перевірки необхідно використовувати наступне вираз: ether[0]&1 = 1, де ether[0] – отримує значення першого байта Ethernet заголовка, а &1 — бітова операція логічне «І», що обнулює всі біти цього байта, крім молодшого, "= 1" — перевірка результату на збіг з одиницею. Розберемо ще один приклад докладніше. Нам потрібно отримати вміст поля Type Of Service (ToS) заголовка IPv4. Для цього звернувшись до RFC-791 ми побачимо, що це поле є однобайтовим полем і другим байтом заголовка:
3.1. Internet Header Format
A summary of the contents of the internet header follows:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Для того щоб отримати його значення нам необхідно скористатися наступним примітивом: ip [1: 1] — отримати один байт заголовка IP починаючи з байта номер 1 (нумерація байт починається з нуля). Тепер ми можемо будувати фільтри, ґрунтуючись на вмісті цього поля. Якщо ми хочемо, щоб відображалися всі кадри, що містять заголовок IPv4, в якому поле ToS дорівнює нулю необхідно написати наступне: ip[1:1] = 0. Якщо ми хочемо, щоб відображалися всі кадри, що містять заголовок IPv4, в якому поле ToS не одно нулю необхідно написати наступне: ip[1:1] != 0. Але можна піти далі, згідно з RFC-791 поле ToS є складовим полем і має таку структуру:
````
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | |
| PRECEDENCE | D | T | R | 0 | 0 |
| | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
Bits 0-2: Precedence.
Bit 3: 0 = Normal Delay, 1 = Low Delay.
Bits 4: 0 = Normal Throughput, 1 = High Throughput.
Bits 5: 0 = Normal Relibility, 1 = High Relibility.
Bit 6-7: Reserved for Future Use.
````
Перші три біти – перевага, четвертий визначає вимоги до затримок, п'ятий визначає вимоги до пропускної спроможності, шостий визначає вимоги до надійності лінії зв'язку, сьомий та восьмий – зарезервовані для майбутнього використання. Якщо звернутися до нових стандартів (RFC1349), значення сьомого біта вже визначено – вимоги за ціною – «Cost» (грошовий еквівалент). І ось, припустимо, ми хочемо визначити, чи є в мережі кадри, в яких в IPv4 заголовку встановлено сьомий біт поля ToS. Як це зробити? Для вирішення цього завдання нам доведеться згадати (або вивчити: D) двійкову систему обчислення. У байті кожен біт має свою вагу, яка починається з одиниці, і збільшується, праворуч наліво щоразу множаючись на два.
````
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | |
| PRECEDENCE | D | T | R | З | 0 |
| 0 0 0 | 0 | 0 | 0 | 1 | 0 |
| | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
128 64 32 16 8 4 2 1
````
Виходить, що вага біта, що цікавить нас, дорівнює 2. Що якщо ми порівняємо значення поля ToS c двійкою? З одного боку, так, але з іншого боку немає. Наприклад, якщо у нас у полі ToS є окрім біта «Cost» ще й інші біти, встановлені в одиницю? Допустимо це буде біт відповідальний за вимоги до пропускної спроможності — Throughput.
````
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | |
| PRECEDENCE | D | T | R | З | 0 |
| 0 0 0 | 0 | 1 | 0 | 1 | 0 |
| | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
128 64 32 16 8 4 2 1
````
В результаті значення цього байта буде вже не 2, а 10, і простим порівнянням не можна отримати відповідь на питання, чи встановлений певний біт в полі, що цікавить нас. Що ж нам заважає отримати відповідь, яка нас цікавить? Нам заважає значення інших, можливо, також встановлених в одиницю бітів. Відповідно треба їх позбутися. Для вирішення цього завдання скористаємося операцією побітового логічного "І" (іноді називається логічне множення), позначається символом "&". Як відомо, в логічній операції «І» на виході буде тільки тоді одиниця, коли перший операнд і другий рівні одиниці. Відповідно якщо ми зробимо побітове множення значення поля ToS на спеціальну маску, в якій буде встановлений в одиницю тільки той біт, який знаходиться на позиції біта, що цікавить нас, в полі ToS, то ми виключимо з результату всі інші біти:
````
Поле ToS: 00001010=10
Маска :00000010=2
Результат:00000010=2
````
Яким би не було значення інших біт, при накладанні цієї маски в результат потрапить тільки значення поля, що цікавить нас. Навіть якщо ми встановимо всі біти в одиницю, це не вплине на результат:
````
Поле ToS: 11111111 = 255
Маска :00000010=2
Результат:00000010=2
````
І тільки, якщо біт, що цікавить нас, дорівнює нулю, в результаті накладання маски буде так само нуль.
````
Поле ToS: 11111101 = 253
Маска :00000010=1
Результат:00000000=0
````
Таким чином, якщо біт, що цікавить нас, дорівнює одиниці, в результаті накладання маски ми отримаємо вагу цього біта, якщо він дорівнює нулю, то ми отримаємо нуль. Виходячи з цього, для вирішення цього завдання нам необхідно застосувати наступний фільтр: ip [1: 1] & 2 = 2 Він буде брати значення другого байта, накладати на нього маску «вирізує» значення певного біта і порівнювати результат з вагою цього біта. Можна навести ще один приклад на підставі аналізу поля Type Of Service заголовка IP: нам потрібно побачити всі кадри, в яких в заголовку IPv4 в полі ToS значення бітів Precedence (переважність) не дорівнює нулю. Для цього застосуємо маску, в який одиницями виділимо ті біти, які відповідають за Precedence:
````
Поле ToS: 10111101=189
Маска: 11100000 = 224
Результат: 10100000 = 160
````
Результат не дорівнює нулю, і це говорить про те, що поле Precedence так само не дорівнює нулю.
````
Поле ToS: 00011111=31
Маска: 11100000 = 224
Результати
````
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | |
| PRECEDENCE | D | T | R | 0 | 0 |
| | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
Bits 0-2: Precedence.
Bit 3: 0 = Normal Delay, 1 = Low Delay.
Bits 4: 0 = Normal Throughput, 1 = High Throughput.
Bits 5: 0 = Normal Relibility, 1 = High Relibility.
Bit 6-7: Reserved for Future Use.
````
Перші три біти – перевага, четвертий визначає вимоги до затримок, п'ятий визначає вимоги до пропускної спроможності, шостий визначає вимоги до надійності лінії зв'язку, сьомий та восьмий – зарезервовані для майбутнього використання. Якщо звернутися до нових стандартів (RFC1349), значення сьомого біта вже визначено – вимоги за ціною – «Cost» (грошовий еквівалент). І ось, припустимо, ми хочемо визначити, чи є в мережі кадри, в яких в IPv4 заголовку встановлено сьомий біт поля ToS. Як це зробити? Для вирішення цього завдання нам доведеться згадати (або вивчити: D) двійкову систему обчислення. У байті кожен біт має свою вагу, яка починається з одиниці, і збільшується, праворуч наліво щоразу множаючись на два.
````
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | |
| PRECEDENCE | D | T | R | З | 0 |
| 0 0 0 | 0 | 0 | 0 | 1 | 0 |
| | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
128 64 32 16 8 4 2 1
````
Виходить, що вага біта, що цікавить нас, дорівнює 2. Що якщо ми порівняємо значення поля ToS c двійкою? З одного боку, так, але з іншого боку немає. Наприклад, якщо у нас у полі ToS є окрім біта «Cost» ще й інші біти, встановлені в одиницю? Допустимо це буде біт відповідальний за вимоги до пропускної спроможності — Throughput.
````
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | |
| PRECEDENCE | D | T | R | З | 0 |
| 0 0 0 | 0 | 1 | 0 | 1 | 0 |
| | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
128 64 32 16 8 4 2 1
````
В результаті значення цього байта буде вже не 2, а 10, і простим порівнянням не можна отримати відповідь на питання, чи встановлений певний біт в полі, що цікавить нас. Що ж нам заважає отримати відповідь, яка нас цікавить? Нам заважає значення інших, можливо, також встановлених в одиницю бітів. Відповідно треба їх позбутися. Для вирішення цього завдання скористаємося операцією побітового логічного "І" (іноді називається логічне множення), позначається символом "&". Як відомо, в логічній операції «І» на виході буде тільки тоді одиниця, коли перший операнд і другий рівні одиниці. Відповідно якщо ми зробимо побітове множення значення поля ToS на спеціальну маску, в якій буде встановлений в одиницю тільки той біт, який знаходиться на позиції біта, що цікавить нас, в полі ToS, то ми виключимо з результату всі інші біти:
````
Поле ToS: 00001010=10
Маска :00000010=2
Результат:00000010=2
````
Яким би не було значення інших біт, при накладанні цієї маски в результат потрапить тільки значення поля, що цікавить нас. Навіть якщо ми встановимо всі біти в одиницю, це не вплине на результат:
````
Поле ToS: 11111111 = 255
Маска :00000010=2
Результат:00000010=2
````
І тільки, якщо біт, що цікавить нас, дорівнює нулю, в результаті накладання маски буде так само нуль.
````
Поле ToS: 11111101 = 253
Маска :00000010=1
Результат:00000000=0
````
Таким чином, якщо біт, що цікавить нас, дорівнює одиниці, в результаті накладання маски ми отримаємо вагу цього біта, якщо він дорівнює нулю, то ми отримаємо нуль. Виходячи з цього, для вирішення цього завдання нам необхідно застосувати наступний фільтр: ip [1: 1] & 2 = 2 Він буде брати значення другого байта, накладати на нього маску «вирізує» значення певного біта і порівнювати результат з вагою цього біта. Можна навести ще один приклад на підставі аналізу поля Type Of Service заголовка IP: нам потрібно побачити всі кадри, в яких в заголовку IPv4 в полі ToS значення бітів Precedence (переважність) не дорівнює нулю. Для цього застосуємо маску, в який одиницями виділимо ті біти, які відповідають за Precedence:
````
Поле ToS: 10111101=189
Маска: 11100000 = 224
Результат: 10100000 = 160
````
Результат не дорівнює нулю, і це говорить про те, що поле Precedence так само не дорівнює нулю.
````
Поле ToS: 00011111=31
Маска: 11100000 = 224
Результати
Результат дорівнює нулю, і це говорить про те, що поле Precedence так само дорівнює нулю. В результаті, перевірка на ненульове значення поля ToS в заголовку IPv4 буде виглядати наступним чином: ip [1: 1] & 224! = 0 або теж саме, але використовуючи шістнадцятковий варіант: ip [1: 1] & 0xe0! = 0 Розглянемо приклад із іншим протоколом. Візьмемо протокол TCP. Наприклад, нам потрібно захопити всі кадри, які передають сегменти TCP з опціями. Для того щоб зрозуміти, що потрібно шукати і де звернемося до RFC-793.
````
TCP Header Format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset | Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +-+-+-+-+-+-+-+
````
Для визначення чи є в сегменті опції, використовується поле Data Offset, воно показується довжину заголовка в чотирьохбайтових словах. Мінімальна довжина заголовка TCP сегмента – 20 байт, а це 5 чотирибайтових слів. Відповідно, якщо в заголовку TCP сегмента є опції, то значення цього поля буде більше 5. Для того щоб отримати значення цього поля необхідно скористатися примітивом tcp[12:1]. Правда, враховуючи те, що мінімальний шматок, який ми можемо взяти це один байт, а нам потрібно всього 4 біти, доведеться трохи подумати. Застосувавши примітив tcp[12:1] ми отримали наступний шматок заголовка:
````
+-+-+-+-+-+-+-+-
| Data |
| Offset | Reserved
| |
+-+-+-+-+-+-+-+-
````
Якби поле Data Offset було в молодшій частині байта, то число 5 в двійковому поданні виглядало б наступним чином:
````
128 64 32 16 8 4 2 1
0 0 0 0 0 1 0 1 = 5
````
Але біти, що цікавлять нас, знаходяться не в лівій, молодшій, а в правій, старшій його частині, тому, для отримання десяткового еквівалента переносимо їх у праву частину байта:
````
128 64 32 16 8 4 2 1
0 1 0 1 0 0 0 0 = 80 (0x50 у шістнадцятковому вигляді)
````
Для виділення старших бітів необхідно накласти маску:
````
Поле Data Offset :01010000=80
Маска: 11110000 = 240
Результат :01010000=80
````
Якщо в заголовку все ж таки є опції, то значення Data Offset буде більше 5. Наприклад, якщо в заголовку буде одна восьмибайтова опція, то значення цього поля буде 7 (5 чотирибайтових слів фіксованої частини заголовка, і 2 чотирибайтові слова опції):
````
128 64 32 16 8 4 2 1
0 0 0 0 0 1 1 1 = 7
````
Перенісши відповідні біти до старшої частини отримуємо:
````
128 64 32 16 8 4 2 1
0 1 1 1 0 0 0 0 = 112 (0x70 у шістнадцятковому вигляді)
````
Виділяємо старші біти накладаючи маску:
````
Поле Data Offset :01110000=112
Маска: 11110000 = 240
Результат :01110000=112
````
Таким чином, виходить, що якщо в результаті виходить значення більше 80, то в заголовку TCP є опції. В принципі тут маску можна було і не накладати, так як зайві біти все одно резервні, і завжди повинні дорівнювати нулю, але мало, що може змінитися, і щоб не переписувати фільтр, якщо раптом стандарт змінитися, ми краще їх обріжемо маскою. Результуючий фільтр, який покаже ті TCP сегменти, в яких довжина TCP заголовка більше 5 чотирибайтових слів, вийшов наступний: tcp[12:1] & 240! = 80 або tcp [12:1] & 240 > 80 або tcp [12:1] 0xf0 > 80 Також давайте розглянемо можливість роботи з прапорами TCP. Їх можна виділяти таким самим методом за допомогою маски, але також можна використовувати символьні класифікатори, які наводилися вище. Наприклад, для того щоб захопити кадри, що містять сегменти з прапорами SYN або FIN, необхідно написати наступний фільтр: tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 Я думаю він цілком читаємо і не вимагає особливих пояснень.