From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- scripts/traceroute-geolocation.nse | 187 +++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 scripts/traceroute-geolocation.nse (limited to 'scripts/traceroute-geolocation.nse') diff --git a/scripts/traceroute-geolocation.nse b/scripts/traceroute-geolocation.nse new file mode 100644 index 0000000..4224731 --- /dev/null +++ b/scripts/traceroute-geolocation.nse @@ -0,0 +1,187 @@ +local http = require "http" +local io = require "io" +local json = require "json" +local stdnse = require "stdnse" +local tab = require "tab" +local table = require "table" +local ipOps = require "ipOps" + +description = [[ +Lists the geographic locations of each hop in a traceroute and optionally +saves the results to a KML file, plottable on Google earth and maps. +]] + +--- +-- @usage +-- nmap --traceroute --script traceroute-geolocation +-- +-- @output +-- | traceroute-geolocation: +-- | hop RTT ADDRESS GEOLOCATION +-- | 1 ... +-- | 2 ... +-- | 3 ... +-- | 4 ... +-- | 5 16.76 e4-0.barleymow.stk.router.colt.net (194.68.128.104) 62,15 Sweden (Unknown) +-- | 6 48.61 te0-0-2-0-crs1.FRA.router.colt.net (212.74.65.49) 54,-2 United Kingdom (Unknown) +-- | 7 57.16 87.241.37.146 42,12 Italy (Unknown) +-- | 8 157.85 212.162.64.146 42,12 Italy (Unknown) +-- | 9 ... +-- |_ 10 ... +-- @xmloutput +-- +-- 1 +--
+-- +-- 2 +--
+-- +-- 3 +--
+-- +-- 4 +--
+-- +-- 5 +-- 16.76 +-- 194.68.128.104 +-- e4-0.barleymow.stk.router.colt.net +-- 62 +-- 15 +--
+-- +-- 6 +-- 48.61 +-- 212.74.65.49 +-- te0-0-2-0-crs1.FRA.router.colt.net +-- 54 +-- -2 +--
+-- +-- @args traceroute-geolocation.kmlfile full path and name of file to write KML +-- data to. The KML file can be used in Google earth or maps to plot the +-- traceroute data. +-- + + +author = "Patrik Karlsson" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"safe", "external", "discovery"} + +local arg_kmlfile = stdnse.get_script_args(SCRIPT_NAME .. ".kmlfile") + +hostrule = function(host) + if ( not(host.traceroute) ) then + return false + end + return true +end + +-- +-- GeoPlugin requires no API key and has no limitations on lookups +-- +local function geoLookup(ip, no_cache) + local output = stdnse.registry_get({SCRIPT_NAME, ip}) + if output then return output end + + local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip, {any_af=true}) + local stat, loc = json.parse(response.body) + + local get_value = function (d) + local t = type(d) + return (t == "string" or t == "number") and d or nil + end + + if not (stat + and get_value(loc.geoplugin_latitude) + and get_value(loc.geoplugin_longitude)) then + return nil + end + output = { + lat = loc.geoplugin_latitude, + lon = loc.geoplugin_longitude, + reg = get_value(loc.geoplugin_regionName) or "Unknown", + ctry = get_value(loc.geoplugin_countryName) or "Unknown" + } + if not no_cache then + stdnse.registry_add_table({SCRIPT_NAME}, ip, output) + end + return output +end + +local function createKMLFile(filename, coords) + local header = '\r\n' + local footer = '' + + local output = {} + for _, coord in ipairs(coords) do + output[#output+1] = ("%s,%s, 0.\r\n"):format(coord.lon, coord.lat) + end + + local f = io.open(filename, "w") + if ( not(f) ) then + return false, "Failed to create KML file" + end + f:write(header .. table.concat(output) .. footer) + f:close() + + return true +end + +-- Tables used to accumulate output. +local output_structured = {} +local output = tab.new(4) +local coordinates = {} + +local function output_hop(count, ip, name, rtt, geo) + if ip then + local label + if name then + label = ("%s (%s)"):format(name or "", ip) + else + label = ("%s"):format(ip) + end + if geo then + table.insert(output_structured, { hop = count, ip = ip, hostname = name, rtt = ("%.2f"):format(rtt), lat = geo.lat, lon = geo.lon }) + tab.addrow(output, count, ("%.2f"):format(rtt), label, ("%.3f,%.3f %s (%s)"):format(geo.lat, geo.lon, geo.ctry, geo.reg)) + table.insert(coordinates, { hop = count, lat = geo.lat, lon = geo.lon }) + else + table.insert(output_structured, { hop = count, ip = ip, hostname = name, rtt = ("%.2f"):format(rtt) }) + tab.addrow(output, count, ("%.2f"):format(rtt), label, ("%s,%s"):format("- ", "- ")) + end + else + table.insert(output_structured, { hop = count }) + tab.addrow(output, count, "...") + end +end + +action = function(host) + tab.addrow(output, "HOP", "RTT", "ADDRESS", "GEOLOCATION") + for count = 1, #host.traceroute do + local hop = host.traceroute[count] + -- avoid timedout hops, marked as empty entries + -- do not add the current scanned host.ip + if hop.ip then + local rtt = tonumber(hop.srtt) * 1000 + local geo + if not ipOps.isPrivate(hop.ip) then + -- be sure not to cache the target address, since it's not likely to be + -- a hop for something else. + geo = geoLookup(hop.ip, ipOps.compare_ip(hop.ip, "eq", host.ip) ) + end + output_hop(count, hop.ip, hop.name, rtt, geo) + else + output_hop(count) + end + end + + if (#output_structured > 0) then + output = tab.dump(output) + if ( arg_kmlfile ) then + if ( not(createKMLFile(arg_kmlfile, coordinates)) ) then + output = output .. ("\n\nERROR: Failed to write KML to file: %s"):format(arg_kmlfile) + end + end + return output_structured, stdnse.format_output(true, output) + end +end -- cgit v1.2.3