Tag Archive: router

Dual WAN Load Balancing

Network

In diesem Artikel beschreibe ich Dual WAN Load Balancing im – aber nicht ausschließlich – Round Robin-/(Rundlauf-)Verfahren und optionalen Failover.
Getestet habe ich das Vorgehen unter Debian Wheezy und Ubuntu Server LTS, jedoch lässt es sich bis auf wenige Kleinigkeiten, zum Beispiel die Netzwerkkonfiguration, auf andere Linux-Derivate mit „iproute2“ sinngemäß übertragen.

Die fiktive Umgebung

Zur besseren Übersicht wähle ich folgende Konfiguration:

eth0, SDSL1, Netzwerk 65.10.10.0/24, Adresse 65.10.10.1, Gateway 65.10.10.254, Tabelle „uplink1
eth1, SDSL2, Netzwerk 65.20.20.0/24, Adresse 65.20.20.1, Gateway 65.20.20.254, Tabelle „uplink2
eth2, Internal Link, Netzwerk 192.168.100.0/24, Adresse 192.168.100.1

IPv4-Forwarding setze ich als konfiguriert voraus.

Konfiguration

Zu Beginn definiere ich alternative DNS-Server. Das kann notwendig sein, da ISP1 womöglich nicht auf den DNS-Server des ISP2 zugreifen darf.
Da ich mit der Leistung der Google DNS-Server sehr zufrieden bin, wähle ich diese:

sudo nano /etc/resolv.conf

Und der Inhalt:

nameserver 8.8.8.8
nameserver 8.8.4.4

Sollte ich auf die DNS-Server der ISP bestehen, würde eine Route für die jeweiligen IPs notwendig, damit der Zugriff stets via Gateway des jeweiligen ISP erfolgt.

Eine weitere Möglichkeit wäre ein DNS-Server im internen Netzwerk, etwa via Windows Domain Controller. Hierzu könnte die IP ohne zusätzliche Route als Nameserver definiert werden, da der Zugriff sowieso via eth2 erfolgen würde.
Aber Vorsicht, ist der hier besprochene Router auch für besagten Domain Controller zuständig, stöße dieser schlussendlich auf das selbe Problem, wenn er zum Forwarden die IPs des ISP eingetragen hätte.

Mit einem Editor erstelle ich zwei neue Tabellen für das Routing, die Beschreibung ist individuell wählbar, darf jedoch – selbstverständlich – noch nicht vorhanden sein:

sudo nano /etc/iproute2/rt_tables

Am Ende folgendes einfügen:

201 uplink1
202 uplink2

Die Netzwerkkonfiguration gewohnt via „/etc/network/interfaces“ vornehmen.

sudo nano /etc/network/interfaces

Hier die gesamte Konfiguration inklusive Loopback:

auto lo eth0 eth1 eth2

iface lo inet loopback

iface eth0 inet static
	address 65.10.10.1
	netmask 255.255.255.0
	post-up ip route add 65.10.10.0/24 dev eth0 src 65.10.10.1 table uplink1
	post-up ip rule add from 65.10.10.1 table uplink1
	post-down ip rule del from 65.10.10.1 table uplink1
	
iface eth1 inet static
	address 65.20.20.1
	netmask 255.255.255.0
	post-up ip route add 65.20.20.0/24 dev eth1 src 65.20.20.1 table uplink2
	post-up ip rule add from 65.20.20.1 table uplink2
	post-down ip rule del from 65.20.20.1 table uplink2
	
iface eth2 inet static
	address 192.168.100.1
	netmask 255.255.255.0
	broadcast 192.168.100.255
	network 192.168.100.0
	post-up ip route add default scope global nexthop via 65.10.10.254 dev eth0 weight 1 nexthop via 65.20.20.254 dev eth1 weight 1

Zu sehen ist, dass die Einrichtung von Adresse und Netzwerk gewöhnlich erfolgt. „Post-up“ führt Aktionen aus, nachdem das übergeordnete Interface gestartet wurde. Dies können beinahe beliebige Befehle sein.
Die Reihenfolge der Abarbeitung erfolgt gemäß „auto 1. 2. 3. 4.“ in erster Zeile.

