The officially official Devuan Forum!

You are not logged in.

#1 2017-10-19 20:44:57

GNUser
Member
Registered: 2017-03-16
Posts: 150

GNU/Linux laptop as router, vpn router, or wifi repeater

I found create_ap and it's so cool that I thought I'd tell all my Devuan friends about it smile It works similarly to the "Hotspot" function on Android phones and is free software (FreeBSD license).

0. Before proceeding, make sure your wireless card supports AP (access point) mode. You want to see "AP" listed when you run "iw list" in a terminal:

bruno@thinkpad:~$ iw list
Wiphy phy0
---snip---
	Supported interface modes:
		 * IBSS
		 * managed
		 * AP

1. To get all create_ap's dependencies:

sudo apt-get util-linux procps hostapd iproute2 iw iwconfig haveged

2. Last step is to get create_ap itself from their github page. To "install" it, just download the zip from github, extract it, then run sudo make install from the root of the extracted folder. Nothing is actually compiled--the make command simply copies some things over to /usr/bin. To uninstall, running sudo make uninstall from the root of the extracted folder removes everything.

---

Now enjoy all the options this opens up:

If you have a laptop connected to wifi and want to use the laptop as a wifi repeater (yes, this actually works with a single wireless adapter):

create_ap wlan0 wlan0 MyAccessPoint MyPassPhrase

If you have a laptop connected to ethernet that you want to use as a router:

create_ap wlan0 eth0 MyAccessPoint MyPassPhrase

If you have a laptop connected to ethernet and running openvpn that you want to use as a vpn router:

create_ap wlan0 tun0 MyAccessPoint MyPassPhrase

Amazing, right?

Last edited by GNUser (2017-10-20 12:50:30)

Offline

#2 2017-10-19 20:51:13

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

Over the past few days I've been dissecting create_ap (over 1800 lines) to see how it works. So far, I've managed to cut it down to about 150 lines by hard-wiring some sensible defaults and eliminating myriad sanity checks. Here is my skinny version:

#!/bin/bash

# Dependencies: iw iproute2 iptables dnsmasq hostapd haveged
# Usage: Set the ssid and password below, then run this script as root/sudo on host machine
# Result: A virtual wireless interface is created on host to share its internet access

hotspot_ssid=GNULinuxAP
hotspot_password=gnuforever

main()
{
    shoo_network_manager
    find_internet_if
    find_wireless_if
    create_hotspot_if
    setup_nat
    setup_dnsmasq
    setup_hostapd
}

shoo_network_manager() # if network manager is running, make sure it doesn't meddle with our hostpot (we don't need its "help")
{
    if pgrep NetworkManager &>/dev/null; then # network manager is running
        nm_config_file=/etc/NetworkManager/NetworkManager.conf
        if grep -q 'interface-name:ap0' $nm_config_file; then # ap0 already mentioned in config file, so we're done
            return
        else # network manager is running and ap0 not mentioned in config file
            if grep -q 'unmanaged-devices' $nm_config_file; then # there's an unmanaged interface list already, add ap0 to it
                sed -i -r 's/(unmanaged-devices.*$)/\1;interface-name:ap0/' $nm_config_file
            else # there's no unmanaged interface list yet, so let's start one
                printf '\n[keyfile]\nunmanaged-devices=interface-name:ap0' >>$nm_config_file
            fi
        fi
    fi
}

find_internet_if() # find host's internet-facing interface
{
    n_candidates=$(route | grep default | awk '{print $8}' | wc -l)
    if [ "$n_candidates" = "1" ]; then
        internet_if=$(route | grep default | awk '{print $8}')
    else
        echo "More than one internet-facing interface found: $(route | grep default | awk '{print $8}')"
        echo -n "Which one should will feed the hotspot? "
        read internet_if
    fi
}

find_wireless_if() # find host's wireless interface
{
    wireless_if=$(cat /proc/net/wireless | perl -ne '/(\w+):/ && print $1') # e.g., wlan0 or wlp2s0
}

