From 0d26741432b3c5da7bb2b4b2bfd4920d40734f45 Mon Sep 17 00:00:00 2001 From: mrdis <31987174+mrdis@users.noreply.github.com> Date: Sat, 4 Dec 2021 16:01:26 +0100 Subject: [PATCH 1/4] Support AP+STA mode --- README.md | 1 + hassio-access-point/config.json | 2 ++ hassio-access-point/run.sh | 54 ++++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fdcaed7..742be63 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Please add - **netmask** (**required**): Subnet mask of the network - **broadcast** (**required**): Broadcast address of the network - **interface** (_optional_): Which wlan card to use. Default: wlan0 +- **virtual_interface** (_optional_): If set (e.g. to wlan1) a new virtual interface will be used as access point, leaving the wlan0 interface working as station. - **hide_ssid** (_optional_): Whether SSID is visible or hidden. 0 = visible, 1 = hidden. Defaults to visible - **dhcp** (_optional_): Enable or disable DHCP server. 0 = disable, 1 = enable. Defaults to disabled - **dhcp_start_addr** (_optional_): Start address for DHCP range. Required if DHCP enabled diff --git a/hassio-access-point/config.json b/hassio-access-point/config.json index 396ec95..a3239a1 100644 --- a/hassio-access-point/config.json +++ b/hassio-access-point/config.json @@ -21,6 +21,7 @@ "netmask": "255.255.255.0", "broadcast": "192.168.99.255", "interface": "wlan0", + "virtual_interface": "", "hide_ssid": "0", "dhcp": "0", "dhcp_start_addr": "192.168.99.10", @@ -40,6 +41,7 @@ "netmask": "str", "broadcast": "str", "interface": "str", + "virtual_interface": "str", "hide_ssid": "int", "dhcp": "int", "dhcp_start_addr": "str", diff --git a/hassio-access-point/run.sh b/hassio-access-point/run.sh index ef305cd..3035ce3 100644 --- a/hassio-access-point/run.sh +++ b/hassio-access-point/run.sh @@ -6,6 +6,9 @@ term_handler(){ ifdown $INTERFACE ip link set $INTERFACE down ip addr flush dev $INTERFACE + if [ ${#VINTERFACE} -ne 0 ]; then + iw dev $INTERFACE del + fi exit 0 } @@ -27,6 +30,7 @@ ADDRESS=$(jq --raw-output ".address" $CONFIG_PATH) NETMASK=$(jq --raw-output ".netmask" $CONFIG_PATH) BROADCAST=$(jq --raw-output ".broadcast" $CONFIG_PATH) INTERFACE=$(jq --raw-output ".interface" $CONFIG_PATH) +VINTERFACE=$(jq --raw-output ".virtual_interface" $CONFIG_PATH) HIDE_SSID=$(jq --raw-output ".hide_ssid" $CONFIG_PATH) DHCP=$(jq --raw-output ".dhcp" $CONFIG_PATH) DHCP_START_ADDR=$(jq --raw-output ".dhcp_start_addr" $CONFIG_PATH) @@ -43,6 +47,12 @@ if [ ${#INTERFACE} -eq 0 ]; then INTERFACE="wlan0" fi +# If we use a virtual interface, INTERFACE points to the base interface +if [ ${#VINTERFACE} -ne 0 ]; then + BASE_INTERFACE="${INTERFACE}" + INTERFACE="${VINTERFACE}" +fi + # Set debug as 0 if not specified in config if [ ${#DEBUG} -eq 0 ]; then DEBUG=0 @@ -56,6 +66,15 @@ logger "Add to /etc/network/interfaces: iface $INTERFACE inet static" 1 # Create and add our interface to interfaces file echo "iface $INTERFACE inet static"$'\n' >> /etc/network/interfaces +# Create virtual interface if needed +if [ ${#VINTERFACE} -ne 0 ]; then + # If using virtual interface, channel must be the same as the base interface + CHANNEL=$(iw dev $BASE_INTERFACE info | grep channel | awk '{print $2}') + # Create virtual interface + logger "Run command: iw dev $BASE_INTERFACE interface add $INTERFACE type __ap" 1 + iw dev $BASE_INTERFACE interface add $INTERFACE type __ap +fi + logger "Run command: nmcli dev set $INTERFACE managed no" 1 nmcli dev set $INTERFACE managed no @@ -195,27 +214,21 @@ if [ $DHCP -eq 1 ]; then echo "$dns_string"$'\n' >> /dnsmasq.conf logger "Add DNS: $dns_string" 0 fi - fi - - # Setup Client Internet Access - if [ $CLIENT_INTERNET_ACCESS -eq 1 ]; then - - ## Route traffic - iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE - iptables -P FORWARD ACCEPT - iptables -F FORWARD - fi else logger "# DHCP not enabled. Skipping dnsmasq" 1 - # Setup Client Internet Access ## No DHCP == No DNS. Must be set manually on client. - ## Step 1: Routing - if [ $CLIENT_INTERNET_ACCESS -eq 1 ]; then - iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE - iptables -P FORWARD ACCEPT - iptables -F FORWARD +fi + +# Setup Client Internet Access +if [ $CLIENT_INTERNET_ACCESS -eq 1 ]; then + ## Route traffic + if [ ${#VINTERFACE} -ne 0 ]; then + iptables -t nat -A POSTROUTING -o $BASE_INTERFACE -j MASQUERADE fi + iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + iptables -P FORWARD ACCEPT + iptables -F FORWARD fi # Start dnsmasq if DHCP is enabled in config @@ -224,10 +237,17 @@ if [ $DHCP -eq 1 ]; then killall -q dnsmasq; dnsmasq -C /dnsmasq.conf fi +if [ ${#VINTERFACE} -ne 0 ]; then + # Don't know why it is needed, but hostapd fails later on without this delay + sleep 10 +fi + logger "## Starting hostapd daemon" 1 # If debug level is greater than 1, start hostapd in debug mode if [ $DEBUG -gt 1 ]; then killall -q hostapd; hostapd -d /hostapd.conf & wait ${!} else killall -q hostapd; hostapd /hostapd.conf & wait ${!} -fi \ No newline at end of file +fi + +term_handler From 9809c3b1d4d454d47083a771a2c0e29095f23859 Mon Sep 17 00:00:00 2001 From: mrdis <31987174+mrdis@users.noreply.github.com> Date: Sat, 4 Dec 2021 18:27:58 +0100 Subject: [PATCH 2/4] Support AP network isolation --- README.md | 1 + hassio-access-point/config.json | 2 ++ hassio-access-point/run.sh | 53 +++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/README.md b/README.md index 742be63..f6a5a1f 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Please add - **broadcast** (**required**): Broadcast address of the network - **interface** (_optional_): Which wlan card to use. Default: wlan0 - **virtual_interface** (_optional_): If set (e.g. to wlan1) a new virtual interface will be used as access point, leaving the wlan0 interface working as station. +- **isolation** (_optional_): Enable or disable network isolation. 0 = disable, 1 = enable. Defaults to disabled. Note: If the DNS server is provided by a local router, it will not be accessible inside the AP network. In that case you should set the _client_dns_override_ option to an external DNS, e.g. 8.8.8.8. - **hide_ssid** (_optional_): Whether SSID is visible or hidden. 0 = visible, 1 = hidden. Defaults to visible - **dhcp** (_optional_): Enable or disable DHCP server. 0 = disable, 1 = enable. Defaults to disabled - **dhcp_start_addr** (_optional_): Start address for DHCP range. Required if DHCP enabled diff --git a/hassio-access-point/config.json b/hassio-access-point/config.json index a3239a1..5bb875b 100644 --- a/hassio-access-point/config.json +++ b/hassio-access-point/config.json @@ -22,6 +22,7 @@ "broadcast": "192.168.99.255", "interface": "wlan0", "virtual_interface": "", + "isolation": "0", "hide_ssid": "0", "dhcp": "0", "dhcp_start_addr": "192.168.99.10", @@ -41,6 +42,7 @@ "netmask": "str", "broadcast": "str", "interface": "str", + "isolation": "str", "virtual_interface": "str", "hide_ssid": "int", "dhcp": "int", diff --git a/hassio-access-point/run.sh b/hassio-access-point/run.sh index 3035ce3..13ca4d1 100644 --- a/hassio-access-point/run.sh +++ b/hassio-access-point/run.sh @@ -9,9 +9,33 @@ term_handler(){ if [ ${#VINTERFACE} -ne 0 ]; then iw dev $INTERFACE del fi + cleanup_iptables exit 0 } + +function cleanup_iptables() { + if [ ${#VINTERFACE} -ne 0 ]; then + iptables -t nat -D POSTROUTING -o $BASE_INTERFACE -j MASQUERADE + fi + iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE + iptables -t nat -D PREROUTING -i $INTERFACE -j ACCEPT + iptables -D INPUT -i $INTERFACE -j DROP + iptables -D INPUT -i $INTERFACE -m state --state ESTABLISHED,RELATED -j ACCEPT + if [ ${#VINTERFACE} -ne 0 ]; then + wifi_net=$(ip addr show $BASE_INTERFACE | grep inet | awk '{print $2}') + if [ ${#wifi_net} -ne 0 ]; then + iptables -D FORWARD -i $INTERFACE -o $BASE_INTERFACE -d ${wifi_net} -j DROP + fi + fi + eth_net=$(ip addr show eth0 | grep inet | awk '{print $2}') + if [ ${#eth_net} -ne 0 ]; then + iptables -D FORWARD -i $INTERFACE -o eth0 -d ${eth_net} -j DROP + fi + iptables -D INPUT -p udp -i $INTERFACE --dport 67 -j ACCEPT +} + + # Logging function to set verbosity of output to addon log logger(){ msg=$1 @@ -31,6 +55,7 @@ NETMASK=$(jq --raw-output ".netmask" $CONFIG_PATH) BROADCAST=$(jq --raw-output ".broadcast" $CONFIG_PATH) INTERFACE=$(jq --raw-output ".interface" $CONFIG_PATH) VINTERFACE=$(jq --raw-output ".virtual_interface" $CONFIG_PATH) +ISOLATION=$(jq --raw-output ".isolation" $CONFIG_PATH) HIDE_SSID=$(jq --raw-output ".hide_ssid" $CONFIG_PATH) DHCP=$(jq --raw-output ".dhcp" $CONFIG_PATH) DHCP_START_ADDR=$(jq --raw-output ".dhcp_start_addr" $CONFIG_PATH) @@ -113,6 +138,11 @@ if [ $DHCP -ne 1 ]; then DHCP=0 fi +# Sanitise config value for isolation +if [ $ISOLATION -ne 1 ]; then + ISOLATION=0 +fi + if [[ -n $error ]]; then exit 1 fi @@ -231,6 +261,29 @@ if [ $CLIENT_INTERNET_ACCESS -eq 1 ]; then iptables -F FORWARD fi +# Setup network isolation +if [ $ISOLATION -eq 1 ]; then + # Do not pass packets coming from AP to docker + iptables -t nat -I PREROUTING -i $INTERFACE -j ACCEPT + # Accept only locally-initiated traffic + iptables -I INPUT -i $INTERFACE -j DROP + iptables -I INPUT -i $INTERFACE -m state --state ESTABLISHED,RELATED -j ACCEPT + if [ ${#VINTERFACE} -ne 0 ]; then + # Prevent access to local wifi network from AP network + wifi_net=$(ip addr show $BASE_INTERFACE | grep inet | awk '{print $2}') + if [ ${#wifi_net} -ne 0 ]; then + iptables -I FORWARD -i $INTERFACE -o $BASE_INTERFACE -d ${wifi_net} -j DROP + fi + fi + # Prevent access to local eth network from AP network + eth_net=$(ip addr show eth0 | grep inet | awk '{print $2}') + if [ ${#eth_net} -ne 0 ]; then + iptables -I FORWARD -i $INTERFACE -o eth0 -d ${eth_net} -j DROP + fi + # Allow access to local DHCP server + iptables -I INPUT -p udp -i $INTERFACE --dport 67 -j ACCEPT +fi + # Start dnsmasq if DHCP is enabled in config if [ $DHCP -eq 1 ]; then logger "## Starting dnsmasq daemon" 1 From 156ee04ee88518b84f3388c9f81007b091ad53ed Mon Sep 17 00:00:00 2001 From: mattlongman Date: Wed, 22 Jun 2022 12:51:45 +0100 Subject: [PATCH 3/4] Update run.sh Prevent matches for inet6 (`grep 'inet '`) --- hassio-access-point/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hassio-access-point/run.sh b/hassio-access-point/run.sh index 88ce3db..da8a3f6 100644 --- a/hassio-access-point/run.sh +++ b/hassio-access-point/run.sh @@ -28,7 +28,7 @@ function cleanup_iptables() { iptables -D FORWARD -i $INTERFACE -o $BASE_INTERFACE -d ${wifi_net} -j DROP fi fi - eth_net=$(ip addr show eth0 | grep inet | awk '{print $2}') + eth_net=$(ip addr show eth0 | grep 'inet ' | awk '{print $2}') if [ ${#eth_net} -ne 0 ]; then iptables -D FORWARD -i $INTERFACE -o eth0 -d ${eth_net} -j DROP fi @@ -289,7 +289,7 @@ if [ $ISOLATION -eq 1 ]; then fi fi # Prevent access to local eth network from AP network - eth_net=$(ip addr show eth0 | grep inet | awk '{print $2}') + eth_net=$(ip addr show eth0 | grep 'inet ' | awk '{print $2}') if [ ${#eth_net} -ne 0 ]; then iptables -I FORWARD -i $INTERFACE -o eth0 -d ${eth_net} -j DROP fi From 7169037b3aa9f9298bf152051e5547884b080286 Mon Sep 17 00:00:00 2001 From: mattlongman Date: Wed, 22 Jun 2022 15:01:14 +0100 Subject: [PATCH 4/4] Remove duplicate config line --- hassio-access-point/run.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/hassio-access-point/run.sh b/hassio-access-point/run.sh index da8a3f6..8ae6844 100644 --- a/hassio-access-point/run.sh +++ b/hassio-access-point/run.sh @@ -60,7 +60,6 @@ HIDE_SSID=$(jq --raw-output ".hide_ssid" $CONFIG_PATH) DHCP=$(jq --raw-output ".dhcp" $CONFIG_PATH) DHCP_START_ADDR=$(jq --raw-output ".dhcp_start_addr" $CONFIG_PATH) DHCP_END_ADDR=$(jq --raw-output ".dhcp_end_addr" $CONFIG_PATH) -DNSMASQ_CONFIG_OVERRIDE=$(jq --raw-output '.dnsmasq_config_override | join(" ")' $CONFIG_PATH) ALLOW_MAC_ADDRESSES=$(jq --raw-output '.allow_mac_addresses | join(" ")' $CONFIG_PATH) DENY_MAC_ADDRESSES=$(jq --raw-output '.deny_mac_addresses | join(" ")' $CONFIG_PATH) DEBUG=$(jq --raw-output '.debug' $CONFIG_PATH)