Asteriskとe164.org

先日VPS上にAsteriskを入れて内線網を作りましたが、
せっかくなのでe164.orgにつないでみます。

実は大昔にe164.orgを使っていたことがあって(こことかこことか)、
そのときのアカウントがまだ生きており、
今回つないでみることにしました。

ところでE.164というのは国際的な電話番号の体系を定めたもので、
日本の国番号が”81″とかいうのもここでの定義によります。
このE.164をインターネットに透過的に浸透させようと
DNS引きできるようにしたのがENUMというもので、
e164.arpaドメインの下にすべての電話番号のレコードがぶら下がるようになっています。
ただしアナログ回線がまだまだ幅を利かせ、
IP電話も各社の囲い込みが激しい中、
これが実用になるには恐ろしく時間がかかりそうです。

そんな状況を打破しようとしてかどうかは分かりませんが、
ずいぶん前からe164.orgが活動していて
勝手に電話番号を割り振っています。
勝手とはいっても現状システムを完全無視しているわけではなく、
E.164で国際ネットワーク用として定義されている国番号”882″に
多分勝手に決定した”99″の事業者識別番号をくっつけて、
その元で6桁の組織識別番号をほしい人たちに配っています。
各組織に割り当てられるのは4桁の電話番号で1万番号運用できます。
何しろ勝手にやっていることなので、
e164.orgを使っている者同士しかつながらないのですが、
Asteriskには標準でe164.org関連の設定が埋め込まれていたりします。
このあたりが参考になります。

では設定してみましょう。
なお、e164.orgでの接続方法設定にIAX2に設定していることを前提とします。
まずは着信です。

"88-299-<組織識別番号(6桁)>-<内線番号(4桁,最初の2桁は'10')>"

にかかってきた電話を各内線番号に着信させます。
設定ファイル”/etc/asterisk/enum.conf”の[general]セクションにある

;search => e164.org

のコメントアウトを解除(行の先頭の’;’を削除)し、
設定ファイル”/etc/asterisk/iax.conf”の[guest]セクションの内容を

type=user
context=mainmenu-iax

に変更し、設定ファイル”/etc/asterisk/extensions.conf”の最後に

[mainmenu-iax]
exten => _88299<組織識別番号(6桁)>10XX,1,Dial(SIP/${EXTEN:11},,tT)
exten => _88299<組織識別番号(6桁)>10XX,n,Hangup

を追加します。
次に発信です。
設定ファイル”/etc/asterisk/extensions.conf”の[default]セクションに

exten => _88299.,1,Macro(enum-call,${EXTEN})
exten => _88299.,n,Congestion

を追加し、設定ファイル”/etc/asterisk/extensions.conf”の最後に

[macro-enum-call]
exten => s,1,Set(cidnum=88299<組織識別番号(6桁)>)
exten => s,n,Set(cidnum=${cidnum}${CALLERID(num)})
exten => s,n,Set(CALLERID(num)=${cidnum})
exten => s,n,Set(counter=0)
exten => s,n,Set(DS=0)
exten => s,n,Set(count=${ENUMLOOKUP(+${ARG1},ALL,c,,e164.org)})
exten => s,n(start),GotoIf($["${counter}" >= "${count}"]?end)
exten => s,n,Set(counter=$[${counter}+1])
exten => s,n,Set(ENUM=${ENUMLOOKUP(+${ARG1},ALL,,${counter},e164.org)})
exten => s,n,GotoIf($["${LEN(${ENUM})}" = "0" ]?start)
exten => s,n,GotoIf($["${ENUM:0:3}"="sip"]?sip)
exten => s,n,GotoIf($["${ENUM:0:6}"="guest@"]?iax:start)
exten => s,n(sip),Set(DS=$[${DS}+1])
exten => s,n,Set(DIALSTR${DS}=SIP/${ENUM:4})
exten => s,n,Goto(start)
exten => s,n(iax),Set(DS=$[${DS}+1])
exten => s,n,Set(iaxhostext=${CUT(ENUM,@,3)})
exten => s,n,Set(DIALSTR${DS}=IAX2/guest@${iaxhostext})
exten => s,n,Goto(start)
exten => s,n(end),Set(counter=0)
exten => s,n(start2),GotoIf($["${counter}" >= "${DS}"]?end2)
exten => s,n,Set(counter=$[${counter}+1])
exten => s,n,Set(DIALSTRING=${DIALSTR${counter}})
exten => s,n,Dial(${DIALSTRING},120)
exten => s,n,GotoIf($[$["${DIALSTATUS}"="CHANUNAVAIL"]|$["${DIALSTATUS}"="CONGESTION"]]?start2:hangup)
exten => s,n(end2),NoOp
exten => s,n(hangup),Hangup

を追加します。
その後

# /etc/init.d/asterisk restart

を実行して設定を反映させます。

通話テストは上記に準じた設定にしているのであれば
組織内の他の電話に88299で始まる外線経由でかけることで可能です。
例えば、内線番号1001の電話機から1002に電話をかけると、
当然1002の電話機には1001から着信した旨が表示され通話も可能ですが、
内線番号1001の電話機から”88-299-<組織識別番号>-1002″に電話をかけると、
1002の電話機には”88-299-<組織識別番号>-1001″から着信した旨が表示され
通話も可能となります。
ちなみに私の知り合いでe164.orgを使っている人を知らないので、
他の組織識別番号との発着信テストについては行っていませんが、
多分大丈夫でしょう。

実はこの設定、特に発信設定にたどり着くまでに結構な時間と試行錯誤が必要でした。

# asterisk -rvvv

を実行して立ち上がっているAsteriskにログインしデバッグ情報を確認したり、

# dig <内線番号(逆文字列、'.'区切り)>.<組織識別番号(逆文字列、'.'区切り)>.9.9.2.8.8.e164.org NAPTR

でDNS引きした結果を確認して行く過程で、
e164.orgでは接続設定をIAXにしている場合通話先を

guest@<電話番号>@<サーバ名>/<電話番号>

と返し、SIPの場合は

guest@<電話番号>@<サーバ名>/<電話番号>
sip:<電話番号>@<サーバ名>

と返していることが分かりました。
SIPのほうは多分問題ない(試してはいない)として
IAXのときは本来

guest@<サーバ名>/<電話番号>

の形式で返すべきと思われ、
e164.orgの単なるバグのような気がしないでもないのですが、
しょうがないので文字列操作で期待される形式に直すようにしました。

このe164.org、実際に役に立つかどうかは分かりませんが、
今回の件でよりAsteriskに詳しくなったので、
そちらのほうが何かの役に立つかもしれません。