Banana Pi als WLAN & LAN Router einrichten

Ich habe mir vor Kurzem einen BananaPi bestellt und wollte diesen probeweise als WLAN & LAN Router einrichten, wobei WLAN und LAN sich gemeinsam ein Netzwerk teilen.

Mit den Programmen hostapd, dnsmasq und Arch-Linux lässt sich das ohne größere Schwierigkeiten umsetzen.

Hardware & Betriebssystem

Wie schon angedeutet, handelt es sich um ein Banana Pi. Das Ding ist so ähnlich wie ein Raspberry Pi, nur kommt es mit einer DualCore CPU und 1 GB RAM, sowie einer 1GBit Netzwerkschnitstelle.

Die Wahl des Betriebssystems fiel auf das Arch Linux v2.0 Image. Dieses kann man, wie gewohnt, einfach herunterladen und auf die SD Karte spielen.

Des Weiteren benötigt man noch einen USB-Ethernet Adapter, sowie einen USB-WLAN Adapter. Die folgenden Produkte hatte ich bei mir noch rumliegen und können out-of-the-box genutzt werden.

  • LogiLink UA0025C
  • TP Link TL-WN722N

Ziel

Wenn wir die folgende Konfiguration annehmen:

  • eth0 : Schnittstelle zum Internet (WAN)
  • eth1 : Schnittstelle zum LAN
  • wlan0 : Schnittstelle zum WLAN

Dann möchten wir folgendes Setup erreichen:

  • eth0 bekommt seine IP per DHCP
  • eth1 & wlan0 teilen sich das Subnet 192.168.4.0/24
  • Die IPs aus dem Subnet werden per DHCP verteilt
  • Dem Subnet wird ein DNS Server zur Verfügung gestellt

Um das zu erreichen, werden wir das Setup in drei größere Konfigurationsabschnitte unterteilen:

  • Netzwerkschnittstellen konfigurieren (systemd-networkd)
  • Iptables konfigurieren
  • Dnsmasq & Hostapd konfigurieren

Kernel vs. Systemd

Die Kernelversion des Images ist bisher bei 3.4.x stehen geblieben. Jedoch werden die Systemd Pakete weiter aktualisiert. Ab systemd-216 führt dies zu Problemen beim Laden von Treibern. Systemd erwartet, dass der Kernel diese Funktion übernimmt, jedoch ist diese in dieser älteren Version noch nicht implementiert.

Folgende Fehler können auf dieses Problem hinweisen:

[ 119.592292] usb 1-1.2: ath9k_htc: Firmware htc_9271.fw requested
[ 180.172266] usb 1-1.2: ath9k_htc: Failed to get firmware htc_9271.fw
[ 180.302130] usb 1-1.2: ath9k_htc: USB layer deinitialized

Natürlich sollte die Datei „htc_9271.fw“ in „/lib/firmware“ bzw. „/usr/lib/firmware“ vorhanden sein.

Die Lösung des Problems besteht darin, dass man Updates für folgende drei Pakete zurückhält:

  • libsystemd
  • systemd
  • systemd-sysvcompat

Diese drei Paketenamen trägt man hinter „IgnorePkg=“ in der „/etc/pacman.conf“ ein.

Danach kann man sich von Archlinux-Rollback die drei Pakete in der Version „216-3“ herunterladen und mittels „pacman -U <Paket>“ installieren.

Netzwerkschnittstellen konfigurieren

Der erste Schritt besteht darin dem System mitzuteilen, wie wir unsere Interfaces konfiguriert haben möchten. Ein Interface soll eine dynamische IP haben und die zwei verbleibenden Schnittstellen sollen ein virtuelles Device bilden.

Hierzu stellen wir erstmal sicher, dass die Voraussetzungen gegeben sind, in dem wir „systemd-networkd“ aktivieren und „netctl“ (ggf. andere Netzwerkmanager) deaktivieren.

systemctl enable systemd-networkd
systemctl stop netctl
systemctl disable netctl

Für die dynamischen IP Adressen benötigen wir dann noch das Paket „dhcpcd“ und entsprechend den aktivierten Dienst:

