技術メモなど

ほぼ自分用の技術メモです。

Open IPv6 ダイナミックDNSとYAMAHA RTXルータを使って自宅から実家まで NGN 間 低遅延VPN の構築

昨年のことですが、実家のパソコンをリモートメンテナンスするためのVPNを刷新したときの話です。

旭川の自宅と岩見沢の実家はそれぞれNTTフレッツ光ネクスト回線を引いているので、以前からインターネットを経由せずともIPv6で所謂NGN網内折返しができる環境でした。しかし、自宅実家ともにプロバイダーから割り当てられるIPv6アドレスは半固定のため(自宅側IIJ、実家側OCN)、どちらかのIPv6アドレスが変わってしまったらVPNを張り直すために直接現地で作業する必要があり、旭川 - 岩見沢間は車で2時間程度の距離とはいえ、そう頻繁に行き来もできないことから、今までは次の構成でVPNを張っていました。

https://cacoo.com/diagrams/dAVBkJeHvZI9H54w-2DCC2.png

さくらのVPSが固定のIPv4/IPv6アドレスを持っているため、さくらのVPS上にSoftEther VPN Serverを建て、自宅のYAMAHA RTX 1200からSoftEther VPN Server間はIPSec over L2TPv3で接続、実家のパソコンにはSoftEther VPN Clientをインストールして接続という構成にしていました。SoftEther VPN Client側はIPアドレスが変動してもSoftEther VPN Server側のIPアドレスが固定であれば問題なくVPNが確立します。

この構成だと IP アドレスの半固定問題は解消されますが、さくらのVPSを介するため無駄な通信が生じてしまっている点と、実家側がクライアントソフトウェアによるVPN接続のため、実家の無線LANアクセスポイントやプリンターに直接リモートアクセスできない点(もちろん実家パソコンにルーティングテーブル設定するなりやりようはあるとは思います)が不満でした。

そんな中、NGN上でダイナミックDNSサービスを提供するOPEN IPv6 ダイナミック DNS for フレッツ・光ネクストが開始されたことを知り、あの登大遊氏が開発したサービスでこれは面白そうだと思っていたところに実家のパソコンがとうとう壊れてしまったとの連絡があり、新しいパソコンを母にプレゼントするついでに、中古のYAMAHA RTX810を買って実家に設置し、NGN網内折返しでIPv4 over IPv6VPN接続することにしました。

実家にRTX810を設置する作業は簡単に往復できる距離ではない以上一発勝負になるので、事前に自宅でRTX1200とRTX810をVPN接続できる状態にし、実家にRTX810を設置する際にプロバイダのPPPoE接続の設定のみ実家用の設定に書き換える方針としました。

