dadv: (chuck)

Стандартная ситуация: локальная сеть с маршрутизатором, один публичный IP, для выхода в мир используется NAT. Плюс на маршрутизаторе работает кеширующий DNS-сервер для локальной сети. Всё работает.

Однажды на одном из хостов локальной сети поселяется сервис, которому требуется пробросить статический диапазон портов UDP с внешнего IP. Казалось бы, какие могут быть проблемы?

А ведь DNS-сервер, выполняя запросы к внешним серверам, для исходящих запросов сам использует динамические UDP-порты и ожидает ответ на них. Например, ISC BIND под FreeBSD использует sysctl net.inet.ip.portrange.hifirst и net.inet.ip.portrange.hilast для определения диапазона таких эфемерных портов, по умолчанию это 49152-65535. Пока этот диапазон не пересекается с диапазоном проброшенных внутрь локалки портов, всё будет в порядке. Но стоит лишь пробросить, скажем, порты 40000-65535, и наступает катастрофа. В случае FreeBSD проброс портов "имеет приоритет выше" (выполняется раньше, чем доставка локальным приложениям) и проброс-то работать будет, но DNS-сервер остается без DNS-ответов на свои запросы, которые теперь уходят по пробросу локальному хосту, которому они и не нужны вовсе. И вся локальная сеть остаётся без локального DNS-сервиса.

Решением будет либо изменить диапазон проброшенных портов, если это допустимо для сервера в локальной сети, а если нет - изменить диапазон эфемерных портов для DNS-сервера. Кроме изменения системного дефолта, ISC BIND позволяет задать этот диапазон в собственной конфигурации:

use-v4-udp-ports { range 10000 30000; };

Аналогично для IPv6. Для защиты от некоторых типов атак, BIND каждый раз выбирает случайный порт из диапазона и рекомендуется, чтобы диапазон был достаточно большим, минимум 16384 портов (14 бит энтропии).

dadv: (chuck)

Довелось поэкспериментировать с компрессией и шифрованием данных на системном уровне в FreeBSD 9/i386. Шифрование делал через GELI, компрессию через ZFS. Обнаружил забавное. В моём случае контейнер для GELI расположен на медленной сетевой шаре (CIFS over 100Mbit/s & mtu=1500) и для уменьшения дополнительных тормозов от "read-modify-write" поигрался с размерами блоков.

И geli init позволяет задать "размер сектора" в создаваемом GEOM, и ZFS позволяет задать размер блока (recordsize). Оказалось, что даже при отлично сжимаемых данных и включенной компрессии ZFS реально ничего не жмет, если размер сектора и recordsize одинаково равны 4096: zfs get compressratio всегда показывает 1.00 и всё работает довольно медленно, упираясь в сеть.

При том же размере сектора в 4k увеличение recordsize до 8k позволяет ZFS достичь compressratio до 2.0 и операции на хорошо жмущихся данных заметно ускоряются. Если при recordsize=8k уменьшить размер сектора до 512 байт, то на тех же данных степень компрессии взлетает до 16.0 и скорость обработки хорошо жмущихся данных, соответственно, взлетает в разы. Например, показания benchmarks/bonnie, который оперирует как раз такими данными, хорошо демонстрируют эффект.

Маленький "размер сектора" контейнера GELI не слишком хорош по разным причинам: и относительные накладные расходы на собственно шифрование возрастают, и совсем мелкие обмены шифрованными данными по сети через CIFS генерируют относительно высокие накладные расходы в TCP. Поэтому "размер сектора" GELI-контейнера увеличил обратно до размера страницы памяти 4k и выставил ZFS recordsize в 8k - при этом на моих характерных данных коэффициент сжатия получается около 1.85.

Это лишь первая серия тестов и, может быть, в итоге - и для других наборов данных - параметры придется поменять.

dir="/mnt/cifs"
size="100g"
poolopts="-O recordsize=8k -O atime=off -O compression=gzip-9 -o failmode=continue"
truncate -s $size $dir/backend
md=$(mdconfig -af $dir/backend)
geli init -s 4096 /dev/$md
geli attach /dev/$md
zpool create $poolopts es /dev/$md.eli

dadv: (chuck)

Открыл для себя, что named читает ключ rndc.key (нужен, в частности, чтобы работала команда rndc) только из каталога, заданного при компиляции пакета и не имеет опции командной строки для переопределения пути к ключу.

Например, пакет bind910 для FreeBSD 10 нынче собирается с путем конфигурационных файлов /usr/local/etc/namedb и это неудобно, если хочется запускать named в chroot, где иерархия /usr/local вообще не нужна. Средствами /etc/rc.conf можно переопределить путь к named.conf внутри chroot, но нельзя к rndc.conf. Можно это сделать настройками самого named.conf, хотя и неочевидным образом. Перед стандартной секцией options добавляем команды:


include "/etc/namedb/rndc.key";
controls { inet 127.0.0.1 port 953 allow { any; } keys { rndc-key; }; };


Первая команда подключает rndc.key по указанному пути, а вторая команда отменяет поиск его по вкомпилированному пути, включая использование только что подключенного ключа для rndc.

В итоге для того, чтобы установленный из портов/пакетов named в FreeBSD 10 работал в chroot так же, как до этого он работал в составе базовой системы FreeBSD 9 и ранее, в /etc/rc.conf остаётся прописать:

named_enable="YES"
named_conf="/etc/namedb/named.conf"
named_chrootdir="/var/named"
named_symlink_enable="YES"

dadv: (chuck)

