e-Billing

Леонид Шалупов

Илья Евсеев


Содержание

Лицензия
Что такое «биллинг»
Что такое RADIUS
RADIUS-клиенты
Главный недостаток RADIUS'a
portslave
Модуль PAM
Маршрутизаторы Cisco
Самодельные решения
Как по IP-адресу узнать логин? (небольшой уход в сторону)
Существующие приложения биллинга
Чем e-Billing отличается от существующих аналогов
Множественные денежные единицы
Принудительное завершение сессий
Компоненты системы
Инсталляция
FreeRADIUS
PPTP daemon
Apache mod_auth_radius
MySQL
Библиотеки
Настройка
server.conf
IP-адреса клиентов
policies.conf
agents.conf
SQL-таблицы
Пользовательский интерфейс и генерация отчётов
Какая система планировалась вначале
Причины отказа от продолжения разработки
Выбор названия

Введение

Данный документ содержит описание системы e-Billing -- программного комплекса для подсчёта стоимости пользовательской активности в компьютерной сети и управления доступом пользователей к предоставленным ресурсам. В дополнение к этому даётся исчерпывающий обзор предметной области и смежного/альтернативного ПО.

Лицензия

Настоящая документация распространяется на условиях GNU Free Documentation License версии 1.1.

Каждый имеет право воспроизводить, распространять и/или вносить в неё изменения в соответствии с условиями этой лицензии.

Данный Документ не содержит Неизменяемых разделов; Данный Документ не содержит текста, помещаемого на первой или последней страницах обложки.

Все исходные тексты программ, разработанные в рамках проекта e-Billing, распространяются на условиях GNU General Public License версии 2 или более поздней, по вашему выбору.

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

Изменения и добавления, внесённые авторами e-Billing'a в ходе его разработки в другие программные продукты, распространяются не под лицензией e-Billing'a, а под лицензиями этих продуктов.

Что такое «биллинг»

Биллинг (от англ. «bill» - счёт, закладная) -- это термин, обозначающий следующий процесс:

  1. сбор информации о количестве предоставленных потребителям услуг;
  2. расчёт их стоимости;
  3. прекращение (или изменение режима) обслуживания, если стоимость превысила некоторый порог (заранее оплаченный кредит и т.д.).

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

  • коммутируемого доступа в Интернет с повремённой тарификацией;
  • постоянного доступа с тарификацией по трафику (количеству переданных данных);
  • доступа к сервисам прикладного уровня: арендованному сайту, почтовому ящику, СУБД и т.д.

Существующие решения могут быть поделены на два типа:

  • самодельные, самостоятельно определяющие состав необходимой для биллинга информации, организующие её получение от сервисов, обработку, хранение, управление сервисами;
  • основанные на протоколе RADIUS.

Что такое RADIUS

