echoip/iputil/geo/geo.go

158 lines
3.3 KiB
Go
Raw Normal View History

2018-08-14 21:00:46 +02:00
package geo
2018-02-10 14:35:12 +01:00
import (
2018-06-15 09:29:13 +02:00
"math"
2018-08-27 21:39:49 +02:00
"net"
2018-02-10 14:35:12 +01:00
geoip2 "github.com/oschwald/geoip2-golang"
)
2018-08-14 21:00:46 +02:00
type Reader interface {
2018-02-10 14:35:12 +01:00
Country(net.IP) (Country, error)
2018-06-15 09:29:13 +02:00
City(net.IP) (City, error)
2019-07-05 15:01:45 +02:00
ASN(net.IP) (ASN, error)
2018-02-10 17:52:55 +01:00
IsEmpty() bool
2018-02-10 14:35:12 +01:00
}
type Country struct {
2018-08-27 21:44:00 +02:00
Name string
ISO string
IsEU *bool
2018-06-15 09:29:13 +02:00
}
type City struct {
2020-05-10 14:23:50 +02:00
Name string
Latitude float64
Longitude float64
PostalCode string
Timezone string
MetroCode uint
RegionName string
RegionCode string
2018-02-10 14:35:12 +01:00
}
2019-07-05 15:01:45 +02:00
type ASN struct {
AutonomousSystemNumber uint
AutonomousSystemOrganization string
}
2018-02-10 14:35:12 +01:00
type geoip struct {
country *geoip2.Reader
city *geoip2.Reader
2019-07-05 15:01:45 +02:00
asn *geoip2.Reader
2018-02-10 14:35:12 +01:00
}
2019-07-05 15:01:45 +02:00
func Open(countryDB, cityDB string, asnDB string) (Reader, error) {
var country, city, asn *geoip2.Reader
2018-02-10 14:35:12 +01:00
if countryDB != "" {
r, err := geoip2.Open(countryDB)
if err != nil {
return nil, err
}
country = r
}
if cityDB != "" {
r, err := geoip2.Open(cityDB)
if err != nil {
return nil, err
}
city = r
}
2019-07-05 15:01:45 +02:00
if asnDB != "" {
r, err := geoip2.Open(asnDB)
if err != nil {
return nil, err
}
asn = r
}
return &geoip{country: country, city: city, asn: asn}, nil
2018-02-10 14:35:12 +01:00
}
func (g *geoip) Country(ip net.IP) (Country, error) {
country := Country{}
if g.country == nil {
return country, nil
}
record, err := g.country.Country(ip)
if err != nil {
return country, err
}
if c, exists := record.Country.Names["en"]; exists {
country.Name = c
}
if c, exists := record.RegisteredCountry.Names["en"]; exists && country.Name == "" {
country.Name = c
}
if record.Country.IsoCode != "" {
country.ISO = record.Country.IsoCode
}
if record.RegisteredCountry.IsoCode != "" && country.ISO == "" {
country.ISO = record.RegisteredCountry.IsoCode
}
isEU := record.Country.IsInEuropeanUnion || record.RegisteredCountry.IsInEuropeanUnion
country.IsEU = &isEU
2018-02-10 14:35:12 +01:00
return country, nil
}
2018-06-15 09:29:13 +02:00
func (g *geoip) City(ip net.IP) (City, error) {
city := City{}
2018-02-10 14:35:12 +01:00
if g.city == nil {
2018-06-15 09:29:13 +02:00
return city, nil
2018-02-10 14:35:12 +01:00
}
record, err := g.city.City(ip)
if err != nil {
2018-06-15 09:29:13 +02:00
return city, err
2018-02-10 14:35:12 +01:00
}
2018-06-15 09:29:13 +02:00
if c, exists := record.City.Names["en"]; exists {
city.Name = c
}
2020-05-10 14:23:50 +02:00
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
}
}
2018-06-15 09:29:13 +02:00
if !math.IsNaN(record.Location.Latitude) {
city.Latitude = record.Location.Latitude
}
if !math.IsNaN(record.Location.Longitude) {
city.Longitude = record.Location.Longitude
2018-02-10 14:35:12 +01:00
}
2020-05-10 14:23:50 +02:00
// 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
}
2018-06-15 09:29:13 +02:00
return city, nil
2018-02-10 14:35:12 +01:00
}
2018-02-10 17:52:55 +01:00
2019-07-05 15:01:45 +02:00
func (g *geoip) ASN(ip net.IP) (ASN, error) {
asn := ASN{}
if g.asn == nil {
return asn, nil
}
record, err := g.asn.ASN(ip)
if err != nil {
return asn, err
}
if record.AutonomousSystemNumber > 0 {
asn.AutonomousSystemNumber = record.AutonomousSystemNumber
}
if record.AutonomousSystemOrganization != "" {
asn.AutonomousSystemOrganization = record.AutonomousSystemOrganization
}
return asn, nil
}
2018-02-10 17:52:55 +01:00
func (g *geoip) IsEmpty() bool {
2018-02-10 20:47:35 +01:00
return g.country == nil && g.city == nil
2018-02-10 17:52:55 +01:00
}