pacman -S dhcpcd
systemctl enable dhcpcd.service
systemctl start dhcpcd.service

Als nächstes wechselt man in das Verzeichnis „/etc/systemd/network/“. Dort legen wir die Datei für unser WAN-Interface an. Die Datei nennt man „eth0.network“.

[Match]
Name=eth0

[Network]
DHCP=yes

Als nächstes ist unser WLAN-Device dran. Dieses bekommt keine IP zugewiesen, da sich hostapd darum kümmern wird. Die Datei „wlan0.network“ enthält folgendes:

[Match]
Name=wlan0

[Network]
DHCP=no

Als nächstes definieren wirin der Datei „br0.netdev“ die virtuelle Netzwerkbrücke:

[NetDev]
Name=br0
Kind=bridge

Dieser weisen wir unser Subnetz zu (br0.network):

[Match]
Name=br0

[Network]
Address=192.168.4.1/24
DHCP=no

Zuletzt wird noch direkt unser LAN-Interface an die virtuelle Netzwerkschnittstelle gebunden (eth1.network):

[Match]
Name=eth1

[Network]
Bridge=br0

Nun sollte die Konfiguration soweit abgeschlossen sein. Das lässt sich so überprüfen:

systemctl restart systemd-networkd #Netzwerk neustarten

Die Ausgabe von „ip a s“ sollte so ähnlich aussehen:

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
 link/ether 02:86:08:82:75:2e brd ff:ff:ff:ff:ff:ff
 inet 192.168.2.208/24 brd 192.168.2.255 scope global eth0

4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UNKNOWN group default qlen 1000
 link/ether 00:60:6e:42:57:d9 brd ff:ff:ff:ff:ff:ff

5: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br0 state UP group default qlen 1000
 link/ether f8:1a:67:17:66:e5 brd ff:ff:ff:ff:ff:ff

6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
 link/ether 00:60:6e:42:57:d9 brd ff:ff:ff:ff:ff:ff
 inet 192.168.4.1/24 brd 192.168.4.255 scope global br0

Wie man sieht, hat eth0 automatisch eine IP von meinem Router bekommen. Das virtuelle Interface br0 hat das Subnetz 192.168.4.1/24 zugewiesen bekommen. Eth0 ist bereits ein Teil vom virtuellen Interface.

Iptables konfigurieren

Damit der Traffic nicht unkontrolliert zwischen den Interfaces fließt bzw. das NAT konfiguriert werden kann, müssen die Iptables genutzt werden.

Normalerweise sind diese schon installiert. Ansonsten muss man das gleichnamige Paket nachinstallieren.

Die im Arch Wiki vorgestellte Konfiguration sieht ungefähr so aus:

# Generated by iptables-save v1.4.21 on Sat Feb 28 02:05:21 2015
*nat
:PREROUTING ACCEPT [5:231]
:INPUT ACCEPT [1:61]
:OUTPUT ACCEPT [2:122]
:POSTROUTING ACCEPT [2:122]
-A POSTROUTING -s 192.168.4.0/24 -o eth0 -j MASQUERADE
COMMIT
# Completed on Sat Feb 28 02:05:21 2015
# Generated by iptables-save v1.4.21 on Sat Feb 28 02:05:21 2015
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [55:4554]
:TCP - [0:0]
:UDP - [0:0]
:fw-interfaces - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j fw-interfaces
-A FORWARD -j REJECT --reject-with icmp-host-unreachable
-A TCP -p tcp -m tcp --dport 22 -j ACCEPT
-A TCP -i br0 -p tcp -m tcp --dport 53 -j ACCEPT
-A TCP -i br0 -p tcp -m tcp --dport 67 -j ACCEPT
-A UDP -i br0 -p udp -m udp --dport 53 -j ACCEPT
-A UDP -i br0 -p udp -m udp --dport 67 -j ACCEPT
-A fw-interfaces -i br0 -j ACCEPT
COMMIT
# Completed on Sat Feb 28 02:05:21 2015

Das speichert man sich in „/etc/iptables/iptables.rules“ und lädt die Regeln neu:

