You are not logged in.

#1 2013-05-07 19:41:01

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

[script] create_ap: Create a NATed or Bridged WiFi Access Point

This script use hostapd + dnsmasq + iptables to create a NATed Access Point OR hostapd + brctl + dhclient to create a bridged Access Point.
The default behavior is a NATed Access Point.

updated script will be here: https://github.com/oblique/create_ap and http://git.2f30.org/create_ap/

Examples

  • No passphrase (open network):

    ./create_ap wlan0 eth0 MyAccessPoint

    OR

    echo -e "MyAccessPoint" | ./create_ap wlan0 eth0
  • WPA + WPA2 passphrase:

    ./create_ap wlan0 eth0 MyAccessPoint MyPassPhrase

    OR

    echo -e "MyAccessPoint\nMyPassPhrase" | ./create_ap wlan0 eth0
  • AP without Internet sharing:

    ./create_ap -n wlan0 MyAccessPoint MyPassPhrase
  • Bridged Internet sharing:

    ./create_ap -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase
  • Internet sharing from the same WiFi interface:

    ./create_ap wlan0 wlan0 MyAccessPoint MyPassPhrase

Usage

Usage: create_ap [options] <wifi-interface> [<interface-with-internet>] [<access-point-name> [<passphrase>]]

Options:
  -h, --help          Show this help
  -c <channel>        Channel number (default: 1)
  -w <WPA version>    Use 1 for WPA, use 2 for WPA2, use 1+2 for both (default: 1+2)
  -n                  Disable Internet sharing (if you use this, don't pass
                      the <interface-with-internet> argument)
  -m <method>         Method for Internet sharing.
                      Use: 'nat' for NAT (default)
                           'bridge' for bridging
                           'none' for no Internet sharing (equivalent to -n)
  --hidden            Make the Access Point hidden (do not broadcast the SSID)
  --ieee80211n        Enable IEEE 802.11n (HT)
  --ht_capab <HT>     HT capabilities (default: [HT40+])
  --driver            Choose your WiFi adapter driver (default: nl80211)
  --no-virt           Do not create virtual interface

Non-Bridging Options:
  -g <gateway>        IPv4 Gateway for the Access Point (default: 192.168.12.1)
  -d                  DNS server will take into account /etc/hosts

Useful informations:
  * If you're not using the --no-virt option, then you can create an AP with the same
    interface you are getting your Internet connection.
  * You can pass your SSID and password through pipe or through arguments (see examples).

Examples:
  create_ap wlan0 eth0 MyAccessPoint MyPassPhrase
  echo -e 'MyAccessPoint\nMyPassPhrase' | create_ap wlan0 eth0
  create_ap wlan0 eth0 MyAccessPoint
  echo 'MyAccessPoint' | create_ap wlan0 eth0
  create_ap wlan0 wlan0 MyAccessPoint MyPassPhrase
  create_ap -n wlan0 MyAccessPoint MyPassPhrase
  create_ap -m bridge wlan0 eth0 MyAccessPoint MyPassPhrase
  create_ap --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase

Code

#!/bin/bash

# general dependencies:
#    bash (to run this script)
#    util-linux (for getopt)
#    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

# dependencies for 'bridge' Internet sharing method
#    bridge-utils

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 "  -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 "  --driver            Choose your WiFi adapter driver (default: nl80211)"
    echo "  --no-virt           Do not create virtual interface"
    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
    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) --driver rtl871xdrv wlan0 eth0 MyAccessPoint MyPassPhrase"
}

# 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_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
}