create_hotspot_if() # create a virtual wireless interface to use as hotspot, with arbitrary name of ap0
{
    iw dev $wireless_if interface add ap0 type __ap

    # wait up to 5 seconds for ap0 to exist
    c=0
    while true; do 
        iw dev ap0 info &>/dev/null && break
        sleep 0.5
        ((c++))
        ((c==10)) && { echo "ap0 could not be created within the time limit."; exit 1; }
    done
    sleep 1

    ip link set dev ap0 address c4:04:15:9c:07:9d # a made-up mac address with real vendor bits (c4:04:15 = Netgear) 
    ip link set down dev ap0
    ip addr flush ap0
    ip link set up dev ap0
    ip addr add 192.168.20.1/24 broadcast 192.168.20.255 dev ap0
}

setup_nat() # nat is more robust than bridge
{
    # first save current routing settings
    cat /proc/sys/net/ipv4/conf/$internet_if/forwarding >/tmp/forwarding.saved
    cat /proc/sys/net/ipv4/ip_forward >/tmp/ip_forward.saved
    
    # now go ahead and change routing/firewall settings for NAT sharing
    echo 1 >/proc/sys/net/ipv4/conf/$internet_if/forwarding
    echo 1 >/proc/sys/net/ipv4/ip_forward
    modprobe nf_nat_pptp &>/dev/null # to enable clients to establish PPTP connections
    iptables -w -t nat -I POSTROUTING -s 192.168.20.0/24 ! -o ap0 -j MASQUERADE
    iptables -w -I FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
    iptables -w -I FORWARD -i $internet_if -d 192.168.20.0/24 -j ACCEPT
    iptables -w -I INPUT -p tcp -m tcp --dport 5353 -j ACCEPT # for dns, can be any non-privileged port
    iptables -w -I INPUT -p udp -m udp --dport 5353 -j ACCEPT
    iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
    iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
    iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT
}

setup_dnsmasq() # DHCP server
{
    echo "listen-address=192.168.20.1
bind-dynamic
dhcp-range=192.168.20.100,192.168.20.200,255.255.255.0,24h
dhcp-option-force=option:router,192.168.20.1
dhcp-option-force=option:dns-server,192.168.20.1
dhcp-option-force=option:mtu,1500
no-hosts" >/tmp/dnsmasq.conf
    dnsmasq -C /tmp/dnsmasq.conf -p 5353
}

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
}

setup_hostapd()
{
    # first figure out radio frequency/channel for hotspot
    frequency=$(iw dev $wireless_if link | grep -i freq | awk '{print $2}')
    if [ -z "$frequency" ]; then # if wifi is off, use an arbitary channel (can be 1 or any other)
        channel=1
    else # if wifi is active on host, put ap0 on same channel for maximum hardware compatibility
        channel=$(ieee80211_frequency_to_channel $frequency)
    fi

    # now we have everything we need for hostapd
    echo "beacon_int=100
ssid=$hotspot_ssid
interface=ap0
driver=nl80211
channel=$channel
ignore_broadcast_ssid=0
ap_isolate=0
hw_mode=g
wpa=3
wpa_passphrase=$hotspot_password
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP" >/tmp/hostapd.conf 
    hostapd /tmp/hostapd.conf
}

cleanup()
{
    echo "Cleaning up..."
    cat /tmp/forwarding.saved >/proc/sys/net/ipv4/conf/$internet_if/forwarding
    cat /tmp/ip_forward.saved >/proc/sys/net/ipv4/ip_forward    
    pkill -f /tmp/dnsmasq.conf # kill only the dnsmasq instance we started
    pkill hostapd
    iptables -w -t nat -D POSTROUTING -s 192.168.20.0/24 ! -o ap0 -j MASQUERADE
    iptables -w -D FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
    iptables -w -D FORWARD -i $internet_if -d 192.168.20.0/24 -j ACCEPT
    iptables -w -D INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
    iptables -w -D INPUT -p udp -m udp --dport 5353 -j ACCEPT
    iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
    iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
    iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT
    ip link set down dev ap0 
    ip addr flush ap0
    iw dev ap0 del
}
trap cleanup EXIT HUP TERM

