08 March 2012

Wi-Fi Access Point on Laptop

If you want to set up a Wi-Fi Access Point on your laptop, this is how you can do it on Linux. I use Arch Linux for demonstration because it is my platform of choice (e.g., the pacman package manager and the rc.d daemon manager are Arch-specific). It should be straightforward to adapt it to other Linux/Unix platform where hostapd and dhcp are supported.

Prerequisite.

A laptop with an AP-capable Wi-Fi interface (i.e., iw list | less with AP listed in the Supported interface modes). I use Cisco Valet Connector AM10 USB Wi-Fi adapter I got cheaply from Woot for illustration. As of this writing, you can get one of these adapters for under $15 on Amazon.

hostapd and dhcp are the key software which makes this work (note that the DHCP server dhcpd is what we really need from dhcp). Install them.

pacman -S hostapd dhcp

The script.

I package the process of setting up an AP in a Bash script for ease of use. You should adapt it if you are not using Arch. You could also study it and see how it works.

You can download it. Here is a listing of it.

#! /bin/sh

usage () {
    echo "`basename $0`    [ssid] [psk]" >&2
}

setup_hostapd () {
    local ap_if=$1
    local ssid=$2
    local psk=$3

    cat > ~/hostapd.conf <<-END
interface=$ap_if
driver=nl80211

logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2

dump_file=/tmp/hostapd.dump

ctrl_interface=/var/run/hostapd
ctrl_interface_group=wheel

ssid=$ssid

hw_mode=g
channel=3

max_num_sta=255

macaddr_acl=0
accept_mac_file=/etc/hostapd/hostapd.accept
deny_mac_file=/etc/hostapd/hostapd.deny

auth_algs=1

ignore_broadcast_ssid=0

wpa=2 # RSN only

wpa_passphrase=$psk
wpa_key_mgmt=WPA-PSK
#wpa_pairwise=TKIP
rsn_pairwise=CCMP

END

    [ -f /etc/hostapd/hostapd.conf ] && sudo cp /etc/hostapd/hostapd.conf /etc/hostapd/hostapd.conf.bak
    sudo mv ~/hostapd.conf /etc/hostapd/
    sudo chown root:root /etc/hostapd/hostapd.conf
}

restore_hostapd () {
    [ -f /etc/hostapd/hostapd.conf.bak ] && sudo cp /etc/hostapd/hostapd.conf.bak /etc/hostapd/hostapd.conf  
}

setup_dhcp4 () {
    local ap_if=$1

    cat > ~/dhcpd <<-END
    #
    # Arguments to be passed to the DHCP server daemon
    #

    # ipv4 runtime parameters
    DHCP4_ARGS="-q $ap_if"

    # ipv6 runtime parameters
    DHCP6_ARGS="-q"
END
    [ -f /etc/conf.d/dhcpd ] && sudo cp /etc/conf.d/dhcpd /etc/conf.d/dhcpd.bak
    sudo mv ~/dhcpd /etc/conf.d/
    sudo chown root:root /etc/conf.d/dhcpd

    cat > ~/dhcpd.conf <<-END
    # dhcpd.conf
    #
    # Sample configuration file for ISC dhcpd
    #

    option domain-name "example.com";

    default-lease-time 600;
    max-lease-time 7200;

    log-facility local7;


    subnet 10.1.1.0 netmask 255.255.255.0 {
    option domain-name "example.com";
    option domain-name-servers 8.8.8.8;
    max-lease-time 3600;
    default-lease-time 600;

    range 10.1.1.10 10.1.1.240;
    option subnet-mask 255.255.255.0;
    option broadcast-address 10.1.1.255;
    option routers 10.1.1.1;
    }
END
    [ -f /etc/dhcpd.conf ] && sudo cp /etc/dhcpd.conf /etc/dhcpd.conf.bak
    sudo mv ~/dhcpd.conf /etc/
    sudo chown root:root /etc/dhcpd.conf

}

restore_dhcp4 () {
    [ -f /etc/dhcpd.conf.bak ] && sudo cp /etc/dhcpd.conf.bak /etc/dhcpd.conf
}



sudo -v

action=$1
ap_if=$2
if [ -n "$3" ]; then
    outbound_if=$3
else
    usage
    exit 1
fi

[ -n "$4" ] && ssid=$4 || ssid="test"
[ -n "$5" ] && psk=$5 || psk="testtest"

if [[ ${#psk} -lt 8 ]] || [[ ${#psk} -gt 63 ]]; then
    echo "psk must be between 8 and 63 characters" >& 2
    exit 2
fi

case "$1" in

    "start")
        setup_hostapd "$ap_if" "$ssid" "$psk"
        sudo systemctl start hostapd
        sudo ip addr add 10.1.1.1/24 dev "$ap_if"
        setup_dhcp4 "$ap_if"
        sudo systemctl start dhcpd4
        sudo systemctl restart iptables
        sudo iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o "$outbound_if" -j MASQUERADE
        sudo sysctl net.ipv4.ip_forward=1
        ;;

    "stop")
        sudo iptables -t nat -D POSTROUTING -s 10.1.1.0/24 -o "$outbound_if" -j MASQUERADE
        sudo systemctl restart iptables
        sudo systemctl stop dhcpd4
        restore_dhcp4
        sudo ip addr del 10.1.1.1/24 dev "$ap_if"
        sudo systemctl stop hostapd
        restore_hostapd
        ;;

    *)
        usage
        exit 1
esac

Usage.

Download and put it somewhere executable ($HOME/bin is a good choice; make sure that directory is in your PATH). Make the script executable chmod +x my-ap.sh.

The script enables a WPA2-Personal AP on your laptop (with your (optional) choice of SSID and PSK), which is the state-of-the-art Wi-Fi security for personal use (that is, without messing around with a separate authentication server). The three mandatory arguments are

  1. start or stop: your intended action.
  2. AP interface: the wireless interface which supports Master/AP mode; hostapd works on this interface.
  3. Outbound interface: the network (either wireless or wired) interface with Internet connection.

The two optional arguments are
  1. SSID: the default is test.
  2. PSK: the default is testtest. By standard, the PSK must be between 8 to 63 characters (inclusive).
Make sure you are able to sudo to root.

For example, suppose the laptop is connected to the Internet through wlan0, then

my-ap.sh start wlan1 wlan0
will create a WPA2-Personal AP on wlan1 with SSID test and PSK testtest.

my-ap.sh start wlan1 wlan0 myap testagain
will create an AP with SSID myap and PSK testagain.

my-ap.sh stop wlan1 wlan0
will de-construct (I avoid saying "destroy" to not scare you away :-)) the AP.

Beware, weak PSK is susceptible to brute-force attack.