カテゴリー「未分類」の記事

ドアスコープモニターを作る (4) 保護編

2018年6月17日 / 未分類

これまでのあらすじ

ちまちまと続けてるんじゃ。

本題

Raspberry Pi Zero W、カメラ、DCDCコンバータと基板むき出し×3だったので何とかした。

Raspberry Pi Zero WのはAmazonで見つけた。
他のアクリルケースとかだと側面空いてたりしたけど、これは側面も覆ってくれるのでいい感じ。
GPIO部分が開いているのはしょうがない。今のところGPIO使う予定ないけど放熱のことも考えてこのまま。

カメラのはスイッチサイエンスのカメラケース(の後ろ部分)
左右の穴にM3のナット接着してM3ネジを通し、先端にネオジム磁石接着することで4本足で扉に張り付く形に。
位置の微調整がとてもやりやすくなった。ネジを回すことで高さも微調整可能。

DCDCコンバータには単一電池ボックスがちょうどいいサイズだった。
柔らかいので穴あけも簡単。ドリルで穴開けた後、木ネジで広げたりデザインナイフで削ったりした。
コンバータにスペーサー立ててケースかぶせてネジで止めて終了。

これまでカメラ位置の微調整に手こずってケーブルに力がかかり、抜けてしまう(Raspi側の固定具が壊れて引っ張ると抜けやすくなってるため)という事故が多発していたため、長いのに交換していたが、微調整が楽になったので短いのに戻そうかな。
そして全部まとめて上から箱を被せたい。DCDCコンバータのケース意味なかったじゃん、ってなるけど。
サイズ的には150x100x30でぴったり収まるので、それより少し大きめあたり。
ホームセンターで使えそうな箱とか探してみたけど、底面を表に出すことになるもんだから、見た目が残念になるものばかりで困った。
急ぐものじゃないので気が向いたときにいろいろ探してみよう。

ドアスコープモニターを作る (3) 挫折編

2018年6月10日 / 未分類

作ろうとしているものと同じコンセプトでより高機能な製品があった。

チャイム音を録音しておいて、同じチャイムをトリガーに動く、というところがまったく一緒で、あちらはスマホ連携して音声通話もできる。
ドアスコープから見るわけじゃないので絵もしょぼくないし、カメラは防水だし、自作するより安いし(Amazonで17,000円弱)、いいことづくめじゃないか。
無理にこちらの利点を挙げるなら、電池交換の必要がない(配線しなきゃならんけど)、設置の制限が緩い(ドアスコープさえあればいい)、くらいか。

いや、必要な機材は買っちゃったし作ってみるよ。
作る過程が楽しいのだ。

ドアスコープモニターを作る (2) 不安定編

2018年6月10日 / 未分類

これまでのあらすじ

カメラ壊した。

本題

新しいカメラ買ってきて電源線引き回してドアに設置したのがこちら。

Raspberry Pi Zero WHは裏にスペーサー挟んでアルミプレートを付け、プレートにマグネット貼り付けてドアに設置。
カメラはひっつき虫でドアスコープのところに固定。

右にあるのは秋月のDCDCコンバータ。こちらもマグネットで付けている。
必要な電源線の長さを計ったら6m超えていて、USBケーブルでは5m超のものはないのと、電圧降下が怖かったので12VのACアダプターから引っ張ってきて直前で5Vにすることにした。

通信はRaspberry Pi Zero WHについている無線LANインタフェースを使用。
この状態で撮影して転送したり、mjpg-streamer使ってストリーミングさせたりとやっていると、通信が不安定であることに気づいた。
そこで、iperfで計ってみた。

