Wednesday 15 February 2017

Smallest hostap RPi setup

The original 2011 Raspberry Pi model B (rev1) with its 256MB is dwarfed by it's younger siblings now but this can still be used a very cost effective board for projects such as a portable wifi access point.



Whilst this use case is nothing new, trying to create an access point with the smallest SD card sizes can cause a few problems.

So why would you want to create a minimum install on a limited set of equipment? Mostly because thats what was available and secondly because there didn't seem much other modern use for such kit. The kit used for this:
  • RPi model B 256MB, with 100Mbit ethernet and 2x USB ports
  • 512MB SD card
  • Ralink RT5370 compact nano USB dongle
The first challenge was to find a Raspbian OS that would fit on a 512MB card and still have room left over for additional software components such as hostapd to run the wifi access point. The main Raspbian distribution (currently based on Jessie) is offered in a lite version which strips out the X interface but the most recent version is still heavyweight (~2GB) when compared to the target SD card but there are luckly a number of projects that try to provide a stripped down OS: Minibian is such a project. However the most recent Minibian releases are still requirining a 1GB installation media but an older (Feb 2015) release is suitable for our needs: the down side is the older versions of components and the (3.18.7 in this case) kernel that could mean less support for wifi devices.

On examination, the 2015-02-18-wheezy-minibian.img (hosted at SourceForge) is a 488MB disk image when downloaded but inspecting the linux filesystem we find that only 334MB is used. Perfect.
$ fdisk -l 2015-02-18-wheezy-minibian.img
Disk 2015-02-18-wheezy-minibian.img: 488 MiB, 511705088 bytes, 999424 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0004a452

Device Boot Start End Sectors Size Id Type
2015-02-18-wheezy-minibian.img1 16 97727 97712 47.7M b W95 FAT32
2015-02-18-wheezy-minibian.img2 97728 999423 901696 440.3M 83 Linux
$ sudo mount 2015-02-18-wheezy-minibian.img /mnt -o loop,ro,offset=$((512*97728))
$ df -h /mnt
Filesystem Size Used Avail Use% Mounted on
/dev/loop0 419M 334M 60M 85% /mnt
$ sudo umount /mnt
The img was therefore written to the SD card and the RPi booted. This resulted in the first problem: the RPi would start to boot but the kernel would suddenly panic during mounting of the ext4 root filesystem. Inspecting the SD card on another linux box we find that fsck of the partition also compalins about curropt filesystem and that the partition table references past the end of the disk. The last item was the give away that even though the minibian image was created for a 512MB card, not all 512MB SD cards are equal in size!

The fix was relatively easy, having us:
  • deleting the existing ext4 partition
  • creating new partition with the remaining space of card and creating the ext4 fs
  • mounting the minibian image and tar/untar over a pipe the contents of the Linux fs across to our newly created filesystem

Booting with this new SD card image was succesful and we're able to install the relevant components.

Wifi Access Point Components

hostapd is the main component that is required to provide the access point but older vanilla versions do not suppport a number of common wifi chipsets, notably the RealTek (rtl8188 etc) chipsets BUT does support the Ralink RT5370; the version from the Wheeezy archives was 1.0 but latest version does include support RealTek but you would need to compile the code yourself for the Wheezy distro which add complication (and space requirements) for the small SD card.
$ apt-get update ## get a refresh of mirrors
$ apt-get install --no-install-recommends \
hostapd
firmware-ralink
iptables
dnsmasq
iw

The access point will need to be configured alongside a DNS/dhcp service for ease of client-use and then finally NAT rules to fwd packets to/from wifi to ethernet.

# /etc/hostapd/hostapd.conf
interface=wlan0
driver=nl80211

# 'openssl rand -base64 16' if you wnt a random string
ssid=your_wifi_ssid_here

hw_mode=g
channel=1-12
ieee80211n=1
wmm_enabled=1

ht_capab=[HT40][SHORT-GI-20]

macaddr_acl=0

ignore_broadcast_ssid=0

wpa=2
wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256
wpa_passphrase=your_wifi_passwd_here
rsn_pairwise=CCMP

# /etc/dnsmasq.conf
interface=wlan0
listen-address=192.168.100.1
bind-interfaces
server=8.8.8.8
domain-needed
bogus-priv
dhcp-range=192.168.100.10,192.168.100.254,1h

# /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
# iface eth0 inet dhcp
# if we know a network that we intend to use frequently..
iface eth0 inet static
address 10.75.1.1
gateway 10.75.1.254
netmask 255.255.255.0
dns-nameservers 8.8.8.8

auto wlan0
iface wlan0 inet static
address 192.168.100.1
netmask 255.255.255.0
network 192.168.100.0
broadcast 192.168.100.255
dns-nameservers 8.8.8.8
wireless-power off
#pre-up macchanger -r wlan0

