Ntọala netwọkụ sitere na FreeRadius site na DHCP

Ntọala netwọkụ sitere na FreeRadius site na DHCP
Ọrụ ahụ rutere iji hazie inye ndị debanyere aha adreesị IP. Ọnọdụ nsogbu:

  • Anyị agaghị enye gị ihe nkesa dị iche maka ikike - ị ga-eme 😉
  • Ndị debanyere aha ga-enwerịrị ntọala netwọkụ site na DHCP
  • Netwọk dị iche iche. Nke a gụnyere akụrụngwa PON na mgba ọkụ oge niile nwere nhọrọ 82 ahaziri yana ntọala WiFi nwere oghere.
  • Ọ bụrụ na data adaghị n'okpuru ọnọdụ ọ bụla maka ịnye IP, ị ga-enyerịrị IP site na netwọk “ọbịa”.

N'akụkụ dị mma: a ka nwere ihe nkesa na FreeBSD nke nwere ike "ịrụ ọrụ", mana ọ dị "ebe dị anya" ;), ọ bụghị "ezigbo na netwọk a".

E nwekwara ọmarịcha ngwaọrụ a na-akpọ Mikrotik. Eserese netwọk izugbe bụ ihe dị ka nke a:

Ntọala netwọkụ sitere na FreeRadius site na DHCP

Mgbe echiche ụfọdụ gasịrị, e kpebiri iji FreeRadius nye ndị debanyere aha ntọala netwọkụ. Na ụkpụrụ, atụmatụ a na-emekarị: anyị na-eme ka ihe nkesa DHCP dị na Microtick na Radius Client na ya. Anyị na-ahazi ihe nkesa DHCP -> Radius Client -> Njikọ sava Radius.

O yighị ka ọ siri ike. Ma! Ekwensu dị na nkọwa. Ya bụ:

  • Mgbe ị na-enye ikike PON OLT site na iji atụmatụ a, a na-ezigara FreeRadius arịrịọ nke nwere aha njirimara ya na adreesị MAC nke isi okwu, Agent-Circuit-Id hà MAC PON Onu na paswọọdụ efu.
  • Mgbe ị na-enye ikike site na switches na nhọrọ 82, FreeRadius na-enweta arịrịọ nwere aha njirimara efu hà nhata MAC nke ngwaọrụ ndị debanyere aha wee jupụta na njirimara ndị ọzọ Agent-Circuit-Id na Agent-Remote-Id nwere, otu, ọzọ MAC nke mgba ọkụ relay na ọdụ ụgbọ mmiri nke ejikọrọ onye debanyere aha ya.
  • Ụfọdụ ndị debanyere aha nwere akara WiFI ka enyere ikike site na usoro PAP-CHAP
  • Ụfọdụ ndị debanyere aha sitere na isi WIFI ka enyere ikike na aha njirimara ha nhata adreesị MAC nke ebe WIFI, na-enweghị paswọọdụ.

Ihe ndabere akụkọ ihe mere eme: gịnị bụ "Nhọrọ 82" na DHCP

Ndị a bụ nhọrọ ndị ọzọ maka ụkpụrụ DHCP nke na-enye gị ohere ịnyefe ozi agbakwunyere, dịka ọmụmaatụ na mpaghara Agent-Circuit-Id na Agent-Remote-Id. A na-ejikarị bufee adreesị MAC nke ngbanwe relay na ọdụ ụgbọ mmiri nke ejikọrọ onye debanyere aha ya. N'ihe gbasara akụrụngwa PON ma ọ bụ ọdụ ọdụ WIFI, mpaghara Agent-Circuit-Id enweghị ozi bara uru (ọ nweghị ọdụ ụgbọ mmiri ndị debanyere aha). Atụmatụ izugbe nke ọrụ DHCP na nke a bụ nke a:

Ntọala netwọkụ sitere na FreeRadius site na DHCP

Nzọụkwụ site nzọụkwụ usoro a na-arụ ọrụ dị ka nke a:

  1. Akụrụngwa onye ọrụ na-arịọ arịrịọ mgbasa ozi DHCP iji nweta ntọala netwọkụ
  2. Ngwaọrụ ahụ (dịka ọmụmaatụ, mgba ọkụ, WiFi ma ọ bụ ọdụ PON) nke akụrụngwa ndị debanyere aha jikọtara ya na ya "na-egbochi" ngwugwu a ma gbanwee ya, na-ewebata nhọrọ ndị ọzọ Nhọrọ 82 na adreesị IP Relay agent n'ime ya, ma na-ebufe ya n'ihu. netwọk.
  3. Ihe nkesa DHCP na-anabata arịrịọ ahụ, wepụta nzaghachi wee ziga ya na ngwaọrụ relay
  4. Ngwa relay na-ebuga ngwugwu nzaghachi na ngwaọrụ ndị debanyere aha

