Идентификатор фрагмента – необходим для однозначной идентификации каждого посланного пакета данных при их фрагментации. Фрагментация (см. раздел 1.2.2) происходит при попытке передать пакет длиннее, чем позволяет данное межсетевое соединение, например, маршрутизатор на пути следования пакета имеет меньшее MTU. Стартовое значение идентификатора выбирается произвольным образом и обычно инкрементируется для всех последующих пакетов; все фрагменты оригинального пакета при последующей фрагментации на маршрутизаторах будут иметь один и тот же идентификатор. Каждая технология локальной сети имеет свой технически обусловленный "максимальный размер пакета" – MTU, Maximum Transfer Unit – максимальный размер полезных данных, переносимых по физической линии связи. Для сетей Ethernet это как правило 1500 байт (некоторые версии до 1514 байт), FDDI – 4096, Token Ring – 4464 байт, ATM - 9188 байт, в других – 296 или 128 байтов (в сетях Х.25.) Использование заголовка SNAP со стандартом Ethernet_802.3 ограничивает размер до 1492 байтов (некоторое оборудование допускает несколько большие кадры), в то время как proNET-10 допускает кадры до 2044 байтов. Многие разработчики сетевых программ считают оптимальным значением MTU= 576. Связано это со следующим обстоятельствам. Для протокола TCP существует понятие MSS – Maximum Segment Size (см. раздел 1.7.1). Если при установлении соединения одна из сторон не принимает значение MSS, то оно принимается равным 536. 536+40 (40 байтов заголовков TCP и IP) и дает значение 576. Минимальное значение MTU для IPv4, называемое канальным MTU, составляет 68 байт. П р им еч а н ие Существует также термин PMTU -- Path Maximum Transfer Unit -- максимальный размер пакета для выбранного пути -- опция для некоторых ОС, заставляющая систему вычислять максимальный размер пакета, при котором не потребуется фрагментация пакетов, для маршрута к заданному хосту, включая все промежуточные переходы. Флаги и смещение фрагмента – позволяют правильно собрать фрагментированный пакет. Флаг DF "Don’t Fragment" – обозначает указание для IP-модуля маршрутизатора запрет на фрагментацию данного пакета. Если этот бит установлен в единицу, IP-модуль не будет фрагментировать пакет, что повышает производительность IP-модуля всвязи с уменьшением времени обработки передаваемых пакетов. Вместо этого пакет уничтожается, а отправителю посылается ICMPсообщение об ошибке "Фрагментация необходима, однако установлен бит не фрагментировать" (Fragmentation needed but don't fragment bit set). Эта ошибка может быть использована программой, которой необходимо определить минимальный MTU в маршруте до пункта назначения – что называется механизмом определения транспортного MTU (MTU path discovery). Впрочем, некоторые маршрутизаторы могут не посылать сообщения о том, что "фрагментация необходима, однако установлен бит не фрагментировать", и пакет как бы исчезает в "черной дыре" - "Black Hole". Существует специальный алгоритм – PMTUBlackHoleDetect – для обнаружения таких маршрутизаторов. Флаг MF, установленный в единицу означает, что "дальше следуют еще фрагменты" (More Fragments). Этот бит устанавливается в единицу для каждого фрагмента, кроме последнего – при условии отсутствия многократной фрагментации. Поле смещения фрагмента (Fragment Offset) содержит смещение этого фрагмента от начала поля данных исходного пакета. Когда пакет фрагментируется, поле полной длины в заголовке каждого фрагмента изменяется так, чтобы соответствовать размеру фрагмента. Модуль TCP старается избежать фрагментации, и для приложения практически невозможно заставить TCP отправлять сегменты, которые нуждаются во фрагментации (в IPv6 это не совсем так). То есть, другими словами, отправить сегмент такого размера, для которого сразу потребуется фрагментация, в IPv4 практически невозможно. 1.1.1. Фрагментация пакетов IPv4 Как мы знаем, практически все сетевые технологии имеют ограничение на максимальную длину передаваемого блока полезных данных, называемую "блок данных максимальной длины" или MTU (Maximum Transfer Unit). Если блок данных имеет большую длину, он автоматически разбивается на части меньшей длины, каждая из которых передается затем по отдельности. Это и есть фрагментация. Фрагментация происходит в случае, если длина пакета превосходит MTU физического сетевого уровня. Однако она также происходит, когда пакет попадает в маршрутизатор с MTU меньшим, нежели MTU локальной сети отправителя. Для управления фрагментацией IP использует второй и последний биты в трехбитовом поле флагов. Существуют некоторые приложения, данные которых действительно нельзя фрагментировать. Включая режим "фрагментация запрещена", то есть устанавливая соответствующий бит, имейте в виду, что если модуль IP обнаружит, что фрагментация все-таки должна произойти, то он отбросит IP-пакет и вернет сообщение об ошибке источнику пакета. Безусловно, для повышения эффективности и производительности модуль IP всегда пытается послать пакет наибольшего допустимого размера. Однако иногда фрагментации не избежать. Существует по крайней мере два подхода к построению алгоритма фрагментации. В первом из них, который применяется в Windows-системах, используется алгоритм с вычислением точки деления (breaking point), которую модуль IP рассчитывает в соответствии со значением MTU низлежащего уровня сети. Точка деления — это расположение байта в пакете, на котором произойдет разделение. Точка деления представляет собой смещение (расстояние) от начала данных пакета. Каждая точка деления записывается IP-модулем в поле "смещение фрагмента" заголовка только что собранного IP-пакета. Другими словами, IP-заголовок каждого пакета содержит смещение данного фрагмента относительно начала данных первоначального пакета. В действительности размер каждого фрагмента слегка отличается от значения MTU. На рис. 1.4 приведена структура IP-заголовка. Обратите внимание на то, что длина поля длины пакета равна 16 битам, а поля смещения фрагмента — тринадцати. Длина поля длины пакета в шестнадцать битов означает, что максимальная длина пакета может равняться 65535 битам. Поле смещения фрагмента должно уметь обозначить точку смещения на всей длине IP-пакета, следовательно, должно адресовать от 1 до 65536 байтов (или от 0 до 65535). Однако длина поля смещения фрагмента равна всего тринадцати битам и, следовательно, может принимать значения в интервале от 0 до 8191, позволяя адресовать максимум 8192 байт. Если значение поля смещения фрагмента кратно 8 байтам, проблема решается. Например, значение поля смещения 1 означает смещение в восемь байтов, 2 — в шестнадцать и т. д. Максимальное смещение при этом равно 65528 (8191*8). Число 65528 указывает на последние восемь байтов пакета максимально возможной длины: 65528 плюс 7 равно 65535 (максимальная длина пакета). Процесс фрагментации таков. Модуль IP вычисляет начало (смещение) каждого фрагмента относительно начала пакета. Длина каждого фрагмента, созданного IP, кратна восьми байтам. Смещение фрагмента относительно начала данных пакета записывается в поле "смещение фрагмента" IP-заголовка нового пакета, содержащего данный фрагмент. Поле "фрагментпродолжение" устанавливается в единицу для каждого вновь образованного пакета, кроме последней (при условии, что не было вложенной фрагментации). Поле "фрагмент-продолжение" пакета, переносящего последний фрагмент, устанавливается модулем IP в ноль, поскольку фрагментов больше не будет. Рассмотрим пример. Пусть MTU=128, а длина данных исходного пакета – 730 байт. Значит, наши новые пакеты-фрагменты не должны быть больше 128 байт, и тогда поле данных составит 12820=108 байт. Но число 108 не делится нацело на 8, что должно было бы гарантировать выравнивание на границу 8-ми байт. Ближайшее число, удовлетворяющее этому условию - это 104. Далее получаем: 730=7*104+2. Таким образом, у нас будет 7 новых пакетов 20+104=124 байта длиной каждый и последний пакет-фрагмент 20+2=22 байта - всего 8 пакетов. Применяя этот алгоритм, мы всегда будем иметь размер последнего пакета меньшим (или равным), чем предыдущий. В UNIX–системах применяется другой подход. Для нашего примера мы тоже будем иметь базовое число в 104 байта и будем последовательно слать 6 пакетов, содержащих 6*104=624 байта исходных данных. После отсылки 6-го пакета окажется, что данных осталось 106 байт. Если добавить к ним 20 байт заголовка, последний 7-ой пакет будет иметь длину в 126 байт (больше, чем 124), но все равно меньше MTU. А так как он последний, для него кратность 8-ми не имеет никакого значения. В результате Windows-алгоритм пошлет 8 пакетов, а UNIX – 7! Глубокие знания механизма фрагментации особенно нужны сетевым администраторам, так как его понимание является залогом успешного анализа трафика (отделения нормальной фрагментации от злоумышленной, которая также может применяться для успешной реализации атак типа «отказа в обслуживании», DoS) с целью выявления потенциально опасных для системы данных. Сборка фрагментов IP-модуль на принимающем IP-фрагменты узле в ситуации, когда он должен транслировать IPсегмент далее по сети, имеет три варианта действий с фрагментами: 1. переслать IP-фрагменты далее неизменными; 2. разбить (если в этом есть необходимость) полученные IP-фрагменты на еще более короткие IPфрагменты; 3. восстановить исходный IP-пакет из фрагментов. Разберем процесс сборки фрагментированных данных. Модуль IP исследует содержимое полей управления фрагментацией IP-заголовка пакета, то есть поля идентификации, флагов и смещения фрагмента. C приходом первого фрагмента IP-пакета запускается специальный таймер сборки и устанавливается в исходное состояние (для UNIX-реализаций это, обычно, 30 сек). Далее таймер начинает обратный отсчет. До момента обнуления таймера должны прийти все IP-фрагменты, относящиеся к этому пакету. Если время истекло, а все фрагменты так и не появились, модуль IP отбрасывает уже принятые фрагменты и не обрабатывает частично принятый пакет. Компьютер-приемник располагает пакет в буфере для сборки. Фрагменты, принадлежащие одному пакету, определяются по адресу источника и полю идентификатора в IP-заголовке. Как только приходит пакет с битом "фрагмент-продолжение", равным нулю, модуль IP может подсчитать общую длину пакета. Выяснив первоначальную длину исходного пакета, модуль IP приступает к изучению полей смещения фрагмента и длины пакета в остальных фрагментах. Теперь модуль IP знает, что в его буфере находится полностью принятый пакет и его можно собрать целиком. Далее исходный пакет собирается, основываясь на известных значениях полей смещения каждого фрагмента. Рассмотрим эффект фрагментации. Во-первых, отдельный независимый пакет становится набором из нескольких пакетов. Каждый из пакетов-частей оказывается зависимым от других в передаваемой последовательности фрагментов. Если сеть теряет один фрагмент, сетевой уровень отбрасывает все остальные фрагменты. Во-вторых, статистика показывает, что чем больше фрагментов, тем выше вероятность потери одного из них и, следовательно, исходного пакета в целом. Вывод: если в сети происходит фрагментация, вероятность потери пакета увеличивается. Протокол TCP часто пользуется MTU, равным 576 байтам, для передачи данных компьютерам через несколько маршрутизаторов. Эта длина выбрана не случайно. Она позволяет разместить в пакете 512 байтов данных и оставить место для TCP и IP-заголовков и опций. Большинство протоколов уровня соединения могут работать с таким MTU, следовательно, не фрагментируя данные до передачи по каналу связи. В зависимости от назначения и функций вашего TCP/IP-приложения, может оказаться возможным, заранее проанализировав пути, по которым пойдут данные, выбрать MTU большего размера, не рискуя подвергнуть данные фрагментации. Пример фрагментации Фрагментация и процедура повторной сборки должны быть способны разбить пакет на произвольное число частей, которые могут быть позже повторно собраны. Получатель фрагментов использует поле идентификации, чтобы гарантировать, что фрагменты не перемешаны. Смещение фрагмента и длина определяют часть первоначального пакета, замещенную этим фрагментом. Флажок more-fragments указывает последний фрагмент. Эти поля обеспечивают достаточную (но не всю) информацию, чтобы осуществить сборку. Поле идентификации используется, чтобы отличить фрагменты одного пакета от других. Все фрагменты данного пакета должны иметь одинаковое значение этого поля. Модуль протокола, порождающий пакет, устанавливает поле идентификации в значение, которое должно быть уникально для пары "исходный адресат" и "протокол" в течение всего времени, пока пакет активен в системе Интернета. Чтобы фрагментировать длинный пакет, модуль IP-протокола (например, в шлюзе) создает новые пакеты и копирует содержание полей заголовка из длинного пакета в новые заголовки. Поле данных длинного пакета затем делится на N равных частей на границе, кратной 8 байтам (64 бит). При этом сумма длины заголовка + длина первой порции не должна превышать MTU сети, через которую будет пересылаться новый пакет. Вторая порция и последующие могут не быть кратны 8-ми байтам. Назовем число восьмибайтовых блоков в первой порции NFB (Число Блоков Фрагмента). Первая часть данных помещается в первую новый пакет, и поле суммарной длины в заголовке устанавливается равным длине первого пакета. Флаг "more fragments" устанавливается в 1. Вторая часть данных помещается во втором новом пакете, и поле общей длины пакета устанавливается равной длине второго пакета. Флаг "more fragments" имеет то же самое значение, которое было установлено в первоначальном пакете. Поле смещения фрагмента второго нового пакета устанавливается равным значению этого поля в оригинальном длинном пак6ете плюс NFB. Эта процедура может быть обобщена для разбиения на N частей. Рассмотрим процесс фрагментации более подробно на следующем примере. IP-модуль на некотором узле получил IP-пакет с идентификатором 9876 и данными длиной 300 байт (при этом бит запрета фрагментации DF установлен в 0). Этот IP-пакет должен быть передан дальше к адресату через сеть, MTU которой равен 128 байтам. Ниже схематично представлено разбиение исходного IP- пакета на три IP-фрагмента. Исходный IP- пакет Заголовок | Данные (300 байт) IP-фрагмент 1 IP-фрагмент 2 IP-фрагмент 3 Заголовок 1 | 104 Заголовок 2| 104 Заголовок 3 | 92 байта байта байта IP-фрагмент 1 содержит в своем заголовке следующую информацию: 1. Идентификатор – 9876; 2. Длина заголовка – 5 (четырехбайтных слов); 3. Длина пакета – 124 (байт); 4. Бит MF – 1; 5. Смещение фрагмента – 0 (восьмибайтных единиц). IP-фрагмент 2 содержит в своем заголовке следующую информацию: 1. Идентификатор – 9876; 2. Длина заголовка – 5 (четырехбайтных слов); 3. Длина пакета – 124 (байт); 4. Бит MF – 1; 5. Смещение фрагмента – 13 (восьмибайтных единиц). IP-фрагмент 3 содержит в своем заголовке следующую информацию: 1. 2. 3. 4. 5. Идентификатор Длина заголовка Длина пакета Бит MF Смещение фрагмента – 9876; – 5 (четырехбайтных слов); – 112 (байт); – 0; – 26 (восьмибайтных единиц). Заметим, что так как смещение фрагмента измеряется в восьмибайтных единицах, то длина данных в каждом IP-фрагменте (кроме последнего в цепочке) обязательно должна быть кратна 8. Вот почему в нашем примере это 104 байта (13 восьмибайтных единиц), а не 108, как допускает максимальная длина кадра в 128 байт (128 – 20 = 108, где 20 – длина заголовка). Чтобы собрать все фрагменты пакета в первоначальный оригинальный пакет, модуль IPпротокола компьютера-приемника объединяет те IP-пакеты, которые имеют одинаковые значения в четырех полях заголовка - требование RFC-791: идентификатор, источник, получатель и протокол. Сборка осуществляется помещением части данных каждого фрагмента в относительной позиции, обозначенной смещением фрагмента в заголовке соответствующего пакета. Первый фрагмент будет иметь нулевое смещение, а последний фрагмент будет иметь сброс флага "more fragments" – правда, как уже отмечалось, не всегда – если имеет место фрагментация "уже фрагментированных пакетов".