...
...
...

Система учета трафика пользователей Sbilling

В большой и дружной семье open source пополнение: открылся новый российский проект — simple billing system. Что такое sbilling? По словам авторов, это простая биллинговая система, использующаяся для подсчета сетевого трафика. Была написана (и продолжает развиваться) из за отсутствия в Linux системного биллинга как такового. Написанная целиком на языке C. Распространяется по лицензии GPL, которая, как водится, прилагается к пакету. Скачать и, естественно, задаром в свое удовольствие использовать, можно с сайта автора — http://sbilling.lrn.ru/download/.

Толкового описания пакета на сайте разработчиков нет, поскольку проект только-только стартовал, да и ребятам-программистам, балующимся в свободное от работы время GPL-программизмом, писать user-freindly описания наверняка лень. Поскольку тестировать это хозяйство нам в редакции было лениво, я попробую "на пальцах" объяснить как этот "псевдобиллинг" работает, и далее проиллюстрировать сказанное выдержками из родного импровизированного man'а, поскольку IMHO man — лучший способ уяснить, что программа способна делать в принципе. Плюс к тому для самых любознательных (но ленивых для немедленного изучения сорсов ;) сетевиков во врезке предлагается информация для потенциальных разработчиков — подробности принципа работы программы и формат пакетов, с помощью которых происходит взаимодействие.
В двух словах, решение состоит из двух демонов, один из которых прокси--сервер, а другой — биллинг-сервер. В зависимости от контекста они по очереди являются друг для друга клиентом или сервером, но в ходе повествования нижерасположенного man'a под "сервером" понинимается биллинг-сервер, а под "клиентом" — прокси-сервер. Располагаться они могут на разных хостах, поскольку все взаимоотношения между демонами происходит по обычному TCP-соединению. Пользователи работают через "ручной" (способный работать с биллинг-сервером) socks-прокси, он скидывает информацию по наработкам биллинг-серверу, последний пишет полученные сведения в базу данных. Для установки системы sbilling вам потребуется собственно ОС Linux ядро 2.0 или выше (реально проверено на 2.2.X и 2.4.X) пакет GNU Make и компилятор C (например GCC). Так же нужен пакет devel от mysql или просто заголовочные файлы с библиотеками mysql.
К сожалению на данный момент графический интерфейс для работы с базой данных отсутствует, и поддерживается только 32 разрядная архитектура и операционная система Linux, хотя, может быть, соберется в других системах. Вот, с большего, и все дела :) Для тех, кому интересно — предлагаем нижеследующий кусок man'а.

конфигурирование 
После проведения установки системы, добавте группу billing и одноименного пользователя в эту группу (useradd -g billing billing). По умолчанию используется пользователь billing , вы можете изменить имя.
Занесите в таблицу proxyes ваших клиентов. Формат таблицы следующий |id|addr|port|try_addr|try_username|try_resolv|about|, где: id — уникальный номер (primary key) в таблице mysql, addr — адрес клиента формата IP (192.168.2.1) или символическое имя (должно быть прописано в зоне DNS) до 255 символов, port к которому будет коннектиться sbillng — от 1 до 65536 (для socks по умолчанию 1081), try_addr — значения 0 или 1 — отображать ли в статистике адрес пользователя в виде IP (192.168.2.1), try_username — значения 0 или 1 — отображать ли в статистике имя пользователя (у socks-сервера имеет смысл только при наличии авторизации), try_resolv — значения 0 или 1 — данная опция учитывается только при try_addr=1 и указывает, преобразовывать ли IP-адрес пользователя в имя машины, при неудачном преобразовании в статистику заносится IP-адрес, about — строка в 255 символов — краткая характеристика клиента. Например: 
insert into proxyes values(NULL,'socks.proxy.com',1081,1,0,1,'socks proxy server in server 1'); 
заведет в таблице proxyes прокси-сервер с адресом socks.proxy.com, порт для связи с прокси- сервером — 1081, в статистику заносить имена машин, отресолвленные по IP-адресу и не заносить имена пользователей, в поле about — "сокс прокси- сервер на сервере 1".
Желательно прикрыть порты прокси- сервера и sbilling'a (по умолчанию 800 порт) файрволом!

