Clone wiki

lisg / Home

Linux ISG

Система предназначена для аутентификации, авторизации, учета и применения политик к трафику пользователей, проходящему через маршрутизатор под управлением ядра Linux. Является попыткой реализовать часть функционала Cisco ISG в рамках ОС Linux.

Основные функции

  • Прозрачный старт пользовательских IPoE-сессий (инициатор - неизвестный IP-адрес источника)
  • Аутентификация, авторизация и учет сессий по протоколу RADIUS
  • Классификация трафика по адресу сети назначения с привязкой классов к сервисам сессии
  • Поддержка RADIUS CoA (RFC 3576)
  • Полисинг трафика (RFC 2697), в том числе по сервисам

Установка

Быстрое руководство для Debian Squeeze и Wheezy

  • Удовлетворить зависимости
$ sudo aptitude install linux-headers-$(uname -r) iptables-dev build-essential
$ sudo cpan -i Net::Radius::Packet
  • Скачать последнюю версию и распаковать
$ wget --no-check-certificate https://bitbucket.org/sysoleg/lisg/get/master.tar.gz
$ tar zxf master.tar.gz
  • Собрать и установить модуль ядра и модули iptables
$ cd sysoleg-lisg-*/kernel
$ ./configure
$ make
$ sudo make install
  • Подгрузить модуль ядра
$ sudo modprobe ipt_ISG
  • Установить поддержку на стороне userspace (скрипты демона и управления на Perl)
$ cd ..
$ sudo cp -r ISG /opt
  • Поправить etc/config.pl по своему вкусу
  • Запустить демон ISGd.pl
sudo /opt/ISG/bin/ISGd.pl
  • Использовать ISG.pl для управления сессиями
/opt/ISG/bin/ISG.pl --help

Использование

Прежде всего нужно определиться, какой трафик будет обрабатываться Linux ISG. Это может быть одна или несколько подсетей, трафик с определенного сетевого интерфейса, не важно. Допустим мы хотим управлять трафиком для подсетей 10.254.0.0/16 и 192.168.99.0/24. В этом случае нужно добавить такие правила:

iptables -A FORWARD -s 10.254.0.0/16 -j ISG --session-init
iptables -A FORWARD -d 10.254.0.0/16 -j ISG
iptables -A FORWARD -s 192.168.99.0/24 -j ISG --session-init
iptables -A FORWARD -d 192.168.99.0/24 -j ISG

Правила с опцией --session-init мы будем называть инициализирующими. Когда пакет попадает в такое правило, модуль ядра ipt_ISG пытается выяснить, принадлежит ли этот пакет к сессии, которая была ранее подтверждена RADIUS-сервером. Если это не так, Linux ISG запрещает прохождение пакета и через Netlink отправляет демону ISGd.pl сообщение. Демон обращается к RADIUS-серверу, чтобы авторизовать этот пакет. В качестве атрибута User-Name используется IP-адрес источника. Если в качестве ответа приходит Access-Accept, сессия становится подтвержденной, а для проходящего через правила трафика применяются соответствующие политики.

Если необходимо, чтобы сессия стартовала при отправлении пакетов на IP-адрес пользователя (например, когда используются реальные IP-адреса), то можно сделать так:

iptables -A FORWARD -s 10.254.0.0/16 -j ISG --session-init
iptables -A FORWARD -d 10.254.0.0/16 -j ISG --session-init --init-mode dst

При этом просто --session-init является эквивалентом --session-init --init-mode src.

Смотрите также iptables -j ISG --help

Обратите внимание, что правила, в которых указано --session-init --init-mode src или просто --session-init используются для обработки трафика от пользователей. В правилах, которые не имеют этого параметра, либо имеют, но в сочетании с параметром --init-mode dst, обрабатывается трафик на пользователей (но только если сессия была подтверждена ранее RADIUS-сервером, в противном же случае трафик на пользователя игнорируется).

Мы также можем сделать что-то подобное:

iptables -I FORWARD -s 192.168.99.0/24 -d 10.99.0.0/16 -j ISG --session-init
iptables -I FORWARD -d 192.168.99.0/24 -s 10.99.0.0/16 -j ISG

В этом случае Linux ISG будет управлять трафиком клиентов из подсети 192.168.99.0/24 при их доступе в подсеть 10.99.0.0/16. Любой другой трафик будет проходить мимо правил и следовательно передаваться "как есть".

Для управления сессиями можно использовать скрипт ISG.pl. Смотрите ISG.pl --help.

Поддержка сервисов

Каждая сессия может иметь примененные к ней сервисы.

Сервисы типа Policer

Такие сервисы предназначены для организации возможности предоставления пользователям дифференцированной скорости, в зависимости от адреса назначения. Представим себе, что пользователь с IP-адресом 10.11.22.33 должен иметь доступ к

  1. Неким частным сетям на скорости 50 Мбит/с
  2. К серверу 10.55.11.16 без ограничения скорости
  3. К другим адресам на скорости 1 Мбит/с (пусть это будет Интернет)

