Как стать автором
Обновить

IP MTU: как перестать жить и начать ботать заголовки

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров6K
Автор оригинала: Iaroslav Bondarenko

Старина IPv4… В сетевом мире он распространён так же, как и воздух на Земле. Однако несмотря на то, что миллионы людей используют этот протокол в повседневной жизни, у IPv4 всё ещё есть пара сюрпризов в рукаве. Сегодня мы рассмотрим один из них.

Очень простая схема из 4 маршрутизаторов, выстроенных в цепь:

На каждом устройстве настроена базовая адресация и включён EIGRP на всех интерфейсах:

R2#show run | section router|interface FastEthernet
interface FastEthernet0/0
 ip address 192.168.12.2 255.255.255.0
interface FastEthernet0/1
 ip address 192.168.23.2 255.255.255.0
router eigrp 1
 network 0.0.0.0

По умолчанию, IP MTU на каждом интерфейсе равен 1500. Это означает, что допустимый размер пакета, включая заголовки и полезную нагрузку, не превышает 1500 байтов; если же пакет больше, то его следует фрагментировать. Предположим, что MTU на интерфейсах R2-R3 равен 1400 с обеих сторон:

R2#show run interface fastEthernet0/1

interface FastEthernet0/1
 ip address 192.168.23.2 255.255.255.0
 ip mtu 1400

На сколько фрагментов будет разделён пакет размером 1500 байтов?

R1#ping 4.4.4.4 source 1.1.1.1 size 1500 repeat 1
Type escape sequence to abort.
Sending 1, 1500-byte ICMP Echos to 4.4.4.4, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1 
!
Success rate is 100 percent (1/1), round-trip min/avg/max = 68/68/68 ms

Согласно учению начальной школы, такой пакет превратится в 2 фрагмента. Неожиданно то, что ответ на пинг тоже оказывается фрагментирован. Однако странным это кажется только на первый взгляд: ICMP echo reply обязан нести на себе ту же полезную нагрузку, что и изначальный пакет.

Уменьшим MTU до 700 байтов на обоих интерфейсах и проверим, можно ли пропихнуть ровно 2 фрагмента по 700 байтов через них. IP-заголовок занимает 20 байтов, поэтому данных в первоначальном пакете должно быть 680*2 + 20 = 1380 байтов (значение IP MTU включает в себя и длину заголовков).

R1#ping 4.4.4.4 source 1.1.1.1 size 1380 repeat 1
Type escape sequence to abort.
Sending 1, 1380-byte ICMP Echos to 4.4.4.4, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1 
!
Success rate is 100 percent (1/1), round-trip min/avg/max = 48/48/48 ms

А теперь к гвоздю сегодняшней программы: волшебному значению MTU в 725 байтов.

R1#ping 4.4.4.4 source 1.1.1.1 size 1430 repeat 1    
Type escape sequence to abort.
Sending 1, 1430-byte ICMP Echos to 4.4.4.4, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1 
!
Success rate is 100 percent (1/1), round-trip min/avg/max = 48/48/48 ms

И так, 20 байтов заголовка и 1410 байтов данных превращаются… в 3 фрагмента? С каких пор 705 + 20 ≠ 725?

По правде говоря, в числе 725 не больше волшебства, чем в любом другом числе, не кратном 8. Засада прячется в поле Fragment Offset, которое содержит сдвиг данных фрагмента относительно данных первоначального пакета.

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Identification        |Flags|      Fragment Offset    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Time to Live |    Protocol   |         Header Checksum       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Source Address                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Destination Address                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Этот сдвиг измеряется в хитрых единицах – по 8 байтов. Поскольку 705 на 8 не делится, маршрутизатор выбирает ближайшее к 705 кратное – 704.

Алгоритм, по которому нужно выбирать размер фрагментов, не фиксирован в RFC. В нашем случае R2 предпочёл отправить 8 байтов со вторым фрагментом, а остальные данные оставить последнему.

Вообще, конечные устройства всячески стараются избежать фрагментации с помощью разных механизмов, например, PMTUD, TCP MSS. Такое поведение сводит на нет шансы наступить на грабли, связанные с неожиданным количеством фрагментов от одного пакета. Впрочем, иногда же надо как-то обосновать требование разобраться с заголовками используемых протоколов?..

За рецензию большое спасибо Анастасии Куралёвой.

Теги:
Хабы:
Всего голосов 12: ↑11 и ↓1+10
Комментарии1

Публикации

Истории

Работа

Ближайшие события

Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург