diff --git a/docker-ap/Dockerfile b/docker-ap/Dockerfile new file mode 100644 index 0000000..be62b82 --- /dev/null +++ b/docker-ap/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine + +MAINTAINER Jaka Hudoklin + +RUN apk add --no-cache bash hostapd iptables dhcp docker iproute2 iw +RUN echo "" > /var/lib/dhcp/dhcpd.leases +ADD wlanstart.sh /bin/wlanstart.sh + +ENTRYPOINT [ "/bin/wlanstart.sh" ] diff --git a/docker-ap/README.md b/docker-ap/README.md new file mode 100644 index 0000000..4403254 --- /dev/null +++ b/docker-ap/README.md @@ -0,0 +1,82 @@ +# Docker container stack: hostap + dhcp server + +This container starts wireless access point (hostap) and dhcp server in docker +container. It supports both host networking and network interface reattaching +to container network namespace modes (host and guest). + +## Requirements + +On the host system install required wifi drivers, then make sure your wifi adapter +supports AP mode: + +``` +# iw list +... + Supported interface modes: + * IBSS + * managed + * AP + * AP/VLAN + * WDS + * monitor + * mesh point +... +``` + +Set country regulations, for example, for Spain set: + +``` +# iw reg set ES +country ES: DFS-ETSI + (2400 - 2483 @ 40), (N/A, 20), (N/A) + (5150 - 5250 @ 80), (N/A, 23), (N/A), NO-OUTDOOR + (5250 - 5350 @ 80), (N/A, 20), (0 ms), NO-OUTDOOR, DFS + (5470 - 5725 @ 160), (N/A, 26), (0 ms), DFS + (57000 - 66000 @ 2160), (N/A, 40), (N/A) +``` + +## Build / run + +* Using host networking: + +``` +sudo docker run -i -t -e INTERFACE=wlan1 -e OUTGOINGS=wlan0 --net host --privileged won10/hostapd +``` + +* Using network interface reattaching: + +``` +sudo docker run -d -t -e INTERFACE=wlan0 -v /var/run/docker.sock:/var/run/docker.sock --privileged offlinehacker/docker-ap +``` + +This mode requires access to docker socket, so it can run a short lived +container that reattaches network interface to network namespace of this +container. It also renames wifi interface to **wlan0**, so you get +deterministic networking environment. This mode can be usefull for example for +pentesting, where can you use docker compose to run other wifi hacking tools +and have deterministic environment with wifi interface. + +## Environment variables + +* **INTERFACE**: name of the interface to use for wifi access point (default: wlan0) +* **OUTGOINGS**: outgoing network interface (default: eth0) +* **CHANNEL**: WIFI channel (default: 6) +* **SUBNET**: Network subnet (default: 192.168.254.0) +* **AP_ADDR**: Access point address (default: 192.168.254.1) +* **SSID**: Access point SSID (default: docker-ap) +* **WPA_PASSPHRASE**: WPA password (default: passw0rd) +* **HW_MODE**: WIFI mode to use (default: g) +* **DRIVER**: WIFI driver to use (default: nl80211) +* **HT_CAPAB**: WIFI HT capabilities for 802.11n (default: [HT40-][SHORT-GI-20][SHORT-GI-40]) +* **MODE**: Mode to run in guest/host (default: host) + +## License + +MIT + +## Author + +Jaka Hudoklin + +Thanks to https://github.com/sdelrio/rpi-hostap for providing original +implementation. diff --git a/docker-ap/run.sh b/docker-ap/run.sh new file mode 100644 index 0000000..add8cd6 --- /dev/null +++ b/docker-ap/run.sh @@ -0,0 +1,2 @@ +#!/bin/bash +docker run -i -t -e INTERFACE=wlan0 -e OUTGOINGS=eth0 --net host --privileged won10/hostapd diff --git a/docker-ap/wlanstart.sh b/docker-ap/wlanstart.sh new file mode 100755 index 0000000..0e6a6a2 --- /dev/null +++ b/docker-ap/wlanstart.sh @@ -0,0 +1,126 @@ +#!/bin/bash -e + +# Check if running in privileged mode +if [ ! -w "/sys" ] ; then + echo "[Error] Not running in privileged mode." + exit 1 +fi + +# Default values +true ${INTERFACE:=wlan0} +true ${SUBNET:=192.168.254.0} +true ${AP_ADDR:=192.168.254.1} +true ${SSID:=docker-ap} +true ${CHANNEL:=11} +true ${WPA_PASSPHRASE:=passw0rd} +true ${HW_MODE:=g} +true ${DRIVER:=nl80211} +true ${HT_CAPAB:=[HT40-][SHORT-GI-20][SHORT-GI-40]} +true ${MODE:=host} + +# Attach interface to container in guest mode +if [ "$MODE" == "guest" ]; then + echo "Attaching interface to container" + + CONTAINER_ID=$(cat /proc/self/cgroup | grep -o -e "/docker/.*" | head -n 1| sed "s/\/docker\/\(.*\)/\\1/") + CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' ${CONTAINER_ID}) + CONTAINER_IMAGE=$(docker inspect -f '{{.Config.Image}}' ${CONTAINER_ID}) + + docker run -t --privileged --net=host --pid=host --rm --entrypoint /bin/sh ${CONTAINER_IMAGE} -c " + PHY=\$(echo phy\$(iw dev ${INTERFACE} info | grep wiphy | tr ' ' '\n' | tail -n 1)) + iw phy \$PHY set netns ${CONTAINER_PID} + " + + ip link set ${INTERFACE} name wlan0 + + INTERFACE=wlan0 +fi + +if [ ! -f "/etc/hostapd.conf" ] ; then + cat > "/etc/hostapd.conf" < /proc/sys/net/ipv4/$i + fi +done + +cat /proc/sys/net/ipv4/ip_dynaddr +cat /proc/sys/net/ipv4/ip_forward + +if [ "${OUTGOINGS}" ] ; then + ints="$(sed 's/,\+/ /g' <<<"${OUTGOINGS}")" + for int in ${ints} + do + echo "Setting iptables for outgoing traffics on ${int}..." + iptables -t nat -D POSTROUTING -s ${SUBNET}/24 -o ${int} -j MASQUERADE > /dev/null 2>&1 || true + iptables -t nat -A POSTROUTING -s ${SUBNET}/24 -o ${int} -j MASQUERADE + + iptables -D FORWARD -i ${int} -o ${INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null 2>&1 || true + iptables -A FORWARD -i ${int} -o ${INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT + + iptables -D FORWARD -i ${INTERFACE} -o ${int} -j ACCEPT > /dev/null 2>&1 || true + iptables -A FORWARD -i ${INTERFACE} -o ${int} -j ACCEPT + done +else + echo "Setting iptables for outgoing traffics on all interfaces..." + iptables -t nat -D POSTROUTING -s ${SUBNET}/24 -j MASQUERADE > /dev/null 2>&1 || true + iptables -t nat -A POSTROUTING -s ${SUBNET}/24 -j MASQUERADE + + iptables -D FORWARD -o ${INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null 2>&1 || true + iptables -A FORWARD -o ${INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT + + iptables -D FORWARD -i ${INTERFACE} -j ACCEPT > /dev/null 2>&1 || true + iptables -A FORWARD -i ${INTERFACE} -j ACCEPT +fi +echo "Configuring DHCP server .." + +cat > "/etc/dhcp/dhcpd.conf" <