Raspberry Piで航空機からの位置情報信号ADS-Bを受信してみた

最近ニュースで航空機の捜索が話題になっていましたが、その中でADS-Bという単語が出てきました。

ADS-B(Automatic Dependent Surveillance-Broadcast)は、航空機から1090MHzの周波数で発信されている、識別子、GPSによる現在位置、高度、対気速度などを含む信号で、この情報を地上や航空機間で利用することでより安全に航空機を運用できるようにするもので、近年これに対応したトランスポンダを搭載する航空機が増えてきているそうです。1030MHzで各航空機に問い合わせを送り、各航空機が1090MHzで応答するというプロトコルになっています。
参考: 空中衝突防止装置 - Wikipedia


Flightradar24というサイトを見ると、航空機の位置情報をリアルタイムで見ることができますが、これはユーザの受信機が拾ったADB-Sの情報を収集して配信することで、世界中の航空機の位置情報をカバーする仕組みになっています(ADB-Sに対応しない航空機もあるため、FAAの情報(5分遅れ)なども利用して補完しています)。


さて、このADS-Bですが、ソフトウェアラジオ(SDR: Software Defined Radio)用のUSBスティックを使うと非常に安価に受信することができます。
R820Tというチップを使ったUSBドングルが特に簡単に利用できるようです。何とたったの999円で手に入るとか。Amazonでも2000円くらいから売られていました。

DVB-T+DAB+FM USB チューナー  RTL2832U+R820T

DVB-T+DAB+FM USB チューナー RTL2832U+R820T


これをRaspberry Piに接続して、ADS-Bの受信(ついでにFMラジオの再生も)にトライしてみました。

今回使用したのは米国Amazon.comで購入したNoElecのR820T USBドングルです。
Raspberry PiでのADS-B受信は、下記のガイドが参考になります。
ADS-B Sniffing with the Raspberry Pi and the NooElec 820T Dongle | the electric stranger
なお、利用方法はR820Tを使用したドングルであればほぼ変わらないはずです。
WindowsMacで利用する方法も検索するといろいろと出てきます。


Raspberry Pi上のソフトウェアのセットアップ手順は下記の通り。

2017.2.1 追記

現在は、コマンド1つで全ての必要なソフトウェアの導入が可能になっています。

sudo bash -c "$(wget -O - http://repo.feed.flightradar24.com/install_fr24_rpi.sh)"

あとは質問に答えるだけ。詳しくは以下のスレッドを見てください。
http://forum.flightradar24.com/threads/8908-New-Flightradar24-feeding-software-for-Raspberry-Pie?p=66479#post66479


以下は古い情報です。

続きを読む

QEMU guest agentを使って仮想マシンのIPアドレスを取得

LinuxKVMで、ゲストのIPアドレスを取得する方法の覚え書き。


VMNICの接続先が仮想ネットワークであれば、

/var/lib/libvirt/dnsmasq/virbr0.leases

等にDHCPサーバが仮想マシンにリースしたIPアドレスが入っていますので、ここから取得できます。


一方、物理NICへのブリッジを作っている場合は、ここには記録されませんので、ゲスト内でip addrコマンド等を実行しなくてはなりません。QEMU guest agent(qemu-ga)がゲストに入っていれば、いちいちゲストにログインしなくてもホスト側からネットワーク情報を問い合わせることが可能です。

事前準備

最近のFedora(20で確認)であれば、自動的に下記のセットアップが行われるはずです。それ以前のVMの場合などは、手動で事前の設定が必要です。

チャネルの作成

最近のvirt-managerであれば自動でqemu-ga用のchannelが作られますが、存在しない場合、
virt-manager等を使って org.qemu.guest-agent.0 という名前のChannelを作ります。

http://wiki.libvirt.org/page/Qemu_guest_agent にあるように、virsh edit等でゲスト構成XMLを編集する方法もあります。

QEMU guest agentのインストー

Fedoraではゲスト上にインストールされた場合、自動的にQEMU guest agentが導入され、qemu-gaというプロセスが実行されます。入っていない場合は、