main

P.S. Both create_ap and my script have a pretty thorough cleanup function. But if you're paranoid, just reboot after using the hotspot and you'll be guaranteed to be 100% back to your pre-hotspot network settings.

Last edited by GNUser (2017-10-21 01:36:02)

Offline

#3 2017-10-20 02:56:31

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

The only quirk with my skinny version is that sometimes (apparently randomly) at this point in the script:

ip link set up dev ap0

I get this error:

RTNETLINK answers: Name not unique on network

This happens randomly and I really can't account for it. Sometimes it happens even after a reboot, so I'm 100% sure that the name ap0 is unique on the network. I'd hate to put 1700 lines of code back in just for this. Any idea how to troubleshoot this?

Last edited by GNUser (2017-10-20 03:03:45)

Offline

#4 2017-10-20 03:03:42

ralph.ronnquist
Administrator
From: Clifton Hill, Victoria, AUS
Registered: 2016-11-30
Posts: 115

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

sometime a sleep 1 beforehand makes wonders

Offline

#5 2017-10-20 03:05:45

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

Good thought. Alas, I tried it and it still happens randomly. Here's an example:

bruno@thinkpad:~$ sudo bash -x hotspot
+ hotspot_ssid=FreeInternet
+ hotspot_password=DevuanRules
++ route
++ wc -l
++ grep default
++ awk '{print $8}'
+ n_candidates=1
+ '[' 1 = 1 ']'
++ route
++ awk '{print $8}'
++ grep default
+ internet_if=wlan0
+ iw dev wlan0 interface add ap0 type __ap
+ ip link set dev ap0 address 5c:ac:4c:2f:93:60
+ ip link set down dev ap0
+ ip addr flush ap0
+ sleep 1
+ ip link set up dev ap0
RTNETLINK answers: Name not unique on network
+ ip addr add 192.168.20.1/24 broadcast 192.168.20.255 dev ap0
+ cat /proc/sys/net/ipv4/conf/wlan0/forwarding
+ cat /proc/sys/net/ipv4/ip_forward
+ echo 1
+ echo 1
+ modprobe nf_nat_pptp
+ iptables -w -t nat -I POSTROUTING -s 192.168.20.0/24 '!' -o ap0 -j MASQUERADE
+ iptables -w -I FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
+ iptables -w -I FORWARD -i wlan0 -d 192.168.20.0/24 -j ACCEPT
+ iptables -w -I INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
+ iptables -w -I INPUT -p udp -m udp --dport 5353 -j ACCEPT
+ iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -t nat -I PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -I INPUT -p udp -m udp --dport 67 -j ACCEPT
+ echo 'listen-address=192.168.20.1
bind-dynamic
dhcp-range=192.168.20.100,192.168.20.200,255.255.255.0,24h
dhcp-option-force=option:router,192.168.20.1
dhcp-option-force=option:dns-server,192.168.20.1
# If you’d like to have dnsmasq assign static IPs, bind the LAN computer'\''s
# NIC MAC address:
#dhcp-host=98:f1:70:4f:4b:67,192.168.20.60 # roku stick
dhcp-option-force=option:mtu,1500
no-hosts'
+ dnsmasq -C /tmp/dnsmasq.conf -p 5353
++ iw dev wlan0 link
++ awk '{print $2}'
++ grep -i freq
+ frequency=2462
+ '[' -z 2462 ']'
++ ieee80211_frequency_to_channel 2462
++ local FREQ=2462
++ [[ 2462 -eq 2484 ]]
++ [[ 2462 -lt 2484 ]]
++ echo 11
+ channel=11
+ echo 'beacon_int=100
ssid=FreeInternet
interface=ap0
driver=nl80211
channel=11
ignore_broadcast_ssid=0
ap_isolate=0
hw_mode=g
wpa=3
wpa_passphrase=DevuanRules
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP'
+ hostapd /tmp/hostapd.conf
Configuration file: /tmp/hostapd.conf
Could not set interface ap0 flags (UP): Name not unique on network
nl80211: Could not set interface 'ap0' UP
nl80211 driver initialization failed.
hostapd_free_hapd_data: Interface ap0 wasn't started
+ trap cleanup EXIT HUP TERM
+ cleanup
+ echo 'Cleaning up...'
Cleaning up...
+ cat /tmp/forwarding.saved
+ cat /tmp/ip_forward.saved
+ pkill hostapd
+ iptables -w -t nat -D POSTROUTING -s 192.168.20.0/24 '!' -o ap0 -j MASQUERADE
+ iptables -w -D FORWARD -i ap0 -s 192.168.20.0/24 -j ACCEPT
+ iptables -w -D FORWARD -i wlan0 -d 192.168.20.0/24 -j ACCEPT
+ iptables -w -D INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
+ iptables -w -D INPUT -p udp -m udp --dport 5353 -j ACCEPT
+ iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -t nat -D PREROUTING -s 192.168.20.0/24 -d 192.168.20.1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
+ iptables -w -D INPUT -p udp -m udp --dport 67 -j ACCEPT
+ ip link set down dev ap0
+ ip addr flush ap0
+ iw dev ap0 del