まずはRTX810を入手後、既設RTX1200とRTX810をNTTからレンタルしているHGW(ひかり電話あり)のLANポートに並列で接続します。実家もひかり電話ありのHGWなので、WAN側のIPv6アドレスは自宅実家ともにDHCPv6 PDで割り当たるので、IPv6関係のコンフィグは実家に設置した後も変更する必要ありません。(設定はFAQ for YAMAHA RT Series / Flet'sを参照。)

自宅のHGWにRTXを2台並列にぶら下げることで2台それぞれにIPv6グローバルアドレスが割り当たるので、実は自宅環境だけでNGN経由のIPv4 over IPv6を試すことができるのです。注意点はDHCPv6 PDで委譲されるPrefixは先にHGWに接続した機器に若い番号から委譲されるみたいなので、自宅側ルータを先に接続してから実家側ルータを接続した方が、自宅側ルータのIPv6アドレスが変わらなくて良いと思います。

# LAN2をWAN側にした場合のIPv6接続に関する必要最低限のコンフィグを抜粋
ipv6 route default gateway dhcp lan2
ipv6 lan2 address dhcp
ipv6 lan2 dhcp service client
ngn type lan2 ntt

2台のRTXにIPv6グローバルアドレスが付与されたことが確認できたら、ダイナミックDNSのホスト名をゲットします。OPEN IPv6 ダイナミック DNS for フレッツ・光ネクストにアクセスし、お好みのホスト名 (hoge.i.open.ad.jp) を自宅用と実家用に2つ登録します。メールアドレスの登録は任意になっていますが、後で情報を確認するのに必要な「ホストキー」を再発行できるようメールアドレスは登録した方が良いです。

なお、ホストの登録により、NGN内だけでなく、インターネット上のDNSサーバからも取得したホスト名で名前解決できるようになりますので、インターネットリーチャビリティのあるIPv6接続サービスを利用している場合、IPv6インターネット経由で容易にアクセスできるようになることは理解して使用した方が良いです。つまり、セキュリティ設定に不備があるホストでこのサービスを利用するべきではありません。

ホスト名を取得したら、RTXにそれぞれ毎分ルータ自身のIPv6グローバルアドレスをダイナミックDNSサーバーに通知する設定を入れます。OPEN IPv6 ダイナミック DNS for フレッツ・光ネクストの「登録済みのホスト一覧」に表示される「更新専用ホスト名」を確認してコンフィグを投入してください。

# pingでなくても任意のパケットでOKらしいが設定例通りping6を毎分0秒に実施
schedule at 1 */* *:*:00 * lua -e \"rt.command(\\\"ping6 update-更新専用ホスト名.i.open.ad.jp\\\")\"

うまく行けばOPEN IPv6 ダイナミック DNS for フレッツ・光ネクストの「登録済みのホスト一覧」に2台のRTXのIPv6グローバルアドレスとそれに紐付いたホスト名が表示されます。なお、これが表示されなくなったら、DDNS ホストキーリストの編集 - OPEN IPv6 ダイナミック DNS for フレッツ・光ネクストにホストキーを貼り付けると再び表示されるようになります。

後はIPv4 over IPv6の設定をそれぞれのRTXに投入するだけです。ipsec local nameとipsec remote nameの箇所が自宅と実家で逆になるようになっていればOKです。

# 自宅側
# 実家側サブネット(ここでは192.168.20/24とする)へのルーティング
ip route 192.168.20.0/24 gateway tunnel 1
ip lan1 address 102.168.10.254/24
# IPSecの設定
tunnel select 1
ipsec tunnel 1
ipsec sa policy 1 1 esp aes-cbc
ipsec ike version 1 2
ipsec ike keepalive log 1 on
ipsec ike keepalive use 1 on rfc4306 10 6 0
ipsec ike local name 1 取得したホスト名(自宅).i.open.ad.jp fqdn
ipsec ike pre-shared-key 1 text 任意の事前共有キー
ipsec ike remote name 1 取得したホスト名(実家).i.open.ad.jp fqdn
ip tunnel tcp mss limit auto
tunnel enable 1
ipsec auto refresh on
# 実家側
# 自宅側サブネット(ここでは192.168.10/24とする)へのルーティング
ip route 192.168.10.0/24 gateway tunnel 1
ip lan1 address 102.168.20.254/24
# IPSecの設定
tunnel select 1
ipsec tunnel 1
ipsec sa policy 1 1 esp aes-cbc
ipsec ike version 1 2
ipsec ike keepalive log 1 on
ipsec ike keepalive use 1 on rfc4306 10 6 0
ipsec ike local name 1 取得したホスト名(実家).i.open.ad.jp fqdn
ipsec ike pre-shared-key 1 text 任意の事前共有キー
ipsec ike remote name 1 取得したホスト名(自宅).i.open.ad.jp fqdn
ip tunnel tcp mss limit auto
tunnel enable 1
ipsec auto refresh on

これで互いのRTXのプライベートIPアドレスのネットワークに通信が確認できれば、NGN上でのVPN接続に成功なので、後は実際にRTX810を実家に持って行ってひかり電話HGWの下にRTX810を接続するだけでVPNは確立しました。一通りVPNの疎通確認が終わったら、実家側RTX810は実家用のOCNのPPPoEの設定を投入して作業完了。NGN網内折返しで接続なので低遅延の高品質なVPNの完成です。

(ちなみに上に記載していませんが、実家側での通信環境は自宅側サブネット宛て以外全て実家側プロバイダーを使うようにしたいので、自宅側サブネット宛て以外の通信は全てIPv4はPPPoEへ、IPv6はLAN2へ向くようデフォルトゲートウェイの設定を入れています。)

IPv6グローバルアドレスはIPv4と違い潤沢に割り当ててもらえるおかげで、事前に自宅側で全て検証済ませてから実家で現地作業ができたので楽でした。(作業よりコロナ対策のためどこにも寄らず実家へ向かい入念に消毒する作業の方が大変でした。早くコロナが終息して欲しい。)

ちなみにルータの設定例は公式サイトに掲載されているものを使っています。YAMAHAだけじゃなく、Allied TelesisCiscoNECのルータでの設定例も掲載されているので簡単にできると思います。

i.open.ad.jp

最終的に自宅と実家間のVPNの構成は次の通りとなりました。

https://cacoo.com/diagrams/dAVBkJeHvZI9H54w-92A18.png

SoftEther VPN Serverもリモートアクセス用に引き続き稼働しています。SoftEther VPN プロジェクト - SoftEther VPN プロジェクトOPEN IPv6 ダイナミック DNS for フレッツ・光ネクストも本当に便利で、情熱大陸見た時も思いましたが登大遊さんは本当にすごい。Open IPv6 DDNSはこれを実現させる技術力と「けしからん」NTTを説得する交渉力も必要だったわけで、並大抵の苦労ではなかったと思います。とても感謝しています。

www.mbs.jp

避難場所検索Webサービスを書き直した(追記・AED設置場所検索も作った)

数年前に旭川市のオープンデータを使って近くの避難場所を検索するWebサービスを作っていたのだけど、地図と避難場所までの経路を表示するのに使っていた YOLP(地図):YOLP(地図) - Yahoo!デベロッパーネットワーク で経路検索APIの提供が2020年10月で終了してしまったので、これを機に、年末年始のステイホーム時間を使って一からWebサービスを作り直しました。

hinanbasho.herokuapp.com

位置情報を許可すれば、現在地から近い避難場所を検索できます。

基本はPython + Flask + PostgreSQL + Herokuで、地図の表示は OpenStreetMapLeaflet を使っています。本当は Leaflet Routing MachineOpenStreetMapで現在地から避難場所までの経路検索もページ内に表示させることができると思っていたのですが、OpenStreetMapは経路検索サーバを自前で建てないと駄目なようで、他のマップサービスは従量課金のサービスしか見つからず、経路検索は諦めることに。(無料枠の中で収まるとは思うけど、設定不備とかいたずらとかで課金されてしまうリスクを考えると趣味のWebサービスなのでちょっと……という。)

今回簡単なDOM操作のために素のJavaScriptを書いたのだけど、最近のフロントエンド全く分からない(というかWebの知識が20年前くらいで止まっている)ので、今年はReactとか勉強してみたいです。

2021/2/7追記

同じ仕組みでAED設置場所検索Webサービスも作ってみました。

ashaed.herokuapp.com

ゆるい勉強会@旭川→ゆるい勉強会@Webに参加した話

ゆるい勉強会@旭川に数年振りに参加することになりました。

asahikawa.connpass.com

きっかけはとみおさん (@tomio2480) に数年振りに会う、しかも職場で、という面白イベント発生したことによります。よっしゃ久しぶりに勉強会行ってみるかとなったのでした。

ちなみにとみおさんにはうちの今は中学生の息子が小1〜小2くらいの時、CoderDojo旭川で一緒にScratchとかでプログラミング教わったりしていて、また参加予定者の中には他にもCoderDojo旭川でメンターしてくれた加藤さん (@ykatombn) もいたので、楽しみにしていたのですが、新型コロナウイルスの関係で残念ながら一同に会すことはできず、Zoomを使ったオンラインでの勉強会となりました。

参加してみての感想は、

  • Zoom使いやすい、映像も音声も低遅延だから多対多でのコミュニケーションが思ってたよりも取りやすそう。(うちは休校で体力有り余っている中学生と小学生の子が自宅にいるためカメラとマイクはミュートで参加してたので、他の参加者のやり取りを見ての感想。)
  • ただ、発表者の方に「オンラインだと聞いている人達の反応が見えづらい」との意見もあり、やはり空気感、ライブ感はオフラインの方が上なのかなと。拍手ボタンとか、「おぉー」「へぇー」ボタンがあればいいのにと思った。
  • あとオフラインだと、自分が分からない分野の話でも気になったことを気軽に発表者に質問できるけど、オンラインだと「こんなこと聞いちゃっていいのかな?」と変に気になってしまい、チャットに書き込む前に手が止まってしまう自分がいたり。
  • とはいえスライドは見やすいし、何よりやはりIT技術の話は面白かった!

でした。

自分も今回大いに刺激を受けて、本当は発表とかしてみたかったんだけど(よわよわの非エンジニアだけど中学サッカー部の息子の試合の応援行くのにあったら便利だと思ってPython旭川サッカー協会のWebページをスクレイピングして試合日程を検索できるようにしたやつ (GitHub - takedah/afajycal) を作った話とか、その他仕事上の課題をPythonに助けてもらった話とか)、スライド作る時間が取れずROM専でした。

旭川は札幌ほどではないにせよ、高専あるし工業高校もあるし、少なくとも自分の出身の岩見沢始め他の市町村より環境が恵まれてると思うし、こうした活動を通じて旭川のITが盛り上がればいいなと思います。

CentOS 7 のインストール(ネットワーク設定編)

NEC Express5800 GT110e には Ethernet ネットワークインターフェースが2個あるため、802.3ad でボンディングして冗長化し、更にタグ VLAN をブリッジ接続できるようにします。CentOS 6 の頃は /etc/sysconfig/network-scripts 以下の設定ファイルを直接編集する必要がありましたが、CentOS 7からは全て nmcli コマンドで設定が可能でした。

設定は次の Web ページと全く同じ手順でできました。

enakai00.hatenablog.com

802.3ad + タグVLAN + ブリッジ接続の設定

ブリッジインタフェースの作成

# nmcli connection add type ifname br1
# nmcli connection add type bridge ifname br1
# nmcli connection bridge-br1 bridge.stp no
# nmcli connection modify bridge-br1 bridge.stp no
# nmcli connection modify bridge-br1 ipv4.method manual ipv4.address "192.0.2.1/24" ipv4.gateway "192.0.2.254"
# nmcli con modify bridge-br0 ipv6.method manual ipv6.address "2001:db8:beaf:14::1:1/64" ipv6.gateway "2001:db8:beaf:14::1"
# nmcli connection modify bridge-br1 ipv4.dns 198.51.100.2 ipv4.dns-search intra.example.com
# nmcli connection modify bridge-br1 ipv6.dns 2001:db8:feed:18::1:2 ipv6.dns-search intra.example.com
# nmcli connection modify bridge-br1 +ipv4.dns 198.51.100.3
# nmcli connection down bridge-br1
# nmcli connection up bridge-br1

ボンディングの作成

# nmcli connection add type bond ifname bond0 con-name bond-bond0 mode 4
# nmcli connection mod bond-bond0 ipv4.method disabled ipv6.method ignore
# nmcli connection add type bond-slave ifname eno1 con-name bond-slave-eno1 master bond0
# nmcli connection add type bond-slave ifname eno2 con-name bond-slave-eno2 master bond0
# nmcli connection down bond-slave-eno1
# nmcli connection down bond-slave-eno2
# nmcli connection down bond-bond0
# nmcli up bond-slave-eno0
# nmcli connection up bond-slave-eno0

VLAN インタフェースの作成

VLAN インタフェースを作成し、ブリッジインタフェースと接続します。

# nmcli connection add type vlan ifname vlan100 con-name vlan-vlan100 dev bond0 id 100
# nmcli connection modify vlan-vlan100 connection.master br1 connection.slave-type bridge
# nmcli connection down bond-slave-eno1
# nmcli connection down bond-slave-eno2
# nmcli connection down bond-bond0
# nmcli connection up bond-slave-eno1
# nmcli connection up bond-slave-eno2
# nmcli connection up bond-bond0
# nmcli connection down vlan-vlan100
# nmcli connection up vlan-vlan100

CentOS 7 をインストール(シリアルコンソールの設定編)

もう CentOS 8 がリリースされたというのに、OS が CentOS 6 のままな自宅サーバーをようやく CentOS 7 に移行することにしました。ちなみに自宅サーバーのハードウェアは2013年頃に購入した NEC Express5800 GT110e です。この機種、オンボードRAID コントローラー (LSI embedded Megaraid) を搭載していますが、残念ながら Broadcom の Web サイトには SAS のドライバーしか置いておらず、NEC の Web サイトにも Windows 用のドライバーしかないので、CentOS では使えません。最近買ったものなら Express Builder の中に入ってるのかな?

OS のインストール

詳細は割愛。CentOS 7 (Minimum) の ISO イメージをダウンロードして適当な USB リムーバブルストレージに dd コマンドで書き込み、インストールメディアを作成→自宅サーバーの BIOS の設定を変更して USB リムーバブルストレージから起動するようにすればグラフィカルなインストーラーが起動するので、特に迷うことなくインストールできると思います。タイムゾーンやキーボードレイアウト、ホスト名、ディスクパーティションあたりはインストーラーで設定するのが楽かと思います。

シリアルコンソールの設定

NEC Express5800 GT110e はちゃんと BMC が搭載されているため、SSH からシリアルコンソールにアクセスできるので、BMC の管理用ネットワークインターフェースに正しく IP アドレスを振りさえすれば以降の作業はディスプレイもキーボードも接続せずにすることができます。

これを使うためには CentOS 7 でシリアルコンソールを使えるように設定する必要があります。具体的には、GRUB2 の設定を変更し、OS 起動時にシリアルコンソール用仮想端末が上がるようにします。

# sed -i 'GRUB_TERMINAL_OUTPUT="console"/GRUB_TERMINAL_OUTPUT="serial console"/' /etc/default/grub
# sed -i '/^GRUB_CMDLINE_LINUX=/s/$/ console=tty0 console=ttyS0,9600 console=ttyS1,9600"/' /etc/default/grub
# echo 'GRUB_TERMINAL="console serial"' >> /ect/default/grub
# echo 'GRUB_SERIAL_COMMAND="serial --speed=9600 --unit=0 --word=8 --parity=no --stop=1"' >> /etc/default/grub
# grub2-mkconfig -o /boot/grub2/grub.cfg

serial 端末を OS 起動時に起動できるようにし、再起動すればシリアルコンソールの設定完了。

# cp /lib/systemd/system/serial-getty\@.service /etc/systemd/system/serial-getty@ttyS1.service
# ln -s /etc/systemd/system/serial-getty\@ttyS1.service /etc/systemd/system/getty.target.wants/
# systemctl daemon-reload
# systemctl start serial-getty@ttyS1.service
# systemctl enable serial-getty@ttyS1.service
# shutdown -r now

設定は次の Web ページを参考にしました。

www.nightmare-yk.com

Ubuntu 16.04 LTSでSoftether VPN Clientを使う

ノートPCで実家から自宅にVPN接続しようと思ったら、ノートPCのOSをUbuntu 14.04 LTSから16.04 LTSにアップグレードした時に、VPN接続用のシェルスクリプトを消してしまっていたことに気付き、VPN接続できるようになるまで手こずったため、手順をメモ。なお、Softethr VPN Serverの設定は事前に済んでいることが前提です。

Softether VPN Clientのインストール

Softether VPNの公式サイトにVPN ClientのLinuxへのインストール手順がないのですが、VPN Serverのインストール手順はあり、serverの箇所を全てclientに書き換えるだけでVPN Clientのインストールができます。

7.3 Linux へのインストールと初期設定 - SoftEther VPN プロジェクト

VPN Clientの設定

上記公式サイトを参考に、クライアント側でvpncmdを起動します。

NicCreateコマンドで仮想LANカードを作成し、AccountCreateコマンド、AccountPasswordSetで接続先を設定。最後にサービスモードのVPN Clientを起動した時に自動でVPN接続を開始するよう*AccountStartupSetコマンドを設定します。詳細は公式サイトのコマンドリファレンス参照。

6.5 VPN Client の管理コマンドリファレンス - SoftEther VPN プロジェクト

なお、仮想LANカードを作成する際に指定した名前は、VPN接続時のUbuntuのインターフェース名に使用されます。例えば仮想LANカードの名前を「tun0」にした場合、Ubuntuのインターフェース名は「vpn_tun0」となります。このインターフェース名は後でIPアドレスを設定する際に使用することになります。

VPN接続の開始

VPN Clientのサービス起動

上記までの手順が完了したら、次のコマンドでVPN Clientサービスを開始します。

/etc/init.d/vpnclient start

ip addrコマンドでvpn_仮想LANカード名のインターフェースが表示されることを確認します。また、このインターフェースにIPアドレスが設定されていないことが分かるため、次の手順でIPアドレスを設定します。

IPアドレス・ルーティングの設定

当初DHCPIPアドレスを割り当てようとdhclientコマンドを試したのですが、。どうもVPN Clientで作成された仮想のインターフェースにdhclientコマンドでのIPアドレス割当はできないっぽいです。そこで、別のコマンドで固定IPアドレスを割り当てることにします。

IPアドレスの割当と一緒にDNSのアドレスも設定したいのでnmcliコマンドを試したのですが、これも何故かうまく行かないため、ipコマンドで設定することにしました。

以下固定IPアドレスを192.168.1.1、サブネットマスクを255.255.255.0、仮想LANカード名をtun0とした場合の例です。また、VPN接続先のLANに192.168.0.0/16のネットワークがあり、そこへのゲートウェイが192.168.1.254とします。

ip address add 192.168.1.1/24 brd 192.168.1.255 dev vpn_tun0
ip route add 192.168.0.0/16 via 192.168.1.254 dev vpn_tun0

DNSゾルバの設定

nmcliが使えないため、邪道ですが直接/etc/resolv.confファイルを書き換えることとします。後述しますが、VPN接続を切断した際には必ず/etc/resolv.confを元に戻す必要があります。

以下参照するDNSサーバのアドレスを192.168.0.1とした場合の例です。

sed -i -e "s/127\.0\.1\.1/192.168.0.1/g" /etc/resolv.conf

以上でVPN接続してネットワーク接続するまでの手順は完了です。

VPN接続の切断

VPN Clientサービスの終了

VPN Clientサービスを止めることで、作成されていた仮想のインターフェースは削除されます。

/etc/init.d/vpnclient stop

DNSゾルバの復元

/etc/resolv.confを元に戻します。なお、後述するNetworkManagerの再起動の際に自動で元に戻るのですが、念の為先に手動で元に戻しておくものです。

sed -i -e "s/192\.168\.0\.1/127.0.1.1/g" /etc/resolv.conf

NetworkManagerの再起動

最後に念の為ネットワークの設定をリセットします。

systemctl restart NetworkManager.service

以上でVPN接続の切断は完了です。

これらの手順をシェルスクリプトにまとめておくと便利です。が、間違えてシェルスクリプトを無くしてしまったときに苦労するので注意ですね。

Rubyでひらがなカタカナをヘボン式ローマ字に変換する

業務で大量の人名の読み仮名データ(しかも半角カタカナ)をヘボン式ローマ字に変換しなくてはならなくなったので、Rubyでひらがなカタカナをヘボン式ローマ字に変換するライブラリを作成してみました。

github.com

個人的には訓令式の方が読みやすくて好きなのですが……。