Ограничение скорости в p2p-клиентах на Linux

Иногда при установке p2p-клиента для раздачи контента с сервера может потребоваться ввести какие-либо ограничения на скорость аплоада. При этом далеко не все файлообменные клиенты позволяют настроить это достаточно гибко. К примеру, в старом microdc2 в принципе отсутствует возможность управления полосой пропускания, а в современном ncdc предусмотрено установление лишь общего лимита скорости для всех соединений.

Но что делать, если требуется ограничивать скорость в зависимости от IP-адреса запросившего контент пользователя?

Оказывается, практически в любой Linux-системе присутствует встроенный механизм QoS (Quality of Service), содержащий весь необходимый нам функционал. В качестве примера покажем, как можно им воспользоваться для ограничения скорости аплоада у p2p-клиентов ncdc (DC++) и transmission-daemon (bittorrent).

Предположим, что у нас есть 100-мегабитный канал, и мы хотим отдать до 90 мбит любым локальным пользователям (10.0.0.0/8) обоих p2p-сетей, интернет-пользователей ncdc ограничим 10-ю мегабитами, а внешних пользователей transmission-daemon ограничим скоростью в 500 кбайт/сек.

Составим правила для tc, создав для transmission-daemon класс трафика 1:2, для ncdc – класс 1:4, а для всех прочих соединений – класс 1:10.

/sbin/tc qdisc add dev eth0 root handle 1: htb default 10 r2q 250
/sbin/tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit burst 2k
/sbin/tc class add dev eth0 parent 1:1 classid 1:2 htb rate 250kbps ceil 500kbps prio 1 burst 2k quantum 25000
/sbin/tc class add dev eth0 parent 1:1 classid 1:4 htb rate 750kbps ceil 1000kbps prio 1 burst 2k quantum 25000
/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 80mbit ceil 90mbit prio 0 burst 2k
/sbin/tc filter add dev eth0 parent 1:0 prio 1 protocol ip handle 2 fw flowid 1:2
/sbin/tc filter add dev eth0 parent 1:0 prio 2 protocol ip handle 4 fw flowid 1:4
/sbin/tc filter add dev eth0 parent 1:0 prio 3 protocol ip handle 10 fw flowid 1:10

Пара комментариев:

  • default 10 — по умолчанию весь трафик относим к классу 1:10;
  • r2q 250 — значение параметра r2q по умолчанию равно 250;
  • quantum 25000 — для классов 1:2 и 1:4 указываем quantum вручную, т.к. при низком rate и r2q=250 автоматическое значение будет неприемлемым.

К вопросу о том, что такое r2q, поисковик может показать что-нибудь вроде этого:

r2q is “rate to quantum” is used to calculate the quantum for each class : quantum = rate / r2q. Quantum must be 1500 < quantum < 60000. Otherwise you will get warnings from the kernel.

Подробнее, например, здесь.

Итак, теперь у нас есть определение разных классов трафика. Осталось раздать указания, какой трафик к какому классу относить. Воспользуемся для этого функциональностью iptables маркировать пакеты. Но возникает проблема: а как определить, какие пакеты относятся к зловредным p2p-клиентам, а какие к добропорядочным программам?

Маркировка по destination ничего не даст – p2p-клиенты могут обращаться к каким угодно хостам. Вероятное желание маркировать пакеты по source-port (мы ведь знаем, на каком порту они слушает соединения?) также ни к чему не приведет: при попытках соединиться с удаленными узлами программы использует случайные исходящие порты, никак не связанные со входящим. В отчаянии мы могли бы даже подумать о том, чтобы использовать iptables-модуль l7-filter. Однако, как вскоре выяснилось бы, для этого модуля необходимо пропатченное системное ядро, да и его стабильность с ресурсоемкостью могут быть несколько сомнительны.

Существует намного более простое решение. В iptables есть стандартный модуль owner, а p2p-клиенты вполне можно запускать от имени разных пользователей. В результате мы легким движением руки можем ограничить скорость только одному пользователю, от имени которого запущен соответствующий клиент, и это никак не затронет других пользователей и системные процессы.

Пишем правила для iptables:

/sbin/iptables -A OUTPUT -t mangle -p tcp -m owner --uid-owner transmission-daemon -j MARK --set-xmark 0x2
/sbin/iptables -A OUTPUT -t mangle -p tcp -m owner --uid-owner ncdc -j MARK --set-xmark 0x4
/sbin/iptables -A OUTPUT -t mangle -d 10.0.0.0/8 -p tcp -j MARK --set-xmark 0x0

Комментарии:

  • Первой строкой мы ставим пометку 0x2 (соответствует правилу tc filter класса 1:2) на все пакеты, которые генерятся от пользователя transmission-daemon, второй – аналогично для ncdc;
  • Последняя строка снимает метки в случае, если получатель пакета находится в подсети 10.0.0.0/8.

Вот и всё: весь исходящий p2p-трафик оказался зарезан в заданных пределах, за исключением исходящих соединений в сторону локальной сети.

PS: Не забудьте добавить и правила файрвола, и tc куда-нибудь в автозагрузку. Автоматически при перезапуске системы они не сохраняются.

This entry was posted in Сеть и интернет and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>