Any other ideas? It would be nice to get the skinny version working reliably.

Last edited by GNUser (2017-10-20 03:10:04)

Offline

#6 2017-10-20 03:14:09

ralph.ronnquist
Administrator
From: Clifton Hill, Victoria, AUS
Registered: 2016-11-30
Posts: 115

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

btw if you care about  IEEE Registration Authority, a "locally administered mac address" needs bit 2 of first byte set and bit 1 cleared. Thus "5e" would be better than "5c".
see eg http://www.noah.org/wiki/MAC_address

Offline

#7 2017-10-20 03:14:55

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

@ralph.ronnquist - Good instinct. Yes, that's all that was needed. This seems to be the slow step:

iw dev wlan0 interface add ap0 type __ap

So putting the sleep 1 immediately after it cured all ills. I've updated my skinny version accordingly.

Thanks a bundle!

Last edited by GNUser (2017-10-20 03:15:15)

Offline

#8 2017-10-20 03:21:19

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

That's weird, because the vendor bits of that made-up mac address are the same as that in my atheros wifi card. I adjusted the made-up address as you recommended, but I'm going to check that the vendor bits 5e:ac:4c match some vendor. I want the mac to be plausible.

Last edited by GNUser (2017-10-20 03:22:55)

Offline

#9 2017-10-20 03:27:50

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

See this tool: https://macvendors.com/
5c:ac:4c are vendor bits of a real vendor (Hon Hai)
5e:ac:4c do not match any existing vendor bits.

I guess Hon Hai didn't follow the rules. I'll stick with the naughty but plausible/existing vendor bits.

Offline

#10 2017-10-20 13:08:38

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

I discovered that NetworkManager can be dealt with without requiring reboot or a service restart. I updated my script and the create_ap instructions accordingly (i.e., removed the step where user needs to bother with this).

Also, I cooked up a different "fake" mac address for the virtual hotspot interface, this one using same vendor bits as my Netgear router. Hopefully Netgear read the rules when they chose their vendor bits.

