lua-geolocate: add package for WLAN-based geolocation based on openwifi.su

Based-on-patch-by: Jan-Tarek Butt <tarek@ring0.de>
This commit is contained in:
Matthias Schiffer 2018-02-27 18:03:25 +01:00
parent 5c6476ea58
commit 53a659abf8
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
2 changed files with 110 additions and 0 deletions

View File

@ -0,0 +1,23 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=lua-geolocate
PKG_VERSION:=1
include $(INCLUDE_DIR)/package.mk
define Package/lua-geolocate
SECTION:=libs
CATEGORY:=Libraries
TITLE:=WLAN-based geolocation librari based on openwifi.su
DEPENDS:=+libubus-lua +libiwinfo-lua +lua-jsonc
endef
define Build/Compile
endef
define Package/lua-geolocate/install
$(INSTALL_DIR) $(1)/usr/lib/lua
$(INSTALL_DATA) src/geolocate.lua $(1)/usr/lib/lua/
endef
$(eval $(call BuildPackage,lua-geolocate))

View File

@ -0,0 +1,87 @@
local iwinfo = require 'iwinfo'
local json = require 'jsonc'
local ubus = require 'ubus'
local function canon_bssid(bssid)
return bssid:upper():gsub(':', '')
end
-- Iterates over all active WLAN interfaces
-- Returning true from the callback function will skip all remaining
-- interfaces of the same radio
local function foreach_radio(f)
local uconn = assert(ubus.connect(), 'failed to connect to ubus')
local status = uconn:call('network.wireless', 'status', {})
ubus.close(uconn)
for name, radio in pairs(status) do
for _, iface in ipairs(radio.interfaces) do
if f(iface.ifname) then
break
end
end
end
end
local function receive_json(request)
local f = assert(io.popen(string.format("exec wget -T 15 -q -O- '%s'", request)), 'failed to run wget')
local data = f:read('*a')
f:close()
return json.parse(data)
end
local function locate(blacklist)
local done_bssids = {}
for _, bssid in ipairs(blacklist or {}) do
done_bssids[canon_bssid(bssid)] = true
end
local found_bssids = {}
foreach_radio(function(ifname)
local iw = iwinfo[iwinfo.type(ifname)]
if not iw then
-- Skip other ifaces of this radio, as they
-- will have the same type
return true
end
local scanlist = iw.scanlist(ifname)
if not scanlist then
return false
end
for _, entry in ipairs(scanlist) do
local bssid = canon_bssid(entry.bssid)
if not done_bssids[bssid] then
table.insert(found_bssids, bssid)
done_bssids[bssid] = true
end
end
return true
end)
assert(#found_bssids >= 12, 'insufficient BSSIDs found')
local data = receive_json('http://openwifi.su/api/v1/bssids/' .. table.concat(found_bssids, ','))
assert(type(data) == 'table' and data.lon and data.lat, 'location not available')
return data
end
local geolocate = {}
function geolocate.locate(blacklist)
ok, result = pcall(locate, blacklist)
if ok then
return result
else
return nil, result
end
end
return geolocate