もぐてっく

人は1つ歳をとるたび、1ビットづつ大きくなれると信じてた。

Raspberry Pi meets XBMCなRaspbmcを無線アクセスポイント化してみた

Raspberry Piって超軽いから、出張に持って行っても苦にならないよね。

これをホテルに持ち込んでテレビに接続してAirPlayで動画を見れる様にしたら¥1,000/泊のメディア費削減になるんじゃね!

ついでにこれが無線ルータになったら、ホテルのネット回線も使い放題!超実用的!!

AirPlayはRaspbmcと言うRaspberry PiをXBMC箱にするディストリを使えば可能。
これに出っ張らないUSB無線LANをつなげてアクセスポイントにしてやればいいね。

と、言う訳でRaspbmcの無線アクセスポイント化スタートです。

用意するもの

・Raspbmc導入済みのRaspberry Pi(Model B、256MB版)
・PLANEX GW-USNano2

PLANEX ハイパワー無線LAN ゲーム機用 Wi-Fi USBアダプタ GW-USNANO2-G

PLANEX ハイパワー無線LAN ゲーム機用 Wi-Fi USBアダプタ GW-USNANO2-G

USB無線LANRealtekのRTL8192CUチップを指名買い。たまたまじゃんぱらで安かったPLANEXのGW-USNano2にしました。

指名買いの理由は、Linuxでのアクセスポイント利用をサポートしてた(公式ドライバに専用のhostapdが同梱されてる)から。独自改変したhostapdを使うってのはなんかダサいんですが、裏を返せばこのチップ専用にフィッティングされてる訳で、細かいトラブルを避けられると思った次第。

ドライバのダウンロード

まずはブラウザの使えるクライアントでRealtekのサイトにアクセスして、RTL8192CUのドライバを取ってきます。今回はRTL8192xC_USB_linux_v3.4.4_4749.20121105.zipを使います。

RaspbmcにはRTL8192CUのドライバが標準で入っているので、今回使うのはこの中のhostapdだけです。

取りあえずRaspbmcにログイン

Raspbmcが起動したのを確認して、sshでアクセスします。
AvahiやBonjourが生きてる環境なら名前でアクセス出来るから超便利。なんでWindowsはサポートしないんだろ。

なお、パスワードはraspberryです。

$ ssh pi@raspbmc.local


初回ログイン時にロケールとかタイムゾーンとかを訊いてきますが、まあお好みで。
(ここでははen_US.UTF-8とAsia/Tokyoにしました。)

今後sudoが面倒なのでrootになっておきます。
(なんかいい方法があったはずだけど忘れた。)

$ sudo su -
#


後、別の端末を開いてさっきダウンロードしたドライバをRaspbmcに転送しときます。

$ scp -p ~/Downloads/RTL8192xC_USB_linux_v3.4.4_4749.20121105-1.zip pi@raspbmc.local:/tmp/

必要なパッケージをインストール

ここからはRaspbmcにログインした端末での作業です。
hostapdのコンパイルに必要なパッケージとお手軽DHCP&DNSサーバであるところのdnsmasqを導入します。

# apt-get update
# apt-get install unzip build-essential dnsmasq

専用hostapdのインストール

なぜかzipなアーカイブを解凍しつつ、最深部(※)にあるソースコードをコンパイルすればこのステージはクリアです。
(※:パスが100文字超になって笑けます。)
途中に設定ファイルのテンプレートが落ちているので、忘れずにゲットして/etc/にコピーしておきましょう。

# unzip /tmp/RTL8192xC_USB_linux_v3.4.4_4749.20121105-1.zip
# cd RTL8188C_8192C_USB_linux_v3.4.4_4749.20121105/wpa_supplicant_hostapd/
# cp -p rtl_hostapd_2G.conf /etc/hostapd.conf
# unzip wpa_supplicant_hostapd-0.8_rtw_20120803.zip
# cd wpa_supplicant_hostapd-0.8/hostapd/
# make
# make install

/etc/hostapd.confの修正

さっき手に入れた設定ファイルをカスタマイズします。
WPSがONだとWPA設定でもWEPのアクセスポイントになってしまうのでWPSを切ります。

 13 ##### Wi-Fi Protected Setup (WPS) #############################################
 14
 15 eap_server=1
 16
 17 # WPS state
 18 # 0 = WPS disabled (default)
 19 # 1 = WPS enabled, not configured
 20 # 2 = WPS enabled, configured
 21 wps_state=0      # 2→0

にっくきNetworkManagerとの戦い

近頃クライアント系で流行のNetworkManager。
GUIで設定が出来たり、ケーブル接続時に通知メッセージが出たりとかで格好良いんですけど、そいつが古き良きネットワーク設定の仕組みを見事にぶち壊してくれています。
ifconfigでIPアドレス設定してても、LANケーブルを抜いたらそれが吹っ飛ぶとか勘弁して欲しいです。

今回も例によってNetworkManagerがしっかり無線LANを管理しちゃってて、hostapdの動きをことごとく邪魔してくれやがります。シネバイイノニ。

