Перейти до вмісту

VLAN, ARP і сусіди

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

Друге питання звучить буденніше. Ви запускаєте ping 192.0.2.2, і кадр Ethernet потребує MAC-адреси отримувача, а ви знаєте лише IP. Хтось мусить перекласти одне в інше, і саме тут трапляється «ping то проходить, то ні», «сервер бачить чужу MAC-адресу» і «весь трафік раптом іде через ноутбук у кутку». Перекладає ARP, а мережевий стек Linux тримає результат у таблиці сусідів, яку корисно вміти читати.

Передумови. Кадр, MAC-адреса, комутатор і широкомовний домен — модуль 4. IP-адреса як поняття — модуль 1; детально про неї в модулі 6.

VLAN: один комутатор, кілька мереж

Section titled “VLAN: один комутатор, кілька мереж”

Широкомовний домен комутатора охоплює всі його порти. Щоб поділити його на частини, можна купити більше комутаторів, а можна навчити один комутатор тримати кілька ізольованих доменів. Останнє й називається VLAN (virtual LAN). Кожному порту приписується номер VLAN, і кадр, що прийшов на порт, лишається всередині цього VLAN: на порти інших VLAN його не розішлють навіть при flooding. Хости з різних VLAN не бачать одне одного на канальному рівні, навіть якщо сидять на сусідніх портах. Щоб вони поспілкувалися, між мережами потрібен маршрутизатор (модуль 7).

Ізоляції достатньо, поки всі хости підключені до одного комутатора. Коли комутаторів два, з’являється питання, як передати кадри двох VLAN одним кабелем так, щоб другий комутатор знав, до якого VLAN належить кожен кадр. Для цього є стандарт IEEE 802.1Q: у кадр вставляється 4-байтовий тег між адресою відправника й EtherType.

Тег складається з:

  • TPID 0x8100: це значення стоїть там, де звичайно EtherType, і повідомляє приймачеві, що далі йде тег;
  • PCP (3 біти): пріоритет кадра;
  • DEI (1 біт): чи можна кадр викинути першим при перевантаженні;
  • VID (12 біт): номер VLAN. Номери 0 і 4095 зарезервовані, тож користувачу доступні 1–4094.

Після тега йде справжній EtherType. Кадр став на 4 байти довшим (1522 байти замість 1518), а MTU лишився 1500, бо вимірюється по навантаженню. Про це варто пам’ятати, коли в мережі є старе обладнання, яке не чекає на кадри понад 1518 байтів.

Два комутатори з двома VLAN. Хости A і C у VLAN 10, B і D у VLAN 20. Порти до хостів access, без тегу. Звʼязок між комутаторами trunk: кадри VLAN 10 і VLAN 20 йдуть по одному кабелю з тегами 10 і 20.комутатор 1комутатор 2trunk: тег 10 або 20 у кожному кадріAVLAN 10BVLAN 20CVLAN 10DVLAN 20access, без тегуaccess, без тегу
Дві VLAN на двох комутаторах. Порти до хостів без тегу: хост про VLAN не знає. По кабелю між комутаторами йдуть кадри обох VLAN, кожен із тегом. Другий комутатор за тегом вирішує, на які порти його розіслати.

Access-порт належить одному VLAN. Кадри від хоста приходять без тегу, комутатор у думках «прикріплює» до них номер VLAN порту, а назад віддає без тегу. Хост навіть не підозрює, що VLAN існує.

Trunk-порт несе кілька VLAN. Кадри по ньому йдуть з тегами, за якими сусідній комутатор розпізнає, куди кадр належить. На trunk зазвичай одна VLAN ходить без тегу: це native VLAN (у термінології Linux — pvid з untagged). Вона потрібна для сумісності, коли на тому кінці хост чи пристрій про теги не знає. Якщо native VLAN не збігається на двох кінцях trunk, кадри однієї VLAN потрапляють в іншу, тож її роблять однаковою на обох кінцях і найкраще порожньою, без хостів.

