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

B2. Linux як маршрутизатор

базовийспирається на модуль 6, модуль 7, модуль 9

Маршрутизатор у модулі 7 виглядає як окрема коробка з таблицею маршрутів. У Linux це звичайний вузол, у якому ядру дозволили пересилати чужі пакети. Тут ви зробите таку коробку з простору імен r1: з’єднаєте нею дві приватні мережі, випустите їх у «зовнішній світ» через NAT із модуля 9 і роздасте одній з мереж адреси по DHCP. Потім подивитеся в tcpdump, що саме бачить провайдер.

Після цієї роботи ви зможете:

  • з’єднати кілька підмереж через Linux: адреси, маршрути за замовчуванням, net.ipv4.ip_forward;
  • пояснити по ttl у відповіді й по tcpdump, що пакет пройшов через маршрутизатор;
  • налаштувати трансляцію адрес (masquerade) у nftables і показати, з якою адресою пакет виходить назовні;
  • підняти DHCP-сервер dnsmasq для однієї підмережі й отримати від нього адресу клієнтом у своєму просторі імен;
  • знайти, чого бракує, коли «хости між собою бачаться, а назовні ні»: маршруту, ip_forward чи NAT.

Така розкладка (дві приватні мережі, шлюз, провайдер) є у кожному офісі та в кожній домашній мережі. Коли в ній щось ламається, поступово перевіряють саме ці три місця.

Результат роботи — чотири простори імен і правила в r1:

LAN A 10.0.1.0/24 LAN B 10.0.2.0/24
┌────┐ ┌────┐
│ h1 │ (DHCP) .2 │ h2 │
└─┬──┘ └─┬──┘
│ │
└───────────┐ ┌───────────┘
┌──┴─────┴──┐
│ r1 │ .1 у кожній LAN
└─────┬─────┘
│ .2
«зовнішня мережа» 203.0.113.0/24
│ .1
┌─────┴─────┐
│ isp │ lo: 198.51.100.1 («інтернет»)
└───────────┘
Простір імен Адреса Примітка
r1 10.0.1.1/24 (LAN A), 10.0.2.1/24 (LAN B), 203.0.113.2/24 (до провайдера) маршрутизатор
h1 з DHCP із діапазону 10.0.1.100–10.0.1.199 хост у LAN A
h2 10.0.2.2/24 хост у LAN B, адреса статична
isp 203.0.113.1/24 на інтерфейсі, 198.51.100.1/32 на lo провайдер і «інтернет»

Назви просторів імен і адреси зафіксовані, їх перевіряє check.sh. Назви інтерфейсів оберіть самі.

Що зробити:

  1. Побудувати топологію: чотири простори імен і три пари veth (r1–h1, r1–h2, r1–isp).
  2. Призначити адреси з таблиці й прописати статичні маршрути: хост відправляє «усе чуже» через r1, r1 відправляє «усе чуже» провайдеру. У isp маршрутів до приватних мереж немає, і це свідоме рішення: так працює справжній провайдер.
  3. Ввімкнути в r1 пересилання пакетів.
  4. Налаштувати NAT так, щоб усе, що виходить із 10.0.0.0/16 не в приватну мережу, виглядало для провайдера як 203.0.113.2.
  5. Підняти в r1 DHCP-сервер dnsmasq для LAN A й отримати адресу та маршрут за замовчуванням у h1 від нього.
  6. Показати в tcpdump на стороні провайдера адресу відправника до NAT і після.

Чого робити не треба. DNS-сервер і DHCP для LAN B не потрібні. Динамічну маршрутизацію і файрвол залишимо для B3 і B4.

Обмеження. nftables для NAT, не iptables. Адресу h1 в еталонному результаті видає dnsmasq, руками її не задавайте.

