Mikrotikルータを使ったひかり電話収容

とにかくあの ntt から強制レンタルしている黒い箱直下にルータを置くのが嫌で今までヤマハのルータを仕方なく愛用していましたが、色々と痒いとこに手が届かない。
極め付けは onu ポートのミラーが出来ないので何を通信しているのか全く分からないことに長い間歯痒い思いをしてきました。

月日が経ち asterisk は pjsip が標準となり、nat 越えが簡単に出来る良い時代となりました。そんな訳でこれを期に mikrotik ルータ ＋ ntt の小型 onu ＋ asterisk を使用してひかり電話を直収してみます。

前提
---
- ntt のひかり電話の契約
- v6の契約（特に必須では無い）
- 小型 onu（これも必須では無いですが、機器を極力減らすのに有効）
- ipipv6（map-e でも良い）
- お好きな mikrotik ルータ

今回購入した mikrotik ルータは rb5009 で、sfp+ ポート付きです。sfp+ から rj45 のメディアコンバータを使用すれば sfp+ ポートの無い他の機種でも出来るかも。


mikrotik
---
##### 小型 onu
なお小型 onu は製造元によって sfp ポートとの相性があるようで[^1]、三菱製はリンクは上がるものの vender 情報が取れず[^2]、キャプチャを見たところ solicit を送っても advertise が無く無反応。当然 v6 アドレスも降ってこない。富士通製にすることで ngn 網と（なんとか）接続が可能となりました。

これは書いて良いのかフレッツのお姉さんに頼んだら、その日の昼には指定したベンダーの小型 onu が届きました。ありがた過ぎ。まあこんなことをやる稀有な物好きは日本全国10人程度でしょう。

##### routeros
苦労したのは rb5009 に限っては富士通製の小型 onu であっても dhcpv6-pd が bound しない点で、リンクは上がってるにもかかわらずネゴシエーションで失敗している模様。以下のスクリプトで対応しました。
``` :routeros
/system script
add dont-require-permissions=no name=sfp_bound owner=admin policy=write source={
 /interface ethernet set sfp-sfpplus1 auto-negotiation=no speed=1G-baseT-half;
 :delay 1;
 /interface ethernet set sfp-sfpplus1 advertise=1G-baseX auto-negotiation=yes;
}
```
オートネゴを切って適当なリンクの上がらない speed を選択 → オートネゴ ＋ 1G-baseX とすることで bound します。ここまでの対応で髪の毛が100本くらいは抜けました。人柱って大変だな。

んで、/scheduler で起動時にスクリプトを設定。routeros が小型 onu を認識するまで10秒程度掛かります。あとは先人達の巷に転がってる情報で ds-lite は繋がります。[^3][^4]

``` :routeros
/system scheduler
add name=everytimeonreboot on-event=":delay 10;/system script run sfp_bound;" policy=write start-time=startup
```

なお WAN、LAN ブリッジさせた仮想ポート、特に mangle で mss を変更する必要も無く、物理ポートそのままを使用し、routeros のバージョン（7.19rc2）が上がったからか速度低下も見られずでした。

隙あらばヘッドショットをキメる、IX に近い距離に住居を構えなきゃならないゲーム狂でも無いので今のところ不満は無いです。

あと記憶ではトンネルのエンドポイントを指定する際に v6 のアドレスのどれかを直に指定されている記事が多く見られましたが、routeros では gw.transix.jp だけで大丈夫です。

```:routeros
/interface ipipv6
add dscp=0 !keepalive local-address=:: mtu=1472 name=ipipv6-dslite remote-address=gw.transix.jp
```

asterisk
---
これは簡単です。ただ巷に転がってる asterisk の情報は皆さん頭が良すぎるのか複雑過ぎて、私の適当なスポンジ脳の構想では端末に sip クライアントを入れて外との発信、着信が出来ればそれで良いのです。

というわけで、andrius/asterisk を起動する準備に取り掛かります。[^5]
container の使うインターフェースなんかは、mikrotik のサイトの pihole[^6] なんかを参考にすると良いです。

asterisk に必要なファイルは hosts、pjsip.conf、extensions.conf の３つです。acl は閉域網なので必要ないかなと思いましたが、必要であれば適宜追加してください。特にひかり電話以外の sip サーバとトンネル経由でドッキングするぜみたいな血気盛んな若者は、男らしさとは何かを考える前に acl の設定を入れて下さい。

hosts には asterisk が使用する sip ドメインの名前解決のためにアドレスを追加しています。これは dhcp で取得した dns に聞いても解決してくれないので、ヤマハのルータで取得していたアドレスを入れてます。どうやら ngn type onu1 ntt とかやると dhcp から降ってくる情報で、例によってヤマハじゃ onu 側のキャプチャが取れないので dhcp client option でリクエストするコード番号が分からない。フレッツの仕様書見れば載ってるかもしれません。（ありました、21でした）[^7]

``` :hosts
127.0.0.1     localhost
124.xxx.xxx.1 ntt-west.ne.jp # 追加
172.17.0.4    asterisk       # 追加
```
あとコンテナ内の hosts を確認したところ自ホストのアドレスが追加されていたので、vethに定義したコンテナのアドレスも渋々追加します。無くてもなんとかなりますが gethostbyname() のエラーが出て着信が遅いです。ちなみにコンテナ内の dns は pjsip が参照しておらず名前解決出来ませんでした。