Прежде всего нам следует определить классы трафика в etc/tc.conf:

FIRST	192.168.0.0/16
FIRST	172.16.0.0/12
CLASS_A	10.0.0.0/8

SECOND	10.55.11.16/32

THIRD	0.0.0.0/0

Вообще подсеть 10.0.0.0/8 мы бы могли тоже отправить в класс "FIRST". Мы используем класс "CLASS_A" только чтобы продемонстрировать, что к одному сервису можно применить много классов.

Теперь определим сервисы (смотрите etc/config.pl):

$cfg{srv}{"PRIVATE"}{type} = "policer"; # this is by default, can be omitted
$cfg{srv}{"PRIVATE"}{rate_info} = "QD;50000000;1562500;U;50000000;1562500";
$cfg{srv}{"PRIVATE"}{traffic_classes} = [ "CLASS_A", "FIRST" ];

$cfg{srv}{"SSERVER"}{rate_info} = "QD;0;0;U;0;0"; # or just comment this line
$cfg{srv}{"SSERVER"}{traffic_classes} = [ "SECOND" ];

$cfg{srv}{"INET-MBIT"}{rate_info} = "QD;1000000;187500;U;1000000;187500";
$cfg{srv}{"INET-MBIT"}{traffic_classes} = [ "THIRD" ];

Профиль пользователя 10.11.22.33 на RADIUS-сервере должен включать атрибуты:

Cisco-Account-Info  = APRIVATE
Cisco-Account-Info += ASSERVER
Cisco-Account-Info += AINET-MBIT

Обратите внимание, что если мы исключим последнюю строку (AINET-MBIT), то пользователь 10.11.22.33 не будет иметь доступа в Интернет. Если исключить первую и вторую строки, то пользователь не будет иметь доступ к частным сетям и к серверу, но будет иметь только доступ в Интернет со скоростью 1 Мбит/с. Другими словами, несмотря на то, что класс выглядит так:

THIRD	0.0.0.0/0

пользователь не будет иметь доступ везде со скоростью 1 Мбит/с, но будет иметь доступ ко всем адресам, за исключением 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 10.55.11.16/32.

Также мы может определить дополнительный сервис, например INET-MBIT-SPEED:

$cfg{srv}{"INET-MBIT-SPEED"}{rate_info} = "QD;5000000;937500;U;5000000;937500";
$cfg{srv}{"INET-MBIT-SPEED"}{traffic_classes} = [ "THIRD" ];

Добавить его в профиль к нужному пользователю:

Cisco-Account-Info  = APRIVATE
Cisco-Account-Info += ASSERVER
Cisco-Account-Info += AINET-MBIT
Cisco-Account-Info += NINET-MBIT-SPEED

Обратите внимание на букву "N" перед именем сервиса. Это означает, что сервис не будет активирован автоматически и в случае необходимости его можно будет включить посредством запроса RADIUS CoA. При этом нужно понимать, что мы не можем иметь оба сервиса включенными, потому что они имеют один пересекающийся класс - "THIRD". Поэтому чтобы включить INET-MBIT-SPEED нужно сначала выключить INET-MBIT. Такое ограничение не относится к сервисам типа "tagger".

Сервисы типа Tagger

Сервисы этого типа предназначены для возможности выполнения match в iptables по имени сервиса. Такие сервисы сами по себе никак не влияют на трафик проходящий через Linux ISG, но дают возможность управлять трафиком средствами других модулей iptables (например, реализовать L4-редирект). Пример:

$cfg{srv}{"L4REDIR"}{type} = "tagger";
$cfg{srv}{"L4REDIR"}{traffic_classes} = [ "SOME_CLASS", "TESTING" ];

В этом случае мы можем "поймать" трафик классов "SOME_CLASS" и "TESTING" таким образом:

iptables -t nat -A PREROUTING -p tcp --dport 80 -m isg --service-name L4REDIR -j DNAT --to-destination 5.5.5.5

Здесь любые пакеты из указанных выше классов (то есть из сервиса "L4REDIR") направленные на порт TCP 80 мы перенаправляем на сервер с IP-адресом 5.5.5.5.

Внимание! В текущей реализации таким образом можно выделить только трафик идущий от пользователя.

Как работает классификатор трафика

Для определения подсетей следует использовать etc/tc.conf. Этот файл перечитывается автоматически, смотрите tc_check_interval в etc/config.pl. Для примера можно посмотреть tc.conf.example.

При желании можно поменять параметр модуля ipt_ISG nehash_key_len. По умолчанию он равен 20. Этот параметр определяет длину ключа хеша. Для простоты представим что этот параметр равен 16 и в etc/tc.conf настроены такие префиксы:

