ホスト名で許される文字って何なんだっけという話

以前の同期の友人と、そういえば数字だけのドメイン名って許されてるんだっけ?という話題で一通り盛り上がった。なかなか面白いことがわかったのと、イマイチよーわからんなーということが出てきたので、せっかくなので記事にしておこうと思う。

TL;DR

  • 数字のみのホスト名は RFC 的に OK
  • アンダースコアはホスト名的には NG だがドメイン名的には OK

数字だけのドメイン

https://0.30000000000000004.com/ というサイトが Twitter で回ってきた。 こういうドメインって RFC 的にどうなんだっけ。数字だけのドメインって大丈夫なんだっけ?

ホスト名の定義(大元)

host name については、元々は RFC952 に記載がある。以下、関係のある部分だけ抜き出し。

GRAMMATICAL HOST TABLE SPECIFICATION

      <official hostname> ::= <hname>
      <hname> ::= <name>*["."<name>]
      <name>  ::= <let>[*[<let-or-digit-or-hyphen>]<let-or-digit>]

見ての通り、 name は文字から開始して、あいだにハイフンとか入ってもいいけど、最後は letter or digit で終わること、とある。ホスト名はこれがドット区切りで1つか複数。これが最初のホスト名の定義だ。*1

でも、ホスト名ってドメイン名と同じなんだっけ?定義はよくわからない。

わからないなら、調べるしかないよね。

ドメイン名の定義(大元)

DNS 初期の RFC は結構gdgdなのは業界的に常識だけど、とりあえず RFC1035 を見てみよう。 ホスト名に対して 推奨される 形式がさっそく見つかった。とりあえず定義部分だけを見てみよう:

The following syntax will result in fewer problems with many
applications that use domain names (e.g., mail, TELNET).
<domain> ::= <subdomain> | " "
<subdomain> ::= <label> | <subdomain> "." <label>
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
<let-dig-hyp> ::= <let-dig> | "-"
<let-dig> ::= <letter> | <digit>
The labels must follow the rules for ARPANET host names.  They must
start with a letter, end with a letter or digit, and have as interior
characters only letters, digits, and hyphen.

この定義はホスト名とほぼ同じだ。違いとしては、先ほどは name だったものが label と呼ばれているくらいだろうか。 RFC 952 は ARPANET を念頭に書かれているので、 RFC 1035 の推奨するドメイン名は RFC 952 のホスト名と同等ということになる。

ただし、この部分はあくまで推奨。時代背景を見てみると、この頃はまだプロトコルの統一も完全でなければ商用インターネットもできる前なので、いろんな環境で共通して使えるような命名規則を作ろうとしていた…という面が強そうだ。

The DNS specifications attempt to be as general as possible in the rules
for constructing domain names.  The idea is that the name of any
existing object can be expressed as a domain name with minimal changes.

However, when assigning a domain name for an object, the prudent user
will select a name which satisfies both the rules of the domain system
and any existing rules for the object, whether these rules are published
or implied by existing programs.

For example, when naming a mail domain, the user should satisfy both the
rules of this memo and those in RFC-822.  When creating a new host name,
the old rules for HOSTS.TXT should be followed.  This avoids problems
when old software is converted to use domain names.

The following syntax will result in fewer problems with many
applications that use domain names (e.g., mail, TELNET).

具体的に「何を使っていいか」ということになると、あまり具体的には指定されていないように見える。

ちょっと脱線してしまったので、話に戻ろう。

そう、数字だ。数字だけのドメイン。 結局、数字だけのドメイン名は RFC 違反なわけ??

いやいやそんなわけ……。調べるしかないので、調べてみる。

ホスト名の定義(更新)

実はホスト名の定義は RFC1123 2.1 で更新されてる。

   2.1  Host Names and Numbers

      The syntax of a legal Internet host name was specified in RFC-952
      [DNS:4].  One aspect of host name syntax is hereby changed: the
      restriction on the first character is relaxed to allow either a
      letter or a digit.  Host software MUST support this more liberal
      syntax.

「RFCC952 で定義されたホスト名の先頭の文字、べつに数字でもよくね?」って言ってる。 RFC952 の BNF っぽい記法でこれを書き直してみると:

GRAMMATICAL HOST TABLE SPECIFICATION

      <official hostname> ::= <hname>
      <hname> ::= <name>*["."<name>]
      <name>  ::= <let-or-digit>[*[<let-or-digit-or-hyphen>]<let-or-digit>]

こういうことになる!! *2 *3

ということで、めでたしめでたし。最初の疑問、「数字オンリーのホスト名はRFC違反か」という疑問への答えが出た。 答えは「the Internet 開始前、 1989年からRFC 1123 で許容されている」ということになる。

ドメインにアンダースコア

