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.