はじめに

過去記事、「開発環境について/外部からのHTTPSテスト環境アクセスについて」では、ローカルな環境(プライベートネットワーク)内で、モバイル端末などの外部端末から HTTPS のテスト環境へアクセスする方法について説明しました。

そして、その後の記事で、この方法で構築した HTTPS のテスト環境に、実際に様々の OS の端末から接続できることも確認してきました。

しかし、このアクセスには、1つ大きな欠点がありました。

それは、多くの場合、プライベートネットワーク内の IP アドレスは、DHCP サーバーによって自動的に割り当てられるため、IP アドレスが変更される可能性があるということです。

HTTPS サーバーを実行するパソコンの IP アドレスが変更される可能性がある場合は、固定化しておく必要があります。

そうでなければ、IP アドレスが変更されるたびに、接続ができなくなり証明書の作り直しが必要になるということでした。

Windows では、イントラネットなどの社内の小さな LAN 環境の名前解決に NetBios という名前解決の仕組みを持っています。

ですが、この方法はセキュリティの観点から、現在は推奨されず、macOS や Linux でも標準では使用できません。

では、小規模なプライベートネットワークにおいても、名前解決のためには、DNS サーバーを立てる必要があるのでしょうか?

実は、そのような需要に打って付けの技術が存在するのです。

それが、今回ご説明する mDNS になります。

今回は、この mDNS がどのような技術であるかを説明し、実際に HTTPS テスト環境に組み込む方法について解説していきたいと思います。


mDNS とは?

mDNS(Bonjour)は 2002 年に Apple が発表した技術です。正式名称は Rendezvous(ランデブー) として登場し、その後 2005 年に、Bonjour に名称変更されました。

その後 Linux・IoT・Windows に広まり、2022 年に Windows 11 22H2 が標準対応しました。

仕組みとしては、DNSサーバー不要で、UDP 5353 番ポート、マルチキャストアドレス 224.0.0.251 を使用し、「xxx.local」 という名前を LAN 内で解決します。

クライアントから、上記ポートとアドレスを使用して、「xxx.local」 という名前を問い合わせると、その名前でサービスを提供しているサーバーから応答として、IP アドレスが返されます。

※ mDNS は DNS と同じ形式で応答し、IPv4 の場合は A レコード、IPv6 の場合は AAAA レコードで IP を返します。

(図1)mDNS ローカルホスト名フロー
┌──────────────────────────────────────────────┐
│  ブラウザ(Chrome / Safari / Edge)           │
│                                              │
│  https://MyLocalDevServer.local:3000         │
└──────────────────────────────────────────────┘
                     │
                     ▼
┌──────────────────────────────────────────────┐
│  mDNS クライアント(OS側の機能)               │
│  「MyLocalDevServer.local の A レコード?」   │
│  を LAN に向けてマルチキャスト送信             │
│  UDP 5353 / 224.0.0.251                      │
└──────────────────────────────────────────────┘
                     │
                     ▼
┌──────────────────────────────────────────────┐
│  LAN 内の mDNS 対応デバイス(サーバー)        │
│  「私が MyLocalDevServer.local です」         │
│  と応答(A/AAAA レコードで IP を返す)         │
└──────────────────────────────────────────────┘
                     │
                     ▼
┌──────────────────────────────────────────────┐
│  ブラウザが IP を取得し、HTTPS で接続          │
│  → 証明書の SAN にホスト名があれば OK          │
└──────────────────────────────────────────────┘
    

Apple の Bonjour、Chromecast、家庭用プリンターなどが使っている方式です。


補足:Bonjour について

Bonjour とは、Apple の OS において、Apple mDNS を提供するものです。

では、Bonjour = mDNS かと言われるとそうではありません。 Bonjour には、mDNS 以外に、DNS-SD という技術も含まれています。

mDNS が、特定の「xxx.local」から IP アドレスを解決する仕組みだとすると、DNS-SD は、LAN 内に「どんなサービスがあるか」の一覧を取得するための技術です。

※ DNS-SD は内部的に SRV レコードを使用し、「サービス名 → ホスト名 → ポート番号」の対応を返します。

(図2)DNS-SD HTTPS サービス検出
┌──────────────────────────────────────────────┐
│  DNS-SD クライアント(Bonjour / Avahi)        │
│  「HTTPS のサービス一覧を教えて」               │
│  → _https._tcp.local を検索                   │
└──────────────────────────────────────────────┘
                     │
                     ▼
┌──────────────────────────────────────────────┐
│  LAN 内の HTTPS サーバーが一覧で応答           │
│  例:                                         │
│   - サービス名: MyLocalDevServer              │
│   - ホスト名: MyLocalDevServer.local          │
│   - ポート: 3000                              │
│   - TXT/SRV レコード                          │
└──────────────────────────────────────────────┘
                     │
                     ▼
┌──────────────────────────────────────────────┐
│  DNS-SD クライアントがホスト名を取得           │
│  → MyLocalDevServer.local                    │
│  → その後は mDNS で名前解決                    │
└──────────────────────────────────────────────┘
    

Chromecast やプリンターは DNS-SD を使って LAN 内にサービスを公開しています。

このように、Bonjour では、この2つの技術の組み合わせで、LAN 内の名前解決を実現しています。

仕組み 役割
mDNS ホスト名(xxxx.local)→ IP を解決する
ブラウザが使うのはこれだけ
DNS-SD LAN 内のサービス一覧を探す
_https._tcp.local などのサービス種別を使う
ブラウザは使わない


主要 OS における mDNS 対応状況

下記は、主要 OS における執筆時点での対応状況をまとめたものです。

