- PVSM.RU - https://www.pvsm.ru -
Времена узких интернет-каналов постепенно уходят в прошлое, но иногда еще бывает нужно шейпить сетевой трафик. В Linux для этого есть соответствующие механизмы ядра и утилиты для управления механизмами. Все это хозяйство довольно сложно устроено, обычно постижение шейпинга занимает не один день. Хотя, в простых случаях можно накопипастить заклинания tc из статей или найти скрипт, который эти заклинания генерирует.
Как человеку любознательному, всегда было интересно, можно ли сделать процесс настройки шейпинга для небольших сетей проще? Можно ли хотя бы грубо детектировать важный трафик и отделять его от неважного без DPI и сигнатурного анализа? Можно ли шейпить трафик в любых направлениях без создания псевдо-интерфейсов или добавления модулей в ядро? И вот, после некоторых размышлений и гуглежа, решил написать простой шейпер в userspace. Чтоб попробовать ответить на вопросы экспериментом.
В результате эксперимента получилась вот такая штука github.com/vmxdev/damper [1]
Работает штука приблизительно так:
При старте создаются два программных потока. В первом NFQUEUE захватывает пакеты, они анализируются, каждому пакету назначается «вес» (или приоритет) и он сохраняется в очереди с приоритетами. Когда очередь заполнена, пакеты с низким приоритетом затираются высокоприоритетными. Другой поток выбирает пакеты с наибольшим весом и помечает их к отправке. Отправка происходит с ограниченной скоростью, из-за этого собственно и получается шейпирование.
Этот механизм позволяет копировать сетевые пакеты в пользовательское пространство для обработки. Приложение, которое слушает соответствующую очередь, должно вынести вердикт относительно пакета (пропустить или отбросить). Кроме этого допускается изменение пакета. Этим механизмом пользуются IDS/IPS типа Snort или Suricata. Пакеты помечаются для обработки в iptables, цель NFQUEUE. То есть мы можем выбрать любое направление (входящий трафик, исходящий, транзитный, или, скажем, UDP с порта 666 на порт 13) и направить его в шейпер. Там пакеты будут анализироваться, возможно изменять свой порядок, а при превышении лимита самые низкоприоритетные будут отбрасываться.
Первые рабочие версии шейпера захватывали пакеты, помещали их в очередь и потом ре-инъектировали в сырой (raw) сокет. На StackOverflow и некоторых других статьях пишут что это единственный способ задерживать пакеты перед перепосылкой. Конструкция работала, но товарищ Vel [2] разъяснил, где можно задерживать пакет прямо в NFQUEUE, настройка шейпера упростилась.
Так как шейпер экспериментальный, я сделал его не монолитным, а «модульным». В каждом модуле вычисляется вес пакета по разным критериям. Из коробки есть 4 модуля, но можно легко написать еще какой-нибудь. Модули можно использовать вместе, можно по отдельности.
Модули:
Веса пакетов, измеренные в каждом модуле, умножаются на коэффициент(каждому модулю можно задать свой) и складываются. Получается результирующий вес
Шейпер умеет вести статистику и рисовать графики. Вживую это выглядит так: damper.xenoeye.com [3]. Зеленый — сколько пропущено байт/пакетов, красный — сколько отброшено. График можно позумить/поскроллить.
Второй график (включается директивой «wchart yes» в конфиге) — средние веса пакетов за секунду, отнормированные, с разбивкой по модулям.
Демо работает на не очень быстрых ARMах (Scaleway bare metal, 32-битные ARMv7), иногда может слегка залипать.
У модулей inhibit_big_flows и entropy есть отладочный режим, включается в конфиге. В этом режиме модули каждые N секунд делают дамп текущих потоков с весами.
Кроме этого есть режим без ограничения скорости («limit no» в конфиге). В этом режиме все пакеты пропускаются (без анализа в модулях), но можно вести статистику прошедних пакетов/байт, медитировать на график загрузки канала, например.
Шейпер получился достаточно простой (ну, на мой, замыленный, взгляд). Для использования нужно выбрать направление по которому шейпить, добавить правило iptables, выставить в конфиге нужную скорость и запустить.
Тяжелые и высокоэнтропийные сессии определяются и понижаются в приоритете, но чудес не бывает: если канал очень узкий, комфортного серфинга не получится.
На больших скоростях и большом количестве пользователей я его не тестировал, но на десятках мегабит и с несколькими пользователями субъективно получается лучше чем без шейпера. Хотя он грузит CPU, но это не только от использования NFQUEUE, а еще и от общей корявости кода (и немного от особенностей clock_nanosleep()), можно отпимизировать и оптимизировать.
Это, конечно, только proof of concepts, код местами сумбурный и практически не причесывался.
Если у кого-то есть соображения, пожелания и предложения по поводу, было бы интересно почитать.
Автор: vmx
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/188745
Ссылки в тексте:
[1] github.com/vmxdev/damper: https://github.com/vmxdev/damper/
[2] Vel: https://www.linux.org.ru/people/vel/profile
[3] damper.xenoeye.com: http://damper.xenoeye.com
[4] Источник: https://habrahabr.ru/post/310242/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.