コンピュータ」カテゴリーアーカイブ

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違反とまでは言えません。

NNIPF 0.10のバグ修正

私の愛用しているNNIPF 0.10に、Received: の行のfromに現れるアドレスが次のようにカッコにIPアドレスのみが記される形式になっていると認識されないというバグがあるようです。

Received: from p11014-ipadfx01hon.saitama.ocn.ne.jp (220.96.189.14)

Webインタフェースでは認識されているような表示になりますが、複数あるfrom行のアドレスのどれを選択するかの処理において無視されています。

PERL/NNIPF.pmのサブルーチンofficialIPを以下のように修正してみましたところ、一応正常に動くようになったようです(無保証)。

######################## from string returned by ReceivedFrom() to official IP
sub officialIP{
  my ($str)=@_;
  my $OIP="";
  if ($str =~ /.*\[([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\].*/) {
    $OIP =$1;
  } else {
    ($OIP) = $str =~ /\((?:[^@]+@)?([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\)/;
  }
#  my @h=split(/ /,$str);
#  if  ((defined $h[3])&&($h[3] =~ /[^0-9]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)[^0-9]*/)) {
#    $OIP = $1;
#  }
  return $OIP;
}

それにしても、一年ほど開発の動きが止まってしまっているのは残念ですね。

追記: IPアドレスが@付きの形式になっていた場合に認識できないというバグがあったので修正しました(2008.12.14)

Referer文字列からロボットかどうかを判定する正規表現

Apacheなどのウェブサーバのアクセスログで、Refererフィールドに出力される文字列が以下のファイルの正規表現のいずれかにマッチするようなら大体それはロボットのアクセスです。

robot_patterns(UNIXテキストファイル)(2010-4-26改訂)

これを使ってApacheのアクセスログからロボットのアクセスを抽出するフィルタの例は以下のとおり。上の内容がrobot_patternsというファイルとしてカレントディレクトリに保存されていると想定してあります。また、Parse::AccessLogEntryが必要ですのでCPANからインストールしておいてください。


#!/usr/bin/perl

use Parse::AccessLogEntry;

$robot_patterns_file = "robot_patterns";
$local_address_patterns_file = "local_address_patterns";

open(RP, $robot_patterns_file) or die $!;
while(<RP>) { chomp; push(@robot_patterns, $_) if ! /^\s+$/; }
$robot_pattern = "(?:" . join(")|(?:", @robot_patterns) . ")";

open(LP, $local_address_patterns_file) or die $!;
while(<LP>) { chomp;push(@local_address_patterns, $_) if ! /^\s+$/; }
$local_address_pattern = "(?:" . join(")|(?:", @local_address_patterns) . ")";

$P = Parse::AccessLogEntry->new();
($myname) = $0 =~ /([^\/]+)$/;

if ($myname eq 'robotsalog') {
        LINE: while(<>) {
                my $e = $P->parse($_);
                next LINE if $e->{host} =~ m/$local_address_pattern/o;
                print if $e->{agent} =~ m/$robot_pattern/o;
        }
} else {
        LINE2: while(<>) {
                my $e = $P->parse($_);
                next LINE2 if $e->{host} =~ m/$local_address_pattern/o;
                print if $e->{agent} !~ m/$robot_pattern/o;
        }
}

robotsalogという名前で呼び出されたときは、ロボットのアクセスだけを出力します。その他の場合はロボットでないアクセスだけを出力します。

ちなみにlocal_address_patternsというファイルも必要です。この中身には自分自身のアドレスのパターンを入れておきます。そうするとその分も除外して出力します。サンプルは以下のとおり。


^192\.168
^127\.0\.


うちではこれで大体うまくいってます。完全無保証でよろしければご自由にお使い下さい。

三菱、24.1型液晶「MDT242WG」の枠つや消し限定モデル

三菱、24.1型液晶「MDT242WG」の枠つや消し限定モデル

先日この液晶モニタの通常版の方のモデルを購入しまして、現在使用中なのですが、今度はそのつや消しモデルが出るとのニュースです。あくまでもフレーム部分だけの話であり、表示部分は通常版でもつや消し(ノングレア処理)です。

通常版のフレームがツヤツヤなのは、要するにPS3に合わせたということのようなのですが、ネットの一部で指紋が付くとか照明が映り込むとかといった批判がありました。ただ、私個人としてはそれほど重大な問題とは思われなかったので、限定モデルとはいえメーカーがわざわざ別型番として用意してくるという展開は意外でした。市場リサーチの結果が相当悪かったのでしょうか。

L.ROOT-SERVERS.NET

旧L.ROOT-SERVERS.NETを信用してはいけない

ううっ、うちのサーバも古いままでした。さっそく直しました。

これ、管理してるサーバが多い人は大変なんじゃないでしょうか。特にWindowsのMicrosoft DNS Serverは一々管理ツールを立ち上げて手で修正しないといけないので、Active Directoryドメインを組んでいる場合にはドメイン毎にすればいいらしいといっても、客先サーバの保守を沢山受け持っているところなどでは作業量が結構なものになるのでは。IPアドレスは手入力だと結構間違えますし。Windows Updateで対応して欲しいところですね。

WordPressアップデート

WordPressを2.5にアップデートしました。
閲覧画面はほとんど変わりありませんが、管理・投稿用画面は大分変わりました。
形式段落の頭にある空白が消えてしまうバグが解消されているかと少し期待したのですが、直っていないようですね。

WordPress Japanサイト閉鎖へ

WordPress Japanのサイトが3月末で閉鎖だそうです。

WordPressの日本語版としては、Wordpress日本語版とWordpress MEの2つの独立した系統があるのですが、実はインストールしたときはその辺りの事情をよく知らず、なんとなくWordpress MEの方をダウンロードして使っておりました。そのMEの方の配布元が閉鎖されるということです。

WordPress MEは新しいバージョンのリリースも停止となっており、おそらくWordpress日本語版の方が既に主流なので、Wordpress MEは役目を終えたということなのでしょう。

ただ使わせて貰っただけの立場で何も貢献はできませんでしたが、Wordpress Japanの皆様、まずはお疲れ様でした。そしてありがとうございました。