This blog post, written by Márton Juhász, is the fifth in a series of blog posts on transforming the Raspberry Pi into a security enhanced IoT platform. This post specifically will explain how to convert the Raspberry Pi into a WiFi access point such that it can perform some gateway-like functionality. First, we describe how to enable WiFi and then how to enable other software components to make the Pi an access point.

Enabling Wi-Fi

In this subsection, we enable the Wi-Fi interface of the Raspberry Pi 3, so it will be able connect to any Wi-Fi networks.

1. Buildroot build options

By default Wi-Fi is not enabled when creating an image with Buildroot. Since the Wi-Fi components come up a little late, dynamic hardware configuration tools, such as hotplug, must be used. Buildroot supports mdev which can be built into the filesystem and used for those required dynamic hardware configurations.

These are the options to set:

  • BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV: Allows the Broadcom wireless driver to be automatically loaded on boot. Set System configuration -> /dev management -> Dynamic using devtmpfs + mdev (BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV = y).

  • BR2_PACKAGE_RPI_WIFI_FIRMWARE: Raspberry Pi 3 and Zero W Broadcom BCM43430 wifi module NVRAM data (https://github.com/RPi-Distro/firmware-nonfree/). Check Target packages -> Hardware handling -> Firmware -> rpi-wifi-firmware (BR2_PACKAGE_RPI_WIFI_FIRMWARE = y).

  • BR2_PACKAGE_WPA_SUPPLICANT: WPA supplicant for secure wireless networks (http://w1.fi/wpa_supplicant/). wpa_supplicant must be installed to help connect to networks. Check Target packages -> Networking applications -> wpa_supplicant (BR2_PACKAGE_WPA_SUPPLICANT = y).

  • BR2_PACKAGE_WPA_SUPPLICANT_NL80211: Enable support for nl80211. This is the current wireless API for Linux, supported by all wireless drivers in vanilla Linux, but may not be supported by some out-of-tree Linux wireless drivers. wpa_supplicant will still fall back to using the Wireless Extensions (wext) API with these drivers. If this option is disabled, then only the deprecated wext API will be supported, with far less features. Linux may support wext with modern drivers using a compatibility layer, but it must be enabled in the kernel configuration. Check Target packages -> Networking applications -> wpa_supplicant -> Enable nl80211 support (BR2_PACKAGE_WPA_SUPPLICANT_NL80211 = y).

  • BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE: Install wpa_passphrase command line utility. This is optional, only needed if you want to connect to other Wi-Fi networks than the originally choosen one without the help of another machine (or if you don’t have wpa_passphrase on your build system). Check Target packages -> Networking applications -> wpa_supplicant -> Install wpa_passphrase binary (BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE = y).

2. wpa_supplicant

Create a file, named interfaces in buildroot/board/raspberrypi/ (all the other raspberrypi* are symlinks to this folder). The auto wlan0 will make sure that wlan0 is started when ifup -a is run, wich is done by the init scripts.

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
    pre-up /etc/network/nfs_check
    wait-delay 15

auto wlan0
iface wlan0 inet dhcp
    pre-up wpa_supplicant -B -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf
    post-down killall -q wpa_supplicant
    wait-delay 15

iface default inet dhcp

Create another file, named wpa_supplicant.conf with wpa_passphrase in buildroot/board/raspberrypi/ (all the other raspberrypi* are symlinks to this folder). It should look like something like this:

network={
    ssid="SSID"
    #psk="PASSWORD"
    psk=XXX
}

3. post-build.sh

The hotplug helper must be set as mdev and write /etc/mdev.conf file. The mdev package itself has some helper script for this and can be used directly. Also the above created files must be copied, so add the following lines to buildroot/board/raspberrypi/post-build.sh:

cp package/busybox/S10mdev ${TARGET_DIR}/etc/init.d/S10mdev
chmod 755 ${TARGET_DIR}/etc/init.d/S10mdev
cp package/busybox/mdev.conf ${TARGET_DIR}/etc/mdev.conf

cp board/raspberrypi3/interfaces ${TARGET_DIR}/etc/network/interfaces
cp board/raspberrypi3/wpa_supplicant.conf ${TARGET_DIR}/etc/wpa_supplicant.conf

Making a Wi-Fi AP

With these additional steps the Wi-Fi interface of the Raspberry Pi 3 can work as a Wi-Fi AP. These depend on the steps in the previous part (Enabling WiFi), so first follow those before continuing here.

1. Buildroot build options

The following must be set before a system build, alongside with the other configuration settings in Buildroot.

  • If the hardening option Build options -> RELRO Protection -> Full (BR2_RELRO_FULL = y) is set, set to Partial (BR2_RELRO_PARTIAL = y), otherwise the build will fail.

  • BR2_PACKAGE_BUSYBOX_SHOW_OTHERS: Show packages in menuconfig that are potentially also provided by busybox. Some of the packages that are needed are provided by busybox and if the following option is not selected, necessary packages will not appear in the package list. Check Target packages -> BusyBox -> Show packages that are also provided by busybox. (BR2_PACKAGE_BUSYBOX_SHOW_OTHERS = y)

  • BR2_PACKAGE_DHCP: DHCP relay agent from the ISC DHCP distribution http://www.isc.org/products/DHCP. Check Target packages -> Networking applications -> dhcp (ISC). (BR2_PACKAGE_DHCP = y)

  • BR2_PACKAGE_DHCP_SERVER: DHCP server from the ISC DHCP distribution. Check Target packages -> Networking applications -> dhcp (ISC) -> dhcp server. (BR2_PACKAGE_DHCP_SERVER = y)

  • BR2_PACKAGE_DHCP_SERVER_DELAYED_ACK: Enable delayed ACK feature in the ISC DHCP server. Check Target packages -> Networking applications -> dhcp (ISC) -> dhcp server -> Enable delayed ACK feature. (BR2_PACKAGE_DHCP_SERVER_DELAYED_ACK = y)

  • BR2_PACKAGE_DHCP_RELAY: DHCP relay agent from the ISC DHCP distribution. Check Target packages -> Networking applications -> dhcp (ISC) -> dhcp relay. (BR2_PACKAGE_DHCP_RELAY = y)

  • BR2_PACKAGE_DHCP_CLIENT: DHCP client from the ISC DHCP distribution. Check Target packages -> Networking applications -> dhcp (ISC) -> dhcp client. (BR2_PACKAGE_DHCP_CLIENT = y)

  • BR2_PACKAGE_DHCPCD: An RFC2131 compliant DHCP client http://roy.marples.name/projects/dhcpcd/. Check Target packages -> Networking applications -> dhcpcd.(BR2_PACKAGE_DHCPCD = y)

  • BR2_PACKAGE_IPTABLES: Linux kernel firewall, NAT, and packet mangling tools http://www.netfilter.org/projects/iptables/index.html. Check Target packages -> Networking applications -> iptables. (BR2_PACKAGE_IPTABLES = y)

  • BR2_PACKAGE_IPTABLES_BPF_NFSYNPROXY: Build bpf compiler and nfsynproxy configuration tool. Check Target packages -> Networking applications -> iptables -> bpfc and nfsynproxy. (BR2_PACKAGE_IPTABLES_BPF_NFSYNPROXY = y)

  • BR2_PACKAGE_IPTABLES_NFTABLES: Build nftables compat utilities. Check Target packages -> Networking applications -> iptables -> nftables compat. (BR2_PACKAGE_IPTABLES_NFTABLES = y)

  • BR2_PACKAGE_WPA_SUPPLICANT_AP_SUPPORT: With this option enabled, wpa_supplicant can act as an access point much like hostapd does with a limited feature set. This links in parts of hostapd functionality into wpa_supplicant, making it bigger but dispensing the need for a separate hostapd binary in some applications hence being smaller overall. Check Target packages -> Networking applications -> wpa_supplicant -> Enable AP mode. (BR2_PACKAGE_WPA_SUPPLICANT_AP_SUPPORT = y)

2. wpa_supplicant

Edit buildroot/board/raspberrypi/interfaces (all the other raspberrypi* are symlinks to this folder). Now the network must be configured manually. The settings here must match with the settings in dhcpd.conf (below).

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
    pre-up /etc/network/nfs_check
    wait-delay 15

auto wlan0
iface wlan0 inet static
    address 192.168.2.1
    netmask 255.255.255.0
    network 192.168.2.0
    gateway 192.168.2.1
    pre-up wpa_supplicant -B -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf
    post-down killall -q wpa_supplicant
    wait-delay 15

iface default inet dhcp

Edit buildroot/board/raspberrypi/wpa_supplicant.conf (all the other raspberrypi* are symlinks to this folder). mode=2 is Access Point mode, and the other settings are for WPA2-PSK. Change the weak psk value of “12345678” to some strong password!

network={
    ssid="RPi3B"
    mode=2
    proto=RSN
    key_mgmt=WPA-PSK
    pairwise=CCMP TKIP
    group=CCMP TKIP
    psk="12345678"
}

3. dhcpd.conf

Create a file, named dhcpd.conf in buildroot/board/raspberrypi/ (all the other raspberrypi* are symlinks to this folder). Below is a modified default /etc/dhcp/dhcpd.conf file which we changed as follows:

  • Commented the following lines:

    #option domain-name "example.org"; #option domain-name-servers ns1.example.org, ns2.example.org;

  • Uncommented the following line:

    authoritative;

  • And of course, uncommented lines at the end of the file.

This is the full config:

#
# Sample configuration file for ISC dhcpd for Debian
#
# $Id: dhcpd.conf,v 1.1.1.1 2002/05/21 00:07:44 peloy Exp $
#

# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;

# option definitions common to all supported networks...
#option domain-name "example.org";
#option domain-name-servers ns1.example.org, ns2.example.org;

default-lease-time 600;
max-lease-time 7200;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# No service will be given on this subnet, but declaring it helps the 
# DHCP server to understand the network topology.

#subnet 10.152.187.0 netmask 255.255.255.0 {
#}

# This is a very basic subnet declaration.

#subnet 10.254.239.0 netmask 255.255.255.224 {
#  range 10.254.239.10 10.254.239.20;
#  option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
#}

# This declaration allows BOOTP clients to get dynamic addresses,
# which we don't really recommend.

#subnet 10.254.239.32 netmask 255.255.255.224 {
#  range dynamic-bootp 10.254.239.40 10.254.239.60;
#  option broadcast-address 10.254.239.31;
#  option routers rtr-239-32-1.example.org;
#}

# A slightly different configuration for an internal subnet.
#subnet 10.5.5.0 netmask 255.255.255.224 {
#  range 10.5.5.26 10.5.5.30;
#  option domain-name-servers ns1.internal.example.org;
#  option domain-name "internal.example.org";
#  option routers 10.5.5.1;
#  option broadcast-address 10.5.5.31;
#  default-lease-time 600;
#  max-lease-time 7200;
#}

# Hosts which require special configuration options can be listed in
# host statements.   If no address is specified, the address will be
# allocated dynamically (if possible), but the host-specific information
# will still come from the host declaration.

#host passacaglia {
#  hardware ethernet 0:0:c0:5d:bd:95;
#  filename "vmunix.passacaglia";
#  server-name "toccata.fugue.com";
#}

# Fixed IP addresses can also be specified for hosts.   These addresses
# should not also be listed as being available for dynamic assignment.
# Hosts for which fixed IP addresses have been specified can boot using
# BOOTP or DHCP.   Hosts for which no fixed address is specified can only
# be booted with DHCP, unless there is an address range on the subnet
# to which a BOOTP client is connected which has the dynamic-bootp flag
# set.
#host fantasia {
#  hardware ethernet 08:00:07:26:c0:a5;
#  fixed-address fantasia.fugue.com;
#}

# You can declare a class of clients and then do address allocation
# based on that.   The example below shows a case where all clients
# in a certain class get addresses on the 10.17.224/24 subnet, and all
# other clients get addresses on the 10.0.29/24 subnet.

#class "foo" {
#  match if substring (option vendor-class-identifier, 0, 4) = "SUNW";
#}

#shared-network 224-29 {
#  subnet 10.17.224.0 netmask 255.255.255.0 {
#    option routers rtr-224.example.org;
#  }
#  subnet 10.0.29.0 netmask 255.255.255.0 {
#    option routers rtr-29.example.org;
#  }
#  pool {
#    allow members of "foo";
#    range 10.17.224.10 10.17.224.250;
#  }
#  pool {
#    deny members of "foo";
#    range 10.0.29.10 10.0.29.230;
#  }
#}

subnet 192.168.2.0 netmask 255.255.255.0 {
  range 192.168.2.10 192.168.2.50;
  option broadcast-address 192.168.2.255;
  option routers 192.168.2.1;
  default-lease-time 600;
  max-lease-time 7200;
  option domain-name "local";
  option domain-name-servers 8.8.8.8, 8.8.4.4;
}

4. post-build.sh

The hotplug helper must be set as mdev and write /etc/mdev.conf file. The mdev package itself has some helper script for this and can be used directly. Also the above created files must be copied, so add the following lines to buildroot/board/raspberrypi/post-build.sh:

cp package/busybox/S10mdev ${TARGET_DIR}/etc/init.d/S10mdev
chmod 755 ${TARGET_DIR}/etc/init.d/S10mdev
cp package/busybox/mdev.conf ${TARGET_DIR}/etc/mdev.conf

cp board/raspberrypi3/interfaces ${TARGET_DIR}/etc/network/interfaces
cp board/raspberrypi3/wpa_supplicant.conf ${TARGET_DIR}/etc/wpa_supplicant.conf
cp board/raspberrypi3/dhcpd.conf ${TARGET_DIR}/etc/dhcp/dhcpd.conf

5. sysctls

This sysctl must be set after each boot. So create a file, named sysctl.conf, and copy to /etc/ on the root partition of the memory card:

# Enable IP forwarding.
net.ipv4.ip_forward = 1

The scripts in /etc/init.d/ run after each boot and before each shutdown. The following script is responsible for setting the sysctls above. So create another, executable file, named S02procps, and copy to /etc/init.d/ on the root partition of the memory card:

#! /bin/sh
if [ "$1" == "start" ]; then
    sysctl -p
fi

6. Firewall settings

The following script is responsible for setting up the firewall. So create another executable file, named S99firewall, and copy to /etc/init.d/ on the root partition of the memory card:

#! /bin/sh
if [ "$1" == "start" ]; then
    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    iptables -P FORWARD DROP
    iptables -A FORWARD -i eth0 -o wlan0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
    iptables -P INPUT DROP
    iptables -A INPUT -i eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i wlan0 -j ACCEPT
fi

Sources

  • Buildroot’s configuration menu’s Help
  • http://www.walavalkar.co.in/home/buildingalinuxfilesystemonraspberrypi3
  • http://www.walavalkar.co.in/home/wirelessrouterwithbuildrootandraspberrypi3
  • http://blog.hoxnox.com/gentoo/wifi-hotspot.html
  • https://wiki.gentoo.org/wiki/Wpa_supplicant
  • https://www.swiftstack.com/docs/install/configure_networking.html
 

Leave a Reply