запуск socks сервера
Если вы установили все параметры при компиляции socks сервера, можете просто запустить его, набрав./socks, или использовать следующие параметры(перечисляются только параметры добавленные в socks сервер):
-bh |--billing-host ip_addr — адрес, на котором socks-сервер откроет порт для биллинга (по умолчанию все интерфейсы); 
-bp |--billing-port port — номер порта, который socks-сервер откроет для биллингового сервера (по умолчанию 1081);
-bs |--billing-server host — IP-адрес или имя хоста, на котором нахродится sbiling (по умолчанию localhost);
-bsp |--billing-server-port port — порт sbiling, к которому надо коннектиться (по умолчанию 800).
Все значения по умолчанию вышеуказанных параметров могут быть измененны при компиляции программы.
После запуска, socks-сервер пошлет пакет connect sbilling-серверу. После чего sbilling-сервер попробует установить связь с socks-сервером. 

остановка socks сервера
Теперь socks-сервер можно остановить только сигналом SIGTERM kill pid или kill -TERM pid При получении сигнала SIGTERM socks-сервер заставляет своих чаилдов выйти и отправляет данные sbilling-серверу. При невозможности отправить данные на sbilling-сервер, данные, находящиеся в буфере, теряются.
Не рекомендуется останавливать socks-сервер с помощью kill -9 (kill): при этом пропадают данные, находящиеся в буфере socks-сервера.

запуск sbilling
Желательно сначала провести запуск вручную, после удачного запуска добавить строку запуска в startup-скрипты (в каталог /etc/rc.d или что-то в этом духе — в зависимости от вашего дистрибутива). Запуск sbilling обязательно производится с опцией пароля для базы mysql, например:
./sbilling -sp password
Параметры запуска: 
--help — высветить меню помощи по параметрам;
-bs |--billing-server addr — IP-адрес, на котором сервер откроет порт (по умолчанию на всех интерфейсах);
-bp |--billing-server-port port — номер порта, который откроет sbilling (по умолчанию 800);
-ss |--sql-server addr — адрес sql-сервера (IP или имя, по умолчанию localhost);
-ssp |--sql-server-port port — порт sql-сервера (по умолчанию 3306);
-sb |--sql-database database — название базы на sql-сервере (по умолчанию billing);
-su |--sql-username username — имя пользователя для соединения с sql-сервером (по умолчанию billing);
-sp |--sql-user-password password — обязательная опция, пароль для коннекта к базе данных (значение по умолчанию отсутствует).
-u username — права пользователя, с которыми будет работать sbilling (по умолчанию billing). Все значения по умолчанию вышеуказанных параметров (кроме password) могут быть измененны при компиляции программы.
После запуска sbiling-cервер прочитает таблицу proxyes и установит соединение со всеми клиентами . Вы можете наблюдать в логе записи вида:
alarm OK ansve all_ok proxy id=1
с периодичностью 150 секунд. Это означает, что система работает нормально.

остановка sbilling сервера
Остановить sbilling сервер вы можете послав один из сигналов SIGTERM или SIGINT — kill -TERM pid. 
При получении одного из сигналов биллинг сервер разрывает соединения с клиентами и сбрасывает всю статистику в базу sql. При невозможности соединится с sql все данные заносятся в swap-файл.
Не рекомендуется посылать сигнал kill -9 (KILL) процессу sbilling: при этом все данные в буферах теряются.
Предупреждение: так как запись данных в sql-базу требует некоторого времени, подкорректируйте скрипт /etc/rc.d/rc.0(6) (или иной, в зависимости от вашего дистрибутива), отвечающий за переход в режим init0(6).
Увеличьте время sleep между командами killall -15 sleep 5 killall -9 до 20 секунд или больше (в зависимости от загруженности вашей сети). При этом у вас будет гарантия, что по команде halt (reboot, shutdown) освободятся буферы sbiling-сервера.

