OpenWrt Forum Archive

Topic: MagicConnect - connect to open APs

The content of this topic has been archived on 15 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

Taking inspiration from AAP, I've written a shell/awk script that connects to any open AP.  The original discussion is here:

https://forum.openwrt.org/viewtopic.php?id=21636

My solution consists of two scripts,  app2 and scan2.awk.  They should "just work".  You can blacklist an AP in /etc/aap.d/blacklist and whitelist in /etc/aap.d/whitelist.

The format of the blacklist is either a MAC address (bssid) unquoted, or a quoted SSID.  So for example:

"EvilAP"
11:22:33:44:55:66

would not connect to any AP with the SSID of EvilAP, and any AP with the bssid of 11:22:33:44:55:66

The whitelist is similar except that each SSID / BSSID is followed by a key.

"GoodAP" "MySuperSecret"
11:22:33:44:55:66 "MyOtherSuperSecret"

You really don't need to whitelist open APs with no encryption; the script will just connect

To use this, you have to configure your openwrt box as a client, not as an AP!!!!

The main script is aap2:

#!/bin/ash

magic="1NkIA4jnx2K9w"

aap_connect () {
    echo 1
    mkdir -p /tmp/cell
    rm -f /tmp/cell/*
    
    iwlist $ifn scan > /tmp/scan.out

    awk 'BEGIN{IGNORECASE=1}/^ *cell [0-9]/{close("/tmp/cell/0"f);f++}{print $0 > "/tmp/cell/0"f}' /tmp/scan.out
        echo "trying to connect 2 " $if $dev $ifn

    for ap in /tmp/cell/0[0-9]* ; do
        echo "Trying cell $ap"
        grep -i essid $ap
#        wifi down $2
            if [ -e /proc/`cat /var/run/$3.pid` ] ; then kill -9 `cat /var/run/$3.pid` ; fi
            echo 0 > /proc/diag/led/power
            if [ -f /tmp/ap ] ; then rm /tmp/ap ; fi
            if [ -f /tmp/script ] ; then rm /tmp/script ; fi
            sleep 3

        cat $ap | /usr/sbin/scan2.awk -v ifd=$if -v dev=$dev -v ifn=$ifn
        if [ -e /tmp/ap ] ; then cat /tmp/ap ; fi
    
        if [ -f /tmp/script ] ; then
            . /tmp/script
            echo restarting $2
            wifi up $2
            sleep 15
            ps | grep wlan0
            aap_test
            if [ $ret -eq 0 ] ; then
                echo 1 > /proc/diag/led/power
                conn=1
                echo test succeeded
                return
            else
                # try to deliver our payload via ping
                echo test failed
                aap_ping
            fi
        fi
        done
    conn=0
    }
    
aap_maintain() {
    ret=0
    while [ $ret -eq 0 ] ; do
        sleep 15
        echo checking connection
        aap_test
        done
    }
    
aap_test() {
    wget -O - http://www.gooddomain.com/magic.txt > /tmp/magic
    ret=$?
    if [ $ret -eq 1 ]; then return ; fi
    if [ `grep -c $magic /tmp/magic` -eq 1 ] ; then
        ret=0
        echo test succeeded - connection up
        return
    fi
    ret=0
    }
    
aap_ping() {
    # placeholder for the ping payload routine
    # eventually craft a ping that can carry a small payload, like GPS coordinates
    # a bit complicated by the fact that busybox ping doesn't have the -p option
    ping -c 3 -q www.google.com
    }
    
aap_payload() {
    echo payload goes here
    # placeholder for whatever we want to do on connection
    # like deliver email, send GPS location coordinates, etc
    }
    
    
while [ 1 ] ; do
    # do this every time in case our user hotplugged an if
    wif=`uci show wireless | grep "mode=sta" | cut -f2 -d.`
    for if in $wif ; do
        echo "Using $if"
            dev=`uci show wireless.$if.device | cut -f2 -d=`
                net=`uci show wireless.$if.network | cut -f2 -d=`
                ifn=`uci -P /var/state show wireless.$if.ifname | cut -f2 -d=`
                echo "trying to connect" $if $dev $ifn
        aap_connect $if $dev $ifn
        if [ $conn -eq 1 ] ; then
            aap_payload
            aap_maintain
            fi
        sleep 15
        done
    done

And the helper script is scan2.awk:

#!/usr/bin/awk -f

BEGIN{
    IGNORECASE=1
    }

/[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]/ {
    m=match($0,/[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]:[0-9,a-f][0-9,a-f]/);
    if (RSTART > 0) {
        bssid=substr($0,m,RLENGTH);
        next;
        }
    }
    
/^ *ESSID/ {
    m=match($0,"\".*\"");
    if (RSTART > 0) essid=substr($0,m+1,RLENGTH-2);
    next;
    }
    
/Channel.+[0-9]/ {
    m=match($0,"Channel");
    if (RSTART > 0) {
        s=substr($0,m);
        n=match(s,/[0-9]+/);
        channel=substr(s,n,RLENGTH)}
    }

/^ *Quality/ {
    m=match($0,/[0-9]+\/[0-9]+/);
    if (RSTART > 0) {
        s=substr($0,m);
            split(s,t,"/");
            if (t[2] > 0) {quality=t[1]*100/t[2];}
            else quality = 50;
            next;
            }
    }

/^ *Encryption Key/ {
    m=match($0, /on$/); 
    if (RSTART > 0) encr=1;
    next;
    }

/^ *IE. *IEEE/ {
    m=match($0, /wpa/);
        if (RSTART > 0) psk2=1;
        next;
        }
        
/^ *IE. *WPA/ {
    m=match($0, /wpa/);
    if (RSTART > 0) psk=1;
    next;
    }

END {
    if(psk2 == 1) crypt = "psk2";
    else if (psk == 1) crypt ="psk";
    else if (encr == 1) crypt = "wep";
    else crypt = "none";
    
    # first we see if we're in blacklist
    while ( ( getline < "/etc/aap.d/blacklist" ) > 0) {
        if (bssid == $0) exit;
        match($0, ("^\"" essid "\"") );
        if (RSTART > 0) exit;
        }
    
    # now we get key if we're encrypted
    if ( crypt != "none" ) {
        rkey = "";
        while ( ( getline < "/etc/aap.d/whitelist" ) > 0 ) {
                if ($1 == bssid) {
                    m=match($0,"\".*\"");
                    if (RSTART > 0) rkey=substr($0,m+1,RLENGTH-2);
                    }
                else {
                    match($0, ("^\"" essid "\"") );
                    if (RSTART > 0) {
                        r=RSTART+RLENGTH+1;
                        s=substr($0, r);
                        m=match(s,"\".*\"");
                        if (RSTART > 0) rkey=substr(s,m+1,RLENGTH-2);
                        }
                    }            
                }
            if ( rkey == "" ) {
                print essid " is encrypted and key not in whitelist";
                exit;
                }
            }
            
    print quality "\n" bssid "\n" essid "\n" channel "\n" crypt "\n" rkey > "/tmp/ap";
    
    print "uci set wireless." dev ".channel=" channel > "/tmp/script";
    print "uci set wireless." ifd ".ssid=" essid >> "/tmp/script";
    print "uci set wireless." ifd ".bssid=" bssid >> "/tmp/script";
    if (crypt == "none") {
        print "uci set wireless." ifd ".encryption=none" >> "/tmp/script";
        }
    else {
        print "uci set wireless." ifd ".key=" rkey >> "/tmp/script";
        print "uci set wireless." ifd ".encryption=" crypt >> "/tmp/script";
        }
    }

The script relies on the subroutine aap_test.  Right now my website has a "magic cookie" that is compared to the magic in the script.  If the cookie can be downloaded and it matches, we assume the connection is good.  The test is repeated every 15 seconds.  You probably want to modify this for your needs.

TODO:

This really needs a "user override" either via a gpio button or a web interface.  I would welcome any help in crafting a page for controlling this.

As stated on the other thread, I'm glad you decided to post the code! Hopefully I will be able to test it during this week on my setup, and get back to you with any comments that might be useful. Thanks again!

Hi cptdondo! Great work!
I run your script on my AUSU wl-500gp, it works perfect on the command line.
but I want autorun it when the AP booting up.
and how to save all of output information to file, so I can use tail -f xxx to review anytime?  Thanks.

start it in /etc/inittab and redirect to a log file

look up the syntax of busybox inittab

You want something like this added to the end of your inittab:

::respawn:/usr/bin/aap2 > /tmp/aap.log

Thanks cptdondo.
It's working.....
haha, I have an always online busybox.

Hi captdondo, I experience another problem.
for my laptop can access my busybox, I set second SSID on the busybox.
If I running the aap2 script on command line, my second SSID(tick) is working, I can connect to my busybox.
But when I use inittab to auto run aap2, the second ssid can’t work.
Could you help me analyze the reason?

The following is my configuration:
root@OpenWrt:/etc# cat /etc/inittab
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K stop
tts/0::askfirst:/bin/ash --login
ttyS0::askfirst:/bin/ash --login
tty1::askfirst:/bin/ash --login
::respawn:/etc/config/aap2/aap2 > /tmp/aap.log


root@OpenWrt:/etc# cat /etc/config/wireless
config 'wifi-device' 'wl0'
        option 'type' 'broadcom'
        option 'txpower' '100'
        option 'disabled' '0'
        option 'channel' '9'

config 'wifi-iface'
        option 'device' 'wl0'
        option 'mode' 'sta'
        option 'network' 'wan'
        option 'ssid' 'TP-LINK-A'
        option 'encryption' 'wep'
        option 'key' 'abcd123456'

config 'wifi-iface'
        option 'device' 'wl0'
        option 'ssid' 'tick'
        option 'network' 'lan'
        option 'mode' 'ap'
        option 'encryption' 'none'

root@OpenWrt:/etc#

Hmmmm... I've never tried to test this with a single AP acting as both sta and ap.  I'm afraid you're in new territory here.  I wrote aap2 to handle multiple wifi interfaces in STA mode.  At the time I was not aware you could use a single AP to act as both AP and STA.

I run 2 separate access points; one in STA mode and one in AP mode.  I've never tried to combine the two although in theory you can.  Perhaps someone with more experience in this sort of set up can help.  I'm not willing to break my setup to help....  :-(

thanks for your response.
the key point puzzle me: while a single AP acting as both sta and ap modes, the  both modes are working fine if I run aap2 on the command.
I don't know the differentia between runing script on the inittab and runing scaript on the command.

the inittab program is running before the progresses of /etc/rc.d/Sxx.
there has a /etc/rc.d/S40network progress, it is in charge of wireless initialization.
I made a /etc/rc.d/S98app2 progress to auto run app2 . it is all working fine....  :-)

I've got this running awesome in a station/ap combo. I haven't figured it out yet, but if the script stays running I cannot browse the internet. If I kill it then it's all fine. I made a startup script that simply had aap2 starting on boot as explained above. I later edited the aap2 file so that it would kill itself once it got the magic cookie from my website. I haven't tried it yet, but is it possible to make this connect to hidden ssids?

(Last edited by foxtroop11 on 3 Apr 2010, 15:45)

I think in the version here there is a aap_test routine.  It may not work very well; the latest code uses openvpn to estblish the connection is up.  Once it does that, it works well.  See if you can trace what's happening in aap_test or aap_maintain; those should be keeping the connection up.

If there are any php developers out there, I'd love to work with you to develop a web interface for this.  Present all of the APs you see, and then be able to select the one you want.

Alas, I'm not much of a programmer anymore - too many other things to do.  Mostly I'm at a point in my life when I'm a bit burned out on programming and getting back into working with my hands and building things.

I tried to install AAP from the forums here but couldn't find the link to actually download it. So I tried cptdondo's scripts.
I have a WRT54GL 1.1 with the latest backfire 10 with 2.6 kernel.

It doesn't seem to work. I get this:

Trying cell /tmp/cell/03
                    ESSID:"wireless"
cat: can't open '/var/run/.pid': No such file or directory
cat: can't open '/var/run/.pid': No such file or directory
ash: you need to specify whom to kill
74.2857
00:E0:5D:FA:91:8C
wireless
11
none

restarting radio0
PHY for wifi device radio0 not found
PHY for wifi device radio0 not found
^C
root@OpenWrt:/overlay#

('wireless' is open)

The can't open messages are normal - on startup the .pid files don't exist and I got lazy and figured those are harmless.

The "PHY for wifi device radio0 not found" is not normal.... Does your wireless work?  Can you get it started with the normal openwrt process?

Yes it seems to work as an AP.
I did a reset to defaults. And to get the scanning to work I made the wifi interface part of wan instead of lan. Now I get this:

restarting radio0
Error for wireless request "Set Power Management" (8B2C) :
    SET failed on device wlan0 ; Operation not supported.
ioctl[SIOCSIWENCODEEXT]: Invalid argument
ioctl[SIOCSIWENCODEEXT]: Invalid argument

I guess that it won't go properly into client mode.
And now 'wifi detect' gives an empty result.
Searched for this and didn't find anything relevant on the forums. I guess I'll try for a couple of days  to make it work and if I can't figure it out, I'll go back to dd-wrt with autoap.

michaelmet wrote:

PHY for wifi device radio0 not found
PHY for wifi device radio0 not found
('wireless' is open)

Try changing radio0 for wlan0 in wireless config

That won't help. The error occurs when the mac address in /e/c/wireless does not match the phy.

Forget the phy for wifi error.
Ok... I just installed the same firmware on Asus wl-500gp. Same thing. Client mode doesn't seem to work. On the wiki for this device it says that on k26 ap mode shouldn't work but client would. It's quite the opposite.

root@OpenWrt:/overlay# cat /etc/config/wireless

config 'wifi-device' 'radio0'
        option 'type' 'mac80211'
        option 'channel' '5'
        option 'macaddr' 'mymac...'
        option 'hwmode' '11g'
        option 'disabled' '0'

config 'wifi-iface'
        option 'device' 'radio0'
        option 'network' 'lan'
        option 'ssid' 'OpenWrt'
        option 'encryption' 'none'
        option 'mode' 'sta'

root@OpenWrt:/overlay# iwlist scan
lo        Interface doesn't support scanning.

eth0      Interface doesn't support scanning.

eth1      Interface doesn't support scanning.

eth0.0    Interface doesn't support scanning.

eth0.1    Interface doesn't support scanning.

br-lan    Interface doesn't support scanning.

wlan0     Interface doesn't support scanning : Device or resource busy

root@OpenWrt:/overlay# wifi down
root@OpenWrt:/overlay# wifi
Error for wireless request "Set Power Management" (8B2C) :
    SET failed on device wlan0 ; Operation not supported.
ioctl[SIOCSIWENCODEEXT]: Invalid argument
ioctl[SIOCSIWENCODEEXT]: Invalid argument

I went through this at one point....  I think for scanning to work, the unit has to be associated.  There's some sort of brokenness going on that I have not been able to figure out; it works with the b43 driver but some combinations produce that error.  Try scanning once associated.  If it works, and you have the time, document and file a bug.

A new update of Magic Connect is available - it' s now a single awk script and totally UCI based.

Available at

http://www.seiner.com/openwrt/magicconnect.tar.bz2

upack, move ssid to /etc/config and aap to /usr/sbin

Configure /etc/config/ssid as you wish.  The keepalive is a web-based magic cookie that will tell the script the connection is working.  Pick something small so you don't chew up bandwidth.  A zero length text file will work.

You will have to change your wifi AP to sta mode.

config 'wifi-iface'
    option 'device' 'radio0'
    option 'network' 'wifi'
    option 'mode' 'sta'
....

MagicConnect will automagically connect to any whitelisted or open AP.  APs using encryption must be whitelisted with the key.  See the ssid file for examples.

This should work on any recent OpenWRT setup regardless of hardware as long as iwlist scan provides encryption info.

I notice there's a 404 on cptdondo's web site for the UCI based MagicConnect.  Any chance someone has that and we can re-post it somewhere? I'd be happy to host.

I can't download the magicconnect package either...anyone have a mirror?

The discussion might have continued from here.