一覧SP-05-1 · SWG・DNSフィルタリング

DNSフィルタリングとWebプロキシ

名前解決、プロキシ、復号、配送のどこで処理したかを記録から説明します。

説明

DNSフィルタリングは名前解決の応答を制御し、SWGはWeb通信の経路上で宛先や要求を評価します。それぞれの通信が、設定した制御点を通るかを確認します。

URLのホストとパス、DNS応答の状態、明示プロキシへの要求を順に開きます。最後に固定の経路記録で、管理外の経路を探します。

名前解決、プロキシ、復号、配送のどこで処理したかを記録から説明します。

1URLをホストとパスへ分解する

同じホストの異なるパスを比較します。

from sp05 import * from sp02 import show db = connect() for u in ('https://docs.example.test/manual','https://docs.example.test/private'): p=urlsplitURLをホストとパスへ分解する(u);print(p.hostname,p.path)

DNSへ問い合わせるホスト名は同じです。DNSの名前単位の制御だけで/manualと/privateを選び分けることはできません。

2DNSヘッダーの応答コードを取り出す

固定ヘッダーのflags下位4ビットがRCODEです。

header = bytes.fromhex('123481850001000000000000') ident,flags,qd,an,ns,ar = struct.unpackDNSヘッダーの応答コードを取り出す('!6H',header) print(hex(ident),flags&15,qd,an)

RCODE 5はREFUSED、回答数は0です。これは拒否を示す固定例で、フィルタリング製品によってはNXDOMAINやブロックページのアドレスを返す方式もあります。

3HTTPプロキシへ渡す要求を開く

暗号化しないHTTPを明示プロキシへ送る場合の要求例です。

proxy_request = b'GET http://docs.example.test/manual HTTP/1.1\r\nHost: docs.example.test\r\n\r\n' print(proxy_request.decodeHTTPプロキシへ渡す要求を開く(),end='')

要求行に絶対URIが含まれます。プロキシはホストとパスの両方を受け取れます。

4HTTPSのトンネル要求と比較する

HTTPSではまずCONNECTで接続先を指定する形があります。

connect_request = b'CONNECT docs.example.test:443 HTTP/1.1\r\nHost: docs.example.test:443\r\n\r\n' print(connect_request.decodeHTTPSのトンネル要求と比較する(),end='')

この要求には/manualがありません。トンネル内のTLSを終端しなければ、このCONNECT行から内部のHTTPパスは分かりません。

5経路別の結果を表示する

resolverとproxyを結果と一緒に読みます。

show経路別の結果を表示する(db,"SELECT * FROM route ORDER BY id")

r2は社内DNSで拒否されています。一方r3は外部resolverと直接接続を使い、同じ制限対象ホストへ到達した記録です。

6制御点を通らない通信を抽出する

社内DNSまたはSWGを使わなかった行です。

show制御点を通らない通信を抽出する(db,"SELECT id,resolver,proxy,result FROM route WHERE resolver<>'corp' OR proxy<>'swg'")

r3が該当します。分類表にrestrictedと書かれているだけでは、経路外の通信を制御できません。

7カテゴリと実際の結果を集計する

制限カテゴリでも結果が一つでないことを確認します。

showカテゴリと実際の結果を集計する(db,"SELECT category,result,COUNT(*) AS requests FROM route GROUP BY category,result ORDER BY category,result")

restrictedに配送とDNS拒否の両方があります。DoHも名前解決の別経路になり得るため、利用するresolverと通信経路を合わせて調べます。

まとめ

DNSは名前、HTTPプロキシは要求の情報を扱います。

CONNECTだけでは内部のパスは分かりません。

ポリシーだけでなく制御点を通る経路を確認します。

操作履歴と解説を振り返れます。

Python 3.15 / TLS MemoryBIO / 固定の経路・配送記録

1
from sp05 import * from sp02 import show db = connect() for u in ('https://docs.example.test/manual','https://docs.example.test/private'): p=urlsplit(u);print(p.hostname,p.path)
docs.example.test /manual
docs.example.test /private
2
header = bytes.fromhex('123481850001000000000000') ident,flags,qd,an,ns,ar = struct.unpack('!6H',header) print(hex(ident),flags&15,qd,an)
0x1234 5 1 0
3
proxy_request = b'GET http://docs.example.test/manual HTTP/1.1\r\nHost: docs.example.test\r\n\r\n' print(proxy_request.decode(),end='')
GET http://docs.example.test/manual HTTP/1.1
Host: docs.example.test

4
connect_request = b'CONNECT docs.example.test:443 HTTP/1.1\r\nHost: docs.example.test:443\r\n\r\n' print(connect_request.decode(),end='')
CONNECT docs.example.test:443 HTTP/1.1
Host: docs.example.test:443

5
show(db,"SELECT * FROM route ORDER BY id")
id | host | resolver | proxy | category | result
r1 | docs.example.test | corp | swg | reference | delivered
r2 | other.example.test | corp | swg | restricted | dns_refused
r3 | other.example.test | external | direct | restricted | delivered
6
show(db,"SELECT id,resolver,proxy,result FROM route WHERE resolver<>'corp' OR proxy<>'swg'")
id | resolver | proxy | result
r3 | external | direct | delivered
7
show(db,"SELECT category,result,COUNT(*) AS requests FROM route GROUP BY category,result ORDER BY category,result")
category | result | requests
reference | delivered | 1
restricted | delivered | 1
restricted | dns_refused | 1

演習完了