diff --git a/http/http.go b/http/http.go index 14d7d12..09d1fca 100644 --- a/http/http.go +++ b/http/http.go @@ -35,14 +35,19 @@ type Response struct { IP net.IP `json:"ip"` IPDecimal *big.Int `json:"ip_decimal"` Country string `json:"country,omitempty"` - CountryEU *bool `json:"country_eu,omitempty"` CountryISO string `json:"country_iso,omitempty"` + CountryEU *bool `json:"country_eu,omitempty"` + RegionName string `json:"region_name,omitempty"` + RegionCode string `json:"region_code,omitempty"` + MetroCode uint `json:"metro_code,omitempty"` + PostalCode string `json:"zip_code,omitempty"` City string `json:"city,omitempty"` - Hostname string `json:"hostname,omitempty"` Latitude float64 `json:"latitude,omitempty"` Longitude float64 `json:"longitude,omitempty"` + Timezone string `json:"time_zone,omitempty"` ASN string `json:"asn,omitempty"` ASNOrg string `json:"asn_org,omitempty"` + Hostname string `json:"hostname,omitempty"` UserAgent *useragent.UserAgent `json:"user_agent,omitempty"` } @@ -122,12 +127,17 @@ func (s *Server) newResponse(r *http.Request) (Response, error) { Country: country.Name, CountryISO: country.ISO, CountryEU: country.IsEU, + RegionName: city.RegionName, + RegionCode: city.RegionCode, + MetroCode: city.MetroCode, + PostalCode: city.PostalCode, City: city.Name, - Hostname: hostname, Latitude: city.Latitude, Longitude: city.Longitude, + Timezone: city.Timezone, ASN: autonomousSystemNumber, ASNOrg: asn.AutonomousSystemOrganization, + Hostname: hostname, UserAgent: userAgent, } s.cache.Set(ip, response) diff --git a/http/http_test.go b/http/http_test.go index 60bc048..ab3a789 100644 --- a/http/http_test.go +++ b/http/http_test.go @@ -21,7 +21,7 @@ func (t *testDb) Country(net.IP) (geo.Country, error) { } func (t *testDb) City(net.IP) (geo.City, error) { - return geo.City{Name: "Bornyasherk", Latitude: 63.416667, Longitude: 10.416667}, nil + return geo.City{Name: "Bornyasherk", RegionName: "North Elbonia", RegionCode: "1234", MetroCode: 1234, PostalCode: "1234", Latitude: 63.416667, Longitude: 10.416667, Timezone: "Europe/Bornyasherk"}, nil } func (t *testDb) ASN(net.IP) (geo.ASN, error) { @@ -134,7 +134,7 @@ func TestJSONHandlers(t *testing.T) { out string status int }{ - {s.URL, `{"ip":"127.0.0.1","ip_decimal":2130706433,"country":"Elbonia","country_eu":false,"country_iso":"EB","city":"Bornyasherk","hostname":"localhost","latitude":63.416667,"longitude":10.416667,"asn":"AS59795","asn_org":"Hosting4Real","user_agent":{"product":"curl","version":"7.2.6.0","raw_value":"curl/7.2.6.0"}}`, 200}, + {s.URL, `{"ip":"127.0.0.1","ip_decimal":2130706433,"country":"Elbonia","country_iso":"EB","country_eu":false,"region_name":"North Elbonia","region_code":"1234","metro_code":1234,"zip_code":"1234","city":"Bornyasherk","latitude":63.416667,"longitude":10.416667,"time_zone":"Europe/Bornyasherk","asn":"AS59795","asn_org":"Hosting4Real","hostname":"localhost","user_agent":{"product":"curl","version":"7.2.6.0","raw_value":"curl/7.2.6.0"}}`, 200}, {s.URL + "/port/foo", `{"error":"invalid port: foo"}`, 400}, {s.URL + "/port/0", `{"error":"invalid port: 0"}`, 400}, {s.URL + "/port/65537", `{"error":"invalid port: 65537"}`, 400}, diff --git a/iputil/geo/geo.go b/iputil/geo/geo.go index 4543d3d..4b73729 100644 --- a/iputil/geo/geo.go +++ b/iputil/geo/geo.go @@ -21,9 +21,14 @@ type Country struct { } type City struct { - Name string - Latitude float64 - Longitude float64 + Name string + Latitude float64 + Longitude float64 + PostalCode string + Timezone string + MetroCode uint + RegionName string + RegionCode string } type ASN struct { @@ -101,12 +106,31 @@ func (g *geoip) City(ip net.IP) (City, error) { if c, exists := record.City.Names["en"]; exists { city.Name = c } + if len(record.Subdivisions) > 0 { + if c, exists := record.Subdivisions[0].Names["en"]; exists { + city.RegionName = c + } + if record.Subdivisions[0].IsoCode != "" { + city.RegionCode = record.Subdivisions[0].IsoCode + } + } if !math.IsNaN(record.Location.Latitude) { city.Latitude = record.Location.Latitude } if !math.IsNaN(record.Location.Longitude) { city.Longitude = record.Location.Longitude } + // Metro code is US Only https://maxmind.github.io/GeoIP2-dotnet/doc/v2.7.1/html/P_MaxMind_GeoIP2_Model_Location_MetroCode.htm + if record.Location.MetroCode > 0 && record.Country.IsoCode == "US" { + city.MetroCode = record.Location.MetroCode + } + if record.Postal.Code != "" { + city.PostalCode = record.Postal.Code + } + if record.Location.TimeZone != "" { + city.Timezone = record.Location.TimeZone + } + return city, nil }