Pull to refresh

Развертывание биллинга для небольшой сети с нуля

Reading time 11 min
Views 62K
Предыстория:
Некие хорошие люди решили начинать провайдерский бизнес. Растянули и разварили оптику в небольшом районе, поставили ящички, засунули туда минимальные свичи, с помощью которых можно организовать VLAN-Per-User, закупили небольшой, для начала, канал у ближайшего магистрала. Встал у них вопрос о том, чем же считать пользователям трафик/денежки и нарезать скоростя.
Общая схема сети должна выглядеть следующим образом:



Кому интересно, далее под катом очень много букв и картинок.


Условности:
— Шлюз аплинка будет 1.2.3.3
— Сетевые адаптеры NAS смотрящие на аплинка будут в сети 1.2.3.3/24
— Сеть, предоставляемая пользователям, будет 172.16.0.0/18, или, если угодно, 255.255.192.0
— IP адреса 172.16.0.0-172.16.0.10 мы резервируем для серверов доступа и прочих собственных нужд
— Сервер пользовательской статистики будет доступен по адресу stat.isp и, учитывая бюджетность решения, будет находиться на одном хосте с биллинговым сервером, хотя хорошим тоном является не только разделять биллинг и трафик абонентов, но и разносить на раздельные хосты БД, ядро биллинга и веб-интерфейс.

Изначальные потребности были четко оговорены:
— Проектная емкость сети — до 10000 абонентов
— Раздача IP абонентам при помощи DHCP
— Авторизация либо по связке IP+MAC
— Несколько полностью безлимитных тарифов
— Трафик все же считать нужно для контроля
— Очень желательно видеть активность каждого отдельного пользователя
— Разделение прав касиров/бухгалтеров/менеджеров/администраторов
— Возможность масштабирования решения относительно роста количества абонентов
— Так как своей АС еще нету и в наличии имеются три с половиной айпишки, выданных аплинком, первых пользователей предполагается NAT-ить.
— Естественно все это максимально бюджетно :)
Беглое изучение ассортимента opensource биллинговых систем показало, что оптимальным в данной ситуации может оказаться Stargazer по следующим причинам:
— Проект открыт, активно развивается, новые версии выходят с завидным постоянством.
— Не страдает врожденной монстроидальностью и позволяет допиливать функционал не привязываясь к внутренней механике
— Ядро написано на C/C++ и категорически быстрое
— Большой выбор методов подсчета трафика
— На выбор поддержка хранения данных в Файлах/MySQL/Firebird/PostgreSQL
— Волшебный механизм исполнения команд на удаленных серверах
Установка будет проходить на голую FreeBSD 8.2-RELEASE, установленную в варианте kern-developer + порты. Весь трафик пользователей будем рулить через удаленный NAS на все
той же FreeBSD 8.2, производя по нему NAT/Shape/NetFlow и отрисовку графиков загрузки абонентского канала при помощи bandwidthd. В роли вебинтерфейса для stargazer 2.407-p1 у нас будет выступать последний на момент написания топика Ubilling 0.1.7, хотя выбор фронтендов у Stargazer довольно широк — от Win-конфигуратора до нескольких консольных и XML-RPC API.
Далее прямой копипаст из консоли с периодическими заострениями внимания на концептуальных моментах.

Итак приступим к настройке биллингового сервера.

1. Морально готовимся
2. Установка зависимостей
  # cd /usr/ports/databases/mysql51-server/ && make install
  # cd /usr/ports/textproc/expat2 && make install
  # cd /usr/ports/devel/libtool && make all && make install
  # cd /usr/ports/security/sudo && make install

Для простоты isc-dhcp собираем без DHCP_PARANOIA
  
  # cd /usr/ports/net/isc-dhcp31-server/ && make install

php5 должен быть собран как минимум с поддержкой CLI и модулем Apache (последний должен нормально подтянуться зависимостью)
  
  # cd /usr/ports/lang/php5 && make install

Собираем жизненно необходимые расширения PHP, а именно: ставим галочки на MYSQL, MBSTRING и ICONV
  # cd /usr/ports/lang/php5-extensions/ && make config && make install


3. Собираем сам stargazer и его консольные конфигураторы в две строчки :)
  # fetch http://stg.dp.ua/download/server/2.407-p1/stg-2.407-p1.tar.gz && tar zxvf stg-2.407-p1.tar.gz && cd stg-2.407-p1/projects/stargazer/ && ./build && gmake install 
  # cd ../sgconf && ./build && gmake && gmake install && cd ../sgconf_xml/ && ./build && gmake && gmake install


