נעץ סעטטינגס פֿון FreeRadius דורך DHCP

נעץ סעטטינגס פֿון FreeRadius דורך DHCP
די אַרבעט איז אנגעקומען צו צולייגן די אַרויסגעבן פון IP אַדרעסעס צו אבאנענטן. באדינגונגען פון די פּראָבלעם:

  • מיר וועלן נישט געבן איר אַ באַזונדער סערווער פֿאַר דערלויבעניש - איר וועט מאַכן עס 😉
  • אבאנענטן מוזן באַקומען נעץ סעטטינגס דורך DHCP
  • די נעץ איז כעטעראַדזשיניאַס. דאָס כולל PON ויסריכט און רעגולער סוויטשיז מיט קאַנפיגיערד אָפּציע 82 און WiFi באַסעס מיט האָצפּאָץ
  • אויב די דאַטן זענען נישט אונטער קיין פון די באדינגונגען פֿאַר אַרויסגעבן אַן IP, איר מוזן אַרויסגעבן אַן IP פֿון די "גאַסט" נעץ

אויף די גוטע זייַט: עס איז נאָך אַ סערווער אויף FreeBSD וואָס קען "אַרבעט", אָבער עס איז "ווייַט אַוועק" ;), נישט "רעכט אויף דעם נעץ".

Ещё есть замечательное устройство Mikrotik. Общая схема сети примерно такая:

נעץ סעטטינגס פֿון FreeRadius דורך DHCP

נאָך עטלעכע געדאַנק, עס איז באַשלאָסן צו נוצן FreeRadius צו אַרויסגעבן נעץ סעטטינגס צו אבאנענטן. אין פּרינציפּ, די סכעמע איז געוויינטלעך: מיר געבן די DHCP סערווער אויף מיקראָטיקק און ראַדיוס קליענט אויף עס. מיר קאַנפיגיער די DHCP סערווער -> ראַדיוס קליענט -> ראַדיוס סערווער קשר.

עס מיינט נישט שווער. אָבער! דער שטן איז אין די פרטים. נעמליך:

  • ווען אָטערייזינג אַ PON OLT ניצן דעם סכעמע, אַ בקשה איז געשיקט צו FreeRadius מיט אַ באַניצער נאָמען גלייך צו די MAC אַדרעס פון די העאַדענד, אַן אַגענט-קרייַז-יד גלייך צו די MAC PON Onu און אַ ליידיק פּאַראָל.
  • ווען דער אָטערייזינג פֿון סוויטשיז מיט אָפּציע 82, FreeRadius באקומט אַ בקשה מיט אַ ליידיק באַניצער נאָמען גלייך צו די MAC פון די אַבאָנענט מיטל און אָנגעפילט מיט נאָך אַטריביוץ אַגענט-קרייַז-יד און אַגענט-רימאָוט-שייַן מיט ריספּעקטיוולי ווידער די MAC פון די רעלע באַשטימען און די פּאָרט צו וואָס דער אַבאָנענט איז קאָננעקטעד.
  • עטלעכע אבאנענטן מיט WiFI פונקטן זענען אָטערייזד דורך PAP-CHAP פּראָטאָקאָלס
  • עטלעכע אבאנענטן פֿון WIFI פונקטן זענען אָטערייזד מיט אַ באַניצער נאָמען גלייך צו די MAC אַדרעס פון די WIFI פונט, אָן אַ פּאַראָל.

היסטאָריש הינטערגרונט: וואָס איז "אָפּציע 82" אין DHCP

דאָס זענען נאָך אָפּציעס פֿאַר די DHCP פּראָטאָקאָל וואָס לאָזן איר צו אַריבערפירן נאָך אינפֿאָרמאַציע, למשל אין די אַגענט-קרייַז-שייַן און אַגענט-רימאָוט-שייַן פעלדער. טיפּיקאַללי געניצט צו אַריבערפירן די MAC אַדרעס פון די רעלע באַשטימען און די פּאָרט צו וואָס דער אַבאָנענט איז קאָננעקטעד. אין די פאַל פון PON ויסריכט אָדער WIFI באַזע סטיישאַנז, די אַגענט-קרייַז-שייַן פעלד טוט נישט אַנטהאַלטן נוציק אינפֿאָרמאַציע (עס איז קיין אַבאָנענט פּאָרט). דער גענעראַל סכעמע פון ​​DHCP אָפּעראַציע אין דעם פאַל איז ווי גייט:

