Litlhophiso tsa marang-rang ho tsoa ho FreeRadius ka DHCP

Litlhophiso tsa marang-rang ho tsoa ho FreeRadius ka DHCP
Mosebetsi o ile oa fihla ho hlophisa ho fanoa ha liaterese tsa IP ho ba ngolisitseng. Maemo a bothata:

  • Re ke ke ra u fa seva e arohaneng bakeng sa tumello - u tla etsa 😉
  • Ba ngolisitseng ba tlameha ho fumana litlhophiso tsa marang-rang ka DHCP
  • Marang-rang a fapane. Sena se kenyelletsa lisebelisoa tsa PON le li-switches tse tloaelehileng tse nang le Option 82 e hlophisitsoeng le metheo ea WiFi e nang le libaka tse hotspots.
  • Haeba data e sa oele tlas'a maemo afe kapa afe a ho fana ka IP, o tlameha ho fana ka IP ho tswa ho marang-rang a "moeti"

Ka lehlakoreng le letle: ho ntse ho e-na le seva ho FreeBSD e ka "sebetsang", empa e "hōle";), eseng "ho nepahetseng marang-rang ena".

Hape ho na le sesebelisoa se babatsehang se bitsoang Mikrotik. Setšoantšo se akaretsang sa marang-rang ke ntho e kang ena:

Litlhophiso tsa marang-rang ho tsoa ho FreeRadius ka DHCP

Kamora ho nahana, ho ile ha etsoa qeto ea ho sebelisa FreeRadius ho fana ka litlhophiso tsa marang-rang ho ba ngolisitseng. Ha e le hantle, morero ona o tloaelehile: re nolofalletsa seva sa DHCP ho Microtick, le Radius Client ho eona. Re lokisa seva sa DHCP -> Radius Client -> Khokahano ea seva ea Radius.

Ha ho bonahale ho le thata. Empa! Diabolosi o ka lintlha. E leng:

  • Ha o fana ka tumello ea PON OLT e sebelisang morero ona, kopo e romelloa ho FreeRadius e nang le User-Name e lekanang le aterese ea MAC ea sehlooho, Agent-Circuit-Id e lekanang le MAC PON Onu le password e se nang letho.
  • Ha e fana ka tumello ho tsoa ho li-switches ka khetho ea 82, FreeRadius e fumana kopo e nang le Lebitso la Mosebelisi le se nang letho le lekanang le MAC ea sesebelisoa sa motho ea ngolisitseng 'me e tlatsitsoe ka litšoaneleho tse ling Agent-Circuit-Id le Agent-Remote-Id e nang le, ka ho latellana, hape le MAC ea switjha ya relay le boemakepe boo motho ya ngodisang a hokahaneng le bona.
  • Bangoli ba bang ba nang le lintlha tsa WiFI ba lumelloa ka liprothokholo tsa PAP-CHAP
  • Bangoli ba bang ba tsoang libakeng tsa WIFI ba lumelloa ka Lebitso la Mosebelisi le lekanang le aterese ea MAC ea ntlha ea WIFI, ntle le password.

Semelo sa nalane: "Kgetho 82" ke eng ho DHCP

Tsena ke likhetho tse ling bakeng sa protocol ea DHCP e u lumellang hore u fetisoe lintlha tse ling, mohlala, libakeng tsa Agent-Circuit-Id le Agent-Remote-Id. Ka tloaelo e sebelisetsoa ho fetisetsa aterese ea MAC ea sesebelisoa sa relay le boema-kepe boo motho ea ngolisitseng a hokahaneng ho bona. Tabeng ea lisebelisoa tsa PON kapa liteishene tsa motheo tsa WIFI, sebaka sa Agent-Circuit-Id ha se na lintlha tse molemo (ha ho na boema-kepe ba ba ngolisitseng). Morero o akaretsang oa ts'ebetso ea DHCP tabeng ena ke o latelang:

Litlhophiso tsa marang-rang ho tsoa ho FreeRadius ka DHCP

Mohato ka mohato morero ona o sebetsa tjena:

  1. Thepa ea mosebelisi e etsa kopo ea phatlalatso ea DHCP ho fumana litlhophiso tsa marang-rang
  2. Sesebelisoa (mohlala, switch, WiFi kapa setsi sa setsi sa PON) seo sesebelisoa sa ba ngolisitseng se hokahaneng ka kotloloho "se thibela" pakete ena ebe ea e fetola, se hlahisa likhetho tse ling tsa Option 82 le aterese ea IP ea moemeli oa Relay ho eona, ebe e e fetisetsa ho ea pele. marangrang.
  3. Seva ea DHCP e amohela kopo, e hlahisa karabo ebe e e romela ho sesebelisoa sa relay
  4. Sesebelisoa sa relay se fetisetsa pakete ea karabo ho sesebelisoa sa ba ngolisitseng