tkito@raspi-camera:~ $ iperf -c 192.168.100.101 -t 100 -i 2
------------------------------------------------------------
Client connecting to 192.168.100.101, TCP port 5001
TCP window size: 43.8 KByte (default)
------------------------------------------------------------
[ 3] local 192.168.100.102 port 39072 connected with 192.168.100.101 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 2.0 sec 512 KBytes 2.10 Mbits/sec
[ 3] 2.0- 4.0 sec 1.12 MBytes 4.72 Mbits/sec
[ 3] 4.0- 6.0 sec 512 KBytes 2.10 Mbits/sec
[ 3] 6.0- 8.0 sec 1.62 MBytes 6.82 Mbits/sec
[ 3] 8.0-10.0 sec 430 KBytes 1.76 Mbits/sec
[ 3] 10.0-12.0 sec 5.66 KBytes 23.2 Kbits/sec
[ 3] 12.0-14.0 sec 4.24 KBytes 17.4 Kbits/sec
[ 3] 14.0-16.0 sec 1.41 KBytes 5.79 Kbits/sec
[ 3] 16.0-18.0 sec 1.41 KBytes 5.79 Kbits/sec
[ 3] 18.0-20.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 20.0-22.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 22.0-24.0 sec 1.41 KBytes 5.79 Kbits/sec
[ 3] 24.0-26.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 26.0-28.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 28.0-30.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 30.0-32.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 32.0-34.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 34.0-36.0 sec 2.83 KBytes 11.6 Kbits/sec
[ 3] 36.0-38.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 38.0-40.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 40.0-42.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 42.0-44.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 44.0-46.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 46.0-48.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 48.0-50.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 50.0-52.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 52.0-54.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 54.0-56.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 56.0-58.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 58.0-60.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 60.0-62.0 sec 1.41 KBytes 5.79 Kbits/sec
[ 3] 62.0-64.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 64.0-66.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 66.0-68.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 68.0-70.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 70.0-72.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 72.0-74.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 74.0-76.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 76.0-78.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 78.0-80.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 80.0-82.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 82.0-84.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 84.0-86.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 86.0-88.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 88.0-90.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 90.0-92.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 92.0-94.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 94.0-96.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 96.0-98.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 98.0-100.0 sec 0.00 Bytes 0.00 bits/sec
[ 3] 0.0-100.6 sec 4.19 MBytes 349 Kbits/sec

(敢えて酷いのを選んではいるけれど)これはひどい。
ちなみにサーバ側は別のRaspberry Pi。

いろいろと試行錯誤してみたところ、ドアから15cmほど離したところでやると25Mbpsくらいの安定した測定結果を得られた。
ドアのごく近くに置いてある、というのが悪いのだろう。
適当な箱でも買ってきてドアから離した形で据え付けることにしよう。

続きはいつになることやら…

余談

ドアに密着している状態でもiperfのサーバ側になった場合は十分な速度が出ることを確認した。

tkito@raspi-fancon:~ $ iperf -c 192.168.100.102 -t 100 -i 2
------------------------------------------------------------
Client connecting to 192.168.100.102, TCP port 5001
TCP window size: 43.8 KByte (default)
------------------------------------------------------------
[ 3] local 192.168.100.101 port 57936 connected with 192.168.100.102 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 2.0 sec 2.88 MBytes 12.1 Mbits/sec
[ 3] 2.0- 4.0 sec 6.12 MBytes 25.7 Mbits/sec
[ 3] 4.0- 6.0 sec 3.62 MBytes 15.2 Mbits/sec
[ 3] 6.0- 8.0 sec 4.38 MBytes 18.4 Mbits/sec
[ 3] 8.0-10.0 sec 3.12 MBytes 13.1 Mbits/sec
[ 3] 10.0-12.0 sec 3.88 MBytes 16.3 Mbits/sec
[ 3] 12.0-14.0 sec 3.38 MBytes 14.2 Mbits/sec
[ 3] 14.0-16.0 sec 5.38 MBytes 22.5 Mbits/sec
[ 3] 16.0-18.0 sec 6.00 MBytes 25.2 Mbits/sec
[ 3] 18.0-20.0 sec 6.00 MBytes 25.2 Mbits/sec
[ 3] 20.0-22.0 sec 4.88 MBytes 20.4 Mbits/sec
[ 3] 22.0-24.0 sec 6.12 MBytes 25.7 Mbits/sec
[ 3] 24.0-26.0 sec 5.62 MBytes 23.6 Mbits/sec
[ 3] 26.0-28.0 sec 7.88 MBytes 33.0 Mbits/sec
[ 3] 28.0-30.0 sec 6.50 MBytes 27.3 Mbits/sec
[ 3] 30.0-32.0 sec 8.12 MBytes 34.1 Mbits/sec
[ 3] 32.0-34.0 sec 8.12 MBytes 34.1 Mbits/sec
[ 3] 34.0-36.0 sec 7.50 MBytes 31.5 Mbits/sec
[ 3] 36.0-38.0 sec 6.25 MBytes 26.2 Mbits/sec
[ 3] 38.0-40.0 sec 6.12 MBytes 25.7 Mbits/sec
[ 3] 40.0-42.0 sec 3.38 MBytes 14.2 Mbits/sec
[ 3] 42.0-44.0 sec 6.88 MBytes 28.8 Mbits/sec
[ 3] 44.0-46.0 sec 7.00 MBytes 29.4 Mbits/sec
[ 3] 46.0-48.0 sec 7.00 MBytes 29.4 Mbits/sec
[ 3] 48.0-50.0 sec 7.62 MBytes 32.0 Mbits/sec
[ 3] 50.0-52.0 sec 7.50 MBytes 31.5 Mbits/sec
[ 3] 52.0-54.0 sec 7.75 MBytes 32.5 Mbits/sec
[ 3] 54.0-56.0 sec 7.50 MBytes 31.5 Mbits/sec
[ 3] 56.0-58.0 sec 9.88 MBytes 41.4 Mbits/sec
[ 3] 58.0-60.0 sec 9.50 MBytes 39.8 Mbits/sec
[ 3] 60.0-62.0 sec 8.88 MBytes 37.2 Mbits/sec
[ 3] 62.0-64.0 sec 9.88 MBytes 41.4 Mbits/sec
[ 3] 64.0-66.0 sec 10.2 MBytes 43.0 Mbits/sec
[ 3] 66.0-68.0 sec 10.4 MBytes 43.5 Mbits/sec
[ 3] 68.0-70.0 sec 10.2 MBytes 43.0 Mbits/sec
[ 3] 70.0-72.0 sec 10.4 MBytes 43.5 Mbits/sec
[ 3] 72.0-74.0 sec 10.2 MBytes 43.0 Mbits/sec
[ 3] 74.0-76.0 sec 10.5 MBytes 44.0 Mbits/sec
[ 3] 76.0-78.0 sec 6.62 MBytes 27.8 Mbits/sec
[ 3] 78.0-80.0 sec 4.00 MBytes 16.8 Mbits/sec
[ 3] 80.0-82.0 sec 6.88 MBytes 28.8 Mbits/sec
[ 3] 82.0-84.0 sec 4.88 MBytes 20.4 Mbits/sec
[ 3] 84.0-86.0 sec 5.25 MBytes 22.0 Mbits/sec
[ 3] 86.0-88.0 sec 6.75 MBytes 28.3 Mbits/sec
[ 3] 88.0-90.0 sec 7.38 MBytes 30.9 Mbits/sec
[ 3] 90.0-92.0 sec 7.50 MBytes 31.5 Mbits/sec
[ 3] 92.0-94.0 sec 7.00 MBytes 29.4 Mbits/sec
[ 3] 94.0-96.0 sec 7.00 MBytes 29.4 Mbits/sec
[ 3] 96.0-98.0 sec 7.00 MBytes 29.4 Mbits/sec
[ 3] 98.0-100.0 sec 7.38 MBytes 30.9 Mbits/sec
[ 3] 0.0-100.0 sec 344 MBytes 28.9 Mbits/sec