# /etc/rc.local
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT

exit 0

And finally, enable IPv4 packaet forwarding at the system level
# sysctl.conf
net.ipv4.ip_forward=1


Once all the above is in place, enabling (and starting) the hostapd and dnsmasq will provide you access to the new AP and running the iptables rules will enable the RPi to actually route wifi traffic to/from your ethernet.

Additionally, if you wish to spoof the MAC address on eth0 you can do so as follows:
# /boot/cmdline.txt
smsc95xx.macaddr=xx:xx:xx:xx:xx:xx
Unfortunately there are some particularities that means macchaner does not work for the RPi ethernet device.

The wifi access point runs relatively smoothly even when there are multiple stations associated. Obviously the network throughput is restricted by the 100Mbit ethernet device and the underlying network but having a tablet streaming YouTube video and 2 other devices browsing the internet gave only brief shots of delay at the client side. Examining the RAM usage, 182864/234612 is free (hostapd consuming less than 2% of RAM) but load average is 02. Trying to ssh into the RPi does appear to take a little longer than normal though but once on, there is no noticable slowness.

Additional Components and clean ups

After the AP is configured, we will find that the 512MB card is getting fairly full and edging past 90%. We can clean up some space by removing additional locales which will give us sufficient space for some additional components:
$ apt-get install localepurge
$ apt-get autopurge
$ apt-get clean
$ apt-get install --no-install-recommends \
lighttpd
macchanger
tcpdump
arp-scan
sudo
nfs-common
wireless-tools usbutils nmap


Management of Target Ethernet Address

Unless we enable dhcp, the IP address of the ethernet has to be known - if we are using our RPi setup in a roaming/portable capacity we will not have a machine handy to ssh onto the RPi to adjust the ethernet address.

A more sensible method would be to provide a web page (hence the installation of lighttpd and sudo) that allows the user to update the address - the user would be able to update the host eth0 IP and gateway address and this would be possible because the wifi client (station) will be associated with our AP (hostapd) which itself has an IP address: the wifi client would therefore use the AP ip address and reach the webserver that way.



Once the IP/gw address is entered, the webserver will run a cgi script to manually update:
#!/bin/bash
echo -e "Content-type: text/html\n\n"
...
# handle post/get http params
...

if [ "${form_ip}" == "${form_gw}" ]; then
    echo "ERROR: $form_ip - IP and GW address are the same"
    exit 1
fi

# doesnt stop .999 address for being requested or .0
echo ${form_ip} | grep -q -E "^([0-9]{1,3}\.){3}[0-9]{1,3}$" 
if [ $? -ne 0 ]; then
    echo "ERROR: $form_ip - invalid IPv4 host address"
    exit 1
fi

echo ${form_gw} | grep -q -E "^([0-9]{1,3}\.){3}[1-9]{1,3}$"
if [ $? -ne 0 ]; then
    echo "ERROR: $form_gw - invalid IPv4 gateway address"
    exit 1
fi

ETH=eth0
echo "updating IP address=$form_ip on $ETH, default gw=${form_gw}"
sudo ifconfig ${ETH} ${form_ip} 
if [ $? -ne 0 ]; then
    echo "failed to update host ip"
    exit 1
fi
sudo route del default
sudo route add default gw ${form_gw}
if [ $? -ne 0 ]; then
    echo "failed to update gateway"
    exit 1
fi

cat <<EOF
$(ifconfig ${ETH})
$(route -n)
$(sudo arp-scan -l -I ${ETH})
EOF
There are probably enhancements that can be made, particularly providing a way to determine the current subnet of the ethernet segment and corresponding gateway so we can plug into any ethernet and then set our ethernet IP details accordingly but this is outside the scope of this right now - we are expecting that if you are plugging into an ethernet you can obtain the IP/subnet/gateway information from the network owner. Shutting down the RPi when finished is also available via a web page backed by a cgi script - it may seem that this would be a security whole but this would require anyone to be associated with the AP (need the WPA2 passwd) but given that the RPi is hanging off an ethernet cable, anyone who really wanted to kill the RPi would be able to do so physically anyway.

Conclusions

Finally, adding a few admin scripts we find our system:
$ df -h Filesystem Size Used Avail Use% Mounted on rootfs 413M 286M 101M 74% / /dev/root 413M 286M 101M 74% / devtmpfs 111M 0 111M 0% /dev tmpfs 23M 224K 23M 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 46M 0 46M 0% /run/shm /dev/mmcblk0p1 48M 15M 34M 30% /boot tmpfs 46M 0 46M 0% /tmp

So whilst it may be a lot easier putting together a portable wifi access point with a newer RPi and Rapsbian Lite we have shown it is possible to do it with older equipment.

No comments:

Post a Comment