1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
local nmap = require "nmap"
local stdnse = require "stdnse"
local table = require "table"
local coroutine = require "coroutine"
_ENV = stdnse.module("geoip", stdnse.seeall)
---
-- Consolidation of GeoIP functions.
--
-- @author "Mak Kolybabi <mak@kolybabi.com>"
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
--- Add a geolocation to the registry
-- @param ip The IP that was geolocated
-- @param lat The latitude in degrees
-- @param lon The longitude in degrees
add = function(ip, lat, lon)
local lat_n = tonumber(lat)
if not lat_n or lat_n < -90 or lat_n > 90 then
stdnse.debug1("Invalid latitude for %s: %s.", ip, lat)
return
end
local lon_n = tonumber(lon)
if not lat_n or lon_n < -180 or lon_n > 180 then
stdnse.debug1("Invalid longitude for %s: %s.", ip, lon)
return
end
if not nmap.registry.geoip then
nmap.registry.geoip = {}
end
nmap.registry.geoip[ip] = {
latitude = lat,
longitude = lon
}
end
--- Check if any coordinates have been stored in the registry
--@return True if any coordinates have been returned, false otherwise
empty = function()
return not nmap.registry.geoip
end
--- Retrieve the table of coordinates by IP
--@return A table of coordinates keyed by IP.
get_all_by_ip = function()
if empty() then
return nil
end
return nmap.registry.geoip
end
--- Retrieve a table of IPs by coordinate
--@return A table of IPs keyed by coordinate in <code>lat,lon</code> format
get_all_by_gps = function()
if empty() then
return nil
end
local t = {}
for ip, coords in pairs(get_all_by_ip()) do
local key = coords["latitude"] .. "," .. coords["longitude"]
if not t[key] then
t[key] = {}
end
table.insert(t[key], ip)
end
return t
end
-- Order in which field names will be shown in XML
local field_order = {
"latitude",
"longitude",
"city",
"region",
"country"
}
--- Location object
--
-- The object supports setting the following fields using functions like
-- <code>set_fieldname</code>:
-- * latitude
-- * longitude
-- * city
-- * region
-- * country
--
-- The location object is suitable for returning from a script, and will
-- produce appropriate string and structured XML output.
Location = {
new = function(self,o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end,
-- Ensure fields are put in the XML in proper order
__pairs = function(self)
local function iterator ()
for i, key in ipairs(field_order) do
coroutine.yield(key, self[key])
end
end
return coroutine.wrap(iterator)
end,
__tostring = function(self)
local out = {
("coordinates: %s, %s"):format(self.latitude, self.longitude)
}
-- if any of these are nil, it doesn't increase #place
local place = {self.city}
place[#place+1] = self.region
place[#place+1] = self.country
if #place > 0 then
out[#out+1] = ("location: %s"):format(table.concat(place, ", "))
end
return table.concat(out, "\n")
end,
}
-- Generate setter functions
for _, field in ipairs(field_order) do
Location["set_" .. field] = function(self, value)
self[field] = value
end
end
return _ENV;
|