Finally, I made miscellaneous improvements to my script. It is tested and working reliably in Devuan Jessie, Debian Jessie, and Trisquel7-mini. (As a side note, each of these three is running its default init: SysVinit, systemd, and Upstart, respectively. In fact, I found that even though Trisquel7-mini officially runs Upstart, it has bits and pieces of SysVinit and systemd thrown in. What a mess! I'm so happy with Devuan!).

So to summarize (and assuming you want to use my version of the script big_smile):
0. Check that your wireless network card offers AP mode (see post #1)
1. Install the dependencies
2. Copy the script in post #2 into a file (hotspot might be a good name for the file!)
3. Make the file executable
4. sudo hotspot

Stopping the script (e.g., with Control + c) turns off the hotspot and cleans everything up.

When my Netgear WNDR3800 router running LibreCMC dies, I think I'll just use this script on my old EeePC to repurpose it as a vpn router.

I hope someone out there finds this script as tremendously useful as I do smile

Last edited by GNUser (2017-10-20 18:08:09)

Offline

#11 2017-10-20 23:02:38

greenjeans
Member
Registered: 2017-04-07
Posts: 355
Website

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

GNUser wrote:

When my Netgear WNDR3800 router running LibreCMC dies, I think I'll just use this script on my old EeePC to repurpose it as a vpn router.

I hope someone out there finds this script as tremendously useful as I do smile

Yet another awesome use for older hardware, thanks GNUser! I'm snagging your script wink


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal 64 and 32 bit Devuan-based openbox and mate systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#12 2017-10-21 01:33:50

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

You're welcome, greenjeans. Enjoy! One of my favorite things about GNU/Linux is definitely the fact that it can make older hardware useful again.

Offline

#13 2017-10-30 16:42:53

GNUser
Member
Registered: 2017-03-16
Posts: 150

Re: GNU/Linux laptop as router, vpn router, or wifi repeater

Just for the fun of it, I went ahead and converted my spare laptop into a router. For the sake of completion and posterity, I want to document here the simplified approach that I took. It really is as easy as 1-2-3:

1. Uninstall or disable network-manager if your soon-to-be router has it (it gets in the way and is not necessary for a machine that gets internet via ethernet)

2. Make sure your /etc/network/interfaces has nothing but this:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

auto wlan0
iface wlan0 inet static
address 192.168.10.1
netmask 255.255.255.0
dns-nameservers 198.153.192.50

3. Run this script at startup:

#!/bin/bash

# Dependencies: iproute2 iptables dnsmasq hostapd haveged
# Usage: Set the variables below, then run this script as root/sudo

ssid=GNULinuxAP
password=DevuanRocks
ip_stem=192.168.10
dns_server=8.8.8.8
channel=11

main()
{
setup_nat
setup_dnsmasq
setup_hostapd
}

setup_nat()
{
echo 1 >/proc/sys/net/ipv4/conf/eth0/forwarding
echo 1 >/proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
}

setup_dnsmasq()
{
ifconfig wlan0 $ip_stem.1
echo "listen-address=$ip_stem.1
bind-dynamic
dhcp-range=$ip_stem.100,$ip_stem.200,255.255.255.0,24h
dhcp-option-force=option:router,$ip_stem.1
dhcp-option-force=option:dns-server,$dns_server
dhcp-option-force=option:mtu,1500
no-hosts" >/tmp/dnsmasq.conf
dnsmasq -C /tmp/dnsmasq.conf
}

setup_hostapd()
{
echo "beacon_int=100
ssid=$ssid
interface=wlan0
driver=nl80211
channel=$channel
ignore_broadcast_ssid=0
ap_isolate=0
hw_mode=g
wpa=3
wpa_passphrase=$password
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP" >/tmp/hostapd.conf 
hostapd /tmp/hostapd.conf
}

main

That's it!

As you can see, without network-manager and without the need to create a virtual hotspot interface (since eth0 is being used to get internet, wlan0 itself can be used as the hotspot interface), the whole thing becomes rather simple.

(BTW, I dug around my Netgear router running LibreCMC and found that both dnsmasq and hostapd were running--my guess is that a lot of linux-based routers follow exactly the above approach.)

Last edited by GNUser (2017-10-30 16:58:53)

Offline

Board footer