chuck

Route-based IPSec tunnel для FreeBSD

Довелось попробовать настроить IPSec в туннельном режиме под FreeBSD в «новом стиле», с созданием системного интерфейса ipsec0 со всеми причиндалами, включая MTU, чего раньше очень не хватало при настройке туннеля в «традиционном» стиле одними политиками IPSec, без туннельного интерфейса.

Удалённый пир нам не подконтролен (головная контора), требует согласования туннеля через IKEv2, не выдаёт дополнительных адресов на туннель.

Сначала поставил strongswan-5.8.2_1 из портов и настроил его через новомодный vici-интерфейс. Создал файл с произвольным именем и расширением .conf:

# cat /usr/local/etc/swanctl/conf.d/hq.conf
connections {
  hq {
    version             = 2
    pull                = no
    mobike              = no
    send_certreq        = no
    dpd_delay           = 5
    keyingtries         = 0

    local_addrs         = 1.1.1.1
    local_port          = 500
    remote_addrs        = 2.2.2.2
    remote_port         = 500

    proposals           = aes256-sha256-modp2048
    reauth_time         = 28800

    local {
      auth              = psk
      id                = 1.1.1.1
    }

    remote {
    }

    children {
      net-net {
        mode            = tunnel
        dpd_action      = restart
        ipcomp          = yes
        copy_df         = no
        start_action    = start
        reqid           = 100
        # policies        = no

        local_ts        = 192.168.18.0/24
        remote_ts       = 10.0.0.0/8,192.168.21.0/24

        esp_proposals   = aes256-sha256-modp2048
      }
    }
  }
}

secrets {
  ike-hq {
    id-hq       = 1.1.1.1
    secret      = XXX
  }
}
#EOF

В этом виде после запуска strongswan согласует IPSec в туннельном режиме, но системный интерфейс ipsec0 не используется и strongswan сам инсталлирует в ядро и политики SPD, и маршруты до удалённых сетей в таблицу маршрутизации. Туннель, тем не менее, работает.

Чтобы теперь добавить в картинку p2p-интерфейс ipsec0, добавляем в /usr/local/etc/strongswan.d/charon.conf команду "install_routes = no" внутрь блока charon {}, так что strongswan перестаёт сам добавлять маршруты до сетей 10.0.0.0/8,192.168.21.0/24 через внешний интерфейс (WAN) и раскомментируем "policies = no" в hq.conf (см. выше), чтобы strongswan не добавлял SPD в ядро, их ядро само создаёт при использовании route-based IPSec-туннеля.

Остальные настройки в /etc/rc.conf по такому типу:

cloned_interfaces="ipsec0"
ifconfig_ipsec0="tunnel 1.1.1.1 2.2.2.2 reqid 100 mtu 1460 up"
static_routes="hq1 hq2"
route_hq1="10.0.0.0/8 -iface ipsec0"
route_hq2="192.168.21.0/24 -iface ipsec0"

strongswan_enable="YES"
strongswan_interface="vici"


Индекс 100 после слова reqid должен быть одинаковым в настройках одного и того же туннеля в rc.conf и в конфигурации strongswan, а если есть ещё туннели, то отличаться для разных туннелей.

Update: Добавил keyingtries = 0 (см. выше), так как оказалось, что без этого при запуске strongswan делает 5 переповторов при попытке подключиться к пиру и если он в это время недоступен, прекращает дальшейшие попытки. Нулевое значение заставляет его делать бесконечное число повторов (каждый с 5 переповторами). Кроме того, в /usr/local/etc/strongswan.d/charon.conf полезно прописать make_before_break = yes и retransmit_base = 1 - последнее для того, чтобы сильно ускорить восстановление туннеля после временных обрывов из-за перезагрузки пира или просто аварии по трассе до него.

chuck

DW Announcement

Тестирую кросспостинг в ЖЖ через DW.

Заодно выдержка из новогоднего объявления от DW:

DW пережил огромный наплыв новых пользователей в последнюю декаду 2016, более 100000 новых аккаунтов и увеличение трафика на 25%. Многие из них из России и Украины.
chuck

DW

Оригинал взят у kika в валить-валить

Чтобы перенести в dreamwidth всю френдленту, надо при импорте
https://www.dreamwidth.org/tools/importer
указать импортировать список френдов, потом когда задание на импорт встанет в очередь, дождаться выполнения, пойти в http://www.dreamwidth.org/manage/circle/edit и поставить там галочки subscribe у всех, кого вы хотите читать.
Если у вас френдов в ЖЖ много и кликать на всех лень, то в консоли броузера можно выполнить вот это:
document.querySelectorAll("[id^='editfriend_edit_'][id$='_watch']").forEach(function(el){el.setAttribute('checked', 'checked');el.setAttribute('value', 1);})

И потом просто нажать кнопку Save changes.

