Сетевой уровень: адресация и маршрутизация
Задачи
- Глобальная идентификация (адресация)
- Структура адреса
Механизм раздачи идентификаторов
- Алгоритм доставки (маршрутизация)
- Известный маршрут и маршрут по умолчанию внутри крупной сети
- Связность крупных сетей (карта достижимости / стоимость)
IPv4
- Структура адреса.
- адрес сети + адрес абонента
- ⇒ сетевая маска (количество битов в адресе сети)
широковещательный адрес (= адрес сети + 1…₂)
Legacy: классы (0*₂, 10*₂, 110*₂; NB: 1110*₂ — multicast)
- адрес сети + адрес абонента
Адреса интерфейсов в Linux: ip address (add, del и т. п.)
- Принятие решения о маршрутизации
- Таблица маршрутизации в соответствии с адресом получателя
Linux: ip route
- Нетабличная («целевая») — по отправителю / протоколу / …
- Таблица маршрутизации в соответствии с адресом получателя
- Заполнение маршрутных таблиц:
Специальные адреса и сети (rfc5735)
0.0.0.0/8
"This" Network
rfc1122, Section 3.2.1.3
10.0.0.0/8
Private-Use Networks
127.0.0.0/8
Loopback
rfc1122, Section 3.2.1.3
169.254.0.0/16
Link Local
172.16.0.0/12
Private-Use Networks
192.0.0.0/24
IETF Protocol Assignments
192.0.2.0/24
TEST-NET-1
192.88.99.0/24
6to4 Relay Anycast
192.168.0.0/16
Private-Use Networks
198.18.0.0/15
Network Interconnect Device Benchmark Testing
198.51.100.0/24
TEST-NET-2
203.0.113.0/24
TEST-NET-3
224.0.0.0/4
Multicast
240.0.0.0/4
Reserved for Future Use
rfc1112, Section 4
255.255.255.255/32
Limited Broadcast
*.*.*.*/31
Point-to-Point Links
- Противодействие зацикливанию и TTL
Протоколы сетевого и сетевого/интерфейсного уровня
ARP: Мы знаем IP адресата, и по маске определили, что он находится в локальной сети за интерфейсом, скажем, eth1. Надо инкапсулировать IP-пакет в фрейм и отослать по MAC-адресу… какому? Решение: Address Resolution Protocol (rfc826)
ip neigh — посмотреть таблицу соответствия MAC → IP
Алсо, Proxy ARP (притворяемся, что это наш MAC, а сами втихую пересылаем)
Работа traceroute отсылка пакетов с увеличивающимся TTL и регистрация ICMP-ответов в стиле «пакет не дожил»
- IPSec, RARP, BOOTP (считается прикладным), …
Настройка IP в Linux и табличная маршрутизация
Сетевая маска: количество старших разрядов в двоичном представлении адреса, соответствующих «адресу сети». Оставшиеся младшие биты — адрес абонента в этой сети:
Часто записывается как последовательность 1 в двоичном виде
# ipcalc 10.20.30.40/24 Address: 10.20.30.40 00001010.00010100.00011110. 00101000 Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000 Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111 => Network: 10.20.30.0/24 00001010.00010100.00011110. 00000000 HostMin: 10.20.30.1 00001010.00010100.00011110. 00000001 HostMax: 10.20.30.254 00001010.00010100.00011110. 11111110 Broadcast: 10.20.30.255 00001010.00010100.00011110. 11111111 Hosts/Net: 254 Class A, Private Internet
- Запись в десятичном виде придумали ещё во времена legacy network classes, когда адрес проходил по границе байта. Сейчас это необязательно, а десятичная запись неудобна:
# ipcalc -n 192.168.11.1 Address: 192.168.11.1 11000000.10101000.00001011. 00000001 Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000 Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111 => Network: 192.168.11.0/24 11000000.10101000.00001011. 00000000 HostMin: 192.168.11.1 11000000.10101000.00001011. 00000001 HostMax: 192.168.11.254 11000000.10101000.00001011. 11111110 Broadcast: 192.168.11.255 11000000.10101000.00001011. 11111111 Hosts/Net: 254 Class C, Private Internet
Настройка «выхода в Интернет» в виртуалке (без DNS)
Что представляет собой таблица маршрутизации:
default — это такая сеть с нулевой сетевой маской 0.0.0.0/0 — т. е. весь Интернет. Такой записи соответствует вообще любой пакет.
Заодно посмотрим
- Статус устаревания: REACHABLE → DELAY → STALE → ∅
Настройка внутренней подсети
При настройке IP на сетевом интерфейсе Linux указывается размер подсети, тем самым заполняется таблица маршрутизации записью вида: «такая-то IP-подсеть находится непосредственно за этим сетевым интерфейсом»
- На базовой машине:
На второй (она будет называться router, потому что в дальнейшем послужит маршрутизатором) — практически то же самое (отличие в двух последних битах IP-адреса):
1 router:~# ip link set dev eth1 up 2 router:~# ip addr add dev eth1 10.20.30.2/24 3 router:~# ip r 4 10.20.30.0/24 dev eth1 proto kernel scope link src 10.20.30.2 5 router:~# ping -c2 10.20.30.1 6 PING 10.20.30.1 (10.20.30.1) 56(84) bytes of data. 7 64 bytes from 10.20.30.1: icmp_seq=1 ttl=64 time=1.23 ms 8 64 bytes from 10.20.30.1: icmp_seq=2 ttl=64 time=0.351 ms 9 10 --- 10.20.30.1 ping statistics --- 11 2 packets transmitted, 2 received, 0% packet loss, time 1001ms 12 rtt min/avg/max/mdev = 0.351/0.792/1.234/0.441 ms 13 router:~# ping -c2 10.20.31.1 14 ping: connect: Network is unreachable 15
Адрес сети интерфейса eth1 — 10.20.30.0/24 совпадает с абонентским (10.20.30.1), если применить ту же сетевую маску /24.
Это значит, что с абонентом мы связаны единой средой передачи данных, и сетевая подсистема вправе ожидать появления MAC-адреса этого 10.20.30.1 в ARP-таблице (ip neighbour)
При применении той же сетевой маски к 10.20.31.1 мы получаем адрес 10.20.31.0/24, он ни с чем не совпадает, а других записей в таблице маршрутизации у нас нет — как следствие, сообщение о недостижимости.
Как работает ARP
1.# Зачистим ARP таблицу на srv
Запустим tcpdump -xx -n -i eth1 на router
Запустим ping -c 1 10.20.30.2 на srv
1 srv:~# ping -c1 10.20.30.2 2 PING 10.20.30.2 (10.20.30.2) 56(84) bytes of data. 3 64 bytes from 10.20.30.2: icmp_seq=1 ttl=64 time=0.380 ms 4 5 --- 10.20.30.2 ping statistics --- 6 1 packets transmitted, 1 received, 0% packet loss, time 0ms 7 rtt min/avg/max/mdev = 0.380/0.380/0.380/0.000 ms 8 srv:~# ip n 9 10.20.30.2 dev eth1 lladdr 08:00:27:68:e0:04 REACHABLE 10
Вывод tcpdump:
1 router:~# tcpdump -xx -n -i eth1 2 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode 3 listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes 4 15:37:35.860375 ARP, Request who-has 10.20.30.2 tell 10.20.30.1, length 46 5 0x0000: ffff ffff ffff 0800 2713 c34c 0806 0001 6 0x0010: 0800 0604 0001 0800 2713 c34c 0a14 1e01 7 0x0020: 0000 0000 0000 0a14 1e02 0000 0000 0000 8 0x0030: 0000 0000 0000 0000 0000 0000 9 15:37:35.860393 ARP, Reply 10.20.30.2 is-at 08:00:27:68:e0:04, length 28 10 0x0000: 0800 2713 c34c 0800 2768 e004 0806 0001 11 0x0010: 0800 0604 0002 0800 2768 e004 0a14 1e02 12 0x0020: 0800 2713 c34c 0a14 1e01 13 15:37:35.860960 IP 10.20.30.1 > 10.20.30.2: ICMP echo request, id 3, seq 1, length 64 14 15:37:35.860995 IP 10.20.30.2 > 10.20.30.1: ICMP echo reply, id 3, seq 1, length 64 15
- Широковещательный фрейм «who-has»
- Ответ, в котором есть поле «MAC отправителя»
Поддерживается ядром Linux.
Маршрутизация между двумя сетями
Машина router подключена сразу к двум локальным сетям: в одной из них (intnet) находится srv, в другой — deep — ещё одна машина, client
- маршрутизатор (дополнительно):
- удалённая машина:
1 client:~# ip link set dev eth1 up 2 client:~# ip addr add dev eth1 10.40.60.1/24 3 client:~# ping -c1 10.40.60.2 4 PING 10.40.60.2 (10.40.60.2) 56(84) bytes of data. 5 64 bytes from 10.40.60.2: icmp_seq=1 ttl=64 time=0.322 ms 6 7 --- 10.40.60.2 ping statistics --- 8 1 packets transmitted, 1 received, 0% packet loss, time 0ms 9 rtt min/avg/max/mdev = 0.322/0.322/0.322/0.000 ms 10 client:~# ping 10.20.30.1 11 ping: connect: Network is unreachable 12
Пока что маршрутизировать никто никого не хочет:
Чтобы linux-машина заработала маршрутизатором, надо включить на ней специальную настройку ядра ip_forward:
(или, что то же самое: router:~# echo 1 > /proc/sys/net/ipv4/ip_forward)
Сейчас машина srv не знает о существовании сети 10.40.60.0/24, а client — о 10.20.30.0/24. Надо добавить это знание в таблицу маршрутов. Сделаем это двумя разными способами:
На client зарегистрируем router как маршрутизатор по умолчанию:
На srv зарегистрируем router как маршрутизатор для конкретной сети 10.40.60.0/24
1 srv:~# ip route add 10.40.60.0/24 via 10.20.30.2 2 srv:~# ip r 3 10.20.30.0/24 dev eth1 proto kernel scope link src 10.20.30.1 4 10.40.60.0/24 via 10.20.30.2 dev eth1 5 srv:~# ping -c1 10.40.60.1 6 PING 10.40.60.1 (10.40.60.1) 56(84) bytes of data. 7 64 bytes from 10.40.60.1: icmp_seq=1 ttl=63 time=0.523 ms 8 9 --- 10.40.60.1 ping statistics --- 10 1 packets transmitted, 1 received, 0% packet loss, time 0ms 11 rtt min/avg/max/mdev = 0.523/0.523/0.523/0.000 ms 12
Простая табличная маршрутизация
Итак, чтобы добавить маршрут в таблицу, можно выполнить команду ip route add сеть via маршрутизатор
Все пакеты, адресованные любому абоненту сети, будут направляться на маршрутизатор
Сеть вида 0/0, она же default — это «весь интернет»: любой IP-адрес принадлежит такой сети; так задаётся маршрут по умолчанию
Сеть вида абонент/32 задаёт маршрут типа абонент → маршрутизатор, то есть хост → хост, а не хост → сеть
Правила вида сеть dev интерфейс задаёт локальную сеть, абоненты которой подключены к той же среде пердачи данных, что и интерфейс.
Алгоритм табличной маршрутизации"
- Получаем пакет
- Просматриваем все записи в таблице, из них выбираем те, для которых адрес сети совпадает с адресом сети получателя пакета (если к нему применить соответствующую маску)
- Если настроен маршрут по умолчанию (с сетевой маской длины 0), он всегда подходит
- Среди подходящих записей выбирается та, что имеет самую длинную сетевую маску (т. е. в которой меньше абонентов)
Это происходит автоматически, так как записи уже отсортированы по приоритету (например, default маршрут — последний)
- Если это запись вида «сеть dev интерфейс», обращаемся за адресом к ARP-таблице, если «сеть via адрес» — используем этот адрес
- Пересылаем пакет на найденный адрес
Сети /32 и proxy ARP
Присоединим к маршрутизатору ещё один компьютер single посредством ещё одной среде передачи данных — deep3 — через интерфейс eth3, причём IP-адрес возьмём из диапазона 10.40.60.0/24. Как сделать его достижимым?
- Вариант 1
Разбить 10.40.60.0/24 на две подсети (скажем, 10.40.60.0/25 и 10.40.60.128/25; (можно воспользоваться ipcalc, чтобы посмотреть, почему 128) и перераспределить адреса абонентов так, чтобы после применения сетевой маски абоненты deep оказались в одном диапазоне, а deep2 — в другом.
Потребуется перенастройка всех интерфейсов этих сетей на новую сетевую маску /25
- Вариант 2
Если в deep2 у нас только один абонент single, можно попробовать по протоколу ARP всем рассказывать, что MAC-адрес этого single принадлежит самому router, а когда ему пришлют фрейм для single — декапсулировать и маршрутизировать его!
- Воспользуемся вариантом маршрутизации вида «сеть/32 → интерфейс» и «абонент/32 → интерфейс»:
1 router:~# ip l set eth3 up 2 router:~# ip addr add 10.40.60.102/32 dev eth3 3 router:~# ip route add 10.40.60.100/32 dev eth3 4 router:~# ip addr show dev eth3 5 5: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 6 link/ether 08:00:27:65:97:e6 brd ff:ff:ff:ff:ff:ff 7 altname enp0s10 8 router:~# ip route 9 10.20.30.0/24 dev eth1 proto kernel scope link src 10.20.30.2 10 10.40.60.0/24 dev eth2 proto kernel scope link src 10.40.60.2 11 10.40.60.100 dev eth3 scope link 12
Настройка адреса в сети 10.40.60.102/32 — это способ «привесить» интерфейсу адрес, ничего при этом не меняя в таблице маршрутизации (потому что сетевая маска занимает все 32 бита: в такой сети ровно один абонент, не имеющий собственного адреса; или, что то же самое, его адрес совпадает с адресом сети).
Если адрес получателя в пакете отвечает сразу нескольким записям в таблице маршрутизации, выбирается запись с наибольшей сетевой маской (т. е. «самая определённая»)
В таблицу заносится правило вида «абонент → интерфейс», которое утверждает, что за интерфейсом eth3 доступен абонент 10.40.60.100. Поскольку сетевая маска такого правила максимальна (/32), оно считается наиболее приоритетным.
- Воспользуемся вариантом маршрутизации вида «сеть/32 → интерфейс» и «абонент/32 → интерфейс»:
На новом абоненте (назовём его single):
1 single:~# ip link set dev eth1 up
2 single:~# ip addr add dev eth1 10.40.60.100/32
3 single:~# ip route add 10.40.60.102/32 dev eth1
4 single:~# ip route add default via 10.40.60.102
5 single:~# ip r
6 default via 10.40.60.102 dev eth1
7 10.40.60.102 dev eth1 scope link
8 single:~# ping -c1 10.20.30.1
9 PING 10.20.30.1 (10.20.30.1) 56(84) bytes of data.
10 64 bytes from 10.20.30.1: icmp_seq=1 ttl=63 time=1.29 ms
11
Proxy ARP
Однако не всё ещё работает. Например, single недоступен с абонента clone, находящегося в «старой» сети:
1 client:~# ping -c1 10.40.60.100 2 PING 10.40.60.100 (10.40.60.100) 56(84) bytes of data. 3 From 10.40.60.1 icmp_seq=1 Destination Host Unreachable 4 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms 5 client:~# ip r 6 default via 10.40.60.2 dev eth1 7 10.40.60.0/24 dev eth1 proto kernel scope link src 10.40.60.1 8 client:~# ip n 9 10.40.60.100 dev eth1 FAILED 10
Почему так? Маршрут вида 10.40.60.0/24 dev eth1 говорит о том, что за интерфейсом eth1 находится вся сеть 10.40.60.0/24 и, стало быть, мы вправе ожидать появления 10.40.60.100 в ARP-таблице. Но взяться ему там неоткуда: в действительности же этот абонент находится совсем в другой сети, и на arp-запрос ответа не приходит.
Решение: попросить router отвечать на приходящий из старой сети ARP-запрос адреса 10.40.60.100 что-то вроде «всё в порядке, это мой IP». Тогда у абонентов создастся впечатление, что router просто имеет два IP-адреса на соответствующем интерфейсе, и они начнут использовать при инкапсуляции на интерфейсный уровень тот же самый MAC-адрес. Получив такой фрейм, router обнаружит там IP-пакет для 10.40.60.100, и перешлёт его.
Теперь работает:
Обратите внимание на совпадение MAC-адресов, которые clone считает закреплёнными за 10.40.60.100 и 10.40.60.2
Proxy ARP можно включить на нескольких интерфейсах целиком:
За это отвечает специальный sysctl, (net.ipv4.conf.интерфейс.proxy_arp, он же /proc/sys/net/ipv4/conf/интерфейс/proxy_arp).
- С точки зрения абонентов устройство с такой настройкой будет работать как bridge, то есть роутер уровня 2 — интерфейсного. Много интерфейсов — единое адресное пространство, в ARP-таблицах видны все абоненты.
- Однако в действительности маршрутизация будет идти на уровне 3, то есть IP, сетевом: полученный фреймы будут декапсулироваться до IP-пакетов, и на основании IP-адреса будет происходит пересылка (с последующей инкапсуляцией в фрейм).
IPv6 (если успеем)
Адрес (IPv6_address)
- 128 бит, включает идентификатор интерфейса (например, MAC или его хэш)
- Unicast: [48+] — routing prefix; [16-] — subnet id; [64] — interface identifier
- Unicast / Anycast / Multicast (нет широковещания, оно — частный случай multicast)
- Link-local адреса: уникальны только в рамках одного сегмента связи
Запись: 2001:0db8:85a3:0000:0000:8a2e:0370:7334 == 2001:db8:85a3::8a2e:370:7334
- 128 бит, включает идентификатор интерфейса (например, MAC или его хэш)
- Нет фрагментации на маршрутизаторе (либо PMTUD, либо на стороне отправителя)
- Нет CRC заголовка (есть же в data link)
- Маршрутизация
- (адрес)/(битовый размер префикса) — как в IPv4
- + Multicast (IGMP) / Anycast и т. п.
Д/З
Образ не изменился.
Задание 4
- Суть: объединить четыре компьютера тремя сетями по простой линейной схеме:
clone ←сеть3→ router2 ←сеть2→ router1 ←сеть1→ base
На машинах clone и base — по одному интерфейсу
На машинах router2 и router1 — два, там настроить маршрутизацию
Обеспечить доступность между clone и base
- Отчёт (выполнятся с нуля на ненастроенных машинах):
report 4 clone
- Настройка/поднятие интерфейса
- Дополнительные настройки маршрутизации (если нужны)
tcpdump -c4 (должен показать пинги)
report 4 router2
- Настройка/поднятие двух интерфейсов
- Дополнительные настройки маршрутизации (если нужны)
report 4 router1
- Настройка/поднятие двух интерфейсов
- Дополнительные настройки маршрутизации (если нужны)
report 4 base (выполняется последним)
- Настройка/поднятие интерфейса
- Дополнительные настройки маршрутизации (если нужны)
ping -c4 адрес_clone (должен проходить)
Четыре отчёта (report.04.base, report.04.router1, report.04.router2 и report.04.clone) именно с такими названиями переслать одним письмом в качестве приложений на uneexlectures@cs.msu.ru
В теме письма должно встречаться слово LinuxNetwork2023