Raspberry Pi 3でパケットキャプチャ用無線アクセスポイントを作る

Raspberry Pi 3にはWi-Fiモジュール(Broadcom BCM43438)が搭載されているが、このモジュールはクライアントとしてだけではなく、アクセスポイントとして動作させることもできる。 ここでは、Raspberry Pi 3でDHCPサーバ付き無線ルータを作り、アクセスポイントに接続するだけで簡単にパケットキャプチャできるようにしてみる。

環境

Raspberry Pi 3 Model B (Raspbian Jessie Lite)

$ uname -a
Linux raspberrypi 4.4.9-v7+ #884 SMP Fri May 6 17:28:59 BST 2016 armv7l GNU/Linux

$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

無線インタフェースが対応している動作モードの確認

次のコマンドで、無線インタフェースが対応している動作モードを調べることができる。

$ iw list
Wiphy phy0
(snip)
        Supported interface modes:
                 * IBSS
                 * managed
                 * AP
                 * P2P-client
                 * P2P-GO
                 * P2P-device
(snip)

上の結果より、クライアントとして動作するmanagedモードに加え、アクセスポイントとして動作するAPモードをサポートしていることがわかる。

無線インタフェースのIP設定

以降、上流の有線ネットワークを192.168.0.0/24、作成する無線ネットワークを192.168.1.0/24とする。 また、IPv6についてはUnique Local IPv6 Unicast Address(ULA)を用い、IPv4同様別セグメントを作ることにする。 ここでは、そのセグメントをfdXX:XXXX:XXXX:1::/64で表し、Xの部分にはランダムに生成した値が入るものとする(参考)。

まず、無線インタフェースwlan0のIPアドレスを192.168.1.1およびfdXX:XXXX:XXXX:1::1に設定する。

$ sudo vi /etc/network/interfaces
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.1.1
netmask 255.255.255.0
iface wlan0 inet6 static
address fdXX:XXXX:XXXX:1::1
netmask 64
#iface wlan0 inet manual
#    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

hostapdの設定

次に、hostapdをインストールし、無線アクセスポイントの設定を行う。

$ sudo apt-get install hostapd
$ sudo sh -c "zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz > /etc/hostapd/hostapd.conf"
$ sudo vi /etc/hostapd/hostapd.conf
interface=wlan0
ssid=raspberrypi_nomap
wpa=2
wpa_passphrase=SECRETPASSPHRASE
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP

一時的にhostapdを起動し、他の端末から設定したSSIDが見えていることを確認する。

$ sudo hostapd /etc/hostapd/hostapd.conf

SSIDが確認できたら、OS起動時にhostapdが自動起動するように設定する。

$ sudo vi /etc/default/hostapd
DAEMON_CONF="/etc/hostapd/hostapd.conf"

dnsmasqの設定

無線ネットワークにおけるDHCP/DNSサーバとして、dnsmasqをインストールする。

$ sudo apt-get install dnsmasq

続けて、設定ファイルを編集する。

$ sudo vi /etc/dnsmasq.conf
no-resolv
no-poll
interface=wlan0
enable-ra
dhcp-range=192.168.1.101,192.168.1.200
dhcp-range=::,constructor:wlan0,ra-stateless
server=192.168.0.1

上の設定は、wlan0インタフェースにDHCPv4で192.168.1.101-200を配り、IPv6ではDHCPv6サーバを使用したステートレス自動設定を行う。 また、dnsmasqが参照するDNSサーバについては/etc/resolv.confを参照せず、有線ネットワーク側のDNSサーバ(192.168.0.1)を直接指定している。

パケット転送およびNAPTの設定

IPv4IPv6のそれぞれについてパケット転送を行うように設定する。

$ sudo vi /etc/sysctl.conf
net.ipv4.conf.all.forwarding = 1
net.ipv6.conf.all.forwarding = 1

次に、iptables-persistentをインストールし、無線ネットワークからeth0に転送されるパケットについてNAPT(IPマスカレード)を行うように設定する。

$ sudo apt-get install iptables-persistent
$ sudo vi /etc/iptables/rules.v4
# Generated by iptables-save v1.4.21 on Thu Sep  1 23:52:33 2016
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu Sep  1 23:52:33 2016
# Generated by iptables-save v1.4.21 on Thu Sep  1 23:52:33 2016
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Thu Sep  1 23:52:33 2016

$ sudo vi /etc/iptables/rules.v6
# Generated by ip6tables-save v1.4.21 on Mon Sep  5 01:44:20 2016
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s fdXX:XXXX:XXXX:1::/64 -o eth0 -j MASQUERADE
COMMIT
# Completed on Mon Sep  5 01:44:20 2016
# Generated by ip6tables-save v1.4.21 on Wed May 25 21:30:37 2016
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Wed May 25 21:30:37 2016

なお、「Raspberry PiでIPv6 PPPoE対応ルータを作る」で説明した方法でRaspberry PiをPPPoEルータにしている場合は、IPv6のNAPTインタフェースをeth0からppp0に変える必要がある。

最後にRaspberry Piを再起動し、wlan0に指定したIPアドレスが割り当てられていること、hostapd/dnsmasqが起動していることを確認する。

