Якось займався однією проблемою у роботі FreeBSD pf firewall. Деякі користувачі мають VPN побудований на IPsec, що ходить через Palo Alto Networks. Та щось там не все працює як очікувалось зі сторони FreeBSD.

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

Якщо пригадати поверхнево мережеві протоколи та stackable headers у стилі OSI model, то операційні системи потребують гнучкого механізму для маніпуляцій та зберігання таких пакетів даних у памʼяті. У FreeBSD network stack історично використовується для цього спеціальна структура під назвою mbuf, memory buffer (у Linux використовується подібна структура під назвою sk_buff). Вона зʼявилась ще за часів класичного університетського BSD Unix, коли кипіла робота над TCP/IP та всім відомим Socket API на замовлення DARPA. Можна сміливо сказати, що майже увесь мережевий software сьогодення побудований на Socket API чи його різновидах (hello Winsock), навіть якщо software developers on higher levels за те не дуже знають.

Так от, один пакет може бути представлений у вигляді так званого mbuf chain. Це можна уявити як linked list декількох mbuf різного розміру, хоч нульового. Так зроблено для оптимізації маніпуляцій над пакетами, ми ж усі хочемо, щоб наші applications швидко працювали — ось для того операційні системи й намагаються робити свою справу “під капотом” якомога оптимальніше. Як приклад, то є потреба легко прибирати оброблені чи додавати нові headers до існуючого пакету, та не робити зайвого копіювання тощо. Виявилось, що pf та ipfw FreeBSD firewalls не готові до ситуації, коли перший буфер у mbuf chain має нульовий розмір.

Зазвичай network drivers та суміжні модулі не формують такі mbuf chains, але знайшлися користувачі певної конфігурації, де дотичний до IPsec модуль під назвою if_enc дозволяє “побачити” пакет після прибирання IPsec headers, простіше кажучи, після розшифрування. А робиться це оптимальним шляхом — тобто перший mbuf, який містить той самий IPsec header, не видаляється фізично, а “згортається” в нуль через зміну його метаданих, наче в ньому немає інформації та треба шукати у наступному mbuf. Для легкої аналогії, це наче як у JavaScript ми колись грались з arr.length = 0 тощо.

Виникає бажання окреслити теорему, що у великих та довгих проєктах завжди якась “цікавинка” чекає свого часу та місця. IT happens.

Telegram channel post: https://t.me/igoro_pro/5

 
 

Copyright © Igor Ostapenko
(handmade content)


Submit a like

Post a comment