送受信するパケットを考えると、受信はできるがパケット長の長いパケットの送信に難がありそうなことが推測できる。
実際、クライアント側として動かしたときも、「0.00 bits/sec」の情報自体はちゃんと定期的に送信されてきていた。こちらも無線LAN経由であることに変わりはないのに。

ドアスコープモニターを作る (1) 破壊編

2018年6月10日 / 未分類

新聞勧誘で嫌な思いしたことがあるので、基本的に在宅中にチャイムが鳴っても出ない。
宅配便や出前など、来ることが分かっている場合は出るけれど、たまに忘れててスルーした後に不在票投函の音で気づくが時すでに遅し、ということがある。
こんな時ドアモニターがあればいいのにな、と思う。

以前住んでいたところにはついていた。今のところにはついていない。
同じマンションの空き部屋のインターフォンがモニタ付きになっていたりするので順次取り換えてはいるようだが、配線作業の問題から、人が住んでいる間には取り換えられないのではと思っている。

ドアスコープモニターという商品は存在している。

ドアスコープにマグネットでつけるだけ、無線で飛ばして手元で確認できる。
なんかもう、これでいいんじゃないかな、といった趣だが違う、違うのだよ。
チャイムが鳴った時に反応して自動で表示してほしいじゃん、外出中に来客があった時に通知して画像確認とかしたいじゃん!
友達が来ることなんてないから気にしないでいいだろとか言うなよ悲しいじゃん!

というわけで自作することにした私は、Raspberry Pi Zero WHとRaspberry Piカメラモジュールv2その他を注文したのである。
ありがとうみんなの味方、秋月。

Raspberry Piカメラモジュールv2にはフォーカス調整冶具がついていて、フォーカス調整ができる。
時計回りに回すと遠方にフォーカスがあたって、反時計回りに回すと近方になるらしい。
面白がって反時計回りに回してたらレンズがポロっと外れてしまった。そりゃそうだよね。
慌ててレンズを付け直し、カメラの画像を見てみたところ…

何か割れた感じに。
ライト周辺の天井を写しているだけで、ライトと天井以外のものはない。
レンズが外れて落ちた時に壊れたのか、付け直した時にきつく締めすぎたのか、何にしろ明らかに壊れている。
こうしてカメラ1つをお釈迦にしてしまった私は、急遽秋葉原へと旅立ち、新しいカメラを調達してきたのであった。