4. Разворачиваем текущую версию Ubilling
  # cd /usr/local/www/data/
  # mkdir billing
  # cd billing
  # fetch http://ubilling.net.ua/ub.tgz
  # tar zxvf ub.tgz
  # chmod -R 777 content/ config/ multinet/ exports/ remote_nas.conf vservices.php

5. Делаем особую симлинковую магию
  # mkdir /etc/stargazer/dn
  # chmod -R 777 /etc/stargazer/dn
  # ln -fs /usr/local/www/data/billing/multinet /usr/local/etc/multinet
  # ln -fs /usr/local/www/data/billing/remote_nas.conf /etc/stargazer/remote_nas.conf
  # ln -fs /etc/stargazer/dn /usr/local/www/data/billing/content/dn 

6. Запускаем Apache и MySQL
  # /usr/local/etc/rc.d/mysql-server start
  # /usr/local/etc/rc.d/apache onestart


7. Устанавливаем новый пароль пользователя root для mysql (newpassword — для примера)
#mysqladmin -u root password newpassword

8. Приводим /etc/stargazer/stargazer.conf к следующему виду
LogFile = /var/log/stargazer.log 
PIDFile = /var/run/stargazer.pid 
Rules = /etc/stargazer/rules 
DetailStatWritePeriod = 1/4 
StatWritePeriod = 10 
DayFee = 1 
DayFeeIsLastDay = no 
DayResetTraff = 1 
SpreadFee = no 
FreeMbAllowInet = no 
WriteFreeMbTraffCost = yes 
FullFee = yes 
<DirNames> 
  DirName0 = Internet 
  DirName1 =
  DirName2 = 
  DirName3 = 
  DirName4 = 
  DirName5 = 
  DirName6 = 
  DirName7 = 
  DirName8 = 
  DirName9 = 
</DirNames> 
ExecutersNum = 1 
ModulesPath = /usr/lib/stg 
<StoreModule store_mysql> 
  dbhost = localhost 
  dbname = stg 
  dbuser = root 
  rootdbpass = newpassword 
</StoreModule> 
<Modules> 
<Module auth_ao> 
</Module> 
<Module auth_ia> 
  Port = 5555 
  UserDelay = 60 
  UserTimeout = 65 
  FreeMb = cash 
</Module> 
<Module conf_sg> 
  Port = 5555 
</Module> 
<Module cap_nf>
        TCPPort = 42111
        UDPPort = 42111
</Module>

<Module remote_script> 
SendPeriod = 10
SubnetFile =/etc/stargazer/remote_nas.conf
Password = пароль_для_rscriptd
UserParams=Cash Tariff
Port = 9999 
</Module>
</Modules> 


9. Редактируем конфиг /etc/stargazer/rules оставля аж одно нужное нам направление, а именно интернеты.
 # echo "ALL     0.0.0.0/0        DIR0" > /etc/stargazer/rules
 


10. Добавляем наш первый NAS в /etc/stargazer/remote_nas.conf
 # echo "172.16.0.0/18 172.16.0.2" > /etc/stargazer/remote_nas.conf


10. запускаем/останавливаем stargazer
  # stargazer
  # killall stargazer


11. Убеждаемся, что умолчальная БД развернулась
 # mysql -u root -p stg -e "S Enter password:
+---------------+
| Tables_in_stg |
+---------------+
| admins        |
| messages      |
| stat          |
| tariffs       |
| users         |
+---------------+


12. Редактируем /usr/local/etc/sudoers, добавляя туда пользователя, под которым будет работать Web интерфейс
User_Alias BILLING = www
BILLING         ALL = NOPASSWD: ALL


13. Разворачиваем дамп Ubilling
  # cd /usr/local/www/data/billing/
  # cat docs/test_dump.sql | mysql -u root -p stg


14. Убеждаемся, что все хорошо
  
#mysql -u root -p stg -e "SHOW TABLES" 
Enter password:
+-----------------+
| Tables_in_stg   |
+-----------------+
| address         |
| admins          |
| ahenassign      |
| apt             |
| build           |
| cardbank        |
| cardbrute       |
| cashtype        |
| cfitems         |
| cftypes         |
| city            |
| contracts       |
| contrahens      |
| cpe             |
| cpetypes        |
| dhcp            |
| directions      |
| dshape_time     |
| emails          |
| employee        |
| jobs            |
| jobtypes        |
| messages        |
| modem_templates |
| modems          |
| nas             |
| nethosts        |
| networks        |
| notes           |
| payments        |
| phones          |
| realname        |
| services        |
| servtariff      |
| speeds          |
| stat            |
| street          |
| switches        |
| switchmodels    |
| tags            |
| tagtypes        |
| tariffs         |
| taskman         |
| userreg         |
| users           |
| userspeeds      |
| vcash           |
| vcashlog        |
| vservices       |
| weblogs         |
+-----------------+