Готово, коли sudo ./check.sh не показує жодного «НІ», а в нотатках є відповіді на питання з етапів.

  • Прочитайте в модулі 6 розділи про адреси й маски, у модулі 7 розділ про пересилання пакетів, а в модулі 9 розділи про NAT і DHCP.
  • Встановіть інструменти: sudo bash setup/provision.sh. Для цієї роботи потрібні iproute2, nftables, dnsmasq, isc-dhcp-client (команда dhclient), conntrack, tcpdump, python3.
  • Потрібні права root. Підходить віртуальна машина й більшість контейнерів, де працюють простори імен та nftables (див. setup/probe-net-env.sh).
  • Працюйте в каталозі labs/b2-linux-router.
  1. Простори імен і дроти.

    Terminal window
    for ns in r1 h1 h2 isp; do
    sudo ip netns add $ns
    sudo ip netns exec $ns ip link set lo up
    done
    sudo ip link add lanA-r netns r1 type veth peer name eth0 netns h1
    sudo ip link add lanB-r netns r1 type veth peer name eth0 netns h2
    sudo ip link add wan-r netns r1 type veth peer name eth0 netns isp

    Назви інтерфейсів тут ваші. ip -n r1 link покаже три нові інтерфейси в стані DOWN.

  2. Адреси й маршрути.

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

    Terminal window
    sudo ip netns exec h2 ip route add default via 10.0.2.1
    sudo ip netns exec r1 ip route add default via 203.0.113.1

    Адресу h1 поки задайте вручну (10.0.1.50/24 і маршрут через 10.0.1.1): DHCP буде пізніше.

    Перевірте: ping від кожного хоста до його шлюзу проходить. h1 → h2 ще ні.

  3. Пересилання.

    Terminal window
    sudo ip netns exec h1 ping -c1 10.0.2.2 # не проходить
    sudo ip netns exec r1 sysctl -w net.ipv4.ip_forward=1
    sudo ip netns exec h1 ping -c1 10.0.2.2 # проходить

    Перший ping не проходить не тому, що маршруту немає. Пакет доходить до r1, але ядро відкидає чужі пакети, поки не ввімкнено ip_forward. Подивіться у відповідь на другий ping: ttl=63, а не 64. Одиниця різниці й підказує, скільки маршрутизаторів на шляху.

    Запишіть: у чому різниця між маршрутом у таблиці й дозволом пересилати? Що було б, якби r1 мав маршрут, але не мав ip_forward?

  4. Вихід назовні й NAT.

    Спершу переконайтеся, що без NAT назовні не вийти. Запустіть tcpdump у isp:

    Terminal window
    sudo ip netns exec isp tcpdump -ni any icmp

    і в іншому вікні sudo ip netns exec h2 ping -c2 198.51.100.1. Запити приходять з адреси 10.0.2.2, а відповіді немає: у isp немає маршруту до приватної мережі. Тепер додайте NAT:

    Terminal window
    sudo ip netns exec r1 nft add table ip nat
    sudo ip netns exec r1 nft add chain ip nat postrouting \
    '{ type nat hook postrouting priority srcnat; }'
    sudo ip netns exec r1 nft add rule ip nat postrouting \
    ip saddr 10.0.0.0/16 ip daddr != 10.0.0.0/16 masquerade

    Повторіть ping. У tcpdump тепер відправник 203.0.113.2, і відповіді доходять. Подивіться, як r1 запам’ятав з’єднання: sudo ip netns exec r1 conntrack -L.

    Запишіть: чому правило NAT стоїть у хуку postrouting, а не prerouting? Звідки r1 знає, кому віддати відповідь?

  5. DHCP.

    Приберіть статичну адресу h1 (ip addr flush dev eth0) і запустіть у r1 DHCP-сервер для LAN A:

    Terminal window
    sudo ip netns exec r1 dnsmasq --conf-file=/dev/null --no-resolv --port=0 \
    --interface=lanA-r --bind-interfaces \
    --dhcp-range=10.0.1.100,10.0.1.199,12h
    sudo ip netns exec h1 dhclient -1 -v eth0

    Замініть lanA-r і eth0 своїми назвами. --port=0 вимикає DNS у dnsmasq, залишаючи лише DHCP. Подивіться в ip -4 addr у h1 адресу з позначкою dynamic і в ip route маршрут за замовчуванням через 10.0.1.1: його теж роздав dnsmasq, адреса інтерфейсу стала шлюзом автоматично.

    Запустіть tcpdump -ni any port 67 or port 68 у r1 і повторіть dhclient. Ви побачите чотири пакети: Discover, Offer, Request, Ack.

    Запишіть: чому Discover іде на 255.255.255.255, а не на адресу сервера? З якої адреси його відправлено?

  6. Порівняння до і після.

    Запишіть у нотатки три числа: ttl у відповіді h1 → h2, адресу відправника, яку бачить isp до NAT і після, і діапазон адрес, який видав dnsmasq. Їх ви й поясните, якщо хтось спитає, що роблять ці три налаштування.

