やあ、現場の最前線でパケットの挙動に一喜一憂しているエンジニアの諸君。今日も元気にターミナルを叩いているかな?
「家に友人が来たからWi-Fiを貸してあげた。数日後、ふと気付くと自分のNASに、見覚えのないスマホからのスキャンログが残っていた……」
笑い話のようだが、これはエンジニアの家庭で実際に起こりうる「ホラー体験」だ。今の時代、スマート家電(IoT)や来客用デバイスをメインネットワークに同居させるのは、玄関の鍵を開けっ放しにするのと同じくらい危うい。
今回は、家庭用ルーターやメッシュWi-Fiの選定基準として極めて重要な「ゲストネットワークの分離」と、その裏側で動く「VLAN(IEEE 802.1Q)」、そして「AP分離(クライアント間通信禁止)」の仕組みについて、現場の泥臭い知見を交えて深く掘り下げていこう。
—
1. なぜ「SSIDを分けるだけ」では不十分なのか?
多くの家庭用ルーターには「ゲストSSID」の設定がある。しかし、安価なルーターの中には、単にビーコン(SSID名)を2つ出しているだけで、内部的にはブリッジ結合されており、IPセグメントが同じという「名前だけの分離」が少なくない。
エンジニアである我々が求めるのは、論理的なL2/L3レベルでの完全な分離だ。
理想的な分離状態
- Main Network (VLAN 10): 自分のPC、NAS、開発サーバー。固定IPを振り、SSHやAPIアクセスを許可。
- Guest/IoT Network (VLAN 20): 友人のスマホ、怪しい挙動をする格安スマート電球。インターネットへの疎通のみ許可し、VLAN 10へのルーティングはFirewallでDROP。
これを実現するのが、タグVLAN(IEEE 802.1Q)という技術だ。
—
2. VLAN(802.1Q)による論理分離のシーケンス
ルーター内部のスイッチングハブや、メッシュWi-Fiのサテライト機との間では、パケットに「タグ」という名の付箋を貼ってやり取りしている。
イーサネットフレームの「タイプ」フィールドの前に、4バイトのVLANタグ(TPID 0x8100 と TCI)を割り込ませるのが、標準的な IEEE 802.1Q の仕様だ。
通信フローのイメージ
1. 無線端末 (Guest): DHCP Discoverを投げる。
2. AP (Access Point): Guest用SSIDから受信したパケットに「VLAN ID: 20」のタグを付与(Tagging)。
3. Trunk Port: メッシュWi-Fiの親機と子機の間を、タグ付きパケットが駆け抜ける。
4. Router/Firewall: VLAN 20のタグを見て、ゲスト用のアドレスプールからIPを払い出す。同時に、ルーティングテーブル上で VLAN 10 への転送を拒否するルールを適用する。
—
3. AP分離(クライアント間通信禁止)の正体
VLANでネットワークを分けたとしても、同じ「Guest SSID」に繋いでいる友人Aのスマホと、友人Bのスマホが通信できてしまうのは望ましくない。これを防ぐのが「AP分離(Isolation)」だ。
通常、Wi-FiルーターはL2スイッチ(ブリッジ)として動作するため、同じセグメント内の通信はルーターのCPUを介さず、スイッチングチップ内で完結しようとする。AP分離を有効にすると、無線インターフェース側で「送信元MAC」と「宛先MAC」をチェックし、同じ無線サブネット内のユニキャスト・ブロードキャストを強制的に遮断する。
実務的には、ルーター内部の ebtables (Ethernet Bridge tables) やチップセット固有のレジスタ設定で、以下のような制御が行われている。
# 概念的なフィルタリングイメージ(Linuxベースのルーター内部)
# ゲスト用インターフェース(wl0.1)からの通信で、宛先が同じサブネットならDROP
ebtables -A FORWARD -i wl0.1 -o wl0.1 -j DROP
—
4. 実践:ネットワークの分離をテストする
インフラエンジニアなら、設定画面を眺めるだけでなく、実際にパケットが通らないことをコードで証明したくなるはずだ。
例えば、Guest Wi-Fiに接続した端末から、メインネットワーク上にあるプライベートAPIサーバー(例: 192.168.10.100)へアクセスを試みる検証スクリプトを考えてみよう。
Pythonによる疎通確認スクリプト
requests ライブラリを使用して、タイムアウト設定を厳密にして検証する。
import requests
from requests.exceptions import Timeout, ConnectionError
# メインネットワーク上の機密資産(NASやAPI)のIP
INTERNAL_API_URL = "http://192.168.10.100:8080/api/v1/status"
def check_isolation():
print(f"Testing connection to: {INTERNAL_API_URL}...")
try:
# ゲストネットワークからは絶対に到達してはいけない
# タイムアウトを短く設定し、遮断されていることを確認する
response = requests.get(INTERNAL_API_URL, timeout=3.0)
if response.status_code == 200:
print("[CRITICAL] 脆弱性検知: ゲストネットワークから社内/宅内資産にアクセス可能です!")
else:
print(f"[WARNING] 応答あり (Status: {response.status_code}): 分離が不完全な可能性があります。")
except Timeout:
print("[OK] Timeout: パケットは正しくドロップされました。分離は有効です。")
except ConnectionError:
print("[OK] Connection Error: ルートが存在しないか、拒否されました。分離は有効です。")
except Exception as e:
print(f"[ERROR] 予期しないエラー: {e}")
if __name__ == "__main__":
check_isolation()
curlによる簡易チェック
エンジニアなら curl 一発で確認することも多いだろう。-I(ヘッダーのみ)と --connect-timeout を組み合わせるのが鉄板だ。
# 接続を試み、3秒以内にリジェクトまたはタイムアウトするか確認
curl -I --connect-timeout 3 http://192.168.10.100:8080/api/v1/status
もしこれで HTTP/1.1 200 OK が返ってくるようなら、そのルーターのゲストモードは単なる「SSIDのエイリアス」に過ぎない。即刻、VLAN設定を見直すべきだ。
—
5. ルーター選定時のチェックポイント(エンジニア向け)
これからメッシュWi-Fiやハイエンドルーターを導入するなら、スペック表の「最大速度」よりも以下の項目を凝視してほしい。
1. VLAN IDの指定が可能か:
SSIDごとに任意のVLAN ID(1-4094)を割り振れるか。
2. マルチSSIDとVLANの紐付け:
単なる「ゲストモード」ではなく、複数のSSIDに対して個別にFirewallルールを書けるか。
3. 有線ポートのVLAN対応:
Wi-Fiだけでなく、ルーターのLANポート1番はVLAN 10、2番はVLAN 20……といった具合に物理ポートも論理分離できるか(これができるとIoTハブなどの有線デバイスも隔離できる)。
OpenWrtなどの設定例(network/wireless)
カスタムファームウェアを利用している場合、内部設定は以下のような構造になる。
/* ゲスト用ネットワークインターフェースの定義 */
{
"interface": "guest",
"proto": "static",
"ipaddr": "192.168.20.1",
"netmask": "255.255.255.0",
"vlan_id": 20 // ここでVLANタグを指定
}
/* SSIDの設定 */
{
"ssid": "MyHome_Guest",
"device": "radio0",
"network": "guest", // 上記のguestインターフェースに紐付け
"isolate": 1 // これがAP分離(Client Isolation)のフラグ
}
—
結びに代えて:パケットの「境界線」を引く責任
我々エンジニアにとって、ネットワークは単なる「繋がる道具」ではない。それは情報の血流であり、境界線を守る最後の砦だ。
「家庭用だから」と妥協せず、パケットがどのVLANタグを背負い、どのスイッチポートでドロップされるのかを意識すること。その泥臭い理解こそが、トラブルシューティングの現場で「勘」として働き、堅牢なインフラを支える力になる。
もし君が新しいルーターを買うなら、まずは「ゲスト用SSIDから自分自身の管理画面(80番/443番ポート)にアクセスできるか」を試してみてほしい。もしアクセスできてしまったら……その夜は設定の見直しで忙しくなるはずだ。
健闘を祈る。
コメント