Chapter 06
探索とメッセージング — DNS-SD と MRP
この章がなぜ必要なのか——「見つからない」と「届かない」を分けて考える.
Matter の通信は 2 段階である。 まず 相手を見つける(DNS-SD)。次に 確実に届ける(MRP)。
トラブルの大半はこのどちらかで、症状は似ているが原因はまったく違う。 「見つからない」ならマルチキャストと mDNS を疑い、 「見つかるが応答しない」ならセッションと MRP を疑う。
この章は 21 章のデバッグの土台になる。
この章で使う既出の用語(定義は各リンク先). Matter(01 章 3 節)、コミッショニング(01 章 3 節)、セキュリティ(01 章 2 節)、ネットワーク(01 章 3 節)、ACL(02 章 4 節)、IPv6(02 章 1 節)、Node(02 章 2 節)、メッセージング(02 章 1 節)、マルチキャスト(03 章 3 節)、Channel(04 章 4 節)、Router(04 章 2 節)、Wi-Fi(04 章 9 節)、必要(05 章 5 節)
1. DNS-SD による探索
Matter は DNS-SD(DNS Service Discovery)でノードを見つける。 ローカルネットワークでは mDNS(マルチキャスト DNS、_5353/udp)を使う。
3 つのサービスタイプ
| サービス | 用途 | いつ広告されるか |
|---|---|---|
_matterc._udp | コミッショニング可能な機器 | まだ Fabric に入っていない、または Commissioning Window が開いている |
_matter._tcp | 運用中のノード | Fabric に参加済み |
_matterd._udp | コミッショナ(ユーザー主導のコミッショニング用) | コミッショナ側が広告 |
_matter._tcpなのに UDP で通信する. 紛らわしいが、これは DNS-SD のサービス名の慣習によるもので、 実際のトランスポートは主に UDP(ポート 5540)である。 「なぜ _tcp なのか」を仕様上の意味で追う必要はない。そういうものだと覚える。
運用サービスのインスタンス名
<Compressed Fabric ID>-<Node ID>._matter._tcp.local.
16 桁 16 進 16 桁 16 進例:
DEDEDEDE00010001-0000000000000042._matter._tcp.local.| 部分 | 内容 |
|---|---|
| Compressed Fabric ID | Root Public Key と Fabric ID から HKDF で導出した 64 bit(02 章) |
| Node ID | その Fabric における Node ID(64 bit) |
これがマルチアドミンの見え方である. 1 台の機器が 3 つの Fabric に所属していれば、 3 つの
_matter._tcpインスタンスを広告する。 Fabric ごとに Compressed Fabric ID も Node ID も違うので、名前も違う。
dns-sd -B _matter._tcpで同じ機器が 3 行出てきても、それは正常である。
コミッショニング用サービスとサブタイプ
_matterc._udp にはサブタイプが付き、絞り込み検索ができる。
| サブタイプ | 意味 | 例 |
|---|---|---|
_S<n> | Short Discriminator(上位 4 bit) | _S15 |
_L<n> | Long Discriminator(12 bit 全体) | _L3840 |
_V<n> | Vendor ID | _V65521 |
_T<n> | Device Type | _T257 |
_CM | Commissioning Mode | _CM |
# 特定の Discriminator の機器だけを探す
dns-sd -B _matterc._udp,_L3840手動ペアリングコード(13 章)には Short Discriminator しか入らない. だから
_S<n>サブタイプが用意されている。 QR コードなら Long Discriminator が入るので_L<n>で正確に絞れる。
TXT レコード
サービスには TXT レコードが付き、通信パラメータが入る。
共通(運用・コミッショニング両方)
| キー | 意味 | 単位 |
|---|---|---|
SII | Session Idle Interval | ms |
SAI | Session Active Interval | ms |
SAT | Session Active Threshold | ms |
T | TCP サポートのビットマップ | — |
ICD | 長時間アイドル運用(LIT)かどうか | 0/1 |
コミッショニング時のみ
| キー | 意味 |
|---|---|
D | Discriminator(12 bit) |
VP | <VendorID>+<ProductID>(10 進) |
CM | Commissioning Mode(0=不可, 1=標準, 2=カスタム) |
DT | Device Type |
DN | Device Name(ユーザー向け表示名) |
RI | Rotating Device Identifier |
PH / PI | Pairing Hint / Pairing Instruction |
SII/SAIが電池機器では決定的である. これはコントローラに「私は寝ているので、再送はこの間隔で待ってくれ」と伝える値である。 ここが正しく広告されていないと、コントローラが短い間隔で再送を繰り返し、 機器の電池を無駄に消耗させる(次節の MRP)。
RI(Rotating Device Identifier)は、 追跡を防ぎつつ機器を識別するための、定期的に変わる値である。 常に同じ ID を広告すると、通りすがりの第三者に機器の存在を追跡されうる。
2. Thread での探索の特殊事情
Thread デバイスは mDNS のマルチキャストを常時受信できない(04 章)。 そこで SRP(Service Registration Protocol)で Border Router に登録し、 Border Router が代理で mDNS を広告する。
[Thread 機器] ──SRP(ユニキャスト)──> [Border Router] ──mDNS──> [Wi-Fi 側]| 確認コマンド | 見るもの |
|---|---|
ot-ctl srp client state | 機器側の登録状態 |
ot-ctl srp server service | Border Router に登録されているサービス |
dns-sd -B _matter._tcp | Wi-Fi 側から見えているか |
この 3 段階のどこで切れているかを特定するのが、Thread のデバッグの基本である。
3. MRP — メッセージ信頼性プロトコル
Matter は主に UDP を使う。UDP には再送も順序保証もない。 そこで Matter 自身が信頼性を担保する仕組みを持つ。それが MRP である。
仕組み
| 要素 | 内容 |
|---|---|
| Message Counter | メッセージごとの通し番号。重複検出と再送検出に使う |
| Reliability フラグ | 「このメッセージは ACK が必要」を示す |
| Standalone ACK | 応答すべきデータがないときの単独 ACK |
| Piggyback ACK | 応答メッセージに ACK を相乗りさせる |
| 再送 | ACK が来なければバックオフして再送 |
Piggyback ACK が重要である. 「電球を点けろ」に対して「点けました」という応答を返すなら、 その応答が ACK を兼ねる。パケット数が半分になる—— 電池機器と 802.15.4 の狭い帯域では、これが効く。
再送のバックオフ
\(n\) 回目の再送までの待ち時間は、次の式で決まる。
| 記号 | 意味 | 仕様上の値 |
|---|---|---|
| \(i\) | 基準間隔。相手が Idle なら SII、Active なら SAI | 相手が広告する値 |
| MARGIN | MRP_BACKOFF_MARGIN | 1.1 |
| BASE | MRP_BACKOFF_BASE | 1.6 |
| THRESHOLD | MRP_BACKOFF_THRESHOLD | 1 |
| JITTER | MRP_BACKOFF_JITTER | 0.25 |
| \(U\) | 0〜1 の一様乱数 | — |
| — | MRP_MAX_TRANSMISSIONS | 5 |
式の読み方.
- 指数バックオフ(BASE = 1.6)で、失敗を重ねるほど待つ。輻輳を悪化させないため。
- THRESHOLD = 1 なので、最初の 1 回はバックオフなし。すぐ再送する。
- JITTER で乱数を混ぜる。複数の機器が同時に再送して衝突するのを防ぐ。
- MARGIN = 1.1 は 10% の余裕。相手の処理時間を見込む。
決定的なのは \(i\)(SII / SAI)である。 相手が眠っている機器(SII が 5 秒など)なら、待ち時間も秒オーダーになる。 DNS-SD の TXT でこれを正しく広告していないと、 コントローラが数百 ms 間隔で再送を繰り返し、機器が受け取れないまま 5 回で諦めて失敗——という事故が起きる。
Active と Idle
| 状態 | 使う間隔 |
|---|---|
直近の通信から SESSION_ACTIVE_THRESHOLD 以内 | SAI(短い) |
| それ以上経過 | SII(長い) |
「さっきまで話していた相手なら、まだ起きているだろう」という前提である。
4. セッションの種類
Matter のメッセージは必ず何らかのセッションで保護される。
| セッション | 確立方法 | いつ使う |
|---|---|---|
| Unsecured | なし | セッション確立のハンドシェイクそのもの |
| PASE | パスコード(SPAKE2+) | コミッショニング時のみ(13 章) |
| CASE | 証明書(SIGMA) | 運用時(14 章) |
| Group | 事前共有のグループ鍵 | マルチキャストによる一斉制御 |
PASE と CASE の使い分けは明確である.
- PASE: まだ証明書がない新品の機器と話すため。パスコードだけが根拠。
- CASE: 証明書を持った機器どうしが、相互に身元を確認して話すため。
PASE で確立したセッションはコミッショニングが終われば破棄される。 以降はすべて CASE である。
5. メッセージの構造(概略)
┌──────────────────────────────────────────────┐
│ Message Header(平文) │
│ Session ID / Message Counter / Source Node… │
├──────────────────────────────────────────────┤
│ ↓ ここから暗号化・認証(AES-CCM) │
│ Protocol Header │
│ Exchange ID / Protocol ID / Opcode │
├──────────────────────────────────────────────┤
│ Application Payload(TLV) │
├──────────────────────────────────────────────┤
│ Message Integrity Check(MIC, 16 bytes) │
└──────────────────────────────────────────────┘| 概念 | 意味 |
|---|---|
| Session | 暗号化の単位。鍵が紐づく |
| Exchange | 1 往復のやりとりの単位。要求と応答を対応づける |
| Protocol ID | Secure Channel / Interaction Model / BDX / User Directed Commissioning |
| Message Counter | 単調増加。リプレイ攻撃を防ぐ |
ヘッダの一部が平文であることに注意. Session ID や Message Counter は、復号する前に必要なので平文である。 ただし認証はされている(MIC の計算対象に含まれる)ので、改竄はできない。
一方、Source/Destination Node ID がヘッダに露出しうる点は、 プライバシー上の考慮事項になる。仕様にはこれを難読化する仕組み (Privacy 拡張)も定義されている。
6. デバッグの手順
「見つからない」とき
1. dns-sd -B _matterc._udp(または avahi-browse)でサービスが見えるか
↓ 見えない
2. ping6 ff02::1 で機器が IPv6 レベルで見えるか
↓ 見えない → ネットワークの問題([03 章](03_IPv6の基礎.md#切り分けの順序))
↓ 見える → mDNS の問題(マルチキャスト遮断、Thread なら SRP)
3. Thread なら ot-ctl srp server service で登録を確認「見つかるが応答しない」とき
1. サービスの TXT レコードを確認(dns-sd -L で詳細)
→ SII / SAI が異常に大きくないか
2. 機器のログでセッション確立まで進んでいるか
↓ PASE/CASE が失敗 → 証明書・パスコードの問題([12 章](12_デバイス認証と証明書.md)〜[14 章](14_運用時のセキュリティ.md))
↓ 成立している → ACL の問題([14 章](14_運用時のセキュリティ.md))or 未実装のコマンド
3. MRP の再送ログを見る(何回再送して諦めたか)# サービスの詳細(TXT レコードとポート)を見る
dns-sd -L <instance-name> _matter._tcp local.
avahi-browse -r _matter._tcp
# 実際に解決してみる
dns-sd -G v6 <hostname>.local.7. 落とし穴
| 落とし穴 | 内容 |
|---|---|
| SII/SAI を広告しない | コントローラが短周期で再送し、電池機器が応答できない |
コミッショニング後も _matterc._udp を出し続ける | セキュリティ上・混乱の元 |
| mDNS の再登録漏れ | IP が変わったのにレコードを更新せず、到達不能になる |
| Compressed Fabric ID の誤計算 | 名前が合わず発見されない |
| SRP のリース切れ | 一定時間後に消える。定期更新が必要 |
| Exchange ID の使い回し | 応答の対応づけが壊れる |
| メッセージカウンタの巻き戻し | リプレイ検出に引っかかり拒否される(不揮発に保存すること) |
メッセージカウンタの永続化は見落とされやすい. 再起動でカウンタが 0 に戻ると、相手は「古いメッセージだ」と判断して破棄する。 仕様に沿った初期化・保存が必要である。SDK は対応しているが、 独自にストレージ層を実装した場合は要注意である。
8. まとめ
- 探索は DNS-SD / mDNS。3 つのサービスタイプ:
_matterc._udp(コミッショニング可)、_matter._tcp(運用中)、_matterd._udp(コミッショナ)。 - 運用インスタンス名は
<CompressedFabricID>-<NodeID>。 マルチアドミンでは Fabric の数だけ広告される。 - TXT レコードの SII / SAI / SAT が MRP の再送間隔を決める。電池機器では死活問題。
- Thread では SRP → Border Router → mDNS の 3 段中継。どこで切れたかを切り分ける。
- MRP が UDP に信頼性を与える。指数バックオフ + ジッタ、最大 5 回。 Piggyback ACK でパケット数を節約する。
- セッションは PASE(コミッショニング) と CASE(運用)。用途がはっきり分かれている。