Ehlile, tsohle ha li sebetse habonolo joalo; o hloka ho hlophisa lisebelisoa tsa marang-rang ka nepo.

Ho kenya FreeRadius

Ha e le hantle, sena se ka finyelloa ka litlhophiso tsa tlhophiso ea FreeRadius, empa ho thata ebile ha ho hlake ... haholo-holo ha u ea moo ka mor'a likhoeli tsa N le "ntho e 'ngoe le e' ngoe e sebetsa." Ka hona, re nkile qeto ea ho ngola module ea rona ea tumello bakeng sa FreeRadius ho Python. Re tla nka data ea tumello ho tsoa ho database ea MySQL. Ha ho na thuso ho hlalosa sebopeho sa eona; leha ho le joalo, e mong le e mong o tla iketsetsa eona. Haholo-holo, ke ile ka nka sebopeho se fanoang ka sql module bakeng sa FreeRadius, 'me ka e fetola hanyenyane ka ho eketsa sebaka sa mac le sa port bakeng sa motho e mong le e mong ea ngolisitseng, ho phaella ho password-password.

Kahoo, pele, kenya FreeRadius:

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

Ho litlhophiso, khetha ho kenya:

Litlhophiso tsa marang-rang ho tsoa ho FreeRadius ka DHCP

Re etsa symlink ho module ea python (ke hore, "e bulela"):

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

Ha re kenye module e eketsehileng bakeng sa python:

pip install mysql-connector

Litlhophisong tsa mojule oa python bakeng sa FreeRadius, o hloka ho hlakisa litsela tsa patlo ea module ho python_path variable. Ka mohlala, ke na le sena:

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"

U ka fumana litsela ka ho qala mofetoleli oa python le ho kenya litaelo:

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

Haeba u sa nke mohato ona, joale lingoloa tse ngotsoeng ka python le tse qalileng ke FreeRadius li ke ke tsa fumana li-module tse thathamisitsoeng ho tsoa kantle ho naha. Ntle le moo, o hloka ho hlakola mesebetsi ea tumello ea ho letsetsa le accounting litlhophisong tsa module. Ka mohlala, mojule ona o shebahala tjena:

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}

}

Sengoloa sa work.py (le tse ling kaofela) se tlameha ho beoa ho /usr/local/etc/raddb/mods-config/python Ke na le mangolo a mararo ka kakaretso.

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

Joalokaha u bona ho tsoa ho khoutu, re leka ho tseba motho ea ngolisitseng a sebelisa mekhoa eohle e fumanehang ka liaterese tsa hae tse tsebahalang tsa MAC kapa Option 82, 'me haeba sena se sa sebetse, re fana ka aterese ea khale ea IP e kileng ea sebelisoa ho tsoa ho "moeti. ” marangrang. Sohle se setseng ke ho hlophisa sengoloa sa kamehla ho foldareng e lumelletsoeng ke libaka, e le hore mesebetsi e hlokahalang ho tsoa ho python script e tla sisinyeha ka nako e behiloeng. Ebile, ho lekane ho tlisa faele foromong:

ya kamehla

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

Ha re leke ho e tsamaisa 'me re bone hore na ho kena eng ka har'a log ea debug:

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

Eng hape. Ha u theha FreeRadius, ho bonolo ho leka ts'ebetso ea eona u sebelisa sesebelisoa sa radclient. Ka mohlala tumello:

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

Kapa ak'haonte:

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

Ke batla ho u lemosa hore ho ke ke ha khoneha ho sebelisa leano le joalo "ntle le liphetoho" ka tekanyo ea "indasteri". Bonyane e hlokomelehang:

  • hoa khoneha ho "fake" aterese ea MAC. Ho lekane hore motho ea ngolisitseng a ngolise MAC ea motho e mong mme ho tla ba le mathata
  • mabaka a ho fana ka marang-rang a baeti ha a nyatsehe. Ha ho na cheke "mohlomong ho se ho na le bareki ba nang le aterese e tšoanang ea IP?"

Ena ke "tharollo ea li-cookie-cutter" e etselitsoeng ho sebetsa ka ho khetheha maemong a ka, ha ho letho le leng hape. Se ahlole ka thata 😉

Source: www.habr.com

Eketsa ka tlhaloso