נעץ סעטטינגס פֿון FreeRadius דורך DHCP

שריט דורך שריט דעם סכעמע אַרבעט ווי דאָס:

  1. דער באַניצער ויסריכט מאכט אַ DHCP בראָדקאַסט בעטן צו באַקומען נעץ סעטטינגס
  2. דער מיטל (למשל, אַ באַשטימען, WiFi אָדער PON באַזע סטאַנציע) צו וואָס די אַבאָנענט ויסריכט איז גלייַך קאָננעקטעד "ינטערסעפּטיז" דעם פּאַקאַט און ענדערונגען עס, ינטראָודוסינג נאָך אָפּציעס אָפּציע 82 און ריליי אַגענט IP אַדרעס אין עס, און טראַנסמיטט עס ווייַטער איבער. די נעץ.
  3. דער DHCP סערווער אַקסעפּץ די בקשה, דזשענערייץ אַ ענטפער און סענדז עס צו די רעלע מיטל
  4. די רעלע מיטל פאָרווערדז די ענטפער פּאַקאַט צו די אַבאָנענט מיטל

דאָך, דאָס אַלץ אַרבעט נישט אַזוי לייכט; איר דאַרפֿן צו קאַנפיגיער דיין נעץ עקוויפּמענט אַקאָרדינגלי.

ינסטאַלירן FreeRadius

דאָך, דאָס קענען זיין אַטשיווד מיט די FreeRadius קאַנפיגיעריישאַן סעטטינגס, אָבער עס איז שווער און ומקלאָר ... ספּעציעל ווען איר גיין דאָרט נאָך N חדשים און "אַלץ אַרבעט." דעריבער, מיר באַשלאָסן צו שרייַבן אונדזער אייגענע דערלויבעניש מאָדולע פֿאַר FreeRadius אין פּיטהאָן. מיר וועלן נעמען דערלויבעניש דאַטן פון די MySQL דאַטאַבייס. עס איז קיין פונט אין דיסקרייבינג זייַן סטרוקטור; סייַ ווי סייַ, אַלעמען וועט מאַכן עס "פֿאַר זיך." אין באַזונדער, איך גענומען די סטרוקטור וואָס איז געפֿינט מיט די sql מאָדולע פֿאַר FreeRadius, און אַ ביסל טשיינדזשד עס דורך אַדינג אַ מעק און פּאָרט פעלד פֿאַר יעדער אַבאָנענט, אין אַדישאַן צו די לאָגין פּאַראָל.

אַזוי, ערשטער, ינסטאַלירן FreeRadius:

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

אין די סעטטינגס, אויסקלייַבן צו ינסטאַלירן:

נעץ סעטטינגס פֿון FreeRadius דורך DHCP

מיר מאַכן אַ סימלינק צו די פּיטהאָן מאָדולע (ד"ה "קער אויף" עס):

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

לאָמיר ינסטאַלירן אַן נאָך מאָדולע פֿאַר פּיטהאָן:

pip install mysql-connector

אין די פּיטהאָן מאָדולע סעטטינגס פֿאַר FreeRadius, איר דאַרפֿן צו ספּעציפיצירן די מאָדולע זוכן פּאַטס אין די פּיטהאָן_פּאַטה בייַטעוודיק. איך האב למשל דאס:

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"

איר קענען געפֿינען די פּאַטס דורך קאַטער די פּיטהאָן יבערזעצער און אַרייַן די קאַמאַנדז:

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

אויב איר טאָן ניט נעמען דעם שריט, סקריפּס געשריבן אין פּיטהאָן און לאָנטשט דורך 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 אַדרעס וואָס איז געווען געוויינט פֿון די "גאַסט". " נעץ. אַלע וואָס בלייבט איז צו קאַנפיגיער די פעליקייַט שריפט אין די זייטלעך-ענייבאַלד טעקע, אַזוי אַז די נויטיק פאַנגקשאַנז פון די פּיטהאָן שריפט וועט טוויטש אין די דעזיגנייטיד מאָומאַנץ. אין פאַקט, עס איז גענוג צו ברענגען די טעקע צו די פאָרעם:

ניט ויסצאָלן

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, עס איז באַקוועם צו פּרובירן די אָפּעראַציע מיט די ראַדקליענט נוצן. למשל רשות:

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

לייגן אַ באַמערקונג