2012/12/12に掲載された記事です
seil-team の tsaito です。
前回の投稿からだいぶ期間が空いてしまいました。すみません。
今回は、つい先日日本でも発売が開始された Amazon Kindle のDHCP機能に関する話題です。
KindleのDHCPクライアント機能の実装は、実はちょっと普通の端末と異なっていて、特定のDHCPサーバからのアドレス取得に失敗することがあるようです。といいますか、SEILのDHCPサーバがまさにこの問題に該当していたのです。
で、SEIL/X, B1 の Ver4.10 でこの問題を調査、修正しリリースしているのですが、巷のブログ等を見ていてもこの原因をきちんと解説している情報があまり無さそうでしたので、参考までにSEILで起きていた問題とその修正方法を解説してみたいと思います。
(2012/12/12追記)
12/7に Kindle のソフトウェアアップデートが行われ、バージョン5.3.1がリリースされました。このバージョンで、DHCPに関する問題が修正されたとのことです。こちらでも試したところ、実際に今回調査した問題が修正されていることを確認しました!
DHCPの動作について軽くおさらい
DHCPサーバの構成
家庭などでKindleを使っていてDHCPでアドレスが取れない!となった場合、その問題の切り分けとしてDHCPサーバがどこで動いているかを正しく認識しておく必要があります。多くの無線LANルータでは「APモード」「ルータモード」の切り替え機能が提供されており、これによってどこでDHCPサーバが動いているかが変わってしまいます。
「ルータモード」の場合、無線LAN機器自体に、無線APの機能とルータとしての機能が同時に動いている状態です。この場合は、DHCPサーバが無線LAN機器そのもので動いていることになります。この場合、通常フレッツ光サービスなどでレンタルされるONUはPPPoEパススルーで動作します。
「APモード」の場合、無線LAN機器はあくまで無線アクセスポイントとしての機能を提供するため、ルータ機能およびそれに伴うDHCP機能は、ONUに任せることになります。
SEILが使われるケースでは、無線LAN機器はAPモードで動かし、ルータ機能を独立してSEILでまかない、さらにONUはPPPoEパススルーで動作させる、といったモデルになります。
もちろん、上記は一般的な例であり、構成によっては多段NATにすることもあったりすると思いますので、実際にどこでDHCPサーバが動いているかは環境をよく確認する必要があります。
DHCPのプロトコルについて
次に、DHCPでアドレスを取得するまでの流れについて軽く説明します。
DHCPでアドレスを取得しようとする端末(DHCPクライアント)から、DHCPサーバの探索リクエスト(DHCPDISCOVER)メッセージが送信されます。これに対し、DHCPサーバからは自分が配布可能なアドレスを通知する(DHCPOFFER)メッセージが返信されます。
DHCPクライアントは、DHCPOFFERメッセージの内容をチェックし、問題なければ正式にアドレス取得要求(DHCPREQUEST)メッセージを投げます。これに対し、DHCPサーバは要求内容に問題がなければ、アドレス払い出し完了(DHCPACK)メッセージを投げます。
このようなシーケンスでアドレスが払い出されます。実際には払い出しの延長や、アドレス重複時の挙動など細かいポイント毎に違いは存在しますが、詳細について興味のある方はRFC2131をご覧ください。
メッセージの中身について
さて、メッセージとして DHCPDISCOVER, DHCPOFFER, DHCPREQUEST, DHCPACK の4つを紹介しましたが、これらのメッセージの中身はどうなっているでしょうか。それを簡単に解説します。
DHCPのメッセージは、共通フィールド部分とオプションフィールド部分に分かれています。共通フィールド部分にはメッセージタイプ(op)やハードウェアアドレス(chaddr)など、すべてのメッセージで共通して必要となる情報が定義されています。一方、オプションフィールドは、環境に依存して異なるパラメータが定義されています。
オプションは、RFC2132などに定義されていますが、代表的なものは例えば以下に示すものがあります。
code | name | 意味 |
---|---|---|
1 | Subnet Mask | サブネットマスクアドレス |
3 | Router | デフォルトゲートウェイアドレス |
6 | Domain Server | DNSサーバアドレス |
12 | Hostname | ホスト名 |
42 | Network Time Protocol Server | NTPサーバアドレス |
53 | DHCP Message Type | DHCPメッセージタイプ |
54 | Server Identifier | DHCPサーバアドレス |
例えば、DHCPメッセージタイプ(53)などは、オプションではありますが全メッセージについて必須となったりします。このオプションフィールドを使って、DHCPサーバからDHCPクライアントに対して、様々な情報を配布することができるというわけです。
Kindle のDHCPクライアントの挙動について
と前置きはこれくらいにして、早速 Kindle の DHCPクライアントでアドレスが取得できない状況を再現させ、tcpdump(パケットキャプチャ)を取ってみました。DHCPサーバはSEIL/B1の旧バージョンを使っており、IPアドレスは192.168.0.1 となっています。Kindleの実機は Kindle PaperWhite を利用しました。
00:10:11.006650 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], length: 308) 0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from f0:4f:7c:xx:xx:xx, length: 280, xid:0xa9886f0b, flags: [none] (0x0000)
Client Ethernet Address: f0:4f:7c:xx:xx:xx
Vendor-rfc1048:
DHCP:DISCOVER
CID:[ether]f0:4f:7c:xx:xx:xx
VC:"udhcp 1.17.1"
MSZ:576
PR:SM+DG+NS+HN+DN+BR+NTP
00:10:12.012896 IP (tos 0x10, ttl 16, id 0, offset 0, flags [none], length: 290) 192.168.0.1.67 > 255.255.255.255.68: [udp sum ok] BOOTP/DHCP, Reply, length: 262, xid:0xa9886f0b, flags: [none] (0x0000)
Your IP: 192.168.0.3
Server IP: 192.168.0.1
Client Ethernet Address: f0:4f:7c:xx:xx:xx
Vendor-rfc1048:
DHCP:OFFER
SID:192.168.0.1
LT:86400
SM:255.255.255.0
00:10:14.023814 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], length: 308) 0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from f0:4f:7c:xx:xx:xx, length: 280, xid:0xa9886f0b, flags: [none] (0x0000)
Client Ethernet Address: f0:4f:7c:xx:xx:xx
Vendor-rfc1048:
DHCP:DISCOVER
CID:[ether]f0:4f:7c:xx:xx:xx
VC:"udhcp 1.17.1"
MSZ:576
PR:SM+DG+NS+HN+DN+BR+NTP
00:10:14.026313 IP (tos 0x10, ttl 16, id 0, offset 0, flags [none], length: 290) 192.168.0.1.67 > 255.255.255.255.68: [udp sum ok] BOOTP/DHCP, Reply, length: 262, xid:0xa9886f0b, flags: [none] (0x0000)
Your IP: 192.168.0.3
Server IP: 192.168.0.1
Client Ethernet Address: f0:4f:7c:xx:xx:xx
Vendor-rfc1048:
DHCP:OFFER
SID:192.168.0.1
LT:86400
SM:255.255.255.0
KindleからはDHCPDISCOVERが出ており、SEILもDHCPOFFERを出してそれに応えているのですが、KindleはどうもそのDHCPOFFERが気に入らないようで、それを無視して再度DHCPDISCOVERを出してしまっています。このような感じで、いつまでたってもKindleはDHCPでのアドレス取得に成功しない、という状況になっていました。
どのように実装を修正したか
ポイントはDHCPOFFERメッセージの内容にありそうです。ということで、正常動作している他のDHCPサーバの挙動とも比較しながら切り分けを進めた結果、以下のことがわかりました。
- KindleのDHCPDISCOVERメッセージの"Parameter Request" オプションでは以下のパラメータを要求している:
- Subnet Mask(SM)
- Router(DG)
- Name Server(NS)
- HostName(HN)
- Domain Name(DN)
- BroadCast Address(BR)
- NTP Server(NTP)
- DHCPサーバからは DHCPOFFER で少なくとも以下のオプションを返してあげないと、KindleはそのDHCPOFFERを無効とみなす、らしい
- Subnet Mask(SM)
- Router(DG)
- Name Server(NS)
- がしかし、SEILではDHCPACKメッセージの送信時にのみこれらのオプションを付加する実装になっており、DHCPOFFERではオプションを付加しないようになっていた
ということで、修正方法は実にシンプルなのですが、DHCPOFFER送信の際にもDHCPACKの時と同様のオプションを付加するようにしたところ、見事にKindleでDHCPが動作するようになりました。
RFC的には、どうなの?
さて今回の挙動、SEIL側の実装を修正することによって解決できたわけですが、RFC的観点からはどうなのでしょうか?ということで該当する箇所を見てみます。"4.3.1 DHCPDISCOVER message" には以下のようにあります。
o Parameters requested by the client, according to the following
rules:
-- IF the server has been explicitly configured with a default
value for the parameter, the server MUST include that value
in an appropriate option in the 'option' field, ELSE
-- IF the server recognizes the parameter as a parameter
defined in the Host Requirements Document, the server MUST
include the default value for that parameter as given in the
Host Requirements Document in an appropriate option in the
'option' field, ELSE
-- The server MUST NOT return a value for that parameter,
The server MUST supply as many of the requested parameters as
possible and MUST omit any parameters it cannot provide. The
server MUST include each requested parameter only once unless
explicitly allowed in the DHCP Options and BOOTP Vendor
Extensions document.
サーバはできる限り要求されたパラメータを返すべき、となっているので、DHCPサーバ側でオプションを省略する実装はよろしくないようです。。ということでSEIL側を修正するのは理に適っていると言えますね。これは推測ですが、他の一般的なDHCPクライアントではアドレスを取得するために必要な最低限の情報だけをチェックしているところ、Kindleでは実際にInternetへの接続に必要なオプション(DG, SM, NS)が含まれていないといけない、と解釈しているようです。
まとめ
DHCPのように一般的には「枯れた」とみなされる技術では、あまりこの手の相互接続性問題は起こらなくなっているのですが、久しぶりに出たような感触です。なお、今回は他の実装や機器の状況について詳しく調べてはいませんが、いくつかのブロードバンドルータで似たような症状が出たりしているようです。
Kindleでわざわざ固定アドレスを設定するような運用は面倒ですし、できれば他の機器でも修正版ファームがリリースされると良いですね。