一覧SP-20-1 · NAC・ZTNA:接続単位のアクセス制御

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の接続資料

1
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
2
code,ident,length=struct.unpack('!BBH',packet[:4]) print(code,ident,length)
2 7 37
3
print(verify(packet)) print(verify(packet,request_auth=bytes(16)))
True
False
4
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
5
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
6
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
7
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

演習完了