In letzter Zeile des Beispiels, erfolgt das eigentliche Load-Balancing, indem ein Bereich für die Standardroute mit beiden Gateways definiert wird:

ip route add default scope global nexthop via 65.10.10.254 dev eth0 weight 1 nexthop via 65.20.20.254 dev eth1 weight 1

Der „nexthop“ für alle Pakete nach außen, kann nun entweder via SDSL1 oder SDSL2 erfolgen. Durch die Gewichtung „weight 1“ sind beide Wege von gleicher Priorität.
Hinweis: Dieser Befehl kann auch an anderer Stelle ausgeführt werden, die Wahl traf ich eher willkürlich. Natürlich müssen die Links eth0 und eth1 bereits verfügbar sein.

Optional: Gewichtung der Ports

Genauso einfach wie es mutmaßen lässt, ist die Konfiguration zur Bevorzugung eines Weges, einen Haken gibt es dennoch zu beachten.
Letzte Zeile des Beispiels aus „/etc/network/interfaces“, ersetze ich folgendermaßen:

[...]
	post-up ip route add default scope global nexthop via 65.10.10.254 dev eth0 weight 10 nexthop via 65.20.20.254 dev eth1 weight 90
[...]

Im Gegensatz zu simplen numerischen Prioritäten, setzt „weight“ ein Verhältnis. Obiges Beispiel ergäbe demnach 10:90, also 10 Anteile eth0, 90 Anteile eth1.
Eine Aufteilung der Last zu 20% auf eth0 und 80% auf eth1 wäre 20:80, also „weight 20“ für eth0 und „weight 80“ für eth1.

Optional: Testen

Um zuverlässig zu testen, ob das Routing auch die definierte Gewichtung beachtet, reicht eine einfache FOR-Schleife via Bash:

for x in $(seq 1 20)
do
ip r g 1.2.3.$x
done

Hierbei werden die Routen zur jeweiligen IP in der Abfolge 1.2.3.1 bis 1.2.3.20 untereinander angezeigt, für Round Robin etwa:

[...]
1.1.2.4 via 65.10.10.254 dev eth0 src 65.10.10.1
1.1.2.5 via 65.20.20.254 dev eth0 src 65.20.20.1
1.1.2.6 via 65.10.10.254 dev eth0 src 65.10.10.1
1.1.2.7 via 65.20.20.254 dev eth0 src 65.20.20.1
[...]

Optional: Failover

Auf dem Weg durchs Internet stieß ich auf ein nützliches Script (http://fatalsite.net/?p=90, edit: Leider nicht mehr erreichbar.), das ununterbrochen in definiertem Zeitabstand (Standard: 10s) einen Ping via „uplink1“ und „uplink2“ auf eine IP/einen Hostnamen ausführt, dabei eine Auswertung durchführt und je nach Konfiguration des Scripts eine „Route abschaltet“.
Das Script ist gut dokumentiert, daher belasse ich es bei dem Hinweis, helfe aber gerne bei der Einrichtung/Fragen.

Optional: Statische Routen

Eine sich dauernd ändernde IP, könnte diverse (Web-)Dienste irritieren. Abhilfe verschafft eine statische Route, die besagt für Dienst X immer über „uplink1“ (Beispiel) oder „uplink2“ zu gehen:

ip route add Web.Dienst.X.IP via 65.10.10.254

Achtung: Bitte beachten, dass falls Failover via obigem Script ausgeführt wird, dieses zu bearbeiten ist, damit die Routen im Zweifelsfall nicht über den toten Link ins Nirvana geschickt werden. :-)

6to4 Tunnel mit dynamischer IPv4-Adresse

IPv6 (c) crazyengineers.com

Vorwort

Hinweis: Der Artikel ist an vielen Stellen sehr detailliert. Das Wissen dient dem allgemeinen Verständnis, was mir in vielen Artikeln im Internet leider fehlte.

