Если кого то интересует DHCP сервер с поддержкой опции 82...
Могу отослать на почту... Ниже приведено описание.
Код: Выделить всё
Проект «DHCP Option 82»
Задача: настроить авторизацию и аутентификацию пользователя сети ООО «СитиЛайн» посредством уникального идентификатора в пакете Option 82.
Средства реализации: Freeradius 2, StaticDHCPd-1.5.4 (python), NetUPUTM 5-007, URFAclientPHP в связке с двумя скриптами отвечающие за привязку IP адреса пользователю для подсчета траффика (add_ip.php) и удаление IP адреса у пользователя при отключении (del_ip.php).
Необходимые библиотеки для функционирования DHCPd: pyrad (bypython для установки pyrad необходимо поставить пакет python-setuptools), ipaddr (bypython), hashlib (bypython для установки библиотеки hashlib необходимо поставить пакет gcc).
Реализация проекта.
Необходимо установить UTM5-007, создать Дополнительный параметр для идентификации пользователя посредством DHCP, настроить URFAClientPHP (можно настроить для работы с другого компьютера указав адрес и порт удаленного сервера, предварительно открыв порты если нужно) для работы с биллинговой системой. Проверить работоспособность скриптов можно (add_ip.php&del_ip.php) вручную, указав в качестве значений переменных статические данные IPадрес, IDклиента и запустить php –fname_scripts.php* .
Далее устанавливаем Freeradius 2.
Везде где встречается строка eap ее необходимо закомментировать.
В главном файле radius.conf раскомментировать строку SQL, и в конфигурационный файл dialup прописываем запросы на аутентификацию и авторизацию пользователей.
authorize_check_query = "SELECT ig.ip_group_id, ig.uname, 'Cleartext-Password', ig.upass, ':=' \
FROM iptraffic_service_linksil, ip_groupsig, service_linkssl, accounts a \
WHERE ig.uname='%{SQL-User-Name}' AND ig.ip_group_id=il.ip_group_id AND sl.account_id=a.id \
AND a.is_deleted=0 AND a.balance>0 and a.int_status=1 and sl.id=il.id and ig.is_deleted=0 and il.is_deleted=0 and sl.is_deleted=0"
###
authorize_reply_query = "SELECT '','%{SQL-User-Name}','Framed-IP-Address',inet_ntoa( ip_groups.ip& 0xffffffff ) AS ip,'=' \
FROM UTM5007.ip_groups WHERE uname ='%{SQL-User-Name}' AND is_deleted = '0' \
AND inet_ntoa( ip_groups.ip& 0xffffffff ) LIKE 'x.y.' \
UNION SELECT '', '%{SQL-User-Name}', 'Framed-Pool', 'dialup_pool', '=' FROM ip_groups \
WHERE uname ='%{SQL-User-Name}' AND inet_ntoa( ip_groups.ip& 0xffffffff ) NOT LIKE 'x.y.'"
Во freeradius \etc\raddb\modules\ippool необходимо создать пул адресов
ippooldhcp_pool {
range-start = 172.18.6.1
range-stop = 172.18.6.7
netmask = 255.255.255.0
cache-size = 800
session-db = ${db_dir}/db2.ippool
ip-index = ${db_dir}/db2.ipindex
override = no
maximum-timeout = 10
#key = "%{NAS-IP-Address} %{NAS-Port}"
}
В sites-enabled/default в секцию аккаунтинга прописать пул адресов выдаваемых клиентам.
accounting {
dialup_pool
dhcp_pool
… }
Настроить в конфигурационном файле sql.conf параметры подключения к БД
sql {
#
# Set the database to one of:
#
# mysql, mssql, oracle, postgresql
#
database = "mysql"
#
# WhichFreeRADIUS driver to use.
#
driver = "rlm_sql_${database}"
# Connection info:
# server = "172.16.2.15"
server = "localhost"
#port = 3306
login = "root"
# password = "root"
password = ""
# Database table configuration for everything except Oracle
# radius_db = "UTM5007"
radius_db = "utm5"
За выдачу IP адресов из определенного пула отвечают таблицы radusergroup, radgroupcheck. В таблице radgroupcheck задается соответствие Группы пользователя в биллинге, соответсвующая пулу адресов в модуле Freeradius2 ippools. В таблице radusergroup задается соответствие пользователя и Группы пользователя. Если необходимо сменить скорость (пул адресов для пользователя) необходимо поправить таблицу соответствий в данной таблице.
Пример лога по выборке группы у пользователя:
expand: SELECT '','%{SQL-User-Name}','Framed-IP-Address',inet_ntoa( ip_groups.ip& 0xffffffff ) AS ip,'=' FROM UTM5007.ip_groups WHERE uname ='%{SQL-User-Name}' AND is_deleted = '0' AND inet_ntoa( ip_groups.ip& 0xffffffff ) LIKE ‘x.y.' UNION SELECT '', '%{SQL-User-Name}', 'Framed-Pool', 'dialup_pool', '=' FROM ip_groups WHERE uname ='%{SQL-User-Name}' AND inet_ntoa( ip_groups.ip& 0xffffffff ) NOT LIKE 'x.y.' -> SELECT '','nat512','Framed-IP-Address',inet_ntoa( ip_groups.ip& 0xffffffff ) AS ip,'=' FROM UTM5007.ip_groups WHERE uname ='nat512' AND is_deleted = '0' AND inet_ntoa( ip_groups.ip& 0xffffffff ) LIKE 'x.y.' UNION SELECT '', 'nat512', 'Framed-Pool', 'dialup_pool', '=' FROM ip_groups WHERE uname ='nat512' AND inet_ntoa(ip_groups.ip& 0xffffffff ) NOT LIKE 'y.x.'
[sql] expand: SELECT groupname FROM radusergroup WHERE username = '%{SQL-User-Name}' ORDER BY priority -> SELECT groupname FROM radusergroup WHERE username = 'nat512' ORDER BY priority
[sql] expand: SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'dhcp_1m' ORDER BY id
[sql] User found in group dhcp_1m
[sql] expand: SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'dhcp_1m' ORDER BY id
Для данного функционала необходимо создать следующие таблицы в базе данных биллинга - radacct , radgroupcheck, radgroupreply, radreply, radusergroup.
mysql>descradacct;
| RadAcctId | bigint(21) | NO | PRI | NULL
| AcctSessionId | varchar(32) | NO | MUL |
| AcctUniqueId | varchar(32) | NO | MUL |
| UserName | varchar(64) | NO | MUL |
| Realm | varchar(64) | YES | |
| NASIPAddress | varchar(15) | NO | MUL |
| NASPortId | varchar(15) | YES | | NULL
| NASPortType | varchar(32) | YES | | NULL
| AcctStartTime | datetime | NO | MUL | 0000-00-00 00:00:00 | |
| AcctStopTime | datetime | NO | MUL | 0000-00-00 00:00:00 | |
| AcctSessionTime | datetime | YES | | NULL
| AcctAuthentic | varchar(32) | YES | | NULL
| ConnectInfo_start |varchar(50) | YES | | NULL
| ConnectInfo_stop | varchar(50) | YES | | NULL
| AcctInputOctets | bigint(12) | YES | | NULL
| AcctOutputOctets | bigint(12) | YES | | NULL
| CalledStationId | varchar(50) | NO | |
| CallingStationId | varchar(50) | NO | |
| AcctTerminateCause | varchar(32) | NO |
| ServiceType | varchar(32) | YES | | NULL
| FramedProtocol | varchar(32) | YES | | NULL
| FramedIPAddress | varchar(15) | YES | MUL | NULL
| AcctStartDelay | int(12) | YES | | NULL
| AcctStopDelay | int(12) | YES | | NULL
mysql>descradgroupcheck;
| groupname | varchar(64) | NO | MUL |
| attribute | varchar(64) | NO |
| op | char(2) | NO |
| value | varchar(253) | NO
mysql>descradgroupcheck;
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| groupname | varchar(64) | NO | MUL |
| attribute | varchar(64) | NO |
| op | char(2) | NO |
| value | varchar(253) | NO |
Устанавливаем StaticDHCPd-1.5.9 путем копирования с внутреннего файлового обменника.
Перед тем как запустить DHCPсервер необходимо установить: yum installpython-setuptools, yuminstallgcc.
Скачиваем библиотеки с сайтов или копируем с сервера из каталога LibForDHCP: pyradipaddr, hashlib - переходим в каждый каталог библиотеки и устанавливаем ее командой pythonsetup.pyinstall.
Важные части конфигурационных файлов DHCP сервера
#получить из БД имя пользователя и пароль
#cisco
vlan = relay_agent[1][2]*256+relay_agent[1][3]
modul = relay_agent[1][4]
port = relay_agent[1][5]
# modul = relay_agent[1][2]
# port = relay_agent[1][3]
#cisco
remoteid = hex2str(relay_agent[2][2:])
#qtech
# remoteid = hex2str(relay_agent[2])
src.logging.writeLog('getRadiusIp: vlan='+str(vlan)+' modul='+str(modul)+' port='+str(port))
# src.logging.writeLog(port)
src.logging.writeLog('getRadiusIp: remoteid')
src.logging.writeLog(remoteid)
db = MySQLdb.connect(host="localhost", port=3306, user="root", passwd="", db="UTM5007")
cursor = db.cursor()
# query = "select u.login,u.password from users u left join user_additional_paramsaon (u.id=a.userid) where a.paramid=8 and a.value='%s' LIMIT 1" % (str(vlan)+'|'+str(port)+'|'+str(remoteid))
query = "select u.login,u.password from users u left join user_additional_paramsaon (u.id=a.userid) where a.paramid=8 and a.value='%s' LIMIT 1" % (str(vlan)+'|'+str(remoteid))
src.logging.writeLog(query)
cursor.execute(query)
data = cursor.fetchall()
src.logging.writeLog(data)
if not data:
return None
#отправим стоповый пакет
req=srv.CreateAcctPacket(User_Name=data[0][0])
src.logging.writeLog('radius send acct-stop')
# req["NAS-IP-Address"]=remoteid
req["NAS-Port"]=vlan
# req["NAS-Port"]=2
req["NAS-Identifier"]="trillian"
req["Called-Station-Id"]=mac
req["Calling-Station-Id"]=mac
# req["Framed-IP-Address"]=reply['Framed-IP-Address'][0]
print "Sending accounting stop packet"
req["Acct-Status-Type"]="Stop"
req["Acct-Session-Id"] = mac
req["Acct-Input-Octets"] = random.randrange(2**10, 2**30)
req["Acct-Output-Octets"] = random.randrange(2**10, 2**30)
req["Acct-Session-Time"] = random.randrange(120, 3600)
req["Acct-Terminate-Cause"] = random.choice(["User-Request", "Idle-Timeout"])
srv.SendPacket(req)
req=srv.CreateAuthPacket(code=pyrad.packet.AccessRequest,User_Name=data[0][0], NAS_Identifier=remoteid, NAS_Port=vlan)
req["User-Password"]=req.PwCrypt(data[0][1])
reply=srv.SendPacket(req)
result = []
if reply.code==pyrad.packet.AccessAccept:
src.logging.writeLog('radius access granted')
src.logging.writeLog(reply['Framed-IP-Address'][0])
#сформируемпакет acct
#ip
result.append(reply['Framed-IP-Address'][0])
#hostname
result.append(data[0][0])
#вычислимшлюз
xx = ipaddr.IPv4Network(str(reply['Framed-IP-Address'][0])+'/255.255.255.0')
gw = xx.network+254
# gw = '192.168.1.1'
src.logging.writeLog('gateway: '+str(gw))
src.logging.writeLog('broadcast: '+str(xx.broadcast))
#gateway
result.append(str(gw))
# result.append("")
#dns-servers
#result.append("")
#'subnet_mask'
result.append("255.255.0.0")
#'broadcast_address'
result.append(str(xx.broadcast))
#'domain_name'
# result.append('city-line.org')
#'domain_name_servers'
result.append("8.8.8.8")
result.append("")
#'ntp_servers'
result.append('')
#'lease_time' sec
result.append(120)
#'subnet'
result.append('255.255.0.0')
#'serial'
result.append(0)
src.logging.writeLog("Sending accounting start packet")
req=srv.CreateAcctPacket(User_Name=data[0][0])
req["Acct-Status-Type"]="Start"
req["Acct-Session-Id"] = mac
В файле dhcp.py (202 строка) при передаче параметров клиенту происходит вызов скрипта add_ip, для привязки IP адреса клиенту в биллинговой системе (подсчет траффика происходит по IP адресу)
#создаем переменную User_Name=data[0][0]
User_Name=data[0][0]
IP_Address= reply['Framed-IP-Address'][0]
subprocess.call('/usr/bin/php -f /netup/utm5/urfaphp/add_ip.php '+User_Name+' '+ IP_Address, shell=True)
Здесь указывается время проверки бездействующих мак адресов клиентов в КЭШ памяти DHCP(время указывается в секундах 180 сек = 3 мин):
if tick2%180==0:
curtime = time.time()
src.logging.writeLog("*************************Starting clear cache ****************************")
for el in src.dhcp._cacheage.items():
if curtime-el[1]['age']>180:
vlan = el[1]['vlan']
mac = el[1]['mac']
Если такой мак адрес найден, то удаляется IP адрес в биллинге у клиента, передав в качестве параметра Имяклиентаel[1]['User_Name']скрипту dellip.php
subprocess.call ('/usr/bin/php -f /netup/utm5/urfaphp/dellip.php '+el[1]['User_Name'],shell=True)
Все необходимые пакеты для данного проекта находятся на сервере в каталоге /Vladimir/По Работе/ Project
Необходимо следить за расположением скриптов и программ, поскольку в проекте идет жесткая ссылка на файлы и перемещение скриптов приведет к неработоспособности всего проекта. В частности касается скриптов и URFAClientPHP.
Billing – создан скрипт bash с командой вызова скрипта php по добавлению пользователя в таблицу.
User_dhcp.sh - /usr/bin/php /netup/utm5/user_dhcp.php $1
В правилах фаервола выставить на добавление и изменение пользователя праметр LOGIN
Пошаговая инструкция заведения IPPool и пользователей.
1. Создаем Группу пользователя (например nat_256 – соответствует ТП со скоростью 256Кбит/с )
2. В модуле Freeradius’а /etc/raddb/modules/ippool создаем одноименный пул адресов
ippool nat_256 {
range-start = 172.18.1.1
range-stop = 172.18.1.14
netmask = 255.255.255.240
cache-size = 800
session-db = ${db_dir}/db3.ippool
ip-index = ${db_dir}/db3.ipindex
override = no
maximum-timeout = 0
#key = "%{NAS-IP-Address} %{NAS-Port}"
}
3. Заносим наименование пулов адресов в файл /sites-enabled/default в секции
accounting {
nat_256
nat_512
post-auth {
nat_256
nat_512
4. В таблице базы данных radgroupcheck задаем соответсвие Групп пользователей и Пулов адресов
| 3 | nat_256 | Pool-Name | := | nat_256 |
| 4 | nat_512 | Pool-Name | := | nat_512 |
5. Создаем учетную запись пользователя присваиваем логин и пароль .
6. В дополнительный параметр в нашем случае CircuitID заносим идентификационные данные Vlan|cisco = 1010|cisco
7. Добавляем пользователю Группу - nat_256.
8. Добавляем тарифный план в соответствие с договором.
9. Добавляем сервисную связку Передача IPтрафика
9.1. При создании IP-группы указываем серый IPадрес
9.2. Вводим логин и пароль
9.3. ОБЯЗАТЕЛЬНОЕ УСЛОВИЕ ГАЛКА Не VPN НЕ ДОЛЖНА СТОЯТЬ
10. Далее в таблице базы данных radusergroupзадаем соответствие Пользователя и IPPolls
| username | groupname | priority |
| nat256 | nat_256 | 1 |
Как происходит добавление соответствия пользователя к группе в таблицу Биллинга.
Имеется скрипт на PHP по добавлению пользователя в таблицу radusergroup, с дополнительными проверками.
Создаем скрипт на bash с запуском этого скрипта с параметром.
Далее создаем правило брандмауэра с параметром LOGIN, который будет передаваться в скрипт, правило срабатывает при изменении пользователя.
Сначала необходимо создать пользователя, записать его данные, сохранить, закрыть окно редактирования пользователя.
Снова его открыть и добавить в группу соответствующую тарифному плану (Событи изменение) .