OS mDNS 解決 mDNS 発信 備考
iOS ◎ ◎ Bonjour 標準。
Android ○ △ Chrome ブラウザが mDNS 対応、発信は弱い
Windows ○ × Windows 11 22H2 以降で mDNS 名前解決は可能だが、発信は不可
macOS ◎ ◎ Bonjour の本家
ChromeOS ○ △ Chrome ブラウザが mDNS 対応、発信は弱い
Linux ◎ ◎ Avahi が標準で強力

OS で標準でサポートされている iOS/macOS/Linux を除くとその対応状況は様々です。

しかし、クライアント機能に着眼すると Chrome ブラウザなど、ブラウザによる「mDNS 解決」がサポートされているおかげで、HTTPS テスト環境へのアクセスという点では、ほぼ問題なく、「xxx.local」の名前解決が可能となっています。

👉 ここで、気になるのは、今回 HTTPS テスト環境を構築している サーバーの OS がWindows であるという点です。

Windows では、「mDNS 発信」に対応していないため、「xxx.local」の問い合わせがきても標準では IP アドレスの返答を行いません。


Windows で「mDNS 発信」に対応する方法

なぜ、Windows 11 22H2 以降では、標準で「mDNS 解決」に対応しているのに、「mDNS 発信」を行わないのでしょうか?

Windows が mDNS 発信を標準で行わない理由は明確ではありませんが、セキュリティやネットワーク設計上の判断によるものと考えられています。

確かに、mDNS は、NetBios などに比べて比較的安全であるといわれていますが、セキュリティリスクがなくなったわけではありません。

そういう点では、mDNS の運用は、各端末でしっかりとファイアーウォールの設定などを行い、慎重に運用することが求められます。

では、Windows では「mDNS 発信」に対応することはできないのでしょうか?

実は、下記のような方法があります。

  • Bonjour(Appleのサービス)をインストールする

iTunes や Bonjour Print Services を入れると Windows でも mDNS を発信できるようになります。

  • 自分で mDNS サーバーを動かす

Node.js の bonjour モジュール や Python の zeroconf ライブラリで mDNS を発信できます。

今回は、HTTPS のテスト環境で、Node.js を利用していることもあり、Node.js で mDNS サーバーを利用する方法をみていきたいと思います。


Node.js の Bonjour モジュールとは?

Node.js の Bonjour モジュール (公式ページ)は、Thomas Watson (GitHub: watson) さんが作成したモジュールです。

Thomas Watson さんは、Node.js のネットワーク周りの OSS を多く手がけている開発者で、この bonjour モジュールもその代表作のひとつです。

Apple の mDNS / DNS-SD 仕様を参考にして JavaScript で再実装された OSS モジュールです。MIT license で公開されています。

技術的には Apple の仕様を忠実に再現しており、 Apple の以下の仕様に基づいています:

  • mDNS(Multicast DNS) ⇒ UDP 5353 / 224.0.0.251
  • DNS-SD(DNS Service Discovery) ⇒ _http._tcp.local のようなサービス名を使う仕組み

これらは Apple が IETF に提出した Zeroconf の標準仕様です。

つまり、Node.js の bonjour は Apple公式ではないのですが、Apple の標準仕様を実装した互換モジュールという位置づけになります。

このモジュールのおかげで、「xxx.local」 ホスト名を使った HTTPS サーバーの名前解決が可能となります。

開発者の方、関係者の方には、この場をお借りして、深くお礼を申し上げたいと思います。


Bonjour モジュールの導入

Node.js で mDNS(Bonjour)を使うには、Apple の Bonjour 仕様を実装した OSS ライブラリ bonjour を導入します。

インストールはターミナルを起動し、次の 1 行を打ち込むだけです。

npm install bonjour

このパッケージは GitHub の watson/bonjour が提供している Bonjour / Zeroconf の純粋な JavaScript 実装で、 macOS/iOS/Linux/Windows や Chrome ブラウザとも完全な互換があります。


Bonjour モジュールの使い方

下記に、 Bonjour モジュールを使用して、「mDNS 発信」を行う方法を示します。

例:

ES Modules(推奨)の場合

import bonjour from "bonjour";
const mdns = bonjour();

mdns.publish({
  name: 'My Local Dev Server',
  type: 'https',
  port: 3000
});

CommonJS の場合

const bonjour = require('bonjour')();

bonjour.publish({
  name: 'My Local Dev Server',
  type: 'https',
  port: 3000
});

publish メソッドを使い、

  • name:サービス名
  • type:http/https
  • port:ポート番号

を指定して稼働します。

ここで指定した、name には注意が必要です。 Bonjour に指定した name は「サービス名」であり、ブラウザで使う「ホスト名」ではありません。

「ホスト名」は DNS の制約に従うため、スペースや記号は使えず、自動的に MyLocalDevServer.local のような形式になります。

つまり、mDNSブラウザからアクセスする場合は、

https://MyLocalDevServer.local:3000/

と指定することになります。


よくある質問(記事に書くと親切)

Q1. bonjour-service という別パッケージは?

→ 別物です。

→ Apple の Bonjour と互換ですが、Node.js では bonjour が最も広く使われています。

Q2. Windows でも動く?

→ 動きます。

→ Windows は mDNS を「受信はできるが発信はできない」ので、Node.js の bonjour がその不足を補います。

Q3. Express と併用できる?

→ できます。

→ 相性はとても良いです。


次回予告

Express と Bonjour は、1つの JavaScript 内で併記することが可能です。次回は、Express サーバーとして使用しているサーバーに、Bonjour を組み込んで稼働してみたいと思います。そして、実際に外部端末からアクセスし、その動きを確認したいと思います。