15. Редактируем файл config/billing.ini, доводя его до кондиции:
baseconf = sgconfxml
SGCONF=/usr/sbin/sgconf
SGCONFXML=/usr/sbin/sgconf_xml
STG_HOST=localhost
STG_PORT=5555
XMLRPC_PORT=8081
STG_LOGIN=admin
STG_PASSWD=новый_пароль_админа_stargazer
SUDO=/usr/local/bin/sudo
TOP = /usr/bin/top -b
CAT=/bin/cat
GREP=/usr/bin/grep
RC_DHCPD=/usr/local/etc/rc.d/isc-dhcpd
UPTIME=/usr/bin/uptime
PING=/sbin/ping
KILL=/bin/kill
STGPID=/var/run/stargazer.pid
STGNASHUP=1
PHPSYSINFO=phpsysinfo/
LANG = ua
TASKBAR_ICON_SIZE = 128
REGRANDOM_MAC=1
REGALWONLINE=1
REGDISABLEDSTAT=1


16. Разворачиваем заготовки стартовых скриптов
  # cp -f docs/presets/FreeBSD/etc/stargazer/config /etc/stargazer/
  # cp -f docs/presets/FreeBSD/etc/stargazer/GetMac /etc/stargazer/
  # chmod a+x /etc/stargazer/*


17. И делаем прибивание IP+MAC в скрипте /etc/stargazer/OnConnect

  
#!/bin/sh
LOGIN=$1
IP=$2
CASH=$3
ID=$4
MAC=`php /etc/stargazer/GetMac $LOGIN`
/usr/sbin/arp -S $IP $MAC

18. Редактируем конфиг /etc/stargazer/config, прописывая в него текущие параметры MySQL

host = localhost 
username = root 
password = newpassword 
database = stg


19. Аналогично редактируем конфиг config/mysql.ini

;database host
server = "localhost"
;database port
port = "3306"
;user login
username = "root"
;user password
password = "newpassword"
;database name to use
db = "stg"
character = "UTF8"
prefix = "billing"


20. Запускаем stargazer и меняем пароль администратора по умолчанию
  # stargazer
  # sgconf_xml -s localhost -p 5555 -a admin -w 123456 -r "<ChgAdmin Login=\"admin\" Password=\"новый_пароль_админа_stargazer\"/>"


21. приводим наш /etc/rc.conf к виду
gateway_enable="YES"
hostname="billing.isp"
ifconfig_em0="inet 172.16.0.1 netmask 255.255.192.0"
inetd_enable="YES"
keymap="ru.koi8-r"
sshd_enable="YES"
named_enable="YES"
sendmail_enable="NO"
mysql_enable="YES"
apache_enable="YES"
dhcpd_enable="YES"
dhcpd_flags="-q"
dhcpd_conf="/usr/local/etc/multinet/dhcpd.conf"
dhcpd_ifaces="em0"


22. Добавляем служебную зону ".isp" в /etc/namedb/named.conf
acl internals { 172.16.0.0/18; };
acl local { 127.0.0.1; };

zone "isp" {
    type master;
    file "/etc/namedb/master/isp";
    allow-query { internals; local; };
};


и в /etc/namedb/master/isp

$TTL    86400
@       IN      SOA     isp.           admin.isp. (
                        2011101001      ; Serial
                                8H      ; Refresh
                                1D      ; Retry
                                2W      ; Expire
                                1D )    ; Negative Cache TTL

        IN      NS      dns.isp.
@       IN      A       172.16.0.1


billing           IN      A       172.16.0.1
stat              IN      A       172.16.0.1
nas1              IN      A       172.16.0.2


23. Создаем стартовый скрипт запуска stargazer в /etc/rc.d/billing
#!/bin/sh
/usr/sbin/stargazer


и назначаем ему нужные права

# chmod a+x /etc/rc.d/billing


24. Прописываем нужные виртуалхосты в /usr/local/etc/apache/httpd.conf
NameVirtualHost *:80