N'ezie, ihe niile anaghị arụ ọrụ nke ọma; ịkwesịrị ịhazi akụrụngwa netwọkụ gị n'otu aka ahụ.

Ịwụnye FreeRadius

N'ezie, enwere ike nweta nke a na ntọala nhazi FreeRadius, ma ọ siri ike ma doo anya ... karịsịa mgbe ị na-aga ebe ahụ mgbe ọnwa N gasịrị na "ihe niile na-arụ ọrụ." Ya mere, anyị kpebiri ide modul ikike nke anyị maka FreeRadius na Python. Anyị ga-ewere data ikike site na nchekwa data MySQL. Ọ dịghị uru ịkọwapụta usoro ya; agbanyeghị, onye ọ bụla ga-emere ya "onwe ya." Karịsịa, ewerere m usoro a na-enye ya na modul sql maka FreeRadius, wee gbanwee ya site na ịgbakwunye Mac na ọdụ ụgbọ mmiri maka onye ọ bụla debanyere aha, na mgbakwunye na paswọọdụ nbanye.

Yabụ, nke mbụ, wụnye FreeRadius:

cd /usr/ports/net/freeradius3
make config
make
install clean

Na ntọala, họrọ ka ịwụnye:

Ntọala netwọkụ sitere na FreeRadius site na DHCP

Anyị na-eme symlink na Python modul (ntụgharị "gbanwuo" ya):

ln -s /usr/local/etc/raddb/mods-available/python /usr/local/etc/raddb/mods-enabled

Ka anyị tinye modul ọzọ maka Python:

pip install mysql-connector

N'ime ntọala modul Python maka FreeRadius, ịkwesịrị ịkọwapụta ụzọ ọchụchọ modul na python_path variable. Dịka ọmụmaatụ, enwere m nke a:

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"

Ị nwere ike chọpụta ụzọ ndị ahụ site na ịmalite onye ntụgharị okwu Python wee tinye iwu ndị a:

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']
>

Ọ bụrụ na ịmeghị usoro a, mgbe ahụ scripts e dere na Python na nke FreeRadius bidoro agaghị ahụ modul ndị edepụtara na mbubata. Na mgbakwunye, ịkwesịrị ịmegharị ọrụ maka ịkpọ oku na ndekọ ego na ntọala modul. Dịka ọmụmaatụ, modul a dị ka nke a:

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}

}

Ekwesịrị itinye akwụkwọ edemede work.py (na ndị ọzọ niile) na /usr/local/etc/raddb/mods-config/python m nwere edemede atọ na mkpokọta.

ọrụ.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

Dị ka ị pụrụ ịhụ site na koodu, anyị na-agbalị ịmata onye debanyere aha na-eji niile dị ụzọ site na ya mara debanyere aha MAC adreesị ma ọ bụ Nhọrọ 82 Nchikota, ma ọ bụrụ na nke a anaghị arụ ọrụ, mgbe ahụ anyị na-enye ndị kasị ochie adreesị IP mgbe eji site na "ọbịa." ” netwọkụ. Naanị ihe fọdụrụ bụ ịhazi script ndabara na nchekwa saịtị na-enyere aka, ka ọrụ ndị dị mkpa sitere na edemede python wee tụgharịa n'oge a kara aka. N'ezie, o zuru ezu iweta faịlụ na ụdị:

ndabara

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
}
}

Ka anyị gbalịa ime ya wee hụ ihe na-abata n'ime log debug:

/usr/local/etc/rc.d/radiusd debug

Kedu ihe ọzọ. Mgbe ị na-edozi FreeRadius, ọ dị mma ịnwale ọrụ ya site na iji ngwa radclient. Dịka ọmụmaatụ ikike:

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

Ma ọ bụ akaụntụ:

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

Achọrọ m ịdọ gị aka ná ntị na ọ gaghị ekwe omume iji atụmatụ dị otú ahụ na edemede "na-enweghị mgbanwe" na ọnụ ọgụgụ "ụlọ ọrụ". Opekempe, pụtara ìhè:

  • ọ ga-ekwe omume "adịgboroja" adreesị MAC. O zuru ezu maka onye debanyere aha ịdebanye aha MAC nke onye ọzọ na a ga-enwe nsogbu
  • echiche nke inye netwọk ndị ọbịa karịrị nkatọ. Enweghị ọbụna nlele "ma eleghị anya, enweelarị ndị ahịa nwere otu adreesị IP?"

Nke a bụ naanị "ihe ngwọta kuki-cutter" emebere ka ọ rụọ ọrụ kpọmkwem na ọnọdụ m, ọ dịghị ihe ọzọ. Ekpela ikpe nke ọma 😉

isi: www.habr.com

Tinye a comment