続く。

自力でIPv4 over IPv6をした(Tunnel編)

2018年5月29日 / 未分類

これまでのあらすじ

やめて!So-netのサービス変更で、MAP-Eなv6プラスを適用されたら、DS-liteでIPv4ネットワークと繋がってるRTX1200の精神まで燃え尽きちゃう!
お願い、死なないで城之内!あんたが今ここで倒れたら、舞さんや遊戯との約束はどうなっちゃうの? ライフはまだ残ってる。ここを耐えれば、マリクに勝てるんだから!
次回、「RTX1200死す」。デュエルスタンバイ!

VPSを利用した自力IPv4 over IPv6

夕方から夜のPPPoE経由の通信が遅いなら、プロバイダの提供するIPv4 over IPv6が使い物にならないなら、自力でやってしまえばいいじゃない、ということでやってみた。
自宅とVPSとの間にIPv6でトンネル張って、その中にIPv4の通信を通すのである。
VPSのOSはUbuntu 18.04、自宅のルータはYAMAHA RTX1200。

とはいえ、本当に自力で1からやれるほどLinuxの仕組みに詳しいわけではないので、やはり先人の知恵にすがるわけである。

やることは以下の4つ。

  • トンネルデバイスの作成とルーティング設定
  • カーネルパラメータの設定
  • ファイアウォールの設定
  • RTX1200の設定

これらを、Ubuntuの流儀(systemd)に従って実施する。

トンネルデバイスの作成とルーティング設定

/etc/systemd/network 以下に.netdevファイルを置くとデバイスが作られ、.networkファイルでネットワークの設定ができる。

[NetDev]
Name=tun0
Kind=ip6tnl

[Tunnel]
Mode=ipip6
Local=【VPSのIPv6アドレス】
Remote=【ルータのIPv6アドレス】
EncapsulationLimit=none

最後の1行(EncapsulationLimit=none)が非常に重要(後述)

[Match]
Name=tun0

[Route]
Destination=【自宅側のネットワーク】
Scope=link
[Match]
Name=ens3

[Network]
Address=【VPSのIPv4アドレス】
Gateway=【VPSのIPv4ゲートウェイ】
DNS=【VPSのIPv4 DNSサーバ(1)】
DNS=【VPSのIPv4 DNSサーバ(2)】
Address=【VPSのIPv6アドレス】
Gateway=【VPSのIPv6ゲートウェイ】
DNS=【VPSのIPv6 DNSサーバ】
Tunnel=tun0

本当は「Tunnel=tun0」だけで済ませたかったのだが、その場合なぜかnetplanの設定が無視される(Name=ens3にマッチしたからこちらが優先された?)ので、やむなくIPv4/v6アドレス等を記載している。

カーネルパラメータの設定

IPv4パケットのフォワーディングを有効にし、各インタフェースのrp filterを無効にする。
rp filterが有効な場合、インターフェースと無関係なアドレス情報を持ったパケットが破棄されてしまうらしい。
今回tun0にはIPアドレスを振っていないため、パケットを破棄されないために無効にする。
ens3でも無効にしているがこれは元文献がそうしていたので同じようにしている。
rp filterを有効にした場合に本当に破棄されてしまうのか、検証はしていない。

net.ipv4.conf.all.forwarding=1
net.ipv4.conf.ens3.rp_filter=0
net.ipv4.conf.tun0.rp_filter=0
net.nf_conntrack_max=65535

ファイアウォールの設定

iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -F
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
ip6tables -A INPUT -s 【自宅のIPv6ネットワーク】 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -j ACCEPT

IPv6ではICMPv6が重要な役割を占めていて、周辺情報等がICMPv6でやり取りされているので通してやらないと通信できなくなるので注意。
22番ポートは自宅以外からもアクセスすることを想定して公開。
これらを設定した後、iptables-persistentパッケージを導入して設定を固定。
iptables-persistentパッケージインストール後にファイアウォールの設定を変えてそれを反映させたい場合には以下のコマンドで。

dpkg-reconfigure iptables-persistent

このパッケージ、やってることはip6?tables-saveとip6?tables-restoreなのでそれでできる人はそれでも構わない。

RTX1200の設定

VPSとの間にトンネル作ってIPv4パケットはそちらに流すように設定するだけ

tunnel select 1
 tunnel encapsulation ipip
 tunnel endpoint address 【VPSのIPv6アドレス】
 ip tunnel tcp mss limit auto
 tunnel enable 1