режимы работы sbilling-сервера
основной режим. Подразумевает: а) перекличку пакетами i_live о подтверждении поддержания коннекта, б) прием данных от клиента, в) запись данных в базу mysql. Также в этом режиме открыт порт 800 (default) для принятия запросов коннекта к клиенту.
режим ожидания клиента. В даном режиме sbilling может находится в двух вариантах: а) при старте sbilling не смог соединится с клиентом, б) произошел разрыв связи с клиентом (то есть нет пакетов i_live в течение 150 секунд).
В этом режиме sbiling пытается приконнектиться к клиенту раз в 150 секунд и ждет пакета connect. По приходу сообщения о коннекте, соединение с клиентом происходит немедленно.
режим ре-инициализации. Возможно вы внесли изменения в таблицу proxyes и хотите произвести ре-инициализацию. Пошлите процессу sbilling сигнал HUP kill -HUP pid. При этом sbiling разорвет соединения со всеми клиентами, перечитает таблицу proxyes и произведет соединение к клиентами в соответствии с таблицей proxyes.
режим ожидания SQL . При старте демона sbilling обязательно должен быть доступ к базе sql-сервера для инициализации таблицы клиентов. При невозможности прочитать данные из базы sql, sbilling будет пытаться приконнектится к базе один раз в 60 секунд. Во время работы sbiling-сервера может быть потеряна связь с sql- сервером При этом данные, поступающие от клиентов, будут заноситься в файл /var/sbilling/billing_swap (default). Данные заносятся в преобразованном виде, то есть, если у вас стоит опция резолвить IP-адреса, будут записываться имена машин, так-же каждому пакету будет соответствовать текущая дата. В данном режиме можно выключить компьютер или переинициализировать демон sbilling. При следующем старте или при удачном соединении с базой sql-сервера sbilling прочитает swap-файл и перенесет данные оттуда в базу sql.
Внимание: при невозможности записи в swap-файл все клиенты переводятся в принудительный stop-режим , данные, находящиеся в буферах sbiling-сервера, а так-же поступающие после перехода в режим stop, теряются. В режиме ожидания sql-сервера в ERR-логе ведутся записи о потере связи с sql-сервером.
stop режим. В данный режим sbilling-сервер может переключиться по одной причине: нет доступа к базе sql и нет возможности записывать данные в swap-файл. Внимание: при невозможности записи в swap-файл все клиенты переводятся в принудительный stop-режим, данные, находящиеся в буферах sbiling-сервера, а также поступающие после перехода в режим stop, теряются. 
В данном режиме происходит запись в ERR-лог о потере связи с sql-сервером и невозможности записи в swap-файл , при этом будет заносится записи вида:
Jan 25 21:01:44 alex ./sbilling [1696]: lose addr=16777343 user=alex in=10822 \ out=530 id=1100 pole=2001-01-25 mons=1
где данные после lose — это потерянный пакет. Также в ERR-лог будет заноситься запись о переводе всех клиентов в stop режим каждые 150 секунд.
Если в данном режиме пере-инициализируется клиент и пошлет sbilling-серверу пакет connect, то клиент тут же будет переведен в принудительный stop режим.
Данный режим будет совершенствоваться в дальнейшем вплоть до репликации между несколькими серверами sbilling.

режимы работы клиента (proxy сервера)
основной режим. а) передача пакетов i_live и получение ответов ansve каждые 150 секунд, б) передача пакетов данных sbilling серверу (каждые 150 секунд, или при переполнении буфера).
режим ожидания billing-сервера. Или stop режим. В данном режиме клиент может находиться по двум причинам: 1. при старте не была установлена связь с sbilling-сервером, 2. была потеряна связь с sbilling- сервером и она не воccтановилась в интервале от 150 до 300 секунд. В данном режиме клиент шлет пакеты connect каждые 150 секунд. Примечание: socks-сервер не дает выход в интернет пока не переключится в нормальный режим.
принудительный stop режим. В принудительный stop режим клиента переключает sbilling-сервер в аварийной ситуации (смотрите stop-режим sbilling). При этом клиент убивает всех своих чайлдов, отправляет всю информацию sbilling-серверу и предотвращает пользователям выход в интернет. Только Из принудительного stop режима клиента может вывести sbilling-сервер или перезапуск (клиента).