RADIUS расшифровывается как Remote Authentication in Dial-In User Service. Это протокол, специально разработанный для передачи сведений между программами-сервисами (в терминах RADIUS'a - NAS, т.е. Network Access Server) и системой биллинга.

Узлы освобождаются от хранения информации о пользователях, которая собирается на общем для всей сети компьютере. RADIUS-сервер подобен серверам NIS и LDAP, а также контроллерам домена Сети Microsoft в том отношении, что управление авторизацией становится централизованным, но отличается предъявляемыми требованиями и составом дополнительной информации. Например, LDAP в первую очередь предназначен для обработки запросов на чтение из центральной базы, и в последнюю - на запись, SMB не содержит встроенных средств для передачи сигнала от сервера рабочей станции о необходимости прекращении обслуживания, и т.д.

Имеет смысл ещё раз подчеркнуть, что компьютеры и приложения, являющиеся серверами и сервисами с точки зрения пользователя, сами, в свою очередь, с точки зрения RADIUS'a являются RADIUS-клиентами и управляются RADIUS-сервером, который отвечает за проверку подлинности пользователей (authentication), право выполнения операций в сети (authorization) и проверку количества выделенных/потреблённых ресурсов (accounting).

Наиболее популярными современными серверами RADIUS являются:

Как правило, сервер RADIUS, от которого зависит работа NAS'ов, сам, в свою очередь, зависит от следующих компонентов:

  • система хранения информации о пользователях;
  • система хранения статистики;
  • система вычисления стоимости и принятия решений.

Далее приводятся возможные варианты их реализации на примере GNU RADIUS. Так, информацию о пользователях GNU RADIUS умеет читать из следующих источников:

  1. из простых текстовых файлов с паролями (plaintext или MD5);
  2. из реляционной базы на SQL-сервере;
  3. с другого сервера RADIUS (удобно, т.к. в стандарте RADIUS предусмотрена поддержка CHAP);
  4. системными вызовами getpwent/getspent (классический Unix-подход);
  5. вызовами библиотеки PAM (современный Unix-подход).

Варианты хранения статистики:

  1. простые текстовые файлы;
  2. база на SQL-сервере (поддерживаются MySQL и PostgreSQL);
  3. подключаемый внешний обработчик.

Для программирования всех расширений, включая запись сложных и/или нестандартных правил биллинга, используется интерпретатор языка Scheme (диалект языка Lisp), называемый GUILE (GNU's Ubiquitous Intelligent Language for Extension). Этот интерпретатор имеет вид программной библиотеки, так чтобы разработчик мог легко подключить её к своему приложению.

RADIUS-клиенты

Большинство типовых сервисов (Sendmail/Postfix SMTP, Apache HTTP server, Squid/Oops HTTP proxy и т.д.) не поддерживают полноценного взаимодействия с RADIUS-сервером. Под неполноценным взаимодействием здесь подразумевается простая проверка паролей и разрешение на доступ, а под полноценным -- подсчёт количества и стоимости данных, полученных клиентом после того, как разрешение на доступ выдано. По-видимому, либо на такую функциональность нет спроса, либо наличие небольшого спроса удовлетворяется закрытыми и/или частными решениями.

Главный недостаток RADIUS'a

RADIUS оперирует сессиями. Из-за этого он хорошо подходит для управления доступом к коммутируемым линиям или (на прикладном уровне) к сервисам наподобие SMB, SMTP, FTP и Telnet. Однако в нём не существует такого понятия, как пользовательская активность вне сессий. По этой причине RADIUS не годится для учёта трафика через маршрутизатор или обращений к прикладным сервисам типа HTTP.

Каким может быть обходное решение? По-видимому, RADIUS-клиент, ответственный за обслуживание маршрутизатора или прикладного сервиса, должен, получив запрос от пользователя, объявить RADIUS-серверу о начале сессии, но не объявлять о её закрытии ещё некоторое время. В течении этого времени все запросы от данного пользователя, будучи по сути никак не связанными, считаются находящимися в одной сессии. Если к сервису попеременно обращается множество пользователей, прикреплённый к нему RADIUS-клиент должен корректно отличать их друг от друга и с точки зрения RADIUS-сервера держать одновременно открытыми соответствующее количество сессий. Реализация такого решения рискует быть громоздкой.

Менее изящное решение для сетевого уровня связано с использованием VPN-туннелей: чтобы получить доступ к сервису, пользователь должен установить с сервером VPN-соединение. VPN-соединение в этой ситуации используется ни для манипуляций с IP-адресами, ни для шифрации содержимого, хотя и то, и другое не запрещено. Причина, по которой оно требуется, состоит в том, что пользовательская активность принимает вид сессий, а значит, снова укладывается в понятия RADIUS'a.

Последнее решение демонстрируется в e-Billing'e, причём в качестве VPN-протокола выбран PPTP (Point-to-Point Tunneling Protocol). Выбор обусловлен тем, что его реализация включена в состав Windows, начиная с NT4 и '98 (для Win95 -- в отдельном пакете MS DUN, начиная с версии 1.3). Соответственно, на Линукс-сервере инсталлируется пакет pptpd.

portslave

Portslave -- это утилита, совмещающая в себе свойства драйвера терминала и проверки пароля.

Как драйвер терминала, Portslave может запускаться из /etc/inittab для работы с последовательным портом ttySn. В этом варианте он выступает как альтернатива mgetty. Во-вторых, его можно запустить из любого приложения, которое установит сетевое соединение и перенаправит его на stdin/stdout, как это делают inetd и vpnd.

После запуска (во втором варианте) или установки соединения (в первом) Portslave узнаёт у удалённого пользователя имя/пароль, связывается с RADIUS-сервером и передаёт ему введённые данные для проверки. На этом этапе Portslave заменяет стандартную утилиту login.

После успешной авторизации Portslave запускает PPP-демон. ???

  • кто разрывает сессию по истечении срока
  • под чьими привилегиями работаем после авторизации
  • запуск других сервисов: ssh, ifcico, telnet
  • запуск из-под telnetd
  • повторная авторизация
  • патчи для PPPD, замена fingerd
  • инсталляция: вместо mgetty или между mgetty и pppd; между vpnd и pppd или другим приложением
  • radiusclient

Модуль PAM

Если RADIUS является сетевой системой авторизации, то есть позволяет с одного компьютера управлять процессом подключения пользователей к сервисам на других компьютерах, то PAM (Pluggable Authentication Modules, Подключаемые Модули Аутентификации) централизует управление подключениями к разным сервисам в пределах одного-единственного компьютера. Сервисы, обязанные заниматься авторизацией пользователей (/bin/login, удалённый терминал, PPP, FTP и т.д.), будучи соответствующим образом переписаны, теперь вызывают функции библиотеки PAM, а та, в свою очередь, запускает модули, указанные в составленной для сервиса политике (policy).

Такая схема не только разгружает исходный текст сервиса, поскольку вызов PAM-функций проще самостоятельных проверок, но и расширяет возможности администратора:

  1. Так как одна политика способна содержать произвольное число модулей, выполняющих произволные действия, всё управление входом в систему (вплоть до монтирования сетевых дисков и предложения сменить устаревший пароль) может быть сведено, пусть и теоретически, к простой правке текстовых файлов-политик в каталоге /etc/pam.d и/или добавлению проверочных модулей в /lib/security.
  2. Так как многим сервисам может быть назначена одна и та же политика, администратор получает возможность настраивать доступ пользователя к системным ресурсам через все сервисы, редактируя одну-единственную политику.

Как и многие другие удачные идеи, PAM был разработан фирмой Sun Microsystems для операционной системы Solaris. По документации на интерфейс администратора, интерфейс разработчика PAM-зависимых сервисов и интерфейс разработчика PAM-модулей фирма RedHat разработала реализацию PAM для Линукса, полностью совместимую для разработчиков сервисов с вариантом от Sun. Пользовательский интерфейс для администраторов и программный интерфейс для разработчиков модулей совместимы не стопроцентно, но в значительной степени.

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

Когда говорят о такой поддержке, имеют в виду (не всегда внятно) одно из двух:

  • сервис (в т.ч. поддерживающий подключения по сети) является PAM-клиентом, то есть для чтения с консоли или сетевого соединения и проверки пользовательских реквизитов вызывает функции PAM-библиотеки, которая, в свою очередь, вызывает PAM-модули;
  • существует PAM-модуль, который умеет соединяться с этим сервисом по сети, тем самым подчиняя ему процесс авторизации, производимый другими сервисами.

Первое позволяет подключать сервис к уже существующей системе авторизации, а второе -- делать сервис ядром новой системы авторизации в существующей вычислительной среде.

Для многих сетевых протоколов имеется и то, и другое. Например, сервер Samba обращается к PAM'у, если исходные тексты сконфигурированы с опцией --with-pam, в smb.conf разрешён приём из сети незашифрованных паролей (опция encrypt passwords = no) и включён флаг obey pam restrictions = yes.

В то же время Samba содержит несколько PAM-модулей для использования другими сервисами: тривиальный pam_smbpass (ключ конфигурации исходников --with-pam_smbpass) проверяет пароли по локальному файлу smbpasswd, и сложный пакет WinBind, PAM-модуль которого авторизует пользователей, обращаясь через сеть к серверу Samba или контроллеру домена под управлением Windows.

Точно таким же образом обстоит дело и с протоколом RADIUS: все современные RADIUS-серверы способны проверять пользователей через PAM, а для PAM существует несколько модулей, способных обращаться для проверки к удалённому RADIUS-серверу. Один из них, pam_radius, имеет минимальные возможности и входит (входил?) в состав базовых исходных текстов PAM от RedHat, а второй, более совершенный, написан в рамках проекта FreeRADIUS и называется pam_radius_auth.

Для сетевой авторизации, в том числе через PAM, существуют два важных препятствия.

Во-первых, некоторые сетевые протоколы предусматривают, что пароль от клиента сервису передаётся в уже зашифрованном виде, без возможности точной обратной дешифрации. Если этот шифр отличается от того, который использует расположенная под PAM'ом система авторизации, использовать PAM под данным сервисом нельзя.

Описанная проблема наиболее актуальна для Самбы: чтобы Самба могла использовать PAM, на рабочих станциях Windows требуется отключать шифрование передаваемых паролей через MD4, чтобы сервис получал их в виде plain text.

Во-вторых, для того, чтобы успешно авторизованный пользователь мог обращаться к файловым и прочим ресурсам на компьютере, на который он получил доступ через сервис, операционная система должна назначить ему персональный идентификатор UID и идентификатор группы GID. Требуется одно из двух.

Либо значения UID/GID придётся хранить на сервере авторизации и читать их на сервисный компьютер, при условии, что сетевой протокол, через который PAM-модуль связывается с системой авторизации, вообще допускает подобный вариант (SMB-протокол не допускает, хотя последние версии WinBind способны читать данные, которые не "влезают" в формат SMB-сообщений, напрямую с LDAP-сервера, на котором хранятся пользовательские записи домена, минуя при этом контроллер домена, также обращающийся к записям через LDAP -- образчик параноидальной находчивости в параноидальном мире современного сетевого ПО). В таком случае необходимо следить, чтобы глобальные значения не пересеклись со значениями в учётных записями локальных пользователей. Этот вариант допустим и рекомендуется, в частности, для протокола LDAP.

В худшем же случае сидящему под PAM'ом модулю потребуется динамически выделять новым сетевым пользователям локальные UID/GID из специально отведённого (чтобы избежать конфликтов с обычными способами регистрации) диапазона и запоминать соответствия между ними для дальнейшего использования. Так поступает WinBind -- PAM-модуль из состава Самбы. Потеря таблицы соответствий равносильна потере /etc/passwd.

Маршрутизаторы Cisco

Поддержка RADIUS'a (и его менее совершенного предшественника, называемого TACACS) в маршрутизаторах и коммутаторах Cisco реализована полностью, потому что Cisco не только использует их, но и является основным разработчиком.

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

В документации FreeRADIUS имеется файл ./doc/cisco, в котором приведены сведения по настройке Cisco IOS для подключения к RADIUS-серверу. Там же имеется пока непроверенная нами ссылка на фирменную документацию.

На данный момент дистрибутив e-Billing'a не содержит никаких средств для поддержки Cisco, равно как и их описаний. Это вызвано тем, что для организации сервера удалённого доступа мы используем другое оборудование: контроллеры фирмы Cyclade для T1 и ISDN, вставляемые в стандартный PCI-слот непосредственно на PC-совместимом компьютере, на котором работают Линукс, биллинговая система и всё остальное ПО.

Не вызывает сомнений, что поддержка Cisco будет добавлена в e-Billing сразу же, как только у кого-то возникнет потребность в подобном симбиозе.

Самодельные решения

Как уже говорилось выше, основными пользователями биллинговых систем являются провайдеры коммутируемых или постоянных подключений к Интернету. Вот основные отличия между ними:

  Коммутируемый доступ Выделенный доступ
Сервис, предоставляющий доступ и осуществляющий учёт PPP-демон Пакетный фильтр
Единица авторизации Сеанс IP-пакеты
Единица измерения Время в секундах Трафик в байтах
Данные для авторизации клиента Имя/пароль IP-адрес (*)
Отключение клиента w | grep $USER_ID && kill $PPP_ID; usermod -L $USER_ID В таблицу пакетной фильтрации добавляется блокирующее правило для данного IP-адреса

И пакетные фильтры, и прикладные сервисы в состоянии выдавать более-менее подробную статистику своей работы в текстовом виде: первые, как правило, по запросу, вторые - постоянно, причём, как правило, через syslog. От простой системы биллинга требуется произвести синтаксический разбор выдаваемого текста (для этого идеально подходит Perl или libRegExp), извлечь из него нужные данные, привести к реляционному виду и поместить в базу на SQL-сервере.

Примером такого «решения» может служить «Простая система учёта трафика», написанная Вадимом Фёдоровым.

Расчёт стоимости также производится несложной процедурой на Perl'e. Доступ к системе осуществляется через Веб-интерфейс. Дополнительно «ваяется» генерация отчётов в MS Office или Delphi. Отключение пользователей в случае перерасхода производится вручную или (по мере накопления опыта отключений) чем-то, написанным на колене.

Следует заметить, что подобные «наколенные» разработки порой вырастают в нечто вполне зрелое, документированное, удобное и коммерчески успешное.

Как по IP-адресу узнать логин? (небольшой уход в сторону)

Сетевая служба Ident (RFC 1413) работает по следующей схеме:

  • Ident-сервис запускается на рабочей станции пользователя с привилегиями локального администратора;
  • приложение пользователя производит запрос к серверу;
  • приложение на сервере, получив запрос, определяет IP-адрес и порт, с которого он был отправлен;
  • приложение на сервере отправляет сервису Ident на рабочую станцию запрос с указанием номера порта;
  • Ident возвращает серверу имя пользователя, которому принадлежит приложение, сделавшее запрос с указанного порта.

Его применение оправдано в следующей ситуации:

  • пользователь может работать с нескольких рабочих станций;
  • на одной рабочей станции могут быть одновременно запущены приложения нескольких пользователей;
  • все рабочие станции находятся под управлением провайдера (иначе на них некому будет инсталлировать Ident, или его ответам нельзя будет доверять);
  • приложение-сервис умеет делать Ident-запросы.

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

Если соблюдаются следующие условия:

  • на рабочих станциях установлены однопользовательские операционные системы;
  • начало работы невозможно без авторизации на центральном сервере (контроллере домена ;-( );
  • IP-адрес рабочей станции нельзя поменять без повторной авторизации или привилегий администратора, ...

... то неплохой потенциальной альтернативой Ident'y является опрос сервера авторизации: «назови мне имя пользователя, который зашёл в сеть с компьютера, имеющего данный IP-адрес».

Существующие приложения биллинга

При поиске в Интернете существующих свободных решений оказалось, что все они написаны на территории бывшего СССР. Из этого следуют два вывода:

  • весь остальной мир пользуется вполне качественным коммерческим ПО, которое нам недоступно в силу (а) бедности и (б) провинциальности;
  • отсутствие т.н. «государственной поддержки» программистов есть явление положительное, так как приводит к увеличению количества, разнообразия и качества создаваемых ими программ, а её наличие, наоборот, провоцирует жесточайшую профессиональную импотенцию.

???

Характеристика LANBilling NetAMS NetUP UserTrafManager KravNet Admin NIBS OSt radacct
Предмет учёта
 
 

Чем e-Billing отличается от существующих аналогов

Решение писать собственную систему учёта, кроме естественного для программиста писать собственные программы вместо настройки чужих, не имело под собой почти никаких причин.

Множественные денежные единицы

Ни одна из существующих систем биллинга не позволяет назначать стоимость нескольких услуг в нескольких неконвертируемых друг в друга денежных единицах. Рассмотрим пример, когда такая возможность необходима настолько, что оправдывает разработку наподобие нашей.

Имеется учебный центр с выходом в Интернет и модемным пулом. Учащиеся имеют возможность звонить на сервер за файлами, заданиям, почтой и т.д. Стоимость телефонного доступа во внутреннюю сеть либо невелика, либо заложена в общую стоимость обучения. Однако предоставляемое время доступа в первом варианте, скорее всего, фиксировано, а во втором - фиксировано обязательно.

Кроме того, у слушателей существует возможность скачивать из Интернета определённый объём данных. Таким образом, у каждого из них имеются две квоты, но запрещается разменивать одно в другое, то есть нельзя, например, провести на линии 50 часов вместо 100 положенных, но выкачать из Интернета 11 мегабайт вместо разрешённых 10.

Описанной проблемы не существует для Интернет-провайдера -- провайдер считает только время на линии. Её не существует и для Интернет-клуба -- в клубе время работы и Интернет-трафик складываются в общий счёт. Многие домашние сети не только не взимают оплату за внутренний трафик, но даже не считают его. Однако учебный центр (такой, как УЦВТ), с одной стороны, должен предоставлять слушателям гарантированный доступ из дома к собственным базам, сайтам и т.д. (возможно, бесплатно, но с ограничением по времени), а с другой -- давать им по этой же линии выходить в Интернет, но уже за дополнительную плату.

Решением служит введение нескольких денежных единиц, одна из которых служит для «оплаты» времени на линии, а вторая -- для оплаты Интернет-трафика. Если и та, и другая услуги являются платными (оставаясь при этом не размениваемыми одна в другую), то вычисление суммарной стоимости должно производиться не в ядре биллинговой системы, ответственном за управление сервисами (NAS'ами), а дальше, в системе расчёта платежей. Ядро же должно манипулировать сервисами, расчитывая стоимость их использования независимо, не смешивая в общий котёл.

Возможный обходной вариант без программирования мог бы состоять в инсталляции нескольких биллинговых систем (по количеству ортогональных денежных единиц) с общей базой пользователей, например, в LDAP. При этом каждая система будет отвечать за обслуживание своего набора сервисов: первая -- за PPP на телефонном входе во внутреннюю сеть, вторая -- за пакетный фильтр на Интернет-шлюзе и т.д.

Для расчёта стоимости в e-Billing'e служит оригинальная функция, подключаемая к системе в двух точках:

  • plugin к FreeRADIUS -- библиотека, вызываемая через определённый во FreeRADIUS интерфейс RLM, RADIUS Loadable Modules;
  • Accounting Daemon -- собственный компонент e-Billing'a, отвечающий за управление NAS'ами в течение сессии.

Принудительное завершение сессий

Как ни удивительно это может показаться, RADIUS-протокол не предусматривает разрыва связи с клиентом в случае исчерпания кредита. В начале и конце сессии NAS посылает RADIUS-серверу соответствующие уведомления, но между этими двумя моментами они никак не взаимодействуют: NAS не сообщает, что клиент ещё работает, а RADIUS-сервер не перерасчитывает кредит и не приказывает оборвать связь, если кредит закончился. Такой механизм в протоколе RADIUS, насколько мы сумели понять, отсутствует по определению.

Вне всяких сомнений, многие Интернет-провайдеры как-то обходят это ограничение, потому что их узлы удалённого доступа умеют разрывать связь с точностью до минуты. Остальные же, наверное, предпочитают обслуживать клиента в кредит, либо дожидаясь следующего платежа, либо производя отключение вручную (естественно, не с точностью до минуты).

Для управления NAS'ами в течение сессии в рамках проекта e-Billing разработана утилита-демон acctd (Accounting Daemon). Её работа происходит по следующей схеме:

  • по статистике, которую FreeRADIUS генерирует через RLM, acctd узнаёт о начале сессии;
  • acctd периодически проверяет, что ответственный за сессию NAS активен;
  • если NAS активен, acctd определяет количество ресурсов, потреблённых пользователем с момента предыдущей проверки, расчитывает их стоимость и сохраняет в статистике;
  • если стоимость превысила кредит, acctd завершает работу экземпляра NAS'a, тем самым разрывая сессию.

Модуль by_command

acctd управляет сервисами через внешние модули собственного формата. Пока существует два модуля.

Первый из них называется by_command. Этот модуль читает команды управления из конфигурационного файла и передаёт их системному интерпретатору команд. Например, конфигурационный файл для управления Portslave-зависимым соединением на локальном компьютере выглядит примерно следующим образом:

<?xml version = "1.0"?>
<options>
    <local-portslave
	    temp="/sbin/route -n | /bin/fgrep %{Client-IP} | /usr/bin/awk {'print $8'}"
	    stat_cmd="/bin/fgrep %{Temp} /proc/net/dev | /usr/bin/awk {'print $2 " $10'}"
	    kill_cmd="kill -s TERM `/bin/cat /var/run/%{Temp}.pid`" />
</options>

Модульная конструкция acctd и возможность использовать произвольные системные команды через модуль by_command в переспективе позволят легко добавлять в acctd поддержку абсолютно любых устройств, включая сервисы на других компьютерах, специализированные маршрутизаторы и т.д.

MPD

Второй модуль служит для управления сервисом MPD (Multi-link PPP daemon), входящим в состав FreeBSD. В отличие от классического PPP-демона, который запускается заново для проведения каждой сессии, MPD работает постоянно и обслуживает все подключения, будучи запущенным в единственном экземпляре. Для управления им существует т.н. MPD-консоль, т.е. вспомогательная утилита, работающая как в интерактивном, так и в пакетном режиме (clear Unix way ;-). К MPD-консоли можно подключаться через TCP-сокет.

Удалённо опрашивать и управлять MPD через MPD-консоль значительно удобнее, чем PPPD, так как опрос нескольких копий PPPD на удалённом узле через SSH потребовал бы либо установки нескольких SSH-соединений, либо громоздкой оптимизации. В случае с MPD сессия между агентом и консолью создаётся ровно один раз, когда наступает момент вызова агентов acctd-демоном.

Примечание: внутренняя структура acctd такова, что агент определённого типа создаётся в единственном экземпляре независимо от того, сколько узлов и сессий он обслуживает. В частности, один экземпляр (instance) mpd-агента обслуживает все MPD на всех узлах. То есть, внутри объекта типа «агент» хранится пул объектов типа «сессия»

У MPD-консоли существует два недостатка. Во-первых, она ведёт себя нестабильно при длительной работе. По этой причине MPD-агент разрывает соединение с консолью в конце каждого цикла опроса и открывает его заново в начале следующего. Во-вторых, сетевая сессия с консолью не шифруется, то есть и данные, и даже пароль передаются через сеть открытым текстом! Решить эту проблему предполагается с помощью утилиты stunnel.

Компоненты системы

Приведённый рисунок вряд ли нуждается в дополнительных комментариях:

Рисунок 1. Компоненты и связи

Компоненты и связи

Направления на стрелках указывают, в какую сторону передаются данные.

Инсталляция

Разработка и эксплуатация системы происходит под операционной системой ALT Linux Master (в данный момент используется версия 2.2 «Orange»). Соответственно, форматом распространения является RPM для i586.

Все вспомогательные пакеты (MySQL и т.д.) были пересобраны, причём далее в описании каждого из них указывается, был ли Spec-файл для него оставлен без изменений, изменён или написан с нуля.

FreeRADIUS

FreeRADIUS выбран по следующим причинам:

  • содержит все необходимые описания и примеры настроек;
  • развивается в соответствии с требованиями момента;
  • входит в стандартный комплект поставки ALT Linux Master.

Отличия нашей нынешней сборки от входящей в состав ALM 2.2 заключаются в следующем:

  • наложен патч, устраняющий использование слова operator в качестве имени переменных, с целью разрешить написание модулей на Си++;
  • создан отдельный devel-пакет, содержащий include-файлы.

Вероятнее всего, первое изменение со временем окажется на freeradius.org, а второе -- в Сизифусе.

PPTP daemon

Выше рассказывалось, какая роль отводится PPTP-протоколу в общей схеме. Чтобы ей соответствовать, стандартный ALT'овский пакет пересобран с опцией --with-pppd-ip-alloc. Собранный с ней PPTP-демон не назначает новому сетевому соединению IP-адрес, а перекладывает эту обязанность на запускаемый им сервис (как правило, это сервис PPP). В свою очередь, запускаемый в нашем случае вместо PPP portslave назначит IP-адрес, значение которого ему сообщит RADIUS-сервер. Таким образом, у Accounting-демона и прочих компонентов биллинговой системы появляется возможность по IP-адресу отличать соединения, требующие или не требующие их контроля.

Кроме того, из зависимостей для сборки убраны autoconf и automake, так как исходные тексты принято поставлять с файлами Makefile и Configure, уже сгенерированными этими утилитами.

Небольшой дополнительный пакет pptpd-portslave содержит сценарий для запуска portslave для соединений, устанавливаемых PPTP-сервисом, и образцы изменений, которые надо внести для его поддержки в файлы конфигурации PPTPd.

Apache mod_auth_radius

Когда пользователь обращается к своей учётной записи и статистике через Web-браузер, Web-сервер Apache должен иметь возможность проверить пользовательские имя и пароль в общей учётной базе. Для этого к Apache подключается дополнительный внешний модуль mod_auth_radius, который производит их проверку на указанном RADIUS-сервере. Для того, чтобы этот модуль вызывался при загрузке пользовательского интерфейса, в каталоге на сервере помещается файл .htaccess с достаточно красноречивым содержимым:

AuthName "E-Billing user authentication"                                              
AuthType Basic                                                                        
AuthAuthoritative off                                                                 
AuthRadiusAuthoritative on                                                            
require valid-user

Примечание: сам пользовательский интерфейс и .htaccess находятся в пакете ebilling-user.

Spec-файл для mod_auth_radius написан с нуля. Конфигурационный файл для Apache, включённый в пакет, после установки требует исправления вручную.

Не исключено, что в дальнейшем вместо непосредственной авторизации Apache на RADIUS-сервере окажется удобнее включить в Apache стандартную авторизацию через PAM и настроить pam_radius_auth.

MySQL

Единственное отличие нашей сборки MySQL от соответствующего пакета ALT Linux состоит в использовании InnoDB -- драйвера, дающего MySQL поддержку транзакций (и не только). Сейчас нами используется версия 3.23. Поскольку в версии 4.0 поддержка InnoDB включена по умолчанию, необходимость собирать собственный пакет отпадёт. Однако даже сейчас вы можете использовать вместо него пакет от ALT Linux'a, пересобрав его следующей командой:

    rpmbuild --rebuild --with=innodb MySQL-3.23*.src.rpm

Как минимум один компонент e-Billing'a в настоящий момент жёстко привязан к связке MySQL/InnoDB и не позволяет заменить её на другой SQL-сервер. Это сценарий configs/tables.sql, создающий структуру таблиц, используемых для сохранения текущей отчётности.

Библиотеки

Библиотеки не нуждаются в настройке, однако для каждой из них здесь приводится краткое описание. Если у вас настроены на наш репозитарий утилиты APT или YUM, а описания не интересны, вы можете полностью пропустить этот раздел.

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

DBSTEP

Для доступа к SQL-базам используется библиотека dbstep. dbstep служит промежуточным слоем между пользовательским приложением на Си++ и клиентской библиотекой для связи с SQL-сервером конкретной марки (сейчас поддерживаются библиотеки MySQL и PostgreSQL). Достоинств у такой схемы два:

  • от разработчика приложения спрятаны все различия в SQL-диалектах;
  • вместо ручной работы со строками SQL-инструкций или низкоуровневых вызовов на Си предлагается стройный набор классов на Си++ со всеми преимуществами ООП: наследованием, перегрузкой операторов и т.д.

Для сборки требуются библиотеки mysqlclient (в ALT Linux Master должен быть установлен виртуальный пакет MySQL-devel, предоставляемый физическим libMySQL-devel с динамической компоновкой или libMySQL-devel-static для статической) и pq3 (RPM-пакеты postgresql-devel и libecpg3/libpq3(-devel) ).

Spec-файл написан с нуля.

Boost

Boost -- это библиотека для Си++, назначение которой заключается в трёх вещах.

Во-первых, Boost содержит наборы классов для областей, которые не охвачены стандартной библиотекой Си++:

  • регулярные выражения (regular expressions);
  • сигналы;
  • многопоточность (multithreading).

Помимо этого, Boost содержит несколько десятков мелких модулей, посвящённых самым разным вещам: преобразованию дат, smart-указателям, манипуляциям битами и т.д.

Первоначально проект Boost был основан отдельными членами Комитета по стандартизации Си++ как полигон для обкатки новых функций. С увеличением числа разработчиков Boost стал развиваться независимо, однако избегая дублирования или конфликтов со стандартной библиотекой.

Во-вторых, Boost восполняет некоторые пробелы, имеющиеся в стандартной библиотеке. Например, встроенные массивы Си++ не обладают полезными свойствами библиотечных контейнеров, в частности, не поддерживают перебора (enumeration). В то же время библиотечные контейнеры несут в себе не всегда нужную, но дорогую универсальность, например, способность увеличивать размер за счёт размещения данных в динамической памяти. В Boost'e предложено компромиссное решение -- контейнер фиксированного размера, который удобнее, чем встроенный массив, и быстрее, чем контейнер из стандартной библиотеки.

В-третьих, исходные тексты Boost, сопровождающая их документация и общий стиль управления проектом являются прекрасным пособием для тех, кто желает усовершенствовать свои навыки программирования на Си++.

Сборка для ALT Linux Master 2.2 разбита на 10 пакетов:

  • boost-devel -- заголовочные файлы .hpp с базовыми шаблонами (обратите внимание, что не-devel-вариант отсутствует за ненадобностью);
  • boost-jam -- простая, но удобная утилита управления сборкой проекта, альтернативная make;
  • boost-python и boost-python-devel -- генерация заголовочных файлов для языка Python из заголовочных файлов .hpp для Си++;
  • boost-regex и boost-regex-devel -- регулярные выражения;
  • boost-signals и boost-signals-devel -- сигналы;
  • boost-thread и boost-thread-devel -- многопоточность.

В настоящий момент e-Billing использует boost-regex и boost-lexical_cast из состава ALM в коде агентов и RLM.

libDaemon

Библиотека libDaemon содержит набор функций-оболочек, облегчающих разработчику приложения следующие задачи:

  • запуск в качестве демона (порождение потомка, открепление от консоли);
  • вывод статистики в syslog, STDERR или файл;
  • создание т.н. PID-файлов, через которые демон сообщает утилитам операционной системы свой идентификатор процесса;
  • перехват сигналов от операционной системы и сообщение о них через «трубу» («pipe») приложению (чтение производится с помощью системных вызовов select или poll).

Использование libDaemon облегчает не только разработку демона для одной конкретной платформы, но и (потенциально) перенос на другие плаформы, так как все перечисленные вопросы в разных Юникс-совместимых ОС решены по-разному. В настоящий момент libDaemon поддерживает только Линукс. Первая и единственная пока версия с номером 0.1 вышла в июле 2003 года.

Spec-файл написан с нуля.

libNetxx

У классического Си-интерфейса к функциям TCP/IP есть два недостатка:

  • неполная переносимость между Posix и Win32, IPv4 и IPv6, SSL и plain transer, и т.д.
  • сложность, которую можно проиллюстрировать следующим примером:
    /* Initiate incoming connections at server side */
    int s;
    struct sockaddr_in my_addr;
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* 0 = IP proto */
    	perror("socket");
    	return -1;
    }
    memset(<my_addr, 0, sizeof(my_addr));
    my_addr.sin_family      = AF_INET;
    my_addr.sin_addr.s_addr = INADDR_ANY;
    my_addr.sin_port        = htons(port);
    if (bind(s, (struct sockaddr *)<my_addr, sizeof(my_addr)) < 0) {
    	perror("bind");
    	return -1;
    }
    if (listen(s, MAX_INCOMING_CONNECTIONS) < 0) {
    	perror("listen");
    	return -1;
    }
      

По этим причинам все высокоуровневые языки предоставляют набор классов-обёрток, упрощающих типовые задачи до одной-двух строк. Например, в Яве аналогичный код будет выглядеть так:

ServerSocket listeningSocket = new ServerSocket(port);

В состав стандартной библиотеки Си++ средства для работы с сетью не входят, а библиотеки сторонних разработчиков получить должного распространения не сумели. Тем не менее, libNetxx является попыткой предоставить программисту на Си++ компактный, удобный и универсальный интерфейс.

Предоставляется только поддержка системных вызовов, без прикладных протоколов типа SMTP или HTTP, но с заявленной кроссплаформенностью, поддержкой SSL/TLS и интеграцией в стандартный механизм потоков ввода-вывода Си++.

e-Billing использует libNetxx только для связи mpd-агента с mpd-консолью, так что, возможно, вместо привлечения дополнительной библиотеки всё же имело смысл вручную написать священную последовательность классических вызовов установки связи на Си.

Spec-файл написан с нуля.

Xerces-C

Xerces представляет из себя XML-парсер, то есть библиотеку, которая отвечает за чтение XML-файлов, их синтаксический разбор в соответствии с заданной схемой и представление в одном из двух видов: в виде дерева классов (DOM-парсер), либо вызывая подпрограммы, которые главный программный модуль ассоциирует с тегами XML-файла (SAX-парсер).

Существует две реализации Xerces: базовая, написанная на Яве, и повторяющая её реализация на/для Си++. Очевидно, что e-Billing использует вторую.

В XML-виде e-Billing хранит все настройки в каталоге /etc/ebilling.

Имевшийся spec-файл изменён в соответствии с соглашениями ALT Linux Team, кроме того, из devel-пакета вынесены примеры.

Поскольку Веб-страница представляет из себя совокупность данных (content), внешнего вида (presentation) и поведения (application logic), её составлением могут быть заняты до трёх категорий разработчиков: автор, дизайнер (template designer) и программист. Прикладываются значительные усилия, чтобы сделать их труд максимально независимым друг от друга.

Существуют ситуации, когда отделить оформление от вычислений довольно трудно. Например, пусть следует прочесть массив строк из текстового файла и поместить их в блок <SELECT>...</SELECT>, раскрасив разными цветами чётные и нечётные строки. Если использовать для решения этой задачи такой язык, как PHP, конструкции HTML и PHP окажутся неразрывно переплетены. Для работы с ними либо дизайнеру придётся стать программистом, либо программисту - дизайнером.

Следовательно, возникает необходимость в инструменте, который позволит (а) вынести из HTML-шаблона описываемую программистом логику генерации HTML-фрагментов в отдельный файл, (б) многократно использовать готовые логические определения, а также (в) создавать свои собственные. Синтаксис вызываемых дизайнером определений должен быть проще, чем синтаксис универсального языка программирования.

Программу, которая обрабатывает текстовый поток, отыскивая в нём имена определений и заменяя их на тела определений, называют макропроцессор, а определения, соответственно, макросами. Из программ данного класса наиболее широко употребляются встроенный препроцессор языка Си и универсальный макропроцессор m4.

Smarty является макропроцессором для HTML и сам, в свою очередь, написан на PHP. Пользователь по-прежнему видит в Web-браузере страницы с расширением .php, при обращении к которым Web-сервер динамически генерирует HTML, но теперь php-файлы выглядят примерно так:

	// This is application logic part, created by developer
	include('Smarty.class.php');

	// create object
	$smarty = new Smarty;

	// assign some content
	// This is content part, created by data producer
	// Normally this part should be readed from database
	$smarty->assign('name', 'Amid Vosur');
	$smarty->assign('address', 'Guantanamo');
	$smarty->assign('id', array(1,2,3,4,5));
	$smarty->assign('names', array('ali','akbar','moustafa','maghomed','ahmad'));

	// display it
	$smarty->display('index.tpl');

Шаблоны страниц в файлах с расширением .tpl имеют вид подобный следующему:

	//This is presentation part, created by designer
	{include file="header.tpl" title="User Info"}

	<p>Prisoner Information:<p>
	
	Name: {$name|capitalize}<br>
	Address: {$address|escape}<br>

	<p>Select best friend:</p>

	<select name=friend>
	{html_options values=$id output=$names selected="5"}
	</select>

	{include file="footer.tpl"}

Таким образом, дизайнер (а) практически полностью избавляется от программирования, (б) получает в своё распоряжение богатую библиотеку готовых макросов (в примере выше их используется три - include, html_options и $ для подстановки значения переменной), а также (в) потенциальную возможность поручать разработчику создание специализированных макросов под собственные нужды.

Ниже приведён список вводной информации по Smarty:

Практически для всех языков программирования, используемых для генерации Веб-страниц, дополнительно существуют написанные на них макропроцессоры, призванные упростить жизнь дизайнеру-составителю шаблонов. Примером может служить макропроцессор Velocity, написанный на языке Java.

LibUCVT ???

common.cpp: инициализация/завершение библиотеки: -//- XML

crc.cpp: -

log.cpp: void c_log(int error_level, const char *format, ...)

options.cpp:

other.cpp: read_file, print_backtrace

persistent.cpp: implementation of class Storage

Настройка

Сейчас файлов настройки в каталоге /etc/ebilling три:

  • server.conf -- определяет системное окружение (IP-адрес, порт, логин и пароль к SQL-серверу, частоту для проверки активности сервисов, имя файла тарифных политик и т.д.)
  • policies.conf -- файл тарифных политик
  • agents.conf -- список агентов для связи с NAS'ами

Все три настроечных conf-файла имеют XML-формат. Каждый из них (кроме agents.conf, который имеет произвольные имена тэгов для описания агентов by_command) сопровождается обязательным файлом с таким же именем и расширением .xsd, в котором хранится описание структуры первого файла, записанное на языке XML Scheme (соответственно, xsd расшифровывается как XML Scheme Definition). Второй файл нужен программе для синтаксического разбора первого. Примеры конфигураций находятся в файлах .conf.sample, которые сейчас устанавливаются в каталог с документацией.

В настоящий момент часть настроек из conf-файлов дублируется в SQL-таблицах. Зачем это сделано? Казалось бы, скорость доступа и компактность хранения, которые предоставляет хранение в СУБД, не дают преимуществ для работы с настройками, потому что настройки имеют небольшой размер и редко пишутся-читаются. Кроме того, текстовый файл легче редактировать вручную, чем таблицу в базе данных.

С другой стороны, система должна предоставлять пользователям возможность работать с настройками через Веб-интерфейс. В этом случае СУБД способна предоставить более высокую степень защиты и более гибкие права доступа к данным, чем файловая система без использования дополнительных инструментов (jail, RSBAC и т.д.).

По этой причине, начиная с одной из следующих версий, из сonf-файлов останется только server.conf, так как в нём находятся сведения, необходимые для подключения к СУБД. Сейчас acctd и RLM читают настройки как из файлов, так и из БД, а Web-компоненты -- только из БД.

server.conf

<?xml version = "1.0"?>
<options>
    <db
        dbtype = "тип_СУБД"    <!-- MySQL, PostgreSQL, FireBird или SQLite -->
        dbname = "имя_БД"
        host = "IP-адрес_или_DNS-имя_сервера_БД"
        user = "имя_пользователя_для_подключения_к_серверу_БД"
        password = "пароль_пользователя" />
    <ip_pool
        ip_2part = "A.B" />   <!-- начальная часть назначаемых клиентам IP-адресов -->
    <policies
	file = "поный_путь_файла_с_описаниями_пользовательских_политик"
	xsd = "полный_путь_файла_со_схемой_парсинга" />
    <radius_auth
	retries = "количество_попыток_повтора"
	timeout = "вещественное_число_секунд_между_попытками" />
    <acctd
	check_interval = "целое_число_секунд-интервал_опроса_NASов_accounting-демоном"
	agents_file = "полный_путь_файла_с_описаниями_агентов_управления_NASами"
	agent_modules_path = "полный_путь_каталога_с_агентами" />
    <hostname_resolver
        cache_mode = "режим_кэширования_DNS_имён_в_RLM" /> <!-- "cache" или "" -->
</options>

Пример:

<?xml version = "1.0"?»
<options>
    <db
        dbtype = "MySQL"
        dbname = "ebilling"
        host = "127.0.0.1"
        user = "ebilling"
        password = "some_very_secure_password" />
    <ip_pool
        ip_2part = "10.30" />
    <policies 
	file = "/etc/ebilling/policies.conf"
	xsd = "/etc/ebilling/policies.xsd" />
    <radius_auth
	retries = "5"
	timeout = "1.0" />
    <acctd
	check_interval = "300" 
	agents_file = "/etc/ebilling/agents.conf"
	agent_modules_path = "/usr/lib/ebilling-acctd" />
    <hostname_resolver
        cache_mode = "cache" />
</options>

IP-адреса клиентов

RADIUS-протокол предусматривает, что при желании администратора IP-адрес, назначаемый NAS'ом подключившемуся клиенту, не генерируется NAS'ом самостоятельно, а сообщается ему RADIUS-сервером, который, в свою очередь, может получать его от RLM-модуля. RLM из состава e-Billing формирует IP-адрес следующим образом:

  • первые два поля берутся из директивы ip_2part в файле server.conf;
  • поле C назначается равным идентификатору группы, которой принадлежит пользователь (см.таблицу Groups);
  • поле D назначается первым незанятым номером линии в таблице IP_pool.

Такая схема предоставляет следующие возможности:

  • назначение статических политик фильтрации для групп клиентов, используя поле C;
  • назначение динамических политик фильтрации для данного клиента, используя поле D;
  • прочий контроль за работой клиента посредством многочисленных стандартных сетевых утилит, использующих IP-адрес.

policies.conf

<?xml version = "1.0"?>
<options>
    <!-- Список единиц стоимости -->
    <money name="название">
        <!-- Список образующих единицу стоимости денежных единиц -->
	<currency name="имя-денежной-единицы"
	    count="вещественное-количество-денежных-единиц-в-единице-стоимости" /> ...
    </money>
    <!-- Список тарифов на услуги -->
    <tariff name="название-тарифа"
        out_traffic="единица-стоимости-трафика-от-NAS-к-клиенту"
        in_traffic="единица-стоимости-трафика-от-клиента-к-NAS"
        time="единица-стоимости-времени" />
    <!-- Список тарифных планов -->
    <policy 
	name="имя-тарифного-плана"
	comment="выразительный-комментарий"
	simultaneous_connections="макс.количество"
	daily="единица-стоимости-взымаемая-ежедневно"
	profit_interval="период-начисления-кредита-в-сутках"
	profit="единица-стоимости-содержащая-размер-кредита"
	profit_mode="что-делать-с-неистраченным-кредитом">
	<!-- значения: add=добавлять-к-старому,
	    replace=обнулять-старый-перед-добавлением,
	    none=не-начислять-кредит -->
        <!-- Список временных интервалов -->
	<interval
		begin_day="день-недели"
		begin_hour="час"
		end_day="день-недели"
		end_hour="час"
		name="all_week">
		    <!-- Список типов устройств -->
		    <nas_type name="название-типа"
			tariff="название-применяемого-тарифа"
			ppp_filter="значение-атрибута-Framed-Filter-ID-отправляемое-NAS'у" />
	    </interval>    
    </policy>	
</options>

Пример:

<?xml version = "1.0"?>
<options>
    <money name="none">
	<currency name="USD" count="0" />
    </money>
    <money name="deny" />
    <money name="rich">
	<currency name="USD" count="1" />
    </money>
    <money name="my_daily">
	<currency name="USD" count="0.6666" />
    </money>
    <money name="monthly_limit">
	<!-- Way to implement monthly, daily, weekly... any limits -->
	<currency name="USD" count="40" />
    </money>
    <tariff name="rich_tariff" out_traffic="none" in_traffic="none" time="rich" />
    <policy 
	name="my_policy"
	comment="Full access 7x24 - too rich"
	simultaneous_connections="2"
	daily="my_daily"
	profit_interval="30"
	profit="monthly_limit"
	profit_mode="replace"> <!-- values: add, replace, none -->
	<interval
		begin_day="0"
		begin_hour="0"
		end_day="6"
		end_hour="23"
		name="all_week">
		    <nas_type name="VPN" tariff="rich_tariff" ppp_filter="strict" />
		    <nas_type name="Cisco" tariff="rich_tariff" />
	    </interval>    
    </policy>	
</options>

agents.conf

<?xml version = "1.0"?>
<options>
    <!-- Данные для агента by_command -->
    <произвольно-выразительное-имя
	temp="команда_выполняемая_перед_командами_stat_и_kill"
	stat_cmd="команда_получения_данных_от_NASа"
	kill_cmd="команда_принудительного_завершения_работы_NASa" />
    <!-- ... ещё данные для агентов by_command -->
    <!-- Данные для агента mpd -->
    <mpd
        host="IP-адрес-или-DNS-имя"   >!-- это поле необязательно и по умолчанию равно NAS-IP -->
        port="номер-IP-порта"
        password="пароль-для-подключения-к-MPD-консоли"
        timeout="таймаут-в-секундах" />    
    <!-- ... ещё данные для агентов mpd -->

</options>

Пример:

<?xml version = "1.0"?>
<options>
    <local-portslave
        <-- по IP-адресу клиента узнаём имя логического сетевого устройства,
	    через которое клиент подключён, и сохраняем имя устройства в %{Temp} -->
	temp="/sbin/route -n | /bin/fgrep %{Client-IP} | /usr/bin/awk {'print $8'}"
	<-- узнаём количество байт, принятых и переданных через сетевое устройство -->
	stat_cmd="/bin/fgrep %{Temp} /proc/net/dev | /usr/bin/awk {'print $2 &#x22; $10'}"
	<-- уничтожаем демона, обеспечивающего работу сетевого устройства -->
	kill_cmd="kill -s TERM `/bin/cat /var/run/%{Temp}.pid`" />
    <mpd
        host="10.10.1.1"
        port="7992"
        password="mynameisebill"
        timeout="1" />
</options>

В agents.conf допустимо использование следующих переменных в форме %{имя_переменной}:

  • Client-IP -- не нуждается в комментарии...;
  • Temp -- то, что команда temp вывела в STDOUT;
  • NAS-IP -- IP-адрес NAS'a, запрашивающего у RADIUS-сервера аутентификацию пользователя;
  • NAS-PORT -- целочисленный идентификатор соединения, присвоенный NAS'ом для сессии данного клиента;
  • NAS-Session-ID -- значение генерируемого NAS'ом атрибута Acct-Session-Id, хранящего уникальный для данного NAS'a в ходе всей его работы идентификатор сессии;
  • NAS-Type-ID -- номер из таблицы NAS_Types, хранящей описания типов различных сервисов.
  • NAS-ID -- номер из таблицы NAS, хранящей IP-адреса и описания сервисов.

Состав перемененных планируется расширять по мере необходимости. В данный момент в него в основном включены сведения, которые e-Billing использует при генерации статистики.

SQL-таблицы

При инсталляции e-Billing'a в каталог с настройками помещаются два сценария: интерактивный для bash'a, который создаёт базу данных MySQL, и сценарий для SQL-консоли, который создаёт таблицы. Второй сценарий вызывается из первого, поэтому вызывать его вручную не нужно. Кроме того, шелл-сценарий создаёт server.conf.

В приведённом ниже списке термином «номер» для краткости обозначаются автоинкрементные счётчики, служащие по совместительству первичными ключами и используемые для связей между таблицами.

Текущий состав таблиц:

  • Currency -- номер и имя денежной единицы.
  • Domains -- номер и имя домена, а также сервер, отвечающий за авторизацию в этом домене. Домен сообщается пользователем NAS'у в составе логина в момент аутентификации, например: «pupkin@spb01.ucvt.ru». Имя сервера авторизации задаётся в URI-формате «proto://dns-name-or-IP-address». Единственным протоколом для связи с сервером, поддерживаемым в данный момент, является «radius». Кроме того, допустим префикс local, при котором пароль пользователя хранится непосредственно в его учётной записи. По мере необходимости может быть добавлена поддержка pam, smb, http и т.д.
  • Groups -- номер, имя и описание группы, с номером применяемой для данной группы тарифной политики;
  • IP_pool -- список IP-адресов, выданных NAS'ами клиентам в данный момент: идентификатор группы (поле С), собственно IP-адрес, время создания, уникальный в данный момент идентификатор сессии в формате «NAS-IP-address:session-physical-port».
  • NAS_types -- номер и имя категории NAS'ов, номер агента, служащего для управления данной категорией.
  • Agents -- номер, имя-заголовок и имя файла динамической библиотеки без указания каталога и суффикса .so.
  • Policies -- номер, название и описание тарифной политики.
  • Price -- номер и название единицы стоимости определённого ресурса, образуемой множеством записей из Price_data.
  • Price_data -- номер единицы стоимости из Price, номер денежной единицы из Currency, коэффициенты??? Записей с разными денежными единицами для одной и той же единицы стоимости может быть несколько.
  • Sessions -- статистика по текущим и прошедшим сессиям:
    • тип и IP-адрес NAS'a, номер порта;
    • идентификатор клиента (номер телефона для PPP или IP-адрес для VPN);
    • IP-адрес, назначенный клиенту NAS'ом;
    • время начала и завершения сессии;
    • количество принятых и отправленных байт.
  • Users -- информация о пользователе:
    • номер, имя (pupkin);
    • номер тарифной группы;
    • номер домена авторизации (spb01.ucvt.ru);
    • комментарий;
    • пароль, используемый в локальном домене, т.е. в домене, сервер авторизации которого имеет префикс local://;
    • дата последнего пополнения счёта;
    • флаг временного запрета.
  • Users_balance -- номер пользователя и денежной единицы, в которой производится расчёт; остаток средств в данной единице (вещественное число). Одному пользователю может соответствовать несколько записей с балансами для разных денежных единиц.
  • Reports -- ???

Все таблицы, кроме Sessions и IP_Pool, являются настроечными. Sessions хранит текущее состояние и архивную статистику. IP_Pool также хранит текущее состояние и, в принципе, могла бы быть поглощена Sessions, но оставлена отдельной для повышения быстродействия.

Пользовательский интерфейс и генерация отчётов

???

Какая система планировалась вначале

С самого начала было поставлено условие, что требуется независимо считать доступ во внутреннюю сеть (через PPP-сервис) и в Интернет, т.е. требуются неконвертируемые деньги за непересекающиеся услуги. Доступ в Интернет планировалось разрешать не на системном уровне (через NAT/фильтр/...), а только на прикладном -- через Squid и Postfix.

О том, что такое RADIUS, мы, естественно, знали, но поскольку его поддержка существовала только в PPP-сервисе, то в тот момент было решено не добавлять её в Squid и Postfix, а составлять полностью новый протокол.

Кроме того, у нас сложилось впечатление, что без серьёзных дополнительных усилий ни один существующий RADIUS-сервер не сможет оперировать несколькими денежными единицами одновременно. Первое впечатление оказалось не вполне верным: добавить поддержку подобной системы расчётов в современный RADIUS-сервер гораздо проще, чем проектировать вокруг неё оригинальное окружение.

Тем не менее, оригинальное ядро биллинговой системы было написано и получило название «Центр принятия решений», сокращённо «ЦПР», по-английски, соответственно, «e-Billing Decree Centre» или «EDC». Это был первый компонент системы.

К моменту начала работ в УЦВТ имелось несколько несвязанных доменов сети Microsoft, плюс сеть Lotus Notes/Domino со своей собственной базой пользователей и системой авторизации. Создавать ещё одну пользовательскую базу не хотелось, поэтому ЦПР должен был уметь извлекать информацию из существующих баз, причём нескольких, причём разнотипных.

За выполнение этой задачи отвечал второй компонент, названный «distauth» (от «distributed authorization», т.е. «распределённая авторизация»). Подразумевалось, что имя пользователя будет включать в себя имя домена (например, vasya@lotus), а distauth на основании настроек оттранслирует имя домена в адрес компьютера, тип протокола и прочие параметры соединения (например, https://www.ucvt.ru/?login).

Более смелые замыслы включали в себя:

  • обращение к контроллеру домена, обслуживающему сеть, которой принадлежит IP-адрес клиента, чтобы по записям в EventLog'e определить имя пользователя;
  • если между Интернет-шлюзом и клиентской сетью расположен промежуточный NAT, получение от него distauth'ом текущей таблицы трансляции адресов, чтобы узнать истинный IP-адрес «спрятавшегося» клиента;
  • сооружение причальной мачты для дирижаблей на крыше УЦВТ.

Первая версия distauth должна была поддерживать минимальный набор: явную авторизацию по имени/паролю с проверкой через LDAP, SMB, PAM и HTTPS. Так и не была написана.

Третьим компонентом являлись т.н. агенты управления сервисами, каждый из которых отвечал за получение статистики от соответствующего сервиса, передачу её ЦПР и манипулирование сервисом по полученным от ЦПР указаниям.

Были написаны два агента: для управления PPPD и для управления Сквидом.

Управление сервисом могло предусматривать такие вещи, как загрузку таблицы пакетной фильтрации для PPP-интерфейса после того, как на нём авторизовался пользователь (например, пользователю newuser разрешается маршрутизация только к серверу register.ucvt.ru), сброс пакетного фильтра после разъединения, загрузку в Squid назначенной для данной группы таблицы URL, которые должны быть заблокированы или перенаправлены, и т.д.

Агенты связывались с ЦПР через сеть, вызывая его подпрограммы по протоколу SOAP (Simple Objects Access Protocol), для чего использовалась библиотека gSOAP. Для конфигурационных файлов и передачи структур через SOAP уже тогда был выбран формат XML, для синтаксического разбора которого использовался парсер Xerces-C.

Каждый агент должен был быть выполнен в виде PAM-модуля и взаимодействовать с управляемым сервисом исключительно через PAM-интерфейс. Для этого при необходимости предполагалось модифицировать исходные коды сервиса, по мере возможности не выходя за рамки PAM. Такой подход имел два достоинства:

  • появлялась возможность дополнительного управления сервисом через произвольные PAM-модули;
  • повышалась вероятность, что изменения будут приняты в официальное дерево разработки сервера.

На практике ограничения PAM заставили переносить часть агента в тело сервиса и использовать для связи между частями агента в PAM-модуле и сервисе дополнительные средства (именованные каналы и т.д.).

Четвёртым компонентом должна была стать система сбора статистики, развитие logrider'a, которая должна была делать следующее:

  • пропускать стандартные отчёты syslog через некие конфигурируемые фильтры для приведения в реляционный вид и сохранять в реляционной базе SQL, TDB или BerkeleyDB;
  • выдавать в виде дерева статистику, упорядоченную или обобщённую одновременно по нескольким параметрам: имени компьютера, пользователя, IP-адресу, интервалу времени, типу сервиса, идентификатору процесса, типу сообщения, его полям и т.д.

Система статистики была признана не имеющей отношения к биллинговому ПО, так как биллинговое ПО нуждается в оперативном доступе к ограниченному количеству информации, а система статистики в заявленном виде предоставляет информации больше, чем нужно, но с задержкой. Её разработка, к сожалению, так и не была начата.

Последним, пятым компонентом проекта являлась так же ненаписанная консоль оператора на Delphi или PHP+HTML.

Причины отказа от продолжения разработки

Во-первых, по мере развития проекта стало ясно, что разместить всю требуемую от PPP- или Squid-агента функциональность внутри PAM-модуля не удастся. Например, для чтения таблицы фильтрации Веб-адресов Squid использует свой собственный примитивный программный интерфейс, использование в котором PAM-вызовов выглядело бы совершенно противоестественным.

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

Перечисленные причины сделали невозможным унифицировать интерфейс между агентами и сервисами.

Во-вторых, отказ от собственного интерфейса между ЦПР и агентами был вызван тем, что было добавлено условие управлять dialup-сервисом на базе Cisco. Хотя "кошкой" можно управлять через rsh, а снимать с неё статистику через IP accounting, в тот момент половина разработчиков не участвовала в обсуждении, а оставшаяся половина разработчиков этого не знала. Поскольку в результате RADIUS выглядел единственным возможным средством управления, то место ЦПР занял FreeRADIUS с ebilling-специфичными модулями. Кстати, требование поддерживать Cisco впоследствии было снято под нашим давлением. Наши аргументы были следующими:

  • её областью применения является передача дорогой информации по дорогим каналам, чего в отечественной практике почти не встретишь;
  • в противном случае её стоимость превышает все разумные пределы;
  • в случае, если необходима авторизация, Циска требует наличия RADIUS-сервера, и её пресловутая автономность-надёжность-защищённость ничего не стоит, если такой сервер работает на обычном ПК;
  • Циску сложнее конфигурировать и практически невозможно нагружать дополнительными сервисами и утилитами.

Выбор названия

Хорошее название, с одной стороны обязано не быть бесцветным, так как на фоне многочисленных и проверенных временем NetAMS'ов, MABill'ов, UTM'ов и NIBS'ов новый продукт неизбежно затеряется. С другой стороны, название не должно быть оторванным от предметной области. Обоим требованиям первоначальный вариант -- е-Вilling -- соответствовал едва ли не идеально. Стоит лишь произнести его вслух, и редкого русскоязычного читателя заставишь заучивать его дважды. Увы, соображения маркетинга заставили нас пожертвовать им в пользу уныло-безликого TBS, что расшифровывается как TBS Billing System. В стороне остался и такой несомненно удачный вариант, как d'Вilling.

Впрочем, не всё ещё потеряно. Работа над системой продолжается!



Хостинг от uCoz