ip route default gateway tunnel 1

EncapsulationLimitの罠

当初、/etc/sytemd/network/01-tun0.netdevの最後の「EncapsulationLimit=none」の行は入れてなかった。
だがその状態だとトンネル経由の通信がうまくいかない。パケットは出ていくが戻りがない。
VPS側で見てみるとパケットは投げ返しているようだったので、ルータで何かが起きていると思ってルータのログを見てみた。

[IPv6] received malformed option from 【VPSのIPv6アドレス】
[IPv6] received malformed option from 【VPSのIPv6アドレス】 
[IPv6] received malformed option from 【VPSのIPv6アドレス】 
...

 

パケットが変だと言われている。VPSでキャプチャしてみた結果がこちら。
8.8.8.8に対するpingとその応答。192.168.100.4は自宅マシン。

表示されているのはルータで破棄される定めの応答パケット。
IPv6ヘッダ内のNext HeaderがDestination Options for IPv6 (60)となっており、Tunnel Encapsulation Limitの情報が含まれていることがわかる。
そしてその中のNext HeaderはIPIP (4)で、IPヘッダが続くことを示している。
ping送信のパケットはDestination Options for IPv6 (60)はなく、IPv6ヘッダ内のNext HeaderはIPIP (4)となっていた。
IPパケットのカプセル化は入れ子が可能であり、Tunnel Encapsulation Limitはその上限を表している(参考:RFC2473)。
上限を示すためにこのオプションがあるのだが、残念なことにRTX1200ではこれをmalformedとして扱ってしまうようだ。

調べてみると、このオプションがついているパケットを検出するIPSシグネチャがあるようだ。

デフォルトではオフなようだが、RFC2473で規定されている通常のパケットを検出するとかお前は何を言っているんだ(RTX1200もだが)。

閑話休題。
LinuxのトンネルデバイスではTunnel Encapsulation Limitのデフォルト値がRFCで推奨されている4となっている。
これをnoneにすることで受信したパケットに前述のオプションがついていない場合は戻りパケットにもつけないようにできる。
この設定をすることにより、トンネルが正常に機能するようになった。

おわりに

PPPoEを経由しないと速くて快適である。みんなも早くこっちにおいでよ。

おわび

次回に予定していたIPsec編は、IPsecでのトンネルがうまく作れないため無期限延期となります。

YAMAHA RTX1200でMAP-Eした(けどやめた)

2018年5月28日 / 未分類

事の始まり

So-netでIPoE(IPv6)オプションを利用していたのだが、先日こんなお知らせが届いた。

v6プラスはJPNEが提供するサービスで、IPv4 over IPv6の技術としてはMAP-Eを使っている模様。
IPoE(IPv6)オプションを利用していた時は(公式には情報は何もなかったが)DS-liteでmfeedと繋げてIPv4 over IPv6をすることができた。
今回、方式が変わるのでその対応をしてみた、という話である。
使用機器はYAMAHAのRTX1200。

YAMAHA RTX1200でMAP-E

といっても先人がいろいろと情報を出してくれている。

基本は上記ページの通りにすればよい。
ただ、自身に割り振られたIPv6アドレスによってゲートウェイのアドレス、利用可能なポート番号が変わるのでそこは注意しないといけない。
このあたりの詳細は下記ページに書いてある。

これでIPv6アドレスから各種パラメータを導き出すことが可能になったのだが、割り振られたIPv6アドレスが変わったりするとまたパラメータを導出しなくてはならない。
恐らくIPv6アドレスが変わることはないだろうとは思うが、変わらない保証はない。
変わるたびに手動で導出するのは面倒だったので、割り振られたIPv6ネットワークを引数で与えるとRTX1200のMAP-E関連の設定を出力してくれるスクリプトを作成した。
MAP-Eの仕様については下記資料を参考にした。

スクリプトはこちら。PSIDオフセットとEAビット長は現在の状況からの推測。

#!/usr/bin/python3
# -*- coding: utf-8 -*-

#########################################
# RTX1200用MAP-EのNAT設定出力スクリプト #
#########################################

import sys
from ipaddress import *

ra_net = IPv6Network(sys.argv[1])

## RTXの設定用
# NAT Descriptor番号の開始番号
ndesc = 600000

# Tunnelの番号
tunnel = 1

# 指定可能なポート範囲の個数
# see: http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/nat/nat_descriptor_masquerade_port_range.html
max_portrange_num = 3

## MAP-Eのパラメータ
# Port-set ID Offset
psid_offset = 4

# BRのIPv6アドレス
br_ipv6_addr = IPv6Address("2404:9200:225:100::64")

