diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2015-04-01 15:24:15 +0200 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2015-04-01 15:24:15 +0200 |
| commit | bc17cd54bb6d2bcccb233012116a551c5199944b (patch) | |
| tree | f8723fe2a9b126f6b206336246d7dc273e53a63f /create_ap | |
| parent | 8d49cec0c11b5aea523ccefb75942bb3c7d5fa2a (diff) | |
| download | nowlan-bc17cd54bb6d2bcccb233012116a551c5199944b.tar.gz nowlan-bc17cd54bb6d2bcccb233012116a551c5199944b.zip | |
Diffstat (limited to 'create_ap')
| -rwxr-xr-x | create_ap | 1205 |
1 files changed, 0 insertions, 1205 deletions
diff --git a/create_ap b/create_ap deleted file mode 100755 index ff46cf5..0000000 --- a/create_ap +++ /dev/null @@ -1,1205 +0,0 @@ -#!/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.1 - -# make sure that all command outputs are in english -# so we can parse them correctly -export LC_ALL=C - -usage() { - echo "Usage: $(basename $0) [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: 1+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 " --hidden Make the Access Point hidden (do not broadcast the SSID)" - echo " --ieee80211n Enable IEEE 802.11n (HT)" - echo " --ht_capab <HT> HT capabilities (default: [HT40+])" - 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 " --daemon Run create_ap in the background" - 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" - echo " --list Show the create_ap processes that are already running" - echo - echo "Non-Bridging Options:" - 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 - 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 " $(basename $0) wlan0 eth0 MyAccessPoint MyPassPhrase" - echo " echo -e 'MyAccessPoint\nMyPassPhrase' | $(basename $0) wlan0 eth0" - echo " $(basename $0) wlan0 eth0 MyAccessPoint" - echo " echo 'MyAccessPoint' | $(basename $0) wlan0 eth0" - echo " $(basename $0) wlan0 wlan0 MyAccessPoint MyPassPhrase" - echo " $(basename $0) -n wlan0 MyAccessPoint MyPassPhrase" - echo " $(basename $0) -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase" - echo " $(basename $0) -m bridge wlan0 br0 MyAccessPoint MyPassPhrase" - echo " $(basename $0) --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase" - echo " $(basename $0) --daemon wlan0 eth0 MyAccessPoint MyPassPhrase" - echo " $(basename $0) --stop wlan0" -} - -# 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() { - [[ ! $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() { - 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() { - PHY=$(get_phy_device "$1") - [[ $? -ne 0 ]] && return 1 - iw phy $PHY info -} - -get_adapter_kernel_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 - 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() { - 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 "Channel ${CHANNEL_NUM} :") - [[ -z "${CHANNEL_INFO}" ]] && return 1 - return 0 - fi -} - -# taken from iw/util.c -ieee80211_frequency_to_channel() { - 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() { - 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_avail_bridge() { - i=0 - while :; do - if ! is_interface br${i}; then - echo br${i} - return - fi - i=$((i + 1)) - done -} - -get_virt_iface_name() { - i=0 - while :; do - if ! is_interface ap${i}; then - echo ap${i} - return - fi - i=$((i+1)) - done -} - -get_all_macaddrs() { - cat /sys/class/net/*/address -} - -get_new_macaddr() { - OLDMAC=$(get_macaddr "$1") - LAST_BYTE=$(printf %d 0x${OLDMAC##*:}) - 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 - echo $NEWMAC -} - -# start haveged when needed -haveged_watchdog() { - local show_warn=0 - while :; do - if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then - if ! which haveged > /dev/null 2>&1; then - if [[ $show_warn -eq 0 ]]; then - echo "WARN: Low entropy detected. We recommend you to install \`haveged'" - show_warn=1 - fi - elif ! pidof haveged > /dev/null 2>&1; then - echo "Low entropy detected, starting haveged" - # boost low-entropy - haveged -w 1024 -F > /dev/null 2>&1 & - local haveged_pid=$! - echo $haveged_pid > $CONFDIR/haveged.pid - wait $haveged_pid - fi - fi - sleep 2 - done -} - -NETWORKMANAGER_CONF=/etc/NetworkManager/NetworkManager.conf -NM_OLDER_VERSION=1 - -networkmanager_exists() { - 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() { - networkmanager_exists || return 1 - if [[ $NM_OLDER_VERSION -eq 1 ]]; then - NMCLI_OUT=$(nmcli -t -f RUNNING nm) - else - NMCLI_OUT=$(nmcli -t -f RUNNING g) - fi - [[ "$NMCLI_OUT" == "running" ]] -} - -networkmanager_iface_is_unmanaged() { - is_interface "$1" || return 2 - (nmcli -t -f DEVICE,STATE d | grep -E "^$1:unmanaged$" > /dev/null 2>&1) || return 1 -} - -ADDED_UNMANAGED= - -networkmanager_add_unmanaged() { - 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 - - 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 ';,' ' ') - - for x in $UNMANAGED; do - [[ $x == "mac:${MAC}" ]] && return 2 - [[ $NM_OLDER_VERSION -eq 0 && $x == "interface-name:${1}" ]] && return 2 - 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} " - - return 0 -} - -networkmanager_rm_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 - - UNMANAGED=$(grep -m1 -Eo '^unmanaged-devices=[[:alnum:]:;,-]*' /etc/NetworkManager/NetworkManager.conf | sed 's/unmanaged-devices=//' | tr ';,' ' ') - - [[ -z "$UNMANAGED" ]] && return 1 - - [[ -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} /}" - - return 0 -} - -networkmanager_fix_unmanaged() { - [[ -f ${NETWORKMANAGER_CONF} ]] || return - sed -e "/^unmanaged-devices=.*/d" -i ${NETWORKMANAGER_CONF} -} - -networkmanager_rm_unmanaged_if_needed() { - [[ $ADDED_UNMANAGED =~ .*\ ${1}\ .* ]] && networkmanager_rm_unmanaged $1 $2 -} - -networkmanager_wait_until_unmanaged() { - 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 exists. - It's probably renamed by a udev rule." - sleep 1 - done - sleep 2 - return 0 -} - - -CHANNEL=default -GATEWAY=192.168.12.1 -WPA_VERSION=1+2 -ETC_HOSTS=0 -HIDDEN=0 -SHARE_METHOD=nat -IEEE80211N=0 -HT_CAPAB='[HT40+]' -DRIVER=nl80211 -NO_VIRT=0 -FIX_UNMANAGED=0 -COUNTRY= -FREQ_BAND=2.4 -NEW_MACADDR= -DAEMONIZE=0 -LIST_RUNNING=0 -STOP_ID= -NO_HAVEGED=0 - -CONFDIR= -WIFI_IFACE= -VWIFI_IFACE= -INTERNET_IFACE= -BRIDGE_IFACE= -OLD_IP_FORWARD= -OLD_BRIDGE_IPTABLES= -OLD_MACADDR= -IP_ADDRS= -ROUTE_ADDRS= - -HAVEGED_WATCHDOG_PID= - -_cleanup() { - trap "" SIGINT - trap "" SIGUSR1 - - # kill haveged_watchdog - [[ -n "$HAVEGED_WATCHDOG_PID" ]] && kill $HAVEGED_WATCHDOG_PID - - # exiting - 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 - if [[ -f $x ]]; then - PID=$(cat $x) - disown $PID - kill -9 $PID - fi - done - rm -rf $CONFDIR - - if [[ "$SHARE_METHOD" != "none" ]]; then - if [[ "$SHARE_METHOD" == "nat" ]]; then - iptables -t nat -D POSTROUTING -o ${INTERNET_IFACE} -j MASQUERADE - iptables -D FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT - iptables -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT - [[ -n "$OLD_IP_FORWARD" ]] && echo $OLD_IP_FORWARD > /proc/sys/net/ipv4/ip_forward - elif [[ "$SHARE_METHOD" == "bridge" ]]; then - if [[ -n "$OLD_BRIDGE_IPTABLES" ]]; then - echo $OLD_BRIDGE_IPTABLES > /proc/sys/net/bridge/bridge-nf-call-iptables - fi - - 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 - - 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 - iptables -D INPUT -p tcp -m tcp --dport 53 -j ACCEPT - iptables -D INPUT -p udp -m udp --dport 53 -j ACCEPT - iptables -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 - 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 -} - -cleanup() { - echo - echo -n "Doing cleanup.. " - _cleanup > /dev/null 2>&1 - echo "done" -} - -die() { - [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2 - cleanup - exit 1 -} - -clean_exit() { - cleanup - exit 0 -} - -list_running() { - for x in /tmp/create_ap.*; do - if [[ -f $x/pid ]]; then - PID=$(cat $x/pid) - if [[ -d /proc/$PID ]]; then - IFACE=${x#*.} - IFACE=${IFACE%%.*} - echo $PID $IFACE - fi - fi - done -} - -is_running_pid() { - list_running | grep -E "^${1} " > /dev/null 2>&1 -} - -send_stop() { - # send stop signal to specific pid - if is_running_pid $1; then - kill -USR1 $1 - return - fi - - # send stop signal to specific interface - for x in $(list_running | grep -E " ${1}\$" | cut -f1 -d' '); do - kill -USR1 $x - done -} - -# if the user press ctrl+c then execute die() -trap "clean_exit" SIGINT -trap "clean_exit" SIGUSR1 - -ARGS=( "$@" ) -GETOPT_ARGS=$(getopt -o hc:w:g:dnm: -l "help","hidden","ieee80211n","ht_capab:","driver:","no-virt","fix-unmanaged","country:","freq-band:","mac:","daemon","stop:","list","version","no-haveged" -n $(basename $0) -- "$@") -[[ $? -ne 0 ]] && exit 1 -eval set -- "$GETOPT_ARGS" - -while :; do - case "$1" in - -h|--help) - usage - exit 1 - ;; - --version) - echo $VERSION - exit 0 - ;; - --hidden) - shift - HIDDEN=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 - ;; - -n) - shift - SHARE_METHOD=none - ;; - -m) - shift - SHARE_METHOD="$1" - shift - ;; - --ieee80211n) - shift - IEEE80211N=1 - ;; - --ht_capab) - shift - HT_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" - shift - ;; - --mac) - shift - NEW_MACADDR="$1" - shift - ;; - --daemon) - shift - DAEMONIZE=1 - ;; - --stop) - shift - STOP_ID="$1" - shift - ;; - --list) - shift - LIST_RUNNING=1 - ;; - --no-haveged) - shift - NO_HAVEGED=1 - ;; - --) - shift - break - ;; - esac -done - -if [[ $# -lt 1 && $FIX_UNMANAGED -eq 0 && -z "$STOP_ID" && $LIST_RUNNING -eq 0 ]]; then - usage >&2 - exit 1 -fi - -if [[ $(id -u) -ne 0 ]]; then - echo "You must run it as root." >&2 - exit 1 -fi - -if [[ -n "$STOP_ID" ]]; then - send_stop "$STOP_ID" - exit 0 -fi - -if [[ $LIST_RUNNING -eq 1 ]]; then - list_running - exit 0 -fi - -if [[ $FIX_UNMANAGED -eq 1 ]]; then - networkmanager_fix_unmanaged - exit 0 -fi - -if [[ $DAEMONIZE -eq 1 ]]; then - # remove --daemon - NEW_ARGS=( ) - for x in "${ARGS[@]}"; do - [[ "$x" != "--daemon" ]] && NEW_ARGS+=( "$x" ) - done - - # run a detached create_ap - setsid "$0" "${NEW_ARGS[@]}" & - exit 0 -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 - -if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then - if ! strings $(which 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 - 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 - 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 [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then - echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&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 [[ "$SHARE_METHOD" == "bridge" ]]; then - if [[ -e /proc/sys/net/bridge/bridge-nf-call-iptables ]]; then - OLD_BRIDGE_IPTABLES=$(cat /proc/sys/net/bridge/bridge-nf-call-iptables) - fi - - if is_bridge_interface $INTERNET_IFACE; then - BRIDGE_IFACE=$INTERNET_IFACE - else - BRIDGE_IFACE=$(get_avail_bridge) - fi -elif [[ "$SHARE_METHOD" == "nat" ]]; then - OLD_IP_FORWARD=$(cat /proc/sys/net/ipv4/ip_forward) -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 - -CONFDIR=$(mktemp -d /tmp/create_ap.${WIFI_IFACE}.conf.XXXXXXXX) -echo "Config dir: $CONFDIR" -echo "PID: $$" -echo $$ > $CONFDIR/pid - -if [[ $NO_VIRT -eq 0 ]]; then - VWIFI_IFACE=$(get_virt_iface_name) - - # 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}; 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 - else - echo - fi - 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 managed; 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 - -can_transmit_to_channel ${WIFI_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz." - -if networkmanager_is_running && ! networkmanager_iface_is_unmanaged ${WIFI_IFACE}; then - echo -n "Network Manager found, set ${WIFI_IFACE} as unmanaged device... " - networkmanager_add_unmanaged ${WIFI_IFACE} - networkmanager_wait_until_unmanaged ${WIFI_IFACE} - echo "DONE" -fi - -[[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!" - -# 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 -EOF - -if [[ -n $COUNTRY ]]; then - [[ $USE_IWCONFIG -eq 0 ]] && iw reg set $COUNTRY - echo "country_code=${COUNTRY}" >> $CONFDIR/hostapd.conf -fi - -if [[ $FREQ_BAND == 2.4 ]]; then - echo "hw_mode=g" >> $CONFDIR/hostapd.conf -else - echo "hw_mode=a" >> $CONFDIR/hostapd.conf -fi - -if [[ $IEEE80211N -eq 1 ]]; then - cat << EOF >> $CONFDIR/hostapd.conf -ieee80211n=1 -wmm_enabled=1 -ht_capab=${HT_CAPAB} -EOF -fi - -if [[ -n "$PASSPHRASE" ]]; then - [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 - cat << EOF >> $CONFDIR/hostapd.conf -wpa=${WPA_VERSION} -wpa_passphrase=$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 -else - # 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 - cat << EOF > $CONFDIR/dnsmasq.conf -listen-address=${GATEWAY} -${DNSMASQ_BIND} -dhcp-range=${GATEWAY%.*}.1,${GATEWAY%.*}.254,255.255.255.0,24h -dhcp-option=option:router,${GATEWAY} -EOF - [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf -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 -t nat -I POSTROUTING -o ${INTERNET_IFACE} -j MASQUERADE || die - iptables -I FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT || die - iptables -I FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT || die - echo 1 > /proc/sys/net/ipv4/ip_forward || die - 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 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 dns + dhcp server -if [[ "$SHARE_METHOD" != "bridge" ]]; then - iptables -I INPUT -p tcp -m tcp --dport 53 -j ACCEPT || die - iptables -I INPUT -p udp -m udp --dport 53 -j ACCEPT || die - iptables -I INPUT -p udp -m udp --dport 67 -j ACCEPT || die - dnsmasq -C $CONFDIR/dnsmasq.conf -x $CONFDIR/dnsmasq.pid || die -fi - -# start access point -echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" - -# from now on we exit with 0 on SIGINT -trap "clean_exit" SIGINT -trap "clean_exit" SIGUSR1 - -if [[ $NO_HAVEGED -eq 0 ]]; then - haveged_watchdog & - HAVEGED_WATCHDOG_PID=$! -fi - -# start hostapd -hostapd $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: |