Terminal window
sudo ./check.sh

Скрипт нічого не будує й від назв інтерфейсів не залежить: він знаходить інтерфейси за адресами. Перевіряється:

  • адреси з таблиці на r1, h2 та isp;
  • що в r1 працює dnsmasq, а h1 має адресу з 10.0.1.0/24, видану за оренду (не задану вручну), і маршрут через 10.0.1.1;
  • що в r1 ввімкнено ip_forward, а h1 і h2 пінгують одне одного;
  • що h1 і h2 досягають 198.51.100.1, а провайдер бачить їхнє TCP-з’єднання з адресою 203.0.113.2, тобто NAT справді працює (скрипт на хвилину запускає в isp слухач, який повідомляє клієнту його адресу);
  • що isp не має доступу до приватних адрес.

Якщо топологію зламати, скрипт показує, де саме: без ip_forward не проходять h1 → h2 і вихід назовні; без NAT проходить усе, крім зовнішньої мережі; без dnsmasq адреса в h1 виявляється заданою вручну.

Не ввімкнено ip_forward у r1. sysctl працює на простір імен: sudo sysctl -w net.ipv4.ip_forward=1 на господарі не допомагає, потрібно в r1: ip netns exec r1 sysctl ....

NAT є, а назовні не проходить. Перевірте, чи маршрут за замовчуванням у r1 дивиться на 203.0.113.1, і чи правило NAT підхоплює пакет: nft list ruleset у r1 та лічильники правила (nft -a list ruleset і counter).

dhclient висить. Перевірте, що dnsmasq слухає саме інтерфейс у LAN A (--interface= ваша назва), а не інший. Дивіться, чи доходить Discover до r1 у tcpdump.

Ручні й динамічні налаштування разом. Якщо після dhclient у h1 лишилася стара статична адреса чи маршрут, два набори налаштувань конфліктують. Перед DHCP зробіть ip addr flush dev <інтерфейс> і ip route flush default.

Залишки попередньої спроби. Якщо будували кілька разів, перевірте, що старий dnsmasq не висить у r1 (ip netns pids r1) і що в просторах імен не лишилося зайвих правил.

Додаткове завдання: IPv6 (dual stack). Дайте LAN A і LAN B адреси fd00:0:0:1::/64 і fd00:0:0:2::/64 (r1 має ::1 у кожній, h1 — fd00:0:0:1::2, h2 — fd00:0:0:2::2), увімкніть net.ipv6.conf.all.forwarding у r1 і переконайтеся, що h1 пінгує h2 командою ping -6. Перевірити це можна так: sudo IPV6=1 ./check.sh. IPv6 працює не в усіх контейнерах (у ядрі господаря його може не бути), тож ця частина потребує віртуальної машини; setup/probe-net-env.sh покаже, чи є він у вас. Подумайте, чому для IPv6 NAT зазвичай не потрібний.

Інші розширення: два правила nft для DNAT (пробросити порт зовнішньої адреси на h2) або dnsmasq із DNS і статичним записом (--address=).