# Mapping Rule Tableの情報
# (rule_ipv6_prefix, rule_ipv4_prefix, ea_bits_length)
map_rule = [
    ( IPv6Network("240b:10::/31"),  IPv4Network("106.72.0.0/15"), 25 ),
    ( IPv6Network("240b:12::/31"),  IPv4Network("14.8.0.0/15"),   25 ),
    ( IPv6Network("240b:250::/31"), IPv4Network("14.10.0.0/15"),  25 ),
    ( IPv6Network("240b:252::/31"), IPv4Network("14.12.0.0/15"),  25 ),
]

rule_v6_net = None
rule_v4_net = None
ea_bits_len = None

# Mapping Rule Tableとのマッチング
for rule in map_rule:
    if ra_net[0] in rule[0]:
        rule_v6_net = rule[0]
        rule_v4_net = rule[1]
        ea_bits_len = rule[2]
        break

if rule_v6_net is None:
    print("No matched rules.")

# MAP-E IPv4アドレス、CE IPv6アドレス、PSIDの算出
ea_bits = (int(ra_net[0]) >> (128 - rule_v6_net.prefixlen - ea_bits_len)) & \
          ((1 << ea_bits_len) - 1) psid_len = ea_bits_len - (32 - rule_v4_net.prefixlen) v4_suffix = ea_bits >> psid_len
map_ipv4_addr = rule_v4_net[0] + v4_suffix
psid = ea_bits & ((1 << psid_len) - 1)
ce_ipv6_addr = ra_net[0] + (int(map_ipv4_addr) << 24) + (psid << 8)

# Port-setの算出
portset = []
prefix_len = 16 - (psid_len + psid_offset)
for i in range(1, 2 ** prefix_len):
    port_min = (i << (psid_len + psid_offset)) + (psid << psid_offset)
    port_max = port_min + 2 ** psid_offset - 1
    portset.append((port_min, port_max))

# output config
descs = []
for i in range(int(len(portset) / max_portrange_num) + 1):
    if i * max_portrange_num == len(portset):
        break

    start_i = i * max_portrange_num
    end_i = start_i + max_portrange_num

    print("nat descriptor type %d masquerade" % ndesc)
    print("nat descriptor address outer %d %s" % (ndesc, str(map_ipv4_addr)))
    print("nat descriptor address inner %d auto" % ndesc)
    print("nat descriptor masquerade port range %d %s" % \
          (ndesc, \
           " ".join(map(lambda x: "-".join(map(str, x)), portset[start_i:end_i]))))
    print("nat descriptor timer %d 600" % ndesc)
    print("nat descriptor timer %d tcpfin 30" % ndesc)
    descs.append(ndesc)
    ndesc += 1

print("tunnel select %d" % tunnel)
print("tunnel encapsulation ipip")
print("tunnel endpoint address %s %s" % (ce_ipv6_addr, br_ipv6_addr))
print("ip tunnel nat descriptor %s" % " ".join(map(str, descs)))

これの出力を使ってMAP-EによるIPv4 over IPv6の実現はできたのだが、Webサイトを見ていると結構な確率で応答が遅かったりタイムアウトしたりしていた。
原因はポートの枯渇であると容易に推測できた。何せ240個しかIPマスカレードに使えるポートがないのである。OSやらアプリやらWebサイトやらが裏でいろいろなところに繋いでいる昨今ではすぐなくなっても仕方がない。
RTX1200にログインして確認してみると、IPマスカレードの状況はこんな感じだった。

> show nat descriptor masquerade port summary 
Interface Desc Num Outer Address Used / All
------------------- ---------- --------------------------- -----------
PP[01](1) 1 ipcp/aaa.bbb.ccc.ddd 3/20000
TUNNEL[1](1) 600000 xxx.yyy.zzz.www 48/ 48
TUNNEL[1](2) 600001 xxx.yyy.zzz.www 48/ 48
TUNNEL[1](3) 600002 xxx.yyy.zzz.www 48/ 48
TUNNEL[1](4) 600003 xxx.yyy.zzz.www 48/ 48
TUNNEL[1](5) 600004 xxx.yyy.zzz.www 48/ 48
------------------- ---------- --------------------------- -----------

pp 1はPPPoEなので無視。TUNNELがMAP-Eのもの。
見事に使い切っている。いや、何度かやり直してちょうど使い切ってた瞬間のをコピペしたのだけど。
それでもブラウザのタブをせいぜいが10個くらい開いた程度のものである。
スマホやiPad、その他インターネットに繋がるデバイスがあるところではこんなものでは使い物にならないので泣く泣くIPv4通信をPPPoE経由に戻したのである。

