Ua hiki mai ka hana e hoʻonohonoho i ka hoʻopuka ʻana i nā helu IP i nā mea kākau inoa. Nā kūlana o ka pilikia:
- ʻAʻole mākou e hāʻawi iā ʻoe i kahi kikowaena ʻokoʻa no ka ʻae - e hana ʻoe 😉
- Pono nā mea kākau inoa e loaʻa nā hoʻonohonoho pūnaewele ma o DHCP
- He heterogene ka pūnaewele. Hoʻopili kēia i nā lako PON a me nā hoʻololi maʻamau me ka koho 82 i hoʻonohonoho ʻia a me nā kumu WiFi me nā wahi wela
- Inā ʻaʻole hāʻule ka ʻikepili ma lalo o kekahi o nā kūlana no ka hoʻopuka ʻana i kahi IP, pono ʻoe e hoʻopuka i kahi IP mai ka pūnaewele "malihini"
Ma ka ʻaoʻao maikaʻi: aia nō kahi kikowaena ma FreeBSD hiki ke "hana", akā "ma kahi mamao";), ʻaʻole "pololei ma kēia pūnaewele".
Aia kekahi mea kupanaha i kapa ʻia ʻo Mikrotik. ʻO ke kiʻikuhi pūnaewele maʻamau e like me kēia:
Ma hope o kekahi noʻonoʻo, ua hoʻoholo ʻia e hoʻohana iā FreeRadius e hoʻopuka i nā hoʻonohonoho pūnaewele i nā mea kākau inoa. Ma ke kumu, maʻamau ka papahana: hiki iā mākou ke hoʻohana i ka server DHCP ma Microtick, a me Radius Client ma luna. Hoʻonohonoho mākou i ka server DHCP -> Radius Client -> Radius server connection.
ʻAʻohe mea paʻakikī. Akā! Aia ka diabolo i nā kikoʻī. ʻO ia hoʻi:
- I ka ʻae ʻana i kahi PON OLT e hoʻohana ana i kēia hoʻolālā, hoʻouna ʻia kahi noi iā FreeRadius me kahi mea hoʻohana-Inoa e like me ka helu MAC o ke poʻo, kahi Agent-Circuit-Id e like me ka MAC PON Onu a me kahi ʻōlelo huna.
- I ka ʻae ʻana mai nā hoʻololi me ke koho 82, loaʻa iā FreeRadius kahi noi me kahi mea hoʻohana-inoa ʻole e like me ka MAC o ka mea kūʻai aku a hoʻopiha ʻia me nā ʻano ʻē aʻe Agent-Circuit-Id a me Agent-Remote-Id i loaʻa, kēlā me kēia, ka MAC o ka hoʻololi relay a me ke awa i hoʻopili ʻia ai ka mea kākau inoa.
- Ua ʻae ʻia kekahi poʻe kākau inoa me nā wahi WiFI ma o nā protocols PAP-CHAP
- Ua ʻae ʻia kekahi mau mea kākau inoa mai nā wahi WIFI me kahi mea hoʻohana-inoa e like me ka helu MAC o ka wahi WIFI, me ka ʻole o ka ʻōlelo huna.
Ka mōʻaukala: he aha ka "koho 82" ma DHCP
He mau koho hou kēia no ka protocol DHCP e hiki ai iā ʻoe ke hoʻololi i ka ʻike hou aku, no ka laʻana ma nā kahua Agent-Circuit-Id a me Agent-Remote-Id. Hoʻohana maʻamau e hoʻouna i ka helu MAC o ka hoʻololi relay a me ke awa kahi e pili ai ka mea kākau inoa. I ka hihia o nā lako PON a i ʻole nā kahua kahua WIFI, ʻaʻole i loaʻa i ka kahua Agent-Circuit-Id ka ʻike kūpono (ʻaʻohe port mea kākau). ʻO ka papahana maʻamau o ka hana DHCP ma kēia hihia penei:
Hana ʻia kēia ʻano hana e like me kēia:
- Hana ka mea hoʻohana i kahi noi hoʻolaha DHCP e kiʻi i nā hoʻonohonoho pūnaewele
- ʻO ka mea hana (no ka laʻana, kahi hoʻololi, WiFi a i ʻole PON base station) kahi i pili pono ai ka mea kākau inoa "hoʻopili" i kēia ʻeke a hoʻololi iā ia, e hoʻolauna ana i nā koho koho 82 a me ka Relay agent IP address i loko, a hoʻouna hou aku ma luna. ka pūnaewele.
- Ua ʻae ke kikowaena DHCP i ka noi, hoʻopuka i kahi pane a hoʻouna iā ia i ka hāmeʻa relay
- Hoʻouna ka mea relay i ka ʻeke pane i ka mea kākau inoa
ʻOiaʻiʻo, ʻaʻole maʻalahi nā mea a pau; pono ʻoe e hoʻonohonoho i kāu lako pūnaewele e like me ia.
Ke hoʻokomo nei iā FreeRadius
ʻOiaʻiʻo, hiki ke hoʻokō ʻia kēia me nā hoʻonohonoho hoʻonohonoho FreeRadius, akā paʻakikī a maopopo ʻole ... ʻoiai ke hele ʻoe i laila ma hope o N mau mahina a "hana nā mea āpau." No laila, ua hoʻoholo mākou e kākau i kā mākou mana ponoʻī no FreeRadius ma Python. E lawe mākou i ka ʻikepili ʻae mai ka waihona MySQL. ʻAʻohe kumu o ka wehewehe ʻana i kona ʻano; akā naʻe, e hana kēlā me kēia "no lākou iho." Ma keʻano kūikawā, ua lawe au i ka hale i hāʻawi ʻia me ka module sql no FreeRadius, a hoʻololi iki iā ia ma ka hoʻohui ʻana i kahi kahua mac a me ke awa no kēlā me kēia mea kākau inoa, me ka ʻōlelo huna.
No laila, mua, e hoʻokomo iā FreeRadius:
cd /usr/ports/net/freeradius3
make config
make
install clean
Ma nā hoʻonohonoho, koho e hoʻokomo:
Hana mākou i kahi symlink i ka module python (ʻo ia hoʻi, "hoʻohuli" iā ia):
ln -s /usr/local/etc/raddb/mods-available/python /usr/local/etc/raddb/mods-enabled
E hoʻokomo i kahi module hou no python:
pip install mysql-connector
Ma nā hoʻonohonoho module python no FreeRadius, pono ʻoe e kuhikuhi i nā ala hulina module i ka helu python_path. No ka laʻana, loaʻa iaʻu kēia:
python_path="/usr/local/etc/raddb/mods-config/python:/usr/local/lib/python2.7:/usr/local/lib/python27.zip:/usr/local/lib/python2.7:/usr/local/lib/python2.7/plat-freebsd12:/usr/local/lib/python2.7/lib-tk:/usr/local/lib/python2.7/lib-old:/usr/local/lib/python2.7/lib-dynload:/usr/local/lib/python2.7/site-packages"
Hiki iā ʻoe ke ʻike i nā ala ma ka hoʻomaka ʻana i ka unuhi ʻōlelo python a komo i nā kauoha:
root@phaeton:/usr/local/etc/raddb/mods-enabled# python
Python 2.7.15 (default, Dec 8 2018, 01:22:25)
[GCC 4.2.1 Compatible FreeBSD Clang 6.0.1 (tags/RELEASE_601/final 335540)] on freebsd12
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/local/lib/python27.zip', '/usr/local/lib/python2.7', '/usr/local/lib/python2.7/plat-freebsd12', '/usr/local/lib/python2.7/lib-tk', '/usr/local/lib/python2.7/lib-old', '/usr/local/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/site-packages']
>
Inā ʻaʻole ʻoe e hana i kēia kaʻina, a laila ʻaʻole ʻike ʻia nā palapala i kākau ʻia ma ka python a hoʻokuʻu ʻia e FreeRadius i nā modules i helu ʻia ma ka lawe ʻana mai. Eia hou, pono ʻoe e hoʻokaʻawale i nā hana no ke kāhea ʻana i ka ʻae a me ka helu helu i nā hoʻonohonoho module. No ka laʻana, ua like kēia module:
python {
python_path="/usr/local/etc/raddb/mods-config/python:/usr/local/lib/python2.7:/usr/local/lib/python2.7/site-packages:/usr/local/lib/python27.zip:/usr/local/lib/python2.7:/usr/local/lib/python2.7/plat-freebsd12:/usr/local/lib/python2.7/lib-tk:/usr/local/lib/python2.7/lib-old:/usr/local/lib/python2.7/lib-dynload:/usr/local/lib/python2.7/site-packages"
module = work
mod_instantiate = ${.module}
mod_detach = ${.module}
mod_authorize = ${.module}
func_authorize = authorize
mod_authenticate = ${.module}
func_authenticate = authenticate
mod_preacct = ${.module}
func_preacct = preacct
mod_accounting = ${.module}
func_accounting = accounting
mod_checksimul = ${.module}
mod_pre_proxy = ${.module}
mod_post_proxy = ${.module}
mod_post_auth = ${.module}
mod_recv_coa = ${.module}
mod_send_coa = ${.module}
}
Pono e hoʻokomo i ka palapala work.py (a me nā mea ʻē aʻe a pau) i loko /usr/local/etc/raddb/mods-config/python Loaʻa iaʻu ʻekolu mau palapala.
work.py:
#!/usr/local/bin/python
# coding=utf-8
import radiusd
import func
import sys
from pprint import pprint
mysql_host="localhost"
mysql_username="укацук"
mysql_password="ыукаыукаыук"
mysql_base="ыукаыкуаыу"
def instantiate(p):
print ("*** instantiate ***")
print (p)
# return 0 for success or -1 for failure
def authenticate(p):
print ("*** Аутенфикация!!***")
print (p)
def authorize(p):
radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***')
conn=func.GetConnectionMysql(mysql_host, mysql_username, mysql_password, mysql_base);
param=func.ConvertArrayToNames(p);
pprint(param)
print ("*** Авторизация ***")
reply = ()
conf = ()
cnt=0
username="";mac="";
# сначала проверяем "как положено", по связке логин/пароль
if ("User-Name" in param) and ("User-Password" in param) :
print ("Вариант авторизации (1): есть логин-пароль")
pprint(param["User-Name"])
pprint(param["User-Password"])
pprint(conn)
print(sys.version_info)
print (radiusd.config)
sql="select radreply.attribute,radreply.value from radcheck inner join radreply on radreply.username=radcheck.username where radcheck.username=%s and radcheck.value=%s"
print(sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql,[param["User-Name"], param["User-Password"]]);
row = cursor.fetchone()
while row is not None:
cnt=cnt+1
username=row["username"]
reply = reply+((str(row["attribute"]),str(row["value"])), )
row = cursor.fetchone()
# вариант, что User-Name - это МАС адрес БС,пароля и порта нет
if ("User-Name" in param) and ("User-Password" in param) and (cnt==0):
if param["User-Password"] =='':
if ":" in param["User-Name"]:
pprint(param["User-Name"])
print ("Вариант авторизации (2): User-Name - это MAC адрес базовой станции, порта и пароля нет")
sql="select radreply.username,radreply.attribute,radreply.value from radcheck inner join radreply on radreply.username=radcheck.username where REPLACE(radcheck.mac,':','') = REPLACE(REPLACE('"+str(param["User-Name"])+"','0x',''),':','') and radcheck.sw_port=''"
print (sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
row = cursor.fetchone()
while row is not None:
cnt=cnt+1
username=row["username"]
mac=param["User-Name"]
reply = reply+((str(row["attribute"]),str(row["value"])), )
row = cursor.fetchone()
if ("Agent-Remote-Id" in param) and ("User-Password" in param) and (cnt==0):
if param["User-Password"] =='':
pprint(param["Agent-Remote-Id"])
print ("Вариант авторизации (2.5): Agent-Remote-Id - это MAC адрес PON оборудования")
sql="select radreply.username,radreply.attribute,radreply.value from radcheck inner join radreply on radreply.username=radcheck.username where REPLACE(radcheck.mac,':','') = REPLACE(REPLACE('"+str(param["Agent-Remote-Id"])+"','0x',''),':','') and radcheck.sw_port=''"
print (sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
row = cursor.fetchone()
while row is not None:
cnt=cnt+1
username=row["username"]
mac=param["User-Name"]
reply = reply+((str(row["attribute"]),str(row["value"])), )
row = cursor.fetchone()
#Вариант, что Agent-Remote-Id - это МАС адрес БС,пароля и порта нет и предыдущие варианты поиска IP результата не дали
if ("Agent-Remote-Id" in param) and ("User-Password" not in param) and (cnt==0):
pprint(param["Agent-Remote-Id"])
print ("Вариант авторизации (3): Agent-Remote-Id - МАС базовой станции/пон. Порта в биллинге нет")
sql="select radreply.username,radreply.attribute,radreply.value from radcheck inner join radreply on radreply.username=radcheck.username where REPLACE(radcheck.mac,':','') = REPLACE(REPLACE('"+str(param["Agent-Remote-Id"])+"','0x',''),':','') and radcheck.sw_port=''"
print(sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
row = cursor.fetchone()
while row is not None:
cnt=cnt+1
mac=param["Agent-Remote-Id"]
username=row["username"]
reply = reply+((str(row["attribute"]),str(row["value"])), )
row = cursor.fetchone()
#Вариант, что предыдущие попытки результата не дали, но есть Agent-Remote-Id и Agent-Circuit-Id
if ("Agent-Remote-Id" in param) and ("Agent-Circuit-Id" in param) and (cnt==0):
pprint(param["Agent-Remote-Id"])
pprint(param["Agent-Circuit-Id"])
print ("Вариант авторизации (4): авторизация по Agent-Remote-Id и Agent-Circuit-Id, в биллинге есть порт/мак")
sql="select radreply.username,radreply.attribute,radreply.value from radcheck inner join radreply on radreply.username=radcheck.username where upper(radcheck.sw_mac)=upper(REPLACE('"+str(param["Agent-Remote-Id"])+"','0x','')) and upper(radcheck.sw_port)=upper(RIGHT('"+str(param["Agent-Circuit-Id"])+"',2)) and radcheck.sw_port<>''"
print(sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
row = cursor.fetchone()
while row is not None:
cnt=cnt+1
mac=param["Agent-Remote-Id"]
username=row["username"]
reply = reply+((str(row["attribute"]),str(row["value"])), )
row = cursor.fetchone()
# если так до сих пор IP не получен, то выдаю иего из гостевой сети..
if cnt==0:
print ("Ни один из вариантов авторизации не сработал, получаю IP из гостевой сети..")
ip=func.GetGuestNet(conn)
if ip!="":
cnt=cnt+1;
reply = reply+(("Framed-IP-Address",str(ip)), )
# если совсем всё плохо, то Reject
if cnt==0:
conf = ( ("Auth-Type", "Reject"), )
else:
#если авторизация успешная (есть такой абонент), то запишем историю авторизации
if username!="":
func.InsertToHistory(conn,username,mac, reply);
conf = ( ("Auth-Type", "Accept"), )
pprint (reply)
conn=None;
return radiusd.RLM_MODULE_OK, reply, conf
def preacct(p):
print ("*** preacct ***")
print (p)
return radiusd.RLM_MODULE_OK
def accounting(p):
print ("*** Аккаунтинг ***")
radiusd.radlog(radiusd.L_INFO, '*** radlog call in accounting (0) ***')
print (p)
conn=func.GetConnectionMysql(mysql_host, mysql_username, mysql_password, mysql_base);
param=func.ConvertArrayToNames(p);
pprint(param)
print("Удалим старые сессии (более 20 минут нет аккаунтинга)");
sql="delete from radacct where TIMESTAMPDIFF(minute,acctupdatetime,now())>20"
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
conn.commit()
print("Обновим/добавим информацию о сессии")
if (("Acct-Unique-Session-Id" in param) and ("User-Name" in param) and ("Framed-IP-Address" in param)):
sql='insert into radacct (radacctid,acctuniqueid,username,framedipaddress,acctstarttime) values (null,"'+str(param['Acct-Unique-Session-Id'])+'","'+str(param['User-Name'])+'","'+str(param['Framed-IP-Address'])+'",now()) ON DUPLICATE KEY update acctupdatetime=now()'
print(sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql)
conn.commit()
conn=None;
return radiusd.RLM_MODULE_OK
def pre_proxy(p):
print ("*** pre_proxy ***")
print (p)
return radiusd.RLM_MODULE_OK
def post_proxy(p):
print ("*** post_proxy ***")
print (p)
return radiusd.RLM_MODULE_OK
def post_auth(p):
print ("*** post_auth ***")
print (p)
return radiusd.RLM_MODULE_OK
def recv_coa(p):
print ("*** recv_coa ***")
print (p)
return radiusd.RLM_MODULE_OK
def send_coa(p):
print ("*** send_coa ***")
print (p)
return radiusd.RLM_MODULE_OK
def detach():
print ("*** На этом всё детишечки ***")
return radiusd.RLM_MODULE_OK
func.py:
#!/usr/bin/python2.7
# coding=utf-8
import mysql.connector
from mysql.connector import Error
# Функция возвращает соединение с MySQL
def GetConnectionMysql(mysql_host, mysql_username, mysql_password, mysql_base):
try:
conn = mysql.connector.connect(host=mysql_host,database=mysql_base,user=mysql_username,password=mysql_password)
if conn.is_connected(): print('---cоединение с БД '+mysql_base+' установлено')
except Error as e:
print("Ошибка: ",e);
exit(1);
return conn
def ConvertArrayToNames(p):
mass={};
for z in p:
mass[z[0]]=z[1]
return mass
# Функция записывает историю соединения по известным данным
def InsertToHistory(conn,username,mac, reply):
print("--записываю для истории")
repl=ConvertArrayToNames(reply)
if "Framed-IP-Address" in repl:
sql='insert into radpostauth (username,reply,authdate,ip,mac,session_id,comment) values ("'+username+'","Access-Accept",now(),"'+str(repl["Framed-IP-Address"])+'","'+str(mac)+'","","")'
print(sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
conn.commit()
# Функция выдает последний по дате выдачи IP адрес из гостевой сети
def GetGuestNet(conn):
ip="";id=0
sql="select * from guestnet order by dt limit 1"
print (sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
row = cursor.fetchone()
while row is not None:
ip=row["ip"]
id=row["id"]
row = cursor.fetchone()
if id>0:
sql="update guestnet set dt=now() where id="+str(id)
print (sql)
cursor = conn.cursor(dictionary=True,buffered=True)
cursor.execute(sql);
conn.commit()
return ip
radiusd.py:
#!/usr/bin/python2.7
# coding=utf-8
# from modules.h
RLM_MODULE_REJECT = 0
RLM_MODULE_FAIL = 1
RLM_MODULE_OK = 2
RLM_MODULE_HANDLED = 3
RLM_MODULE_INVALID = 4
RLM_MODULE_USERLOCK = 5
RLM_MODULE_NOTFOUND = 6
RLM_MODULE_NOOP = 7
RLM_MODULE_UPDATED = 8
RLM_MODULE_NUMCODES = 9
# from log.h
L_AUTH = 2
L_INFO = 3
L_ERR = 4
L_WARN = 5
L_PROXY = 6
L_ACCT = 7
L_DBG = 16
L_DBG_WARN = 17
L_DBG_ERR = 18
L_DBG_WARN_REQ = 19
L_DBG_ERR_REQ = 20
# log function
def radlog(level, msg):
import sys
sys.stdout.write(msg + 'n')
level = level
E like me kāu e ʻike ai mai ke code, ke hoʻāʻo nei mākou e ʻike i ka mea kūʻai aku me ka hoʻohana ʻana i nā ala āpau i loaʻa e kāna mea kākau inoa inoa MAC a i ʻole koho 82 hui pū ʻana, a inā ʻaʻole hana kēia, a laila hoʻopuka mākou i ka leka uila IP kahiko loa i hoʻohana ʻia mai ka "guest. ” pūnaewele. ʻO nā mea a pau i koe, ʻo ia ka hoʻonohonoho ʻana i ka palapala paʻamau i loko o ka waihona i hoʻohana ʻia i nā pūnaewele, i hiki ai i nā hana pono mai ka script python ke ʻoki i nā manawa i koho ʻia. ʻO ka ʻoiaʻiʻo, ua lawa ka lawe ʻana i ka faila i ke ʻano:
ka paʻamau
server default {
listen {
type = auth
ipaddr = *
port = 0
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipaddr = *
port = 0
type = acct
limit {
}
}
listen {
type = auth
port = 0
limit {
max_connections = 1600
lifetime = 0
idle_timeout = 30
}
}
listen {
ipv6addr = ::
port = 0
type = acct
limit {
}
}
authorize {
python
filter_username
preprocess
expiration
logintime
}
authenticate {
Auth-Type PAP {
pap
python
}
Auth-Type CHAP {
chap
python
}
Auth-Type MS-CHAP {
mschap
python
}
eap
}
preacct {
preprocess
acct_unique
suffix
files
}
accounting {
python
exec
attr_filter.accounting_response
}
session {
}
post-auth {
update {
&reply: += &session-state:
}
exec
remove_reply_message_if_eap
Post-Auth-Type REJECT {
attr_filter.access_reject
eap
remove_reply_message_if_eap
}
Post-Auth-Type Challenge {
}
}
pre-proxy {
}
post-proxy {
eap
}
}
E hoʻāʻo kākou e holo a ʻike i ka mea i komo i loko o ka log debug:
/usr/local/etc/rc.d/radiusd debug
He aha hou aʻe. I ka hoʻonohonoho ʻana iā FreeRadius, hiki ke hoʻāʻo i kāna hana me ka hoʻohana ʻana i ka pono radclient. No ka laʻana ka mana:
echo "User-Name=4C:5E:0C:2E:7F:15,Agent-Remote-Id=0x9845623a8c98,Agent-Circuit-Id=0x00010006" | radclient -x 127.0.0.1:1812 auth testing123
A i ʻole moʻokāki:
echo "User-Name=4C:5E:0C:2E:7F:15,Agent-Remote-Id=0x00030f26054a,Agent-Circuit-Id=0x00010002" | radclient -x 127.0.0.1:1813 acct testing123
Makemake wau e ao aku iā ʻoe he mea hiki ʻole ke hoʻohana i kēlā ʻano hoʻolālā a me nā palapala "me ka ʻole o nā loli" ma kahi pālākiō "ʻoihana". Hiki ke ʻike ʻia:
- hiki ke "hoʻopunipuni" i ka helu MAC. Ua lawa ka mea kākau inoa e hoʻopaʻa inoa i ka MAC o kekahi a aia nā pilikia
- ʻOi aku ka manaʻo o ka hoʻopuka ʻana i nā pūnaewele malihini. ʻAʻole loaʻa kahi hōʻoia "ua loaʻa paha nā mea kūʻai aku me ka helu IP like?"
ʻO kēia wale nō kahi "kuki-cutter solution" i hoʻolālā ʻia e hana kūikawā i koʻu kūlana, ʻaʻohe mea ʻē aʻe. Mai noʻonoʻo pono 😉
Source: www.habr.com