Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1 @@
testdata/GeoIP2-City.mmdb
testdata/GeoIP2-Connection-Type.mmdb
testdata/GeoIP2-Country.mmdb
testdata/GeoIP2-ISP.mmdb
testdata/GeoLite2-ASN.mmdb
testdata/GeoLite2-City.mmdb
testdata/GeoLite2-Country.mmdb

testdata/GeoIP2-Anonymous-IP-Test.mmdb
testdata/GeoIP2-City-Test.mmdb
testdata/GeoIP2-Connection-Type-Test.mmdb
testdata/GeoIP2-Country-Test.mmdb
testdata/GeoIP2-Domain-Test.mmdb
testdata/GeoIP2-Enterprise-Test.mmdb
testdata/GeoIP2-ISP-Test.mmdb
testdata/GeoLite2-ASN-Test.mmdb
testdata
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,38 @@ connection_type-24 3883234 305 ns/op 32 B/op 2 allocs/o
connection_type_parallel-24 34284831 32.1 ns/op 32 B/op 2 allocs/op
```

## Supported databases types

### Country
- GeoIP2-Country
- GeoLite2-Country
- DBIP-Country
- DBIP-Country-Lite
- Geoacumen-Country

### City
- GeoIP2-City
- GeoLite2-City
- GeoIP2-Enterprise
- DBIP-City-Lite

### ISP
- GeoIP2-ISP

### ASN
- GeoLite2-ASN
- DBIP-ASN-Lite
- DBIP-ASN-Lite (compat=GeoLite2-ASN)

### Connection Type
- GeoIP2-Connection-Type

### Anonymous IP
- GeoIP2-Anonymous-IP

### Domain
- GeoIP2-Domain

## License

[MIT License](LICENSE).
12 changes: 12 additions & 0 deletions reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,15 @@ func newReader(buffer []byte) (*reader, error) {
}
return reader, nil
}

func isExpectedDatabaseType(databaseType string, expectedTypes ...string) bool {
if len(expectedTypes) == 0 {
return true
}
for _, expectedType := range expectedTypes {
if databaseType == expectedType {
return true
}
}
return false
}
11 changes: 9 additions & 2 deletions reader_anonymous_ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,26 @@ func (r *AnonymousIPReader) Lookup(ip net.IP) (*AnonymousIP, error) {
return result, nil
}

func NewAnonymousIPReader(buffer []byte) (*AnonymousIPReader, error) {
// NewAnonymousIPReaderWithType creates a new AnonymousIPReader that accepts MMDB files with a custom database type.
// Note that AnonymousIPReader only implements the fields provided by MaxMind GeoIP2-Anonymous-IP databases, and will
// ignore other fields. It is up to the developer to ensure that the database provides a compatible selection of fields.
func NewAnonymousIPReaderWithType(buffer []byte, expectedTypes ...string) (*AnonymousIPReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoIP2-Anonymous-IP" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB Anonymous-IP type: " + reader.metadata.DatabaseType)
}
return &AnonymousIPReader{
reader: reader,
}, nil
}

func NewAnonymousIPReader(buffer []byte) (*AnonymousIPReader, error) {
return NewAnonymousIPReaderWithType(buffer, "GeoIP2-Anonymous-IP")
}

func NewAnonymousIPReaderFromFile(filename string) (*AnonymousIPReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
11 changes: 9 additions & 2 deletions reader_asn.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,26 @@ func (r *ASNReader) Lookup(ip net.IP) (*ASN, error) {
return result, nil
}

func NewASNReader(buffer []byte) (*ASNReader, error) {
// NewASNReaderWithType creates a new ASNReader that accepts MMDB files with a custom database type. Note that
// ASNReader only implements the fields provided by MaxMind GeoLite2-ASN databases, and will ignore other fields.
// It is up to the developer to ensure that the database provides a compatible selection of fields.
func NewASNReaderWithType(buffer []byte, expectedTypes ...string) (*ASNReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoLite2-ASN" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB ASN type: " + reader.metadata.DatabaseType)
}
return &ASNReader{
reader: reader,
}, nil
}

func NewASNReader(buffer []byte) (*ASNReader, error) {
return NewASNReaderWithType(buffer, "GeoLite2-ASN", "DBIP-ASN-Lite", "DBIP-ASN-Lite (compat=GeoLite2-ASN)")
}

func NewASNReaderFromFile(filename string) (*ASNReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
13 changes: 9 additions & 4 deletions reader_city.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,26 @@ func (r *CityReader) Lookup(ip net.IP) (*CityResult, error) {
return result, nil
}

func NewCityReader(buffer []byte) (*CityReader, error) {
// NewCityReaderWithType creates a new CityReader that accepts MMDB files with a custom database type. Note that
// CityReader only implements the fields provided by MaxMind Geo*-City and GeoIP2-Enterprise databases, and will ignore
// other fields. It is up to the developer to ensure that the database provides a compatible selection of fields.
func NewCityReaderWithType(buffer []byte, expectedTypes ...string) (*CityReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoIP2-City" &&
reader.metadata.DatabaseType != "GeoLite2-City" &&
reader.metadata.DatabaseType != "GeoIP2-Enterprise" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB City type: " + reader.metadata.DatabaseType)
}
return &CityReader{
reader: reader,
}, nil
}

func NewCityReader(buffer []byte) (*CityReader, error) {
return NewCityReaderWithType(buffer, "GeoIP2-City", "GeoLite2-City", "GeoIP2-Enterprise", "DBIP-City-Lite")
}

func NewCityReaderFromFile(filename string) (*CityReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
12 changes: 10 additions & 2 deletions reader_connection_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,27 @@ func (r *ConnectionTypeReader) Lookup(ip net.IP) (string, error) {
return result.ConnectionType, nil
}

func NewConnectionTypeReader(buffer []byte) (*ConnectionTypeReader, error) {
// NewConnectionTypeReaderWithType creates a new ConnectionTypeReader that accepts MMDB files with a custom database
// type. Note that ConnectionTypeReader only implements the fields provided by MaxMind GeoIP2-Connection-Type databases,
// and will ignore other fields. It is up to the developer to ensure that the database provides a compatible selection
// of fields.
func NewConnectionTypeReaderWithType(buffer []byte, expectedTypes ...string) (*ConnectionTypeReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoIP2-Connection-Type" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB Connection-Type type: " + reader.metadata.DatabaseType)
}
return &ConnectionTypeReader{
reader: reader,
}, nil
}

func NewConnectionTypeReader(buffer []byte) (*ConnectionTypeReader, error) {
return NewConnectionTypeReaderWithType(buffer, "GeoIP2-Connection-Type")
}

func NewConnectionTypeReaderFromFile(filename string) (*ConnectionTypeReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
12 changes: 9 additions & 3 deletions reader_country.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,26 @@ func (r *CountryReader) Lookup(ip net.IP) (*CountryResult, error) {
return result, nil
}

func NewCountryReader(buffer []byte) (*CountryReader, error) {
// NewCountryReaderWithType creates a new CountryReader that accepts MMDB files with a custom database type. Note that
// CountryReader only implements the fields provided by MaxMind Geo*-Country databases, and will ignore other fields.
// It is up to the developer to ensure that the database provides a compatible selection of fields.
func NewCountryReaderWithType(buffer []byte, expectedTypes ...string) (*CountryReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoIP2-Country" &&
reader.metadata.DatabaseType != "GeoLite2-Country" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB Country type: " + reader.metadata.DatabaseType)
}
return &CountryReader{
reader: reader,
}, nil
}

func NewCountryReader(buffer []byte) (*CountryReader, error) {
return NewCountryReaderWithType(buffer, "GeoIP2-Country", "GeoLite2-Country", "Geoacumen-Country", "DBIP-Country", "DBIP-Country-Lite")
}

func NewCountryReaderFromFile(filename string) (*CountryReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
11 changes: 9 additions & 2 deletions reader_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,26 @@ func (r *DomainReader) Lookup(ip net.IP) (string, error) {
return result.Domain, nil
}

func NewDomainReader(buffer []byte) (*DomainReader, error) {
// NewDomainReaderWithType creates a new DomainReader that accepts MMDB files with a custom database type. Note that
// DomainReader only implements the fields provided by MaxMind GeoIP2-Domain databases, and will ignore other fields.
// It is up to the developer to ensure that the database provides a compatible selection of fields.
func NewDomainReaderWithType(buffer []byte, expectedTypes ...string) (*DomainReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoIP2-Domain" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB Domain type: " + reader.metadata.DatabaseType)
}
return &DomainReader{
reader: reader,
}, nil
}

func NewDomainReader(buffer []byte) (*DomainReader, error) {
return NewDomainReaderWithType(buffer, "GeoIP2-Domain")
}

func NewDomainReaderFromFile(filename string) (*DomainReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
11 changes: 9 additions & 2 deletions reader_isp.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,26 @@ func (r *ISPReader) Lookup(ip net.IP) (*ISP, error) {
return result, nil
}

func NewISPReader(buffer []byte) (*ISPReader, error) {
// NewISPReaderWithType creates a new ISPReader that accepts MMDB files with a custom database type. Note that
// ISPReader only implements the fields provided by MaxMind GeoIP2-ISP databases, and will ignore other fields.
// It is up to the developer to ensure that the database provides a compatible selection of fields.
func NewISPReaderWithType(buffer []byte, expectedTypes ...string) (*ISPReader, error) {
reader, err := newReader(buffer)
if err != nil {
return nil, err
}
if reader.metadata.DatabaseType != "GeoIP2-ISP" {
if !isExpectedDatabaseType(reader.metadata.DatabaseType, expectedTypes...) {
return nil, errors.New("wrong MaxMind DB ISP type: " + reader.metadata.DatabaseType)
}
return &ISPReader{
reader: reader,
}, nil
}

func NewISPReader(buffer []byte) (*ISPReader, error) {
return NewISPReaderWithType(buffer, "GeoIP2-ISP")
}

func NewISPReaderFromFile(filename string) (*ISPReader, error) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
84 changes: 83 additions & 1 deletion reader_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Test DB https://github.com/maxmind/MaxMind-DB
// Test DB
// https://github.com/maxmind/MaxMind-DB
// https://db-ip.com/db/lite.php
package geoip2

import (
Expand Down Expand Up @@ -406,3 +408,83 @@ func TestASN(t *testing.T) {
t.Fatal()
}
}

func TestDBIPCity(t *testing.T) {
reader, err := NewCityReaderFromFile("testdata/dbip-city-lite.mmdb")
if err != nil {
t.Fatal(err)
}
record, err := reader.Lookup(net.ParseIP("66.30.184.198"))
if err != nil {
t.Fatal(err)
}
if record.City.GeoNameID != 0 {
t.Fatal()
}
if record.City.Names["en"] != "Boston" {
t.Fatal()
}
if record.Location.Latitude != 42.3601 {
t.Fatal()
}
if record.Location.Longitude != -71.0589 {
t.Fatal()
}
if len(record.Subdivisions) != 1 {
t.Fatal()
}
if record.Subdivisions[0].Names["en"] != "Massachusetts" {
t.Fatal()
}
}

func TestDBIPCountry(t *testing.T) {
reader, err := NewCountryReaderFromFile("testdata/dbip-country-lite.mmdb")
if err != nil {
t.Fatal(err)
}
record, err := reader.Lookup(net.ParseIP("66.30.184.198"))
if err != nil {
t.Fatal(err)
}
if record.Continent.GeoNameID != 6255149 {
t.Fatal()
}
if record.Continent.Code != "NA" {
t.Fatal()
}
if record.Continent.Names["en"] != "North America" ||
record.Continent.Names["ru"] != "Северная Америка" {
t.Fatal()
}
if record.Country.GeoNameID != 6252001 {
t.Fatal()
}
if record.Country.ISOCode != "US" {
t.Fatal()
}
if record.Country.Names["fr"] != "États-Unis" ||
record.Country.Names["pt-BR"] != "Estados Unidos" {
t.Fatal()
}
if record.Country.IsInEuropeanUnion {
t.Fatal()
}
}

func TestDBIPASN(t *testing.T) {
reader, err := NewASNReaderFromFile("testdata/dbip-asn-lite.mmdb")
if err != nil {
t.Fatal(err)
}
record, err := reader.Lookup(net.ParseIP("66.30.184.198"))
if err != nil {
t.Fatal(err)
}
if record.AutonomousSystemNumber != 7922 {
t.Fatal()
}
if record.AutonomousSystemOrganization != "Comcast Cable Communications, LLC" {
t.Fatal()
}
}