6to4 ist eine einfache Möglichkeit, auch ohne „echte“ Adresse vom ISP IPv6 via IPv4-Tunnel zu verwenden.
Eine 6to4 IPv6-Adresse ist einmalig. Jeder Benutzer mit IPv4-Adresse, besitzt grundsätzlich auch eine IPv6-Adresse/ein Netz.
Das Netz setzt sich folgendermaßen zusammen:
2002:AABB:CCDD::/48
„AABB:CCDD“ habe ich symbolisch für den IPv4-Adressanteil gewählt. Hierzu später mehr.

Im Folgenden werde ich folgende IPv6-Adressen bzw. -Netze konfigurieren. Alles auf Basis von Debian, Ubuntu und weiteren Derivaten:
2002:AABB:CCDD:1::1/64 für den Router
2002:AABB:CCDD:2::/64 als Netz für die Clients

Für die Konfiguration der Clients wähle ich keinen DHCP(v6)-Server, sondern bediene mich an einer Besonderheit des IPv6: Das „Stateless Address Autoconfiguration“ (SLAAC).
SLAAC ist Bestandteil von IPv6 und konfiguriert die Clients in einem Netzwerk automatisch.
Natürlich besteht mit IPv6 weiterhin die Möglichkeit, einen DHCP-Server zu verwenden. Das empfiehlt sich besonders dann, wenn IPv6 DNS-Serveradressen verteilt werden sollen, da SLAAC dies nicht tut!
Warum keine DNS-Server mehr? Mit IPv6/SLAAC wendet man sich immer mehr von der aufwendigen (manuellen) Konfiguration komplexer Netzwerke ab. Garantiert nicht neu, aber im Kommen, ist mDNS. Anfragen zur Namensauflösung werden direkt via Multicast in das Netzwerk gesendet.
Hierauf werde ich nicht weiter eingehen, das ist ein Thema für sich, jedoch möchte ich es im Zusammenhang mit SLAAC nicht unerwähnt lassen.

Die Umrechnung

Eine IPv4-Adresse:
A.B.C.D -> 10.10.10.10
Darstellung in Bit. Ich habe nach jedem 4. Bit ein „|“ gesetzt, um die Umrechnung in Hex genauer aufzuzeigen:
0000|1010 0000|1010 0000|1010 0000|1010
Nun wird jeder 4-Bit Block in Hex umgerechnet:
0|a 0|a 0|a 0|a
Ein Block im IPv6 ist 16 Bit lang, daher fasse ich zusammen:
0a0a:0a0a
IPv6 hat einen 128 Bit großen Adressraum. Das Resultat mit vorangehender „2002“ für den Tunnel mit /48 Subnetz lautet also:
2002:0a0a:0a0a:0000:0000:0000:0000:0000
FFFF:FFFF:FFFF:0000:0000:0000:0000:0000

Die vereinfachte Darstellung unter Auslassung der angereihten 0000er Blocks sowie vorangehenden 0en:
2002:a0a:a0a::/48

Natürlich wird keiner gezwungen, das Netz des Tunnels manuell auszurechnen.
Ohne zusätzliche Tools, lässt sich das Netz für den Tunnel via IP 10.10.10.10 in der Bash errechnen und anzeigen:

printf "2002:%02x%02x:%02x%02x::\n" 10 10 10 10

Ausgabe:
2002:0a0a:0a0a::

Konfiguration des Tunnels

Da mein ISP (Unitymedia) mir eine öffentliche IPv4 via DHCP zuteilt, die sich über die Zeit ändern kann, erstelle ich ein Script, welches die 6to4-Adresse unter Angabe des Interface ausgibt:

sudo nano /usr/local/bin/6to4

Mit Inhalt:

#!/bin/bash
/sbin/ip addr list $1 |grep "inet " |cut -d' ' -f6|cut -d/ -f1

Nun noch als ausführbar markieren:

sudo chmod +x /usr/local/bin/6to4

Mein Netzwerk konfiguriere ich folgendermaßen, das Script ist direkt mit eingebunden:

auto lo eth0 eth1