systemctl restart iptables.service
systemctl enable iptables.service

Die Iptables kann man bei diesem Schritt direkt für den Autostart markieren.

Die Regeln sind so aufgebaut, dass in der Input-Chain der Traffic in UDP/TCP unterteilt wird. In diesen Unter-Chains kann man dann Traffic zulassen oder ablehnen. Wir werden später udp/tcp Port 53,67 nutzen, um darüber DHCP/DNS zu verschicken.

Die Forward-Chain „fw-interfaces“ regelt, von welchen Netzwerken Traffic wohin weitergeleitet werden darf. Hier sagen wir ganz grob, dass alles vom br0 weitergeleitet werden darf.

Ansonsten kümmert sich das conntrack-Modul um die Verwaltung der Verbindungen, in dem es die Pakete zu einer „neuen/ähnlichen/verbundenen“ Verbindung zugeordnet wird.

Ganz wichtig ist die POSTROUTING-Regel im oberen Bereich. Diese kümmert sich um das NAT, in dem alle ausgehenden Pakete vom Subnetz 192.168.4.0/24 die IP vom eth0 verpasst bekommen.

Eine relativ gute Übersicht über alle Regeln bekommt man mit:

sudo iptables -L -vn

Zusätzlich muss das IP-Forwarding im System aktiviert werden:

sudo sysctl -w net.ipv4.ip_forward=1

Dnsmasq & Hostapd konfigurieren

Kommen wir nun zum letzten Teil. Zunächst installieren wir die nötigen Pakete:

sudo pacman -S dnsmasq hostapd

Dnsmasq ist ein kleiner DHCP/DNS Server und hostapd ein Tool zum Erstellen von Access Points.

Dnsmasq

Für Dnsmasq editieren wir die Datei „/etc/dnsmasq.conf“ und setzen dort diese Optionen:

interface=br0
dhcp-range=192.168.4.100,192.168.4.200,24h

Für einen erfolgreichen Betrieb reichen die o.g. Einstellungen aus. Allerdings sollte man sich die Konfigurationsdatei durchlesen, um ggf. Sicherheitsvorkehrungen zu treffen oder weitere Features zu aktivieren.

Mit der ersten Zeile wird festgelegt, dass nur Anfragen vom Interface br0 verarbeitet werden. Die zweite Zeile legt den zu vergebenden IP-Bereich bzw. die Leasetime fest.

Danach muss man dnsmasq neustarten und im Autostart verankern:

systemctl enable dnsmasq.service
systemctl restart dnsmasq.service

Hostapd

Auch hier müssen wir eine Konfigurationsdatei bearbeiten. Beispiele und eine ausführliche Dokumentation finden sich diesmal hier: „/usr/share/doc/hostapd/*“

Die Einstellungen landen dann in der „/etc/hostapd/hostapd.conf“. Diese kann zum Beispiel so aussehen:

interface=wlan0
bridge=br0
driver=nl80211
ssid=PiWiFi
channel=1
ignore_broadcast_ssid=0
country_code=DE
ieee80211d=1
hw_mode=g
beacon_int=100
dtim_period=2
macaddr_acl=0
max_num_sta=20
rts_threshold=2347
fragm_threshold=2346
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
dump_file=/tmp/hostapd.dump
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
auth_algs=3
wmm_enabled=0
wpa=2
rsn_preauth=1
rsn_preauth_interfaces=wlan0
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_group_rekey=600
wpa_ptk_rekey=600
wpa_gmk_rekey=86400
wpa_passphrase=DASPASSWORT!

Wichtig hierbei ist nur, dass der „Interface=wlan0“ und der „Bridge=br0“ Eintrag vorhanden sind.

Zuletzt muss hostapd noch neugestartet und im Autostart verankert werden:

systemctl restart hostapd.service
systemctl enable hostapd.service

Abschließende Worte

Das von uns definierte Ziel ist nun erreicht. Wir haben einen funktionierenden kleinen Router.

Ich hatte noch probiert „traffic shaping“ umzusetzen, jedoch schien das der Treiber bzw. der Kernel nicht zu unterstützen.

~ Sebastian