Міст Linux вміє це сам. Вмикається фільтрація vlan_filtering, і кожен порт моста отримує список VLAN, які через нього проходять. За замовчуванням усі порти в VLAN 1 як pvid untagged, тобто нічого не змінюється, доки не налаштуєте. Далі командою bridge vlan add виставляється, який порт у якій VLAN.

Terminal window
ip link add br0 type bridge vlan_filtering 1
# access-порти: кадри без тегу, належать одній VLAN
bridge vlan add dev q1 vid 10 pvid untagged
bridge vlan add dev q2 vid 20 pvid untagged
# trunk-порт: кадри обох VLAN із тегами
bridge vlan add dev q3 vid 10
bridge vlan add dev q3 vid 20
# прибрати початкову VLAN 1 з access-портів
bridge vlan del dev q1 vid 1
bridge vlan del dev q2 vid 1
Terminal window
bridge vlan show
port vlan-id
q1 10 PVID Egress Untagged
q2 20 PVID Egress Untagged
q3 10
20
br0 1 PVID Egress Untagged

Мітки PVID і Egress Untagged означають: кадри без тегу, що прийшли на порт, потрапляють у цю VLAN, а виходять з порту вже без тегу. Рядок без міток (як для q3) описує тегований вхід і вихід. Окремо мости в Linux мають власний інтерфейс br0, який теж належить до VLAN (bridge vlan add dev br0 vid 10 self), якщо хост із цим мостом бере участь в мережі, наприклад, має там IP-адресу.

А от на самому хості, що сидить на trunk, VLAN створюється як окремий інтерфейс: ip link add link eth0 name eth0.10 type vlan id 10. Кадри, які надсилає цей інтерфейс, отримують тег 10 автоматично.

ARP: як з IP-адреси отримати MAC

Section titled “ARP: як з IP-адреси отримати MAC”

Хост 192.0.2.1 хоче надіслати пакет на 192.0.2.2, що в тій самій підмережі. Кадр мусить мати MAC-адресу призначення, а хост її не знає. Цю задачу розв’язує ARP (address resolution protocol), і розв’язує найпростіше: питає всіх.

  1. Хост надсилає широкомовний кадр (адресат ff:ff:ff:ff:ff:ff, EtherType 0x0806) із запитом: «хто має адресу 192.0.2.2? Скажіть 192.0.2.1», а у полі відправника стоїть його власна MAC-адреса.

  2. Усі пристрої широкомовного домену отримують кадр. Той, хто має цю IP-адресу, відповідає унікастом одному запитувачу: «192.0.2.2 знаходиться за 8e:ce:a8:35:e6:ac». Решта мовчить.

  3. Запитувач записує пару в кеш ARP і відправляє накопичений пакет. Наступні пакети йдуть без запиту, поки запис живий.

Пакет ARP маленький, 28 байтів для IPv4 поверх Ethernet: тип апаратури і протоколу, довжини адрес, код операції (1 — запит, 2 — відповідь) і по дві пари «MAC + IP» відправника й цілі. Він не використовує IP, лежить прямо в кадрі, тому ARP не маршрутизується й не виходить за межі широкомовного домену. Якщо цільовий хост у іншій мережі, ARP питає не про нього, а про шлюз (як хост це вирішує, розповідає модуль 7).

Таблиця сусідів і її стани

Section titled “Таблиця сусідів і її стани”

У Linux кеш ARP входить до загальної таблиці сусідів (neighbour table), якою користуються і ARP для IPv4, і NDP для IPv6. Дивляться на неї командою ip neigh. Запис у ній проходить кілька станів, бо сусід може зникнути, а хост не хоче ні щоразу питати наново, ні слати пакети в нікуди.