iface lo inet loopback
iface eth0 inet dhcp
        post-up sleep 5
        post-up /sbin/ifup tun6to4
iface eth1 inet static
        address 192.168.1.254
        netmask 255.255.255.0
        broadcast 192.168.1.255
        network 192.168.1.0
iface tun6to4 inet6 v4tunnel
        address `printf "2002:%02x%02x:%02x%02x:1::1" \`6to4 eth0 | tr . " "\``
        netmask 64
        gateway ::192.88.99.1
        endpoint any
        local `6to4 eth0`
        up ip route add `printf "2002:%02x%02x:%02x%02x:2::/64" \`6to4 eth0 | tr . " "\`` dev eth1
        down ip route del `printf "2002:%02x%02x:%02x%02x:2::/64" \`6to4 eth0 | tr . " "\`` dev eth1

IPv4:
eth0: via DHCP vom ISP; Interface startet automatisch
eth1: 192.168.1.254/24, intern; Interface startet automatisch

IPv6:
tun6to4 (Host, Netz), wie im Vorwort erwähnt:
2002:XXXX:XXXX:0001:0000:0000:0000:0001
FFFF:FFFF:FFFF:FFFF:0000:0000:0000:0000

Also 2002:XXXX:XXXX:1::1/64, wobei XXXX:XXXX der IPv4-Anteil des Interfaces eth0 ist; Interface startet 5 Sekunden nachdem eth0 gestartet wurde, um eth0 Zeit zu geben, eine IPv4 via DHCP zu requesten.

Route:
Zu sehen ist, dass nachdem Interface tun6to4 gestartet wurde, die Route für die Clients in das IPv6-Internet gesetzt wird. Selbstverständlich ist diese Option Pflicht, schließlich befinden sich die Clients in einem anderen Subnetz als der Router.

Was ist ::192.88.99.1?

::192.88.99.1 bzw. 2002:c058:6301:: ist eine Anycast-Adresse, die uns das nächste/am schnellsten antwortende 6to4 Relay mitteilt.
Klingt ungewöhnlich, wenn man vorher noch nie mit IPv6 gearbeitet hat. Hat aber alles seine Richtigkeit.
Um herauszufinden, welcher Relay gerade der nächste ist, kann ich diesen tracen:

traceroute 192.88.99.1

Mir antwortet as6939.dus.ecix.net. Da Unitymedia für Neukunden (so mein letzter Stand) auch nativ IPv6 im Dual-Stack Verfahren anbietet, gibt es dort wohl keine eigenen Relays.

Konfiguration der SLAAC

Zuerst wird der Server zum IPv6-Router promoviert:

sudo nano /etc/sysctl.conf

Folgende Zeile hinzufügen/auf „1“ setzen:

net.ipv6.conf.all.forwarding=1

„Scharf schalten“:

sudo sysctl -p

Fortan ignoriert der Server SLAAC für sich selbst, konfiguriert sich also nicht selber automatisch. Logisch.

Damit an die Clients die Konfiguration ausgegeben werden kann, muss der Server sich im Netzwerk als IPv6-Router ausgeben. Das kann durch „radvd“ eingestellt werden:

sudo apt-get install radvd

Der Router Advertisement Daemon (radvd) startet nach der Installation durch die fehlende Konfiguration nicht automatisch, daher erstelle ich diese:

sudo nano /etc/radvd.conf

Der Inhalt: eth1 ist das Interface, das die physische Verbindung zu den Clients hat, eth0 (weiter unten) mein getunneltes Interface mit der öffentlichen IPv4-Adresse.
prefix 0:0:0:2::/64 bezeichnet das IPv6-Subnetz meiner Clients. Wie beschrieben wähle ich hier die „2“ im vierten Block. Im Subnetz 0:0:0:1::/64 („1“ im vierten Block) befindet sich der Router, das spielt hier keine Rolle.

interface eth1
{
  AdvSendAdvert on;
  MaxRtrAdvInterval 30;
  prefix 0:0:0:2::/64
  {
    Base6to4Interface eth0;
    AdvValidLifetime 300; 
    AdvPreferredLifetime 120;
  };
};