Rev.14系以降のファームウェア(RTX1200はRev.10系)ではポートセービングIPマスカレードという機能があって、これを使えばこの問題は解決されるようだ。
市販のv6プラス対応ルータも恐らく同様の機能を有しているのであろう。
しかしRTX1200にはその機能はないのである。
さらばMAP-E。さらばv6プラス。

余談

先週からいろいろと試行錯誤している間に、RTX1210では公式にv6プラス対応のファームウェアが出ていた。

RTX1200にもファームウェアアップデートが出ているが、v6プラス対応もポートセービングIPマスカレード追加も書いてないのでRTX1200だと使い物にならないままだろう。

UEFI PXE netboot用のDHCPサーバをCentOS6で作る際はdhcpd.confにnext-serverの設定を入れよう

2018年4月18日 / 未分類

タイトルで言いたいことは言い終わった。

いきさつ

諸事情から40台のコンピュータにUbuntuインストールすることになり、手動でやるのは死ねるのでPXE boot + Preseedで自動インストールしようと思い、手元にあった環境でテストしてた。諸事情によりネットワークブート用のサーバとして使えたのはCentOS6の入ったコンピュータであった(悲劇の始まり)

UEFI/PXE-netboot-install – Ubuntu Wikiを見ながらネットワークブートの環境を作っていた。Ubuntu Wikiではdnsmasqを使っていたが、以前使ったことがあって設定もある程度調べていたdhcpdを使うことにした。同じように設定すればいいだろうと思って。あとDNSに関すること全くさせないのにdnsmasq使うのが何となく嫌だった。

で、いざやってみるとtftp経由でgrubイメージ読むところまではうまくいっているが、その後grub.cfgを読みに来ない。GRUBのシェルになる。dnsmasqを使ってやるとちゃんとgrub.cfgを読みに来てブートメニューが表示される。

なんでじゃーと思い、方々を調べながら試行錯誤を繰り返していたところ、dhcpd.confにnext-serverの設定を追加したら期待通りの動作をするようになった。
Man page of dhcpd.confから

next-server 文は初期ブートファイル (filename 文で指定したもの) をロードするサーバのホストアドレスを指定するために使います。 server-name は数値の IP アドレスかドメイン名です。 接続してきたクライアントに対して与えるべき next-server パラメータがなければ、DHCP サーバの IP アドレスが用いられます

next-serverの項目書いてなければDHCPサーバのIPアドレスになるとあり、実際grubイメージは同じIPで動いているTFTPサーバに読みに来てるのに、その先にはnext-serverの項目がないと進まないってわけがわからないよ。

追記

manpageからnext-serverが存在しないときの部分が削られてた。手元でman dhcpd.confしたら新しいのがちゃんと出てきた。13年以上前の情報が平然と上位に出てくるインターネットこわい。

オチ

不可解な点はあっても問題は解決したのでよしよし、同じことで困ってる人もいるだろうから帰ってブログエントリ書くか、と思ってUbuntu 16.04でやってみたらnext-serverなくてもしっかり動いて悲しみにくれる。

結論

CentOS6とかいう旧時代の遺物は破却しましょう。する。

SECCON 2017 Online CTF Writeup #seccon

2017年12月11日 / 未分類

スキルも文章力もない奴が何偉そうに言ってんの?(自分です)と思ったので書く。

とあるチームに参加して4問解いた。Submitしたのは上の3問で計500点。

Vigenere3d (Crypto 100)

ヴィジュネル暗号の3次元版。
2つ目の鍵を使ってヴィジュネル暗号の表を3次元方向に拡張している。

ヴィジュネル暗号の強さは鍵の長さ(=周期)に依存している。
Vigenere3dは、鍵を2つ用いているため、周期は2つの鍵の長さの最小公倍数となる。
問題のプログラムでは2つの鍵が同じ長さになっているため、拡張した意味がまったくない…

さて、暗号プロセスを見てみると、平文1文字に対して、2つの鍵のsにおけるインデックスの和で暗号文が決まることがわかる。
t[x]のデータを表にしてみるとわかりやすい。以下は平文が’S’の場合。

この問題では、2つ目の鍵は1つ目の鍵を逆順にしたものにしている。
このため、1つ目の鍵と2つ目の鍵のインデックスの和、というのは、後ろ半分の8文字目からは1~7文字目の順番を逆にしたものとなり、前半分の7文字分だけ鍵(のインデックスの和)がわかれば全部わかることになる。
7文字分は平文と暗号文の両方がわかっているため、これだけで鍵が全部導出できる。
平文1文字分ずつ上記の表を出して暗号文との対応から鍵を求めていくと、vigenere3d.pyの入力として与える鍵(の一例)は

