qmailのReceivedヘッダがRFC違反に?

qmailの付けるReceivedヘッダが奇妙であることは、受け取ったメールのヘッダをじっくりと眺めたことのある方ならご存じと思います。しかしながら、これがRFC違反かという点については、以下の記事で説明されているように、一応そうではないということになっていたようです。

The myth about qmail-queue’s Received: headers being non-standard

ところが、このたびSMTPの規格がRFC 28212822からRFC 53215322へと改正されました。なにぶん長大な規格ですので斜め読みですが、どうもこの改正後の規格では、Receivedヘッダの規則が厳しくなったようで、例えば次のような(おそらくqmail特有の)ReceivedヘッダはRFC違反(非準拠)となったように見えます。

Received: (qmail 42078 invoked by uid 1004); 4 Nov 2008 21:10:19 +0900

参考までに、RFC 5321・5322記載のReceivedヘッダ関連のBNFを引用しておきます。

   Time-stamp-line  = "Received:" FWS Stamp 

   Stamp          = From-domain By-domain Opt-info [CFWS] ";"
                  FWS date-time
                  ; where "date-time" is as defined in RFC 5322 [4]
                  ; but the "obs-" forms, especially two-digit
                  ; years, are prohibited in SMTP and MUST NOT be used.

   From-domain    = "FROM" FWS Extended-Domain

   By-domain      = CFWS "BY" FWS Extended-Domain

   Extended-Domain  = Domain /
                    ( Domain FWS "(" TCP-info ")" ) /
                    ( address-literal FWS "(" TCP-info ")" )

   TCP-info       = address-literal / ( Domain FWS address-literal )
                  ; Information derived by server from TCP connection
                  ; not client EHLO.
   FWS             =   ([*WSP CRLF] 1*WSP) /  obs-FWS
                                          ; Folding white space

   ctext           =   %d33-39 /          ; Printable US-ASCII
                       %d42-91 /          ;  characters not including
                       %d93-126 /         ;  "(", ")", or "\"
                       obs-ctext

   ccontent        =   ctext / quoted-pair / comment

   comment         =   "(" *([FWS] ccontent) [FWS] ")"

   CFWS            =   (1*([FWS] comment) [FWS]) / FWS
   obs-FWS         =   1*WSP *(CRLF 1*WSP)
   domain          =   dot-atom / domain-literal / obs-domain

   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]

   dtext           =   %d33-90 /          ; Printable US-ASCII
                       %d94-126 /         ;  characters not including
                       obs-dtext          ;  "[", "]", or "\"
   address-literal  = "[" ( IPv4-address-literal /
                    IPv6-address-literal /
                    General-address-literal ) "]"
   IPv4-address-literal  = Snum 3("."  Snum)

   IPv6-address-literal  = "IPv6:" IPv6-addr

   General-address-literal  = Standardized-tag ":" 1*dcontent

   Standardized-tag  = Ldh-str
                     ; Standardized-tag MUST be specified in a
                     ; Standards-Track RFC and registered with IANA

   dcontent       = %d33-90 / ; Printable US-ASCII
                  %d94-126 ; excl. "[", "\", "]"

   Snum           = 1*3DIGIT
                  ; representing a decimal integer
                  ; value in the range 0 through 255

   IPv6-addr      = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp

   IPv6-hex       = 1*4HEXDIG

   IPv6-full      = IPv6-hex 7(":" IPv6-hex)

   IPv6-comp      = [IPv6-hex *5(":" IPv6-hex)] "::"
                  [IPv6-hex *5(":" IPv6-hex)]
                  ; The "::" represents at least 2 16-bit groups of
                  ; zeros.  No more than 6 groups in addition to the
                  ; "::" may be present.

   IPv6v4-full    = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal

   IPv6v4-comp    = [IPv6-hex *3(":" IPv6-hex)] "::"
                  [IPv6-hex *3(":" IPv6-hex) ":"]
                  IPv4-address-literal
                  ; The "::" represents at least 2 16-bit groups of
                  ; zeros.  No more than 4 groups in addition to the
                  ; "::" and IPv4-address-literal may be present.
   atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
                       "!" / "#" /        ;  characters not including
                       "$" / "%" /        ;  specials.  Used for atoms.
                       "&" / "'" /
                       "*" / "+" /
                       "-" / "/" /
                       "=" / "?" /
                       "^" / "_" /
                       "`" / "{" /
                       "|" / "}" /
                       "~"

   atom            =   [CFWS] 1*atext [CFWS]

   dot-atom-text   =   1*atext *("." 1*atext)

   dot-atom        =   [CFWS] dot-atom-text [CFWS]

つまり、Received: のあとの「FROM ~」「BY ~」の記述はすべて必須になったわけです。

また、このような記述もあります(RFC 5322 4.)。

One important difference between the obsolete (interpreting) and the
current (generating) syntax is that in structured header field bodies
(i.e., between the colon and the CRLF of any structured header
field), white space characters, including folding white space, and
comments could be freely inserted between any syntactic tokens. This
allowed many complex forms that have proven difficult for some
implementations to parse.

つまり、改正後はスペースやコメントの入れ方が制限的になったということで、これにより、CFWSと書かれていない場所(例えばReceived: の直後)に、カッコで括って任意の文字列(例えば「(qmail 42078 invoked by uid 1004)」を挿入することもできなくなったわけです。

追記: qmail の RFC 違反
今回の話と直接の関係はないけれど。

追記2:
qmailに見られる

Received: from unknown (HELO vc3.example.jp) (210.233.64.45)
by mail.example.jp with SMTP; 4 Nov 2008 21:10:18 +0900

のようなヘッダは、新しいRFCの推奨事項に従うならば

Received: from vc3.example.jp ([210.233.64.45])
by mail.example.jp with SMTP; 4 Nov 2008 21:10:18 +0900

と表わすことになりますが、by~の前にはコメントが認められているため、前者もRFC違反とまでは言えません。

qmailのReceivedヘッダがRFC違反に?」への2件のフィードバック

  1. y-hira

    「Received: (qmail 42078 invoked by uid 1004); 4 Nov 2008 21:10:19 +0900」はRFC違反ですけど

    「Received: from unknown (HELO vc3.example.jp) (210.233.64.45)
    by mail.example.jp with SMTP; 4 Nov 2008 21:10:18 +0900」は RFC違反でしょうか?
    「(HELO vc3.example.jp) (210.233.64.45)」を By-domain の CFWS とみれば 違反して無いように思えますが..。

  2. admin 投稿作成者

     コメントが遅くなりましてスミマセン。
     書いたのが少し前のことなので当時の記憶が曖昧ですが、(210.233.64.45)をTCP-infoのようなものと見るとその前にはCFWSが認められていない……ということで従来の版のような表現にしたのだと思います。しかしご指摘の通り、二つのコメントを丸ごとBY~の前のコメントと見ればRFC違反とまでは言えませんので、本文を修正しました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください