RADIUS認証とVLANの割り当て
応答の属性と実際の接続状態を別々に確認します。
説明
NACは端末や利用者の認証、端末状態などからネットワーク参加の条件を決めます。認証サーバーの許可応答と、スイッチが実際に割り当てた接続先を対応付けます。
固定のRADIUS Access-Acceptをバイト列から開き、認証値とVLAN属性を解析します。最後に端末状態の変化と、再評価後のポート台帳を比較します。
応答の属性と実際の接続状態を別々に確認します。
1応答パケットを16進数で開く
公開の共有試験値と要求Authenticatorに対する応答を作ります。
from sp20 import *
from sp02 import show
db=connect()
packet=accept()
print(packet.hex応答パケットを16進数で開く(' '))
print(len(packet))全長37バイトです。最初の4バイトがCode、Identifier、Length、続く16バイトがResponse Authenticatorです。
2ヘッダーをネットワークバイト順で読む
先頭4バイトを1・1・2バイトへ分けます。
code,ident,length=struct.unpackヘッダーをネットワークバイト順で読む('!BBH',packet[:4])
print(code,ident,length)Code 2はAccess-Accept、Identifier 7、長さ37です。要求との対応にはIdentifierだけでなく認証値も確認します。
3要求に対応する認証値を照合する
この固定RADIUS応答のMD5計算を検証します。
print(verify要求に対応する認証値を照合する(packet))
print(verify(packet,request_auth=bytes(16)))正しい要求AuthenticatorではTrue、別の要求値ではFalseです。これはResponse Authenticatorの照合であり、EAPやRADIUSの全保護条件を検査するものではありません。
4属性の型・長さ・値を取り出す
属性はType、Length、Valueの順に並びます。
for typ,n,value in attributes属性の型・長さ・値を取り出す(packet):print(typ,n,value.hex(' '))64はTunnel-Type、65はTunnel-Medium-Type、81はTunnel-Private-Group-IDです。今回の値は同じタグ0を使っています。
5VLANと媒体の値を復号する
タグを除いた値を読みます。
attrs={typ:value for typ,n,value in attributes(packet)}
print(int.from_bytesVLANと媒体の値を復号する(attrs[64][1:],'big'),int.from_bytes(attrs[65][1:],'big'),attrs[81][1:].decode())13はVLAN、6はIEEE 802、文字列20がVLAN IDです。VLAN IDはこの属性では数字の文字列として表されています。
6端末状態の悪化と現在の接続を確認する
dev7をhealthy=0へ変えても、ポートの値は別に保持されます。
db.execute("UPDATE device SET healthy=0 WHERE id='dev7'")
show端末状態の悪化と現在の接続を確認する(db,"SELECT d.id,d.healthy,p.vlan FROM device d JOIN port p ON p.device=d.id")端末状態0でもVLANは20のままです。再評価や接続変更の適用が必要になります。
7再評価結果と適用後のVLANを照合する
固定の隔離用VLAN30を応答資料とポート台帳へ反映します。
new=accept('30')
print(verify(new),dict((t,v) for t,n,v in attributes(new))[81][1:].decode())
db.execute("UPDATE port SET vlan=30 WHERE device='dev7'")
show再評価結果と適用後のVLANを照合する(db,"SELECT id,vlan FROM port")応答資料もポートも30です。実機ではCoAなどの要求結果と、スイッチ側の適用状態を読み直します。VLAN変更だけで全通信が遮断されるとは限らず、接続先の規則も確認します。
まとめ
応答の型、認証値、属性を順に確認します。
認証結果とスイッチの適用状態を照合します。
端末再評価後の接続変更を確認します。
操作履歴と解説を振り返れます。
Python 3.15 / 固定パケット・SQLiteの接続資料
from sp20 import *
from sp02 import show
db=connect()
packet=accept()
print(packet.hex(' '))
print(len(packet))02 07 00 25 12 5b db 6b e2 ed c0 84 e6 d0 8b 52 68 59 2d 54 40 06 00 00 00 0d 41 06 00 00 00 06 51 05 00 32 30 37
code,ident,length=struct.unpack('!BBH',packet[:4])
print(code,ident,length)2 7 37
print(verify(packet))
print(verify(packet,request_auth=bytes(16)))True False
for typ,n,value in attributes(packet):print(typ,n,value.hex(' '))64 6 00 00 00 0d 65 6 00 00 00 06 81 5 00 32 30
attrs={typ:value for typ,n,value in attributes(packet)}
print(int.from_bytes(attrs[64][1:],'big'),int.from_bytes(attrs[65][1:],'big'),attrs[81][1:].decode())13 6 20
db.execute("UPDATE device SET healthy=0 WHERE id='dev7'")
show(db,"SELECT d.id,d.healthy,p.vlan FROM device d JOIN port p ON p.device=d.id")id | healthy | vlan dev7 | 0 | 20
new=accept('30')
print(verify(new),dict((t,v) for t,n,v in attributes(new))[81][1:].decode())
db.execute("UPDATE port SET vlan=30 WHERE device='dev7'")
show(db,"SELECT id,vlan FROM port")True 30 id | vlan sw1:7 | 30
演習完了