10.5.5.0/24
10.5.6.0/24
192.168.0.0/16

Прежде всего будет создана хеш-таблица с (2^16 = 65535) элементами (или цепочками, buckets). Таким образом:

10.5.5.0/24	оказывается в цепочке 10.5.0.0	(= 10.5.5.0 & 255.255.0.0)
10.5.99.0/24	оказывается в цепочке 10.5.0.0
192.168.0.0/16	оказывается в цепочке 192.168.0.0

Получается, что у нас уже две записи в цепочке 10.5.0.0. Для лучшей производительности нам бы хотелось, чтобы в цепочках было как можно меньше записей (чтобы уменьшить процессорное время, которое занимает линейный поиск). Значит мы можем увеличить параметр nehash_key_len, но это приведет к большему использованию оперативной памяти. Например, если мы установим его значение в 24, то добавление какого-нибудь префикса с маской /8 приведет к созданию 65535 клонов префикса /8 (потому что в рамках /8 сети возможно 65535 подсетей по /24).

Значение 20 является хорошим компромиссом между использованием памяти и производительностью.

Идея структуры данных заимствована у Robert Olsson (fib_hash2).

Поддержка RADIUS CoA

Linux ISG поддерживает сообщения RADIUS CoA и PoD. Прежде всего нужно настроить соответствующие параметры в файле etc/config.pl. Для идентификации сессии можно использовать следующие атрибуты:

  • User-Name (IP-адрес пользователя)
  • Acct-Session-Id
  • NAS-Port
  • NAS-Identifier (указывается в любом случае)

Для основной сессии при помощи CoA можно изменить следующие атрибуты:

  • Cisco-Account-Info (когда используется для задания скорости в виде: QU;...;D;...)

Для сервисов при помощи CoA мы можем выполнить их активацию и деактивацию:

Cisco-AVPair   = "subscriber:command=activate-service"
Cisco-AVPair  += "subscriber:service-name=SOME_SERVICE"
User-Name      = 5.5.5.5
NAS-Identifier = 127.0.0.1

В данном примере мы активируем сервис "SOME_SERVICE" для пользователя с IP-адресом 5.5.5.5 на NAS с идентификатором 127.0.0.1. Последние два атрибута используются для однозначной идентификации пользовательской сессии.

Можно использовать атрибут

Cisco-AVPair = "subscriber:command=deactivate-service"
... ... ...

для последующей деактивации сервиса.

Список поддерживаемых атрибутов в Access-Accept

Имя атрибутаОписаниеПример использования
Acct-Interim-IntervalСтандартный атрибут (см. RFC)Acct-Interim-Interval = 180
Session-TimeoutСтандартный атрибут (см. RFC)Session-Timeout = 86400
Idle-TimeoutСтандартный атрибут (см. RFC)Idle-Timeout = 1800
ClassСтандартный атрибут (см. RFC). Строка до 32 символов.Class = user_id_31
Cisco-Account-Info = QU;cir;normal burst;D;cir;normal burstУказание скорости передачи данных для главной сессии. cir задается в бит/с, burst указывается в байтах. Этот атрибут не имеет действия, когда к сессии применены какие-либы сервисы. Также может использоваться в CoA-запросах. Для скоростей меньше 1 Мбит/с рекомендуется burst = cir / 8 * 1,5. Иначе burst = cir / 8 * 0,25.Cisco-Account-Info = QU;512000;96000;D;512000;96000
Framed-IP-Address = <IP-адрес>Атрибут может использоваться для реализации 1-to-1 NATFramed-IP-Address = 51.61.71.22
Cisco-Account-Info = A<имя_сервиса>Имя сервиса, который будет применен к авторизуемой сессии в активированном режиме. Атрибут может повторяться для указания множества сервисов. На одну сессию невозможно применить два или более сервиса с пересекающимеся классами. Это ограничение не действует для сервисов типа "tagger" и сервисов, примененных в деактивированном состоянии.Cisco-Account-Info = AINTERNET
Cisco-Account-Info = ALOCAL
Cisco-Account-Info = N<имя_сервиса>То же самое, что и A<имя_сервиса>, но сервис будет применен в деактивированном состоянии. Позже его можно будет включить CoA запросом.Cisco-Account-Info = NLOCAL
Cisco-Account-Info = QC;<имя_класса>;U;cir;normal burst;D;cir;normal burstУказание скорости для класса трафика. Будет динамически создан сервис с именем вида DYN_*, с единственным классом "имя_класса" и применен к сессии.Cisco-Account-Info = QC;MY_CLASS;U;512000;96000;D;512000;96000

Разное

Для надежного взаимодействия между ядром и userspace рекомендуется перед запуском демона и ISG.pl выполнить (однократно):

echo "1048576" > /proc/sys/net/core/rmem_max

В противном случае могут быть проблемы при выводе длинных списков, состоящих из тысяч записей.

Обратная связь

Updated