Brotherの複合機の通信プロトコル解析(スキャナ部分)(3) - スキャナへのPCの登録

以下の続き。

本題のスキャンデータの取り込み部分をまとめていたらめんどくさくなってきたので、やっぱり簡単なほうから先に書くことにする。スキャナ側の操作で取り込み先として指定するPC一覧に表示されるPCの登録方法についてまとめる。

以下、PC名をhogeIPアドレスを192.168.0.1、スキャナのIPアドレスを192.168.0.2とする。スキャナへのPCの登録は、概要にも書いたように、PCからスキャナにSNMPのSet-Requestを送ることで行う。

  • OID: 1.3.6.1.4.1.2435.2.3.9.2.11.1.1.0
  • community: internal

に対して、以下のようなSet-Requestを送る。

TYPE=BR;BUTTON=SCAN;USER="hoge";FUNC=IMAGE;HOST=192.168.0.1:54925;APPNUM=1;DURATION=360;
TYPE=BR;BUTTON=SCAN;USER="hoge";FUNC=OCR;HOST=192.168.0.1:54925;APPNUM=3;DURATION=360;
TYPE=BR;BUTTON=SCAN;USER="hoge";FUNC=EMAIL;HOST=192.168.0.1:54925;APPNUM=2;DURATION=360;
TYPE=BR;BUTTON=SCAN;USER="hoge";FUNC=FILE;HOST=192.168.0.1:54925;APPNUM=5;DURATION=360;

末尾に改行は含まない。4つのリクエストを同じOID宛に同時に送る。FUNC=に対応する値IMAGE、OCR、EMAIL、FILEが名前のとおりそれぞれのメニュー項目に対応する。ここで、1つのデータしか送らなかった場合などは、指定されなかったデータは登録を抹消される。

  • TYPE: BR固定。ブラザー?
  • BUTTON: SCAN固定。
  • USER: 表示されるPC名。ASCII文字以外は"?"となるようだ。最長16文字。PC名に設定された'"'やその他記号のエスケープはしていない。
  • FUNC: メニュー項目。
  • HOST: スキャナからのスキャンのリクエストを受け付けるPCのIPアドレスとポート。ここにUDPのパケットが送られる。
  • APPNUM: スキャンのリクエスト時に一緒に送られる。Brotherのアプリケーションでは、IMAGE: 1、OCR: 3、EMAIL: 2、FILE: 5となっているが、ほかの値でも問題ない。
  • DURATION: スキャナに登録される有効時間を秒単位で指定する。Brotherのアプリケーションでは、360秒を指定している。有効時間内に再度登録された場合は、(長くても短くても)新しい値で上書きされる。最長でどの程度まで有効なのかは未調査。
  • BRID: パスワードを設定した場合は、ここに16進8桁の値が設定される。パスワードを設定しない場合はこの項目はない。

以上の値を設定し、上の例のように値の後ろにセミコロンをつけてつなげる。USERに設定されたPC名とBRIDの組が各PCを区別するキーとなる。再度Set-Requestを送ったときに、これらが同じ場合上書きされ、どちらか片方でも異なる場合(IPアドレスが同じでも)別PCとして新規登録される。

スキャンキー用のパスワードを設定した場合は、BRIDという項目が増えて16進8桁の値が設定される。パスワードはスキャナ側でチェックするのみで、PC側でのチェックは行わない。前述のとおり、USERとBRIDの組でPCを識別しているため、パスワードの設定を変えると同じ名前のPCが複数登録されるのに、パスワードが異なるので解析中どれがどれかわからなくなって困った。BRIDは、一方向関数でなく、ビットの入れ替えとXORで復元できる簡易的なものだった。あえて解説する必要はないと思うので、割愛する。

というわけで通信手順がわかったので、スキャナにPCを登録するRubyスクリプトを書いてみた。SNMPプロトコルによるリクエストの送信には、
http://members.at.infoseek.co.jp/m6809/index-j.html
のs2nmpを使わせていただいた。

require 'socket'
require 's2nmp'

OID = '1.3.6.1.4.1.2435.2.3.9.2.11.1.1.0'
PC_ADDR = '192.168.0.1'
PC_PORT = 54925
PC_NAME = 'hoge'
SCANNER_ADDR = '192.168.0.2'

functions = [
  {:FUNC => 'IMAGE', :APPNUM => 1},
  {:FUNC => 'OCR'  , :APPNUM => 3},
  {:FUNC => 'EMAIL', :APPNUM => 2},
  {:FUNC => 'FILE' , :APPNUM => 5},
]

request = functions.map do |func|
  [OID, 4, %Q{TYPE=BR;BUTTON=SCAN;USER="#{PC_NAME}";FUNC=#{func[:FUNC]};HOST=#{PC_ADDR}:#{PC_PORT};APPNUM=#{func[:APPNUM]};DURATION=360;}]
end

snmp = SNMP.new(SCANNER_ADDR)
snmp.set('internal', request)

スクリプトを実行し、その後スキャナを操作してみると、"hoge"というPCが選択肢に現れていることを確認できた。ここで、"スキャンの実行"までしてしまうと、スキャンを行う部分はまだ用意していないので、タイムアウトまで長い間スキャナの操作できなくなるので注意。

PCの登録部分なら簡単なのですぐに書き終わるかと思ったら意外と長くなった。今回はこれで終わり。