ラズベリーパイでゲストWi-Fi構築
BuffaloのWi-Fiルーターでは機種によりゲストWi-Fiを設定できます。やってきた友人や親族などのために家のネットワークとは別の架空のWi-Fiを提供するものです。来客者にWi-Fiパスワードを教え家のネットワークに入れてしまうと、IoT端末の入り口をさらしてしまうことになります。またパスワードのかかってない共有フォルダがあった場合は公開してしまうことになります。さらに、家のネットワークセキュリティで何かあったとき「あの人が……かも」と、疑心暗鬼になったり心の健康にもよくありません。
ゲストWi-Fiを設定しておけばインターネット回線を提供するだけで、ゲスト専用のパスワードを設定することができる上、ファイアウォールで家にあるスマホやPCへのアクセスを禁止することもできます。
今回はそのゲストWi-Fiルーターをラズベリーパイで単独で作成しようという話です。
ラズベリーパイを使えばルーターと物理的に分割できるので、使ってないときはコードを抜くということができます。さらにMicroSDカードを差し替えればラズベリーパイを他の用途に利用することもできます。
ただし、今使っているルーターに経路設定(ルーティング)機能が必要です。それがない場合でも、アクセスポイントという形でパスワードが違う入り口を作ることならできます。その際は、家の中のネットワークを探索されないようにするには工夫が必要になります。
今回は写真のラズベリーパイ(中身は3B+)を使ってみました。
ここではIPv4のみ取り扱います。単に「IPアドレス」という言葉が出てきた時はIPv4のことを指します。
必要なアプリ
ラズベリーパイのOSインストールについてはリンク先の記事を確認してください。初期状態のラズベリーパイに次のアプリをインストールします。
- hostapd
ラズベリーパイの無線インターフェースを無線親機にするために使います。本体に熱がこもるのが心配なら親機になれるUSBアンテナを接続してもいいです。ただし近年のWi-Fi規格のUSBアンテナは親機になれないものが主流のようです。筆者が確認しているのはIO-DATAの「WN-G300UA」なら親機として稼働しました(ただしWindows10では親機にはなれないそうです)。安いWi-Fi USBアンテナは「技適」がない商品もあったりします。それを利用すると違法となりますのでくれぐれも注意してください。
- isc-dhcp-server
接続してきた機器にIPアドレスを割り振る際に用います。アクセスポイント式の場合は不要です(たいていルーターがその役目を担っています)。
- iptables-persistent
ファイアウォールであるiptablesの設定を記憶しておくための補助アプリです。こちらもアクセスポイント式の場合は使いません。
- bridge-utils
こちらはアクセスポイント式にする場合のみ必要です。ラズベリーパイの無線インターフェースと有線インターフェースを同じネットワークとしてつなげる役目をします。
ここから先は併記するとわかりづらいので、ネットワーク分割式と、アクセスポイント式で分けて記述します。セキュリティが高いネットワーク分割式がおすすめですが、後から紹介するアクセスポイント式の方が簡単に実現できます。どちらも可能な場合は都合にあわせて選択してください。
設定(ネットワーク分割式)
まずネットワーク分割式での設定方法からです。まずはアプリのインストールから始めます。
- アプリのインストール
$ sudo apt update ... $ sudo apt install isc-dhcp-server hostapd iptables-persistent ...
isc-dhcp-serverは起動に失敗すると思いますが、あとで修正します。iptables-persistentの途中の質問は2回ともyesで答えます。
- 家のルーターの設定確認
まず、家のルーターのIPアドレスを調べてください。ブラウザで設定画面に行くときに、192.168.1.1だったり、192.168.100.1だったり入力すると思いますが、その値です。
また、その際DHCPサーバーを使用している場合は設定画面よりラズベリーパイ用にアドレスを一つ確保してください。DHCPで固定アドレスにするか、配布しない空きアドレスを作るかどちらかになると思います。
- ラズベリーパイのアドレス設定
DHCPを使わない場合、手動でラズベリーパイにアドレスを設定します。
設定ファイルは/etc/dhcpcd.confになります。# Example static IP configurationの次の行のコメントアウト(#)を消して、ラズベリーパイ用のIPアドレス(ip_address)を設定します。
routersとdomain_name_serversにルーターのIPアドレスを入力します。domain_name_serversにはGoogleのパブリックDNSである8.8.8.8や、CiscoのopenDNS(意訳:フィルタ付DNS)である208.67.222.123を設定してもいいです。
/etc/dhcpcd.conf
# Example static IP configuration interface eth0 static ip_address=192.168.1.251/24 static routers=192.168.1.1 static domain_name_servers=8.8.8.8
次にゲスト側のIPアドレスをWi-Fiインターフェースに設定します。ip_addressの部分は家のルーターとは違ったネットワークにします。ルーターが192.168.x.y/24のネットーワークだったらxの値が重ならなければ別のネットワークです。
routersは設定しません。ゲスト側のネットワークのルーターはラズベリーパイ自身です。
ラズベリーパイの無線インターフェースはwlan0なので、それに設定します。
/etc/dhcpcd.conf
# 先の設定の続きに挿入 interface wlan0 static ip_address=192.168.2.251/24 static domain_name_servers=8.8.8.8
- hostapdの設定
hostapdの設定については、「DebianにUSB Wi-Fiアダプタを付けてAP化」の記事にて詳細を紹介していますので、設定項目だけ記述しておきます。
/etc/hostapd/hostapd.conf(新規作成)
interface=wlan0 driver=nl80211 ssid=guest-wifi auth_algs=1 wpa=2 wpa_psk_file=/etc/hostapd/psk wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP TKIP rsn_pairwise=CCMP country_code=JP ieee80211d=1 ieee80211h=0 hw_mode=g channel=1
/etc/hostapd/psk
# "wifi-password"の部分がゲストWi-Fiのパスワードになります。 00:00:00:00:00:00 wifi-password
- DHCPの設定
DHCPサーバーが家のネットワーク側にあってもなくても、ゲスト側のDHCPサーバーを設定します。DHCPサーバーはネットワーク毎に必要です。
DHCPサーバーの設定については別記事で公開していますので、ここでは設定値だけを紹介します。
/etc/default/isc-dhcp-server
INTERFACESv4="wlan0" INTERFACESv6=""
/etc/dhcp/dhcpd.conf
... #ドメインを設定 option domain-name "your.domain.name"; #DNSを設定 option domain-name-servers 8.8.8.8; ... #コメントアウトを外します authoritative; ... #配布アドレスの設定 subnet 192.168.2.0 netmask 255.255.255.0 { range 192.168.2.10 192.168.2.30; option routers 192.168.2.251; }
subnetの部分にゲストWi-Fiのネットワークを記述します。rangeにはDHCPサーバーが配布するアドレスの範囲、option routersにはラズベリーパイに設定したアドレスを入力します。
dhcpd.confの設定行は;(セミコロン)で終わるようになっています。忘れるとエラーになりますので注意してください。
- テスト稼働
ここまで記述できたら、ゲストWi-Fiが使えるようになりますので稼働させてみます。
注意が必要なのはhostapdが起動してwlan0のインターフェースがアップしてIPアドレスが設定されている状態でないと、dhcpサーバーの起動に失敗します。
$sudo hostapd -d /etc/hostapd/hostapd.conf-dオプションでログを出力しながら待機しているので、もう一つ別のSSH接続をするか、直接操作だったらALT+F2でターミナルを変えて実行します。(戻るときはALT+F1です)
逆に操作ができる状態になっていたら、何かしらのエラーが起きています。ログを確認してみてください。
hostapdの待機をやめるにはCTRL+Cを押します。
hostapdが稼働したら今度はdhcpサーバーを稼働させます。
$ sudo systemctl start isc-dhcp-serverスマホなどの端末で接続できるか確認してみましょう。経路設定をしていないのでこの段階ではまだインターネットにはつながりません。Wi-Fiに接続できるかだけの確認になります。
- インターフェース間の転送の設定
通常ラズベリーパイの無線と有線インターフェース間はセキュリティ上の観点から通信ができないようになっています。それを許可するために/etc/sysctl.confに記述します。
/etc/sysctl.conf
#通常はコメントアウトされて入っているので #コメントアウトを除去します。 net.ipv4.ip_forward=1
この設定は次回起動時に有効になります。即時反映させるには「sudo sysctl -p」を実行します。
- 家のルーターの経路設定をする
家のネットワークにあるルーターに今回設定したゲストネットワークの経路を設定します。ここでは192.168.2.0/24(ゲストネットワーク)は、192.168.1.251(ラズベリーパイ)に転送するという設定を入れています。
ここまでの設定が終わればインターネットへの接続ができるようになります。再度テストしてみましょう。
- ファイアウォールの設定
テスト通信に問題なければ、最後にファイアウォールの設定をしてゲストネットワークからは家のネットワークへの通信ができないようにします。
ファイアウォールにはiptablesを使います。iptablesの詳しい設定方法については別記事で紹介していますのでよろしかったら目を通してみて下さい。
iptable-persistentを利用しているため/etc/iptables/にあるrules.v6と、rules.v4にルールを記述します。これは起動時に自動で読み込まれます。
まずIPv6の通信の設定をします。意図しない場所との通信が発生することを避けるために入ってくるデータと、転送要求をすべて遮断します。
/etc/iptables/rules.v6
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0]
本命のIPv4のファイアウォールの設定です。設定の仕方はいろいろあると思いますが次のようにしてみました。
ファイアウォールは「入」と「転送」はデフォルトで禁止、「出」はデフォルトで許可するのが一般的ですが、ここでは「転送」をデフォルトで許可にしました。
その上で、ゲスト側からのルーター宛の転送、ルーター側からの転送の許可を記述した後、ゲスト側からプライベートネットワークへの転送はすべて拒否します。
こうすることで、ゲスト側からはインターネットとの通信しかできなくなります。
/etc/iptables/rules.v4
*filter :INPUT DROP [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] # 家のネットワーク側からの入は許可 # 管理用の設定 -A INPUT -p all -i eth0 -j ACCEPT # 次の1.2の設定は全体の拒否設定※より先に記述する必要があります。 # 1.家のルーターへの転送は許可 -A FORWARD -p all -d 192.168.1.1 -j ACCEPT # 2.ゲストネットワークへの転送は許可 -A FORWARD -p all -d 192.168.2.0/24 -j ACCEPT # ルーター以外へのプライベートアドレス宛の転送は拒否※ -A FORWARD -p all -d 10.0.0.0/8 -j DROP -A FORWARD -p all -d 172.16.0.0/12 -j DROP -A FORWARD -p all -d 192.168.0.0/16 -j DROP
設定(アクセスポイント式)
次にアクセスポイントモードにする場合です。インストールから始めます。
- アプリのインストール
$ sudo apt update ... $ sudo apt install hostapd brige-utils ...
- DHCPの設定
DHCPは家のルーターで稼働しているならそれをそのまま利用できます。また稼働していなければルーターのDHCPサーバーを稼働させてください。設定方法はお手持ちのルーターの説明書を参考にしてください。
先のネットワーク分割式で設定したように、ラズベリーパイのeth0にDHCPサーバーを立てることも可能ですが、二元管理になりかねないのでお勧めできません。
- ブリッジの設定
/etc/hostapd/hostapd.confの設定を次のように記述します。先のネットワーク分割式との違いは下線部だけです。bridge-utilsをインストールし、brigeの項目に対象のインターフェースを記入すると、アプリ立ち上がった際に自動的にブリッジ接続してくれます。
/etc/hostapd/hostapd.conf
interface=wlan0 bridge=eth0 driver=nl80211 ssid=guest-wifi auth_algs=1 wpa=2 wpa_psk_file=/etc/hostapd/psk wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP TKIP rsn_pairwise=CCMP country_code=JP ieee80211d=1 ieee80211h=0 hw_mode=g channel=1
/etc/hostapd/psk(新規作成)
# "wifi-password"の部分がゲストWi-Fiのパスワードになります。 00:00:00:00:00:00 wifi-password
- ファイアウォール
アクセスポイント式だと、IP基準でのファイアウォールは利用できません。MACアドレス単位でのフィルタリングは可能ですが、意図したように設定するのは難しそうです。
hostapdのサービス化(自動起動)
hostapdはインストール時にはサービスはmaskedに設定されていて自動化されていません。
先の手順では手動で起動させましたが、サービスとして自動起動させます。
masked(使用不可)になっているので、いったんをunmaskで解除した後、enableにします。
$ sudo systemctl unmask hostapd ... $ sudo systemctl enable hostapd ...
isc-dhcp-serverの自動起動
興味があるかたは、後述の失敗談を見ていただければこうするに至った経緯が書いてありますが、筆者はdhcpcdによる設定でisc-dhcp-serverを自動起動させることができませんでした。
そこでdhcpcdでのネットワーク設定をあきらめ、従来型のnetworkingを利用します。
$sudo systemctl disable dhcpcd $sudo systemctl enable networking
/etc/network/interfaces
# コメントアウト # source-directory /etc/network/interfaces.d allow-hotplug eth0 iface eth0 inet static address 192.168.1.251/24 gateway 192.168.1.1 dns-nameservers 8.8.8.8 allow-hotplug wlan0 iface wlan0 inet static address 192.168.2.251/24
interfacesに固定アドレスを書けばisc-dhcp-serverは起動時に実行されてもエラーとなりません。伴ってhostapdへの依存性もなくなりますので、そのためのスクリプトを設定する必要もありません。
isc-dhcp-serverの自動起動(失敗談1)
ラズベリーパイ起動後に「systemctl status isc-dhcp-server」を実行してみるとわかりますが、このサービスはいつも失敗に終わっています。
先ほどの記事内でhostapdの起動後でないとisc-dhcp-serverは起動できないと書きましたが、それが原因です。
「systemctl list-dependencies」でサービスの起動順序を調べてみると、isc-dhcp-serverはhostapdより優先順位が高くなっています。
そこで、isc-dhcp-serverがhostapdの起動後に起動するようにinit.d内のスクリプトを変えてみました。
この設定ファイルは/etc/init.d/isc-dhcp-serverです。これがsystemd-sysv-generatorにより自動的にsystemdのunitに変換されています。
この/etc/init.d/isc-dhcp-serverのRequired-Start:の行を次のように変更します。
/etc/init.d/isc-dhcp-server
... # Required-Start: hostapd ...
筆者の記憶ではinit.dでのサービスの登録方法は「chkconfig --add service-name」「chkconfig service-name on」でサービスを登録した覚えがあったのですが、ラズベリーパイでは(今では)update-rc.dに差し替えられています。
$ sudo update-rc.d service-name defaults ...
defaultsをremoveに変えると、「chkconfig serciec-name off」と「chkconfig -del serciec-name」の代替になります。
これで再起動してみるとisc-dhcp-serverはhostapdの後に実行されているようですが、起動には失敗します。おそらくhostapdサービスのtypeがforkingになっているので、この設定でもIPアドレスが設定される前にisc-dhcp-serverが起動してしまうようです。
isc-dhcp-serverの自動起動(失敗談2)
1の失敗を受け、interfaceが起動した時にフックするスクリプトを/etc/networking/if-up.d/に設置してみました。
if-up.d設置するファイルは、shスクリプトをそのまま配置することができますが、 ファイル名に.や数字-等があると起動されないので注意してください。ここではhostapdと名前をつけました。
isc-dhcp-serverの自動起動を止めます。そして、if-up.dにスクリプトを書き、無線インターフェースがupしたときにサービスを起動させるように変更します。
/etc/network/if-up.d/hostapd
#!/bin/bash # IFACEは起動したインタフェース名が入る環境変数です # すべてが対象の場合--allが入ります。 case "$IFACE" "--all" | "wlan0" ) systemctl restart isc-dhcp-server;; *);; esac
利用しているバージョンでのbusterの記事ではなかったのですが、ネット上の記事を調べてみるとdhcpcdを稼働させていると/etc/networkディレクトリ以下の設定に干渉するようです。
それが理由かどうかわかりませんが、上記のスクリプトでもうまくいきませんでした。
加えて「ip link set dev wlan0 up」のコマンドを利用すると、実行されません。