работа с базой данных
По умолчанию база данных для сервера sbilling называется billing. База состоит из таблиц 3-х видов. Таблица proxyes: список клиентов (прокси-серверов). Формат таблицы см. выше.
Таблицы mons01 — mons12. Это таблицы месяцев, соответственно от 1 до 12. Формат таблицы: |id|proxy|userna-me|addr|date|in_bytes,out_bytes где id — уникальный номер записи (primary key), proxy — номер прокси-сервера (клиента), username — имя пользователя (до 15 символов), addr — фактический IP-адрес или имя машины, date — дата в формате YYYY-MM-DD (примечание: данные в таблице хранятся с дискретизацией в один день, то есть если пользователь работал 30 дней в месяце, то в таблице ему будет соответствовать 30 записей за месяц), in_bytes и out_bytes, соответственно, входящий и исходящий трафик в байтах. Статистика ведется непрерывным циклом в году. В начале каждой таблицы первой записью id=1 всегда хранится идентификационная запись вида |1|0|NULL|NULL|2001-02-12|0|0| . Данная запись гласит, что в таблице mons02 ведется статистика за 2001 год. При несоответствии даты года текущему или при отсутствии этой строки все данные из таблицы текущего месяца перемещаются в таблицу tmp. При этом в лог записывается следующее предупреждение : 
Feb 11 21:50:40 darkstar ./billing[6053]: warning replase table mons02 to tmp !!!
Таблица tmp. Имеет ту же структуру, что и mons-таблицы. В таблицу tmp происходит перенос устаревших данных или перенос данных по причине сбоя (например локальной даты). Удаление или перенос записей из таблицы tmp будет осуществляться интерфейсом к базе данных (который еще не написан).

заключение
Данный проект развивается достаточно медленно. В нем на данный момент принимает участие только автор, проект пишется в свободное от работы время. Надеюсь, система sbilling будет развиваться и в дальнейшем. Если вы хотите принять участие в проекте или написать клиента (или патч к серверу), то пишите на alex@lrn.ru, постараюсь дать информацию и консультации!
В дальнейшем планируется следующее: 1. Написать патч на squid (чем я уже начал заниматься). 2. Написать сервер для подсчета цепочек ipchains. 3. Написать сервер для снятия статистики с cisco (ipaccont) 4. Дописать режим full-billing (ограничение трафика, привязка пользователя к IP-адресу и прочее).
Об остальном позже: идей много а времени нет :(

Ильин Алексей Владимирович, руководитель проекта sbilling. Обыкновенный администратор Linux-системы и начинающий программист на языке C.
Перевод с русского 
на русский — Alice D. Saemon ;)

информация для разработчиков
краткий принцип работы системы.
Сервер sbilling держит всегда открытым порт 800. Клиент дополнительно держит всегда (или на время потери связи) со своей стороны биллинговый порт. В качестве транспортного протокола используется TCP/IP.
Клиент может посылать пакет give_mee_all на порт 800 sbilling сервера (остальные виды пакетов будут отвергнуты). Для установления связи sbilling сам соединяется с клиентом, после чего начинается нормальный режим работы и обмен пакетами). Весь информационный обмен происходит только при наличии установленной связи между sbilling сервером и клиентом.

описания пакетов
reset. Данный пакет клиент получает от sbilling-сервера. При получении данного пакета клиент должен "прибить" всех своих чаилдов , переключится в нормальным режим работы (если был включен stop режим).
i_live. Данный пакет клиент отправляет sbilling-серверу каждые 150 секунд(при потери связи с сервером не отправляется).
all_OK. Данный пакет клиент получает от sbilling-сервера каждые 150 секунд. Если в течение 150 секунд после отправки пакета i_live от sbilling нет ответа пакетом all_OK, связь с sbilling-сервером считается потерянной.
stop. Данный пакет клиент получает от sbilling-сервера. При его получении клиент должен "прибить" всех своих чайлдов и отослать всю информацию на sbilling-сервер.
send_bytes. Отправляется sbilling-серверу каждые 150 секунд или или по мере завершения работы чайлдов (время отправления пакетов асинхронно, то есть каждый чайлд сам отсчитывает время от момента своего рождения).
give_mee_all. Данный пакет отправляется при инициализации клиента или каждые 150 секунд при потери связи с сервером.