Стани запису сусіда в ядрі Linux. INCOMPLETE після ARP-запиту; відповідь переводить у REACHABLE, а її відсутність після трьох спроб у FAILED. REACHABLE за кілька десятків секунд стає STALE. Перший же пакет до STALE переводить запис у DELAY; підтвердження за 5 секунд повертає в REACHABLE, інакше PROBE: унікастні запити, відповідь дає REACHABLE, тиша FAILED.перший пакет до сусіда: широкомовний запитвідповідьтиша, 3 запитиминув reachable timeнадіслали пакет5 с без підтвердженняпідтвердженнявідповідьтиша, 3 запитиINCOMPLETEREACHABLESTALEDELAYPROBEFAILED
Життєвий цикл запису в таблиці сусідів Linux. Зелений стан означає, що нещодавно було підтвердження досяжності. Червоний — сусіда не знайшли.
  • INCOMPLETE: запит надіслано, відповіді ще немає. Пакети до цього адресата чекають у короткій черзі.
  • REACHABLE: сусід нещодавно підтвердив себе. Час у цьому стані береться з base_reachable_time_ms (30 секунд за замовчуванням), ядро додає випадковий розкид, тож реальне число коливається.
  • STALE: часу минуло багато, і запис «можливо, застарів». Але він лишається придатним: пакети йдуть на збережену MAC-адресу без пауз. Перевірка настає лише тоді, коли знадобиться.
  • DELAY: відправили пакет на STALE-запис і чекаємо 5 секунд, чи не надійде непряме підтвердження (наприклад, від TCP прийшла відповідь).
  • PROBE: підтвердження не було, ядро надсилає сусідові унікастні запити.
  • FAILED: відповіді не дочекалися. Пакети на цю адресу викидаються, а програма отримує помилку No route to host або тайм-аут.
  • PERMANENT: запис внесений вручну й не старіє, нічого не перевіряється.

Якщо запис завис на INCOMPLETE або FAILED, хост не отримує відповіді на ARP, і причину треба шукати нижче за IP: фізичний порт, VLAN, фільтр на комутаторі чи просто не той хост.

Gratuitous ARP хост надсилає без жодного питання, про власну адресу; це може бути і запит, і відповідь. У запиті власна IP-адреса стоїть і як адреса відправника, і як цільова.

Так хост, який щойно налаштував адресу, перевіряє, чи хтось уже нею користується. Якщо прийшла відповідь, адреса конфліктує.

Важливіше інше застосування. Коли адреса переходить на інший пристрій (міграція віртуальної машини, перемикання на резервний сервер, VRRP), усі сусіди ще тримають у кеші стару MAC-адресу, і трафік іде в нікуди до закінчення запису. Новий власник розсилає gratuitous ARP, і сусіди, що вже мають запис, оновлюють його й негайно перемикаються, і адреса переїжджає «плавно».

Головна слабкість протоколу в тому, що ARP не має автентифікації. Будь-хто в широкомовному домені може оголосити себе власником чужої IP-адреси, і хости повірять. Досить надіслати кожному потрібну «відповідь» чи gratuitous ARP. Це називається ARP-спуфінг, або отруєння кеша. Зловмисник, що оголосив свою MAC-адресу замість шлюзу, стає посередником: увесь трафік жертви в інтернет проходить через нього, і він може читати його, змінювати або просто викидати (тоді жертва втрачає зв’язок).

Захист від цього будують шарами:

  • Dynamic ARP Inspection на керованих комутаторах: комутатор звіряє кожен ARP-пакет із таблицею, зібраною DHCP snooping (яка адреса видана якому порту), і відкидає неправдиві.
  • Port security: обмеження кількості й набору MAC-адрес на порту.
  • Статичні записи для критичних адрес (шлюз сервера): ip neigh replace … nud permanent. Працює, але незручно в більшій мережі.
  • Шифрування вище за рівнем: TLS і SSH не прибирають перехоплення, але роблять його марним, бо зловмисник бачить лише зашифровані байти. Підміна сертифіката при цьому помітна.
  • Моніторинг: arpwatch повідомляє, коли пара «IP — MAC» змінюється.

Жоден із цих методів не закладений у сам ARP: його проєктували для довірливої локальної мережі 1980-х.

В IPv6 ARP нема. Його роль виконує NDP (neighbor discovery protocol), який працює поверх ICMPv6: замість широкомовного запиту — Neighbor Solicitation, замість відповіді — Neighbor Advertisement. Запит іде не на широкомовну адресу, якої в IPv6 немає, а на спеціальну групову, яку слухає лише вузьке коло хостів, серед яких шуканий. Таблиця сусідів і її стани лишаються тими самими, ip -6 neigh покаже ті самі REACHABLE і STALE. Подробиці — у модулі 10.

