Update ip-geolocation-ipinfodb.nse

IPinfoDB is no longer accepting new sign ups for the IPInfoDB API.Instead, IPinfoDB requests for signing up for IP2Location.io IP Geolocation API.Furthermore, the new service endpoint (api.ip2location.io) uses different JSON field names for location data (e.g., city_name instead of cityName).This change makes the script more resilient to external service changes, ensuring geolocation continues to work with both old and new API keys provided by the service migration.


The script is updated to implement a dual-endpoint fallback mechanism within the ipinfodb function:

Primary Attempt (New API): 
The script first attempts to query the IP2Location.io API (api.ip2location.io). This ensures compatibility for all newly registered API keys. It uses the new field names (city_name, region_name, country_name) to correctly parse the JSON response.


Fallback Attempt (Old API): 
If the primary request fails, the script falls back to querying the IPInfoDB API (api.ipinfodb.com). This preserves functionality for existing Nmap users who possess an old, still-active IPInfoDB API key, using the legacy field names (cityName, regionName, countryName).


Unified Error Handling: 
Error handling for invalid API keys is maintained and applied to both requests.

Updated Documentation
The script description has also been updated to include information about the new IP2Location.io service and its registration link.
This commit is contained in:
Umesh Joshi 2025-11-20 22:06:56 +05:45 committed by GitHub
parent a74125aef5
commit 4305308812
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,12 +8,12 @@ local table = require "table"
description = [[
Tries to identify the physical location of an IP address using the
IPInfoDB geolocation web service
(http://ipinfodb.com/ip_location_api.php).
IPInfoDB geolocation web service (http://ipinfodb.com/ip_location_api.php)
or its successor, IP2Location.io.
There is no limit on requests to this service. However, the API key
needs to be obtained through free registration for this service:
<code>http://ipinfodb.com/login.php</code>
<code>http://ipinfodb.com/login.php</code> or the new signup at
<code>https://www.ip2location.io/register</code>
]]
---
@ -65,30 +65,83 @@ hostrule = function(host)
return true
end
-- Function to make a request and attempt to parse the response
local function do_request(host_name, api_url, api_key, ip, city_key, region_key, country_key)
local response = http.get(host_name, 80, api_url..api_key.."&format=json".."&ip="..ip, {any_af=true})
local stat, loc = oops.raise(
"Unable to parse "..host_name.." response",
json.parse(response.body)
)
if not stat then
return stat, loc
end
if loc.statusMessage and loc.statusMessage == "Invalid API key." then
return false, oops.err(loc.statusMessage)
end
-- Check if we got location data (specific to the new IP2Location API response)
if loc.latitude and loc.longitude and loc[city_key] then
local output = geoip.Location:new()
output:set_latitude(loc.latitude)
output:set_longitude(loc.longitude)
output:set_city(loc[city_key])
output:set_region(loc[region_key])
output:set_country(loc[country_key])
geoip.add(ip, loc.latitude, loc.longitude)
return true, output
end
-- If no location data was found, return failure for this API attempt
return false, oops.err("No location data found in response from "..host_name)
end
-- No limit on requests. A free registration for an API key is a prerequisite
local ipinfodb = function(ip)
local api_key = stdnse.get_script_args(SCRIPT_NAME..".apikey")
local response = http.get("api.ipinfodb.com", 80, "/v3/ip-city/?key="..api_key.."&format=json".."&ip="..ip, {any_af=true})
local stat, loc = oops.raise(
"Unable to parse ipinfodb.com response",
json.parse(response.body))
if not stat then
return stat, loc
end
if loc.statusMessage and loc.statusMessage == "Invalid API key." then
return false, oops.err(loc.statusMessage)
-- 1. Try NEW IP2Location API (api.ip2location.io)
local stat, result = do_request(
"api.ip2location.io",
"/?key=",
api_key,
ip,
"city_name", -- New key name for City
"region_name", -- New key name for Region
"country_name" -- New key name for Country
)
-- If successful, return the result
if stat then
stdnse.debug1("Successfully retrieved geolocation from ip2location.io")
return stat, result
end
local output = geoip.Location:new()
output:set_latitude(loc.latitude)
output:set_longitude(loc.longitude)
output:set_city(loc.cityName)
output:set_region(loc.regionName)
output:set_country(loc.countryName)
stdnse.debug1("Failed to retrieve geolocation from ip2location.io, error: %s. Trying ipinfodb.com...", result)
geoip.add(ip, loc.latitude, loc.longitude)
-- 2. Fallback to OLD IPInfoDB API (api.ipinfodb.com)
stat, result = do_request(
"api.ipinfodb.com",
"/v3/ip-city/?key=",
api_key,
ip,
"cityName", -- Old key name for City
"regionName", -- Old key name for Region
"countryName" -- Old key name for Country
)
return true, output
-- If successful, return the result
if stat then
stdnse.debug1("Successfully retrieved geolocation from ipinfodb.com")
return stat, result
end
-- If both fail, return the last error
stdnse.debug1("Failed to retrieve geolocation from ipinfodb.com, error: %s.", result)
return stat, result
end
action = function(host,port)