форматы пакетов 
Вид пакетов будет представлен в следующей форме:
reset'\0'|15|"reset"|'\0' 11
где reset — название пакета, '\0'|15|"reset"|'\0' — форма представления пакета, | — это табулятор '\t' или 09, 11 -длинна пакета в байтах, то есть пакет reset в коде C выглядит так 
char reset[]={'\0', '\t', 15, '\t', 'r', 'e', 's', 'e', 't', '\t', '\0'};
write(socket,reset,11); — отправка пакета

Итак, пакеты: 
i_live '\0'|13|"i_live__"|'\0' 14 
geve_mee_all'\0'|14|"1081mee_"|'\0' 14
Примечание: в теле пакета первыми цифрами должен быть обозначен порт к которому будет производить подключение sbilling , если данный порт для данного клиента не совпадает с базой sql, sbilling не производит попытки подключения.

reset'\0'|15|"reset"|'\0' 11 

all_OK'\0'|16|"allOK"|'\0' 11

stop'\0'|19|"stop0"|'\0' 11

send_bytes'\0'|17|"1234"|"1234"|"1234"|
"123456789012345"|'\0' 36 

Примечание по формату пакета: 
'\0'|17|in|out|addr|user|'/0'
in — число принятых(со стороны рабочей станции) байт в форме int 4-е байта(32 бита);
out — число отправленных(со стороны рабочей станции) байт в форме int 4-e байта(32 бита);
addr — адрес в формате uint32_t 4-е байта (32 бита);
user — строка имя пользователя, длинна 15 символов, на конце '\0' необязателен

режимы работы клиента
режим запуска
При запуске клиент не принимает соединения (тоесть не выполняет своих функций прокси-сервера). После инициализации клиента (прочтения конфигурационных файлов открытия портов)клиент посылает пакет give_mee_all, после чего ожидает коннекта от sbilling-сервера. Если sbilling сервер не подсоединился, то каждые 150 секунд клиент будет пытаться послать пакет give_mee_all (при этом клиент по прежнему не выполняет своих функций).Если при инициализации клиента sbilling находится в аварийном состоянии(stop)режим , то после подключения sbilling сервера к клиенту клиент получает пакет stop. При подключении sbilling сервера клиент переходит в нормальный режим работы и получает пакет reset.

режим завершения работы
Обычно в режим завершения программа переводится сигналом SIGTERM. При получении сигнала SIGTERM клиент обязан правильно завершить работу своих чайлдов, собрав статистику о переданных байтах каждого чайлда .Отправить всю статистику на sbilling сервер. Закрыть sbilling порт и завершить свою работу.

нормальный режим работы
В нормальном режиме работы клиент выполняет свои основные задачи(например proxy сервер дает доступ в интернет). Помимо этого каждые 150 секунд отправляется пакет i_live sbilling серверу. Также каждые 150 секунд передается пакет send_bytes (обычно серия пакетов и асинхронно, то есть каждый чайлд считает время за себя, не синхронизируя его ни с кем).

режим потери связи с sbilling-сервером
Если в течение 150 секунд после отправления пакета i_live не было получено пакета all_OK, то связь с sbilling-сервером считается потерянной.
При этом в первые 150 секунд закрывается сокет и отправляется пакет give_mee_all, если в следующие 150 секунд связь с sbilling-сервером не восстановится, клиент обязан правильно завершить работу своих чайлдов, собрав статистику о переданных байтах каждого чайлда и хранить статистику в своем кэше до восстановления связи или получения сигнала SIGTERM (при получении сигнала SIGTERM данные теряются).
При подключении sbilling-сервера клиент переводится в нормальный режим работы. Данный режим будет продолжать совершенствоваться.

принудительный stop режим
При получении пакета stop клиент должен правильно завершить работу своих чайлдов, собрав статистику о переданных байтах каждого чайлда . Отправить всю статистику на sbilling сервер, перестать давать доступ к интернету. При этом связь с sbilling-сервером не разрывается, прием и отправление пакетов i_live all_OK продолжаются . Выйти из данного режима клиент может получив пакет reset.


© Сетевые решения