pjsip の定義も用意します。
私は西に引っ越したので ntt-west.ne.jp ですが、東は east です。そんなの説明しなくても分かるか。
<details><summary>pjsip 設定例</summary>

``` :pjsip.conf
[global]
type = global
debug = no

[system]
type = system
disable_rport = yes

[hikari-tp]
type = transport
protocol = udp
bind = 0.0.0.0:5060
external_media_address = 124.xx.xx.1     ; sipサーバのv4アドレス
external_signaling_address = 124.xx.xx.1 ; sipサーバのv4アドレス
local_net = 10.1.1.0/24      ; 端末のあるプライベートネットワーク例
local_net = 172.24.3.0/16    ; 端末のあるプライベートネットワーク例

[hikari-dc]
type = aor
contact = sip:ntt-west.ne.jp

[hikari-dc]
type = identify
endpoint = hikari-dc
match = ntt-west.ne.jp

[hikari-dc]
type = registration
contact_user = xxxxxxxxxx     ; xxxはひかり電話の電話番号
transport = hikari-tp
expiration = 3600
fatal_retry_interval = 60
forbidden_retry_interval = 60
server_uri = sip:ntt-west.ne.jp
client_uri = sip:xxxxxxxxxx@ntt-west.ne.jp

[hikari-dc]
type = endpoint
transport = hikari-tp
context = default
dtmf_mode = inband
language = ja
disallow = all
allow = ulaw
rtp_symmetric = no
force_rport = no
rewrite_contact = no
direct_media = no
send_pai = yes
tos_audio = 0xb8
from_user = xxxxxxxxxx
from_domain = ntt-west.ne.jp
aors = hikari-dc

[101]
type = endpoint
transport = hikari-tp
context = ext
disallow = all
allow = ulaw
auth = 101
aors = 101
rewrite_contact = yes

[101]
type = auth
auth_type = userpass
password = 101
username = 101

[101]
type = aor
max_contacts = 10

[102]
type = endpoint
transport = hikari-tp
context = ext
disallow = all
allow = ulaw
auth = 102
aors = 102
rewrite_contact = yes

[102]
type = auth
auth_type = userpass
password = 102
username = 102

[102]
type = aor
max_contacts = 10
```

```:extensions.conf
[general]
writeprotect = no
priorityjumping = no

[globals]
PHONEALL = PJSIP/101&PJSIP/102 ;子機全部指定

[default]
exten => _X.,1,Dial(${PHONEALL},30,r)
exten => _X.,n,Hangup

[ext]
exten => _X.,1,Dial(PJSIP/${EXTEN}@hikari-dc)
exten => _X.,n,Hangup
```
</details>

ファイルが準備出来たらscpやwinboxで適当なディレクトリに転送し、リモートイメージからコンテナを起動します。
``` :routeros
/container config
set registry-url=https://registry-1.docker.io tmpdir=/pull
/container mounts
add dst=/etc/hosts name=asterisk_hosts src=/asterisk_conf/hosts
add dst=/etc/asterisk/pjsip.conf name=asterisk_pjsip_conf src=/asterisk_conf/pjsip.conf
add dst=/etc/asterisk/extensions.conf name=asterisk_ext_conf src=/asterisk_conf/extensions.conf
/container
add hostname=asterisk interface=veth3 logging=yes mounts=asterisk_pjsip_conf,asterisk_hosts,asterisk_ext_conf,asterisk_conf remote-image=andrius/asterisk:alpine-20.5.2 name=asterisk root-dir=asterisk start-on-boot=yes
```

これで nat 配下にある sip 端末は外部からの着信で全部が鳴るはず。あとは必要であれば voide mail なんかを入れたら良いかもです。

というわけで先人が苦労に苦労を重ねた知識を一つの箱に収めることが出来ました。

[^1]:NTT東日本 フレッツ光 小型ONU Wiki
[動作確認済機器一覧](https://wikiwiki.jp/fletssfponu/%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D%E6%B8%88%E6%A9%9F%E5%99%A8%E4%B8%80%E8%A6%A7)
[^2]: vender の情報が全て 000000000 となる
[^3]: NTT光ネクストのひかり電話へAsteriskを直接接続する
<https://qiita.com/kmorimoto/items/d99cd9edcf7436eea7cc>
[^4]: RouterOS Xpass 固定IPアドレス(ひかりクロス)の設定方法
<https://zenn.dev/revelation1048/articles/5fbd40d2251591>
[^5]: 7.4beta docker test: Install & run Asterisk 16.3 on hap ac2
<https://forum.mikrotik.com/viewtopic.php?t=187102>
[^6]: Running Pi-hole
<https://help.mikrotik.com/docs/spaces/ROS/pages/84901929/Container#Container-RunningPi-hole>
[^7]: 次世代ネットワークインタフェース資料（ＩＰ通信網）
<https://www.ntt-east.co.jp/info-st/mutial/ngn/ip_uni_1.0.pdf>