Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # general dependencies:
- # bash (to run this script)
- # util-linux (for getopt)
- # procps or procps-ng
- # hostapd
- # 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
- # iptables
- VERSION=0.4.6
- PROGNAME="$(basename $0)"
- # make sure that all command outputs are in english
- # so we can parse them correctly
- export LC_ALL=C
- # all new files and directories must be readable only by root.
- # in special cases we must use chmod to give any other permissions.
- SCRIPT_UMASK=0077
- umask $SCRIPT_UMASK
- usage() {
- echo "Usage: "$PROGNAME" [options] <wifi-interface> [<interface-with-internet>] [<access-point-name> [<passphrase>]]"
- echo
- echo "Options:"
- echo " -h, --help Show this help"
- echo " --version Print version number"
- echo " -c <channel> Channel number (default: 1)"
- echo " -w <WPA version> Use 1 for WPA, use 2 for WPA2, use 1+2 for both (default: 2)"
- echo " -n Disable Internet sharing (if you use this, don't pass"
- echo " the <interface-with-internet> argument)"
- echo " -m <method> Method for Internet sharing."
- echo " Use: 'nat' for NAT (default)"
- echo " 'bridge' for bridging"
- echo " 'none' for no Internet sharing (equivalent to -n)"
- 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 " --redirect-to-localhost If -n is set, redirect every web request to localhost (useful for public information networks)"
- echo " --hostapd-debug <level> 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)"
- echo " --ieee80211ac Enable IEEE 802.11ac (VHT)"
- echo " --ht_capab <HT> HT capabilities (default: [HT40+])"
- echo " --vht_capab <VHT> VHT capabilities"
- echo " --country <code> Set two-letter country code for regularity (example: US)"
- echo " --freq-band <GHz> 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"
- echo " --mac <MAC> Set MAC address"
- echo " --dhcp-dns <IP1[,IP2]> Set DNS returned by DHCP"
- echo " --daemon Run create_ap in the background"
- echo " --pidfile <pidfile> Save daemon PID to file"
- echo " --logfile <logfile> Save daemon messages to file"
- echo " --stop <id> Send stop command to an already running create_ap. For an <id>"
- echo " you can put the PID of create_ap or the WiFi interface. You can"
- echo " get them with --list-running"
- echo " --list-running Show the create_ap processes that are already running"
- echo " --list-clients <id> List the clients connected to create_ap instance associated with <id>."
- echo " For an <id> 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 " --mkconfig <conf_file> Store configs in conf_file"
- echo " --config <conf_file> 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 <gateway> IPv4 Gateway for the Access Point (default: 192.168.12.1)"
- echo " -d DNS server will take into account /etc/hosts"
- echo " -e <hosts_file> DNS server will take into account additional hosts file"
- echo
- echo "Useful informations:"
- 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 <interface-with-internet> is not a bridge interface, then"
- echo " a bridge interface is created automatically."
- echo
- echo "Examples:"
- echo " "$PROGNAME" wlan0 eth0 MyAccessPoint MyPassPhrase"
- echo " echo -e 'MyAccessPoint\nMyPassPhrase' | "$PROGNAME" wlan0 eth0"
- echo " "$PROGNAME" wlan0 eth0 MyAccessPoint"
- echo " echo 'MyAccessPoint' | "$PROGNAME" wlan0 eth0"
- echo " "$PROGNAME" wlan0 wlan0 MyAccessPoint MyPassPhrase"
- 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"
- }
- # Busybox polyfills
- if cp --help 2>&1 | grep -q -- --no-clobber; then
- cp_n() {
- cp -n "$@"
- }
- else
- cp_n() {
- yes n | cp -i "$@"
- }
- fi
- # on success it echos a non-zero unused FD
- # on error it echos 0
- get_avail_fd() {
- local x
- for x in $(seq 1 $(ulimit -n)); do
- if [[ ! -a "/proc/$BASHPID/fd/$x" ]]; then
- echo $x
- return
- fi
- done
- echo 0
- }
- # lock file for the mutex counter
- COUNTER_LOCK_FILE=/tmp/create_ap.$$.lock
- cleanup_lock() {
- rm -f $COUNTER_LOCK_FILE
- }
- init_lock() {
- local LOCK_FILE=/tmp/create_ap.all.lock
- # we initialize only once
- [[ $LOCK_FD -ne 0 ]] && return 0
- LOCK_FD=$(get_avail_fd)
- [[ $LOCK_FD -eq 0 ]] && return 1
- # open/create lock file with write access for all users
- # otherwise normal users will not be able to use it.
- # to avoid race conditions on creation, we need to
- # use umask to set the permissions.
- umask 0555
- eval "exec $LOCK_FD>$LOCK_FILE" > /dev/null 2>&1 || return 1
- umask $SCRIPT_UMASK
- # there is a case where lock file was created from a normal
- # user. change the owner to root as soon as we can.
- [[ $(id -u) -eq 0 ]] && chown 0:0 $LOCK_FILE
- # create mutex counter lock file
- echo 0 > $COUNTER_LOCK_FILE
- return $?
- }
- # recursive mutex lock for all create_ap processes
- mutex_lock() {
- local counter_mutex_fd
- local counter
- # lock local mutex and read counter
- counter_mutex_fd=$(get_avail_fd)
- if [[ $counter_mutex_fd -ne 0 ]]; then
- eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE"
- flock $counter_mutex_fd
- read -u $counter_mutex_fd counter
- else
- echo "Failed to lock mutex counter" >&2
- return 1
- fi
- # lock global mutex and increase counter
- [[ $counter -eq 0 ]] && flock $LOCK_FD
- counter=$(( $counter + 1 ))
- # write counter and unlock local mutex
- echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd
- eval "exec ${counter_mutex_fd}<&-"
- return 0
- }
- # recursive mutex unlock for all create_ap processes
- mutex_unlock() {
- local counter_mutex_fd
- local counter
- # lock local mutex and read counter
- counter_mutex_fd=$(get_avail_fd)
- if [[ $counter_mutex_fd -ne 0 ]]; then
- eval "exec $counter_mutex_fd<>$COUNTER_LOCK_FILE"
- flock $counter_mutex_fd
- read -u $counter_mutex_fd counter
- else
- echo "Failed to lock mutex counter" >&2
- return 1
- fi
- # decrease counter and unlock global mutex
- if [[ $counter -gt 0 ]]; then
- counter=$(( $counter - 1 ))
- [[ $counter -eq 0 ]] && flock -u $LOCK_FD
- fi
- # write counter and unlock local mutex
- echo $counter > /proc/$BASHPID/fd/$counter_mutex_fd
- eval "exec ${counter_mutex_fd}<&-"
- return 0
- }
- # it takes 2 arguments
- # returns:
- # 0 if v1 (1st argument) and v2 (2nd argument) are the same
- # 1 if v1 is less than v2
- # 2 if v1 is greater than v2
- version_cmp() {
- local V1 V2 VN x
- [[ ! $1 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!"
- [[ ! $2 =~ ^[0-9]+(\.[0-9]+)*$ ]] && die "Wrong version format!"
- V1=( $(echo $1 | tr '.' ' ') )
- V2=( $(echo $2 | tr '.' ' ') )
- VN=${#V1[@]}
- [[ $VN -lt ${#V2[@]} ]] && VN=${#V2[@]}
- for ((x = 0; x < $VN; x++)); do
- [[ ${V1[x]} -lt ${V2[x]} ]] && return 1
- [[ ${V1[x]} -gt ${V2[x]} ]] && return 2
- done
- return 0
- }
- USE_IWCONFIG=0
- is_interface() {
- [[ -z "$1" ]] && return 1
- [[ -d "/sys/class/net/${1}" ]]
- }
- 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
- }
- is_bridge_interface() {
- [[ -z "$1" ]] && return 1
- [[ -d "/sys/class/net/${1}/bridge" ]]
- }
- 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
- }
- get_adapter_info() {
- local PHY
- PHY=$(get_phy_device "$1")
- [[ $? -ne 0 ]] && return 1
- iw phy $PHY info
- }
- get_adapter_kernel_module() {
- local MODULE
- MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module")
- echo ${MODULE##*/}
- }
- 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
- 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
- }
- 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
- }
- can_transmit_to_channel() {
- local IFACE CHANNEL_NUM CHANNEL_INFO
- 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] MHz \[${CHANNEL_NUM}\]")
- else
- CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\) MHz \[${CHANNEL_NUM}\]")
- fi
- [[ -z "${CHANNEL_INFO}" ]] && return 1
- [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1
- [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1
- return 0
- 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
- fi
- }
- # taken from iw/util.c
- ieee80211_frequency_to_channel() {
- local FREQ=$1
- if [[ $FREQ -eq 2484 ]]; then
- echo 14
- elif [[ $FREQ -lt 2484 ]]; then
- echo $(( ($FREQ - 2407) / 5 ))
- elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then
- echo $(( ($FREQ - 4000) / 5 ))
- elif [[ $FREQ -le 45000 ]]; then
- echo $(( ($FREQ - 5000) / 5 ))
- elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then
- echo $(( ($FREQ - 56160) / 2160 ))
- else
- echo 0
- fi
- }
- is_5ghz_frequency() {
- [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]]
- }
- 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
- }
- is_macaddr() {
- echo "$1" | grep -E "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$" > /dev/null 2>&1
- }
- is_unicast_macaddr() {
- local x
- is_macaddr "$1" || return 1
- x=$(echo "$1" | cut -d: -f1)
- x=$(printf '%d' "0x${x}")
- [[ $(expr $x % 2) -eq 0 ]]
- }
- get_macaddr() {
- is_interface "$1" || return
- cat "/sys/class/net/${1}/address"
- }
- get_mtu() {
- is_interface "$1" || return
- cat "/sys/class/net/${1}/mtu"
- }
- alloc_new_iface() {
- local prefix=$1
- local i=0
- mutex_lock
- while :; do
- if ! is_interface $prefix$i && [[ ! -f $COMMON_CONFDIR/ifaces/$prefix$i ]]; then
- mkdir -p $COMMON_CONFDIR/ifaces
- touch $COMMON_CONFDIR/ifaces/$prefix$i
- echo $prefix$i
- mutex_unlock
- return
- fi
- i=$((i + 1))
- done
- mutex_unlock
- }
- dealloc_iface() {
- rm -f $COMMON_CONFDIR/ifaces/$1
- }
- get_all_macaddrs() {
- cat /sys/class/net/*/address
- }
- get_new_macaddr() {
- local OLDMAC NEWMAC LAST_BYTE i
- OLDMAC=$(get_macaddr "$1")
- LAST_BYTE=$(printf %d 0x${OLDMAC##*:})
- mutex_lock
- for i in {1..255}; do
- NEWMAC="${OLDMAC%:*}:$(printf %02x $(( ($LAST_BYTE + $i) % 256 )))"
- (get_all_macaddrs | grep "$NEWMAC" > /dev/null 2>&1) || break
- done
- mutex_unlock
- echo $NEWMAC
- }
- # 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
- networkmanager_exists() {
- local NM_VER
- which nmcli > /dev/null 2>&1 || return 1
- NM_VER=$(nmcli -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+')
- version_cmp $NM_VER 0.9.9
- if [[ $? -eq 1 ]]; then
- NM_OLDER_VERSION=1
- else
- NM_OLDER_VERSION=0
- fi
- return 0
- }
- networkmanager_is_running() {
- local NMCLI_OUT
- networkmanager_exists || return 1
- if [[ $NM_OLDER_VERSION -eq 1 ]]; then
- NMCLI_OUT=$(nmcli -t -f RUNNING nm 2>&1 | grep -E '^running$')
- else
- NMCLI_OUT=$(nmcli -t -f RUNNING g 2>&1 | grep -E '^running$')
- fi
- [[ -n "$NMCLI_OUT" ]]
- }
- networkmanager_knows_iface() {
- # check if the interface $1 is known to NetworkManager
- # an interface may exist but may not be known to NetworkManager if it is in a different network namespace than NetworkManager
- nmcli -t -f DEVICE d 2>&1 | grep -Fxq "$1"
- }
- networkmanager_iface_is_unmanaged() {
- is_interface "$1" || return 2
- networkmanager_knows_iface "$1" || return 0
- (nmcli -t -f DEVICE,STATE d 2>&1 | grep -E "^$1:unmanaged$" > /dev/null 2>&1) || return 1
- }
- ADDED_UNMANAGED=
- networkmanager_add_unmanaged() {
- local MAC UNMANAGED WAS_EMPTY x
- networkmanager_exists || return 1
- [[ -d ${NETWORKMANAGER_CONF%/*} ]] || mkdir -p ${NETWORKMANAGER_CONF%/*}
- [[ -f ${NETWORKMANAGER_CONF} ]] || touch ${NETWORKMANAGER_CONF}
- if [[ $NM_OLDER_VERSION -eq 1 ]]; then
- if [[ -z "$2" ]]; then
- MAC=$(get_macaddr "$1")
- else
- MAC="$2"
- fi
- [[ -z "$MAC" ]] && return 1
- fi
- mutex_lock
- UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf)
- WAS_EMPTY=0
- [[ -z "$UNMANAGED" ]] && WAS_EMPTY=1
- UNMANAGED=$(echo "$UNMANAGED" | sed 's/unmanaged-devices=//' | tr ';,' ' ')
- # if it exists, do nothing
- for x in $UNMANAGED; do
- if [[ $x == "mac:${MAC}" ]] ||
- [[ $NM_OLDER_VERSION -eq 0 && $x == "interface-name:${1}" ]]; then
- mutex_unlock
- return 2
- fi
- done
- if [[ $NM_OLDER_VERSION -eq 1 ]]; then
- UNMANAGED="${UNMANAGED} mac:${MAC}"
- else
- UNMANAGED="${UNMANAGED} interface-name:${1}"
- fi
- UNMANAGED=$(echo $UNMANAGED | sed -e 's/^ //')
- UNMANAGED="${UNMANAGED// /;}"
- UNMANAGED="unmanaged-devices=${UNMANAGED}"
- if ! grep -E '^\[keyfile\]' ${NETWORKMANAGER_CONF} > /dev/null 2>&1; then
- echo -e "\n\n[keyfile]\n${UNMANAGED}" >> ${NETWORKMANAGER_CONF}
- elif [[ $WAS_EMPTY -eq 1 ]]; then
- sed -e "s/^\(\[keyfile\].*\)$/\1\n${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
- else
- sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
- fi
- ADDED_UNMANAGED="${ADDED_UNMANAGED} ${1} "
- mutex_unlock
- local nm_pid=$(pidof NetworkManager)
- [[ -n "$nm_pid" ]] && kill -HUP $nm_pid
- return 0
- }
- networkmanager_rm_unmanaged() {
- local MAC UNMANAGED
- networkmanager_exists || return 1
- [[ ! -f ${NETWORKMANAGER_CONF} ]] && return 1
- if [[ $NM_OLDER_VERSION -eq 1 ]]; then
- if [[ -z "$2" ]]; then
- MAC=$(get_macaddr "$1")
- else
- MAC="$2"
- fi
- [[ -z "$MAC" ]] && return 1
- fi
- mutex_lock
- UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf | sed 's/unmanaged-devices=//' | tr ';,' ' ')
- if [[ -z "$UNMANAGED" ]]; then
- mutex_unlock
- return 1
- fi
- [[ -n "$MAC" ]] && UNMANAGED=$(echo $UNMANAGED | sed -e "s/mac:${MAC}\( \|$\)//g")
- UNMANAGED=$(echo $UNMANAGED | sed -e "s/interface-name:${1}\( \|$\)//g")
- UNMANAGED=$(echo $UNMANAGED | sed -e 's/ $//')
- if [[ -z "$UNMANAGED" ]]; then
- sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF}
- else
- UNMANAGED="${UNMANAGED// /;}"
- UNMANAGED="unmanaged-devices=${UNMANAGED}"
- sed -e "s/^unmanaged-devices=.*/${UNMANAGED}/" -i ${NETWORKMANAGER_CONF}
- fi
- ADDED_UNMANAGED="${ADDED_UNMANAGED/ ${1} /}"
- mutex_unlock
- local nm_pid=$(pidof NetworkManager)
- [[ -n "$nm_pid" ]] && kill -HUP $nm_pid
- return 0
- }
- networkmanager_fix_unmanaged() {
- [[ -f ${NETWORKMANAGER_CONF} ]] || return
- mutex_lock
- sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF}
- mutex_unlock
- local nm_pid=$(pidof NetworkManager)
- [[ -n "$nm_pid" ]] && kill -HUP $nm_pid
- }
- networkmanager_rm_unmanaged_if_needed() {
- [[ $ADDED_UNMANAGED =~ .*\ ${1}\ .* ]] && networkmanager_rm_unmanaged $1 $2
- }
- networkmanager_wait_until_unmanaged() {
- local RES
- networkmanager_is_running || return 1
- while :; do
- networkmanager_iface_is_unmanaged "$1"
- RES=$?
- [[ $RES -eq 0 ]] && break
- [[ $RES -eq 2 ]] && die "Interface '${1}' does not exist.
- It's probably renamed by a udev rule."
- sleep 1
- done
- sleep 2
- return 0
- }
- CHANNEL=default
- GATEWAY=192.168.12.1
- WPA_VERSION=2
- ETC_HOSTS=0
- ADDN_HOSTS=
- DHCP_DNS=gateway
- NO_DNS=0
- NO_DNSMASQ=0
- DNS_PORT=
- HIDDEN=0
- MAC_FILTER=0
- MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept
- ISOLATE_CLIENTS=0
- SHARE_METHOD=nat
- IEEE80211N=0
- IEEE80211AC=0
- IEEE80211AX=0
- HT_CAPAB='[HT40+]'
- VHT_CAPAB=
- DRIVER=nl80211
- NO_VIRT=0
- COUNTRY=
- FREQ_BAND=2.4
- NEW_MACADDR=
- DAEMONIZE=0
- DAEMON_PIDFILE=
- DAEMON_LOGFILE=/dev/null
- NO_HAVEGED=0
- USE_PSK=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
- SHARE_METHOD IEEE80211N IEEE80211AC IEEE80211AX 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)
- FIX_UNMANAGED=0
- LIST_RUNNING=0
- STOP_ID=
- LIST_CLIENTS_ID=
- STORE_CONFIG=
- LOAD_CONFIG=
- CONFDIR=
- WIFI_IFACE=
- VWIFI_IFACE=
- INTERNET_IFACE=
- BRIDGE_IFACE=
- OLD_MACADDR=
- IP_ADDRS=
- ROUTE_ADDRS=
- HAVEGED_WATCHDOG_PID=
- _cleanup() {
- local PID x
- trap "" SIGINT SIGUSR1 SIGUSR2 EXIT
- 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
- # a value in $x. so we need to check if the value is a file
- [[ -f $x ]] && kill -9 $(cat $x)
- done
- rm -rf $CONFDIR
- local found=0
- for x in $(list_running_conf); do
- if [[ -f $x/nat_internet_iface && $(cat $x/nat_internet_iface) == $INTERNET_IFACE ]]; then
- found=1
- break
- fi
- done
- if [[ $found -eq 0 ]]; then
- cp -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding \
- /proc/sys/net/ipv4/conf/$INTERNET_IFACE/forwarding
- rm -f $COMMON_CONFDIR/${INTERNET_IFACE}_forwarding
- fi
- # if we are the last create_ap instance then set back the common values
- if ! has_running_instance; then
- # kill common processes
- for x in $COMMON_CONFDIR/*.pid; do
- [[ -f $x ]] && kill -9 $(cat $x)
- done
- # set old ip_forward
- if [[ -f $COMMON_CONFDIR/ip_forward ]]; then
- cp -f $COMMON_CONFDIR/ip_forward /proc/sys/net/ipv4
- rm -f $COMMON_CONFDIR/ip_forward
- fi
- # set old bridge-nf-call-iptables
- if [[ -f $COMMON_CONFDIR/bridge-nf-call-iptables ]]; then
- if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
- cp -f $COMMON_CONFDIR/bridge-nf-call-iptables /proc/sys/net/bridge
- fi
- rm -f $COMMON_CONFDIR/bridge-nf-call-iptables
- fi
- rm -rf $COMMON_CONFDIR
- fi
- if [[ "$SHARE_METHOD" != "none" ]]; then
- if [[ "$SHARE_METHOD" == "nat" ]]; then
- 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
- elif [[ "$SHARE_METHOD" == "bridge" ]]; then
- if ! is_bridge_interface $INTERNET_IFACE; then
- ip link set dev $BRIDGE_IFACE down
- ip link set dev $INTERNET_IFACE down
- ip link set dev $INTERNET_IFACE promisc off
- ip link set dev $INTERNET_IFACE nomaster
- ip link delete $BRIDGE_IFACE type bridge
- ip addr flush $INTERNET_IFACE
- ip link set dev $INTERNET_IFACE up
- dealloc_iface $BRIDGE_IFACE
- for x in "${IP_ADDRS[@]}"; do
- x="${x/inet/}"
- x="${x/secondary/}"
- x="${x/dynamic/}"
- x=$(echo $x | sed 's/\([0-9]\)sec/\1/g')
- x="${x/${INTERNET_IFACE}/}"
- ip addr add $x dev $INTERNET_IFACE
- done
- ip route flush dev $INTERNET_IFACE
- for x in "${ROUTE_ADDRS[@]}"; do
- [[ -z "$x" ]] && continue
- [[ "$x" == default* ]] && continue
- ip route add $x dev $INTERNET_IFACE
- done
- for x in "${ROUTE_ADDRS[@]}"; do
- [[ -z "$x" ]] && continue
- [[ "$x" != default* ]] && continue
- ip route add $x dev $INTERNET_IFACE
- done
- networkmanager_rm_unmanaged_if_needed $INTERNET_IFACE
- fi
- fi
- fi
- if [[ "$SHARE_METHOD" != "bridge" ]]; then
- if [[ $NO_DNS -eq 0 ]]; then
- iptables -w -D INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT
- iptables -w -D INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT
- iptables -w -t nat -D PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \
- -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
- fi
- iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT
- fi
- if [[ $NO_VIRT -eq 0 ]]; then
- if [[ -n "$VWIFI_IFACE" ]]; then
- ip link set down dev ${VWIFI_IFACE}
- ip addr flush ${VWIFI_IFACE}
- networkmanager_rm_unmanaged_if_needed ${VWIFI_IFACE} ${OLD_MACADDR}
- iw dev ${VWIFI_IFACE} del
- dealloc_iface $VWIFI_IFACE
- fi
- else
- ip link set down dev ${WIFI_IFACE}
- ip addr flush ${WIFI_IFACE}
- if [[ -n "$NEW_MACADDR" ]]; then
- ip link set dev ${WIFI_IFACE} address ${OLD_MACADDR}
- fi
- networkmanager_rm_unmanaged_if_needed ${WIFI_IFACE} ${OLD_MACADDR}
- fi
- mutex_unlock
- cleanup_lock
- if [[ $RUNNING_AS_DAEMON -eq 1 && -n "$DAEMON_PIDFILE" && -f "$DAEMON_PIDFILE" ]]; then
- rm $DAEMON_PIDFILE
- fi
- }
- cleanup() {
- echo
- echo -n "Doing cleanup.. "
- _cleanup > /dev/null 2>&1
- echo "done"
- }
- die() {
- [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2
- # send die signal to the main process
- [[ $BASHPID -ne $$ ]] && kill -USR2 $$
- # we don't need to call cleanup because it's traped on EXIT
- exit 1
- }
- clean_exit() {
- # send clean_exit signal to the main process
- [[ $BASHPID -ne $$ ]] && kill -USR1 $$
- # we don't need to call cleanup because it's traped on EXIT
- exit 0
- }
- list_running_conf() {
- local x
- mutex_lock
- for x in /tmp/create_ap.*; do
- if [[ -f $x/pid && -f $x/wifi_iface && -d /proc/$(cat $x/pid) ]]; then
- echo $x
- fi
- done
- mutex_unlock
- }
- list_running() {
- local IFACE wifi_iface x
- mutex_lock
- for x in $(list_running_conf); do
- IFACE=${x#*.}
- IFACE=${IFACE%%.*}
- wifi_iface=$(cat $x/wifi_iface)
- if [[ $IFACE == $wifi_iface ]]; then
- echo $(cat $x/pid) $IFACE
- else
- echo $(cat $x/pid) $IFACE '('$(cat $x/wifi_iface)')'
- fi
- done
- mutex_unlock
- }
- get_wifi_iface_from_pid() {
- list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E "^${1} " | cut -d' ' -f2
- }
- get_pid_from_wifi_iface() {
- list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E " ${1}$" | cut -d' ' -f1
- }
- get_confdir_from_pid() {
- local IFACE x
- mutex_lock
- for x in $(list_running_conf); do
- if [[ $(cat $x/pid) == "$1" ]]; then
- echo $x
- break
- fi
- done
- mutex_unlock
- }
- print_client() {
- local line ipaddr hostname
- local mac="$1"
- if [[ -f $CONFDIR/dnsmasq.leases ]]; then
- line=$(grep " $mac " $CONFDIR/dnsmasq.leases | tail -n 1)
- ipaddr=$(echo $line | cut -d' ' -f3)
- hostname=$(echo "$line" | cut -d' ' -f4)
- fi
- [[ -z "$ipaddr" ]] && ipaddr="*"
- [[ -z "$hostname" ]] && hostname="*"
- printf "%-20s %-18s %s\n" "$mac" "$ipaddr" "$hostname"
- }
- list_clients() {
- 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")
- 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")
- if [[ -z "$client_list" ]]; then
- echo "No clients connected"
- return
- fi
- 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
- }
- has_running_instance() {
- local PID x
- mutex_lock
- for x in /tmp/create_ap.*; do
- if [[ -f $x/pid ]]; then
- PID=$(cat $x/pid)
- if [[ -d /proc/$PID ]]; then
- mutex_unlock
- return 0
- fi
- fi
- done
- mutex_lock
- return 1
- }
- is_running_pid() {
- list_running | grep -E "^${1} " > /dev/null 2>&1
- }
- send_stop() {
- local x
- mutex_lock
- # send stop signal to specific pid
- if is_running_pid $1; then
- kill -USR1 $1
- mutex_unlock
- return
- fi
- # send stop signal to specific interface
- for x in $(list_running | grep -E " \(?${1}( |\)?\$)" | cut -f1 -d' '); do
- kill -USR1 $x
- done
- mutex_unlock
- }
- # Storing configs
- write_config() {
- local i=1
- if ! eval 'echo -n > "$STORE_CONFIG"' > /dev/null 2>&1; then
- echo "ERROR: Unable to create config file $STORE_CONFIG" >&2
- exit 1
- fi
- WIFI_IFACE=$1
- if [[ "$SHARE_METHOD" == "none" ]]; then
- SSID="$2"
- PASSPHRASE="$3"
- else
- INTERNET_IFACE="$2"
- SSID="$3"
- PASSPHRASE="$4"
- fi
- for config_opt in "${CONFIG_OPTS[@]}"; do
- eval echo $config_opt=\$$config_opt
- done >> "$STORE_CONFIG"
- echo -e "Config options written to '$STORE_CONFIG'"
- exit 0
- }
- is_config_opt() {
- local elem opt="$1"
- for elem in "${CONFIG_OPTS[@]}"; do
- if [[ "$elem" == "$opt" ]]; then
- return 0
- fi
- done
- return 1
- }
- # Load options from config file
- read_config() {
- local opt_name opt_val line
- while read line; do
- # Read switches and their values
- opt_name="${line%%=*}"
- opt_val="${line#*=}"
- if is_config_opt "$opt_name" ; then
- eval $opt_name="\$opt_val"
- else
- echo "WARN: Unrecognized configuration entry $opt_name" >&2
- fi
- done < "$LOAD_CONFIG"
- }
- ARGS=( "$@" )
- # Preprocessing for --config before option-parsing starts
- for ((i=0; i<$#; i++)); do
- if [[ "${ARGS[i]}" = "--config" ]]; then
- if [[ -f "${ARGS[i+1]}" ]]; then
- LOAD_CONFIG="${ARGS[i+1]}"
- read_config
- else
- echo "ERROR: No config file found at given location" >&2
- exit 1
- fi
- break
- 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","ieee80211ax","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" -- "$@")
- [[ $? -ne 0 ]] && exit 1
- eval set -- "$GETOPT_ARGS"
- FREQ_BAND_SET=0
- while :; do
- case "$1" in
- -h|--help)
- usage
- exit 0
- ;;
- --version)
- echo $VERSION
- exit 0
- ;;
- --hidden)
- shift
- HIDDEN=1
- ;;
- --mac-filter)
- shift
- MAC_FILTER=1
- ;;
- --mac-filter-accept)
- shift
- MAC_FILTER_ACCEPT="$1"
- shift
- ;;
- --isolate-clients)
- shift
- ISOLATE_CLIENTS=1
- ;;
- -c)
- shift
- CHANNEL="$1"
- shift
- ;;
- -w)
- shift
- WPA_VERSION="$1"
- [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2
- shift
- ;;
- -g)
- shift
- GATEWAY="$1"
- shift
- ;;
- -d)
- shift
- ETC_HOSTS=1
- ;;
- -e)
- shift
- ADDN_HOSTS="$1"
- shift
- ;;
- -n)
- shift
- SHARE_METHOD=none
- ;;
- -m)
- shift
- SHARE_METHOD="$1"
- shift
- ;;
- --ieee80211n)
- shift
- IEEE80211N=1
- ;;
- --ieee80211ac)
- shift
- IEEE80211AC=1
- ;;
- --ieee80211ax)
- shift
- IEEE80211AX=1
- ;;
- --ht_capab)
- shift
- HT_CAPAB="$1"
- shift
- ;;
- --vht_capab)
- shift
- VHT_CAPAB="$1"
- shift
- ;;
- --driver)
- shift
- DRIVER="$1"
- shift
- ;;
- --no-virt)
- shift
- NO_VIRT=1
- ;;
- --fix-unmanaged)
- shift
- FIX_UNMANAGED=1
- ;;
- --country)
- shift
- COUNTRY="$1"
- shift
- ;;
- --freq-band)
- shift
- FREQ_BAND="$1"
- FREQ_BAND_SET=1
- shift
- ;;
- --mac)
- shift
- NEW_MACADDR="$1"
- shift
- ;;
- --dhcp-dns)
- shift
- DHCP_DNS="$1"
- shift
- ;;
- --daemon)
- shift
- DAEMONIZE=1
- ;;
- --pidfile)
- shift
- DAEMON_PIDFILE="$1"
- shift
- ;;
- --logfile)
- shift
- DAEMON_LOGFILE="$1"
- shift
- ;;
- --stop)
- shift
- STOP_ID="$1"
- shift
- ;;
- --list)
- shift
- LIST_RUNNING=1
- echo -e "WARN: --list is deprecated, use --list-running instead.\n" >&2
- ;;
- --list-running)
- shift
- LIST_RUNNING=1
- ;;
- --list-clients)
- shift
- LIST_CLIENTS_ID="$1"
- shift
- ;;
- --no-haveged)
- shift
- NO_HAVEGED=1
- ;;
- --psk)
- shift
- USE_PSK=1
- ;;
- --no-dns)
- shift
- NO_DNS=1
- ;;
- --no-dnsmasq)
- shift
- NO_DNSMASQ=1
- ;;
- --redirect-to-localhost)
- shift
- REDIRECT_TO_LOCALHOST=1
- ;;
- --hostapd-debug)
- shift
- if [ "x$1" = "x1" ]; then
- HOSTAPD_DEBUG_ARGS="-d"
- elif [ "x$1" = "x2" ]; then
- HOSTAPD_DEBUG_ARGS="-dd"
- else
- printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1"
- exit 1
- fi
- shift
- ;;
- --mkconfig)
- shift
- STORE_CONFIG="$1"
- shift
- ;;
- --config)
- shift
- shift
- ;;
- --)
- shift
- break
- ;;
- esac
- done
- # Load positional args from config file, if needed
- if [[ -n "$LOAD_CONFIG" && $# -eq 0 ]]; then
- i=0
- # set arguments in order
- for x in WIFI_IFACE INTERNET_IFACE SSID PASSPHRASE; do
- if eval "[[ -n \"\$${x}\" ]]"; then
- eval "set -- \"\${@:1:$i}\" \"\$${x}\""
- ((i++))
- fi
- # we unset the variable to avoid any problems later
- eval "unset $x"
- done
- 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
- usage >&2
- exit 1
- fi
- # Set NO_DNS, if dnsmasq is disabled
- if [[ $NO_DNSMASQ -eq 1 ]]; then
- NO_DNS=1
- fi
- trap "cleanup_lock" EXIT
- if ! init_lock; then
- echo "ERROR: Failed to initialize lock" >&2
- exit 1
- fi
- # if the user press ctrl+c or we get USR1 signal
- # then run clean_exit()
- trap "clean_exit" SIGINT SIGUSR1
- # if we get USR2 signal then run die().
- trap "die" SIGUSR2
- [[ -n "$STORE_CONFIG" ]] && write_config "$@"
- if [[ $LIST_RUNNING -eq 1 ]]; then
- #echo -e "List of running $PROGNAME instances:\n"
- list_running
- exit 0
- fi
- if [[ -n "$LIST_CLIENTS_ID" ]]; then
- list_clients "$LIST_CLIENTS_ID"
- exit 0
- fi
- if [[ $(id -u) -ne 0 ]]; then
- echo "create_ap must be run as root." >&2
- exit 1
- fi
- if [[ -n "$STOP_ID" ]]; then
- echo "Trying to kill $PROGNAME instance associated with $STOP_ID..."
- send_stop "$STOP_ID"
- exit 0
- fi
- if [[ $FIX_UNMANAGED -eq 1 ]]; then
- echo "Trying to fix unmanaged status in NetworkManager..."
- networkmanager_fix_unmanaged
- exit 0
- fi
- if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then
- # Assume we're running underneath a service manager if PIDFILE is set
- # and don't clobber it's output with a useless message
- if [ -z "$DAEMON_PIDFILE" ]; then
- echo "Running as Daemon..."
- fi
- # run a detached create_ap
- RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" >>$DAEMON_LOGFILE 2>&1 &
- exit 0
- elif [[ $RUNNING_AS_DAEMON -eq 1 && -n "$DAEMON_PIDFILE" ]]; then
- echo $$ >$DAEMON_PIDFILE
- fi
- if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then
- echo "ERROR: Invalid frequency band" >&2
- exit 1
- fi
- if [[ $CHANNEL == default ]]; then
- if [[ $FREQ_BAND == 2.4 ]]; then
- CHANNEL=1
- else
- CHANNEL=36
- fi
- fi
- if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then
- echo "Channel number is greater than 14, assuming 5GHz frequency band"
- FREQ_BAND=5
- fi
- WIFI_IFACE=$1
- if ! is_wifi_interface ${WIFI_IFACE}; then
- echo "ERROR: '${WIFI_IFACE}' is not a WiFi interface" >&2
- exit 1
- fi
- if ! can_be_ap ${WIFI_IFACE}; then
- echo "ERROR: Your adapter does not support AP (master) mode" >&2
- exit 1
- fi
- if ! can_be_sta_and_ap ${WIFI_IFACE}; then
- if is_wifi_connected ${WIFI_IFACE}; then
- echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2
- exit 1
- elif [[ $NO_VIRT -eq 0 ]]; then
- echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2
- NO_VIRT=1
- fi
- fi
- HOSTAPD=$(which hostapd)
- if [[ ! -x "$HOSTAPD" ]]; then
- echo "ERROR: hostapd not found." >&2
- 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
- fi
- if [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" != "none" ]]; then
- echo "ERROR: Wrong Internet sharing method" >&2
- echo
- usage >&2
- exit 1
- fi
- if [[ -n "$NEW_MACADDR" ]]; then
- if ! is_macaddr "$NEW_MACADDR"; then
- echo "ERROR: '${NEW_MACADDR}' is not a valid MAC address" >&2
- exit 1
- fi
- if ! is_unicast_macaddr "$NEW_MACADDR"; then
- echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2
- exit 1
- fi
- if [[ $(get_all_macaddrs | grep -c ${NEW_MACADDR}) -ne 0 ]]; then
- echo "WARN: MAC address '${NEW_MACADDR}' already exists. Because of this, you may encounter some problems" >&2
- fi
- fi
- if [[ "$SHARE_METHOD" != "none" ]]; then
- MIN_REQUIRED_ARGS=2
- else
- MIN_REQUIRED_ARGS=1
- fi
- if [[ $# -gt $MIN_REQUIRED_ARGS ]]; then
- if [[ "$SHARE_METHOD" != "none" ]]; then
- if [[ $# -ne 3 && $# -ne 4 ]]; then
- usage >&2
- exit 1
- fi
- INTERNET_IFACE="$2"
- SSID="$3"
- PASSPHRASE="$4"
- else
- if [[ $# -ne 2 && $# -ne 3 ]]; then
- usage >&2
- exit 1
- fi
- SSID="$2"
- PASSPHRASE="$3"
- fi
- else
- if [[ "$SHARE_METHOD" != "none" ]]; then
- if [[ $# -ne 2 ]]; then
- usage >&2
- exit 1
- fi
- INTERNET_IFACE="$2"
- fi
- if tty -s; then
- while :; do
- read -p "SSID: " SSID
- if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
- echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
- continue
- fi
- break
- done
- while :; do
- if [[ $USE_PSK -eq 0 ]]; then
- read -p "Passphrase: " -s PASSPHRASE
- echo
- if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
- echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
- continue
- fi
- read -p "Retype passphrase: " -s PASSPHRASE2
- echo
- if [[ "$PASSPHRASE" != "$PASSPHRASE2" ]]; then
- echo "Passphrases do not match."
- else
- break
- fi
- else
- read -p "PSK: " PASSPHRASE
- echo
- if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
- echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
- continue
- fi
- fi
- done
- else
- read SSID
- read PASSPHRASE
- fi
- fi
- if [[ "$SHARE_METHOD" != "none" ]] && ! is_interface $INTERNET_IFACE; then
- echo "ERROR: '${INTERNET_IFACE}' is not an interface" >&2
- exit 1
- fi
- if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
- echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
- exit 1
- fi
- if [[ $USE_PSK -eq 0 ]]; then
- if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
- echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
- exit 1
- fi
- elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
- echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
- 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
- exit 1
- 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
- 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
- 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
- mutex_unlock
- if [[ "$SHARE_METHOD" == "bridge" ]]; then
- if is_bridge_interface $INTERNET_IFACE; then
- BRIDGE_IFACE=$INTERNET_IFACE
- else
- BRIDGE_IFACE=$(alloc_new_iface br)
- fi
- fi
- if [[ $USE_IWCONFIG -eq 0 ]]; then
- iw dev ${WIFI_IFACE} set power_save off
- fi
- if [[ $NO_VIRT -eq 0 ]]; then
- VWIFI_IFACE=$(alloc_new_iface ap)
- # in NetworkManager 0.9.9 and above we can set the interface as unmanaged without
- # the need of MAC address, so we set it before we create the virtual interface.
- if networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]]; then
- echo -n "Network Manager found, set ${VWIFI_IFACE} as unmanaged device... "
- networkmanager_add_unmanaged ${VWIFI_IFACE}
- # do not call networkmanager_wait_until_unmanaged because interface does not
- # exist yet
- echo "DONE"
- fi
- if is_wifi_connected ${WIFI_IFACE} && [[ $FREQ_BAND_SET -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
- if ( get_adapter_info ${IFACE} | grep "#channels <= 2" -q )
- then
- echo -e "\nmultiple channels supported"
- else
- echo -e "\nmultiple channels not supported",
- echo -e "\nfallback to channel ${WIFI_IFACE_CHANNEL}"
- CHANNEL=$WIFI_IFACE_CHANNEL
- fi
- else
- echo "channel------------------ ${CHANNEL}"
- fi
- elif is_wifi_connected ${WIFI_IFACE} && [[ $FREQ_BAND_SET -eq 1 ]]; then
- echo "Custom frequency band set with ${FREQ_BAND}Mhz with channel ${CHANNEL}"
- fi
- VIRTDIEMSG="Maybe your WiFi adapter does not fully support virtual interfaces.
- Try again with --no-virt."
- echo -n "Creating a virtual WiFi interface... "
- if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then
- # now we can call networkmanager_wait_until_unmanaged
- networkmanager_is_running && [[ $NM_OLDER_VERSION -eq 0 ]] && networkmanager_wait_until_unmanaged ${VWIFI_IFACE}
- echo "${VWIFI_IFACE} created."
- else
- VWIFI_IFACE=
- die "$VIRTDIEMSG"
- fi
- OLD_MACADDR=$(get_macaddr ${VWIFI_IFACE})
- if [[ -z "$NEW_MACADDR" && $(get_all_macaddrs | grep -c ${OLD_MACADDR}) -ne 1 ]]; then
- NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE})
- fi
- WIFI_IFACE=${VWIFI_IFACE}
- else
- OLD_MACADDR=$(get_macaddr ${WIFI_IFACE})
- fi
- mutex_lock
- echo $WIFI_IFACE > $CONFDIR/wifi_iface
- chmod 444 $CONFDIR/wifi_iface
- mutex_unlock
- if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then
- iw reg set "$COUNTRY"
- fi
- can_transmit_to_channel ${WIFI_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz."
- if networkmanager_exists && ! networkmanager_iface_is_unmanaged ${WIFI_IFACE}; then
- echo -n "Network Manager found, set ${WIFI_IFACE} as unmanaged device... "
- networkmanager_add_unmanaged ${WIFI_IFACE}
- if networkmanager_is_running; then
- networkmanager_wait_until_unmanaged ${WIFI_IFACE}
- fi
- echo "DONE"
- fi
- [[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!"
- [[ $MAC_FILTER -eq 1 ]] && echo "MAC address filtering is enabled!"
- [[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!"
- # hostapd config
- cat << EOF > $CONFDIR/hostapd.conf
- beacon_int=100
- ssid=${SSID}
- interface=${WIFI_IFACE}
- driver=${DRIVER}
- channel=${CHANNEL}
- ctrl_interface=$CONFDIR/hostapd_ctrl
- ctrl_interface_group=0
- ignore_broadcast_ssid=$HIDDEN
- ap_isolate=$ISOLATE_CLIENTS
- EOF
- if [[ -n "$COUNTRY" ]]; then
- cat << EOF >> $CONFDIR/hostapd.conf
- country_code=${COUNTRY}
- ieee80211d=1
- ieee80211h=1
- EOF
- fi
- if [[ $FREQ_BAND == 2.4 ]]; then
- echo "hw_mode=g" >> $CONFDIR/hostapd.conf
- else
- echo "hw_mode=a" >> $CONFDIR/hostapd.conf
- fi
- if [[ $MAC_FILTER -eq 1 ]]; then
- cat << EOF >> $CONFDIR/hostapd.conf
- macaddr_acl=${MAC_FILTER}
- accept_mac_file=${MAC_FILTER_ACCEPT}
- EOF
- fi
- if [[ $IEEE80211N -eq 1 ]]; then
- cat << EOF >> $CONFDIR/hostapd.conf
- ieee80211n=1
- ht_capab=${HT_CAPAB}
- EOF
- fi
- if [[ $IEEE80211AC -eq 1 ]]; then
- echo "ieee80211ac=1" >> $CONFDIR/hostapd.conf
- fi
- if [[ $IEEE80211AX -eq 1 ]]; then
- echo "ieee80211ax=1" >> $CONFDIR/hostapd.conf
- echo "he_oper_chwidth=1" >> $CONFDIR/hostapd.conf
- echo "he_oper_centr_freq_seg0_idx=42" >> $CONFDIR/hostapd.conf
- echo "he_su_beamformee=1" >> $CONFDIR/hostapd.conf
- fi
- if [[ -n "$VHT_CAPAB" ]]; then
- echo "vht_capab=${VHT_CAPAB}" >> $CONFDIR/hostapd.conf
- echo "vht_oper_chwidth=1" >> $CONFDIR/hostapd.conf
- echo "vht_oper_centr_freq_seg0_idx=42" >> $CONFDIR/hostapd.conf
- #echo "vht_oper_centr_freq_seg1_idx=155" >> $CONFDIR/hostapd.conf
- fi
- if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC ]] || [[ $IEEE80211AX -eq 1 ]]; then
- echo "wmm_enabled=1" >> $CONFDIR/hostapd.conf
- 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}
- wpa_${WPA_KEY_TYPE}=${PASSPHRASE}
- wpa_key_mgmt=WPA-PSK
- wpa_pairwise=TKIP CCMP
- rsn_pairwise=CCMP
- EOF
- fi
- if [[ "$SHARE_METHOD" == "bridge" ]]; then
- echo "bridge=${BRIDGE_IFACE}" >> $CONFDIR/hostapd.conf
- elif [[ $NO_DNSMASQ -eq 0 ]]; then
- # dnsmasq config (dhcp + dns)
- DNSMASQ_VER=$(dnsmasq -v | grep -m1 -oE '[0-9]+(\.[0-9]+)*\.[0-9]+')
- version_cmp $DNSMASQ_VER 2.63
- if [[ $? -eq 1 ]]; then
- DNSMASQ_BIND=bind-interfaces
- else
- DNSMASQ_BIND=bind-dynamic
- fi
- if [[ "$DHCP_DNS" == "gateway" ]]; then
- DHCP_DNS="$GATEWAY"
- fi
- cat << EOF > $CONFDIR/dnsmasq.conf
- listen-address=${GATEWAY}
- ${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
- 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
- [[ -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
- fi
- fi
- # initialize WiFi interface
- if [[ $NO_VIRT -eq 0 && -n "$NEW_MACADDR" ]]; then
- ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die "$VIRTDIEMSG"
- fi
- ip link set down dev ${WIFI_IFACE} || die "$VIRTDIEMSG"
- ip addr flush ${WIFI_IFACE} || die "$VIRTDIEMSG"
- if [[ $NO_VIRT -eq 1 && -n "$NEW_MACADDR" ]]; then
- ip link set dev ${WIFI_IFACE} address ${NEW_MACADDR} || die
- 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"
- fi
- # enable Internet sharing
- if [[ "$SHARE_METHOD" != "none" ]]; then
- echo "Sharing Internet using method: $SHARE_METHOD"
- if [[ "$SHARE_METHOD" == "nat" ]]; then
- iptables -w -t nat -I POSTROUTING -s ${GATEWAY%.*}.0/24 ! -o ${WIFI_IFACE} -j MASQUERADE || die
- iptables -w -I FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT || die
- 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
- # to enable clients to establish PPTP connections we must
- # load nf_nat_pptp module
- modprobe nf_nat_pptp > /dev/null 2>&1
- elif [[ "$SHARE_METHOD" == "bridge" ]]; then
- # disable iptables rules for bridged interfaces
- if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then
- echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables
- fi
- # to initialize the bridge interface correctly we need to do the following:
- #
- # 1) save the IPs and route table of INTERNET_IFACE
- # 2) if NetworkManager is running set INTERNET_IFACE as unmanaged
- # 3) create BRIDGE_IFACE and attach INTERNET_IFACE to it
- # 4) set the previously saved IPs and route table to BRIDGE_IFACE
- #
- # we need the above because BRIDGE_IFACE is the master interface from now on
- # and it must know where is connected, otherwise connection is lost.
- if ! is_bridge_interface $INTERNET_IFACE; then
- echo -n "Create a bridge interface... "
- OLD_IFS="$IFS"
- IFS=$'\n'
- IP_ADDRS=( $(ip addr show $INTERNET_IFACE | grep -A 1 -E 'inet[[:blank:]]' | paste - -) )
- ROUTE_ADDRS=( $(ip route show dev $INTERNET_IFACE) )
- IFS="$OLD_IFS"
- if networkmanager_is_running; then
- networkmanager_add_unmanaged $INTERNET_IFACE
- networkmanager_wait_until_unmanaged $INTERNET_IFACE
- fi
- # create bridge interface
- ip link add name $BRIDGE_IFACE type bridge || die
- ip link set dev $BRIDGE_IFACE up || die
- # set 0ms forward delay
- echo -n 0 > /sys/class/net/$BRIDGE_IFACE/bridge/forward_delay
- # attach internet interface to bridge interface
- ip link set dev $INTERNET_IFACE promisc on || die
- ip link set dev $INTERNET_IFACE up || die
- ip link set dev $INTERNET_IFACE master $BRIDGE_IFACE || die
- ip addr flush $INTERNET_IFACE
- for x in "${IP_ADDRS[@]}"; do
- x="${x/inet/}"
- x="${x/secondary/}"
- x="${x/dynamic/}"
- x=$(echo $x | sed 's/\([0-9]\)sec/\1/g')
- x="${x/${INTERNET_IFACE}/}"
- ip addr add $x dev $BRIDGE_IFACE || die
- done
- # remove any existing entries that were added from 'ip addr add'
- ip route flush dev $INTERNET_IFACE
- ip route flush dev $BRIDGE_IFACE
- # we must first add the entries that specify the subnets and then the
- # gateway entry, otherwise 'ip addr add' will return an error
- for x in "${ROUTE_ADDRS[@]}"; do
- [[ "$x" == default* ]] && continue
- ip route add $x dev $BRIDGE_IFACE || die
- done
- for x in "${ROUTE_ADDRS[@]}"; do
- [[ "$x" != default* ]] && continue
- ip route add $x dev $BRIDGE_IFACE || die
- done
- echo "$BRIDGE_IFACE created."
- fi
- fi
- else
- echo "No Internet sharing"
- fi
- # start dhcp + dns (optional)
- if [[ "$SHARE_METHOD" != "bridge" ]]; then
- if [[ $NO_DNS -eq 0 ]]; then
- DNS_PORT=5353
- iptables -w -I INPUT -p tcp -m tcp --dport $DNS_PORT -j ACCEPT || die
- iptables -w -I INPUT -p udp -m udp --dport $DNS_PORT -j ACCEPT || die
- iptables -w -t nat -I PREROUTING -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} \
- -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
- 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 which complain > /dev/null 2>&1; then
- # openSUSE's apparmor does not allow dnsmasq to read files.
- # remove restriction.
- complain dnsmasq
- fi
- umask 0033
- dnsmasq -C $CONFDIR/dnsmasq.conf -x $CONFDIR/dnsmasq.pid -l $CONFDIR/dnsmasq.leases -p $DNS_PORT || die
- umask $SCRIPT_UMASK
- fi
- 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
- STDBUF_PATH=$STDBUF_PATH" -oL"
- fi
- $STDBUF_PATH $HOSTAPD $HOSTAPD_DEBUG_ARGS $CONFDIR/hostapd.conf &
- HOSTAPD_PID=$!
- 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 "try running the following before starting create_ap:" >&2
- if [[ $NM_OLDER_VERSION -eq 1 ]]; then
- echo " nmcli nm wifi off" >&2
- else
- echo " nmcli r wifi off" >&2
- fi
- echo " rfkill unblock wlan" >&2
- fi
- die
- fi
- clean_exit
- # Local Variables:
- # tab-width: 4
- # indent-tabs-mode: nil
- # End:
- # vim: et sts=4 sw=4
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement