Ρυθμίσεις δικτύου από το FreeRadius μέσω DHCP

Ρυθμίσεις δικτύου από το FreeRadius μέσω DHCP
Έφτασε η αποστολή να κανονίσουμε την έκδοση διευθύνσεων IP στους συνδρομητές. Προϋποθέσεις του προβλήματος:

  • Δεν θα σας δώσουμε ξεχωριστό διακομιστή για εξουσιοδότηση - θα το κάνετε 😉
  • Οι συνδρομητές πρέπει να λαμβάνουν ρυθμίσεις δικτύου μέσω DHCP
  • Το δίκτυο είναι ετερογενές. Αυτό περιλαμβάνει εξοπλισμό PON και κανονικούς διακόπτες με διαμορφωμένη επιλογή 82 και βάσεις WiFi με hotspot
  • Εάν τα δεδομένα δεν εμπίπτουν σε καμία από τις προϋποθέσεις για την έκδοση IP, πρέπει να εκδώσετε IP από το δίκτυο "επισκέπτης"

Από την καλή πλευρά: υπάρχει ακόμα ένας διακομιστής στο FreeBSD που μπορεί να "δουλέψει", αλλά είναι "μακριά" ;), όχι "ακριβώς σε αυτό το δίκτυο".

Υπάρχει επίσης μια υπέροχη συσκευή που ονομάζεται Mikrotik. Το γενικό διάγραμμα δικτύου είναι κάπως έτσι:

Ρυθμίσεις δικτύου από το FreeRadius μέσω DHCP

Μετά από σκέψη, αποφασίστηκε η χρήση του FreeRadius για την έκδοση ρυθμίσεων δικτύου στους συνδρομητές. Κατ 'αρχήν, το σχήμα είναι συνηθισμένο: ενεργοποιούμε τον διακομιστή DHCP στο Microtick και το Radius Client σε αυτόν. Διαμορφώνουμε τον διακομιστή DHCP -> Radius Client -> Σύνδεση διακομιστή Radius.

Δεν φαίνεται δύσκολο. Αλλά! Ο διάβολος βρίσκεται στις λεπτομέρειες. Και συγκεκριμένα:

  • Όταν εξουσιοδοτείτε ένα PON OLT χρησιμοποιώντας αυτό το σχήμα, αποστέλλεται ένα αίτημα στο FreeRadius με ένα Όνομα χρήστη ίσο με τη διεύθυνση MAC του headend, ένα Agent-Circuit-Id ίσο με το MAC PON Onu και έναν κενό κωδικό πρόσβασης.
  • Κατά την εξουσιοδότηση από διακόπτες με την επιλογή 82, το FreeRadius λαμβάνει ένα αίτημα με ένα κενό Όνομα Χρήστη ίσο με το MAC της συσκευής του συνδρομητή και γεμάτο με πρόσθετα χαρακτηριστικά Agent-Circuit-Id και Agent-Remote-Id που περιέχουν, αντίστοιχα, και πάλι το MAC του ο διακόπτης ρελέ και η θύρα στην οποία είναι συνδεδεμένος ο συνδρομητής.
  • Ορισμένοι συνδρομητές με σημεία WiFI είναι εξουσιοδοτημένοι μέσω πρωτοκόλλων PAP-CHAP
  • Ορισμένοι συνδρομητές από σημεία WIFI έχουν εξουσιοδότηση με Όνομα χρήστη ίσο με τη διεύθυνση MAC του σημείου WIFI, χωρίς κωδικό πρόσβασης.

Ιστορικό υπόβαθρο: τι είναι η "Επιλογή 82" στο DHCP

Αυτές είναι πρόσθετες επιλογές για το πρωτόκολλο DHCP που σας επιτρέπουν να μεταφέρετε πρόσθετες πληροφορίες, για παράδειγμα στα πεδία Agent-Circuit-Id και Agent-Remote-Id. Συνήθως χρησιμοποιείται για τη μετάδοση της διεύθυνσης MAC του διακόπτη ρελέ και της θύρας στην οποία είναι συνδεδεμένος ο συνδρομητής. Στην περίπτωση εξοπλισμού PON ή σταθμών βάσης WIFI, το πεδίο Agent-Circuit-Id δεν περιέχει χρήσιμες πληροφορίες (δεν υπάρχει θύρα συνδρομητή). Το γενικό σχήμα λειτουργίας DHCP σε αυτήν την περίπτωση είναι το εξής:

Ρυθμίσεις δικτύου από το FreeRadius μέσω DHCP

Βήμα προς βήμα αυτό το σχήμα λειτουργεί ως εξής:

  1. Ο εξοπλισμός χρήστη υποβάλλει αίτημα μετάδοσης DHCP για να αποκτήσει ρυθμίσεις δικτύου
  2. Η συσκευή (για παράδειγμα, ένας διακόπτης, ένας σταθμός βάσης WiFi ή PON) με τον οποίο είναι απευθείας συνδεδεμένος ο εξοπλισμός συνδρομητή "αναχαιτίζει" αυτό το πακέτο και το αλλάζει, εισάγοντας σε αυτό πρόσθετες επιλογές Option 82 και διεύθυνση IP του πράκτορα αναμετάδοσης και το μεταδίδει περαιτέρω. το δίκτυο.
  3. Ο διακομιστής DHCP αποδέχεται το αίτημα, δημιουργεί μια απάντηση και τη στέλνει στη συσκευή αναμετάδοσης
  4. Η συσκευή αναμετάδοσης προωθεί το πακέτο απόκρισης στη συσκευή συνδρομητή

