Как пакет выбирается из своей сети и как ему отвечают
Отправляя пакет, узел сначала решает: получатель в моей сети или нет. Если в своей — кадр отправляется прямо ему (через ARP). Если нет — пакет отдаётся маршрутизатору, а тот решает, что делать дальше. Решение принимается по таблице маршрутов:
$ ip route
default via 192.168.116.1 dev ens18 proto dhcp src 192.168.116.34 metric 1002
192.168.116.0/24 dev ens18 proto dhcp scope link src 192.168.116.34 metric 1002
| Строка | Смысл |
|---|---|
192.168.116.0/24 dev ens18 … scope link | Своя сеть: отправлять напрямую через интерфейс ens18 |
default via 192.168.116.1 | Всё остальное (0.0.0.0/0) — шлюзу 192.168.116.1 |
metric | Приоритет, если маршрутов в одну сеть несколько: меньше — лучше |
Спросить у ядра, какой маршрут оно выберет для адреса, — ip route get:
$ ip route get 77.88.8.8
77.88.8.8 via 192.168.116.1 dev ens18 src 192.168.116.34 uid 1000
$ ip route get 192.168.116.10
192.168.116.10 dev ens18 src 192.168.116.34 uid 1000
Если подходят несколько маршрутов, выбирается самый точный — с наибольшим префиксом. Маршрут в 10.1.2.0/24 победит маршрут в 10.0.0.0/8 для адреса 10.1.2.5, а default (префикс 0) подходит всем и проигрывает всем.
Соберём в пространствах имён схему: два офисных компьютера в разных сетях, маршрутизатор r1 между ними и «провайдер» isp. Команды сборки — в задании на портале; ниже — что происходит на каждом шаге.
h1 192.168.10.10/24 h2 192.168.20.10/24
│ │
lan1 192.168.10.1 lan2 192.168.20.1
└──────────[ r1 ]────────────┘
│ wan 203.0.113.2/30
│
isp 203.0.113.1/30 ── «интернет» 198.51.100.1
Шаг 1. Нет шлюза. У h1 есть только маршрут в свою сеть — про 192.168.20.0 он ничего не знает:
$ sudo ip netns exec h1 ping -c 1 192.168.20.10
ping: connect: Сеть недоступна
$ sudo ip -n h1 route
192.168.10.0/24 dev eth0 proto kernel scope link src 192.168.10.10
Шаг 2. Шлюз есть, а ответа нет. Добавляем маршруты по умолчанию на h1 и h2 — пакеты уходят на r1, но дальше не идут:
$ sudo ip -n h1 route add default via 192.168.10.1
$ sudo ip -n h2 route add default via 192.168.20.1
$ sudo ip netns exec h1 ping -c 1 -W 1 192.168.20.10
1 packets transmitted, 0 received, 100% packet loss, time 0ms
$ sudo ip netns exec r1 sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
По умолчанию Linux — не маршрутизатор: пакеты, адресованные не ему, он выбрасывает. Это защита: обычный сервер с двумя сетевыми картами не должен соединять сети без ведома администратора.
Шаг 3. Включаем пересылку.
$ sudo ip netns exec r1 sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
$ sudo ip netns exec h1 ping -c 2 192.168.20.10
64 bytes from 192.168.20.10: icmp_seq=1 ttl=63 time=0.118 ms
64 bytes from 192.168.20.10: icmp_seq=2 ttl=63 time=0.070 ms
$ sudo ip netns exec h1 traceroute -n -q1 192.168.20.10
traceroute to 192.168.20.10 (192.168.20.10), 30 hops max, 60 byte packets
1 192.168.10.1 0.052 ms
2 192.168.20.10 0.025 ms
Обратите внимание на ttl=63 вместо 64: каждый маршрутизатор уменьшает поле TTL (Time To Live) на единицу, а при нуле выбрасывает пакет. Так пакеты не кружат вечно, если маршруты зациклились. На этом же построен traceroute (модуль 08). Постоянно пересылка включается файлом в /etc/sysctl.d/: net.ipv4.ip_forward = 1.
У r1 три сети подключены напрямую, а путь в остальной мир он должен знать — добавляем маршрут по умолчанию через провайдера:
$ sudo ip -n r1 route
192.168.10.0/24 dev lan1 proto kernel scope link src 192.168.10.1
192.168.20.0/24 dev lan2 proto kernel scope link src 192.168.20.1
203.0.113.0/30 dev wan proto kernel scope link src 203.0.113.2
$ sudo ip -n r1 route add default via 203.0.113.1
$ sudo ip -n r1 route get 198.51.100.1
198.51.100.1 via 203.0.113.1 dev wan src 203.0.113.2 uid 0
Маршрут в конкретную сеть через конкретный шлюз — ip route add 10.50.0.0/16 via 192.168.20.254: так подключают сеть филиала через VPN-шлюз. Шлюз в маршруте должен быть доступен напрямую — находиться в одной из сетей интерфейсов.
В больших сетях маршруты не прописывают руками: маршрутизаторы обмениваются ими по протоколам динамической маршрутизации — OSPF внутри организации, BGP между провайдерами. Именно BGP связывает автономные системы интернета.
Попробуем выйти «в интернет» с h1:
$ sudo ip netns exec h1 ping -c 1 -W 1 198.51.100.1
1 packets transmitted, 0 received, 100% packet loss, time 0ms
$ sudo ip netns exec isp tcpdump -i eth0 -nn icmp # что видит провайдер
IP 192.168.10.10 > 198.51.100.1: ICMP echo request, id 39677, seq 1, length 64
Запрос до провайдера дошёл, но с частным адресом отправителя 192.168.10.10. Провайдер не знает, куда отвечать на такой адрес: таких сетей в мире миллионы. Решение — NAT (трансляция адресов): r1 заменяет адрес отправителя своим внешним, запоминает соответствие и, получив ответ, возвращает его нужному компьютеру. Вариант, при котором подставляется адрес исходящего интерфейса, называется маскарадингом. В Linux его настраивают в nftables:
$ sudo ip netns exec r1 nft list ruleset
table ip nat {
chain post {
type nat hook postrouting priority srcnat; policy accept;
oifname "wan" masquerade
}
}
$ sudo ip netns exec h1 ping -c 1 -W 1 198.51.100.1
64 bytes from 198.51.100.1: icmp_seq=1 ttl=63 time=0.426 ms
$ sudo ip netns exec isp tcpdump -i eth0 -nn icmp
IP 203.0.113.2 > 198.51.100.1: ICMP echo request, id 39699, seq 1, length 64
IP 198.51.100.1 > 203.0.113.2: ICMP echo reply, id 39699, seq 1, length 64
Провайдер теперь видит только адрес r1. Так работает каждый домашний роутер: десяток устройств выходит в интернет через один публичный адрес.
IPv6 решает проблему нехватки адресов: в нём 128 бит. Адрес пишут восемью группами по 4 шестнадцатеричные цифры через двоеточие; ведущие нули в группе опускают, а одну серию нулевых групп заменяют на ::.
2001:0db8:0000:0000:0000:ff00:0042:8329
2001:db8::ff00:42:8329 # то же самое, сокращённо
$ ip -6 addr show ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 fe80::b641:8f47:5a50:a157/64 scope link
valid_lft forever preferred_lft forever
| Адрес | Назначение |
|---|---|
fe80::/10 — link-local | Есть у каждого интерфейса всегда, работает только в пределах своей сети. В выводе выше — именно он |
2000::/3 — глобальные | Публичные адреса интернета, выдаются провайдером |
fd00::/8 — уникальные локальные | Аналог частных сетей IPv4 |
::1 | Петлевой, аналог 127.0.0.1 |
/64; провайдер выдаёт клиенту блок /56 или /48 — сотни подсетей.В России IPv6 у домашних абонентов встречается редко, а в ЦОД и облаках — всё чаще. Сервис, слушающий порт на [::], доступен и по IPv6: проверяйте, что правила межсетевого экрана заданы для обоих протоколов.
ip route, ip route get)default — последний вариантnet.ipv4.ip_forward = 1; каждый маршрутизатор уменьшает TTL