sudo yum install qemu-guest-agent

で導入できます。Ubuntu等の場合は、

sudo apt-get install qemu-guest-agent

で。

勝手に有効になるはずですが、念のため sudo systemctl enable qemu-guest-agent を実行しておきます。

jqのインストー

問い合わせの結果はJSONで返ってきます。見やすくする & 以下で使うスクリプトで利用するために、jqというJSONフィルタツールを導入しておきます。

sudo yum install jq

IPアドレスの取得

QEMU guest agentに、

{"execute":"guest-network-get-interfaces"}

という問い合わせを送ると、結果が帰ってきます。

# sudo virsh qemu-agent-command domain-name '{"execute":"guest-network-get-interfaces"}' | jq .
{
  "return": [
    {
      "hardware-address": "00:00:00:00:00:00",
      "ip-addresses": [
        {
          "prefix": 8,
          "ip-address": "127.0.0.1",
          "ip-address-type": "ipv4"
        },
        {
          "prefix": 128,
          "ip-address": "::1",
          "ip-address-type": "ipv6"
        }
      ],
      "name": "lo"
    },
   ...
      "name": "eth0"
    }
  ]
}


このままだと情報量が多すぎる&&コマンドも長いので、フィルタリングするためのシェルスクリプトを用意します。

https://gist.github.com/NeoCat/9903497

これをvirt-addrという名前でパスの通った場所に保存しておきます。

実行例:
$ virt-addr
usage: virt-addr [OPTIONS] domain
  -6             get ipv6 address  (default: ipv4)
  -h             show this help
  -n             show interface name
  -p             show prefix
  -i interface   specify interface (default: all)
$ virt-addr fedora20
127.0.0.1
10.0.0.123
$ virt-addr -n fedora20
lo:   127.0.0.1
eth0: 10.0.0.123
$ virt-addr -i eth0 -p fedora20        # prefix付きで表示
10.0.0.123/24
$ virt-addr -i lo -6 fedora20   # loインターフェースのIPv6アドレス
::1

ssh $(virt-addr -i eth0 fedora20) 等とすれば、対象ゲストにsshログインすることもできます。

emacs daemonの設定メモ

ちょっと設定を見直したのでそのときのメモです。


拡張をいろいろ追加すると起動に時間がかかるというemacsの欠点を補う方法として、emacs --daemonというものがある。これは要するにemacsをデーモンとしてバックグラウンドで起動しっぱなしにしておき、使いたいときには手元の端末やXのウィンドウでクライアントを立ち上げてデーモンに接続するだけ、というもの。いちいち初期化しないので本当に一瞬で起動できます。


で、何らかのタイミング(マシン起動時とかログイン時とか)であらかじめデーモンを立ち上げておく必要があるのですが、普段デスクトップとして使っているマシン*以外*では、初回使用時にデーモンがいなければ起動するようにして使っています*1


やり方としては、下記のスクリプトを"E"という名前でパスの通ったディレクトリにおいておきます。
ファイルを編集するときは "E ファイルパス" を実行すれば、デーモンが未起動の場合は起動した上で、クライアントが起動します。
ついでに"export EDITOR=E"しておくと、gitのコミットログを書くときとか、lessでファイルを見ていてvで編集開始したときとか、そういうときもemacsが一瞬で起動できます。

#!/bin/sh
if emacsclient -t "$@" ; then
  :
else
  emacs --daemon
  exec emacsclient -t "$@"
fi
追記

こんなスクリプトを使わなくとも、全く同じことをする emacsclient -a "" というオプションがあるのでこれを使って

alias E="emacsclient -t -a ''"

としておけば良かったようです。


ちなみに.emacsを編集したときなどにデーモンを終了したいときは

emacsclient -e '(kill-emacs)'

を実行します。


おまけ。編集したファイルのカーソルの位置を記憶して、次回開いたときに移動してくれる saveplace という拡張を使っていますが、これをdaemonと組み合わせると、デーモンが正常終了しなかった場合に位置が保存されないという問題があるので、下記のようにして10分に1回、位置を保存させています。