しかしながら安易にNetworkManagerを停止させると今度はRaspbmcのXBMCが文句を言い出すので、今回はなんとか共存の道を探らねばなりません。

爆乳の魔王が相手なら和平交渉も楽しいんでしょうが、相手バイナリファイルだし。面倒いなぁ。

まぁいいや。んでは、色々ファイルを書き換えていきます。

/etc/NetworkManager/NetworkManager.confの編集


「ごめんなさい。そして、ありがとうございました。
 私に、私のwlan0を返してください。それは私が背負うべき物でした。」


などと、NetworkManager様に丁重にお願いします。ちっ。

あらかじめ、ifconfigで無線インターフェースのMACアドレスを控えておきます。

# ifconfig wlan0
wlan0     Link encap:Ethernet  HWaddr 00:22:cf:b7:a5:da  ←コレ
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


メモしたMACアドレスをNetworkManagerの管理対象外にします。

  1 [main]
  2 plugins=ifupdown,keyfile
  3
  4 no-auto-default=B8:27:EB:9B:C0:8C,
  5
  6 [ifupdown]
  7 managed=false
  8
  9 # 以下追加。11行目のmac以降は調べたMACアドレス
 10 [keyfile]
 11 unmanaged-devices=mac:00:22:cf:b7:a5:da


これを保存すると即座に対象のインターフェースがダウンするので、その誠実さにちょっと感激したりしました。

/etc/network/if-up.d/secure-rmcの編集

まだいました!お邪魔設定ファイル!

こやつはifupしたタイミングで実行されて、そのインターフェース用の基本的なnetfilterルールを設定しやがります。
(インターフェースのサブネットからのパケットはACCEPT、それ以外はDROP。)

通常の用途だと毒にも薬にもならないルールですが、今回のアクセスポイント化に当たっては、クライアントからのDHCPパケット(0.0.0.0→255.255.255.255)が捨てられてしまうのでダメダメです。

# こいつのせいでifupで立ち上げたらうまくDHCPIPアドレスが取れなくて、ifconfigでなら正常動作と言う謎の動作になって数時間悩んだよ。。。

ルールを追加してやります。

125 logger -t iptables "Configuring ip tables for interface $IFACE"
126 if [ "$IFACE" != "lo" ]; then
127     NETMASK=$(get_subnet $IFACE)
128     iptables -A INPUT -s $NETMASK -i $IFACE -j ACCEPT
129     # DHCPを許可するルールを追加
130     iptables -A INPUT -s 0.0.0.0 -i $IFACE -j ACCEPT
131     iptables -A INPUT -i $IFACE -j DROP
132 fi

/etc/network/interfacesの編集

ここからは前向きな設定作業です。
無線インターフェースのIPアドレス他を設定していきます。
hostapdのinitスクリプトを書くのが面倒なのでpost-up/pre-downで起動・停止を制御することにします。
さらに、IPマスカレードの設定も入れときます。

interfaces超便利!

  1 allow-hotplug wlan0
  2
  3 iface wlan0 inet static
  4     address 192.168.0.1
  5     netmask 255.255.255.0
  6     broadcast 192.168.0.255
  7     network 192.168.0.0
  8     post-up /usr/local/bin/hostapd -B /etc/hostapd.conf
  9     post-up iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j MASQUERADE
  9     pre-down kill `pidof hostapd`
 10     pre-down iptables -t nat -D POSTROUTING -o eth0 -s 192.168.0.0/24 -j MASQUERADE


なぜかauto wlan0ではインターフェースが上がらなかったので、allow-hotplugにしてます。

/etc/dnsmasq.confの編集

無線インターフェースに対するDHCPサーバの設定を行います。

90行目のinterfaceのコメントを外して、wlan0を指定します。
これを忘れると家中のIPネットワークが混乱の渦に巻き込まれるので注意。

 86 # If you want dnsmasq to listen for DHCP and DNS requests only on
 87 # specified interfaces (and the loopback) give the name of the
 88 # interface (eg eth0) here.
 89 # Repeat the line for more than one interface.
 90 interface=wlan0


147行目のdhcp-rangeのコメントを外します。

143 # This is an example of a DHCP range where the netmask is given. This
144 # is needed for networks we reach the dnsmasq DHCP server via a relay
145 # agent. If you don't know what a DHCP relay agent is, you probably
146 # don't need to worry about this.
147 dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h

/etc/sysctl.d/ipv6.confの新規作成

RaspbmcのAirPlayでハマったでござる - もぐてっく

で、書いたAirPlayのためのIPv6無効化を行っておきます。

  1 net.ipv6.conf.all.disable_ipv6 = 1

/opt/xbmc-bcm/xbmc-bin/share/xbmc/addons/script.raspbmc.settings/autostart.pyの編集

Raspbmcはリセットボタンを押さずに電源を引っこ抜くと、次回起動時に

「ちゃんと画面端のパワーボタン押して終了せぇやボケぇ!死ぬかと思たわ!!」

と、怒られます。

その主張はごもっともなんですが、外出先でこのダイアログが出たら消す方法が無いので、当該コードをコメントアウトします。