Wichtig: „AdvSendAdvert on“ sagt dem Netz, dass der Server ein Router ist.
Eine Beschreibung der Optionen und weitere Einstellungen finden sich hier: http://linux.die.net/man/5/radvd.conf

Der Dienst kann gestartet werden, nachdem der Tunnel eingeschaltet wurde:

sudo ifup tun6to4
sudo service radvd start

Clients prüfen

Ich wähle als Client einen PC mit Windows 7. IPv6 ist installiert und aktiviert.
Die Verbindung hat sich sofort automatisch konfiguriert:

Windows 7 mit IPv6
Windows 7 mit IPv6

Zu sehen ist, dass die Local Link Adress als mein IPv6 Gateway eingetragen ist, was korrekt ist.
Diese Adresse ist weniger eine IP. Eher vergleichbar ist sie mit einer MAC-Adresse. Sie setzt sich auch aus dieser zusammen.

Hier ein Beispiel:
– MAC-Adresse 00:11:22:33:44:55
Jetzt der mathematische Teil. Ich nehme den ersten Block („00“), schreibe ihn binär nieder und invertiere den siebten Bit:
Hex „00“ ergibt binär „0000 0000“. Der siebte Bit wird invertiert: „0000 0010“. Zurück zu Hex ergibt das „02“.
Die veränderte MAC-Adresse lautet also: 02:11:22:33:44:55. Dem wird nun das Prefix FE80::/64 vorangestellt, was zu diesem (lokalen!) Zweck definiert ist. In der Mitte füge ich FFEF ein:
FE80:0000:0000:0000:0211:22FF:FE33:4455

Wer sich schon mal die Frage stellte, wofür die „Privacy Extension“ des IPv6 da ist, hat die Antwort nun gefunden. In einem nativen IPv6-Netzwerk möchte (fast) keiner seine MAC-Adresse verteilen.
Das spielt in diesem Artikel aber keine Rolle und ist hier nur sehr schwach und oberflächlich zum Verständnis beschrieben. :)

Getestet werden kann im Anschluss noch mit einem Ping auf „ping ipv6.google.com“.
Einen besonderen IPv6 DNS-Server brauche ich hierfür nicht.

Ping ipv6.google.com
Ping ipv6.google.com

Sicherheit!

IPv6 verzichtet im Gegensatz zu IPv4 auf NAT.
Rufe ich die Seite ipv6.whatismyv6.com auf, wird meine vom Router vergebene Adresse angezeigt. Nicht die von dem Router selber.
Grund ist das von IPv6 verwendete Peer-To-Peer Verfahren.
Der Router leitet die Pakete natürlich trotzdem an die Clients weiter, daher findet das altbekannte „iptables“ weiterhin Verwendung. Allerdings in Form von „ip6tables“.
Waren die Clients des klassischen NAT-Routers schon durch die Maskierung relativ sicher vor Angriffen aus dem Internet, darf mit IPv6 auf keinen Fall die Konfiguration/Absicherung via ip6tables vergessen werden.
Das Vorgehen lässt sich beinahe 1:1 übertragen. Ich werde bei Zeit entsprechende Beispiel nachliefern.

Wireless Access-Point mit Hostapd aus dem Git-Repository

Changelog

  • 15. Juli 2014 – Einige Fixes

Vorwort und Umgebung

In diesem Artikel möchte ich die Installation und Konfiguration eines Wireless Access-Points mit Hostapd aus dem Git-Repository unter Verwendung von Debian, Ubuntu und weiteren Derivaten beschreiben.
Als optional erwähne ich die automatische Auswahl des Kanals, welche sich allerdings noch in einem experimentellen Stadium befindet und zudem nur mit bestimmten Chipsets funktionieren kann, jedoch nicht muss.
In dem beschriebenen Fall richte ich einen n-Standard Access-Point via „ath9k_htc“-Gerät ein. Für ac-Netze habe ich entsprechende Kommentare eingefügt.

Hinweis: Die Installation und Konfiguration von NAT, DHCP- und DNS-Forwarder erwähne ich hier nicht. Ich persönlich verwende eine Kombination aus „ISC-DHCP-Server“, „DNSMasq“, „Resolvconf“ und IP Masquerading.

Mein Netzwerk besteht aus 3 physischen Netzwerkadaptern:

auto lo eth0 eth1 wlan0 br0

iface lo inet loopback
iface eth0 inet dhcp
iface eth1 inet manual
iface wlan0 inet manual
iface br0 inet static
    address 192.168.1.254
    netmask 255.255.255.0
    broadcast 192.168.1.255
    bridge_ports eth1 wlan0
    network 192.168.1.0

Kurze Erläuterung:

  • eth0: Öffentlicher Zugang via DHCP vom Cable-Modem
  • eth1: via br0
  • wlan0: via br0
  • br0: Brücke aus eth0 und wlan0, um jeweils verkabelte- und kabellose Clients anzubinden.
Die Verwendung einer Brücke setzt das Paket „bridge-utils“ voraus!

Installation und Konfiguration von Hostapd

Zuerst die Abhängigkeiten installieren:

apt-get build-dep hostapd
apt-get install git iw crda libnl-genl-3-200 libnl-3-200 libssl1.0.0 libssl-dev

Zur Erklärung der Abhängigkeiten, habe ich eine schöne Darstellung zur Arbeitsweise des Hostapd gefunden:
Hostapd Arbeitsweise

Aus dem Git-Repository die Quellen klonen und das Beispiel der Build-Konfiguration kopieren:

mkdir ~/build && cd ~/build
git clone git://w1.fi/srv/git/hostap.git
cd ~/build/hostap/hostapd
cp defconfig .config

Die kopierte Build-Konfiguration anpassen:

nano .config

Folgende Zeilen suchen und ändern. Die erste Option für WLAN n-Standard aktivieren, ac-Standard bei Bedarf.
Hinweis 1: „CONFIG_ACS“ wählt automatisch den günstigsten Channel für das Netz. Allerdings funktioniert dies zur Zeit nur mit ath9k-, ath5k- und ath10k-Chipsets, und selbst mit diesen nur experimentell!
Hinweis 2: Den Schalter „CONFIG_LIBNL32“ nur verwenden, wenn ein System mit einer neueren nl-Lib verwendet wird. Das trifft etwa auf Debian Jessie zu. Ansonsten droht folgender Fehler:

../src/drivers/driver_nl80211.c:19:31: fatal error: netlink/genl/genl.h: No such file or directory
CONFIG_IEEE80211N=y
CONFIG_IEEE80211AC=y
CONFIG_ACS=y # ath9k, ath5k or ath10k may work only! 
CONFIG_LIBNL32=y # only if libnl is >=3.2!

Bauen und nach „/usr/local“ installieren…

make && sudo make install

Es folgt die Konfigurationsdatei für den Hostapd:

sudo nano /etc/hostapd.conf

Untenstehendes einfügen und anpassen. Ich habe einige Optionen kommentiert:

### Bitfield -1, um alle Module zu loggen
logger_syslog=-1
### Log-Level
###  0 = verbose debugging
###  1 = debugging
###  2 = informational messages
###  3 = notification
###  4 = warning
logger_syslog_level=3
### Socket für Interaktion mit Hostapd via CLI etc.
ctrl_interface=/var/run/hostapd
### Der Name des Wifi-Netzes
ssid=MeinWifi
### Channel für das Netz
### ACHTUNG: "0" oder "acs_survey" für automatische Konfiguration. Hinweis oben beachten!
channel=1
### IEEE 802.11n kann nur mit "g" benutzt werden. "n" ist kein eigener Modus!
hw_mode=g
### Der Beacon-Frame teilt u.A. mit, dass "wir" ein AP sind. "100" ist ein guter Standard-Wert. 
### Höhere Werte bringen praktisch kaum/keine Verbesserung der Leistung, können aber zu Fehlern führen.
beacon_int=100
dtim_period=2
### Anzahl der maximalen Clients/Stationen
max_num_sta=20
### "rts_threshold" und "fragm_threshold" sind durch diese Werte deaktiviert.
rts_threshold=2347
fragm_threshold=2346
### Falls macaddr_acl=1, werden nur MAC-Adressen der "accept_mac_file" akzeptiert.  
macaddr_acl=0
### Untereinander aufgelistete MAC-Adressen im Format 00:11:22:33:44:55, falls macaddr_acl=1
#accept_mac_file=/etc/hostapd/accept
auth_algs=1
### WPA2 Konfiguration
wpa=2
wpa_passphrase=meingeheimespasswort
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_pairwise=TKIP CCMP
wpa_group_rekey=600
wpa_ptk_rekey=600
wpa_gmk_rekey=86400
### Physisches Wifi-Gerät und Netzwerkbrücke
interface=wlan0
bridge=br0
### Der Treiber für mac80211 Wifi-Geräte unter Linux
driver=nl80211
ieee80211n=1
### Falls unterstützt, ac-Standard aktivieren:
#ieee80211ac=1
wmm_enabled=1
# Netzwerknamen NICHT verstekcen
ignore_broadcast_ssid=0
# Regionale Einstellungen
country_code=DE
ieee80211d=1

Das Init-Script für Hostapd erstellen:

sudo nano /etc/init.d/hostapd:

Der Inhalt muss nicht weiter angepasst werden. Ich habe das Debian-eigene Init-Script etwas vereinfacht:

#!/bin/bash

### BEGIN INIT INFO
# Provides:             hostapd
# Required-Start:       $remote_fs
# Required-Stop:        $remote_fs
# Should-Start:         $network
# Should-Stop:
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    Advanced IEEE 802.11 management daemon
# Description:          Userspace IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
#                       Authenticator
### END INIT INFO

DAEMON_SBIN=/usr/local/bin/hostapd
DAEMON_CONF=/etc/hostapd.conf
NAME=hostapd
DESC="advanced IEEE 802.11 management"
PIDFILE=/var/run/hostapd.pid

[ -x "$DAEMON_SBIN" ] || exit 0
[ -n "$DAEMON_CONF" ] || exit 0

DAEMON_OPTS="-B -P $PIDFILE $DAEMON_OPTS $DAEMON_CONF"

. /lib/lsb/init-functions

case "$1" in
  start)
        log_daemon_msg "Starting $DESC" "$NAME"
        start-stop-daemon --start --oknodo --quiet --exec "$DAEMON_SBIN" \
                --pidfile "$PIDFILE" -- $DAEMON_OPTS >/dev/null
        log_end_msg "$?"
        ;;
  stop)
        log_daemon_msg "Stopping $DESC" "$NAME"
        start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN" \
                --pidfile "$PIDFILE"
        log_end_msg "$?"
        ;;
  reload)
        log_daemon_msg "Reloading $DESC" "$NAME"
        start-stop-daemon --stop --signal HUP --exec "$DAEMON_SBIN" \
                --pidfile "$PIDFILE"
        log_end_msg "$?"
        ;;
  restart|force-reload)
        $0 stop
        sleep 8
        $0 start
        ;;
  status)
        status_of_proc "$DAEMON_SBIN" "$NAME"
        exit $?
        ;;
  *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload|reload|status}" >&2
        exit 1
        ;;
esac

exit 0

Der Dienst kann sofort installiert-, jedoch noch nicht gestartet werden:

sudo update-rc.d hostapd defaults

CRDA passe ich zum Schluss noch meinen regionalen Vorgaben an:
/etc/default/crda:

...
REGDOMAIN=DE
...

Hostapd testen und starten

Ich empfehle den Hostapd vorab einmal im Debug-Modus zu starten:

sudo hostapd -dd /etc/hostapd.conf

Treten keine Fehler auf, kann das Programm mit STRG+C abgebrochen- und der Dienst anschließend gestartet werden:

sudo service hostapd start

Als kleiner Hinweis noch folgender Artikel, falls für euch relevant: Multicast über Netzwerkbrücke