<VirtualHost *:80>
ServerName billing.isp
DocumentRoot "/usr/local/www/data/billing/"
AddDefaultCharset utf-8
</VirtualHost>


<VirtualHost *:80>
ServerName stat.isp
DocumentRoot "/usr/local/www/data/billing/userstats/"
AddDefaultCharset utf-8
</VirtualHost>


25. Правим глобальный шаблон по которому будут генерироваться конфиги dhcp, он находиться вот здесь: /usr/local/www/data/billing/config/dhcp/global.template

option domain-name "isp";
option domain-name-servers 172.16.0.1;
default-lease-time 3600;
max-lease-time 43200;
authoritative;
ddns-update-style none;
log-facility local7;
one-lease-per-client true;
deny duplicates;

shared-network ourisp {
{SUBNETS}
}


26. Выставляем нужный уровень логирования для dhcpd в /etc/syslog.conf

27. Можем сделать профилактический ребут чтобы посмотреть как все подымается, либо поперезапускать все, что мы уже понастраивали вручную.

28. А теперь самое интересное ради чего все затевалось :)

Заходим на наш servername.isp/billing и логинимся с логином и паролем по умолчанию admin/demo (не забываем сразу же сменить) и видим следующую картину:



Добавляем нужный нам класс трафика:



Добавляем сеть и сервис (напоминаю, что мы резервируем первых 10 IP под свои нужды)



Добавляем сети обработчик DHCP



и применяем к нему свой шаблон подсети
subnet {NETWORK} netmask {MASK} {
default-lease-time 3600;
option domain-name "ourisp";
option subnet-mask {MASK};
option routers 172.16.0.2;
include "/usr/local/etc/multinet/{HOSTS}";
}


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

Проверяем, удачно ли создается конфиг dhcpd.conf в справочнике «Сети»



Добавляем свой первый тариф, пусть он будет зваться Unlim-1 и будет безлимиткой с абонплатой 50 денег в месяц



Навешиваем на него симметричную скорость в 1 мегабит/с



Добавляем наш сервер доступа который мы будем настраивать чуть пожже



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





Ну и вроде все, регистрируем нашего первого абонента




Назначаем ему MAC, тариф, вписываем Ф.И.О. и все что нужно в «редактировании», и, в общем-то, он должен работать.

Настройка NAS сервера.

Опять же, имеем Голую FreeBSD 8.2, от которой хотим, чтобы она выступала шлюзом по умолчанию для наших пользователей.
Нужные модуля можно и просто подгрузить, но это дело привычки, так что соберем ядро руками с попутным выкидыванием всего что нам не нужно.

# cd /usr/src/sys/i386/conf/
# cp GENERIC NAS1


Заменяем в конфиге нашего нового ядра ident GENERIC на NAS1

options IPFIREWALL 
options IPFIREWALL_DEFAULT_TO_ACCEPT 
options IPFIREWALL_FORWARD 
options IPFIREWALL_VERBOSE 
options IPFIREWALL_VERBOSE_LIMIT=50 
options IPFIREWALL_NAT 
options LIBALIAS 
options ROUTETABLES=2 
options DUMMYNET 


И собираем/ставим его в одну строчку:

# config NAS1 && cd ../compile/NAS1 && make cleandepend && make depend && make && make install


Следим за тем, чтобы наш /etc/rc.conf имел где-то такой вид:

defaultrouter="1.2.3.3"
gateway_enable="YES"
hostname="nas1"
ifconfig_em1="inet 1.2.3.4  netmask 255.255.255.0 -rxcsum -txcsum -tso"
ifconfig_em0="inet 172.16.0.2 netmask 255.255.192.0 -rxcsum -txcsum -tso"
inetd_enable="YES"
sshd_enable="YES"
firewall_enable="YES" 
firewall_nat_enable="YES" 
dummynet_enable="YES" 
firewall_script="/etc/firewall.conf" 
thttpd_enable="YES"
thttpd_enable="YES" 


Устанавлиеваем thttpd, которым будем показывать графички
 # cd /usr/ports/www/thttpd/ && make install


Отличный сенсор NetFlow
  # cd /usr/ports/net-mgmt/softflowd/ && make install


Expat нужен
  #cd /usr/ports/textproc/expat2 && make install


И умеренно врущий, но идеально простой в настройке bandwidthd для отрисовки per-user графиков
  # cd /usr/ports/net-mgmt/bandwidthd/ && make install

