Linux Network Administration — Механизм PMTUD
Долго думал, какой блог выбрать, сначала склонялся к "Пятиминутке ненависти", но "Linux Network Administration" победил.
Вообще, написать об этой не очевидной сетевой проблеме, проявляющейся по-разному, но имеющей один корень, меня побудил один интересный случай.
Совсем недавно одному удаленному бухгалтеру понадобилось подключаться по RDP к нашему терминальному серверу для работы с 1C. Виндовый админ выделил нужные права, завел учетку, с моей стороны тоже проблем нет: IP клиента статический, а RDP использует TCP порт 3389, который сразу и был проброшен на терминальный сервер:
Проверили конфигурацию с внешнего компьютера, успешно соединились, клиенту сразу был дан ответ «Готово, подключайтесь». Ко всеобщему удивлению клиент не смог соединиться, с его стороны соединение «зависало», не выдавая ошибок.
Мы проверили конфигурацию с еще нескольких внешних компьютеров, и везде соединение шло гладко. Пришлось списаться с их сисадмином, который, вместо того, чтобы подумать вместе, заявил, что проблема явно у нас, и что его клиенты подключаются таким образом ко многим серверам, а его ISA (это, вроде, такой виндовый фаерволл) и вовсе безупречна. Несколько дней я ломал голову над этой проблемой, даже временно частично или полностью отключал фаерволл, после чего выяснилось, что консольный-то доступ к терминалу у клиента работает.
Подозрение сразу пало на некорректный MTU, так как присутствовал самый явный симптом: текстовая информация и прочая мелочь размером до полутора килобайт передавалась успешно, а с более весомой графикой возникали проблемы.
Здесь хотелось бы подробнее остановиться на замечательной технологии определения максимального размера передаваемого сегмента в протоколе TCP — Path Maximum Transmission Unit Discovery или просто PMTUD. Два компьютера (клиент и сервер) начинают сессию передачи данных с SYN и SYN-ACK пакетов, которые содержат информацию о MSS — Maximum Segment Size — это характеристика протокола TCP, сообщающая максимально допустимый размер передаваемого сегмента. Так это выглядит:
Видно, что для одного компьютера MSS равен 1452, для другого 1412. Из этих двух значений выбирается наименьшее. В этой сессии размер любого сегмента обязательно будет меньше либо равен 1412 байт:
Путать MSS и MTU не стоит, последний — характеристика сетевого интерфейса, а не протокола. Ну, и конечно, MSS напрямую зависит от MTU и вычисляется как MTU — 20 (размер IP-заголовка) — 20 (размер TCP заголовка).
Таким образом, клиент и сервер могут обмениваться между собой информацией, посылая TCP-пакеты определенного размера с установленным битом «DF: Don't Fragment». Но если на пути между ними обнаружится узел, не способный передать пакет размером 1452 байта (1412+40), этот узел отбросит пакет и сформирует отправителю специальный ICMP пакет с типом 3 (Destination Unreachable) и кодом 4 (fragmentation needed and DF set), который, кроме самой ошибки, будет содержать информацию о максимально допустимом сегменте передачи.
Отправитель получает его, меняет свой MSS на еще более меньший и передача успешно продолжается. Это теория.
На практике же где-то между мной и клиентом эти столь необходимые ICMP-пакеты с информацией о фрагментации просто терялись. И передающая сторона, не получая ошибку, повторяла попытки передачи снова и снова, ожидая подтверждения приемной.
Эту проблему помог решить iptables. В таблице mangle он умеет изменять то самое передаваемое значение mss в SYN и SYN-ACK пакетах при помощи цели TCPMSS:
Это правило берет SYN-пакет, отправленный хостом клиента, и меняет его значение mss на 1452 (определял подбором). После того, как правило было прописано, у клиента все заработало, и все остались довольны.
Случай второй.
Наши плановики начали работать со специальной вебмордой на удаленном сервере. Оформление этого сайта не содержало каких-либо тяжелых объектов или графики, навигация по сайту работала прекрасно. Но среди используемых ими функций была «Формирование отчета в excel», которая просто «зависала» в ожидании ответа от сервера. На удаленной стороне ответили «У всех все работает» и предложили искать проблему у себя.
После некоторых размышлений, решил просто пропинговать их сервер, чтобы проверить присутствие icmp — и да, пинг не шел. Точно таким же образом, в iptables для серверного хоста был прописан еще меньший mss - 1380, после чего плановики смогли работать нормально.
Случай третий. Заметил недавно, что в очереди писем postfix на протяжении нескольких дней стали скапливаться письма на один и тот же домен, с одной о той же необычной причиной отсрочки:
ADC2F308358: from=, size=33628, nrcpt=2 (queue active)
ADC2F308358: enabling PIX workarounds: disable_esmtp delay_dotcrlf for mailserver.com[22.22.22.22]:25
ADC2F308358: to=, relay=mailserver.com[22.22.22.22]:25, delay=333009, delays=332827/0.02/1.5/181, dsn=4.4.2, status=deferred (conversation with mailserver.com[22.22.22.22] timed out while sending message body)
Жизнь, что называется, научила, поэтому первым делом проверил пинг до сервера. И пинга не оказалось.
Выставил наугад значение mss в 1380 байт, флашнул очередь — не помогло. Значения 1024, 768 и даже 512 тоже результата не дали О.о Началось активное гугление по ругани почтовика, и даже нашелся аналогичный случай, решением которого стало отключение tcp_sack (выборочный ACK на пакеты из очереди TCP). Но нашему серверу не помогло. И вот уже, готовый списаться с админами этого почтового сервера, я зачем-то в последний раз попробовал значение mss в 256 байт и это сработало. Я до сих пор не могу понять, какие же узлы могут находиться между нами, и какими извращенными способами где-то происходит инкапсуляция трафика, из-за чего mss в шесть раз ниже нормы.
И точно так же не понимаю, по каким причинам нужно глушить весь ICMP. Да, существуют легко реализуемые атаки, с его использованием, но вред от них не ахти какой, и уж тем более, это не повод зарезать целый протокол. Без ICMP нельзя, а одминам, которые этого не знают, я желаю рака яичек.
На прошлой неделе списался снова с админом той конторы, откуда подключался клиент RDP:
А тем временем весь мир пингуется.
Админы, плохо знающие сети никуда не денутся, поэтому, дорогой читатель, если ты еще не сталкивался с рядом таких проблем, то обязательно столкнешься, и пусть случаи, описанные здесь, помогут быстрее найти и исправить проблему. И не глуши ICMP.
Вообще, написать об этой не очевидной сетевой проблеме, проявляющейся по-разному, но имеющей один корень, меня побудил один интересный случай.
Совсем недавно одному удаленному бухгалтеру понадобилось подключаться по RDP к нашему терминальному серверу для работы с 1C. Виндовый админ выделил нужные права, завел учетку, с моей стороны тоже проблем нет: IP клиента статический, а RDP использует TCP порт 3389, который сразу и был проброшен на терминальный сервер:
1 2 |
iptables -t nat -A PREROUTING -p tcp -s $ext_term_access -d $INET_IP --dport 3389 -j DNAT --to-destination $SRV1C |
Проверили конфигурацию с внешнего компьютера, успешно соединились, клиенту сразу был дан ответ «Готово, подключайтесь». Ко всеобщему удивлению клиент не смог соединиться, с его стороны соединение «зависало», не выдавая ошибок.
Мы проверили конфигурацию с еще нескольких внешних компьютеров, и везде соединение шло гладко. Пришлось списаться с их сисадмином, который, вместо того, чтобы подумать вместе, заявил, что проблема явно у нас, и что его клиенты подключаются таким образом ко многим серверам, а его ISA (это, вроде, такой виндовый фаерволл) и вовсе безупречна. Несколько дней я ломал голову над этой проблемой, даже временно частично или полностью отключал фаерволл, после чего выяснилось, что консольный-то доступ к терминалу у клиента работает.
Подозрение сразу пало на некорректный MTU, так как присутствовал самый явный симптом: текстовая информация и прочая мелочь размером до полутора килобайт передавалась успешно, а с более весомой графикой возникали проблемы.
Здесь хотелось бы подробнее остановиться на замечательной технологии определения максимального размера передаваемого сегмента в протоколе TCP — Path Maximum Transmission Unit Discovery или просто PMTUD. Два компьютера (клиент и сервер) начинают сессию передачи данных с SYN и SYN-ACK пакетов, которые содержат информацию о MSS — Maximum Segment Size — это характеристика протокола TCP, сообщающая максимально допустимый размер передаваемого сегмента. Так это выглядит:
1 2 |
IP (0x64, 44702, [DF], TCP, 52) client.com.55679 > server.com.http: S, cksum 0x13ea (correct), 3230584989:3230584989(0) win 5840 <mss 1452,nop,nop,sackOK,nop,wscale 4> |
Видно, что для одного компьютера MSS равен 1452, для другого 1412. Из этих двух значений выбирается наименьшее. В этой сессии размер любого сегмента обязательно будет меньше либо равен 1412 байт:
1 2 3 4 5 6 7 8 9 |
IP (0x64, 44703, [DF], TCP, 40) client.com.55679 > server.com.http: ., cksum 0x0a21 (correct), 1:1(0) ack 1 win 365 |
Путать MSS и MTU не стоит, последний — характеристика сетевого интерфейса, а не протокола. Ну, и конечно, MSS напрямую зависит от MTU и вычисляется как MTU — 20 (размер IP-заголовка) — 20 (размер TCP заголовка).
Таким образом, клиент и сервер могут обмениваться между собой информацией, посылая TCP-пакеты определенного размера с установленным битом «DF: Don't Fragment». Но если на пути между ними обнаружится узел, не способный передать пакет размером 1452 байта (1412+40), этот узел отбросит пакет и сформирует отправителю специальный ICMP пакет с типом 3 (Destination Unreachable) и кодом 4 (fragmentation needed and DF set), который, кроме самой ошибки, будет содержать информацию о максимально допустимом сегменте передачи.
Отправитель получает его, меняет свой MSS на еще более меньший и передача успешно продолжается. Это теория.
На практике же где-то между мной и клиентом эти столь необходимые ICMP-пакеты с информацией о фрагментации просто терялись. И передающая сторона, не получая ошибку, повторяла попытки передачи снова и снова, ожидая подтверждения приемной.
Эту проблему помог решить iptables. В таблице mangle он умеет изменять то самое передаваемое значение mss в SYN и SYN-ACK пакетах при помощи цели TCPMSS:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -s $ext_term_access -j TCPMSS --set-mss 1452
Это правило берет SYN-пакет, отправленный хостом клиента, и меняет его значение mss на 1452 (определял подбором). После того, как правило было прописано, у клиента все заработало, и все остались довольны.
Случай второй.
Наши плановики начали работать со специальной вебмордой на удаленном сервере. Оформление этого сайта не содержало каких-либо тяжелых объектов или графики, навигация по сайту работала прекрасно. Но среди используемых ими функций была «Формирование отчета в excel», которая просто «зависала» в ожидании ответа от сервера. На удаленной стороне ответили «У всех все работает» и предложили искать проблему у себя.
После некоторых размышлений, решил просто пропинговать их сервер, чтобы проверить присутствие icmp — и да, пинг не шел. Точно таким же образом, в iptables для серверного хоста был прописан еще меньший mss - 1380, после чего плановики смогли работать нормально.
Случай третий. Заметил недавно, что в очереди писем postfix на протяжении нескольких дней стали скапливаться письма на один и тот же домен, с одной о той же необычной причиной отсрочки:
ADC2F308358: from=, size=33628, nrcpt=2 (queue active)
ADC2F308358: enabling PIX workarounds: disable_esmtp delay_dotcrlf for mailserver.com[22.22.22.22]:25
ADC2F308358: to=, relay=mailserver.com[22.22.22.22]:25, delay=333009, delays=332827/0.02/1.5/181, dsn=4.4.2, status=deferred (conversation with mailserver.com[22.22.22.22] timed out while sending message body)
Жизнь, что называется, научила, поэтому первым делом проверил пинг до сервера. И пинга не оказалось.
Выставил наугад значение mss в 1380 байт, флашнул очередь — не помогло. Значения 1024, 768 и даже 512 тоже результата не дали О.о Началось активное гугление по ругани почтовика, и даже нашелся аналогичный случай, решением которого стало отключение tcp_sack (выборочный ACK на пакеты из очереди TCP). Но нашему серверу не помогло. И вот уже, готовый списаться с админами этого почтового сервера, я зачем-то в последний раз попробовал значение mss в 256 байт и это сработало. Я до сих пор не могу понять, какие же узлы могут находиться между нами, и какими извращенными способами где-то происходит инкапсуляция трафика, из-за чего mss в шесть раз ниже нормы.
И точно так же не понимаю, по каким причинам нужно глушить весь ICMP. Да, существуют легко реализуемые атаки, с его использованием, но вред от них не ахти какой, и уж тем более, это не повод зарезать целый протокол. Без ICMP нельзя, а одминам, которые этого не знают, я желаю рака яичек.
На прошлой неделе списался снова с админом той конторы, откуда подключался клиент RDP:
<Я> а ты сам глушишь icmp или кто-то между нами это делает?
<Админ> у меня isa глушит по-умолчанию
<Я> а мб откроешь? там же icmp type 3 code 4 - необходима фрагментация
<Админ> только с вами, это вообще умолчательная настройка, с нею весь мир живёт, так что не в ней дело
<Админ> у меня isa глушит по-умолчанию
<Я> а мб откроешь? там же icmp type 3 code 4 - необходима фрагментация
<Админ> только с вами, это вообще умолчательная настройка, с нею весь мир живёт, так что не в ней дело
А тем временем весь мир пингуется.
Админы, плохо знающие сети никуда не денутся, поэтому, дорогой читатель, если ты еще не сталкивался с рядом таких проблем, то обязательно столкнешься, и пусть случаи, описанные здесь, помогут быстрее найти и исправить проблему. И не глуши ICMP.