$ sudo reboot
$ ip addr
(snip)
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.1/24 brd 192.168.1.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet 169.254.120.61/16 brd 169.254.255.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fdXX:XXXX:XXXX:1::1/64 scope global
       valid_lft forever preferred_lft forever
(snip)

$ systemctl status hostapd
● hostapd.service - LSB: Advanced IEEE 802.11 management daemon
   Loaded: loaded (/etc/init.d/hostapd)
   Active: active (running) since Mon 2016-09-05 03:18:44 JST; 4min 45s ago
  Process: 1319 ExecStart=/etc/init.d/hostapd start (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/hostapd.service
           └─1534 /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf

$ systemctl status dnsmasq
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
   Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled)
  Drop-In: /run/systemd/generator/dnsmasq.service.d
           └─50-dnsmasq-$named.conf, 50-insserv.conf-$named.conf
   Active: active (running) since Mon 2016-09-05 03:18:07 JST; 5min ago
  Process: 712 ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf (code=exited, status=0/SUCCESS)
  Process: 642 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited, status=0/SUCCESS)
  Process: 553 ExecStartPre=/usr/sbin/dnsmasq --test (code=exited, status=0/SUCCESS)
 Main PID: 711 (dnsmasq)
   CGroup: /system.slice/dnsmasq.service
           └─711 /usr/sbin/dnsmasq -x /var/run/dnsmasq/dnsmasq.pid -u dnsmasq -r /var/run/dnsmasq/resolv.conf -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trust-anchor=.,19...

無線アクセスポイントを通る通信をパケットキャプチャしてみる

パケットキャプチャを行うために、tcpdumpをインストールする。

$ sudo apt-get install tcpdump

wlan0インタフェースに対してtcpdumpを実行し、Android端末から無線アクセスポイントに接続してみる。

$ sudo tcpdump -i wlan0 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
03:34:55.912458 ba:27:eb:XX:XX:XX > b8:27:eb:XX:XX:XX, ethertype Unknown (0x886c), length 74:
        0x0000:  8001 0068 0000 1018 0001 0002 0000 0000  ...h............
        0x0010:  0004 0000 0000 0000 0000 0000 0000 0000  ................
        0x0020:  0000 90b6 86c3 2241 776c 3000 0000 0000  ......"Awl0.....
        0x0030:  0000 0000 0000 0000 0000 0000            ............