Оказалось, что немецкий хостер-лоукостер Hetzner в порядке защиты своей инфраструктуры от атак режет, в частности, входящие фрагментированные пакеты UDP, что в современном интернете частично ломает DNS-сервис. Проблема актуальна только тем, кто держит собственные DNS-серверы на физических или виртуальных серверах в Hetzner.

Детально проблема расписана в базе знаний ISC (наш случай - пункт 4. DNS queries/responses using EDNS are allowed, but UDP fragmentation and reassembly is broken), но решение достаточно простое - настроить свой DNS-сервер сообщать другим серверам не посылать требующие фрагментации ответы. Этакий аналог TCP adjust mss, но для DNS через UDP. Более крупные ответы будут доставляться сразу по TCP вместо UDP.

Для сервера BIND достаточно прописать в секции options:

options {
  edns-udp-size 1432;
}

dadv: (chuck)

В продолжение темы.

После того, как Глеб исправил несколько проблем в ядре FreeBSD, нагруженные роутеры с mpd5/PPPoE у меня работают стабильно. Однако, где-то раз в год всё-таки на каком-нибудь из них нет-нет, да и произойдет паника и все следы ведут в dummynet. Но раньше по разным причинам не удавалось сохранить одновременно крешдамп и отладочное ядро, а сегодня-таки удалось.

По итогам предварительного разбирательства найдено подозрительное место в коде dummynet и оформлен PR: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=195102

Судя по коду, проблема общая и для 9.x, 10.x и CURRENT - это место практически неизменно во всех ветках. Теперь главное, чтобы PR не завис незамеченным на годы.

dadv: (chuck)

В продолжение темы.

Умение протоколов компрессии/шифрования трафика автоматически восстанавливаться после потерь или переупорядочивания пакетов в сети это, конечно, хорошо. Но если с потерями почти ничего сделать нельзя (разве что передавать данные с избыточностью/перепосылками на транспортном уровне :-), то с небольшим переупорядочиванием можно и побороться.

Представим себе, что недалеко от точки приёма такого трафика возникают неподконтрольные нам перестановки пакетов - то есть, все пакеты доставляются без потерь, но очень часто соседние пакеты приходят переставленными местами (с таким я столкнулся на практике при использовании арендованной виртуалки в LeaseWeb). В таких условиях MPPE вынужден непрерывно выполнять re-keying и скорость на туннеле, проброшенном через такую сеть, падает ниже плинтуса. И даже если использовать PPP-туннель без шифрования/компрессии, мы получаем огромный процент потерь внутри туннеля, потому что GRE вынужден дропать "опоздавшие" фреймы PPP, так как не имеет права доставлять их с нарушением порядка (дропать - имеет право).

Но если обучить GRE восстанавливать порядок пакетов, то PPP/MPPE даже и не узнают, что были проблемы с доставкой (пока не начнутся настоящие потери). Для ноды ng_pptpgre(4), которую использует mpd при создании PPtP-туннелей, сделал патч. Update 07.09.2016: обновление патча для 11.0

Патч даёт возможность управлять глубиной очереди ожидания переупорядоченных пакетов через sysctl net.graph.pptpgre.reorder_max (ноль отключает восстановление порядка) и таймаутом ожидания "опоздавших" пакетов (в милисекундах) через net.graph.pptpgre.reorder_timeout. Тесты показали хороший результат при reorder_max=16 и таймаутом в 1ms, когда точка переупорядочивания близко к нам и в 50ms, если далеко. Изменять значения этих параметров можно "на лету", без переустановки туннелей. В итоге CCP даже не дергается, если низлежащий GRE успешно восстанавливает порядок.

Патч предварительный в том смысле, что параметры глобальные для всех PPtP-туннелей в системе. Можно улучшить его, сделав эти настройки локальными для каждого туннеля, но, к сожалению, этого нельзя сделать без того, чтобы не сломать ABI ноды ng_pptpgre, после чего старые сборки mpd перестанут вообще работать с патченной нодой. С текущим патчем пересобирать ничего не нужно, кроме ng_pptpgre.ko (или ядра, если нода статически слинкована с ним).

dadv: (chuck)

В последние уже довольно-таки много дней страницы ЖЖ у меня открывается с огромнейшим скрипом. Экспериментально выяснил, что открытие страниц тормозят множественные обращения к l-stat.livejournal.net и l-userpic.livejournal.com. Для этих имен ЖЖ использует балансировку, основанную на DNS и у меня эти адреса ресолвятся в различные IP-адреса из диапазона 37.29.0.*. Причем часто эти IP-адреса тупо не отвечают на коннект, отсюда безумные таймауты и полузагруженные страницы.

Если же подключаться к этим именам из Германии, например, они ресолвятся в адреса диапазонов 151.249.89.* и 151.249.90.*, которые прекрасно отвечают не только немецким клиентам, но и нам. Отсюда выход: в hosts прописываем, скажем:

151.249.89.13  l-stat.livejournal.net
151.249.90.200 l-userpic.livejournal.com

И ЖЖ чудесным образом перестаёт тормозить, при этом работая корректно.

Update. Если не грузятся картинки, помогает ещё добавить в hosts:

151.249.89.150 ic.pics.livejournal.com
151.249.90.137 pics.livejournal.com

Проблема с ними та же самая.
Update2. Для встроенного видео:

151.249.89.194 l.lj-toys.com

dadv: (chuck)

Сегодня в пол-второго ночи одновременно испортились оба блока питания PWR-2700-AC в шасси Cisco 7606.
чудеса )

Profile

dadv: (Default)
Choose your future

June 2017

M T W T F S S
   1234
56 7891011
12131415161718
19202122232425
2627282930  

Syndicate

RSS Atom

Tags

Style Credit

Powered by Dreamwidth Studios