(require 'saveplace)
(setq-default save-place t)
(run-at-time 600 600 'save-place-kill-emacs-hook)

*1:デスクトップでは、ログインしたときにemacs --daemonを実行するよう、gnome-session-propertyで設定してあります

iOS7のSiriのMPTCP通信をキャプチャしてみた

iOS7のSiriはMPTCP (Multi-path TCP) に対応しているとのこと。

参考: iOS 7は3G・4G通信とWi-Fiなどを同時使用して回線速度を安定させる「MPTCP(マルチパスTCP)」に対応していることが判明 - GIGAZINE
参考: iOS 7でMPTCPがサポートされた話 | nunnun's weblog
RFC: RFC 6824 - TCP Extensions for Multipath Operation with Multiple Addresses


ということで、実際にその通信をキャプチャしてみました。(ちなみにSiri以外の通信にはMPTCPは有効にならないようです。残念。)
3G/LTEの通信を直接キャプチャすることはできないので、ちょっとした細工がDNSに必要です。


まず、iPhoneからWi-Fiで接続できるゲートウェイ・サーバが必要です。今回はLinuxを使用しました。iPhoneと同一のネットワークセグメントになるように接続します。

 Internet -- Wi-Fi router
             +-- Gateway Server
             +-- iPhone

Wi-Fiルータの設定

あらかじめWi-Fiルータの設定で、インターネットからゲートウェイ・サーバにHTTPS接続できるように、グローバルアドレスに対するHTTPS接続(TCP port 443)をゲートウェイ・サーバにフォワードするように設定しておきます。加えて、Wi-FiからグローバルアドレスへのHTTPS接続もゲートウェイ・サーバに繋がるようにする必要があります。これができるかはWi-Fiルータの仕様によります。できない場合は、外部ネットワークにゲートウェイをおくなどの工夫が必要になります。

ゲートウェイサーバの設定

HTTPS接続をAppleのSiriサーバに転送するようにします。やり方はいくつかありますが、

1. iptablesを使う

DNATでTCP 443番ポートのパケットをAppleのサーバに中継します。ファイアウォールで443をACCEPTするのもお忘れなく。

sudo iptables -t nat -A PREROUTING -d <ゲートウェイサーバのIPアドレス> -p tcp --dport 443 -j DNAT --to <guzzoni.apple.comのIPアドレス>:443
sudo iptables -t nat -A POSTROUTING -p tcp --dport 443 -j MASQUERADE

guzzoni.apple.comのIPアドレスはhostコマンドで調べてください。akamaiを使っているようなので環境により違うと思います。

2. MPTCPパッチ + stoneなどのTCPリピーターを使う

まず、MPTCPパッチLinuxカーネルに当てて再コンパイルしておく必要があります。ビルド方法はこのページを参照
ビルドしたカーネルで起動したら、stoneを導入し、

stone guzzoni.apple.com:443 443

とすればOKです。この場合、AppleのサーバとのiPhoneの直接MPTCP通信ではなく、ゲートウェイ・サーバを介した3者間でのMPTCP通信をキャプチャすることになります。ついでにLinuxのMPTCPともiPhoneAppleのサーバが通信できることも確認できますね:-)


両方ともやってみましたが、以下は2の方を使った場合の結果です。

DNSの導入

ゲートウェイにSiriサーバのエントリを改変するためのDNSを導入します。dnsmasqなどを使えばよいでしょう。こちらの記事にあるSiriProxyでも良いです。そして、「guzzoni.apple.com」の問い合わせに対して、自分のグローバルアドレスを返すように設定します。


そして、iPhoneWi-FI設定のDNSのアドレスを導入したサーバのものに変更します。


Wi-Fi側のDNSさえ弄っておけば、3G/LTE側の接続でもそこで引いたアドレスを使ってくれます。同一ホストに接続しなければMPTCPは意味がないので当然ですね。だからこそこの仕掛けでキャプチャができるわけですが。

MPTCP対応tcpdumpを導入

MPTCP対応tcpdumpも開発されているようです。ありがたく使わせていただきましょう。ビルドして…

git clone git://github.com/multipath-tcp/tcpdump.git
cd tcpdump
yum install libpcap-devel  # Fedoraの場合
./configure
make -j4

実行します。

./tcpdump -i <NICのインターフェース名> port https and not host guzzoni.apple.com

guzzoni.apple.comとの通信を除外しているのは、受信したパケットと転送パケットの両方がキャプチャされてしまうのを抑制するためです。

Siriを起動

この状態でSiriを起動してみると、

22:28:46.003820 IP iPhone.1024 > daisy.apple.com.https: Flags [S], seq 3599195999, win 65535, options [mss 1460,nop,wscale 3,mptcp capable {0x72d38468f5b08cec},nop,nop,TS val 172462590 ecr 0,sackOK,eol], length 0
22:28:46.005030 IP daisy.apple.com.https > iPhone.1024: Flags [S.], seq 486719052, ack 3599196000, win 14280, options [mss 1460,sackOK,TS val 12199698 ecr 172462590,nop,wscale 7,mptcp capable csum {0x2bbdacfe975af7bf}], length 0
22:28:46.028714 IP iPhone.1024 > daisy.apple.com.https: Flags [.], ack 1, win 8211, options [nop,nop,TS val 172462684 ecr 12199698,mptcp capable csum {0x72d38468f5b08cec,0x2bbdacfe975af7bf}], length 0

まずWi-Fiで通信が始まります。MPTCPオプションがついてますね(ホスト名がdaisy.apple.comとなっていますが、実際にはゲートウェイです。iPhoneというのはiPhoneWi-Fi側アドレスです)。さらに…

22:28:46.388811 IP LTE.51471 > daisy.apple.com.https: Flags [S], seq 970380433, win 65535, options [mss 1388,nop,wscale 3,mptcp join backup id 2 token 0x79701d4c nonce 0xa55d4e97,nop,nop,TS val 172462952 ecr 0,sackOK,eol], length 0
22:28:46.388923 IP daisy.apple.com.https > LTE.51471: Flags [S.], seq 130921612, ack 970380434, win 14280, options [mss 1460,sackOK,TS val 12200088 ecr 172462952,nop,wscale 7,mptcp join id 0 hmac 0xeddb2cca2f4efad9 nonce 0x76d9b16d], length 0

LTE側からもセッションが張られています(ホスト名がLTEとなっていますが、実際にはiPhoneLTE側のIPアドレスです)。今回キャプチャした限りでは、LTE側にはデータは流れておらず、制御用のパケットだけのようです。Wi-Fi側を故意に切断したりパケットをブロックしたりすると、LTE側にもデータが流れるのかもしれません。


キャプチャした内容はこちら → tcpdump of Siri connection with MPTCP option Captured with https://github.com/multipath-tcp/tcpdump on the gateway server (Linux with MPTCP patch). DNS server is modified to answer the gateway server's IP address for guzzoni.apple.com "LTE" means iPhone's LTE network address. · GitHub

kobo touchをWebブラウザからリモート操作

一つ前の記事(kobo touchのスクリーンショットをHTTP経由で取得 - Okiraku Programming)に引き続き、Webブラウザからkoboをリモート操作できるようにしてみました。(正確には画面をタップできるようにしただけ)

セットアップ方法は一つ前の記事と全く同様です。
inetdを有効化し、GitHub/NeoCat/kobo-remoteからkobo-remoteのバイナリをダウンロードして、ftpkobo内の適当な場所(/usr/bin/など)におきます。
そして、/etc/inetd.conf を編集して80番ポートなどにアクセスがあったらkobo-remoteを起動するように設定します。

# <service_name> <sock_type> <proto> <flags> <user> <server_path> <args>
21      stream  tcp     nowait  root    /bin/busybox ftpd -w -S /
23      stream  tcp     nowait  root    /bin/busybox telnetd -i
80      stream  tcp     nowait  root    /usr/bin/kobo-remote


あとはブラウザを起動するなどして無線LAN接続を有効にし、WebブラウザでkoboIPアドレスにアクセスすればOKです。


スクリーンキャプチャが表示されるので、適当な場所をクリックすると、その場所をタップしたというイベントが注入されます。画面は1秒後に自動更新されますが、koboの再描画が追いついていない場合はRefreshをクリックして手動で画面を再更新する必要があります。

ホームボタンを押す機能はありません(←ただの手抜き)ので、本を開く場合は左上の検索を使います(この手順でないと、省電力機能で無線LANがOFFになってしまい、途中でリモート操作不能になります。ブラウザ起動→検索だとこれが発生しない模様)。


というわけであんまり実用性はないのですが、とりま、こんなこともできるということで。iPadからアクセスすればkobo for iPadに(?)。
なお、何のセキュリティもかかっていないので、これを入れたままパブリックネットワークに接続すると、他人が勝手に購入ボタンを押しまくるといったことができてしまいますので注意して下さい、念のため(--;


ちなみに、タップ時にやっていることは、座標をHTTPでkobo上のサーバに送り、サーバ側では /dev/input/event1 (タッチパネルの入力デバイス) を開いて、イベント(struct input_event)を注入(write)しているだけです。詳しくはソースを見て下さい。


補足:GitHubにある tap-screen を引数なしで起動すると、イベントを眺めることができます。X,Yが90°回転した座標系になっている点に注意が必要。見てると感圧イベントも飛んでますが、タッチしている間100と101を交互に行き来するだけでダミーのようです。また /dev/input/event0 はホームボタンです。

kobo touchのスクリーンショットをHTTP経由で取得

kobo touchを改造して、Webブラウザ等からスクリーンキャプチャを撮れるようにしてみました。

内部的にはカラーで処理されているのが分かりますね。


やり方は以下の通り。

0. あらかじめ、telnetftpなどを有効化してファイルを転送できるようにしておきます。(inetdを有効化しておく必要があります。
 こちらなどを参考に→ 楽天のkoboを買いました – wifi経由でtelnet接続できるのを確認 - 記録


1. こちらのソースCodeSourceryのARM用GNU/Linux向けgcc等を使ってビルドします。

% arm-none-linux-gnueabi-gcc -Os fb2bmp.c -o fb2bmp

なお、ビルド済みの物はこちらからダウンロードできます

やっていることは、/dev/fb0 からフレームバッファの中身を取得し、24bit RGBに変換してHTTPレスポンスを返すというものです。


2. FTP等で、fb2bmpをkoboの/usr/bin/に転送します。

3. /etc/inetd.conf を編集して、下記の行を追加します。この例では、80番ポートにアクセスがあったら /usr/bin/fb2bmpを起動するようにしています。

80      stream  tcp     nowait  root    /usr/bin/fb2bmp

4. kill -HUP とするか、koboを再起動します。

5. Wi-Fiに接続した状態で、koboIPアドレスの上記ポートにWebブラウザからアクセスすると、BMP形式でスクリーンキャプチャが取得できます。


https://gist.github.com/3923865

Raspberry PiにI2C液晶をつける

Raspberry Piは、GPIOピンの一部をSPIやI2Cインターフェースとして使用できます。
これを利用して、Strawberry Linuxで販売されているI2Cキャラクタ液晶Raspberry Piに取り付けてみました。

配線

Raspberry PiのGPIOのピン配置は下記で分かります。
RPi Low-level peripherals - eLinux.org


これを見ながら、下記のように接続します。I2C用のプルアップ抵抗も不要です*1。液晶のRST端子は開放でOKです Vddに直結しておかないと動作が不安定になることがあります。

RaspberryPi I2C液晶
01 3.3V 5 VDD
03 SDA 3 SDA
05 SCL 2 SCL
06 GND 4 GND


こんな感じのアダプタのようなものを作ってみました。ピンヘッダにそのまま刺せます。

ソフトウェア

I2Cの使い方は下記サイトを参考にさせていただきました。
Raspberry Pi I2C How-To ガイド by @azarashi55 | GVC : Global Versatile Controller


1. /etc/modules に以下一行を追加

*1:Raspberry Piが内蔵プルアップ/プルダウン機能を持っているため

続きを読む