get_phy_device() {
    for x in /sys/class/ieee80211/*; do
        [[ ! -d "$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
}

can_have_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_have_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=$2

    if [[ $USE_IWCONFIG -eq 0 ]]; then
        CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep "MHz \[${CHANNEL}\]")
        [[ -z "${CHANNEL_INFO}" ]] && return 1
        [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1
        [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1
        return 0
    else
        CHANNEL=$(printf '%02d' ${CHANNEL})
        CHANNEL_INFO=$(iwlist ${IFACE} channel | grep "Channel ${CHANNEL} :")
        [[ -z "${CHANNEL_INFO}" ]] && return 1
        return 0
    fi
}

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
}

get_macaddr() {
    ip link show "$1" | grep ether | grep -Eo '([0-9a-f]{2}:){5}[0-9a-f]{2}[[:space:]]' | tr -d '[[:space:]]'
}

get_avail_bridge() {
    for i in {0..100}; do
        curr_bridge=$(brctl show | grep "br$i" | cut -s -f1)
        if [[ -z $curr_bridge ]]; then
            echo "br$i"
            return
        fi
    done
}

get_new_macaddr() {
    OLDMAC=$(get_macaddr "$1")
    for i in {20..255}; do
        NEWMAC="${OLDMAC%:*}:$(printf %02x $i)"
        (ip link | grep "ether ${NEWMAC}" > /dev/null 2>&1) || break
    done
    echo $NEWMAC
}

ADDED_UNMANAGED=0
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.10
    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() {
    nmcli -t -f DEVICE,STATE d | grep -E "^$1:unmanaged$" > /dev/null 2>&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 | sed 's/unmanaged-devices=//' | tr ';,' ' ')
    WAS_EMPTY=0
    [[ -z "$UNMANAGED" ]] && WAS_EMPTY=1

    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_rm_unmanaged_if_needed() {
    [[ $ADDED_UNMANAGED =~ .*\ ${1}\ .* ]] && networkmanager_rm_unmanaged ${1}
}

networkmanager_wait_until_unmanaged() {
    networkmanager_is_running || return 1
    while ! networkmanager_iface_is_unmanaged "$1"; do
        sleep 1
    done
    sleep 2
    return 0
}


CHANNEL=1
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

CONFDIR=
WIFI_IFACE=
VWIFI_IFACE=
INTERNET_IFACE=
BRIDGE_IFACE=
OLD_IP_FORWARD=
OLD_BRIDGE_IPTABLES=
OLD_MACADDR=

cleanup() {
    trap "" SIGINT

    echo
    echo "Doing cleanup..."

    # 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
        [[ -f $x ]] && kill -9 $(cat $x)
    done
    rm -rf $CONFDIR

    if [[ "$SHARE_METHOD" != "none" ]]; then
        if [[ "$SHARE_METHOD" == "nat" ]]; then
            iptables -t nat -D POSTROUTING -o ${INTERNET_IFACE} -j MASQUERADE > /dev/null 2>&1
            iptables -D FORWARD -i ${WIFI_IFACE} -s ${GATEWAY%.*}.0/24 -j ACCEPT > /dev/null 2>&1
            iptables -D FORWARD -i ${INTERNET_IFACE} -d ${GATEWAY%.*}.0/24 -j ACCEPT > /dev/null 2>&1
            [[ -n $OLD_IP_FORWARD ]] && echo $OLD_IP_FORWARD > /proc/sys/net/ipv4/ip_forward
        elif [[ "$SHARE_METHOD" == "bridge" ]]; then
            ip link set down $BRIDGE_IFACE
            brctl delbr $BRIDGE_IFACE
            [[ -n $OLD_BRIDGE_IPTABLES ]] && echo $OLD_BRIDGE_IPTABLES > /proc/sys/net/bridge/bridge-nf-call-iptables
        fi
    fi

    if [[ "$SHARE_METHOD" != "bridge" ]]; then
        iptables -D INPUT -p tcp -m tcp --dport 53 -j ACCEPT > /dev/null 2>&1
        iptables -D INPUT -p udp -m udp --dport 53 -j ACCEPT > /dev/null 2>&1
        iptables -D INPUT -p udp -m udp --dport 67 -j ACCEPT > /dev/null 2>&1
    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}
        networkmanager_rm_unmanaged_if_needed ${WIFI_IFACE}
    fi
}

die() {
    [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2
    cleanup
    exit 1
}

clean_exit() {
    cleanup
    exit 0
}

# if the user press ctrl+c then execute die()
trap "die" SIGINT

ARGS=$(getopt -o hc:w:g:dnm: -l "help","hidden","ieee80211n","ht_capab:","driver:","no-virt" -n $(basename $0) -- "$@")
[[ $? -ne 0 ]] && exit 1
eval set -- "$ARGS"

while :; do
    case "$1" in
        -h|--help)
            usage >&2
            exit 1
            ;;
        --hidden)
            shift
            HIDDEN=1
            ;;
        -c)
            shift
            CHANNEL="$1"
            shift
            ;;
        -w)
            shift
            WPA_VERSION="$1"
            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
            ;;
        --)
            shift
            break
            ;;
    esac
done

if [[ $# -lt 1 ]]; then
    usage >&2
    exit 1
fi

if [[ $(id -u) -ne 0 ]]; then
    echo "You must run it as root." >&2
    exit 1
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_have_ap ${WIFI_IFACE}; then
    echo "ERROR: Your adapter does not support AP (master) mode" >&2
    exit 1
fi

if ! can_have_sta_and_ap ${WIFI_IFACE}; then
    if is_wifi_connected ${WIFI_IFACE}; then
        echo "ERROR: Your adapter can not be connected to an AP and at the same time transmit as an AP" >&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 [[ "$SHARE_METHOD" != "nat" && "$SHARE_METHOD" != "bridge" && "$SHARE_METHOD" != "none" ]]; then
    echo "ERROR: Wrong Internet sharing method" >&2
    echo
    usage >&2
    exit 1
fi

if [[ "$SHARE_METHOD" == "bridge" ]]; then
    OLD_BRIDGE_IPTABLES=$(cat /proc/sys/net/bridge/bridge-nf-call-iptables)
    BRIDGE_IFACE=$(get_avail_bridge)
    if [[ -z $BRIDGE_IFACE ]]; then
        echo "ERROR: No availabe bridges < br100" >&2
        exit 1
    fi
elif [[ "$SHARE_METHOD" == "nat" ]]; then
    OLD_IP_FORWARD=$(cat /proc/sys/net/ipv4/ip_forward)
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
        read -p "SSID: " SSID
        while :; do
            read -p "Passphrase: " -s PASSPHRASE
            echo
            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 [[ $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"

if [[ $NO_VIRT -eq 0 ]]; then
    VWIFI_IFACE=${WIFI_IFACE}ap

    # in NetworkManager 0.9.10 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 $1 as unmanaged device... "
        networkmanager_add_unmanaged ${VWIFI_IFACE}
        # do not call networkmanager_wait_until_unmanaged because interface does not
        # exist yet
        echo "DONE"
    fi

    WIFI_IFACE_CHANNEL=$(iw dev ${WIFI_IFACE} info | grep channel | awk '{print $2}')

    if [[ -n $WIFI_IFACE_CHANNEL && $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then
        echo "hostapd will fail to use channel $CHANNEL because $WIFI_IFACE is already set to channel $WIFI_IFACE_CHANNEL, fallback to channel $WIFI_IFACE_CHANNEL."
        CHANNEL=$WIFI_IFACE_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... "
    iw dev ${VWIFI_IFACE} del > /dev/null 2>&1
    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})
    [[ ${OLD_MACADDR} == $(get_macaddr ${WIFI_IFACE}) ]] && NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE})
    WIFI_IFACE=${VWIFI_IFACE}
fi

can_transmit_to_channel ${WIFI_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}."

if networkmanager_is_running && ! networkmanager_iface_is_unmanaged ${WIFI_IFACE}; then
    echo -n "Network Manager found, set $1 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
ssid=${SSID}
interface=${WIFI_IFACE}
driver=${DRIVER}
hw_mode=g
channel=${CHANNEL}

ctrl_interface=$CONFDIR/hostapd_ctrl
ctrl_interface_group=0
ignore_broadcast_ssid=$HIDDEN
EOF

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" == "2+1" ]] && 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
interface=${WIFI_IFACE}
${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 [[ "$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
        echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables || die
        # create and initialize bridged interface
        brctl addbr ${BRIDGE_IFACE} || die
        brctl addif ${BRIDGE_IFACE} ${INTERNET_IFACE} || die
        ip link set dev ${BRIDGE_IFACE} up || die
    fi
else
    echo "No Internet sharing"
fi

# boost low-entropy
if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then
    which haveged > /dev/null 2>&1 && {
        haveged -w 1024 -p $CONFDIR/haveged.pid
    }
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

if ! hostapd $CONFDIR/hostapd.conf; 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

Last edited by OBLiQUE (2014-09-02 20:26:22)

Offline

#2 2013-05-07 23:14:41

dimigon
Member
Registered: 2009-03-07
Posts: 139
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Awesome!

Offline

#3 2013-05-25 15:45:34

lbonn
Member
Registered: 2012-11-03
Posts: 2

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Saved my day after a long and painful WiFi struggle.

Thanks a lot !

Offline

#4 2013-06-02 19:49:47

brevity
Member
From: ENS, Paris
Registered: 2011-07-02
Posts: 12

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Thanks a million big_smile

Offline

#5 2013-06-11 07:29:52

adam777
Member
Registered: 2012-05-28
Posts: 158

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Thank, just what I was looking for.
Unfortunately, it seems that currently my Intel 5300 card (using the iwlwifi driver), does not support AP mode.
From what I understand, hostapd can be used in bridge mode as well, which should have no compatibility problems.
Can some one point me in the right direction?

* EDIT *
After more attempts, I think I got it wrong and AP mode is indeed required.

Last edited by adam777 (2013-06-12 16:20:10)

Offline

#6 2013-06-30 03:57:11

fatjake
Member
Registered: 2010-04-26
Posts: 45

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Thank you so much for this!

Offline

#7 2013-07-01 10:51:29

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

adam777 wrote:

Thank, just what I was looking for.
Unfortunately, it seems that currently my Intel 5300 card (using the iwlwifi driver), does not support AP mode.
From what I understand, hostapd can be used in bridge mode as well, which should have no compatibility problems.
Can some one point me in the right direction?

* EDIT *
After more attempts, I think I got it wrong and AP mode is indeed required.

Sorry for the late reply, I didn't noticed your message.. Did you got any errors? I have Intel 6205 and it works.
Also if you use NetworkManager, then you have to say to NetworkManager to stop using your interface.
You can do it by editing the /etc/NetworkManager/NetworkManager.conf file and put the following (without the <>):

[keyfile]
unmanaged-devices=mac:<interface's mac address here>

and restart your NetworkManager. Ofcourse after you finish, you have to remove it in order to get your wifi back to working with NetworkManager.

Offline

#8 2013-07-27 16:55:48

Nad
Member
Registered: 2013-07-27
Posts: 1

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Thanks a lot!

This works perfectly for me on Debian 7 with my Intel Centrino Wireless-N 1030 (iwlwifi) card :-)

I had some trouble at first with "Unable to listen on IP, address in use", but then realised that I needed to stop the dnsmasq daemon which starts automatically after apt-get installing it, but I guess the create_ap script calls it standalone and doesn't want the daemon running.

Offline

#9 2013-07-29 10:13:03

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Nad wrote:

but I guess the create_ap script calls it standalone and doesn't want the daemon running.

yes, that's true

Offline

#10 2013-08-03 14:59:17

micrograce
Member
Registered: 2013-08-03
Posts: 1

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Brilliant! Thanks, OBLiQUE.

Offline

#11 2013-09-14 11:19:54

Evert7
Member
From: Lier, Belgium
Registered: 2012-02-18
Posts: 63
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Wow. This saved me hours and hours of bridging, aliasing, and whatever I had to do to get my Raspberry Pi AP working.
Thanks a lot OBLiQUE.


Website: evertheylen.appspot.com (new!)

Offline

#12 2013-09-15 15:41:41

Mr Green
Forum Fellow
From: U.K.
Registered: 2003-12-21
Posts: 5,745

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Have spent last couple of days trying to get pi to run as access point, turned out my usb wifi did not support nl802111. Managed to find a working hostapd and now your script works fine. Do need a way to run it on boot (systemd service file)

Might be the wrong place to ask this but I want access point to stand alone, just allow connections to it not forward on to eth0. Run as a media server?

Last edited by Mr Green (2013-09-15 16:52:15)


Mr Green

Offline

#13 2013-09-15 21:33:36

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

As I understand you want to create an access point that does not have an Internet connection and use it as a server?
You can do this by using the 'lo' interface instead of an actual interface that is connected to the Internet. After this you can connect to the access point and then use 192.168.12.1 to access it.

example:

create_ap wlan0 lo MyAccessPoint

Last edited by OBLiQUE (2013-09-15 21:37:24)

Offline

#14 2013-09-16 03:25:43

Mr Green
Forum Fellow
From: U.K.
Registered: 2003-12-21
Posts: 5,745

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Thanks very much knew it would be something really simple I was missing


Mr Green

Offline

#15 2013-09-16 10:35:46

Mr Green
Forum Fellow
From: U.K.
Registered: 2003-12-21
Posts: 5,745

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

I have server working now just need to figure a way of starting script from boot. gmedia-renderer is only working via eth0 (which is connected to home router) and not via wlan0 > localhost. Last piece of the puzzle


Mr Green

Offline

#16 2013-09-16 14:30:57

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

I updated my script and now you can use the following if you want a standalone AP (i.e. AP without Internet sharing)

create_ap -n wlan0 MyAccessPoint

To make it run on boot check this: https://wiki.archlinux.org/index.php/Sy … vice_files
also, make gmediarender to run on boot.

I don't know why gmediarender is only working via eth0, netstat is showing that is binded to the 0.0.0.0, so it should worked without any problems. Make sure that you didn't pass the '-I' or '--ip-address' to the gmediarender.

Offline

#17 2013-09-16 16:06:15

Mr Green
Forum Fellow
From: U.K.
Registered: 2003-12-21
Posts: 5,745

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

I can connect to ArchPi (AP name) via wifi and it does get an address, then I can see ArchPi in bubbleupnp. Thing is I can on run create_ap via ethernet to allow me ssh in. Did try writing a service file but it did not work correctly (just would not start). To me create_ap runs but does not end so maybe I need to background script somehow.

Will update script and try new version. wink


Mr Green

Offline

#18 2013-09-23 12:01:10

vishal8492
Member
Registered: 2011-12-15
Posts: 17

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Wow , after almost 3 dissapointing hours and just when I was about to give up , Thanks man !!!
When they're going to support AP mode in Network Manager , a bit frustrating and is there any
workaround for making this work with NetworkManager ?.

Works with :
Linux power 3.10.10-1-ARCH #1 SMP PREEMPT Fri Aug 30 12:11:59 CEST 2013 i686 GNU/Linux
TP-LINK 821N USB Adapter

Offline

#19 2013-09-23 18:53:19

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

The only workaround for NetworkManager is to put your wifi interface in the 'unmanaged-devices' of NetworkManager.
To do this you have to edit the /etc/NetworkManager/NetworkManager.conf and put the following (without the <>):

[keyfile]
unmanaged-devices=mac:<interface's mac address here>

after this you have to restart the NetworkManager daemon with:

systemctl restart NetworkManager

and then start my script. after you finish, remove your changes from /etc/NetworkManager/NetworkManager.conf and restart the NetworkManager again.

Offline

#20 2013-09-25 08:12:54

vishal8492
Member
Registered: 2011-12-15
Posts: 17

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

Thanks , it indeed works without interfering with NetWorkManager ; but I meant is there any way , we can create AP using NetworkManager ?
Again Awesome work with script , will take a look at it soon.

Offline

#21 2013-09-25 15:13:43

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

vishal8492 wrote:

Thanks , it indeed works without interfering with NetWorkManager ; but I meant is there any way , we can create AP using NetworkManager ?

I don't think so

Offline

#22 2013-09-28 04:09:21

fantab
Member
From: 3rd Rock from the Sun
Registered: 2011-06-07
Posts: 150

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

The Script is not really working for me. The hotspot is detected but I cannot successfully establish connection. I have installed all the necessary dependencies, including 'haveged'; and disabled the device in NetworkManger.

I use UFW and as such iptables.service is NOT enabled. Since iptables is a dependency I was wondering if it not being enabled is the issue. If its is then how can I get it working with UFW?
Or any other ideas?

EDIT: on my Windows 7 netbook the diagnostics report, "Wireless Network Connection" doesn't have a valid IP".
(My ISP uses Dynamic IP).

(By the way, I dual boot with Ubuntu.. I have my hotspot working fine there with 'ap-hotspot-0.2' script.)

Last edited by fantab (2013-09-28 04:41:34)


"Evolution is the nature's way of issuing upgrades".
__________________________________________________________
Arch_x64-Gnome-Shell ~ Arch-lts_x64-Xfce ~ Trusty Thar_x64-Unity ~ LMDE_x64-Cinnamon

Offline

#23 2013-09-28 05:31:38

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

fantab wrote:

I use UFW and as such iptables.service is NOT enabled. Since iptables is a dependency I was wondering if it not being enabled is the issue. If its is then how can I get it working with UFW?
Or any other ideas?

I never used UFW, I don't know if interferes with iptable. You don't have to enable/start iptables.service to make my script works.
I'm a bit busy right now, so I will check it in few days about UFW.

fantab wrote:

(By the way, I dual boot with Ubuntu.. I have my hotspot working fine there with 'ap-hotspot-0.2' script.)

Can you check in your Ubuntu if my script works?

Last edited by OBLiQUE (2013-09-28 05:33:37)

Offline

#24 2013-09-28 05:58:30

progandy
Member
Registered: 2012-05-17
Posts: 2,143

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

OBLiQUE wrote:

The only workaround for NetworkManager is to put your wifi interface in the 'unmanaged-devices' of NetworkManager.
To do this you have to edit the /etc/NetworkManager/NetworkManager.conf and put the following (without the <>):

I used to create an AP alongside NetworkManager without those changes. To stop nm from using the wlan device, I executed "nmcli nm wifi off", then "rfkill unblock wlan". When I was done "nmcli nm wifi on" and NetworkManager takes over again.

I am running UFW and it works with my custom script. This is my iptables setup

iptables -t nat -A POSTROUTING -o $eth -j MASQUERADE
iptables -A FORWARD -i $wlan -s $_subnet -j ACCEPT 
iptables -A FORWARD -i $eth -d $_subnet -j ACCEPT
echo 1 > /proc/sys/net/ipv4/ip_forward

Last edited by progandy (2013-09-28 06:04:09)

Offline

#25 2013-09-28 06:18:29

OBLiQUE
Member
Registered: 2008-12-04
Posts: 107
Website

Re: [script] create_ap: Create a NATed or Bridged WiFi Access Point

create_ap now has its own repository https://github.com/oblique/create_ap and http://git.2f30.org/create_ap/

Offline

Board footer

Powered by FluxBB