From aa47c28ea296f05a73edf0da2ad490008e03f0b6 Mon Sep 17 00:00:00 2001 From: Junde Yhi Date: Sat, 27 Oct 2018 20:33:44 +0800 Subject: [PATCH 01/41] create_ap: add support for config comments --- create_ap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/create_ap b/create_ap index f23d444..99e91e7 100755 --- a/create_ap +++ b/create_ap @@ -1000,6 +1000,9 @@ read_config() { local opt_name opt_val line while read line; do + # Skip comments and blank lines + [[ -z "${line}" || "${line:0:1}" == "#" ]] && continue + # Read switches and their values opt_name="${line%%=*}" opt_val="${line#*=}" From b9f68055b4f30b2d05319d6e60b724bf5b0d85c3 Mon Sep 17 00:00:00 2001 From: Junde Yhi Date: Sat, 27 Oct 2018 20:38:56 +0800 Subject: [PATCH 02/41] create_ap.conf: add comments to explain options --- create_ap.conf | 90 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/create_ap.conf b/create_ap.conf index 9f55f09..2e91af8 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -1,28 +1,82 @@ -CHANNEL=default +# Configuration file for create_ap (https://github.com/oblique/create_ap) + +########## Access Point Information ########## + +# Name of access point +SSID=MyAccessPoint +# Pre-shared key or passphrase of access point (see USE_PSK option) +PASSPHRASE=12345678 +# Type of key in PASSPHRASE +# - Set to "0" if the content of PASSPHRASE is an 8..63 character long ASCII +# passphrase (i.e. what you type when you connect) +# - Set to "1" if the content of PASSPHRASE is a 256-bit secret in hex format +# (64 hex digits) +USE_PSK=0 +# Set whether the access point should hide its SSID or not +HIDDEN=0 + +########## Sharing Options ########## + +# The network interface where create_ap creates access point +WIFI_IFACE=wlan0 +# The network interface to be shared +INTERNET_IFACE=eth0 +# Method to share the network +# Available options: "nat", "bridge" +SHARE_METHOD=nat +# IP address of the gateway in NAT mode (the subnet is /24) GATEWAY=10.0.0.1 +# Set whether the connected clients can see each other or not +ISOLATE_CLIENTS=0 + +########## Wireless Options ########## + +# The channel number on which the access point is served +# Set to "default" will set channel to 1 in 2.4Ghz band and 36 in 5GHz band +CHANNEL=default +# Wireless frequency (band) +# Available options: "2.4", "5" +FREQ_BAND=2.4 +# Country code (ISO/IEC 3166-1) to set regulatory domain +COUNTRY= +# WPA version +# Available options: "1", "2", "1+2" (or "3") WPA_VERSION=2 -ETC_HOSTS=0 +# Whether IEEE 802.11n (HT) is enabled +IEEE80211N=0 +# Whether IEEE 802.11ac (VHT) is enabled +IEEE80211AC=0 +# HT / VHT capabilities +# For all possible options please look at +# https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf +HT_CAPAB=[HT40+] +VHT_CAPAB= + +########## Network Options ########## + +# DNS server to be pushed by DHCP server +# Set to "gateway" to use the gateway itself DHCP_DNS=gateway +# Set to 1 to disable DNS NO_DNS=0 +# Set to 1 to disable dnsmasq completely (DHCP and DNS) NO_DNSMASQ=0 -HIDDEN=0 +# Whether dnsmasq should use DNS servers provided in /etc/hosts or not +ETC_HOSTS=0 +# Set to 1 to enable MAC address based authentication MAC_FILTER=0 +# Acceptance list for MAC address based authentication MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept -ISOLATE_CLIENTS=0 -SHARE_METHOD=nat -IEEE80211N=0 -IEEE80211AC=0 -HT_CAPAB=[HT40+] -VHT_CAPAB= -DRIVER=nl80211 -NO_VIRT=0 -COUNTRY= -FREQ_BAND=2.4 +# New MAC address for the access point, leave it blank to keep it as-is NEW_MACADDR= + +########## Miscellaneous ########## + +# Specify the driver to use +DRIVER=nl80211 +# Set whether create_ap should run in the background DAEMONIZE=0 +# Set to 1 to disable virtual interface creation +NO_VIRT=0 +# Set to 1 to disable haveged random number generation NO_HAVEGED=0 -WIFI_IFACE=wlan0 -INTERNET_IFACE=eth0 -SSID=MyAccessPoint -PASSPHRASE=12345678 -USE_PSK=0 From f44ad156aa26d29235d697cd46ea66c5413b452d Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Fri, 27 Dec 2019 22:25:38 -0800 Subject: [PATCH 03/41] clarify action of --dhcp-dns, --no-dns, --no-dns-masq options, and explain default non-bridged network in a little more detail --- create_ap | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/create_ap b/create_ap index 4f06255..f971a0e 100755 --- a/create_ap +++ b/create_ap @@ -60,7 +60,7 @@ usage() { echo " close create_ap, then use this option to switch your interface" echo " back to managed" echo " --mac Set MAC address" - echo " --dhcp-dns Set DNS returned by DHCP" + echo " --dhcp-dns Set DNS returned by DHCP (default is gateway; see also --no-dns below)" echo " --daemon Run create_ap in the background" echo " --pidfile Save daemon PID to file" echo " --logfile Save daemon messages to file" @@ -75,10 +75,10 @@ usage() { echo " --mkconfig Store configs in conf_file" echo " --config Load configs from conf_file" echo - echo "Non-Bridging Options:" - echo " --no-dns Disable dnsmasq DNS server" - echo " --no-dnsmasq Disable dnsmasq server completely" - echo " -g IPv4 Gateway for the Access Point (default: 192.168.12.1)" + echo "Non-bridging options:" + echo " --no-dns Disable dnsmasq DNS server (prevents clients from using Access Point for DNS)" + echo " --no-dnsmasq Disable dnsmasq completely (implies --no-dns and also disables DHCP)" + echo " -g IPv4 Gateway address for the Access Point (default: 192.168.12.1)" echo " -d DNS server will take into account /etc/hosts" echo " -e DNS server will take into account additional hosts file" echo @@ -86,8 +86,10 @@ usage() { echo " * If you're not using the --no-virt option, then you can create an AP with the same" echo " interface you are getting your Internet connection." echo " * You can pass your SSID and password through pipe or through arguments (see examples)." - echo " * On bridge method if the is not a bridge interface, then" + echo " * With bridge method, if the is not a bridge interface, then" echo " a bridge interface is created automatically." + echo " * With other methods, the default behavior is to run dnsmasq as a DNS and DHCP server." + echo " It will assign client addresses in the /24 address range matching the gateway." echo echo "Examples:" echo " "$PROGNAME" wlan0 eth0 MyAccessPoint MyPassPhrase" From 7eac6b6ad0aadee6b9c3ce67e56abf8d0c065edf Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Wed, 25 Mar 2020 16:47:17 -0700 Subject: [PATCH 04/41] create backups when overwriting existing create_ap.conf --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5ad53c6..e2eef8c 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ all: install: install -Dm755 create_ap $(DESTDIR)$(BINDIR)/create_ap - install -Dm644 create_ap.conf $(DESTDIR)/etc/create_ap.conf + install -Dm644 --backup=existing --suffix=.orig create_ap.conf $(DESTDIR)/etc/create_ap.conf [ ! -d /lib/systemd/system ] || install -Dm644 create_ap.service $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service [ ! -e /sbin/openrc-run ] || install -Dm755 create_ap.openrc $(DESTDIR)/etc/init.d/create_ap install -Dm644 bash_completion $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap From ae1d795a23f95fbb935f9aa8b8b4cbaf4b58a674 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Wed, 1 Apr 2020 23:35:18 -0700 Subject: [PATCH 05/41] add option to set beacon interval May help with battery life, throughput, and signal retention depending on network environment --- create_ap | 6 ++++-- create_ap.conf | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/create_ap b/create_ap index 4f06255..2e969b7 100755 --- a/create_ap +++ b/create_ap @@ -51,6 +51,7 @@ usage() { echo " --ieee80211ac Enable IEEE 802.11ac (VHT)" echo " --ht_capab HT capabilities (default: [HT40+])" echo " --vht_capab VHT capabilities" + echo " --beacon-interval Set beacon interval in milliseconds (default 100)" echo " --country Set two-letter country code for regularity (example: US)" echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" echo " --driver Choose your WiFi adapter driver (default: nl80211)" @@ -639,6 +640,7 @@ DRIVER=nl80211 NO_VIRT=0 COUNTRY= FREQ_BAND=2.4 +BEACON_INTERVAL=100 NEW_MACADDR= DAEMONIZE=0 DAEMON_PIDFILE= @@ -652,7 +654,7 @@ REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL) FIX_UNMANAGED=0 LIST_RUNNING=0 @@ -1631,7 +1633,6 @@ fi # hostapd config cat << EOF > $CONFDIR/hostapd.conf -beacon_int=100 ssid=${SSID} interface=${WIFI_IFACE} driver=${DRIVER} @@ -1640,6 +1641,7 @@ ctrl_interface=$CONFDIR/hostapd_ctrl ctrl_interface_group=0 ignore_broadcast_ssid=$HIDDEN ap_isolate=$ISOLATE_CLIENTS +beacon_int=${BEACON_INTERVAL} EOF if [[ -n "$COUNTRY" ]]; then diff --git a/create_ap.conf b/create_ap.conf index 9f55f09..d35ebfa 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -26,3 +26,4 @@ INTERNET_IFACE=eth0 SSID=MyAccessPoint PASSPHRASE=12345678 USE_PSK=0 +BEACON_INTERVAL=100 From 8080710ea3028cf8d07348c25e4035ab97c8a0f2 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Thu, 2 Apr 2020 23:05:20 -0700 Subject: [PATCH 06/41] add option for DTIM period too --- create_ap | 5 ++++- create_ap.conf | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/create_ap b/create_ap index 2e969b7..adda804 100755 --- a/create_ap +++ b/create_ap @@ -52,6 +52,7 @@ usage() { echo " --ht_capab HT capabilities (default: [HT40+])" echo " --vht_capab VHT capabilities" echo " --beacon-interval Set beacon interval in milliseconds (default 100)" + echo " --dtim-period Set DTIM period in numbers of beacons (default 2)" echo " --country Set two-letter country code for regularity (example: US)" echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" echo " --driver Choose your WiFi adapter driver (default: nl80211)" @@ -641,6 +642,7 @@ NO_VIRT=0 COUNTRY= FREQ_BAND=2.4 BEACON_INTERVAL=100 +DTIM_PERIOD=2 NEW_MACADDR= DAEMONIZE=0 DAEMON_PIDFILE= @@ -654,7 +656,7 @@ REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK BEACON_INTERVAL) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD) FIX_UNMANAGED=0 LIST_RUNNING=0 @@ -1642,6 +1644,7 @@ ctrl_interface_group=0 ignore_broadcast_ssid=$HIDDEN ap_isolate=$ISOLATE_CLIENTS beacon_int=${BEACON_INTERVAL} +dtim_period=${DTIM_PERIOD} EOF if [[ -n "$COUNTRY" ]]; then diff --git a/create_ap.conf b/create_ap.conf index d35ebfa..d45c4b0 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -27,3 +27,4 @@ SSID=MyAccessPoint PASSPHRASE=12345678 USE_PSK=0 BEACON_INTERVAL=100 +DTIM_INTERVAL=2 From 380e4f4d857d22b958fe6612a08462ac58ca51b0 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Wed, 15 Apr 2020 19:39:40 -0700 Subject: [PATCH 07/41] restart create_ap after suspend-and-resume Uses the /lib/systemd/system-sleep mechanism. See https://www.freedesktop.org/software/systemd/man/systemd-suspend.service.html for how this works. For unclear reasons, this only works in /lib/systemd/system-sleep, not in /usr/lib/systemd/system-sleep. (ping #153, #167) --- Makefile | 2 ++ create_ap.resume | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100755 create_ap.resume diff --git a/Makefile b/Makefile index 5ad53c6..08fee2b 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ install: install -Dm755 create_ap $(DESTDIR)$(BINDIR)/create_ap install -Dm644 create_ap.conf $(DESTDIR)/etc/create_ap.conf [ ! -d /lib/systemd/system ] || install -Dm644 create_ap.service $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service + [ ! -d /lib/systemd/system-sleep ] || install -Dm755 create_ap.resume $(DESTDIR)/lib/systemd/system-sleep/create_ap.resume [ ! -e /sbin/openrc-run ] || install -Dm755 create_ap.openrc $(DESTDIR)/etc/init.d/create_ap install -Dm644 bash_completion $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md @@ -18,6 +19,7 @@ uninstall: rm -f $(DESTDIR)$(BINDIR)/create_ap rm -f $(DESTDIR)/etc/create_ap.conf [ ! -f /lib/systemd/system/create_ap.service ] || rm -f $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service + [ ! -f /lib/systemd/system-sleep/create_ap.resume ] || rm -f $(DESTDIR)/lib/systemd/system/create_ap.resume [ ! -e /sbin/openrc-run ] || rm -f $(DESTDIR)/etc/init.d/create_ap rm -f $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap rm -f $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md diff --git a/create_ap.resume b/create_ap.resume new file mode 100755 index 0000000..34ee440 --- /dev/null +++ b/create_ap.resume @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# After resume, restart create_ap service (if it was already running) +# See: +# https://www.freedesktop.org/software/systemd/man/systemd-suspend.service.html + +case "$1" in + pre) ;; + post) /bin/systemctl try-restart create_ap.service ;; +esac From 7811c5c2a7c006876bd972a3656d970ad12264ea Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Sun, 19 Apr 2020 01:21:04 -0700 Subject: [PATCH 08/41] initial IPv6 --- create_ap | 118 +++++++++++++++++++++++++++++++++++++++++++++++-- create_ap.conf | 8 +++- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/create_ap b/create_ap index 13aae87..fd11630 100755 --- a/create_ap +++ b/create_ap @@ -63,6 +63,7 @@ usage() { echo " back to managed" echo " --mac Set MAC address" echo " --dhcp-dns Set DNS returned by DHCP (default is gateway; see also --no-dns below)" + echo " --dhcp-dns6 Set DNSv6 returned by DHCP (default is gateway; see also --no-dns below)" echo " --daemon Run create_ap in the background" echo " --pidfile Save daemon PID to file" echo " --logfile Save daemon messages to file" @@ -81,6 +82,7 @@ usage() { echo " --no-dns Disable dnsmasq DNS server (prevents clients from using Access Point for DNS)" echo " --no-dnsmasq Disable dnsmasq completely (implies --no-dns and also disables DHCP)" echo " -g IPv4 Gateway address for the Access Point (default: 192.168.12.1)" + echo " --ipv6 Enable IPv6 support" echo " -d DNS server will take into account /etc/hosts" echo " -e DNS server will take into account additional hosts file" echo @@ -627,6 +629,7 @@ WPA_VERSION=1+2 ETC_HOSTS=0 ADDN_HOSTS= DHCP_DNS=gateway +DHCP_DNS6=gateway NO_DNS=0 NO_DNSMASQ=0 DNS_PORT= @@ -651,14 +654,15 @@ DAEMON_PIDFILE= DAEMON_LOGFILE=/dev/null NO_HAVEGED=0 USE_PSK=0 +IPV6=0 HOSTAPD_DEBUG_ARGS= REDIRECT_TO_LOCALHOST=0 -CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS +CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6) FIX_UNMANAGED=0 LIST_RUNNING=0 @@ -710,6 +714,14 @@ _cleanup() { cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding \ /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding rm -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding + + cp -f $COMMON_CONFDIR/ipv6_forwarding \ + /proc/sys/net/ipv6/conf/all/forwarding + rm -f $COMMON_CONFDIR/ipv6_forwarding + + cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_ipv6_forwarding \ + /proc/sys/net/ipv6/conf/$INTERNET_IFACE/forwarding + rm -f $COMMON_CONFDIR/${INTERNET_IFACE}_ipv6_forwarding fi # if we are the last create_ap instance then set back the common values @@ -732,6 +744,12 @@ _cleanup() { fi rm -f $COMMON_CONFDIR/bridge-nf-call-iptables fi + if [[ -f $COMMON_CONFDIR/bridge-nf-call-ip6tables ]]; then + if [[ -e /proc/sys/net/bridge/bridge-nf-call-ip6tables ]]; then + cp -f $COMMON_CONFDIR/bridge-nf-call-ip6tables /proc/sys/net/bridge + fi + rm -f $COMMON_CONFDIR/bridge-nf-call-ip6tables + fi rm -rf $COMMON_CONFDIR fi @@ -741,6 +759,7 @@ _cleanup() { iptables -w -t nat -D POSTROUTING -s ${GATEWAY%.*}.0/24 ! -o ${WIFI_IFACE} -j MASQUERADE iptables -w -D FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT iptables -w -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT + # FIXME: restore ip6tables? elif [[ "$SHARE_METHOD" == "bridge" ]]; then if ! is_bridge_interface $INTERNET_IFACE; then ip link set dev $BRIDGE_IFACE down @@ -788,8 +807,21 @@ _cleanup() { -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT iptables -w -t nat -D PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \ -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT + if [[ "$IPV6" -ne 0 ]]; then + ip6tables -w -D INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT + ip6tables -w -D INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT + ip6tables -w -t nat -D PREROUTING -s ${GATEWAY6}/$PREFIXLEN6 -d ${GATEWAY6} \ + -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT + ip6tables -w -t nat -D PREROUTING -s ${GATEWAY6}/$PREFIXLEN6 -d ${GATEWAY6} \ + -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT + fi fi iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT + if [[ $IPV6 -ne 0 ]]; then + ip6tables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT + ip -6 route del "$INTERNET6"/"$PREFIXLEN6" dev $WIFI_IFACE + ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev $INTERNET_IFACE + fi fi if [[ $NO_VIRT -eq 0 ]]; then @@ -1056,7 +1088,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","mkconfig:","config:" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","ipv6","mkconfig:","config:" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1103,6 +1135,10 @@ while :; do GATEWAY="$1" shift ;; + --ipv6) + shift + IPV6=1 + ;; -d) shift ETC_HOSTS=1 @@ -1172,6 +1208,11 @@ while :; do DHCP_DNS="$1" shift ;; + --dhcp-dns6) + shift + DHCP_DNS6="$1" + shift + ;; --daemon) shift DAEMONIZE=1 @@ -1540,11 +1581,18 @@ if [[ "$SHARE_METHOD" == "nat" ]]; then echo $INTERNET_IFACE > $CONFDIR/nat_internet_iface cp_n /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding \ $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding + cp_n /proc/sys/net/ipv6/conf/all/forwarding \ + $COMMON_CONFDIR/ipv6_forwarding + cp_n /proc/sys/net/ipv6/conf/${INTERNET_IFACE}/forwarding \ + $COMMON_CONFDIR/${INTERNET_IFACE}_ipv6_forwarding fi cp_n /proc/sys/net/ipv4/ip_forward $COMMON_CONFDIR if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then cp_n /proc/sys/net/bridge/bridge-nf-call-iptables $COMMON_CONFDIR fi +if [[ -e /proc/sys/net/bridge/bridge-nf-call-ip6tables ]]; then + cp_n /proc/sys/net/bridge/bridge-nf-call-ip6tables $COMMON_CONFDIR +fi mutex_unlock if [[ "$SHARE_METHOD" == "bridge" ]]; then @@ -1553,6 +1601,22 @@ if [[ "$SHARE_METHOD" == "bridge" ]]; then else BRIDGE_IFACE=$(alloc_new_iface br) fi +elif [[ $IPV6 -ne 0 ]]; then + echo "Looking up IPv6 address of internet interface..." + NETADDR6=$(ip -6 addr show $INTERNET_IFACE scope global | sed -e 's/ /\n/g' | sed -ne '/inet6/{n;p}') + if [[ -n "$NETADDR6" ]]; then + INTERNET6="${NETADDR6%/*}" + PREFIXLEN6="${NETADDR6#*/}" + # FIXME: this is a dodgy/bad way to pick an IPv6 address. + # We want a different IPv6 address for the AP (internal), + # compared to our external IPv6 address, but they need to be + # in the same /64 subnet. This is the current ugly kludge. + GATEWAY6="${INTERNET6%:*}":$(printf "%04x" "$(( 0x${INTERNET6##*:} + 1))") + echo "Got $INTERNET6/$PREFIXLEN6. Will route $GATEWAY6/$PREFIXLEN6 to clients." + else + echo "No IPv6 address found. Disabling IPv6." + IPV6=0 + fi fi if [[ $USE_IWCONFIG -eq 0 ]]; then @@ -1721,13 +1785,28 @@ elif [[ $NO_DNSMASQ -eq 0 ]]; then if [[ "$DHCP_DNS" == "gateway" ]]; then DHCP_DNS="$GATEWAY" fi + if [[ "$DHCP_DNS6" == "gateway" ]]; then + DHCP_DNS6="[$GATEWAY6]" + fi cat << EOF > $CONFDIR/dnsmasq.conf -listen-address=${GATEWAY} +interface=${WIFI_IFACE} ${DNSMASQ_BIND} dhcp-range=${GATEWAY%.*}.1,${GATEWAY%.*}.254,255.255.255.0,24h dhcp-option-force=option:router,${GATEWAY} dhcp-option-force=option:dns-server,${DHCP_DNS} EOF + if [[ $IPV6 -ne 0 ]]; then + if [[ "$NO_DNS" -ne 0 ]]; then + RA_MODE="ra-names" + else + RA_MODE="ra-stateless" + fi + [[ -n "$DHCP_DNS6" ]] && echo "dhcp-option-force=option6:dns-server,${DHCP_DNS6}" >> $CONFDIR/dnsmasq.conf + cat <> $CONFDIR/dnsmasq.conf +dhcp-range=::,constructor:${WIFI_IFACE}, $RA_MODE, slaac, 24h +dhcp-authoritative +EOF + fi MTU=$(get_mtu $INTERNET_IFACE) [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> $CONFDIR/dnsmasq.conf [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf @@ -1754,6 +1833,15 @@ fi if [[ "$SHARE_METHOD" != "bridge" ]]; then ip link set up dev ${WIFI_IFACE} || die "$VIRTDIEMSG" ip addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${WIFI_IFACE} || die "$VIRTDIEMSG" + if [[ $IPV6 -ne 0 ]]; then + # Keep only /128 for Internet-facing IPv6 address + ip -6 addr del "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" + ip -6 addr add "$INTERNET6"/128 dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" + ip -6 route replace "$INTERNET6"/128 dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" + # While routing full IPv6 subnet to clients + ip -6 addr add "$GATEWAY6"/"$PREFIXLEN6" dev ${WIFI_IFACE} || die "$VIRTDIEMSG" + ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev ${WIFI_IFACE} || die "$VIRTDIEMSG" + fi fi # enable Internet sharing @@ -1765,6 +1853,17 @@ if [[ "$SHARE_METHOD" != "none" ]]; then iptables -w -I FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT || die echo 1 > /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding || die echo 1 > /proc/sys/net/ipv4/ip_forward || die + if [[ $IPV6 -ne 0 ]]; then + # This enables forwarding of *all* IPv6 packets, which is handy for running an IPv6 + # server on a device inside the network without NAT... + ip6tables -P FORWARD ACCEPT || die + # ... but if you want something that prevents random incoming connections, try: + #ip6tables -P FORWARD DENY || die + #ip6tables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT || die + #ip6tables -I FORWARD -i ${WIFI_IFACE} -j ACCEPT || die + echo 1 > /proc/sys/net/ipv6/conf/$INTERNET_IFACE/forwarding || die + echo 1 > /proc/sys/net/ipv6/conf/all/forwarding || die + fi # to enable clients to establish PPTP connections we must # load nf_nat_pptp module modprobe nf_nat_pptp > /dev/null 2>&1 @@ -1852,12 +1951,23 @@ if [[ "$SHARE_METHOD" != "bridge" ]]; then -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die iptables -w -t nat -I PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \ -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die + if [[ $IPV6 -ne 0 ]]; then + ip6tables -w -I INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT || die + ip6tables -w -I INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT || die + ip6tables -w -t nat -I PREROUTING -s ${GATEWAY6}/$PREFIXLEN6 -d ${GATEWAY6} \ + -p tcp -m tcp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die + ip6tables -w -t nat -I PREROUTING -s ${GATEWAY6}/$PREFIXLEN6 -d ${GATEWAY6} \ + -p udp -m udp --dport 53 -j REDIRECT --to-ports $DNS_PORT || die + fi else DNS_PORT=0 fi if [[ $NO_DNSMASQ -eq 0 ]]; then iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT || die + if [[ $IPV6 -ne 0 ]]; then + ip6tables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT || die + fi if which complain > /dev/null 2>&1; then # openSUSE's apparmor does not allow dnsmasq to read files. diff --git a/create_ap.conf b/create_ap.conf index a033e69..dd8763c 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -26,6 +26,8 @@ INTERNET_IFACE=eth0 SHARE_METHOD=nat # IP address of the gateway in NAT mode (the subnet is /24) GATEWAY=10.0.0.1 +# Set whether IPv6 should be enabled +IPV6=0 # Set whether the connected clients can see each other or not ISOLATE_CLIENTS=0 @@ -58,9 +60,13 @@ DTIM_INTERVAL=2 ########## Network Options ########## -# DNS server to be pushed by DHCP server +# DNS servers to be pushed by DHCP server; separate multiple with , # Set to "gateway" to use the gateway itself DHCP_DNS=gateway +# IPv6 DNS servers to be pushed by DHCP server; enclose IPv6 +# addresses in [], and separate multiple with , +# Set to "gateway" to use the gateway itself +DHCP_DNS6= # Set to 1 to disable DNS NO_DNS=0 # Set to 1 to disable dnsmasq completely (DHCP and DNS) From 0f3b4c2ad272f5ad458b1d1a86cd749b7181a444 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 20 Apr 2020 20:58:08 -0700 Subject: [PATCH 09/41] fix IPv6 address assignment and restoration --- create_ap | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/create_ap b/create_ap index fd11630..0ddd30e 100755 --- a/create_ap +++ b/create_ap @@ -434,6 +434,28 @@ get_new_macaddr() { echo $NEWMAC } +get_ipv6addr() { + ip -6 addr show "$1" scope global | sed -e 's/ /\n/g' | sed -ne '/inet6/{n;p}' | tail -n1 +} + +get_new_ipv6addr() { + local OLDIP NEWIP LAST_CHUNK i + OLDIP=$(get_ipv6addr "$1") + OLDIP="${OLDIP%/*}" + mutex_lock + for i in {1..65535}; do + if [[ "$OLDIP" == ::* ]]; then + NEWIP="${OLDIP}::$(printf %04x $i)" + else + LAST_CHUNK=$(printf %d 0x${OLDIP##*:}) + NEWIP="${OLDIP%:*}:$(printf %02x $(( ($LAST_CHUNK + $i) % 65536 )))" + ip -6 addr show "$1" scope global | sed -e 's/ /\n/g' | sed -ne '/inet6/{n;p}' | grep "$NEWIP" > /dev/null 2>&1 || break + fi + done + mutex_unlock + echo $NEWIP +} + # start haveged when needed haveged_watchdog() { local show_warn=1 @@ -819,8 +841,10 @@ _cleanup() { iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT if [[ $IPV6 -ne 0 ]]; then ip6tables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT - ip -6 route del "$INTERNET6"/"$PREFIXLEN6" dev $WIFI_IFACE - ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev $INTERNET_IFACE + # Restore original subnet to internet-facing interface + ip -6 addr del "$INTERNET6"/128 dev ${INTERNET_IFACE} + ip -6 addr add "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} + ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} fi fi @@ -1603,16 +1627,12 @@ if [[ "$SHARE_METHOD" == "bridge" ]]; then fi elif [[ $IPV6 -ne 0 ]]; then echo "Looking up IPv6 address of internet interface..." - NETADDR6=$(ip -6 addr show $INTERNET_IFACE scope global | sed -e 's/ /\n/g' | sed -ne '/inet6/{n;p}') + NETADDR6=$(get_ipv6addr $INTERNET_IFACE) if [[ -n "$NETADDR6" ]]; then INTERNET6="${NETADDR6%/*}" PREFIXLEN6="${NETADDR6#*/}" - # FIXME: this is a dodgy/bad way to pick an IPv6 address. - # We want a different IPv6 address for the AP (internal), - # compared to our external IPv6 address, but they need to be - # in the same /64 subnet. This is the current ugly kludge. - GATEWAY6="${INTERNET6%:*}":$(printf "%04x" "$(( 0x${INTERNET6##*:} + 1))") - echo "Got $INTERNET6/$PREFIXLEN6. Will route $GATEWAY6/$PREFIXLEN6 to clients." + GATEWAY6=$(get_new_ipv6addr $INTERNET_IFACE) + echo "Internet interface is $INTERNET6/$PREFIXLEN6. Will route $GATEWAY6/$PREFIXLEN6 to wireless clients." else echo "No IPv6 address found. Disabling IPv6." IPV6=0 @@ -1834,11 +1854,14 @@ if [[ "$SHARE_METHOD" != "bridge" ]]; then ip link set up dev ${WIFI_IFACE} || die "$VIRTDIEMSG" ip addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${WIFI_IFACE} || die "$VIRTDIEMSG" if [[ $IPV6 -ne 0 ]]; then - # Keep only /128 for Internet-facing IPv6 address + # Normally, the Internet-facing device has been assigned a /64 subnet (saved in INTERNET6/PREFIXLEN6). + # We want to keep only /128 for the Internet-facing device, but route the rest of the subnet to + # the AP, so that it can be used by clients via DHCPv6 or SLAAC. + ip -6 addr del "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" ip -6 addr add "$INTERNET6"/128 dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" ip -6 route replace "$INTERNET6"/128 dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" - # While routing full IPv6 subnet to clients + ip -6 addr add "$GATEWAY6"/"$PREFIXLEN6" dev ${WIFI_IFACE} || die "$VIRTDIEMSG" ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev ${WIFI_IFACE} || die "$VIRTDIEMSG" fi From ec98791da38a92cf7987b8a94331a89249ecef41 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Tue, 21 Apr 2020 18:54:31 -0700 Subject: [PATCH 10/41] no need for explicit IPv6 routes, just address? no dhcp-authoritative --- create_ap | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/create_ap b/create_ap index 0ddd30e..1f4e1e0 100755 --- a/create_ap +++ b/create_ap @@ -844,7 +844,6 @@ _cleanup() { # Restore original subnet to internet-facing interface ip -6 addr del "$INTERNET6"/128 dev ${INTERNET_IFACE} ip -6 addr add "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} - ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} fi fi @@ -1822,10 +1821,7 @@ EOF RA_MODE="ra-stateless" fi [[ -n "$DHCP_DNS6" ]] && echo "dhcp-option-force=option6:dns-server,${DHCP_DNS6}" >> $CONFDIR/dnsmasq.conf - cat <> $CONFDIR/dnsmasq.conf -dhcp-range=::,constructor:${WIFI_IFACE}, $RA_MODE, slaac, 24h -dhcp-authoritative -EOF + echo "dhcp-range=::,constructor:${WIFI_IFACE}, $RA_MODE, slaac, 24h" >> $CONFDIR/dnsmasq.conf fi MTU=$(get_mtu $INTERNET_IFACE) [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> $CONFDIR/dnsmasq.conf @@ -1860,10 +1856,8 @@ if [[ "$SHARE_METHOD" != "bridge" ]]; then ip -6 addr del "$INTERNET6"/"$PREFIXLEN6" dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" ip -6 addr add "$INTERNET6"/128 dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" - ip -6 route replace "$INTERNET6"/128 dev ${INTERNET_IFACE} || die "$VIRTDIEMSG" ip -6 addr add "$GATEWAY6"/"$PREFIXLEN6" dev ${WIFI_IFACE} || die "$VIRTDIEMSG" - ip -6 route replace "$INTERNET6"/"$PREFIXLEN6" dev ${WIFI_IFACE} || die "$VIRTDIEMSG" fi fi From fe98b1e20c835b1b3dde956849b5fb7615bae105 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Tue, 22 Dec 2020 22:59:58 -0800 Subject: [PATCH 11/41] Update README.md --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index c5b6e0f..2d0b7d0 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,4 @@ -## NOT MAINTAINED - -This project is no longer maintained. - -If you are still interested in this project, checkout the following fork that -also provides GUI: [lakinduakash/linux-wifi-hotspot] +This project is a fork of the no-longer-maintained [oblique/create_ap](//github.com/oblique/create_ap). ## Features @@ -94,5 +89,3 @@ Using the persistent [systemd](https://wiki.archlinux.org/index.php/systemd#Basi ## License FreeBSD - -[lakinduakash/linux-wifi-hotspot]: https://github.com/lakinduakash/linux-wifi-hotspot From 04d4c7c7bbc17bd7734f2f3163d7f8886ee859a2 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Sun, 24 Jan 2021 13:39:00 -0800 Subject: [PATCH 12/41] clarify --country option / COUNTRY config --- create_ap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create_ap b/create_ap index 5f4aa7f..f250762 100755 --- a/create_ap +++ b/create_ap @@ -53,7 +53,7 @@ usage() { echo " --vht_capab VHT capabilities" echo " --beacon-interval Set beacon interval in milliseconds (default 100)" echo " --dtim-period Set DTIM period in numbers of beacons (default 2)" - echo " --country Set two-letter country code for regularity (example: US)" + echo " --country Set two-letter country code for 802.11d regulatory domain (example: US)" echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" echo " --driver Choose your WiFi adapter driver (default: nl80211)" echo " --no-virt Do not create virtual interface" From 12107700553d370d1997cbfad8b618a05c1bb05b Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Fri, 21 May 2021 14:08:11 -0700 Subject: [PATCH 13/41] Allow 'gateway' to be listed as one DNS server, among several --- create_ap | 10 ++++------ create_ap.conf | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/create_ap b/create_ap index f250762..b77ec18 100755 --- a/create_ap +++ b/create_ap @@ -63,7 +63,9 @@ usage() { echo " back to managed" echo " --mac Set MAC address" echo " --dhcp-dns Set DNS returned by DHCP (default is gateway; see also --no-dns below)" + echo " Multiple servers may be specified (example: 'gateway,8.8.8.8')" echo " --dhcp-dns6 Set DNSv6 returned by DHCP (default is gateway; see also --no-dns below)" + echo " Multiple servers may be specified (example: 'gateway,2001:4860:4860::8888')" echo " --daemon Run create_ap in the background" echo " --pidfile Save daemon PID to file" echo " --logfile Save daemon messages to file" @@ -1808,12 +1810,8 @@ elif [[ $NO_DNSMASQ -eq 0 ]]; then else DNSMASQ_BIND=bind-dynamic fi - if [[ "$DHCP_DNS" == "gateway" ]]; then - DHCP_DNS="$GATEWAY" - fi - if [[ "$DHCP_DNS6" == "gateway" ]]; then - DHCP_DNS6="[$GATEWAY6]" - fi + DHCP_DNS="${DHCP_DNS/gateway/$GATEWAY}" + DHCP_DNS6="${DHCP_DNS6/gateway/[$GATEWAY6]}" cat << EOF > $CONFDIR/dnsmasq.conf interface=${WIFI_IFACE} ${DNSMASQ_BIND} diff --git a/create_ap.conf b/create_ap.conf index dd8763c..5c48afa 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -61,11 +61,11 @@ DTIM_INTERVAL=2 ########## Network Options ########## # DNS servers to be pushed by DHCP server; separate multiple with , -# Set to "gateway" to use the gateway itself +# Include "gateway" to use the gateway itself DHCP_DNS=gateway # IPv6 DNS servers to be pushed by DHCP server; enclose IPv6 # addresses in [], and separate multiple with , -# Set to "gateway" to use the gateway itself +# Include "gateway" to use the gateway itself DHCP_DNS6= # Set to 1 to disable DNS NO_DNS=0 From 69ae387561d673559fa02e4cbcdcdd6f6da612dd Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Fri, 21 May 2021 14:38:47 -0700 Subject: [PATCH 14/41] Clarify MAC, ETC_HOSTS, and ADDN_HOSTS in --help, and add example create_ap.conf comments Also makes it *possible* to set ADDN_HOSTS via create_ap.conf --- create_ap | 8 ++++---- create_ap.conf | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/create_ap b/create_ap index b77ec18..fda3775 100755 --- a/create_ap +++ b/create_ap @@ -61,7 +61,7 @@ usage() { echo " --fix-unmanaged If NetworkManager shows your interface as unmanaged after you" echo " close create_ap, then use this option to switch your interface" echo " back to managed" - echo " --mac Set MAC address" + echo " --mac Set MAC address of WiFi interface" echo " --dhcp-dns Set DNS returned by DHCP (default is gateway; see also --no-dns below)" echo " Multiple servers may be specified (example: 'gateway,8.8.8.8')" echo " --dhcp-dns6 Set DNSv6 returned by DHCP (default is gateway; see also --no-dns below)" @@ -85,8 +85,8 @@ usage() { echo " --no-dnsmasq Disable dnsmasq completely (implies --no-dns and also disables DHCP)" echo " -g IPv4 Gateway address for the Access Point (default: 192.168.12.1)" echo " --ipv6 Enable IPv6 support" - echo " -d DNS server will take into account /etc/hosts" - echo " -e DNS server will take into account additional hosts file" + echo " -d DNS server will include /etc/hosts in its results" + echo " -e DNS server will include additional hosts file in its results" echo echo "Useful informations:" echo " * If you're not using the --no-virt option, then you can create an AP with the same" @@ -693,7 +693,7 @@ REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS) FIX_UNMANAGED=0 LIST_RUNNING=0 diff --git a/create_ap.conf b/create_ap.conf index 5c48afa..53cbc87 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -71,8 +71,10 @@ DHCP_DNS6= NO_DNS=0 # Set to 1 to disable dnsmasq completely (DHCP and DNS) NO_DNSMASQ=0 -# Whether dnsmasq should use DNS servers provided in /etc/hosts or not +# Set to 1 to make dnsmasq DNS server include /etc/hosts in its results ETC_HOSTS=0 +# Additional hosts file that dnsmasq should include in its results +ADDN_HOSTS= # Set to 1 to enable MAC address based authentication MAC_FILTER=0 # Acceptance list for MAC address based authentication From 86a3d60e10d29ad0faec65db41965b42dbfe8f7b Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Wed, 19 Jan 2022 20:47:34 -0800 Subject: [PATCH 15/41] Enable WPS push button (PBC) and PIN modes Use 'sudo create_ap --wps-pbc ' to simulate the button being pushed, or 'sudo create_ap --wps-pin ,' to enroll a specific PIN requested by a device. --- README.md | 6 ++++ create_ap | 83 ++++++++++++++++++++++++++++++++++++++++++++++++-- create_ap.conf | 3 ++ 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2d0b7d0..705d820 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. * Create an AP (Access Point) at any channel. * Choose one of the following encryptions: WPA, WPA2, WPA/WPA2, Open (no encryption). * Hide your SSID. +* Enable [Wi-Fi Protected Setup](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup) (WPS) with push-button or PIN methods. * Disable communication between clients (client isolation). * IEEE 802.11n & 802.11ac support * Internet sharing methods: NATed or Bridged or None (no Internet sharing). @@ -50,6 +51,11 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. ### WPA + WPA2 passphrase: create_ap wlan0 eth0 MyAccessPoint MyPassPhrase +### WPS Push Button or PIN entry: + create_ap wlan0 eth0 MyAccessPoint MyPassPhrase + create_ap --wps-pbc wlan0 # Device will have 2 minutes to connect + create_ap --wps-pin wlan0,12345678 # Enroll PIN 12345678 for device requesting it + ### AP without Internet sharing: create_ap -n wlan0 MyAccessPoint MyPassPhrase diff --git a/create_ap b/create_ap index fda3775..db38534 100755 --- a/create_ap +++ b/create_ap @@ -40,6 +40,7 @@ usage() { echo " Use: 'nat' for NAT (default)" echo " 'bridge' for bridging" echo " 'none' for no Internet sharing (equivalent to -n)" + echo " --wps Enable WPS (Wireless Protected Setup) with push button (PBC) and PIN modes" echo " --psk Use 64 hex digits pre-shared-key instead of passphrase" echo " --hidden Make the Access Point hidden (do not broadcast the SSID)" echo " --mac-filter Enable MAC address filtering" @@ -77,6 +78,8 @@ usage() { echo " For an you can put the PID of create_ap or the WiFi interface." echo " If virtual WiFi interface was created, then use that one." echo " You can get them with --list-running" + echo " --wps-pbc Simulate WPS push button (PBC)" + echo " --wps-pin , Enroll PIN for WPS" echo " --mkconfig Store configs in conf_file" echo " --config Load configs from conf_file" echo @@ -686,6 +689,7 @@ DAEMON_LOGFILE=/dev/null NO_HAVEGED=0 USE_PSK=0 IPV6=0 +WPS=0 HOSTAPD_DEBUG_ARGS= REDIRECT_TO_LOCALHOST=0 @@ -693,7 +697,7 @@ REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS) FIX_UNMANAGED=0 LIST_RUNNING=0 @@ -1006,6 +1010,40 @@ list_clients() { fi } +wps_trigger() { + local wifi_iface pid + + # If PID is given, get the associated wifi iface + if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then + pid="$1" + wifi_iface=$(get_wifi_iface_from_pid "$pid") + [[ -z "$wifi_iface" ]] && die "'$pid' is not the pid of a running $PROGNAME instance." + fi + + [[ -z "$wifi_iface" ]] && wifi_iface="$1" + is_wifi_interface "$wifi_iface" || die "'$wifi_iface' is not a WiFi interface." + + [[ -z "$pid" ]] && pid=$(get_pid_from_wifi_iface "$wifi_iface") + [[ -z "$pid" ]] && die "'$wifi_iface' is not used from $PROGNAME instance.\n\ + Maybe you need to pass the virtual interface instead.\n\ + Use --list-running to find it out." + [[ -z "$CONFDIR" ]] && CONFDIR=$(get_confdir_from_pid "$pid") + + HOSTAPD_CLI=$(which hostapd_cli) + if ! $HOSTAPD_CLI -p $CONFDIR/hostapd_ctrl get_config | grep -q wps_state=configured; then + die "WPS is not configured. You need to run $PROGNAME with --wps, or add WPS=1 to config file." + fi + + if [[ "$2" = "PBC" ]]; then + echo "Triggering WPS pushbutton; your device will have 120 seconds to connect..." + $HOSTAPD_CLI -p $CONFDIR/hostapd_ctrl wps_pbc + else + echo "Enrolling WPS PIN '$2'..." + $HOSTAPD_CLI -p $CONFDIR/hostapd_ctrl wps_pin any "$2" + fi + $HOSTAPD_CLI -p $CONFDIR/hostapd_ctrl wps_get_status +} + has_running_instance() { local PID x @@ -1120,7 +1158,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","ipv6","mkconfig:","config:" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1278,10 +1316,26 @@ while :; do LIST_CLIENTS_ID="$1" shift ;; + --wps-pbc) + shift + WPS_TRIGGER_ID="$1" + WPS_TRIGGER_PIN="PBC" + shift; + ;; + --wps-pin) + shift + WPS_TRIGGER_ID="${1/,*/}" + WPS_TRIGGER_PIN="${1/*,/}" + shift; + ;; --no-haveged) shift NO_HAVEGED=1 ;; + --wps) + shift + WPS=1 + ;; --psk) shift USE_PSK=1 @@ -1342,7 +1396,7 @@ fi # Check if required number of positional args are present if [[ $# -lt 1 && $FIX_UNMANAGED -eq 0 && -z "$STOP_ID" && - $LIST_RUNNING -eq 0 && -z "$LIST_CLIENTS_ID" ]]; then + $LIST_RUNNING -eq 0 && -z "$LIST_CLIENTS_ID" && -z "$WPS_TRIGGER_ID" ]]; then usage >&2 exit 1 fi @@ -1383,6 +1437,11 @@ if [[ $(id -u) -ne 0 ]]; then exit 1 fi +if [[ -n "$WPS_TRIGGER_ID" ]]; then + wps_trigger "$WPS_TRIGGER_ID" "$WPS_TRIGGER_PIN" + exit 0 +fi + if [[ -n "$STOP_ID" ]]; then echo "Trying to kill $PROGNAME instance associated with $STOP_ID..." send_stop "$STOP_ID" @@ -1744,6 +1803,24 @@ beacon_int=${BEACON_INTERVAL} dtim_period=${DTIM_PERIOD} EOF +if [[ $WPS -eq 1 ]]; then + echo "Enabling WPS push button (PBC) and PIN modes!" + # WPS configuration: AP configured, do not allow external WPS Registrars, + # device type is "Network Infrastructure / AP" + cat << EOF >> $CONFDIR/hostapd.conf +wps_state=2 +ap_setup_locked=1 +device_type=6-0050F204-1 +config_methods=push_button label +EOF + # Show SSID as device_name unless hidden + # (other potential descriptive options are manufacturer, model_name, + # model_number, serial_number, os_version) + if [[ $HIDDEN -ne 1 ]]; then + echo "device_name=${SSID}" >> $CONFDIR/hostapd.conf + fi +fi + if [[ -n "$COUNTRY" ]]; then cat << EOF >> $CONFDIR/hostapd.conf country_code=${COUNTRY} diff --git a/create_ap.conf b/create_ap.conf index 53cbc87..f32aa6d 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -48,6 +48,9 @@ WPA_VERSION=2 IEEE80211N=0 # Whether IEEE 802.11ac (VHT) is enabled IEEE80211AC=0 +# Whether Wi-Fi Protected Setup (WPS) is enabled +# Use '--wps-pbc' to simulate the push button, or '--wps-pin' for PIN entry. +WPS=0 # HT / VHT capabilities # For all possible options please look at # https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf From 624eb207fb2f3e38dfd8e675caf6bd3e2f35616b Mon Sep 17 00:00:00 2001 From: exuvo Date: Mon, 11 Apr 2022 15:11:13 +0200 Subject: [PATCH 16/41] Fix incorrect DTIM_PERIOD name in example config Fixes https://github.com/dlenski/create_ap/issues/2 --- create_ap.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create_ap.conf b/create_ap.conf index f32aa6d..1b74108 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -59,7 +59,7 @@ VHT_CAPAB= # Beacon interval, and DTIM period (https://en.wikipedia.org/wiki/DTIM) # in multiples of the beacon interval. BEACON_INTERVAL=100 -DTIM_INTERVAL=2 +DTIM_PERIOD=2 ########## Network Options ########## From 91e095ae7a328b79cde0a93881ee091c0328cfda Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Fri, 8 Dec 2023 13:36:35 -0800 Subject: [PATCH 17/41] Fix (?) WPS support I added WPS push-button and PIN modes in 86a3d60, but now they don't work for me. Apparently: 1. hostapd's built in EAP server *must* be enabled in order for WPS to complete. (Did this ever actually work for me previously, without this??) 2. Also, the 'push_button' method seems to have been replaced with 'virtual_push_button', per the following warning message from hostapd (v2.9): ``` WPS: Converting push_button to virtual_push_button for WPS 2.0 compliance ``` --- create_ap | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/create_ap b/create_ap index db38534..25273f5 100755 --- a/create_ap +++ b/create_ap @@ -1808,10 +1808,11 @@ if [[ $WPS -eq 1 ]]; then # WPS configuration: AP configured, do not allow external WPS Registrars, # device type is "Network Infrastructure / AP" cat << EOF >> $CONFDIR/hostapd.conf +eap_server=1 wps_state=2 ap_setup_locked=1 device_type=6-0050F204-1 -config_methods=push_button label +config_methods=push_button virtual_push_button label EOF # Show SSID as device_name unless hidden # (other potential descriptive options are manufacturer, model_name, From 365d9e37994186e43825d6dc3fd605b7f8a5e5c4 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Fri, 8 Dec 2023 13:36:36 -0800 Subject: [PATCH 18/41] Add --metered option to indicate that network is metered and/or should be used sparingly This extremely useful StackExchange post summarizes the different ways of indicating this to clients: https://unix.stackexchange.com/a/631812 1. Microsoft's "network cost information element" (https://learn.microsoft.com/fi-fi/windows-hardware/drivers/mobilebroadband/network-cost-information-element) which seems to be quasi-standard at this point. Recent versions of NetworkManager also understand it, but due to a mistake in earlier versions of Microsoft's documentation, older versions parse the element incorrectly (gory details at https://openwrt.org/docs/guide-user/network/wifi/ms-meteredconnection#under_the_hood). 2. Apple's vendor element (https://apple.stackexchange.com/a/457630) seems to be undocumented, but it can be copied/used as is. 3. Adding the value "ANDROID_METERED" as part of the force-sent DHCP option 43 causes Android devices to perceive this wireless network as metered (see https://unix.stackexchange.com/a/631812 as well as https://www.lorier.net/docs/android-metered.html). --- create_ap | 34 ++++++++++++++++++++++++++++++++-- create_ap.conf | 2 ++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/create_ap b/create_ap index 25273f5..86bf1e8 100755 --- a/create_ap +++ b/create_ap @@ -40,6 +40,7 @@ usage() { echo " Use: 'nat' for NAT (default)" echo " 'bridge' for bridging" echo " 'none' for no Internet sharing (equivalent to -n)" + echo " --metered Indicate to clients that WiFi is metered and/or should be used sparingly." echo " --wps Enable WPS (Wireless Protected Setup) with push button (PBC) and PIN modes" echo " --psk Use 64 hex digits pre-shared-key instead of passphrase" echo " --hidden Make the Access Point hidden (do not broadcast the SSID)" @@ -672,6 +673,7 @@ MAC_FILTER=0 MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept ISOLATE_CLIENTS=0 SHARE_METHOD=nat +METERED=0 IEEE80211N=0 IEEE80211AC=0 HT_CAPAB='[HT40+]' @@ -697,7 +699,7 @@ REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED) FIX_UNMANAGED=0 LIST_RUNNING=0 @@ -1158,7 +1160,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1227,6 +1229,10 @@ while :; do SHARE_METHOD="$1" shift ;; + --metered) + shift + METERED=1 + ;; --ieee80211n) shift IEEE80211N=1 @@ -1801,8 +1807,24 @@ ignore_broadcast_ssid=$HIDDEN ap_isolate=$ISOLATE_CLIENTS beacon_int=${BEACON_INTERVAL} dtim_period=${DTIM_PERIOD} +#device_name=Fnord +#manufacturer=Vark EOF +if [[ $METERED -ne 0 ]]; then + # Add Microsoft's "network cost information element" + # (https://learn.microsoft.com/fi-fi/windows-hardware/drivers/mobilebroadband/network-cost-information-element) + # and Apple's vendor element that indicates a personal hotspot + # (https://apple.stackexchange.com/questions/199163/how-does-ios-and-os-x-detect-when-a-wi-fi-network-is-a-personal-hotspot) + # The Microsoft element seems to be quasi-standardized now. + + # We intentionally set the last byte (which is reserved and + # supposed to always be 00) to 02 in order to work around a bug caused by + # previously-incorrect documentation by Microsoft. See: + # https://openwrt.org/docs/guide-user/network/wifi/ms-meteredconnection#under_the_hood + echo "vendor_elements=dd080050f21102000002dd0a0017f206010103010000" >> $CONFDIR/hostapd.conf +fi + if [[ $WPS -eq 1 ]]; then echo "Enabling WPS push button (PBC) and PIN modes!" # WPS configuration: AP configured, do not allow external WPS Registrars, @@ -1897,6 +1919,14 @@ dhcp-range=${GATEWAY%.*}.1,${GATEWAY%.*}.254,255.255.255.0,24h dhcp-option-force=option:router,${GATEWAY} dhcp-option-force=option:dns-server,${DHCP_DNS} EOF + + # Android devices apparently detect metered networks using + # this DHCP vendor option, according to + # https://www.lorier.net/docs/android-metered.html + if [[ $METERED -ne 0 ]]; then + echo "dhcp-option-force=43,ANDROID_METERED" >> $CONFDIR/dnsmasq.conf + fi + if [[ $IPV6 -ne 0 ]]; then if [[ "$NO_DNS" -ne 0 ]]; then RA_MODE="ra-names" diff --git a/create_ap.conf b/create_ap.conf index 1b74108..4f7db13 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -30,6 +30,8 @@ GATEWAY=10.0.0.1 IPV6=0 # Set whether the connected clients can see each other or not ISOLATE_CLIENTS=0 +# Indicate to clients that WiFi is metered and/or should be used sparingly +METERED=0 ########## Wireless Options ########## From 4664f050155f0d74be2489c7ddf6c156eac42837 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Thu, 7 Dec 2023 18:42:00 -0800 Subject: [PATCH 19/41] Remove the 'haveged' options and entropy watchdog These were needed because of an annoying bug in old versions of 'hostapd', where the kernel's entropy pool was used incorrectly, and 'hostapd' would decide that there wasn't enough randomness available, e.g.: random: Only 9/20 bytes of strong random data available from /dev/random random: Not enough entropy pool available for secure operations WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects That issue has been fixed since hostapd v2.6, released in 2016 (https://packetstormsecurity.com/files/156573/Hostapd-Insufficient-Entropy.html), so there's really no reason for 'create_ap' to have an entropy-checking watchdog or to encourage users to install 'haveged'. --- README.md | 3 ++- bash_completion | 3 --- create_ap | 43 ++----------------------------------------- create_ap.conf | 2 -- 4 files changed, 4 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 705d820..3ae4b61 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,11 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. * util-linux (for getopt) * procps or procps-ng * hostapd + * Version 2.6 or newer is required; earlier versions may + fail unpredictably due to [a RNG bug](https://packetstormsecurity.com/files/156573/Hostapd-Insufficient-Entropy.html). * iproute2 * iw * iwconfig (you only need this if 'iw' can not recognize your adapter) -* haveged (optional) ### For 'NATed' or 'None' Internet sharing method * dnsmasq diff --git a/bash_completion b/bash_completion index aae0bb2..78a2a15 100644 --- a/bash_completion +++ b/bash_completion @@ -115,9 +115,6 @@ _create_ap() { --no-virt) # No Options ;; - --no-haveged) - # No Options - ;; --fix-unmanaged) # No Options ;; diff --git a/create_ap b/create_ap index 86bf1e8..7df1e3c 100755 --- a/create_ap +++ b/create_ap @@ -8,7 +8,6 @@ # iproute2 # iw # iwconfig (you only need this if 'iw' can not recognize your adapter) -# haveged (optional) # dependencies for 'nat' or 'none' Internet sharing method # dnsmasq @@ -59,7 +58,6 @@ usage() { echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" echo " --driver Choose your WiFi adapter driver (default: nl80211)" echo " --no-virt Do not create virtual interface" - echo " --no-haveged Do not run 'haveged' automatically when needed" echo " --fix-unmanaged If NetworkManager shows your interface as unmanaged after you" echo " close create_ap, then use this option to switch your interface" echo " back to managed" @@ -462,28 +460,6 @@ get_new_ipv6addr() { echo $NEWIP } -# start haveged when needed -haveged_watchdog() { - local show_warn=1 - while :; do - mutex_lock - if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then - if ! which haveged > /dev/null 2>&1; then - if [[ $show_warn -eq 1 ]]; then - echo "WARN: Low entropy detected. We recommend you to install \`haveged'" - show_warn=0 - fi - elif ! pidof haveged > /dev/null 2>&1; then - echo "Low entropy detected, starting haveged" - # boost low-entropy - haveged -w 1024 -p $COMMON_CONFDIR/haveged.pid - fi - fi - mutex_unlock - sleep 2 - done -} - NETWORKMANAGER_CONF=/etc/NetworkManager/NetworkManager.conf NM_OLDER_VERSION=1 @@ -688,7 +664,6 @@ NEW_MACADDR= DAEMONIZE=0 DAEMON_PIDFILE= DAEMON_LOGFILE=/dev/null -NO_HAVEGED=0 USE_PSK=0 IPV6=0 WPS=0 @@ -698,7 +673,7 @@ REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND - NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE NO_HAVEGED WIFI_IFACE INTERNET_IFACE + NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED) FIX_UNMANAGED=0 @@ -718,8 +693,6 @@ OLD_MACADDR= IP_ADDRS= ROUTE_ADDRS= -HAVEGED_WATCHDOG_PID= - _cleanup() { local PID x @@ -727,9 +700,6 @@ _cleanup() { mutex_lock disown -a - # kill haveged_watchdog - [[ -n "$HAVEGED_WATCHDOG_PID" ]] && kill $HAVEGED_WATCHDOG_PID - # kill processes for x in $CONFDIR/*.pid; do # even if the $CONFDIR is empty, the for loop will assign @@ -1160,7 +1130,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-haveged","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1334,10 +1304,6 @@ while :; do WPS_TRIGGER_PIN="${1/*,/}" shift; ;; - --no-haveged) - shift - NO_HAVEGED=1 - ;; --wps) shift WPS=1 @@ -2114,11 +2080,6 @@ fi # start access point echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" -if [[ $NO_HAVEGED -eq 0 ]]; then - haveged_watchdog & - HAVEGED_WATCHDOG_PID=$! -fi - # start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout) STDBUF_PATH=`which stdbuf` if [ $? -eq 0 ]; then diff --git a/create_ap.conf b/create_ap.conf index 4f7db13..b7c0809 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -95,5 +95,3 @@ DRIVER=nl80211 DAEMONIZE=0 # Set to 1 to disable virtual interface creation NO_VIRT=0 -# Set to 1 to disable haveged random number generation -NO_HAVEGED=0 From 8bb90688c9731b05eef319d4997c86da4a0c85ad Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Tue, 12 Dec 2023 21:32:57 -0800 Subject: [PATCH 20/41] Install create_ap.resume in the proper location, /usr/lib/systemd/system-sleep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For unclear reasons, this only worked for me on Ubuntu 16.04 if it was put in `/lib/systemd/system-sleep`, and NOT in `/usr/lib/systemd/system-sleep`. I'm unsure if this was a systemd bug, a distro bug, or what… but it's probably no longer applicable on modern distros. Fix it, and leave behind a warning comment. Thanks to @exuvo for bringing this up in https://github.com/dlenski/create_ap/issues/1. --- Makefile | 4 ++-- create_ap.resume | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 878f94f..bf87cbb 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ install: install -Dm755 create_ap $(DESTDIR)$(BINDIR)/create_ap install -Dm644 --backup=existing --suffix=.orig create_ap.conf $(DESTDIR)/etc/create_ap.conf [ ! -d /lib/systemd/system ] || install -Dm644 create_ap.service $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service - [ ! -d /lib/systemd/system-sleep ] || install -Dm755 create_ap.resume $(DESTDIR)/lib/systemd/system-sleep/create_ap.resume + [ ! -d /lib/systemd/system-sleep ] || install -Dm755 create_ap.resume $(DESTDIR)$(PREFIX)/lib/systemd/system-sleep/create_ap.resume [ ! -e /sbin/openrc-run ] || install -Dm755 create_ap.openrc $(DESTDIR)/etc/init.d/create_ap install -Dm644 bash_completion $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md @@ -19,7 +19,7 @@ uninstall: rm -f $(DESTDIR)$(BINDIR)/create_ap rm -f $(DESTDIR)/etc/create_ap.conf [ ! -f /lib/systemd/system/create_ap.service ] || rm -f $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service - [ ! -f /lib/systemd/system-sleep/create_ap.resume ] || rm -f $(DESTDIR)/lib/systemd/system/create_ap.resume + [ ! -f /lib/systemd/system-sleep/create_ap.resume ] || rm -f $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.resume [ ! -e /sbin/openrc-run ] || rm -f $(DESTDIR)/etc/init.d/create_ap rm -f $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap rm -f $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md diff --git a/create_ap.resume b/create_ap.resume index 34ee440..b71994a 100755 --- a/create_ap.resume +++ b/create_ap.resume @@ -1,6 +1,16 @@ #!/bin/sh set -e +###################################################################### +# WARNING: # For unclear reasons (distribution-specific bug? +# systemd bug?), this script might work +# ONLY if it is named /lib/systemd/system-sleep +# and NOT if it is named /usr/lib/systemd/system-sleep +# +# If you encounter this issue, please report at +# https://github.com/dlenski/create_ap/issues/1 +###################################################################### + # After resume, restart create_ap service (if it was already running) # See: # https://www.freedesktop.org/software/systemd/man/systemd-suspend.service.html From 5f7257db829ffaa2e332c51b9375cf2f829548a2 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 29 Apr 2024 09:00:29 -0700 Subject: [PATCH 21/41] Show QR code --- create_ap | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/create_ap b/create_ap index 7df1e3c..47e9bea 100755 --- a/create_ap +++ b/create_ap @@ -2077,6 +2077,28 @@ if [[ "$SHARE_METHOD" != "bridge" ]]; then fi fi +escape() { + local length="${#1}" + for (( i = 0; i < length; i++ )); do + local c="${1:i:1}" + case $c in + [\\\"\;\:\,]) echo -n "\\$c" ;; + *) echo -n "$c" ;; + esac + done +} + +URI="WIFI:S:$(escape $SSID);" +if [[ -n "$PASSPHRASE" ]]; then + URI+="T:WPA;P:$(escape $PASSPHRASE);" +fi +if [[ $HIDDEN -ne 0 ]]; then + URI+="H:true;" +fi +URI+=";" +echo "$URI" >&2 +qrencode -t utf8 "$URI" >&2 + # start access point echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" From 946c41488ec35918158d4912366cf4320c07a936 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Wed, 8 Jan 2025 22:43:38 -0800 Subject: [PATCH 22/41] Enabled local timezone advertisement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature is specified in 802.11v-2011 7.3.2.87. The timezone is supposed to be specified via beacon tag 98 (0x62) as a string in "POSIX format" (https://developer.ibm.com/articles/au-aix-posix/#understanding-the-posix-format3). Happily, the POSIX format timezone is easily extracted from the tzfile format (https://stackoverflow.com/a/67045287), and /etc/localtime is a symlink to such a file. I'm not sure what OSes, if any, will detect these tags and use them to set timezone. Most likely it would only be used as a fallback from some "location-based" timezone determination algorithm. - Android 5.x source alludes to knowledge of this 802.11 feature in `DateTimeSettings.java`: https://android.googlesource.com/platform/packages/apps/Settings/+/android-5.0.1_r1/src/com/android/settings/DateTimeSettings.java#113 - … but more recent versions of Android don't appear to mention it at all: https://android.googlesource.com/platform/packages/apps/Settings/+/main/src/com/android/settings/datetime/DateTimeSettings.java FIXME: The capability of advertising local timezoney was added to hostapd in https://chromium.googlesource.com/external/w1.fi/cgit/hostap/+/39b97072b2a45551e6f20e6251eeaca269f22a2d%5E%21/#F1 with the 'time_zone' variable, but appears to be broken in hostapd v2.9. --- create_ap | 37 ++++++++++++++++++++++++++++++++++--- create_ap.conf | 2 ++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/create_ap b/create_ap index 47e9bea..62988bf 100755 --- a/create_ap +++ b/create_ap @@ -55,6 +55,7 @@ usage() { echo " --beacon-interval Set beacon interval in milliseconds (default 100)" echo " --dtim-period Set DTIM period in numbers of beacons (default 2)" echo " --country Set two-letter country code for 802.11d regulatory domain (example: US)" + echo " --timezone Advertise local timezone in beacons (following 802.11v-2011 7.3.2.87)" echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" echo " --driver Choose your WiFi adapter driver (default: nl80211)" echo " --no-virt Do not create virtual interface" @@ -657,6 +658,7 @@ VHT_CAPAB= DRIVER=nl80211 NO_VIRT=0 COUNTRY= +TIMEZONE= FREQ_BAND=2.4 BEACON_INTERVAL=100 DTIM_PERIOD=2 @@ -672,7 +674,7 @@ HOSTAPD_DEBUG_ARGS= REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS - SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY FREQ_BAND + SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY TIMEZONE FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED) @@ -1130,7 +1132,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1239,6 +1241,10 @@ while :; do COUNTRY="$1" shift ;; + --timezone) + shift + TIMEZONE=1 + ;; --freq-band) shift FREQ_BAND="$1" @@ -1777,18 +1783,20 @@ dtim_period=${DTIM_PERIOD} #manufacturer=Vark EOF +VENDOR_ELEMENTS="" if [[ $METERED -ne 0 ]]; then # Add Microsoft's "network cost information element" # (https://learn.microsoft.com/fi-fi/windows-hardware/drivers/mobilebroadband/network-cost-information-element) # and Apple's vendor element that indicates a personal hotspot # (https://apple.stackexchange.com/questions/199163/how-does-ios-and-os-x-detect-when-a-wi-fi-network-is-a-personal-hotspot) # The Microsoft element seems to be quasi-standardized now. + VENDOR_ELEMENTS+="dd080050f21102000002" # We intentionally set the last byte (which is reserved and # supposed to always be 00) to 02 in order to work around a bug caused by # previously-incorrect documentation by Microsoft. See: # https://openwrt.org/docs/guide-user/network/wifi/ms-meteredconnection#under_the_hood - echo "vendor_elements=dd080050f21102000002dd0a0017f206010103010000" >> $CONFDIR/hostapd.conf + VENDOR_ELEMENTS+="dd0a0017f206010103010000" fi if [[ $WPS -eq 1 ]]; then @@ -1817,6 +1825,25 @@ ieee80211d=1 EOF fi +if [[ -n "$TIMEZONE" ]]; then + # FIXME: This capability was added to hostapd in + # https://chromium.googlesource.com/external/w1.fi/cgit/hostap/+/39b97072b2a45551e6f20e6251eeaca269f22a2d%5E%21/#F1 + # with the 'time_zone' variable, but appears to be broken in hostapd v2.9 + + # Per 802.11v-2011 7.3.2.87, the timezone is supposed to be specified via tag 98 (0x62) + # as a string in "POSIX format" (https://developer.ibm.com/articles/au-aix-posix/#understanding-the-posix-format3). + # Happily, the POSIX format timezone is easily extracted from the tzfile (https://stackoverflow.com/a/67045287), + # and /etc/localtime is a symlink to such a file. + POSIXTZ=$(tail -n1 /etc/localtime) + TZNAME=$(readlink -f /etc/localtime | sed -e 's|^.*/zoneinfo/||') + VENDOR_ELEMENTS+=$(printf "62%02x" ${#POSIXTZ})$(echo -n "$POSIXTZ" | xxd -p) + echo "Kludging timezone tag (802.11v-2011 7.3.2.87) for POSIX timezone '$POSIXTZ' ($TZNAME) into beacon via vendor_elements" >&2 + + # If/when 'time_zone' variable in hostapd.conf is fixed: + #echo "time_advertisement=2" >> $CONFDIR/hostapd.conf + #echo "time_zone=$POSIXTZ" >> $CONFDIR/hostapd.conf +fi + if [[ $FREQ_BAND == 2.4 ]]; then echo "hw_mode=g" >> $CONFDIR/hostapd.conf else @@ -1865,6 +1892,10 @@ rsn_pairwise=CCMP EOF fi +if [[ -n "$VENDOR_ELEMENTS" ]]; then + echo "vendor_elements=$VENDOR_ELEMENTS" >> $CONFDIR/hostapd.conf +fi + if [[ "$SHARE_METHOD" == "bridge" ]]; then echo "bridge=${BRIDGE_IFACE}" >> $CONFDIR/hostapd.conf elif [[ $NO_DNSMASQ -eq 0 ]]; then diff --git a/create_ap.conf b/create_ap.conf index b7c0809..3fdee25 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -43,6 +43,8 @@ CHANNEL=default FREQ_BAND=2.4 # Country code (ISO/IEC 3166-1) to set regulatory domain COUNTRY= +# Whether to advertise local timezone (802.11v-2011 7.3.2.87) +TIMEZONE=0 # WPA version # Available options: "1", "2", "1+2" (or "3") WPA_VERSION=2 From a4e1cee9937286713cde024a0440dc64ff8717c5 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Wed, 8 Jan 2025 23:04:00 -0800 Subject: [PATCH 23/41] Enable GPS location advertisement ("French drone format") The format is defined in this French legislative document specifying how UAVs/drones should broadcast their GPS position and heading via vendor elemnts in WiFi beacons: https://www.legifrance.gouv.fr/eli/arrete/2019/12/27/ECOI1934044A/jo/texte Wireshark dissector shows how the sub-fields are decoded: https://gitlab.com/wireshark/wireshark/commit/7ed3180 There are other fields such as "takeoff" coordinates, takeoff-relative altitude, heading, and aircraft serial numbers; these seem pointless for a non-aircraft application. --- create_ap | 31 +++++++++++++++++++++++++++++-- create_ap.conf | 3 +++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/create_ap b/create_ap index 62988bf..d3145fe 100755 --- a/create_ap +++ b/create_ap @@ -56,6 +56,7 @@ usage() { echo " --dtim-period Set DTIM period in numbers of beacons (default 2)" echo " --country Set two-letter country code for 802.11d regulatory domain (example: US)" echo " --timezone Advertise local timezone in beacons (following 802.11v-2011 7.3.2.87)" + echo " --gps Advertise location in beacons (coordinates are in 10^5 degree)" echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" echo " --driver Choose your WiFi adapter driver (default: nl80211)" echo " --no-virt Do not create virtual interface" @@ -659,6 +660,7 @@ DRIVER=nl80211 NO_VIRT=0 COUNTRY= TIMEZONE= +GPS= FREQ_BAND=2.4 BEACON_INTERVAL=100 DTIM_PERIOD=2 @@ -674,7 +676,7 @@ HOSTAPD_DEBUG_ARGS= REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS - SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY TIMEZONE FREQ_BAND + SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY TIMEZONE GPS FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED) @@ -1132,7 +1134,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1245,6 +1247,11 @@ while :; do shift TIMEZONE=1 ;; + --gps) + shift + GPS="$1" + shift + ;; --freq-band) shift FREQ_BAND="$1" @@ -1892,6 +1899,26 @@ rsn_pairwise=CCMP EOF fi +if [[ -n "$GPS" ]]; then + # The format is defined in this French law requiring UAVs/drones to broadcast + # their GPS position and heading via WiFi beacons: + # https://www.legifrance.gouv.fr/eli/arrete/2019/12/27/ECOI1934044A/jo/texte + # Wireshark dissector clarifies some things: + # https://gitlab.com/wireshark/wireshark/commit/7ed3180 + # Other fields such as "takeoff" coords, takeoff-relative altitude, and heading seem pointless + # for a non-aircraft application. + + IFS=, read LAT LNG <<< "$GPS" + [[ $LAT -lt 0 ]] && LAT=$((0x100000000+$LAT)) + [[ $LNG -lt 0 ]] && LNG=$((0x100000000+$LNG)) + VENDOR_ELEMENTS+="dd136a5c3501" + VENDOR_ELEMENTS+="010101" # version (01) = 01 "sa valeur est fixée à 1" + VENDOR_ELEMENTS+=$(printf "0404%08x" $LAT) # current latitude (+N,-S) in 10^-5 degrees + VENDOR_ELEMENTS+=$(printf "0504%08x" $LNG) # current longitude (+W,-E) in 10^-5 degrees + #VENDOR_ELEMENTS+="06020000" # absolute altitude in m + #VENDOR_ELEMENTS+="0a0100" # horizontal speed in m/s +fi + if [[ -n "$VENDOR_ELEMENTS" ]]; then echo "vendor_elements=$VENDOR_ELEMENTS" >> $CONFDIR/hostapd.conf fi diff --git a/create_ap.conf b/create_ap.conf index 3fdee25..db1f893 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -45,6 +45,9 @@ FREQ_BAND=2.4 COUNTRY= # Whether to advertise local timezone (802.11v-2011 7.3.2.87) TIMEZONE=0 +# Advertise location in GPS coordinates, lat/lng in 10^-5 degrees +# (e.g. '4078628,-7396287' for Central Park in New York) +GPS= # WPA version # Available options: "1", "2", "1+2" (or "3") WPA_VERSION=2 From 17c8e6d964213908b368a320bfb319a19de92c00 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 29 Apr 2024 09:00:29 -0700 Subject: [PATCH 24/41] Show QR code only if qrencode available --- create_ap | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/create_ap b/create_ap index d3145fe..91cf70e 100755 --- a/create_ap +++ b/create_ap @@ -2146,16 +2146,19 @@ escape() { done } -URI="WIFI:S:$(escape $SSID);" -if [[ -n "$PASSPHRASE" ]]; then - URI+="T:WPA;P:$(escape $PASSPHRASE);" -fi -if [[ $HIDDEN -ne 0 ]]; then - URI+="H:true;" +QRENCODE_PATH=`which qrencode` +if [ $? -eq 0 ]; then + URI="WIFI:S:$(escape $SSID);" + if [[ -n "$PASSPHRASE" ]]; then + URI+="T:WPA;P:$(escape $PASSPHRASE);" + fi + if [[ $HIDDEN -ne 0 ]]; then + URI+="H:true;" + fi + URI+=";" + echo "WiFi connection QR code:" + qrencode -t utf8 "$URI" >&2 fi -URI+=";" -echo "$URI" >&2 -qrencode -t utf8 "$URI" >&2 # start access point echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" From 8b7008c3ade4a096416a5998b89d265cc1c78159 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Sat, 22 Feb 2025 16:58:22 -0800 Subject: [PATCH 25/41] Add WPA3 support and make WPA2/3 the default --- README.md | 6 +++--- create_ap | 27 +++++++++++++++++++-------- create_ap.conf | 6 +++--- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 3ae4b61..2c91f7a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. ## Features * Create an AP (Access Point) at any channel. -* Choose one of the following encryptions: WPA, WPA2, WPA/WPA2, Open (no encryption). +* Choose one of the following encryptions: WPA, WPA2, WPA3, WPA/WPA2, WPA2/WPA3, Open (no encryption). * Hide your SSID. * Enable [Wi-Fi Protected Setup](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup) (WPS) with push-button or PIN methods. * Disable communication between clients (client isolation). @@ -49,7 +49,7 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. ### No passphrase (open network): create_ap wlan0 eth0 MyAccessPoint -### WPA + WPA2 passphrase: +### WPA2 + WPA3 passphrase: create_ap wlan0 eth0 MyAccessPoint MyPassPhrase ### WPS Push Button or PIN entry: @@ -75,7 +75,7 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. ### No passphrase (open network) using pipe: echo -e "MyAccessPoint" | create_ap wlan0 eth0 -### WPA + WPA2 passphrase using pipe: +### WPA2 + WPA3 passphrase using pipe: echo -e "MyAccessPoint\nMyPassPhrase" | create_ap wlan0 eth0 ### Enable IEEE 802.11n diff --git a/create_ap b/create_ap index 91cf70e..edc8811 100755 --- a/create_ap +++ b/create_ap @@ -32,7 +32,7 @@ usage() { echo " -h, --help Show this help" echo " --version Print version number" echo " -c Channel number (default: 1)" - echo " -w Use 1 for WPA, use 2 for WPA2, use 1+2 for both (default: 1+2)" + echo " -w Use 1 for WPA, use 2 for WPA2, use 3 for WPA3, use 1+2+3 for all (default: 2+3)" echo " -n Disable Internet sharing (if you use this, don't pass" echo " the argument)" echo " -m Method for Internet sharing." @@ -638,7 +638,7 @@ networkmanager_wait_until_unmanaged() { CHANNEL=default GATEWAY=192.168.12.1 -WPA_VERSION=1+2 +WPA_VERSION=2+3 ETC_HOSTS=0 ADDN_HOSTS= DHCP_DNS=gateway @@ -1173,7 +1173,6 @@ while :; do -w) shift WPA_VERSION="$1" - [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2 shift ;; -g) @@ -1884,21 +1883,32 @@ if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then fi if [[ -n "$PASSPHRASE" ]]; then - [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 if [[ $USE_PSK -eq 0 ]]; then WPA_KEY_TYPE=passphrase else WPA_KEY_TYPE=psk fi - cat << EOF >> $CONFDIR/hostapd.conf -wpa=${WPA_VERSION} + case "$WPA_VERSION" in + 1) wpa=1; wpapw=TKIP ;; + *1*) wpa=3; wpapw="TKIP CCMP" ;; + *) wpa=2; wpapw=CCMP ;; + esac + case "$WPA_VERSION" in + 3) wpaw=2; wpakm="SAE" ;; + *3*) wpaw=1; wpakm="WPA-PSK WPA-PSK-SHA256 SAE" ;; + *) wpaw=0; wpakm="WPA-PSK WPA-PSK-SHA256" ;; + esac + cat <> $CONFDIR/hostapd.conf +wpa=$wpa wpa_${WPA_KEY_TYPE}=${PASSPHRASE} -wpa_key_mgmt=WPA-PSK -wpa_pairwise=TKIP CCMP +wpa_key_mgmt=$wpakm +wpa_pairwise=$wpapw rsn_pairwise=CCMP +ieee80211w=$wpaw EOF fi + if [[ -n "$GPS" ]]; then # The format is defined in this French law requiring UAVs/drones to broadcast # their GPS position and heading via WiFi beacons: @@ -2155,6 +2165,7 @@ if [ $? -eq 0 ]; then if [[ $HIDDEN -ne 0 ]]; then URI+="H:true;" fi + # If the AP is WPA3-only, should we add the transition-disable indicator? "R:1;" (https://superuser.com/a/1752085) URI+=";" echo "WiFi connection QR code:" qrencode -t utf8 "$URI" >&2 diff --git a/create_ap.conf b/create_ap.conf index db1f893..9dea568 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -48,9 +48,9 @@ TIMEZONE=0 # Advertise location in GPS coordinates, lat/lng in 10^-5 degrees # (e.g. '4078628,-7396287' for Central Park in New York) GPS= -# WPA version -# Available options: "1", "2", "1+2" (or "3") -WPA_VERSION=2 +# WPA-Personal version +# Available options: "1", "2", "3" +WPA_VERSION=2+3 # Whether IEEE 802.11n (HT) is enabled IEEE80211N=0 # Whether IEEE 802.11ac (VHT) is enabled From 64845860d4c30b763bdaf964101d866078826079 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Sat, 22 Feb 2025 22:38:37 -0800 Subject: [PATCH 26/41] Check for adapters which don't support 802.11w and thus can't do WPA3 While WPA3 is "mostly" a pure-software feature, it requires 802.11w (protected management frames) which require hardware support. Detect adapters that don't support this and prevent them from attempting WPA3. --- create_ap | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/create_ap b/create_ap index edc8811..ec0414e 100755 --- a/create_ap +++ b/create_ap @@ -303,6 +303,18 @@ get_adapter_kernel_module() { echo ${MODULE##*/} } +can_do_80211w() { + local PHY + PHY=$(get_phy_device "$1") + [[ $? -ne 0 ]] && return 1 + if [[ $USE_IWCONFIG -eq 1 ]]; then + # https://askubuntu.com/a/1445236 + grep -q MFP_CAPABLE /sys/kernel/debug/ieee80211/${PHY}/hwflags + else + iw phy $PHY info | grep -q 'CMAC (00-0f-ac:6)' + fi +} + can_be_sta_and_ap() { # iwconfig does not provide this information, assume false [[ $USE_IWCONFIG -eq 1 ]] && return 1 @@ -1491,6 +1503,16 @@ if ! can_be_sta_and_ap ${WIFI_IFACE}; then fi fi +if [[ "$WPA_VERSION" = *3* ]] && ! can_do_80211w ${WIFI_IFACE}; then + if [[ "$WPA_VERSION" = 3 ]]; then + echo "ERROR: Your adapter does not support protected management frames (802.11w), no WPA3" >&2 + exit 1 + else + echo "WARN: Your adapter does not support protected management frames (802.11w), disabling WPA3" >&2 + WPA_VERSION="${WPA_VERSION/3}" + fi +fi + HOSTAPD=$(which hostapd) if [[ ! -x "$HOSTAPD" ]]; then From c26da0d3ff5a36bd8f412a7d65ade1a2a48a8f4a Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 24 Feb 2025 22:11:18 -0800 Subject: [PATCH 27/41] Allow virtual AP device on separate channel if adapter supports it --- create_ap | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/create_ap b/create_ap index ec0414e..7a327af 100755 --- a/create_ap +++ b/create_ap @@ -330,6 +330,12 @@ can_be_sta_and_ap() { return 1 } +can_be_multi_channel() { + # iwconfig does not provide this information, assume false + [[ $USE_IWCONFIG -eq 1 ]] && return 1 + get_adapter_info "$1" | grep -E '#channels <= [2-9]+' > /dev/null 2>&1 +} + can_be_ap() { # iwconfig does not provide this information, assume true [[ $USE_IWCONFIG -eq 1 ]] && return 0 @@ -1733,16 +1739,21 @@ if [[ $NO_VIRT -eq 0 ]]; then WIFI_IFACE_FREQ=$(iw dev ${WIFI_IFACE} link | grep -i freq | awk '{print $2}') WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel ${WIFI_IFACE_FREQ}) echo -n "${WIFI_IFACE} is already associated with channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" - if is_5ghz_frequency $WIFI_IFACE_FREQ; then - FREQ_BAND=5 - else - FREQ_BAND=2.4 - fi - if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then - echo ", fallback to channel ${WIFI_IFACE_CHANNEL}" - CHANNEL=$WIFI_IFACE_CHANNEL + if can_be_multi_channel ${WIFI_IFACE}; then + echo ", allowing because adapter supports multiple simultaneous channels" + echo "WARN: This may result in poor or unreliable performance." >&2 else - echo + if is_5ghz_frequency $WIFI_IFACE_FREQ; then + FREQ_BAND=5 + else + FREQ_BAND=2.4 + fi + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then + echo ", fallback to channel ${WIFI_IFACE_CHANNEL}" + CHANNEL=$WIFI_IFACE_CHANNEL + else + echo + fi fi fi From eca2b090a099b542ab0edb60698645886695d1d5 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 24 Feb 2025 22:40:34 -0800 Subject: [PATCH 28/41] Brevity --- create_ap | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/create_ap b/create_ap index 7a327af..5e113f0 100755 --- a/create_ap +++ b/create_ap @@ -272,22 +272,9 @@ is_bridge_interface() { } get_phy_device() { - local x - for x in /sys/class/ieee80211/*; do - [[ ! -e "$x" ]] && continue - if [[ "${x##*/}" = "$1" ]]; then - echo $1 - return 0 - elif [[ -e "$x/device/net/$1" ]]; then - echo ${x##*/} - return 0 - elif [[ -e "$x/device/net:$1" ]]; then - echo ${x##*/} - return 0 - fi - done - echo "Failed to get phy interface" >&2 - return 1 + local PHY + PHY=$(readlink -f "/sys/class/net/$1/phy80211") + echo ${PHY##*/} } get_adapter_info() { @@ -2008,9 +1995,7 @@ EOF [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf [[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> $CONFDIR/dnsmasq.conf if [[ "$SHARE_METHOD" == "none" && "$REDIRECT_TO_LOCALHOST" == "1" ]]; then - cat << EOF >> $CONFDIR/dnsmasq.conf -address=/#/$GATEWAY -EOF + echo "address=/#/$GATEWAY" >> $CONFDIR/dnsmasq.conf fi fi From 21d5aa37ca28328c40ad26d293d9b577214a0961 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 24 Feb 2025 22:41:09 -0800 Subject: [PATCH 29/41] Precision --- create_ap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create_ap b/create_ap index 5e113f0..8213205 100755 --- a/create_ap +++ b/create_ap @@ -45,7 +45,7 @@ usage() { echo " --hidden Make the Access Point hidden (do not broadcast the SSID)" echo " --mac-filter Enable MAC address filtering" echo " --mac-filter-accept Location of MAC address filter list (defaults to /etc/hostapd/hostapd.accept)" - echo " --redirect-to-localhost If -n is set, redirect every web request to localhost (useful for public information networks)" + echo " --redirect-to-localhost If -n is set, redirect every DNS request to localhost (useful for public information networks)" echo " --hostapd-debug With level between 1 and 2, passes arguments -d or -dd to hostapd for debugging." echo " --isolate-clients Disable communication between clients" echo " --ieee80211n Enable IEEE 802.11n (HT)" From e65f24af2731c3164729e898f94599d95d11cdbf Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Sat, 1 Mar 2025 20:20:02 -0800 Subject: [PATCH 30/41] Move confdir to /run and make name deterministic The /run directory is writable only by root, so we should be able to use the directory `/run/create_ap.${VWIFI_IFACE}.conf/` in all cases. --- create_ap | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/create_ap b/create_ap index 8213205..86629df 100755 --- a/create_ap +++ b/create_ap @@ -726,6 +726,8 @@ _cleanup() { fi done + # if we are the last create_ap instance using this Internet-facing + # interface, then set back common values for that interface if [[ $found -eq 0 ]]; then cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding \ /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding @@ -891,7 +893,7 @@ clean_exit() { list_running_conf() { local x mutex_lock - for x in /tmp/create_ap.*; do + for x in /run/create_ap.*; do if [[ -f $x/pid && -f $x/wifi_iface && -d /proc/$(cat $x/pid) ]]; then echo $x fi @@ -1029,7 +1031,7 @@ has_running_instance() { local PID x mutex_lock - for x in /tmp/create_ap.*; do + for x in /run/create_ap.*; do if [[ -f $x/pid ]]; then PID=$(cat $x/pid) if [[ -d /proc/$PID ]]; then @@ -1654,21 +1656,10 @@ fi mutex_lock trap "cleanup" EXIT -CONFDIR=$(mktemp -d /tmp/create_ap.${WIFI_IFACE}.conf.XXXXXXXX) -echo "Config dir: $CONFDIR" -echo "PID: $$" -echo $$ > $CONFDIR/pid - -# to make --list-running work from any user, we must give read -# permissions to $CONFDIR and $CONFDIR/pid -chmod 755 $CONFDIR -chmod 444 $CONFDIR/pid - -COMMON_CONFDIR=/tmp/create_ap.common.conf +COMMON_CONFDIR=/run/create_ap.common.conf mkdir -p $COMMON_CONFDIR if [[ "$SHARE_METHOD" == "nat" ]]; then - echo $INTERNET_IFACE > $CONFDIR/nat_internet_iface cp_n /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding \ $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding cp_n /proc/sys/net/ipv6/conf/all/forwarding \ @@ -1766,8 +1757,18 @@ else fi mutex_lock +CONFDIR=/run/create_ap.${WIFI_IFACE}.conf +mkdir $CONFDIR || die "Config dir $CONFDIR already exists. Previous $PROGNAME instance may have crashed without cleanup!" +echo "Config dir: $CONFDIR" +echo "PID: $$" +echo $$ > $CONFDIR/pid echo $WIFI_IFACE > $CONFDIR/wifi_iface -chmod 444 $CONFDIR/wifi_iface +[[ "$SHARE_METHOD" == "nat" ]] && echo $INTERNET_IFACE > $CONFDIR/nat_internet_iface + +# to make --list-running work from any user, we must give read +# permissions to $CONFDIR, $CONFDIR/pid, and $CONFDIR/wifi_iface +chmod 755 $CONFDIR +chmod 444 $CONFDIR/pid $CONFDIR/wifi_iface mutex_unlock if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then From 97faad1f3c26527b7dd55c27ca66358282fbb367 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 3 Mar 2025 15:14:33 -0800 Subject: [PATCH 31/41] Handle systemd's resume-from-suspend automatically Instead of relying on a "static" `create_ap.resume` script (added in 8bb90688), just create one on-the-fly. If the AP isn't working after resume-from-suspend, it will disable and re-enable it via `hostapd_cli`. (ping https://github.com/dlenski/create_ap/issues/1, https://github.com/oblique/create_ap/issues/153, https://github.com/oblique/create_ap/issues/167) --- Makefile | 2 -- create_ap | 19 +++++++++++++++++++ create_ap.resume | 21 --------------------- 3 files changed, 19 insertions(+), 23 deletions(-) delete mode 100755 create_ap.resume diff --git a/Makefile b/Makefile index bf87cbb..e2eef8c 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ install: install -Dm755 create_ap $(DESTDIR)$(BINDIR)/create_ap install -Dm644 --backup=existing --suffix=.orig create_ap.conf $(DESTDIR)/etc/create_ap.conf [ ! -d /lib/systemd/system ] || install -Dm644 create_ap.service $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service - [ ! -d /lib/systemd/system-sleep ] || install -Dm755 create_ap.resume $(DESTDIR)$(PREFIX)/lib/systemd/system-sleep/create_ap.resume [ ! -e /sbin/openrc-run ] || install -Dm755 create_ap.openrc $(DESTDIR)/etc/init.d/create_ap install -Dm644 bash_completion $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md @@ -19,7 +18,6 @@ uninstall: rm -f $(DESTDIR)$(BINDIR)/create_ap rm -f $(DESTDIR)/etc/create_ap.conf [ ! -f /lib/systemd/system/create_ap.service ] || rm -f $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service - [ ! -f /lib/systemd/system-sleep/create_ap.resume ] || rm -f $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.resume [ ! -e /sbin/openrc-run ] || rm -f $(DESTDIR)/etc/init.d/create_ap rm -f $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap rm -f $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md diff --git a/create_ap b/create_ap index 86629df..b668784 100755 --- a/create_ap +++ b/create_ap @@ -716,6 +716,7 @@ _cleanup() { [[ -f $x ]] && kill -9 $(cat $x) done + rm -f "/lib/systemd/system-sleep/create_ap.${WIFI_IFACE}.resume" rm -rf $CONFDIR local found=0 @@ -1810,6 +1811,24 @@ dtim_period=${DTIM_PERIOD} #manufacturer=Vark EOF +# hostapd resume-after-suspend +if [[ -d /lib/systemd/system-sleep ]]; then + resumer="/lib/systemd/system-sleep/create_ap.${WIFI_IFACE}.resume" + cat << EOF > "$resumer" +#!/bin/sh +# After resuming, ensure hostapd is still sending beacons, and if it's not then +# disable and reenable to ensure AP continues working +if [ "\$1" = post ]; then + if [ OK != \`hostapd_cli -i "${WIFI_IFACE}" -p "$CONFDIR/hostapd_ctrl" update_beacon\` ]; then + hostapd_cli -i "${WIFI_IFACE}" -p "$CONFDIR/hostapd_ctrl" disable + hostapd_cli -i "${WIFI_IFACE}" -p "$CONFDIR/hostapd_ctrl" enable + fi +fi +EOF + chmod 755 "$resumer" + echo "Installed systemd resume-after-suspend handler in $resumer" +fi + VENDOR_ELEMENTS="" if [[ $METERED -ne 0 ]]; then # Add Microsoft's "network cost information element" diff --git a/create_ap.resume b/create_ap.resume deleted file mode 100755 index b71994a..0000000 --- a/create_ap.resume +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e - -###################################################################### -# WARNING: # For unclear reasons (distribution-specific bug? -# systemd bug?), this script might work -# ONLY if it is named /lib/systemd/system-sleep -# and NOT if it is named /usr/lib/systemd/system-sleep -# -# If you encounter this issue, please report at -# https://github.com/dlenski/create_ap/issues/1 -###################################################################### - -# After resume, restart create_ap service (if it was already running) -# See: -# https://www.freedesktop.org/software/systemd/man/systemd-suspend.service.html - -case "$1" in - pre) ;; - post) /bin/systemctl try-restart create_ap.service ;; -esac From de3f42e52176695c1361c058f2047fe0f6369fd4 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Tue, 4 Mar 2025 16:48:06 -0800 Subject: [PATCH 32/41] --mac-filter-accept OR --mac-filter-deny It doesn't make any sense to use both. --- create_ap | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/create_ap b/create_ap index b668784..f85a648 100755 --- a/create_ap +++ b/create_ap @@ -43,8 +43,8 @@ usage() { echo " --wps Enable WPS (Wireless Protected Setup) with push button (PBC) and PIN modes" echo " --psk Use 64 hex digits pre-shared-key instead of passphrase" echo " --hidden Make the Access Point hidden (do not broadcast the SSID)" - echo " --mac-filter Enable MAC address filtering" - echo " --mac-filter-accept Location of MAC address filter list (defaults to /etc/hostapd/hostapd.accept)" + echo " --mac-filter-accept File containing MAC addresses to accept" + echo " --mac-filter-deny File containing MAC addresses to deny" echo " --redirect-to-localhost If -n is set, redirect every DNS request to localhost (useful for public information networks)" echo " --hostapd-debug With level between 1 and 2, passes arguments -d or -dd to hostapd for debugging." echo " --isolate-clients Disable communication between clients" @@ -653,7 +653,8 @@ NO_DNSMASQ=0 DNS_PORT= HIDDEN=0 MAC_FILTER=0 -MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept +MAC_FILTER_ACCEPT= +MAC_FILTER_DENY= ISOLATE_CLIENTS=0 SHARE_METHOD=nat METERED=0 @@ -1142,7 +1143,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter","mac-filter-accept:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1160,15 +1161,16 @@ while :; do shift HIDDEN=1 ;; - --mac-filter) - shift - MAC_FILTER=1 - ;; --mac-filter-accept) shift MAC_FILTER_ACCEPT="$1" shift ;; + --mac-filter-deny) + shift + MAC_FILTER_DENY="$1" + shift + ;; --isolate-clients) shift ISOLATE_CLIENTS=1 @@ -1791,7 +1793,8 @@ fi [[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!" -[[ $MAC_FILTER -eq 1 ]] && echo "MAC address filtering is enabled!" +[[ -n "$MAC_FILTER_ACCEPT" ]] && echo "MAC address allow-list is enabled! $MAC_FILTER_ACCEPT" +[[ -n "$MAC_FILTER_DENY" ]] && echo "MAC address deny-list is enabled! $MAC_FILTER_DENY" [[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!" @@ -1896,11 +1899,16 @@ else echo "hw_mode=a" >> $CONFDIR/hostapd.conf fi -if [[ $MAC_FILTER -eq 1 ]]; then +if [[ -n "$MAC_FILTER_ACCEPT" ]]; then cat << EOF >> $CONFDIR/hostapd.conf -macaddr_acl=${MAC_FILTER} +macaddr_acl=1 accept_mac_file=${MAC_FILTER_ACCEPT} EOF +elif [[ -n "$MAC_FILTER_DENY" ]]; then + cat << EOF >> $CONFDIR/hostapd.conf +macaddr_acl=0 +deny_mac_file=${MAC_FILTER_DENY} +EOF fi if [[ $IEEE80211N -eq 1 ]]; then From fa35d18bd60ebb8c0273b28f552448196c2d966e Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Thu, 4 Dec 2025 22:32:51 -0800 Subject: [PATCH 33/41] Add hidden --wep option Obviously, WEP (https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy) is thoroughly insecure and has been crackable for decades, but it can be useful for research or testing purposes. --- create_ap | 57 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/create_ap b/create_ap index f85a648..271ee3d 100755 --- a/create_ap +++ b/create_ap @@ -33,6 +33,7 @@ usage() { echo " --version Print version number" echo " -c Channel number (default: 1)" echo " -w Use 1 for WPA, use 2 for WPA2, use 3 for WPA3, use 1+2+3 for all (default: 2+3)" + # --wep is intentionally hidden because it's obviously insecure echo " -n Disable Internet sharing (if you use this, don't pass" echo " the argument)" echo " -m Method for Internet sharing." @@ -644,6 +645,7 @@ networkmanager_wait_until_unmanaged() { CHANNEL=default GATEWAY=192.168.12.1 WPA_VERSION=2+3 +WEP=0 ETC_HOSTS=0 ADDN_HOSTS= DHCP_DNS=gateway @@ -681,10 +683,10 @@ WPS=0 HOSTAPD_DEBUG_ARGS= REDIRECT_TO_LOCALHOST=0 -CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS +CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION WEP ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY TIMEZONE GPS FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE WIFI_IFACE INTERNET_IFACE - SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED) + SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED WEP) FIX_UNMANAGED=0 LIST_RUNNING=0 @@ -1143,7 +1145,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered","wep" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1185,6 +1187,12 @@ while :; do WPA_VERSION="$1" shift ;; + --wep) + shift + WEP=1 + WPA_VERSION= + echo -e "WARN: WEP is insecure and obsolete and should only be used for testing or research" >&2 + ;; -g) shift GATEWAY="$1" @@ -1931,22 +1939,34 @@ if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then fi if [[ -n "$PASSPHRASE" ]]; then - if [[ $USE_PSK -eq 0 ]]; then - WPA_KEY_TYPE=passphrase + if [[ $WEP -eq 1 ]]; then + if [[ $USE_PSK -eq 1 ]]; then + psk="${PASSPHRASE}" + else + case ${#PASSPHRASE} in + 5) ;; 13) ;; 16) ;; + *) die "WEP password must be 5, 13, or 16 characters in length" ;; + esac + psk="\"${PASSPHRASE}\"" + fi + echo "wep_key0=${psk}" >> $CONFDIR/hostapd.conf else - WPA_KEY_TYPE=psk - fi - case "$WPA_VERSION" in - 1) wpa=1; wpapw=TKIP ;; - *1*) wpa=3; wpapw="TKIP CCMP" ;; - *) wpa=2; wpapw=CCMP ;; - esac - case "$WPA_VERSION" in - 3) wpaw=2; wpakm="SAE" ;; - *3*) wpaw=1; wpakm="WPA-PSK WPA-PSK-SHA256 SAE" ;; - *) wpaw=0; wpakm="WPA-PSK WPA-PSK-SHA256" ;; - esac - cat <> $CONFDIR/hostapd.conf + if [[ $USE_PSK -eq 0 ]]; then + WPA_KEY_TYPE=passphrase + else + WPA_KEY_TYPE=psk + fi + case "$WPA_VERSION" in + 1) wpa=1; wpapw=TKIP ;; + *1*) wpa=3; wpapw="TKIP CCMP" ;; + *) wpa=2; wpapw=CCMP ;; + esac + case "$WPA_VERSION" in + 3) wpaw=2; wpakm="SAE" ;; + *3*) wpaw=1; wpakm="WPA-PSK WPA-PSK-SHA256 SAE" ;; + *) wpaw=0; wpakm="WPA-PSK WPA-PSK-SHA256" ;; + esac + cat <> $CONFDIR/hostapd.conf wpa=$wpa wpa_${WPA_KEY_TYPE}=${PASSPHRASE} wpa_key_mgmt=$wpakm @@ -1954,6 +1974,7 @@ wpa_pairwise=$wpapw rsn_pairwise=CCMP ieee80211w=$wpaw EOF + fi fi From 968d5501d10652943573b5e18daffcf10f055a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= Date: Sat, 23 Dec 2023 20:00:34 +0000 Subject: [PATCH 34/41] Update frequency parsing for iw 6.7 compatibility [ Cherry picked from https://github.com/lakinduakash/linux-wifi-hotspot/commit/50cf12cbb527cfd35034948da7fd840f69101c9d ] Since iw 6.7, which adds 802.11ah support, iw may print fractional frequencies (e.g. 917.4 MHz). The change in the formatting code can also affect frequencies in the 2.4 and 5 GHz bands, so a frequency that used to be shown as "2412 MHz" may now be shown as "2412.0 MHz". This breaks the parsing logic in `can_transmit_to_channel`, `ieee80211_frequency_to_channel` and `is_5ghz_frequency`. The problem in `can_transmit_to_channel` causes an error when creating an AP, due the frequency not being detected as supported ("ERROR: Your adapter can not transmit to channel 1, frequency band 2.4GHz."). Fix this by changing the parsing logic to accept a trailing ".0" (or even ".00", etc.) suffix for the existing 2.4 and 5 GHz bands. See also: https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/commit/?id=f2d9f5b52677f5414dc194be94b5916d2b080eab https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/commit/?id=e2224c729840cc33c6ea89ba5e91b69f79c88e85 https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/commit/?id=1bc6ab0abbb6f26f35d826d166d06bc28ae47b6b --- create_ap | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/create_ap b/create_ap index 271ee3d..389daa1 100755 --- a/create_ap +++ b/create_ap @@ -338,9 +338,9 @@ can_transmit_to_channel() { if [[ $USE_IWCONFIG -eq 0 ]]; then if [[ $FREQ_BAND == 2.4 ]]; then - CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9] MHz \[${CHANNEL_NUM}\]") + CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9]\(\.0\+\)\? MHz \[${CHANNEL_NUM}\]") else - CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\) MHz \[${CHANNEL_NUM}\]") + CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\)\(\.0\+\)\? MHz \[${CHANNEL_NUM}\]") fi [[ -z "${CHANNEL_INFO}" ]] && return 1 [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1 @@ -356,7 +356,9 @@ can_transmit_to_channel() { # taken from iw/util.c ieee80211_frequency_to_channel() { - local FREQ=$1 + local FREQ_MAYBE_FRACTIONAL=$1 + local FREQ=${FREQ_MAYBE_FRACTIONAL%.*} + if [[ $FREQ -eq 2484 ]]; then echo 14 elif [[ $FREQ -lt 2484 ]]; then @@ -373,7 +375,7 @@ ieee80211_frequency_to_channel() { } is_5ghz_frequency() { - [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]] + [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})(\.0+)?$ ]] } is_wifi_connected() { From e863af54f52ad46ec52071c4a469da61fe818f99 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Tue, 28 Apr 2026 09:07:46 -0700 Subject: [PATCH 35/41] Fix option to enable local timezone advertisement Setting this to zero should disable it. --- create_ap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create_ap b/create_ap index 389daa1..19a2395 100755 --- a/create_ap +++ b/create_ap @@ -1884,7 +1884,7 @@ ieee80211d=1 EOF fi -if [[ -n "$TIMEZONE" ]]; then +if [[ "$TIMEZONE" -ne 0 ]]; then # FIXME: This capability was added to hostapd in # https://chromium.googlesource.com/external/w1.fi/cgit/hostap/+/39b97072b2a45551e6f20e6251eeaca269f22a2d%5E%21/#F1 # with the 'time_zone' variable, but appears to be broken in hostapd v2.9 From cf68756d03cb621b417230faca73d33d355d8527 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Tue, 28 Apr 2026 08:58:57 -0700 Subject: [PATCH 36/41] No QR code if not outputting to terminal No need to spam log files with this --- create_ap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create_ap b/create_ap index 19a2395..7098771 100755 --- a/create_ap +++ b/create_ap @@ -2226,7 +2226,7 @@ escape() { } QRENCODE_PATH=`which qrencode` -if [ $? -eq 0 ]; then +if [ -t 1 -a $? -eq 0 ]; then URI="WIFI:S:$(escape $SSID);" if [[ -n "$PASSPHRASE" ]]; then URI+="T:WPA;P:$(escape $PASSPHRASE);" From c9224466b11d9f8f03810d935e1b9ad1b67c3d57 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 27 Apr 2026 16:33:03 -0700 Subject: [PATCH 37/41] Verify hostapd version is >=2.6 I should have done this back in 4664f05 ("Remove the 'haveged' options and entropy watchdog") --- create_ap | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/create_ap b/create_ap index 7098771..1134527 100755 --- a/create_ap +++ b/create_ap @@ -1540,6 +1540,14 @@ if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ fi fi +HOSTAPD_VER=$($HOSTAPD -v 2>&1 | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+') +version_cmp $HOSTAPD_VER 2.6 +if [[ $? -eq 1 ]]; then + echo "ERROR: You are running hostapd $HOSTAPD_VERSION, which has a broken" >&2 + echo " random number generator. Please upgrade to v2.6+" >&2 + exit 1 +fi + if [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" != "none" ]]; then echo "ERROR: Wrong Internet sharing method" >&2 echo From 219d356c21d7d1db910e55fbe994aa29740868ca Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 27 Apr 2026 11:36:53 -0700 Subject: [PATCH 38/41] Stop supporting iwconfig It's old and incomplete, and only needed as a workaround for old and buggy hardware drivers that don't support iw/nl80211. --- README.md | 1 - create_ap | 87 +++++++++++++++++-------------------------------------- 2 files changed, 27 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 2c91f7a..06af1e5 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. fail unpredictably due to [a RNG bug](https://packetstormsecurity.com/files/156573/Hostapd-Insufficient-Entropy.html). * iproute2 * iw -* iwconfig (you only need this if 'iw' can not recognize your adapter) ### For 'NATed' or 'None' Internet sharing method * dnsmasq diff --git a/create_ap b/create_ap index 1134527..b8c9337 100755 --- a/create_ap +++ b/create_ap @@ -7,7 +7,6 @@ # hostapd # iproute2 # iw -# iwconfig (you only need this if 'iw' can not recognize your adapter) # dependencies for 'nat' or 'none' Internet sharing method # dnsmasq @@ -251,8 +250,6 @@ version_cmp() { return 0 } -USE_IWCONFIG=0 - is_interface() { [[ -z "$1" ]] && return 1 [[ -d "/sys/class/net/${1}" ]] @@ -260,10 +257,6 @@ is_interface() { is_wifi_interface() { which iw > /dev/null 2>&1 && iw dev $1 info > /dev/null 2>&1 && return 0 - if which iwconfig > /dev/null 2>&1 && iwconfig $1 > /dev/null 2>&1; then - USE_IWCONFIG=1 - return 0 - fi return 1 } @@ -295,17 +288,14 @@ can_do_80211w() { local PHY PHY=$(get_phy_device "$1") [[ $? -ne 0 ]] && return 1 - if [[ $USE_IWCONFIG -eq 1 ]]; then - # https://askubuntu.com/a/1445236 - grep -q MFP_CAPABLE /sys/kernel/debug/ieee80211/${PHY}/hwflags - else - iw phy $PHY info | grep -q 'CMAC (00-0f-ac:6)' - fi + # Per https://kevinlocke.name/bits/2019/12/28/checking-802.11w-support, debugfs + # is the most reliable way to detect 802.11, aka management frame protection. + # Grep iw output as a fallback. + grep -q MFP_CAPABLE /sys/kernel/debug/ieee80211/${PHY}/hwflags && return 0 + get_adapter_info "$PHY" | grep -q 'CMAC (00-0f-ac:6)' } can_be_sta_and_ap() { - # iwconfig does not provide this information, assume false - [[ $USE_IWCONFIG -eq 1 ]] && return 1 if [[ "$(get_adapter_kernel_module "$1")" == "brcmfmac" ]]; then echo "WARN: brmfmac driver doesn't work properly with virtual interfaces and" >&2 echo " it can cause kernel panic. For this reason we disallow virtual" >&2 @@ -319,16 +309,11 @@ can_be_sta_and_ap() { } can_be_multi_channel() { - # iwconfig does not provide this information, assume false - [[ $USE_IWCONFIG -eq 1 ]] && return 1 get_adapter_info "$1" | grep -E '#channels <= [2-9]+' > /dev/null 2>&1 } can_be_ap() { - # iwconfig does not provide this information, assume true - [[ $USE_IWCONFIG -eq 1 ]] && return 0 - get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 && return 0 - return 1 + get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 } can_transmit_to_channel() { @@ -336,22 +321,15 @@ can_transmit_to_channel() { IFACE=$1 CHANNEL_NUM=$2 - if [[ $USE_IWCONFIG -eq 0 ]]; then - if [[ $FREQ_BAND == 2.4 ]]; then - CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9]\(\.0\+\)\? MHz \[${CHANNEL_NUM}\]") - else - CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\)\(\.0\+\)\? MHz \[${CHANNEL_NUM}\]") - fi - [[ -z "${CHANNEL_INFO}" ]] && return 1 - [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1 - [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1 - return 0 + if [[ $FREQ_BAND == 2.4 ]]; then + CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9]\(\.0\+\)\? MHz \[${CHANNEL_NUM}\]") else - CHANNEL_NUM=$(printf '%02d' ${CHANNEL_NUM}) - CHANNEL_INFO=$(iwlist ${IFACE} channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:") - [[ -z "${CHANNEL_INFO}" ]] && return 1 - return 0 + CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\)\(\.0\+\)\? MHz \[${CHANNEL_NUM}\]") fi + [[ -z "${CHANNEL_INFO}" ]] && return 1 + [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1 + [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1 + return 0 } # taken from iw/util.c @@ -379,12 +357,7 @@ is_5ghz_frequency() { } is_wifi_connected() { - if [[ $USE_IWCONFIG -eq 0 ]]; then - iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 && return 0 - else - iwconfig "$1" 2>&1 | grep -E 'Access Point: [0-9a-fA-F]{2}:' > /dev/null 2>&1 && return 0 - fi - return 1 + iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 } is_macaddr() { @@ -979,24 +952,20 @@ list_clients() { Use --list-running to find it out." [[ -z "$CONFDIR" ]] && CONFDIR=$(get_confdir_from_pid "$pid") - if [[ $USE_IWCONFIG -eq 0 ]]; then - local awk_cmd='($1 ~ /Station$/) {print $2}' - local client_list=$(iw dev "$wifi_iface" station dump | awk "$awk_cmd") + local awk_cmd='($1 ~ /Station$/) {print $2}' + local client_list=$(iw dev "$wifi_iface" station dump | awk "$awk_cmd") - if [[ -z "$client_list" ]]; then - echo "No clients connected" - return - fi + if [[ -z "$client_list" ]]; then + echo "No clients connected" + return + fi - printf "%-20s %-18s %s\n" "MAC" "IP" "Hostname" + printf "%-20s %-18s %s\n" "MAC" "IP" "Hostname" - local mac - for mac in $client_list; do - print_client $mac - done - else - die "This option is not supported for the current driver." - fi + local mac + for mac in $client_list; do + print_client $mac + done } wps_trigger() { @@ -1717,9 +1686,7 @@ elif [[ $IPV6 -ne 0 ]]; then fi fi -if [[ $USE_IWCONFIG -eq 0 ]]; then - iw dev ${WIFI_IFACE} set power_save off -fi +iw dev ${WIFI_IFACE} set power_save off if [[ $NO_VIRT -eq 0 ]]; then VWIFI_IFACE=$(alloc_new_iface ap) @@ -1792,7 +1759,7 @@ chmod 755 $CONFDIR chmod 444 $CONFDIR/pid $CONFDIR/wifi_iface mutex_unlock -if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then +if [[ -n "$COUNTRY" ]]; then iw reg set "$COUNTRY" fi From cbc42c473dfbf80fdfc2a5ac6368b09f63b9ba4f Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Mon, 27 Apr 2026 16:50:42 -0700 Subject: [PATCH 39/41] Stop working around non-nl80211 drivers Both brcmfmac and old Realtek drivers only support very old hardware: I don't have any to test it with. Instead of attempting various heroic workarounds for them, just warn about them. --- README.md | 9 ++---- create_ap | 58 ++++++++++++++----------------------- create_ap.conf | 2 -- howto/realtek.md | 74 ------------------------------------------------ 4 files changed, 23 insertions(+), 120 deletions(-) delete mode 100644 howto/realtek.md diff --git a/README.md b/README.md index 06af1e5..4af6d41 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,9 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. * bash (to run this script) * util-linux (for getopt) * procps or procps-ng -* hostapd - * Version 2.6 or newer is required; earlier versions may - fail unpredictably due to [a RNG bug](https://packetstormsecurity.com/files/156573/Hostapd-Insufficient-Entropy.html). +* hostapd (v2.6 or newer) * iproute2 -* iw +* iw (non-`nl80211` wifi drivers are no longer supported) ### For 'NATed' or 'None' Internet sharing method * dnsmasq @@ -68,9 +66,6 @@ This project is a fork of the no-longer-maintained [oblique/create_ap](//github. ### Internet sharing from the same WiFi interface: create_ap wlan0 wlan0 MyAccessPoint MyPassPhrase -### Choose a different WiFi adapter driver - create_ap --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase - ### No passphrase (open network) using pipe: echo -e "MyAccessPoint" | create_ap wlan0 eth0 diff --git a/create_ap b/create_ap index b8c9337..0a6799d 100755 --- a/create_ap +++ b/create_ap @@ -58,7 +58,6 @@ usage() { echo " --timezone Advertise local timezone in beacons (following 802.11v-2011 7.3.2.87)" echo " --gps Advertise location in beacons (coordinates are in 10^5 degree)" echo " --freq-band Set frequency band. Valid inputs: 2.4, 5 (default: 2.4)" - echo " --driver Choose your WiFi adapter driver (default: nl80211)" echo " --no-virt Do not create virtual interface" echo " --fix-unmanaged If NetworkManager shows your interface as unmanaged after you" echo " close create_ap, then use this option to switch your interface" @@ -110,7 +109,6 @@ usage() { echo " "$PROGNAME" -n wlan0 MyAccessPoint MyPassPhrase" echo " "$PROGNAME" -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase" echo " "$PROGNAME" -m bridge wlan0 br0 MyAccessPoint MyPassPhrase" - echo " "$PROGNAME" --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase" echo " "$PROGNAME" --daemon wlan0 eth0 MyAccessPoint MyPassPhrase" echo " "$PROGNAME" --stop wlan0" } @@ -296,13 +294,6 @@ can_do_80211w() { } can_be_sta_and_ap() { - if [[ "$(get_adapter_kernel_module "$1")" == "brcmfmac" ]]; then - echo "WARN: brmfmac driver doesn't work properly with virtual interfaces and" >&2 - echo " it can cause kernel panic. For this reason we disallow virtual" >&2 - echo " interfaces for your adapter." >&2 - echo " For more info: https://github.com/oblique/create_ap/issues/203" >&2 - return 1 - fi get_adapter_info "$1" | grep -E '{.* managed.* AP.*}' > /dev/null 2>&1 && return 0 get_adapter_info "$1" | grep -E '{.* AP.* managed.*}' > /dev/null 2>&1 && return 0 return 1 @@ -639,7 +630,6 @@ IEEE80211N=0 IEEE80211AC=0 HT_CAPAB='[HT40+]' VHT_CAPAB= -DRIVER=nl80211 NO_VIRT=0 COUNTRY= TIMEZONE= @@ -659,7 +649,7 @@ HOSTAPD_DEBUG_ARGS= REDIRECT_TO_LOCALHOST=0 CONFIG_OPTS=(CHANNEL GATEWAY WPA_VERSION WEP ETC_HOSTS DHCP_DNS DHCP_DNS6 NO_DNS NO_DNSMASQ HIDDEN MAC_FILTER MAC_FILTER_ACCEPT ISOLATE_CLIENTS - SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB DRIVER NO_VIRT COUNTRY TIMEZONE GPS FREQ_BAND + SHARE_METHOD IEEE80211N IEEE80211AC HT_CAPAB VHT_CAPAB NO_VIRT COUNTRY TIMEZONE GPS FREQ_BAND NEW_MACADDR DAEMONIZE DAEMON_PIDFILE DAEMON_LOGFILE WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE USE_PSK BEACON_INTERVAL DTIM_PERIOD IPV6 ADDN_HOSTS WPS METERED WEP) @@ -1116,7 +1106,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","driver:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered","wep" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered","wep" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1213,11 +1203,6 @@ while :; do VHT_CAPAB="$1" shift ;; - --driver) - shift - DRIVER="$1" - shift - ;; --no-virt) shift NO_VIRT=1 @@ -1497,16 +1482,23 @@ if [[ ! -x "$HOSTAPD" ]]; then exit 1 fi -if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then - if ! strings "$HOSTAPD" | grep -m1 rtl871xdrv > /dev/null 2>&1; then - echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2 - exit 1 - fi - - if [[ $DRIVER != "rtl871xdrv" ]]; then - echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2 - DRIVER=rtl871xdrv - fi +WIFI_KMOD="$(get_adapter_kernel_module ${WIFI_IFACE})" +if [[ "$WIFI_KMOD" =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then + echo "WARNING: You are running a very old and buggy wifi driver. It may not work" >&2 + echo " at all. See https://github.com/dlenski/create_ap/commit/3460580c" >&2 + echo >&2 +elif [[ "$WIFI_KMOD" =~ ^rtl[0-9].*$ ]]; then + echo "WARNING: You are running a very old and buggy wifi driver. It may not work with" >&2 + echo " WPA properly. See https://github.com/dlenski/create_ap/commit/04fa4860" >&2 + echo >&2 +elif [[ "$WIFI_KMOD" = "rtl871xdrv" ]]; then + echo "WARNING: You are running an old and buggy wifi driver. It may not work with" >&2 + echo " with iw. See https://github.com/oblique/create_ap/issues/43" >&2 + echo >&2 +elif [[ "$WIFI_KMOD" = "brcmfmac" ]]; then + echo "WARNING: You are running an old and buggy wifi driver. It may not work with" >&2 + echo " virtual wifi devices. See https://github.com/oblique/create_ap/issues/203" >&2 + echo >&2 fi HOSTAPD_VER=$($HOSTAPD -v 2>&1 | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+') @@ -1630,14 +1622,6 @@ elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then exit 1 fi -if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then - if [[ -n "$PASSPHRASE" ]]; then - echo "WARN: Realtek drivers usually have problems with WPA1, enabling -w 2" >&2 - WPA_VERSION=2 - fi - echo "WARN: If AP doesn't work, please read: howto/realtek.md" >&2 -fi - if [[ $NO_VIRT -eq 1 && "$WIFI_IFACE" == "$INTERNET_IFACE" ]]; then echo -n "ERROR: You can not share your connection from the same" >&2 echo " interface if you are using --no-virt option." >&2 @@ -1787,7 +1771,7 @@ fi cat << EOF > $CONFDIR/hostapd.conf ssid=${SSID} interface=${WIFI_IFACE} -driver=${DRIVER} +driver=nl80211 channel=${CHANNEL} ctrl_interface=$CONFDIR/hostapd_ctrl ctrl_interface_group=0 @@ -2230,7 +2214,7 @@ echo $HOSTAPD_PID > $CONFDIR/hostapd.pid if ! wait $HOSTAPD_PID; then echo -e "\nError: Failed to run hostapd, maybe a program is interfering." >&2 if networkmanager_is_running; then - echo "If an error like 'n80211: Could not configure driver mode' was thrown" >&2 + echo "If an error like 'nl80211: Could not configure driver mode' was thrown" >&2 echo "try running the following before starting create_ap:" >&2 if [[ $NM_OLDER_VERSION -eq 1 ]]; then echo " nmcli nm wifi off" >&2 diff --git a/create_ap.conf b/create_ap.conf index 9dea568..df68241 100644 --- a/create_ap.conf +++ b/create_ap.conf @@ -94,8 +94,6 @@ NEW_MACADDR= ########## Miscellaneous ########## -# Specify the driver to use -DRIVER=nl80211 # Set whether create_ap should run in the background DAEMONIZE=0 # Set to 1 to disable virtual interface creation diff --git a/howto/realtek.md b/howto/realtek.md deleted file mode 100644 index 266d818..0000000 --- a/howto/realtek.md +++ /dev/null @@ -1,74 +0,0 @@ -## Try this first - -If you are facing any problems with Realtek adapters (e.g. Edimax EW-7811Un) -first try to run create_ap with `-w 2` (i.e. use WPA2 only) or use it -without passphrase. If you are still facing any problems or you want to -also use WPA1, then follow the instructions below. - -NOTE: The instructions below are only valid for Realtek adapters with 8192 chipset. - -## Before installation - -If you're using ArchLinux, run: - -``` -pacman -S base-devel linux-headers dkms git -pacman -R hostapd -``` - -If you're using Debian, Ubuntu, or any Debian-based distribution, run: - -``` -apt-get install build-essential linux-headers-generic dkms git -apt-get remove hostapd -apt-get build-dep hostapd -``` - -## Install driver - -The driver in the mainline of Linux kernel doesn't work well with the 8192 adapters. -For this reason you need to install the driver that is provided from Realtek. Their -driver can not be compiled with newer kernels, but since it was an open-source -release under GPL license some people were able to fixed it and make it compile. - -With the following commands you can install a fixed version of Realtek's driver: - -``` -git clone https://github.com/pvaret/rtl8192cu-fixes.git -dkms add rtl8192cu-fixes -dkms install 8192cu/1.9 -cp rtl8192cu-fixes/blacklist-native-rtl8192.conf /etc/modprobe.d -cp rtl8192cu-fixes/8192cu-disable-power-management.conf /etc/modprobe.d -``` - -After installation, unload the previous driver and load the new one, or just reboot. - -## Install hostapd - -Realtek's driver is using an old subsystem which is called `wireless-extensions` -(or `wext`). Hostapd works only with the new subsystem (which is called `nl80211`). -For this reason Realtek wrote a patch for hostapd. You can install it with the -following commands: - -If you have ArchLinux install [hostapd-rtl871xdrv](https://aur.archlinux.org/packages/hostapd-rtl871xdrv) -from AUR or just run: - -``` -yaourt -S hostapd-rtl871xdrv -``` - -If you're using any other distribution, run: - -``` -git clone https://github.com/pritambaral/hostapd-rtl871xdrv.git -wget http://w1.fi/releases/hostapd-2.2.tar.gz -tar zxvf hostapd-2.2.tar.gz -cd hostapd-2.2 -patch -p1 -i ../hostapd-rtl871xdrv/rtlxdrv.patch -cp ../hostapd-rtl871xdrv/driver_* src/drivers -cd hostapd -cp defconfig .config -echo CONFIG_DRIVER_RTW=y >> .config -make -make install -``` From 482776df8dcf2be97e8a4e2c785038e62c83f22f Mon Sep 17 00:00:00 2001 From: Mathias Sass Michno Date: Wed, 6 Oct 2021 13:30:16 +0200 Subject: [PATCH 40/41] Add --hostapd-timestamps options to create_ap [ Cherry picked from https://github.com/lakinduakash/linux-wifi-hotspot/commit/bae89dae0f00062ac60e05a3d30f18f135f8e254 ] --- create_ap | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/create_ap b/create_ap index 0a6799d..b81a12e 100755 --- a/create_ap +++ b/create_ap @@ -47,6 +47,7 @@ usage() { echo " --mac-filter-deny File containing MAC addresses to deny" echo " --redirect-to-localhost If -n is set, redirect every DNS request to localhost (useful for public information networks)" echo " --hostapd-debug With level between 1 and 2, passes arguments -d or -dd to hostapd for debugging." + echo " --hostapd-timestamps Include timestamps in hostapd debug messages." echo " --isolate-clients Disable communication between clients" echo " --ieee80211n Enable IEEE 802.11n (HT)" echo " --ieee80211ac Enable IEEE 802.11ac (VHT)" @@ -1106,7 +1107,7 @@ for ((i=0; i<$#; i++)); do fi done -GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered","wep" -n "$PROGNAME" -- "$@") +GETOPT_ARGS=$(getopt -o hc:w:g:de:nm: -l "help","hidden","hostapd-debug:","hostapd-timestamps","redirect-to-localhost","mac-filter-accept:","mac-filter-deny:","isolate-clients","ieee80211n","ieee80211ac","ht_capab:","vht_capab:","no-virt","fix-unmanaged","country:","timezone","gps:","freq-band:","mac:","dhcp-dns:","dhcp-dns6:","daemon","pidfile:","logfile:","stop:","list","list-running","list-clients:","version","psk","no-dns","no-dnsmasq","ipv6","mkconfig:","config:","wps","wps-pbc:","wps-pin:","metered","wep" -n "$PROGNAME" -- "$@") [[ $? -ne 0 ]] && exit 1 eval set -- "$GETOPT_ARGS" @@ -1313,15 +1314,19 @@ while :; do --hostapd-debug) shift if [ "x$1" = "x1" ]; then - HOSTAPD_DEBUG_ARGS="-d" + HOSTAPD_DEBUG_ARGS+="-d " elif [ "x$1" = "x2" ]; then - HOSTAPD_DEBUG_ARGS="-dd" + HOSTAPD_DEBUG_ARGS+="-dd " else printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1" exit 1 fi shift ;; + --hostapd-timestamps) + shift + HOSTAPD_DEBUG_ARGS+="-t " + ;; --mkconfig) shift STORE_CONFIG="$1" From d57d76bff3cf0fdc886905d2ee371e4f0e61626b Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Tue, 28 Apr 2026 11:13:44 -0700 Subject: [PATCH 41/41] Add reinstall option, which doesn't clobber config file --- Makefile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e2eef8c..59b2fde 100644 --- a/Makefile +++ b/Makefile @@ -5,15 +5,26 @@ BINDIR=$(PREFIX)/bin all: @echo "Run 'make install' for installation." @echo "Run 'make uninstall' for uninstallation." + @echo "Run 'make reinstall' for installation without clobbering existing config file." -install: +install-noconf: install -Dm755 create_ap $(DESTDIR)$(BINDIR)/create_ap - install -Dm644 --backup=existing --suffix=.orig create_ap.conf $(DESTDIR)/etc/create_ap.conf [ ! -d /lib/systemd/system ] || install -Dm644 create_ap.service $(DESTDIR)$(PREFIX)/lib/systemd/system/create_ap.service [ ! -e /sbin/openrc-run ] || install -Dm755 create_ap.openrc $(DESTDIR)/etc/init.d/create_ap install -Dm644 bash_completion $(DESTDIR)$(PREFIX)/share/bash-completion/completions/create_ap install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/create_ap/README.md +install: install-noconf + [ -e $(DESTDIR)/etc/create_ap.conf ] && echo "Existing $(DESTDIR)/etc/create_ap.conf will be renamed with .orig suffix" >&2 + install -Dm644 --backup=existing --suffix=.orig create_ap.conf $(DESTDIR)/etc/create_ap.conf + +reinstall: install-noconf + if [ -e $(DESTDIR)/etc/create_ap.conf ]; then \ + echo "Leaving existing $(DESTDIR)/etc/create_ap.conf unchanged" >&2; \ + else \ + install -Dm644 --backup=existing --suffix=.orig create_ap.conf $(DESTDIR)/etc/create_ap.conf; \ + fi + uninstall: rm -f $(DESTDIR)$(BINDIR)/create_ap rm -f $(DESTDIR)/etc/create_ap.conf