……が、ここでふと次の疑問が湧いてきた。アンダースコアってどうなんだっけ?

そういやホスト名ってハイフンしか使っちゃダメって書いてあるよね。でも Let's Encrypt とか各種サービスの認証で ACME 使うとき、アンダースコアから始まるドメイン名使うよね。あれは RFC 的にはオッケーなんだっけ?

Informational な RFC で許容されている

実は、 DNS Operation の方法を記した RFC1033 ではアンダースコアが明示的に許容されている。

   The domain system allows a label to contain any 8-bit character.
   Although the domain system has no restrictions, other protocols such
   as SMTP do have name restrictions.  Because of other protocol
   restrictions, only the following characters are recommended for use
   in a host name (besides the dot separator):

           "A-Z", "a-z", "0-9", dash and underscore

各種サービス側で問題が出るから色々な制限を入れているけれど、 DNS はただのデータベースなのだから、何をラベルに使ったっていいんだ、アンダースコアはオッケーだよ、と、こう言っているわけ。

一方で、 RFC1912 というドキュメントがある。これは Common DNS Operational and Configuration Errors というタイトルの RFC 。重要な部分だけ抜き出してみると:

2.1 Inconsistent, Missing, or Bad Data

   Every Internet-reachable host should have a name.  The consequences
   of this are becoming more and more obvious.  Many services available
   on the Internet will not talk to you if you aren't correctly
   registered in the DNS.

   DNS domain names consist of "labels" separated by single dots.  The
   DNS is very liberal in its rules for the allowable characters in a
   domain name.  However, if a domain name is used to name a host, it
   should follow rules restricting host names.

   Allowable characters in a label for a host name are only ASCII
   letters, digits, and the `-' character.  Labels may not be all
   numbers, but may have a leading digit  (e.g., 3com.com).  Labels must
   end and begin only with a letter or digit.

   Note there are some Internet
   hostnames which violate this rule (411.org, 1776.com).  The presence
   of underscores in a label is allowed in [RFC 1033], except [RFC 1033]
   is informational only and was not defining a standard.  There is at
   least one popular TCP/IP implementation which currently refuses to
   talk to hosts named with underscores in them.

つまりアンダースコアを使うのはよくあるミスであって、使うべきではないぞと。 また、 RFC1035 の表現は問題を避けたいがゆえの曖昧さでいっぱいなので問題だとも言ってる。著者のクセが強い。

ちなみに RFC2181 の方ではアンダースコアが許容されていると語る人もいて、うーんなるほど曖昧という気持ちになる。

   The DNS itself places only one restriction on the particular labels
   that can be used to identify resource records.  That one restriction
   relates to the length of the label and the full name. 

結局、ドメイン名的にはアンダースコアは許容されているのかいないのか、微妙なところだ。

Apache 2.4 ではアンダースコアは使えない

じゃあ現実世界はどうだっけと、ふと Apache に目を向けてみると、なんと。

Apache 2.4 では host name を RFC 準拠にしたことで、 virtualhost などにアンダースコアを使えなくなっていた。まじかよ……

nderscores are not permitted in hostnames and are now rejected.  RFC 3986 sec 3.2.2 - https://tools.ietf.org/html/rfc3986#section-3.2.2 --

   A registered name intended for lookup in the DNS uses the syntax
   defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123].
   Such a name consists of a sequence of domain labels separated by ".",
   each domain label starting and ending with an alphanumeric character
   and possibly also containing "-" characters.

Using "HttpProtocolOptions unsafe" should allow the old behaviour.

https://bugzilla.redhat.com/show_bug.cgi?id=1410130

何がまじかよって、この RFC 3986 って URI を定義している RFC なんだよね。ということは、 URI 的には hyphen - は OK で underscore _ は NG とされているわけで。 Web サービスを提供する際は、ハイフンを使うのは必須だった ってことになる。知らなかった……。

Microsoft 的にはハイフンが推奨

とはいっても、やはりアンダースコアは世の中に存在している。存在するものをなかったことにはできない。ウォーハクタク。

ここで、 RFC に準拠しすぎて相互接続に難が出ることで有名な Microsoft のドキュメントを見てみよう。

ドメイン名にアンダースコア (_) を使用することは避けてください。
厳重に RFC に従ったアプリケーションがドメイン名を拒否して、
インストールされなかったり、ドメイン内で機能しなかったりして、
古い DNS サーバーで問題が発生する可能性があります。

https://support.microsoft.com/ja-jp/help/909264/naming-conventions-in-active-directory-for-computers-domains-sites-and

意外と柔軟

そして、こんな文言も見つかる:

アンダースコアには特殊な役割があり、RFC 定義では SRV レコードの
先頭文字として許可されていますが、比較的新しい DNS サーバーでは、
名前の任意の場所での使用が許容される場合もあります。 

ん…? SRV レコードの先頭には使っていいの?

SRV レコードの先頭には underscore を使っていいんです

SRV レコードでのアンダースコアについては、 RFC2782 に明確に記載がある。

The format of the SRV RR

   Here is the format of the SRV RR, whose DNS type code is 33:

        _Service._Proto.Name TTL Class SRV Priority Weight Port Target

   Service
        The symbolic name of the desired service, as defined in Assigned
        Numbers [STD 2] or locally.  An underscore (_) is prepended to
        the service identifier to avoid collisions with DNS labels that
        occur in nature.

ホスト名やその他の世間的に使われているドメイン名では、先頭アンダースコアなんて変なことしない。だからカブらない。 SRV レコードはこの書式を使っても大丈夫なんだ!と、こう RFC に書かれているわけ。

なるほどー。*4

オチ

だいたい疑問が解決したところで、また違う MS のドキュメントを見て、アレッとなってしまった。

    Strict RFC (ANSI) . Allows "A" to "Z", "a" to "z", the hyphen (-), the asterisk (*) as a first label; and the underscore (_) as the first character in a label.

    Non RFC (ANSI) . Allows all characters allowed when you select Strict RFC (ANSI) , and allows the underscore (_) anywhere in a name.

    Multibyte (UTF-8) . Allows all characters allowed when you select Non RFC (ANSI) , and allows UTF - 8 characters.

    Any character . Allows any character, including UTF - 8 characters.

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc959336(v=technet.10)

マルチバイト文字が許容されている…?

そう、実は RFC 2181 を読むと、ドメイン名のラベル部分には any binary string が使用可能、と書かれているんです。えー……今更そんな……

11. Name syntax

   Occasionally it is assumed that the Domain Name System serves only
   the purpose of mapping Internet host names to data, and mapping
   Internet addresses to host names.  This is not correct, the DNS is a
   general (if somewhat limited) hierarchical database, and can store
   almost any kind of data, for almost any purpose.

   The DNS itself places only one restriction on the particular labels
   that can be used to identify resource records.  That one restriction
   relates to the length of the label and the full name.
(略)
   Those restrictions
   aside, any binary string whatever can be used as the label of any
   resource record.  Similarly, any binary string can serve as the value
   of any record that includes a domain name as some or all of its value
   (SOA, NS, MX, PTR, CNAME, and any others that may be added).

   Implementations of the DNS protocols must not place any restrictions
   on the labels that can be used.  In particular, DNS servers must not
   refuse to serve a zone because it contains labels that might not be
   acceptable to some DNS client programs.

ということで、ドメイン名にはどんな文字でも使えちゃう、したがって当然ドメイン名にアンダースコアがあっても問題は一切ない、ということでした。*5

ちなみにドメイン名の基本的な挙動*6については case insensitive であることが RFC 的に MUST なんだけど、そうすると(記号類もフルで使えると仮定しても) 1byte が 256 - 26 - 1 = 230 の情報量しか示さないことになって、なんだか中途半端で気持ち悪い。

でも逆に、こういうところが DNS 最高って思うんです()

終わりに

ということで、以上まとめると、結論としては以下のようになる。

  • 数字だけのドメインRFC 的に許容されている
  • アンダースコアについては、 RFC 上、ホスト名はもちろん URI でも許容されていない
  • ドメイン名にはどのような文字でも使えるのでアンダースコアを含むドメイン名を作ることには一切問題がない

こうやって調べてみるのも久しぶりでなかなか面白かった。どさにっきさんっぽくなりたい。

でも記事の内容的には、 RFC を 3000番台までしか参照していなくて deprecated かもしれないし、また読み違いもあるかもしれない。 非常に不安なので、詳しいところの読み方については識者からのご指摘を待ちたいところです。

そんなとこ。

*1:ちなみに letter 一文字でも valid な official hostname になる

*2:数字オンリーの name が4桁続くと IP Address Form と同じになってしまう可能性があるじゃないか、とおっしゃる方、実際その通りなのだけど、この RFC では TLD は必ず letter が入るので問題ない、と言っており、この点は問題ないことになっている

*3:このあたりからは、 host name は DNS での lookup が前提とされていることも読み取れる。 host name と domain name との区別はかなり微妙だったようだ

*4:ただこれでも疑問は残って、 TXT レコードに転用されるようになった経緯とかそれに関する RFC とかはよーわからん

*5:バイナリラベルの書き方についてはRFC2673に定義されている。現実世界で有効活用している様子を見たことはないけれど、 C&C との通信や VPN over DNS なんかで使えそうではある。 Punycode あればいらない気がして仕方ない…

*6:case を利用した security extension もあるので、あくまで「基本的に」という表現にはなってしまう