fchiba memo

引き続き、linuxでルーターを作る話。

IPマスカレードしているときに、外部に対してNATでサーバーを公開する場合、iptablesのnatテーブルはこんな感じになると思います。

-A POSTROUTING -o wan -j MASQUERADE
-A PREROUTING -i wan -p tcp --dport 8080 -j DNAT --to 192.168.0.100:80

そして、そのサーバーへLANの外からも中からも同じようにアクセスしたいとします。

通常は、DDNSなどでルーターのグルーバルアドレスをサーバー名にひも付けていると思いますので、LAN側からだとルーターそのものへアクセスしてしまいます。

一つの方法としては、LANの中でDNSを立ててLANからアクセスした際にはローカルのアドレスを返すというものです。これでも大体の場合はうまくいくのですが、上記のように外と中で使っているポートが違う(WANの8080をサーバーの80に転送している)ときは、うまくいきません。

これをよしなにパケット転送して解決するのがループバックNAT(ヘアピンNAT)です。

WAN側のアドレスがわかっている場合、書き方は簡単で、

-A POSTROUTING -o wan -j MASQUERADE
-A PREROUTING -i wan -p tcp --dport 8080 -j DNAT --to 192.168.0.100:80
-A POSTROUTING -o lan -s 192.168.0.0/24 -d 192.168.0.100/32 -p tcp --dport 80 -j MASQUERADE
-A PREROUTING -i lan -p tcp -d (WANアドレス) --dport 8080 -j DNAT --to 192.168.0.100:80

外からきた場合と同じように、中からWAN側アドレスに対してアクセスした場合にはマスカレードするだけです(ここまではググれば出てくる話)。

しかし、これをサーバー上の設定ファイルに書こうと思うと困ったことがあります。それはWAN側のアドレスが変わってしまうということです。iptable-save/restoreは、マクロを展開するような機能を持っていないようですし、そもそもグローバルアドレスが変わるたびに実行しなおす仕組みが必要です。

WAN側アドレスを汎用的に指定する方法がないか探していたところみつけたのが、addrtype拡張のLOCALアドレスタイプです。これはルーティングテーブル上ローカルに配送されるものが含まれるようです。(詳細はmanを参照)

これを使えば、最後の部分は

-A PREROUTING -i lan -p tcp -m addrtype --dst-type LOCAL --dport 8080 -j DNAT --to 192.168.0.100:80

と書けて無事解決です(ルーターのLAN側アドレスを除外しないと厳密には同じではないですが)。

Raspberry Piでルーターを作ったのだが、VPN(PPTP)が通らなかった。

VPN Clientのログ(Macなので/var/log/ppp.log)を見たところ、LCP ConfReq というパケットを送ったのに、その返信が返ってこなくてタイムアウトしている模様。

ググると、GREパケットが途中で落ちているとのことなので、tcpdumpで調査。ppp0を見ると返ってきているのに、eth1(LAN側)には返ってきていないので、NATの問題だと予想。さらにググった結果、
http://serverfault.com/questions/167485/pptp-gre-multi-forwarding-nat-iptables-example

を発見し、
modprobe nf_conntrack_pptp
modprobe ip_nat_pptp
で解決。
 

前の記事でリモコンを自作したのですが、2通りの操作しかできない(シングルクリックとダブルクリックのみ。長押しは音声検索に奪われてユーザには使えない)ので、結局センチュリー Bluetooth接続マルチメディアリモコン iRemote Shutterを買ってしまいました。これはiPhone用ですが、Bluetoothキーボードとして認識されるらしいので、Androidでも使えることを期待して購入しました。

実際に使ってみると、接続はスムーズにでき、再生・曲送り・ボリューム調整は問題なく動きました。ただし、接続中はソフトウェアキーボードが消えてしまうので、日本語入力はできません。ソフトウェアキーボードを出すボタンがついているのですが、Androidでは動作しませんでした(どうせ運転中にしか使わないので影響はありませんが)。

車の運転中はボリューム調整がいらない(カーオーディオに接続しているのでそちらで調整できる)代わりに、早送り&巻き戻しが欲しかったので、キーボードのレイアウトを調整することにしました。幸いにもAndroid4.1からはユーザー定義のキーボードレイアウトをインストールできるので、さくっと自作。これでだいぶ操作しやすくなった気がします。

キーボードレイアウトのソースはgithubにあげました。


参考資料は以下の通りです。

Android入力デバイスの公式資料(ただし、カスタマイズ用ではなくデバイスメーカー向け)
Android入力デバイスの仕組みがわかりやすく解説されているマイナビの記事
カスタマイズキーボードを公開している方々
キーイベントの一覧



このカスタムキーボードの技術的に興味深い点としては、https://github.com/fchiba/iremoteshutter/blob/master/res/raw/iremoteshutter2.kcm#L4 のように、
map key (linuxのキーコード) (Androidのキーコード)
とかけば、kcm(=Key Character Map)という本来は文字の変換しか出来ないファイルにも関わらずキー自体の配置を変えられてしまうところです。これはy10gさんのソースを見ていて発見したんですが、undocumentedな仕様ですかね…

このページのトップヘ