Стенд той самий, що в модулі 4: комутатор із трьох хостів, поки без VLAN. Тобто є простори імен h1, h2, h3 з адресами 192.0.2.1/24, 192.0.2.2/24 і 192.0.2.3/24 на інтерфейсах p1, p2, p3 і міст br0 у просторі sw.

Свіжий кеш порожній, а після першого ping у ньому є сусід:

Terminal window
sudo ip netns exec h1 ping -c1 192.0.2.2
sudo ip netns exec h1 ip neigh show
192.0.2.2 dev p1 lladdr 8e:ce:a8:35:e6:ac REACHABLE

Зачекайте з пів хвилини й подивіться ще раз: тепер там STALE. Щоб пройти цикл далі, надішліть пакет і подивіться, не чекаючи:

Terminal window
sudo ip netns exec h1 ping -c1 192.0.2.2 >/dev/null
sudo ip netns exec h1 ip neigh show
sleep 6
sudo ip netns exec h1 ip neigh show
192.0.2.2 dev p1 lladdr 8e:ce:a8:35:e6:ac DELAY
192.0.2.2 dev p1 lladdr 8e:ce:a8:35:e6:ac REACHABLE

Сусід одразу після пакета у DELAY, а за кілька секунд, коли ядро перепитало його, знову REACHABLE. ICMP-відповідь ядро не вважає підтвердженням досяжності, тож перепитує сусіда саме; той відповідає, і цикл замикається.

Тепер адреса, якої нема:

Terminal window
sudo ip netns exec h1 ping -c1 -W1 192.0.2.50
sudo ip netns exec h1 ip neigh show 192.0.2.50
192.0.2.50 dev p1 INCOMPLETE

Через кілька секунд, коли ядро зробить усі спроби, запис стає FAILED. Файл /proc/net/arp показує те саме в старому форматі (колонка Flags: 0x2 — запис повний, 0x0 — невдалий, 0x6 — постійний).

Лічильники і параметри: ip -s neigh додає колонки used і probes, а налаштування читаються з sysctl net.ipv4.neigh.default (там base_reachable_time_ms = 30000, delay_first_probe_time = 5, ucast_solicit = 3, mcast_solicit = 3).

Щоб побачити ARP без ICMP, підійде arping (пакет arping у Debian і Ubuntu). Він шле лише ARP, тож спрацює й тоді, коли ICMP на шляху блокують:

Terminal window
sudo ip netns exec h1 arping -c2 -i p1 192.0.2.2
ARPING 192.0.2.2
42 bytes from 8e:ce:a8:35:e6:ac (192.0.2.2): index=0 time=5.785 usec
42 bytes from 8e:ce:a8:35:e6:ac (192.0.2.2): index=1 time=4.878 usec

Опція -i задає інтерфейс. Існує ще інша програма з такою ж назвою (з пакета iputils), де інтерфейс задається -I, а синтаксис інший; тому звіряйтеся з arping -h.

Чесно проведемо атаку на власний стенд. Вона працює лише у ваших просторах імен, але ілюструє справжню поведінку. Залежно від пакета ваш arping може мати інші опції.

Хост h1 знає справжню MAC-адресу h2. Хост h3 надсилає gratuitous ARP, від імені 192.0.2.2 зі своєю MAC-адресою (-S задає підставлену IP-адресу, -U — unsolicited-запит):

Terminal window
sudo ip netns exec h3 arping -c1 -U -S 192.0.2.2 -i p3 192.0.2.2
sudo ip netns exec h1 ip neigh show 192.0.2.2
192.0.2.2 dev p1 lladdr ce:a4:16:e4:26:bb STALE

lladdr тепер MAC-адреса h3 (ce:a4:16:e4:26:bb). Запис лишився чинним, але змінився, а ping 192.0.2.2 із h1 більше не отримує відповіді: кадри йдуть на h3, у якого цієї IP-адреси нема. Тепер захист:

