A3. Розбір пакетів із pcap
tcpdump -r і Wireshark розбирають пакети так буденно, що легко забути,
скільки рішень стоїть за кожним рядком: де закінчується заголовок IP,
що таке довжина TCP-заголовка, чому кадр довший за IP-пакет, звідки
в полі TCP-прапорів літера P. Відповіді лежать у заголовках, які
описують модуль 4 (кадр Ethernet), модуль 6
(IPv4) і модуль 11 (TCP і UDP). Тут ви прочитаєте їх
самі, з файла на диску.
Після цієї роботи ви зможете:
- прочитати класичний
.pcapу будь-якому порядку байтів і з будь-якою точністю часу, не покладаючись на бібліотеку; - розібрати Ethernet (зокрема з тегом VLAN), IPv4 з опціями, TCP з опціями, UDP та ICMP і знати, яке поле за що відповідає;
- відрізнити довжину кадру від довжини IP-пакета й пояснити, звідки береться різниця;
- зібрати статистику потоків і побачити, що «з’єднання» у TCP і «обмін»
в UDP розпізнаються лише за п’ятіркою
(протокол, адреса, порт, адреса, порт); - обробити пошкоджений або невідомий вхід, не зависнувши й не повернувши мовчки неправильну відповідь.
Це потрібно щоразу, коли tcpdump показує щось дивне і треба зрозуміти,
що саме лежить у файлі, або коли потрібен власний інструмент, який
дивиться на трафік не так, як готові.
Завдання
Section titled “Завдання”Написати програму pcap-parse: на C або на Python, за вибором. Чекер
запускає виконуваний файл, тож для Python потрібен shebang і chmod +x.
Використання libpcap, scapy, dpkt та інших розбирачів заборонене.
Стандартні struct в Python і функції для читання файла в C дозволені.
./pcap-parse capture.pcap # рядок на пакет./pcap-parse --flows capture.pcap # статистика потоківФормат виводу перевіряється по словах, тож кількість пробілів між
ними не має значення. Номер пакета починається з 1. Час — це секунди від
першого пакета у файлі з шістьма знаками після крапки. Значення менше
мікросекунди відкидаються, не округлюються.
Поле len — довжина кадру «на дроті» із заголовка запису (orig_len),
а не обсяг збережених байтів.
1 0.000000 TCP 10.0.0.1:40000 -> 10.0.0.2:80 len=74 flags=S seq=1000 ack=0 win=64240 payload=02 0.000120 TCP 10.0.0.2:80 -> 10.0.0.1:40000 len=74 flags=SA seq=5000 ack=1001 win=65160 payload=03 0.009000 TCP 10.0.0.1:40000 -> 10.0.0.2:80 len=166 flags=PA seq=1001 ack=5001 win=502 payload=1004 0.010000 UDP 10.0.0.1:5353 -> 10.0.0.53:53 len=71 payload=295 0.011000 ICMP 10.0.0.1 -> 10.0.0.2 len=74 type=8 code=06 0.012000 IP/47 10.0.0.1 -> 10.0.0.2 len=607 0.013000 ETH 0x0806 02:00:00:00:00:01 -> ff:ff:ff:ff:ff:ff len=608 0.014000 TCP 10.3.0.1:1 -> 10.3.0.2:2 len=60 flags=S seq=1 ack=0 win=100 payload=0 vlan=1009 0.015000 TRUNC len=6010 0.016000 UDP 10.0.0.53:53 -> 10.0.0.1:5353 len=119 payload=77- TCP:
flags— букви з наборуFSRPAUEC(FIN, SYN, RST, PSH, ACK, URG, ECE, CWR) у порядку від молодшого біта до старшого,-, якщо прапорів немає;payload— число байтів даних TCP, обчислене за довжиною в заголовку IP, а не за розміром кадру. - UDP:
payload— довжина даних. - ICMP: тип і код, без портів.
- Інший протокол поверх IPv4:
IP/<номер протоколу>. - Не IPv4:
ETH 0x<тип в шістнадцятковому вигляді> <джерело> -> <призначення>. - Кадр із тегом 802.1Q розбирається як звичайний, а в кінець рядка
додається
vlan=<номер>(тег не впливає наETH 0x…для не-IPv4: там тип береться після тегу). - Кадр, збережений не повністю, так що заголовків не вистачає (дев’ятий пакет у прикладі), дає рядок
TRUNC len=<довжина кадру на дроті>.
Статистика потоків у режимі --flows. Потік двосторонній: пакети
A→B і B→A одного протоколу належать одному потокові. Один рядок
на потік, у порядку першої появи в файлі; адреса (з портом для TCP і UDP),
що йде першою, — це відправник першого пакета потоку:
TCP 10.0.0.1:40000 <-> 10.0.0.2:80 packets=3 bytes=314 duration=0.009000UDP 10.0.0.1:5353 <-> 10.0.0.53:53 packets=2 bytes=190 duration=0.006000ICMP 10.0.0.1 <-> 10.0.0.2 packets=1 bytes=74 duration=0.000000TCP 10.3.0.1:1 <-> 10.3.0.2:2 packets=1 bytes=60 duration=0.000000total packets=10 flows=4bytes — сума len пакетів потоку; duration — різниця часу останнього
й першого пакета потоку. У total рахуються усі пакети файла, а в потоки
потрапляють лише TCP, UDP і ICMP (тобто ARP і IP/47 потоками не є).
Формати файла. Обидва порядки байтів (за сигнатурою в перших чотирьох
байтах), мікросекундна й наносекундна сигнатури, канальний рівень
Ethernet (тип 1). Захоплення з tcpdump -i any має тип 113 (Linux cooked):
для нього потрібна відмова з кодом 2, а не розбір.
Обробка помилок:
- код 0 — успіх; порожній файл із лише заголовком дає порожній вивід;
- код 1 — файл обірвано посеред запису: усе, що вдалося прочитати
до того, виводиться (і в режимі
--flowsтеж), а в stderr з’являється повідомлення; - код 2 — вхід не підтримується: файла немає, сигнатура невідома,
це
pcapng(повідомлення в stderr має містити словоpcapng), тип каналу не Ethernet. У stdout нічого.
Чого робити не треба. pcapng, IPv6, фрагментацію IP (перший фрагмент
розбирається, як звичайний пакет, інші ви не перевіряєте), збирання TCP-потоку
з сегментів, перевірку контрольних сум, розбір протоколів прикладного рівня.
Готово, коли:
./check.sh ./pcap-parseпроходить усі перевірки;- на власному записі (
sudo tcpdump -i eth0 -w my.pcap, деeth0— ваш інтерфейс, кілька запитівcurlіping) ваш вивід збігається зtcpdump -nn -r my.pcapза кількістю пакетів, адресами, портами й прапорами; - у звіті є відповіді на запитання з етапів 3 і 4.
Перед початком
Section titled “Перед початком”- У модулі 4 знайдіть формат кадру Ethernet і тег 802.1Q,
у модулі 6 заголовок IPv4 (поля IHL і Total Length),
в модулі 11 заголовки TCP і UDP. Заголовок запису й
файла
pcapописано вman 5 pcap-savefile. - Розпакуйте архів курсу: чекер лежить
у
labs/a3-pcap-parser/check.sh. - Знадобляться
gccчиpython3іtcpdump. Root потрібен лише для перевірки на справжньому захопленні (вона пропускається, якщо ви запускаєте чекер без root) та для власних записів. Переглянути байти зручно черезxxdабоhexdump -C.
-
Заголовок файла й записи.
Перші 24 байти — заголовок файла: сигнатура (вона ж підказує порядок байтів і точність часу), версія,
snaplen, тип каналу. Далі йдуть записи: 16 байтів заголовка (секунди, мікро- або наносекунди,caplen,orig_len) іcaplenбайтів кадру.Почніть із програми, яка друкує
номер, час, caplen, orig_lenдля кожного пакета. Порівняйте число пакетів ізtcpdump -nn -r файл | wc -l. -
Ethernet і IPv4.
У кадрі 14 байтів заголовка Ethernet; якщо тип
0x8100, далі йдуть ще 4 байти тегу VLAN і справжній тип. Заголовок IPv4 має довжинуIHL × 4байтів, а не завжди 20. Протокол — дев’ятий байт, адреси — з 12-го по 19-й.Виведіть
ETH-рядки для не-IPv4 і початкові рядки IPv4 без портів. -
TCP і UDP.
Довжина TCP-заголовка береться зі старшої половини байта Data Offset (у четвірках байтів), прапорів вісім, вони лежать в одному байті. Розмір даних у пакеті — це довжина IP-пакета мінус заголовки, яку беруть із поля Total Length, а не з розміру кадру.
Запишіть у звіт: коли розмір кадру більший за
14 + Total Lengthі звідки береться цей хвіст. Підказка: порахуйте, який мінімальний розмір кадру Ethernet і скільки байтів має TCP ACK без даних. -
ICMP, інші протоколи, обрізані кадри.
Додайте
ICMP,IP/nіTRUNC. Перевірте всі межі: ваш код не має читати за кінець кадру, боcaplenможе бути меншим, ніж вимагають заголовки. Запишіть у звіт, чому знімок може бути обрізаний (snaplen) і чим тодіcaplenвідрізняється відorig_len. -
Порядок байтів і наносекунди.
Підтримайте всі чотири сигнатури. Перевірка: чекер створює файл у big-endian і з наносекундами, а також пакети на межі секунди (
100.999990і101.000010). -
Статистика потоків.
Ключ потоку однаковий для обох напрямків: відсортуйте пару
(адреса, порт)для джерела й призначення. Зберігайте порядок першої появи окремо від словника. Додайте--flows. -
Помилки й обсяг.
Обірваний файл,
pcapng, файл, що не є захопленням, відсутній файл. Потім перевірте швидкість на 60 000 пакетів: якщо ви читаєте файл по байту або додаєте рядки до вихідного буфера квадратично, чекер це помітить.
Перевірка
Section titled “Перевірка”cd labs/a3-pcap-parser./check.sh ./pcap-parse # без root: лише перевірки на згенерованих файлахsudo ./check.sh ./pcap-parse # із root ще й справжній захватЧекер складає .pcap-файли за описом пакетів і порівнює ваш вивід
з очікуваним, обчисленим із цього опису (а не з розбору цих самих байтів).
Окремі файли перевіряють: рукостискання TCP з опціями; UDP, ICMP, чужий
протокол, ARP і всі вісім прапорів; IPv4 з опціями; доповнення Ethernet
до 60 байтів і хвіст після IP-пакета; теги VLAN; big-endian, наносекунди,
межу секунди; кадр, обрізаний у середині TCP-заголовка; порожній, обірваний,
pcapng, чужий тип каналу й неіснуючий файл; потоки з двома TCP-з’єднаннями,
обміном UDP і ICMP; 60 000 пакетів.
Якщо запустити від root і tcpdump встановлений, чекер створює два
простори імен lab-a3-a і lab-a3-b, пересилає 200 000 байтів через TCP,
три UDP-датаграми й два ping, записує це tcpdump-ом і перевіряє, що ваш
розбір бачить стільки ж пакетів, що й tcpdump, сумарні дані TCP і UDP
збігаються з надісланими, а потоків рівно три. Після цього простори імен
видаляються.
Кількість пробілів у рядках і порожні рядки значення не мають; мова, якою ви пишете, теж.
Часті помилки
Section titled “Часті помилки”Довжина даних за розміром кадру. Ethernet доповнює короткі кадри до 60 байтів (без контрольної суми), і TCP ACK без даних тоді виглядатиме як пакет із шістьма байтами даних. Довжина даних береться з Total Length у заголовку IP.
IHL — у четвірках байтів. Значення 5 означає 20 байтів. Те саме стосується Data Offset у TCP.
Порядок байтів. Числа в заголовках мережевих протоколів лежать у
мережевому порядку (big-endian), а числа в заголовку запису pcap — у порядку
машини, що писала файл. Їх легко переплутати, і на типовому Linux вони
різні.
Час у нано- і мікросекундах. Поле після секунд — частка секунди. У файлі
з сигнатурою a1b23c4d це наносекунди, тож ділити його на тисячу
треба тільки там.
Читання за кінець кадру. Якщо кадр обрізано, struct.unpack_from
кине виняток, а C-код прочитає сміття. Перевіряйте довжину, перш ніж
читати поле.
Потік визначено за напрямком. Тоді запит і відповідь потраплять у різні потоки. Ключ не повинен залежати від того, хто написав першим.
Обірваний файл. Програма, що падає з винятком і не виводить
прочитане, для tcpdump -w, який ще пише в файл, марна.
Далі, якщо цікаво
Section titled “Далі, якщо цікаво”Додати pcapng: блоки секції, опису інтерфейсу й розширеного пакета.
Збирати TCP-потік із сегментів за seq і знаходити повторні передачі.
Підтримати фрагменти IP і IPv6. Замінити власний вивід на формат, який
зрозуміє text2pcap, і замкнути цикл із Wireshark.