AAAAAAA_aZ2PK_

であることがわかる。
あとは復号プログラムを作って暗号文と鍵を与えてやればいい。

import sys

def _l(idx, s):
    return s[idx:] + s[:idx]

def main(c, k1, k2):
    s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
    t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))]
    i1 = 0
    i2 = 0
    p = ""
    for a in c:
        for i in range(len(s)):
            if t[i][s.find(k1[i1])][s.find(k2[i2])] == a:
            p += s[i]
            break
        i1 = (i1 + 1) % len(k1)
        i2 = (i2 + 1) % len(k2)
    return p

print main(sys.argv[1], sys.argv[2], sys.argv[2][::-1])
Flag: SECCON{Welc0me_to_SECCON_CTF_2017}

Run me! (Programming 100)

与えられたソースコードを見ると、11011番目のフィボナッチ数の頭32桁がフラグの模様。
あとは下の通り。

Flag: SECCON{65076140832331717667772761541872}

Powerful Shell (Binary 300)

難読化(?)されたPowershellスクリプトを解析する(Binary…?)
要所要所で変数に保持したPowershellプログラムを実行する部分があるので、代わりにWrite-Hostで標準出力に出すなどしてやれば見ることができる。

1段目。
文字を延々と生成して変数$ECCONに追加している。
最後の”Write-Progress -Completed”の後に実行しているので変数$ECCONを出力してやればよい。

2段目。
キーボードを叩いて秘密のメロディを演奏させる。演奏されたメロディが正しいと次の段階に進む。
環境等チェックしているところはコメントアウトしつつ、Powershell ISEでデバッグ実行するのが楽、
“Play the secret melody.”と標準出力に出しているところまで進むと$keytoneにキーと鳴らす音の周波数の対応が入っている。
正解のメロディは少し後の$secret変数に周波数の列として納められているので$keytoneの内容と見比べて正解のキー列を得る。
ソースを追っていくと入力したキー列は$fに文字列の形で入っているため、正解のキー列で文字列を作っておく。

$f = "hhjhhjhjkjhjhf"

この$fは後でXORデコードの鍵として使われる。
下の方の$text以降に上記の$fの値を設定する一行を加え、最後のiexをWrite-Hostに書き換えれば実行されるコードを取得できる。

3段目。
最後はPowershellでの記号プログラミング。
記号のみで任意のPowerShellコードを実行 – JPerl advent calendar 2010 Sym Trackに書かれているのとまったく同じやりかたで記号化している。
(上記リンクはサーバにアクセスできなかったため、Web Archiveにリンクしている)
やり方を見て解読していけばいい。

Flag: SECCON{P0wEr$H311}

Simon and Speck Block Ciphers (Crypto 100)

アルゴリズム、平文、暗号文、鍵の一部が与えられており、鍵がフラグになっている。
鍵のうちわからない部分はたった4文字なので、Brute forceすればよい。
ググるとGitHubに実装があったのでこれを使った。

from simon import SimonCipher

def str2long(s):
    l = 0
    for i in range(len(s)):
        l = l * 256 + ord(s[i])
    return l

plain = 0x6d564d37426e6e71
cipher = 0xbb5d12ba422834b5

chars = [ chr(i) for i in range(33, 127) ]
solved = False
for c1 in chars:
    for c2 in chars:
        print "c1 = %c, c2 = %c" % (c1, c2)
        for c3 in chars:
            for c4 in chars:
                k = "SECCON{%c%c%c%c}" % (c1, c2, c3, c4)
                s = SimonCipher(str2long(k), key_size = 96, block_size = 64)
                if s.encrypt(plain) == cipher:
                    print "Key = %s" % k
                    solved = True
                    break
            if solved:
                break
        if solved:
            break
    if solved:
        break
Flag: SECCON{6Pz0}

以上。
久しぶりのCTFで楽しかったが、セキュリティの知識が必要とされる問題を解けていないことがわかる。
実働時間も短かった(まあこれはしょうがない)
Pwn系を解けなかったしそのスキルがあるとは思えないので精進したい。

Trend Micro CTF 2015 Writeup #TrendCTF #TrendCTF2015

2015年9月27日 / 未分類

Trend Micro CTF Asia Pacific & Japan 2015に参加した。
チームとしては1400点獲得。
自分は200点問題を3問解いたので書いていく。
(問題文等の確保をしてなかったのでその辺は適当。後ほどアップデートできればする)

続きを読む»

SECCON 2014 Online予選(2) writeup

2014年12月8日 / 未分類

オンライン予選冬の陣に参加したので取り組んだ問題について書いていく。

続きを読む»

TOPへ戻る