126 #       if DISTRO == "Raspbmc" and os.path.isfile("/home/pi/.bootstatus") and check_service_running("wd") == "true" and not os.path.isfile("/home/pi/.nowarning"):
127 #             import xbmcgui
128 #             dialog = xbmcgui.Dialog()
129 #             dialog.ok("Raspbmc did not shut down properly", "Raspbmc should always be shut down via the\npower icon in the lower left corner")

リブート!

これでRaspberry Piの無線AP化は完了です。リブートして成果を確認します。

お手持ちの無線クライアントを見ると、rtwapってアクセスポイントが増えています。
パスワード87654321で接続出来れば成功です!

RaspbmcのAirPlayでハマったでござる


MacBook Airを買ったぜわっしょい!


さっそく今までヨダレ垂らして指くわえて見てたステキ機能を堪能するぜ!
まずはAirPlayだ!手元の動画をRegzaで見るぜ!
ああ、でもAppleTV持ってないぞ。でもきっとオプソ界にはニートな解が転がってるはず!


パスっ!タスタスタス!(SpotlightでWeb検索)


よし、Raspberry Pi向けのXBMC(Raspbmc)はAirPlayがしゃべれるぞ!!!


と、言うわけでRaspbmc導入スタート!

ダメでした

むぅ、iTunesのAirPlayデバイスにはRaspbmcが表示されてるんだけど、クリックしても「接続中です」がずっと出て接続が確立しない。。。


暇だからちょっと調査してみますか。

通信の状況を調べる

まずはMBAとRaspbmcの通信の状況を確認してみる。
まずはhomebrewでtcpdumpを・・・ってデフォルトで入ってるの!?
何このOS!超いいじゃん!

Alicia:~ moguno$ sudo tcpdump | grep raspbmc
・・・
18:36:41.308272 IP6 alicia.local.49174 > raspbmc.local.36666: Flags [S], seq 105655457, win 65535, options [mss 1440,nop,wscale 4,nop,nop,TS val 744813686 ecr 0,sackOK,eol], length 0
18:36:41.312502 IP6 raspbmc.local.36666 > alicia.local.49174: Flags [R.], seq 0, ack 105655458, win 0, length 0


ポート36666に対してコネクションしようとしてるけど拒否られてる。
てことは、Raspbmc側で必要なサーバが起動してないってことか。

ほーらやっぱり・・・あれ?

と、言うわけでRaspbmc側でポートが開いてないことを確認。
(ちなみにRaspbmcはRaspbianと同じく、ユーザ名:pi、パスワードraspberryでsshログイン可能です。)

pi@raspbmc:~$ netstat -a | grep LISTEN
・・・
tcp        0      0 *:36666                 *:*                     LISTEN     
tcp        0      0 *:36667                 *:*                     LISTEN     
tcp6       0      0 [::]:sunrpc             [::]:*                  LISTEN 
・・・


あれ?開いてるじゃん??

繋がる・・・だと?

一旦MBAに戻って、telnetを汎用TCPクライアントとして導通確認をば。
このMBAさん、telnetもばっちりデフォルトで完備です。
sshも入ってないのにtelnet消しちゃった某OSに、りんごのヘタを煎じて飲ませてやりたいですよ。

Alicia:~ moguno$ telnet raspbmc.local 36666
Trying 192.168.11.14...
Connected to raspbmc.local.
Escape character is '^]'.

RTSP/1.0 200 OK
Audio-Jack-Status: connected; type=analog
CSeq: 

^]
telnet> quit
Connection closed.

えー、なんで繋がるん???

IPv6だ!

よく分からなくなってきたので、もっかいtcpdumpログを見なおしてみる。

18:36:41.308272 IP6 alicia.local.49174 > raspbmc.local.36666: Flags [S], seq 105655457, win 65535, options [mss 1440,nop,wscale 4,nop,nop,TS val 744813686 ecr 0,sackOK,eol], length 0
18:36:41.312502 IP6 raspbmc.local.36666 > alicia.local.49174: Flags [R.], seq 0, ack 105655458, win 0, length 0


IP6・・・だと?

tcp        0      0 *:36666                 *:*                     LISTEN     
tcp6       0      0 [::]:sunrpc             [::]:*                  LISTEN 


あー、ポート36666はIPv4のINADDR_ANYにしかバインドされてない!これだ!!


つまり、こういうことでした。


・RaspbmcはIPv4IPv6両方のアドレスを持つので、avahiで両方のアドレスが他のノードにアナウンスされる。
・でも、RaspbmcはIPv4の36666ポートしか接続を受け付けない。
MBAIPv6を優先でIPv6の36666ポートにアクセスしに行くけど、RaspbmcはIPv4の36666ポートしか見てないから繋がない。

お兄ちゃん!いつまで寝てるの!!

と、言うわけでこの話のオチ。
RaspbmcのIPv6を無効にすることで対処しました。

pi@raspbmc:~$ sudo vi /etc/sysctl.d/ipv6.conf
net.ipv6.conf.all.disable_ipv6 = 1


そしてリブート・・・


通った。(エルクゥ風に)


256MB版Raspberry Piだけども、動作は超良好。
AirPlayサーバが欲しいだけならRaspberry Piで十分だわ。