Я пишу в LJ уже года три через dw на самом деле, просто убрал баннер трансляции из постов, поэтому этого было не видно. Наверное после устаканивания текущей бури в стакане и когда станет понятно что dw нормально справился с всплеском нагрузки, я трансляцию уберу. Не то чтобы я тут сильно подрывал и очень уж отчаянно плевал и уж тем более я не собираюсь в ближайшее время ехать в РФ (делать там совершенно нечего), но просто как-то неаккуратненько что-ли. Пусть меня читают только гебисты с прямыми руками и не крышующие ларьки, у которых дазы банных не "утекают" на рынок.


Надо будет тоже присмотреться к альтернативам. Не в ФБ же идти, в самом деле.
chuck

DNS, NAT и проброс портов

Стандартная ситуация: локальная сеть с маршрутизатором, один публичный 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 бит энтропии).

chuck

ЭЦП с ГОСТ 3410/3411 и подписывание PDF

Поискал как-то утилитку, которая смогла бы в пакетном режиме подписывать заранее заданный PDF заранее заданным сертификатом/ключом формата PKCS#12, в которых используются не варианты RSA/DSA, а отечественный ГОСТ, с внедрением подписи в PDF. И среди опенсорса ничего рабочего не нашел. Отсоединенную подпись (в отдельном от PDF файле) создать проблем нет просто командой openssl, но вопрос стоял о внедренной в PDF подписи.

Под Windows есть Adobe Acrobat и КриптоПро, при помощи которых можно проверять существующую подпись в файле PDF и подписывать самостоятельно при наличии ЭЦП, но мне хотелось найти путь с использованием открытого софта и автоматически, в пакетном, а не ручном режиме.

Нашелся BouncyCastle - опенсорс-криптопровайдер для Java, который с версии 1.50 умеет ГОСТ. Нашлась Java-библиотека iText PDF для манипуляций с файлами PDF, которая умеет создавать подписанные PDF и поддерживает использование криптопровайдера BouncyCastle вместо дефолтного Sun-овского, который ГОСТ не умеет.

И нашелся баг в исходниках iText всех версий, включая последние 5.5.9 и 7.0.0, из-за которого при подписывании PDF ГОСТ-ключом никаких ошибок не возвращается и генерируется PDF cо встроенной подписью, но битым хешем, отчего проверка подписи потом говорит "документ был изменён после подписывания". Участок кода itextpdf в 5.5.9 и 7.0.0, в котором сидит баг, практически идентичен, не менялся при смене версии.

После исправления бага (на самом деле полное исправление неизбежно сломало бы совместимость со старым кодом, так что в API добавлен новый метод для обходного пути) и добавления OID-ов для GOST3410 и ECGOST3410 в itextpdf у меня заработало пакетное подписывание PDF. Результат проходит проверку подписи в виндовом Adobe Acrobat с аддоном от КриптоПро, добавляющим Акробату поддержку ГОСТ.

Для этого требуется JRE или JDK с Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files (тестировал с OpenJDK 1.6 и 1.7), BouncyCastle версии не ниже 1.50 (тестировал с 1.54), itextpdf-5.5.9.jar (патченный для поддержки ГОСТ) или новее.

И коротенькое консольное java-приложение (просто обвязка вокруг библиотек), которое можно взять тут: http://www.grosbein.net/signpdf/

Там же лежит описание использования в http://www.grosbein.net/signpdf/Readme.txt плюс готовый патченный itextpdf-5.5.9.jar, сами патчи и прочее.

chuck

ЖЖ-поиск умер, да здравствует ljsear.ch

Появилась реинкарнация поиска по архиву ЖЖ: http://ljsear.ch/
В настоящее время ищет по архивной копии, содержащей записи и обсуждения за 2000-2015 год и выдаёт ссылки на сам ЖЖ плюс даёт доступ к архивным копиям найденного, но "сохраненные копии" доступны только с не-российских IP во избежание блокировки поисковика цензурой.

chuck

ZFS compression, sector size & recordsize

Довелось поэкспериментировать с компрессией и шифрованием данных на системном уровне в 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

chuck

Трудовые будни

Нарастил память у сервера, увеличив с 6G до 6+32=38G. Старый BIOS ругался на неподдерживаемые DIMM, но после обновления заработало всё, кроме одного 32-битного процесса.

Этот сервер работает под управлением FreeBSD 9.3-STABLE/amd64, но внутри себя, кроме всего прочего, крутит jail со спасенной со старой работы системой FreeBSD 4.11, в которой крутится фидонода 2:5006/1 с NNTP-гейтом и innd. И вот нормально работавший при 6G физической памяти innd после расширения стал падать при старте с руганью в лог news.err:

innd: SERVER cant malloc 909626760 bytes at line 146 of chan.c: Cannot allocate memory

Дело в том, что по умолчанию в FreeBSD9/amd64 предел datasize для 32-битных процессов составляет 512M (для 64-битных - 32G), а в innd, очевидно, слишком жадная автонастройка. Поднял системный предел для 32-битных процессов до 2G через sysctl compat.ia32.maxdsiz=2147483648 и проблема ушла.