From: Roman Shramko <http://dormestmass.blogspot.com>
Date: Mon, 20 Dec 2007 14:31:37 +0000 (UTC)
Subject: Борьба с битом DF и черными дырами или как фрагментировать нефрагментируемое
В заголовке IP пакета имеется один интересный флаг -"don't
fragment" или сокращенно DF. Назначение сего флага - запретить
разбивку пакета на фрагменты. Честно говоря, ситуации, когда
встречаются пакеты с этим флагом довольно редки, но они таки бывают и
могут надолго испортить настроение администратору/пользователю вот по
какой причине.
Различные технологии канального уровня предусматривают различный
размер MTU. И вполне естественно, что на пути следования трафика между
сервером и клиентом могут попадатся сегменты с разными размерами MTU.
На схеме ниже показана ситуация, когда клиент подключен к сети через
GRE-туннель, у которого размер MTU на 24 байта меньше, чем у
исходящего реального интерфейса. Клиент хочет произвести некий
обмен трафиком с удаленным сервером, а вот сервер выставляет этот
самый флаг на свои исходящие пакеты.
Происходит следующая ситуация. Во время установки TCP-сессии клиент и
сервер анонсируют свои максимальные размеры сегментов (maximum segment
size или MSS), показывая друг другу какие максимальные TCP сегменты
они могут принимать. После получения опций MSS устройства вычисляют
максимальный размер сегмента, который будет посылатся удаленной
стороне (Send Max Segment Size или SMSS). SMSS будет равен размеру
меньшего MSS. Процедура установки TCP MSS описана в RFC 879.
В нашем случае как у клиента, так и у сервера максимальный размер
сегментов, которые они могут обработать - 1500 байт, ибо подключены
они к своим маршрутизаторам по локальной сети. Соответственно SMSS для
TCP сессии будет установлен в 1500.
Когда пакет размером 1500 байт от сервера придет на Router B, то
естественно, что тот не сможет его передать в интерфейс, у которого
MTU равен 1476 байт. В нормальной ситуации, когда флаг DF не
установлен, Router B произведет фрагментацию пакета, создав 2
фрагмента.
В случае же с установленным флагом, запрещающим фрагментацию пакетов,
Router B произведет попытку сообщить серверу о том, что необходимо
слать пакеты меньшего размера. Для этого, ему (серверу) будет послано
ICMP сообщение - тип 3 код 4 (Destination Unreachable; Fragmentation
Needed and DF set). В этом сообщении содержится размер MTU, который
следует использовать серверу. Приблизительно это выглядит так:
C:>ping 10.10.10.10 -f -l 1473
Pinging 10.10.10.10 with 1473 bytes of data:
Packet needs to be fragmented but DF set.
Packet needs to be fragmented but DF set.
В данном примере был умышленно завышен размер данных, чтобы размер
пакета составил 1501 байт - 1473 + 28 байт заголовка и пакет был
отброшен.
Вот тут-то и кроется подвох. Если маршрутизатор не отправляет ICMP
сообщения (а такие маршрутизаторы принято называть "черными дырами")
или доставка ICMP сообщений данного типа будет заблокирована для
сервера, то он никогда и не узнает, что необходимо посылать пакеты
меньшего размера.
Побороть такую ситуацию можно несколькими путями.
1. Уменьшить размер MTU на сетевом интерфейсе у клиента, чтобы
автоматически уменьшить SMSS. Соответственно у Router-а B исчезнет
необходимость фрагментировать пакеты. Однако если у нас за
Router-ом А находится большая сеть, то придется менять MTU на всех
машинах.
2. Пустить туннель через физический линк, который будет иметь MTU
больше чем 1500 + размер заголовка. В нашем случае это 1524. Такое
решение не всегда и не везде уместно.
3. Изменить опцию TCP MSS в SYN-пакетах, которые проходят через
роутер.
Для маршрутизаторов Cisco это можно сделать следующим образом:
interface tunnel0
...
!MTU - size of IP,TCP and GRE headers = 1436 bytes
ip tcp adjust-mss 1436
...
Эта опция доступна в IOS 12.2(4) и выше.
Для маршрутизаторов на основе linux:
iptables -A FORWARD -p tcp -tcp-flags SYN,RST SYN -j TCPMSS -set-mss 1436
Для xBSD, которые используют packet filter (pf):
...
scrub in on fxp0 all max-mss 1436
...
4. Снимать с IP пакетов флаг DF. Соответственно пакеты станет
возможно фрагментировать и проблема исчезнет. В маршрутизаторах
cisco можно это сделать при помощи policy routing-а:
interface FastEthernet 0/0
! Это интерфейс, который смотрит нам в локальную сеть
...
ip policy route-map clear-df
!
route-map clear-df permit 10
match ip address 150
set ip df 0
!
access-list 150 remark clear df bit for this traffic
access-list 150 permit tcp 10.0.0.0 0.255.255.255 any
К сожалению, судя по форумам, на цисках возможны грабли с CEF при
применении policy routing.
В Линухах операции с DF помоему невозможны. Не буду утверждать
категорично, поскольку не использую на роутерах Linux. Однако я
встречал патчи ядра, которые добавляют эту функциональность в
netfilter.
Для pf это делается так:
...
scrub in on fxp0 all no-df
...
На своих роутерах я использую вариант со снятием флага DF, т.к. при
минимальных трудозатратах это даст эффект для всего траффика, а не
только для TCP (в случае использования adjust-mss).
Существует ещё один метод борьбы DF при использовании именно туннелей,
который я сознательно не привел в вышеперечисленном списке. Это -
увеличение MTU самого туннельного интерфеса. В этом случае
передаваемые пакеты начнут фрагментироватся, поскольку бит DF из
оригинального пакета не копируется в заголовок пакета туннеля. На
другом конце туннеля роутер соберет GRE пакет (ну или другой
туннельный пакет, если мы говорим о другом типе туннеля) из фрагментов
и отфорвардит инкапсулированный пакет дальше. Большой недостаток этого
решения - сильно увеличатся накладные расходы, т.к. при практически
все туннельные пакеты будут фрагментированны.
676 Прочтений • [Борьба с битом DF и черными дырами или как фрагментировать нефрагментируемое (mtu tcp packet tcpip fragment mss cisco)] [08.05.2012] [Комментариев: 0]