MACアドレスとフレームの受信
ユニキャスト・ブロードキャスト・マルチキャストの宛先を調べます。
説明
MACアドレスには一台を示す個別アドレスと、複数の受信先を示すグループアドレスがあります。同じフレームがリンク上を流れても、すべての端末が上位処理へ渡すとは限りません。
三種類の宛先を持つPCAPを読み、受信条件のモデルでBとCの扱いを確認します。I/GとU/Lビットを調べ、最後に異なるIPマルチキャストが同じMACへ対応する例を計算します。
1同じLANの三つの端末
Aが送信し、BとCが受信する例です。Bだけが01:00:5e:01:02:03のマルチキャストを受け付ける設定とします。
cat nodes.csvMACと受信グループ三台は同じVLAN内です。以後は送信元Aを除き、BとCの通常のMAC受信フィルターを比較します。プロミスキャスや全マルチキャスト受信は無効とした条件です。
2三種類の宛先を含む記録
同じDATAをユニキャスト、ブロードキャスト、マルチキャストへ送ったPCAPを読みます。
tcpdump -n -tt -e宛先MACを表示 -r destinations.pcap三種類のフレーム宛先は順にBのMAC、ff:ff:ff:ff:ff:ff、01:00:5e:01:02:03です。EtherTypeは実験用0x88b5で、IPパケットではありません。配送先のMACだけを比較できるよう、内容は同じにしています。
3受信条件をソースで確認
delivery.pyは端末の受信条件を表す短いモデルです。全員宛て、自分宛て、加入グループ宛てを確認します。
cat delivery.py受信判定の条件スイッチの出力ポート選択と、端末がフレームを受け付けるかは別です。このプログラムは、フレームがその端末へ届いたときの受信条件だけを判定します。実際のスイッチでどのポートへ転送するかは、学習状態やマルチキャスト制御等でも変わります。
4一台のMACへ送る
BのMACを宛先にします。
python3 delivery.py端末の受信条件を評価 02:00:00:00:00:0bBへの個別宛先Bだけacceptです。先頭バイト02の最下位ビットI/Gが0なので個別アドレスです。次のU/Lビットが1なのでローカル管理アドレスであり、メーカーのOUIとして先頭3バイトを解釈しません。
5同じLANの全端末へ送る
全ビット1の宛先を指定します。
python3 delivery.py受信範囲を評価 ff:ff:ff:ff:ff:ffブロードキャスト宛先BとCがacceptです。ブロードキャストは同じブロードキャスト領域へ向けた配送で、インターネットの全端末へ配る意味ではありません。ルーターは通常、このEthernetフレームをそのまま別LANへ中継しません。
6指定グループへ送る
Bだけが受け付けるグループMACを指定します。
python3 delivery.py加入グループを照合 01:00:5e:01:02:03マルチキャスト宛先Bがaccept、Cがdiscardです。先頭バイト01のI/Gビットが1でグループアドレスを表します。スイッチ側で複数ポートへ転送されても、通常の端末フィルターで受け付ける範囲は加入設定によります。
7異なるIPグループが同じMACになる場合
IPv4マルチキャストの下位23ビットをMACへ対応させる規則で、239.1.2.3と225.1.2.3を変換します。
python3 -cIPv4グループをMACへ変換 'import ipaddress; groups=["239.1.2.3","225.1.2.3"]; print([(ip,(bytes.fromhex("01005e")+(int(ipaddress.IPv4Address(ip))&0x7fffff).to_bytes(3,"big")).hex(":")) for ip in groups])'下位23ビットの対応両方01:00:5e:01:02:03になります。IPグループの情報すべてをMACへ写しているわけではないため、MACだけではIPグループを一意に決められません。受信側ではIP層の宛先も確認します。
まとめ
I/Gは個別・グループ、U/Lはグローバル・ローカル管理の区別に使います。
スイッチの転送範囲と端末の通常の受信フィルターは別の判定です。
IPグループとMACグループは一対一ではないため、上位の宛先も確認します。
操作履歴と解説を振り返れます。
シェル / PCAPと通信の記録
cat nodes.csvNODE,MAC,MULTICAST A,02:00:00:00:00:0a,no B,02:00:00:00:00:0b,01:00:5e:01:02:03 C,02:00:00:00:00:0c,no
tcpdump -n -tt -e -r destinations.pcapreading from file destinations.pcap, link-type EN10MB (Ethernet) 0.000000 02:00:00:00:00:0a > 02:00:00:00:00:0b, ethertype Unknown (0x88b5), length 60: 0x0000: 4441 5441 0000 0000 0000 0000 0000 0000 DATA............ 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 0000 0000 0000 0000 0000 0000 .............. 0.000100 02:00:00:00:00:0a > ff:ff:ff:ff:ff:ff, ethertype Unknown (0x88b5), length 60: 0x0000: 4441 5441 0000 0000 0000 0000 0000 0000 DATA............ 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 0000 0000 0000 0000 0000 0000 .............. 0.000200 02:00:00:00:00:0a > 01:00:5e:01:02:03, ethertype Unknown (0x88b5), length 60: 0x0000: 4441 5441 0000 0000 0000 0000 0000 0000 DATA............ 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
cat delivery.py"""Destination filtering model for nodes B/C; all are on the same VLAN."""
import csv, sys
from pathlib import Path
nodes=list(csv.DictReader(Path('nodes.csv').open()))
dest=sys.argv[1].lower()
first=int(dest[:2],16)
print('destination:',dest,'I/G:',first&1,'U/L:',(first>>1)&1)
for node in nodes:
if node['NODE']=='A':
continue
accepted=dest=='ff:ff:ff:ff:ff:ff' or dest==node['MAC'] or dest==node['MULTICAST']
print(node['NODE'], 'accept' if accepted else 'discard')python3 delivery.py 02:00:00:00:00:0bdestination: 02:00:00:00:00:0b I/G: 0 U/L: 1 B accept C discard
python3 delivery.py ff:ff:ff:ff:ff:ffdestination: ff:ff:ff:ff:ff:ff I/G: 1 U/L: 1 B accept C accept
python3 delivery.py 01:00:5e:01:02:03destination: 01:00:5e:01:02:03 I/G: 1 U/L: 0 B accept C discard
python3 -c 'import ipaddress; groups=["239.1.2.3","225.1.2.3"]; print([(ip,(bytes.fromhex("01005e")+(int(ipaddress.IPv4Address(ip))&0x7fffff).to_bytes(3,"big")).hex(":")) for ip in groups])'[('239.1.2.3', '01:00:5e:01:02:03'), ('225.1.2.3', '01:00:5e:01:02:03')]演習完了