Terminal window
sudo ip netns exec h1 ip neigh replace 192.0.2.2 lladdr 8e:ce:a8:35:e6:ac dev p1 nud permanent
sudo ip netns exec h3 arping -c1 -U -S 192.0.2.2 -i p3 192.0.2.2
sudo ip netns exec h1 ip neigh show 192.0.2.2
192.0.2.2 dev p1 lladdr 8e:ce:a8:35:e6:ac PERMANENT

Запис PERMANENT нова «відповідь» не чіпає, і пінг знову працює.

Якщо ip link set br0 type bridge vlan_filtering 1 повертає Operation not supported, ваше ядро зібране без CONFIG_BRIDGE_VLAN_FILTERING. Таке трапляється в контейнерах і на деяких хостингах; на віртуальній машині з ядром дистрибутива фільтрація працює. Перевірити, що VLAN справді ізолює, можна так: хости h1 і h2 з одного VLAN пінгують один одного, а h1 і h3 з різних VLAN ні, і ARP-запит від h1 у tcpdump на h3 не з’являється.

Прибрати за собою: sudo ip netns delete h1 і так само h2, h3, sw.

Типові помилки розуміння

Section titled “Типові помилки розуміння”

«VLAN — це окрема підмережа IP». VLAN — рівень 2, підмережа — рівень 3. Зазвичай одній VLAN відповідає одна підмережа, але технічно ніщо цього не вимагає: на одній VLAN можна налаштувати дві підмережі, а одну підмережу розтягнути на дві VLAN і отримати сюрпризи.

«Хост у VLAN 10 бачить тег». На access-порту тегу нема: комутатор додає й знімає його сам. Теги бачать лише trunk-порти й пристрої, що налаштовані на VLAN явно (наприклад, інтерфейс eth0.10).

«ARP питає про цілий інтернет». ARP працює лише в межах широкомовного домену. Для адреси поза підмережею хост питає MAC шлюзу за замовчуванням, а не адресата.

«STALE означає, що сусід недоступний». Навпаки: запис цілком придатний. STALE означає «давно не перевіряли», а недоступний сусід — це FAILED.

«Якщо ping працює, то ARP у порядку». Ping проходить і тоді, коли кеш отруєно, але отруїв його ваш сусід, який пересилає трафік далі. Поки кадри доходять, ніхто нічого не помічає. Справжню картину показує ip neigh: чи збігається lladdr шлюзу з MAC-адресою справжнього шлюзу.

«Проти ARP-спуфінгу допоможе брандмауер на хості». Брандмауер працює вище за кадри. Підміна відбувається на канальному рівні, до нього пакет навіть не доходить. Потрібен захист на комутаторі або шифрування вище.

Перевір себе

1. Хост у VLAN 10 на access-порту надсилає кадр. Що відбувається з тегом 802.1Q?
2. Чому між VLAN 10 і VLAN 20 на одному комутаторі без маршрутизатора нема зв’язку?
3. У ip neigh запис для шлюзу має стан STALE. Що це означає?
4. Навіщо хост розсилає gratuitous ARP після перенесення IP-адреси на новий сервер?
5. Чому ARP-спуфінг неможливо зупинити налаштуванням брандмауера на хості-жертві?
6. Що станеться, якщо на двох кінцях trunk native VLAN налаштовано по-різному?

B1. Міст і VLAN руками: два хости й міст, тоді VLAN-фільтрація на мості; ARP і широкомовлення видно в tcpdump. Там же на практиці стає зрозуміло, чим access відрізняється від trunk.

B7. Налагодження зламаної мережі: одна з несправностей стосується ARP. Вміння швидко зазирнути в ip neigh і відрізнити FAILED від STALE заощадить там час.

  • Kurose, Ross, Computer Networking: A Top-Down Approach, розділ про канальний рівень, ARP і VLAN
  • Peterson, Davie, Computer Networks: A Systems Approach, розділ про комутатори й VLAN
  • Stevens, TCP/IP Illustrated, Vol. 1, розділ про ARP
  • IEEE 802.1Q (VLAN), RFC 826 (ARP)
  • man 8 ip-neighbour, man 8 bridge, man 7 arp
  • Документація ядра Linux: Documentation/networking/ip-sysctl.rst (параметри neigh і arp_*)