Φυσικά, όλα δεν λειτουργούν τόσο εύκολα· πρέπει να διαμορφώσετε ανάλογα τον εξοπλισμό του δικτύου σας.

Εγκατάσταση του FreeRadius

Φυσικά, αυτό μπορεί να επιτευχθεί με τις ρυθμίσεις διαμόρφωσης FreeRadius, αλλά είναι δύσκολο και ασαφές... ειδικά όταν πηγαίνετε εκεί μετά από N μήνες και "όλα λειτουργούν". Ως εκ τούτου, αποφασίσαμε να γράψουμε τη δική μας ενότητα εξουσιοδότησης για το FreeRadius στην Python. Θα λάβουμε δεδομένα εξουσιοδότησης από τη βάση δεδομένων MySQL. Δεν έχει νόημα να περιγράψουμε τη δομή του· έτσι κι αλλιώς, ο καθένας θα το φτιάξει «για τον εαυτό του». Συγκεκριμένα, πήρα τη δομή που προσφέρεται με τη μονάδα sql για το FreeRadius και την άλλαξα ελαφρώς προσθέτοντας ένα πεδίο mac και port για κάθε συνδρομητή, εκτός από το login-password.

Έτσι, πρώτα, εγκαταστήστε το FreeRadius:

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

Στις ρυθμίσεις, επιλέξτε για εγκατάσταση:

Ρυθμίσεις δικτύου από το FreeRadius μέσω DHCP

Δημιουργούμε έναν συμβολικό σύνδεσμο προς τη λειτουργική μονάδα python (δηλαδή "ενεργοποιήστε την"):

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

Ας εγκαταστήσουμε μια πρόσθετη ενότητα για python:

pip install mysql-connector

Στις ρυθμίσεις της μονάδας python για το FreeRadius, πρέπει να καθορίσετε τις διαδρομές αναζήτησης λειτουργικών μονάδων στη μεταβλητή python_path. Για παράδειγμα έχω αυτό:

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"

Μπορείτε να μάθετε τις διαδρομές εκκινώντας τον διερμηνέα python και εισάγοντας τις εντολές:

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

Εάν δεν κάνετε αυτό το βήμα, τότε τα σενάρια που είναι γραμμένα σε python και εκκινούνται από το FreeRadius δεν θα βρουν τις λειτουργικές μονάδες που αναφέρονται στην εισαγωγή. Επιπλέον, πρέπει να αφαιρέσετε το σχολιασμό των λειτουργιών για την εξουσιοδότηση κλήσεων και τη λογιστική στις ρυθμίσεις της μονάδας. Για παράδειγμα, αυτή η ενότητα μοιάζει με αυτό:

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}

}

Το σενάριο work.py (και όλα τα άλλα) πρέπει να τοποθετηθεί στο /usr/local/etc/raddb/mods-config/python Έχω τρία σενάρια συνολικά.

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

Όπως μπορείτε να δείτε από τον κώδικα, προσπαθούμε να αναγνωρίσουμε τον συνδρομητή χρησιμοποιώντας όλες τις διαθέσιμες μεθόδους από τις γνωστές του διευθύνσεις MAC συνδρομητών ή τον συνδυασμό Επιλογής 82, και αν αυτό δεν λειτουργήσει, τότε εκδώσουμε την παλαιότερη διεύθυνση IP που χρησιμοποιήθηκε ποτέ από τον "επισκέπτη δίκτυο. Το μόνο που απομένει είναι να διαμορφώσετε το προεπιλεγμένο σενάριο στον φάκελο με ενεργοποιημένο τοποθεσίες, έτσι ώστε οι απαραίτητες λειτουργίες από το σενάριο της python να συσπώνται στις καθορισμένες στιγμές. Στην πραγματικότητα, αρκεί να φέρετε το αρχείο στη φόρμα:

αθέτηση

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

Ας προσπαθήσουμε να το εκτελέσουμε και να δούμε τι μπαίνει στο αρχείο καταγραφής εντοπισμού σφαλμάτων:

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

Τι άλλο. Κατά τη ρύθμιση του FreeRadius, είναι βολικό να δοκιμάσετε τη λειτουργία του χρησιμοποιώντας το βοηθητικό πρόγραμμα radclient. Για παράδειγμα εξουσιοδότηση:

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

Ή λογαριασμός:

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

Θέλω να σας προειδοποιήσω ότι είναι απολύτως αδύνατο να χρησιμοποιήσετε ένα τέτοιο σχήμα και σενάρια "χωρίς αλλαγές" σε "βιομηχανική" κλίμακα. Τουλάχιστον αξιοσημείωτο:

  • είναι δυνατό να "πλαστογραφηθεί" η διεύθυνση MAC. Αρκεί ο συνδρομητής να καταχωρήσει το MAC κάποιου άλλου και θα υπάρξουν προβλήματα
  • Η λογική της έκδοσης δικτύων φιλοξενούμενων είναι πέρα ​​από κριτική. Δεν υπάρχει καν έλεγχος "μήπως υπάρχουν ήδη πελάτες με την ίδια διεύθυνση IP;"

Αυτή είναι απλώς μια «λύση κοπής μπισκότων» που έχει σχεδιαστεί για να λειτουργεί ειδικά στις δικές μου συνθήκες, τίποτα περισσότερο. Μην κρίνετε αυστηρά 😉

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο