Geo geraten aus Nachbar WIFI Accesspoints - Beispielscript

wollte das schon lange mal schreiben, ist fern von Perfekt.
Skript zum herausfinden des Groben Standortes Anhand benachbarter WIFI Accesspoints

(funktioniert mit busybox wget so auch nicht auf den Routern selbt, u.a. wegen fehlender https unterstützung, dies hier muss also mit ssh zugang auf einen Knoten benutzt werden. desweiteren benutzt es ALLE gefundenen Nodes und benutzt NICHT die Empfangsstärke)

start [Wiki] (eventuelle Nacharbeiten NUR dort!)

#!/bin/bash
#
# simple code to get geo out of mix of macs

if [ $# != 1 ]; then
echo "usage of geoguess: $0 <node_ip>"
exit 1
fi

# debuglevel
debug=false

# get key out of keyfile
apikey=$(cat geoapikey)
# if there is no API Keyfile use test instead (limited!)
: ${apikey:=test}

# first get some macs from node, and ignore hostkeychecking
macs=$(ssh -lroot $1 -o LogLevel=quiet -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "iwinfo phy0 scan |grep -o -E [0-9A-F]{2}[:][0-9A-F]{2}[:][0-9A-F]{2}[:][0-9A-F]{2}[:][0-9A-F]{2}[:][0-9A-F]{2}")

# make nice POST-string snippet out of it
string=$(echo -n $(for mac in $macs; do echo -n "{\"macAddress\": \"$mac\"},"; done))
string=$(echo ${string%?})

# make POST Wget request to mozilla 
# https://mozilla.github.io/ichnaea/api/geolocate.html
# basicly something like:
# wget -O geodata https://location.services.mozilla.com/v1/geolocate?key=test --post-data='{ "wifiAccessPoints": [{"macAddress": "00:00:11:22:33:44"},{"macAddress": "00:00:55:66:77:88"}]}' 
wget -q -O geodata https://location.services.mozilla.com/v1/geolocate?key=$apikey --post-data="{ \"wifiAccessPoints\": [$(echo -n $string)]}"

# sample output is something like
# {"location": {"lat": 48.0006632, "lng": 7.8236051}, "accuracy": 960.0275115}
# cat geodata
lat=$(cat geodata |grep -o [4-5][0-9].[0-9]* |head -n1)
lon=$(cat geodata |grep -o " [5-9].[0-9]*" |grep -o "[6-9].[0-9]*" |head -n1)
echo "you may try http://www.openstreetmap.org/?mlat=$lat&mlon=$lon#map=16/$lat/$lon&layers=N"
echo "or use this on router:"
echo "ssh -lroot $1 \"uci set gluon-node-info.@location[0].latitude=$lat ; uci set gluon-node-info.@location[0].longitude=$lon; uci set gluon-node-info.@location[0].altitude=200; uci set gluon-node-info.@location[0].share_location=1 ; uci commit gluon-node-info\""

if [ $debug = true ]; then
        echo "#### debugfoo"
        echo "request is : wget -q -O geodata https://location.services.mozilla.com/v1/geolocate?key=$apikey --post-data=\"{ \\\"wifiAccessPoints\\\": [$(echo -n $string)]}\""
        echo "api key is : $apikey"
        echo "macs is : $macs"
        echo "string becomes : $string"
        echo "return is : $(cat geodata)"
fi
3 Likes

@DSchmidtberg hatte sowas mal mit den Google Location Services ausprobiert (kein Script, nur manuell) und auch probiert, nur die MAC des AP selber hinzuschicken, was schon erschreckend genau war.

Ich wollte das mal zwecks Knoten uns Subdomänen schubsen nutzen. Leider wollte der Service immer mindestens zwei MAC Adressen haben. Daher war es für mich nicht brauchbar. Oder habe ich etwas falsch/anders gemacht?

@descilla , es werden immer mind. 2 mac benötigt - das ist eine Art Sicherungsvorkehrung, so behauptet. Du sollst nicht nach MAC einzeln abfragen dürfen, das zudem relativ ungenau.
Das skript oben, nimmt alle Accesspoint MAC aus der Umgebung, können auch mal 10++ sein. und generiert daraus die Anfrage.
Im Prinzip könnte man daraus ein Paket bauen : gluon-guess-geo
was im Betrieb aus den nahegelegenen AP die Geo rausholt.

1 Like

Bei Google geht auch eine

hast du mal so eine Beispiel Anfrage an die API? und verlangt google https?

Das muss @DSchmidtberg sagen…

hier kann man übrigends nachsehen wie gut die sample qualität in bestimmten berreichen ist - heisst wieviele messpunkte vorhanden sind
https://location.services.mozilla.com/map#13/47.9815/7.8054

das nur weil es regionen gibt wo das schlicht nicht so gute ergebnisse liefern wird, wie in Liechtenstein z.B.

2 Likes

Ja, das habe ich mir auch gedacht. Ich hatte halt die Motivation die Knoten „von außen“ zu verorten. Habe dann einfach mal random-mäßig MACs von anderen Knoten in unserem Netzwerk mit in die Query geworfen, in der Hoffnung, dass wenn ich das mit ausreichend vielen mache ich hinterher die Lokation des einzelnen Knoten herausrechnen kann (1-2km Genauigkeit würden mir ja schon reichen). Leider müssen die Knoten wohl recht nah beieinander liegen, damit die API eine Ausgabe ausspuckt. Wohl auch eine Art Sicherheitsvorkehrung.

Ja, die Schnittstelle, die auf maps.google.de die Geo-Position bestimmt antwortet wohl auch bei nur einer MAC-Adresse. Leider wird jedoch (so ist zumindest meine Annahme) auch die „Geo-Position“ der IP Adresse, von der aus man die Anfrage stellt mit in die Positionsbestimmung verschnitten. Zumindest bekam ich von unterschiedlichen Internet-Zugängen aus mit der selbem WiFi-MAC Adresse unterschiedliche Koordinaten zurück, mit einer Differenz von > 60 Km.

Ja, das hatte ich gestern Abend nicht direkt erkannt, so macht das Script jetzt auch wirklich Sinn. :+1: Hatte irgendwie im Kopf, dass man es via SSH draufbügeln muss.

Naja ich werde mal meine Community befragen, was die darüber denken. Ich kann mir gut vorstellen, dass dort einige Stimmen Datenschutz/Privatsphäre Bedenken anmelden.

1 Like

Hatte am Anfang die MAC des AP genommen + die Mesh-MAC wenn dann noch der IP-Fallback ausgeschaltet wird verweigert die API eine Antwort.

Ein Script was beim Routerstart ein Scan macht und in /tmp ein json hinterlegt reicht doch aus. Eine einfache Abfrage per http auf dem Router könnte es dann allen zur Verfügung stellen.

Davon abgesehen, dass es ein interessantes Vorhaben ist einen AP zu verorten: Es gibt sicherlich einen Grund warum ein Knotenaufsteller explizit den Standort seines Knotens nicht eingetragen hat; entweder aus Unvermögen die geographischen Koordinaten herauszufinden oder aus Gründen. Inwiefern leisten wir Freifunker diesem Knotenaufsteller einen Dienst die fehlenden Koordinaten durch Messung und Extrapolation ohne sein Einverständnis „nach zu liefern“? Ist das ein Wunsch des Knotenaufstelles keine Koordinaten anzugeben oder sein Unvermögen? Sollen wir die geratenen Koordinaten verarbeiten und veröffentlichen? Ist das geratene Ergebnis wirklich valide? Sollen wir Zeit und Energie für das Raten aufwenden?

2 Likes

@phip: bei sagen wir 7-15 Accesspoints in deiner Nähe - alle Knoten die ich ausprobiert habe und wo ich dann die xx Accesspoints in die Api geworfen habe, ich lag nie mehr als 30 Meter daneben.

wenn man das als Feature bauen will - dann wäre das, ja rate meine Geo -
das ist für „faule“ wie aber auch für Knoten die Mobil sind interessant. Ich hab zum Beispiel so ein „event“ Bike … und da is nen Freifunkknoten dran. Warum soll das nicht valide geo auspucken?

das man hinterrücks die abwahl von GEO umgeht - oder pauschal ALLE Knoten guess-geo sammelt - da war nie die rede von.
Wenn man als Comunity aber eh einen geo zwang hat - dann spricht nix gegen die Validierung. Muss jede Gruppe selber wissen.

@DSchmidtberg , du sprichst in Rätseln … Die Routermac selber bringt doch wenig bei der Abfrage - die der anderen Accespoints um dich herum machen die Magic…

im Grunde ist das Skript eine Spielerei von mir gewesen, just because i can - und damit andere auch freude daran haben - hier geteilt.
Grundidee entstand als uns in einem Jugendzentrum ein Knoten geklaut wurde, der nie wieder aufgetaucht ist.

Aber um das nochmal klar zu sagen: obiges Skript kann so NICHT auf einem Router laufen, da es

  1. den testkey benutzt (das klappt nur wenige male pro IP)
  2. die Router KEIN HTTPS WGET können für die API
  3. das busybox wget auf den Routern (glaube) kein POST-DATA kennt
  4. die Daten in dem Skript nicht verarbeitet werden.
    Das Skript holt von einem Router die MAC der benachbarten Accesspoints und macht dann das wget lokal von eurem Computer/Server. Die Daten könnte man benutzen um das wiederum in den Router zu hacken.

hab hier mal schnell was in bash gehacked als proof of concept, was die geo.json erzeugt welche man dann absenden kann
evtl. bau ich daraus noch ein packet, muss aber noch überlegen wie am besten das zu gestalten wäre

#!/bin/sh
echo "Content-Type: application/json"
echo ""

echo "{ \"wifiAccessPoints\": ["
{
        for iface in $(iw list | grep -o -E phy[01]); do
                iwinfo $iface scan | \
                        grep -o -E '(([0-9A-F]{2}:){5}[0-9A-F]{2}|Signal: *-[1-9][0-9]*)' | \
                        sed "s/Signal: //" | awk '/([0-9A-F]{2}:){5}[0-9A-F]{2}/{if (match($0, "([0-9A-F]{2}:){5}[0-9A-F]{2}"))printf "{\"macAddress\":\"%s\",", $0}{if (match($0, "-[1-9][0-9]*"))printf "\"signalStrength\": %s},\n", $0}'
        done
} | sed '$ s/.$//'
echo "],\"considerIp\": \"false\"}"

nachdem wir auf den Routern ja weder https noch einen API key haben würde ich evtl. hergehen und die APs einfach nur die .json erzeugen lassen, damit man dann z.B. am alfred master die Position berechnen kann (für alle die die keine Position eingetragen haben)

3 Likes

ich hab hier ein script gebaut das funktioniert …
es benutzt quasi ein relay auf dem ein php sript läuft

HTTPS ist auch auf 4MB Routern möglich, indem man die TLS-Library (idealerweise mbedTLS und nicht openssl, weil viel kleiner) im RAM (/tmp) ablegt. Wir haben das examplarisch auch schonmal gebaut um Mozilla Location Services zu nutzen.

Infos: Freifunk:Mobiler Hotspot – Hacksaar Wiki

Ansonsten wollten wir das ganze durch einen einfachen reverse-proxy auch ohne https möglich machen, dann kann man das theoretisch auch mit der Firmware ausliefern. Ich weiß, dass andere Communities an sowas bereits gearbeitet haben…

@larma … das ist genau was dieses verlinkte script/Anlietung macht … via proxy geocoordinaten vom Mozilla projekt holen.
danke für den Hinweis mit dem Paket im RAM, wobei ich das so verstehe das das doch „richtig“ installiert wird
# opkg install /tmp/mlsc_1_ar71xx.15.05.ipk - ihr umgeht bestenfalls dependencys auf andere (große) Pakete mit dem direkten install.
edit: mein irrtum

Ich glaube du hast diese Zeile unter zwischen Punkt 1 und 2 überlesen.

Wenn weniger als 1M Speicherplatz vorhanden ist, springe zu Schritt 3

Das Skript in Schritt 3 lädt in den RAM wenn man das Paket nicht vorab installiert hat.

Dein Skript habe ich gesehen, alles was mit PHP ist, ist aber deutlich unschöner als mit nginx/apache einen reverse proxy einzurichten. Der system-call ist auch alles andere als schön - php kann auch selber http, da muss man kein wget für starten…

2 Likes