03:34:55.924089 90:b6:86:XX:XX:XX > ff:ff:ff:ff:ff:ff Null Unnumbered, xid, Flags [Response], length 6: 01 00
03:34:55.925734 ba:27:eb:XX:XX:XX > b8:27:eb:XX:XX:XX, ethertype Unknown (0x886c), length 229:
        0x0000:  8001 0103 0000 1018 0001 0002 0000 0000  ................
        0x0010:  0008 0000 0000 0000 0000 0000 0000 0000  ................
        0x0020:  009b 90b6 86c3 2241 776c 3000 0000 0000  ......"Awl0.....
        0x0030:  0000 0000 0000 0000 0000 0011 7261 7370  ............rasp
        0x0040:  6265 7272 7970 695f 6e6f 6d61 7001 0882  berrypi_nomap...
        0x0050:  848b 9624 3048 6c32 040c 1218 6021 0202  ...$0Hl2....`!..
        0x0060:  1224 0201 0d30 1401 0000 0fac 0401 0000  .$...0..........
        0x0070:  0fac 0401 0000 0fac 0280 002d 1a2d 0017  ...........-.-..
        0x0080:  ff00 0000 0000 0000 0000 0000 0000 0000  ................
        0x0090:  0000 0000 0000 007f 0800 0008 8001 4000  ..............@.
        0x00a0:  40dd 1e00 904c 332d 0017 ff00 0000 0000  @....L3-........
        0x00b0:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x00c0:  00dd 0900 1018 0200 0010 0000 dd07 0050  ...............P
        0x00d0:  f202 0001 0000 00                        .......
03:34:55.930534 EAPOL key (3) v2, len 95
03:34:55.970042 EAPOL key (3) v1, len 117
03:34:55.971198 EAPOL key (3) v2, len 151
03:34:55.983969 EAPOL key (3) v1, len 95
03:34:56.051210 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fe80::XXXX:XXXX:XXXX:XXXX, length 24
03:34:56.056070 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
03:34:56.412020 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::2: ICMP6, router solicitation, length 16
03:34:56.412693 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, router advertisement, length 64
03:34:56.426102 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fdXX:XXXX:XXXX:1:XXXX:XXXX:XXXX:XXXX, length 24
03:34:56.437585 IP6 :: > ff02::1:XXXX:XXXX: ICMP6, neighbor solicitation, who has fdXX:XXXX:XXXX:1:XXXX:XXXX:XXXX:XXXX, length 24
03:34:56.437758 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 2 group record(s), length 48
03:34:56.462079 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 90:b6:86:c3:22:41, length 314
03:34:56.622910 IP 192.168.1.1.67 > 192.168.1.170.68: BOOTP/DHCP, Reply, length 300
03:34:56.719521 ARP, Request who-has 192.168.1.1 tell 192.168.1.170, length 28
03:34:56.719557 ARP, Reply 192.168.1.1 is-at b8:27:eb:XX:XX:XX, length 28
03:34:57.049105 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::2: ICMP6, router solicitation, length 16
03:34:57.049738 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, router advertisement, length 64
03:34:59.664530 IP6 fe80::XXXX:XXXX:XXXX:XXXX > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
03:35:01.419914 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, neighbor solicitation, who has fe80::XXXX:XXXX:XXXX:XXXX, length 32
03:35:01.549158 IP 192.168.1.170.35684 > 192.168.1.1.53: 43557+ A? connectivitycheck.android.com. (47)
03:35:01.549334 IP 192.168.1.170.43378 > 192.168.1.1.53: 12979+ A? connectivitycheck.android.com. (47)
03:35:01.549422 IP6 fe80::XXXX:XXXX:XXXX:XXXX > fe80::XXXX:XXXX:XXXX:XXXX: ICMP6, neighbor advertisement, tgt is fe80::XXXX:XXXX:XXXX:XXXX, length 32
03:35:01.558617 IP 192.168.1.1.53 > 192.168.1.170.43378: 12979 1/0/0 A 216.58.221.174 (63)
03:35:01.559263 IP 192.168.1.1.53 > 192.168.1.170.35684: 43557 1/0/0 A 216.58.221.206 (63)
03:35:01.575683 IP 192.168.1.170.51055 > 192.168.1.1.53: 36811+ AAAA? ipv4only.arpa. (31)
03:35:01.575771 IP 192.168.1.1.53 > 192.168.1.170.51055: 36811 0/0/0 (31)
03:35:01.577961 IP 192.168.1.170.40382 > 192.168.1.1.53: 53548+ A? ipv4only.arpa. (31)
03:35:01.578023 IP 192.168.1.1.53 > 192.168.1.170.40382: 53548 2/0/0 A 192.0.0.171, A 192.0.0.170 (63)
03:35:01.700229 IP 192.168.1.170.41658 > 192.168.1.1.53: 56266+ AAAA? north-america.pool.ntp.org. (44)
03:35:01.722678 IP 192.168.1.1.53 > 192.168.1.170.41658: 56266 0/1/0 (99)
03:35:01.727875 IP 192.168.1.170.55498 > 192.168.1.1.53: 51322+ A? north-america.pool.ntp.org. (44)
03:35:01.749989 IP 192.168.1.1.53 > 192.168.1.170.55498: 51322 4/0/0 A 38.229.71.1, A 206.108.0.132, A 104.156.99.226, A 69.167.160.102 (108)
03:35:01.751144 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [S], seq 2110605975, win 65535, options [mss 1460,sackOK,TS val 4294940628 ecr 0,nop,wscale 7], length 0
03:35:01.755148 IP 192.168.1.170.33459 > 38.229.71.1.123: NTPv3, Client, length 48
03:35:01.764984 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [S.], seq 2111217721, ack 2110605976, win 42540, options [mss 1414,sackOK,TS val 1370227089 ecr 4294940628,nop,wscale 7], length 0
03:35:01.767118 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [.], ack 1, win 685, options [nop,nop,TS val 4294940630 ecr 1370227089], length 0
03:35:01.770321 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [P.], seq 1:430, ack 1, win 685, options [nop,nop,TS val 4294940630 ecr 1370227089], length 429
03:35:01.783798 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [.], ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 0
03:35:01.783914 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [P.], seq 1:103, ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 102
03:35:01.784154 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [F.], seq 103, ack 430, win 341, options [nop,nop,TS val 1370227108 ecr 4294940630], length 0
03:35:01.786455 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [.], ack 103, win 685, options [nop,nop,TS val 4294940632 ecr 1370227108], length 0
03:35:01.786945 IP 192.168.1.170.33118 > 216.58.221.206.80: Flags [F.], seq 430, ack 104, win 685, options [nop,nop,TS val 4294940632 ecr 1370227108], length 0
03:35:01.800821 IP 216.58.221.206.80 > 192.168.1.170.33118: Flags [.], ack 431, win 341, options [nop,nop,TS val 1370227125 ecr 4294940632], length 0
(snip)
03:35:31.574015 IP 192.168.1.170.64782 > 192.168.1.1.53: 53427+ AAAA? inaz2.hatenablog.com. (38)
03:35:31.583433 IP 192.168.1.1.53 > 192.168.1.170.64782: 53427 0/1/0 (122)
(snip)
03:35:31.610380 IP 192.168.1.170.42707 > 192.168.1.1.53: 43177+ A? inaz2.hatenablog.com. (38)
(snip)
03:35:31.684565 IP 192.168.1.1.53 > 192.168.1.170.42707: 43177 1/0/0 A 52.197.171.58 (54)
(snip)

上の結果から、接続したAndroid端末の通信をキャプチャできていることが確認できる。

注意事項

作成したアクセスポイントは、適切なパスフレーズを設定し、自身の利用においてのみ使用すること。 無断で第三者の通信を取得した場合、不正アクセス禁止法等に抵触するおそれがある。

関連リンク