PHP собираем с поддержкой CLI
  # cd /usr/ports/lang/php5 && make install

И модуль MYSQL к нему
  # cd /usr/ports/lang/php5-extensions/ && make config && make install

Приводим наш /etc/firewall.conf к виду:

#!/bin/sh
# отправляем netflow на биллинговый сервер
/usr/local/sbin/softflowd -i em0 -n 172.16.0.1:42111
FwCMD="/sbin/ipfw -q"
${FwCMD} -f flush
#сеть пользователей
${FwCMD} table 2 add 172.16.0.0/18
#сети которые не будем NAT-ить
${FwCMD} table 9 add 1.2.3.4/24
#NAT
${FwCMD} nat 1 config log if em1 reset same_ports
${FwCMD} add 600 nat 1 ip from table\(2\) to not table\(9\) via em1
${FwCMD} add 601 nat 1 ip from any to 1.2.3.4 via em1
#политика блокирования по умолчанию
${FwCMD} add 65533 deny all from table\(2\) to any via em0
${FwCMD} add 65534 deny all from any to table\(2\) via em0
${FwCMD} add 65535 allow all from any to any


Выставляем правильные права на наш скрипт инициализации фаервола
   # chmod a+x /etc/firewall.conf
 

Собираем rscriptd и обеспечиваем его запуск при ребуте

# fetch http://stg.dp.ua/download/server/2.407-p1/stg-2.407-p1.tar.gz && tar zxvf stg-2.407-p1.tar.gz &&  cd stg-2.407-p1/projects/rscriptd/ && ./build && gmake install


редактируем /etc/rc.d/rscriptd, приводя его к виду

#!/bin/sh
/usr/sbin/rscriptd

и назначаем ему правильные права

#chmod a+x /etc/rc.d/rscriptd


Разворачиваем заготовки скриптов Ubilling

# mkdir ubilling && fetch http://ubilling.net.ua/ub.tgz && tar zxvf ub.tgz && cd ubilling
# mkdir /etc/stargazer/dn && chmod a+w /etc/stargazer/dn
# cp -f docs/presets/FreeBSD/etc/stargazer/* /etc/rscripd/
# chmod a+x /etc/rscriptd/*


Редактируем конфиг /etc/rscriptd/config, прописывая в него текущие параметры MySQL для того, чтобы скрипты GetSpeed, GetUpSpeed, GetMAC могли нормально получать информацию о пользователях.
Также, не забываем поправить /etc/rscriptd/OnConnect, указав в нем входной интерфейс для шейпинга, который в нашем случае

IFACE="em0"


Настраиваем bandwidthd для того, чтобы он рисовал красивые графики, которые мы потом должны лицезреть в Ubilling:

В файл /usr/local/bandwidthd/etc/bandwidthd.conf вписываем сеть наших пользователей
subnet 172.16.0.0/18
dev "em0"
output_cdf true
recover_cdf true

добавляем периодический SIGHUP для bandwidthd в crontab -e
  3  3  * * *      /bin/kill -HUP `cat /var/run/bandwidthd.pid` 

И опять страшная симлинковая магия, чтобы наш thttpd мог нормально показывать графички

# mv /usr/local/bandwidthd/htdocs /usr/local/www/data/band
# ln -fs /usr/local/www/data/band/ /usr/local/bandwidthd/htdocs
# cp /usr/local/etc/thttpd.conf.sample  /usr/local/etc/thttpd.conf


Обеспечиваем при загрузке запуск
  # /usr/local/bandwidthd/bandwidthd
  # /usr/local/etc/rc.d/thttpd start

И как последний штрих, добавляем более-менее универсальные вещи, помогущие хоть как-то поднять быстродействие в дальнейшем в /etc/sysctl.conf
net.inet.ip.fw.one_pass=1 
net.inet.ip.fastforwarding=1 
net.inet.tcp.nolocaltimewait=1

После перезагрузки получаем работающий NAS, получающий удаленно команды от биллинга, отправляющий ему сведения о трафике и все остальное, что от него требовалось.
Хотелось бы еще написать о настройке кабинета пользователя, недокументированых «фичах» с переходом на следующий месяц и прочих вещах, на которых можно споткнуться в первое время. Но статья и так уже получилась слишком монстроидальной и нудной. Обещаюсь, если карма позволит, на недельке описать все эти вещи в отдельном сказании.

Оффсайт Stargazer
Оффсайт Ubilling
Tags:
Hubs:
+82
Comments 29
Comments Comments 29

Articles