maxmind / GeoIP2-java

Java API for GeoIP2 webservice client and database reader
https://maxmind.github.io/GeoIP2-java/
Apache License 2.0
783 stars 205 forks source link

Some IP addresses return IllegalArgument Exception from DatabaseReader #295

Closed ethanpaek closed 2 years ago

ethanpaek commented 2 years ago

Hi there,

I am currently attempting to incorporate this library into my project and was testing out the sample code as specified here: https://github.com/maxmind/GeoIP2-java#city with a sample MMDB file.

// A File object pointing to your GeoIP2 or GeoLite2 database
File database = new File("/path/to/GeoIP2-City.mmdb");

// This creates the DatabaseReader object. To improve performance, reuse
// the object across lookups. The object is thread-safe.
DatabaseReader reader = new DatabaseReader.Builder(database).build();

InetAddress ipAddress = InetAddress.getByName("128.101.101.101");

// Replace "city" with the appropriate method for your database, e.g.,
// "country".
CityResponse response = reader.city(ipAddress);

However, whenever I attempt to run this code, I receive java.lang.IllegalArgumentException: argument type mismatch when it tries to look up the IP address. Oddly enough, if I replace the IP address string with something like 155.56.208.64 in getByName(), then the code runs seamlessly and is able to return the corresponding IP information (country, city, etc.).

I've also noticed that if I switch CityReponse to CountryResponse, it seems to work successfully. However, I'd like to retrieve other IP info such as city, longitude, latitude, etc.

Would you happen to have a workaround or explanation as to why this might be happening?

oschwald commented 2 years ago

I am not sure why that would be happening. The sample code works fine for me. My guess is that the MMDB file you are using is corrupted in some way. A stack trace would help.

ethanpaek commented 2 years ago

Sure, here is a stack trace:

Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
    at com.maxmind.db.Decoder.decodeMapIntoObject(Decoder.java:436)
    at com.maxmind.db.Decoder.decodeMap(Decoder.java:342)
    at com.maxmind.db.Decoder.decodeByType(Decoder.java:162)
    at com.maxmind.db.Decoder.decode(Decoder.java:151)
    at com.maxmind.db.Decoder.decodeMapIntoObject(Decoder.java:429)
    at com.maxmind.db.Decoder.decodeMap(Decoder.java:342)
    at com.maxmind.db.Decoder.decodeByType(Decoder.java:162)
    at com.maxmind.db.Decoder.decode(Decoder.java:151)
    at com.maxmind.db.Decoder.decode(Decoder.java:76)
    at com.maxmind.db.Reader.resolveDataPointer(Reader.java:267)
    at com.maxmind.db.Reader.getRecord(Reader.java:180)
    at com.maxmind.geoip2.DatabaseReader.get(DatabaseReader.java:263)
    at com.maxmind.geoip2.DatabaseReader.getCity(DatabaseReader.java:348)
    at com.maxmind.geoip2.DatabaseReader.city(DatabaseReader.java:331)
ethanpaek commented 2 years ago

I am also using a sample MMDB that was provided by GeoLite2. Could it be a possibility that this IP address simply isn't present within the MMDB file?

oschwald commented 2 years ago

No, this error would not happen due to a missing IP. I am still leaning towards the database being corrupt. I just tested it with the GeoLite2 City from 2022-01-27 and it worked ok. The sha256 of that database is 78f2a16a874a74766a06fa07c3d345feabf4fc1b3caf91c9336af8257e390525. Is this the same database you are trying? Can you confirm that the hash matches?

ethanpaek commented 2 years ago

Ah, looks like that was the issue! It appears I haven't updated the file since May of last year so perhaps it was corrupted. Thank you so much for your help!

ethanpaek commented 2 years ago

Hi there, I am re-opening the issue because I have attempted to use a new mmdb file (provided by Neustar, another third-party IP info company) and am once again running into the issue stated initially. However, oddly enough, it seems to populate IP info for every country so far except for those within the United States. Thus, I am attempting to figure out if this is an issue with the mmdb file itself or this open-source library.

Any thoughts or opinions as to why this might be occurring? Thank you very much in advance for your help!

oschwald commented 2 years ago

It is pretty hard to speculate on the exact cause without access to the database. Would you be able to provide the output of mmdblookup -v -f <file> -i <ip> for an IP that exhibits this issue? mmdblookup is part of libmaxminddb.

It may also be worth following up with Neustar if they generated the MMDB file.

ethanpaek commented 2 years ago

No problem at all! Here is the output:

libmaxminddb-main % libmaxminddb-main % mmdblookup -v -f UltraGeoPoint2-City.mmdb -i 169.145.42.41

  Database metadata
    Node count:    149478204
    Record size:   32 bits
    IP version:    IPv6
    Binary format: 2.0
    Build epoch:   1644723381 (2022-02-13 03:36:21 UTC)
    Type:          GeoLite2-City
    Languages:     en
    Description:
      en:   Neustar IP Intelligence

  Record prefix length: 126

  {
    "city":
      {
        "names":
          {
            "en":
              "San Ramon" <utf8_string>
          }
      }
    "continent":
      {
        "code":
          "NA" <utf8_string>
        "names":
          {
            "en":
              "North America" <utf8_string>
          }
      }
    "country":
      {
        "iso_code":
          "US" <utf8_string>
        "names":
          {
            "en":
              "United States" <utf8_string>
          }
      }
    "location":
      {
        "latitude":
          37.763540 <double>
        "longitude":
          -121.912060 <double>
        "metro_code":
          807 <uint32>
        "time_zone":
          "-08:00" <utf8_string>
      }
    "postal":
      {
        "code":
          "94582" <utf8_string>
      }
    "registered_country":
      {
        "iso_code":
          "US" <utf8_string>
        "names":
          {
            "en":
              "United States" <utf8_string>
          }
      }
    "subdivisions":
      [
        {
          "iso_code":
            "CA" <utf8_string>
          "names":
            {
              "en":
                "California" <utf8_string>
            }
        }
      ]
  }

As we can see, this is likely an issue with GeoIP2, rather than the mmdb file that I am using... any possible ideas as to why?

oschwald commented 2 years ago

I believe the issue is that metro_code is a uint32 rather than a uint16, as it is in databases from MaxMind. The maxmind-db error exception certainly could be improved and possibly the reflection code could handle this case as long as the value fits in the type in the model class.

ethanpaek commented 2 years ago

Gotcha, that makes sense. I've attempted to look up other IP addresses outside the United States and you appear to be correct since other countries don't seem to even have metro_code present. Is there any way to bypass this exception? I don't need to use this attribute at all in my database and could certainly use a workaround

oschwald commented 2 years ago

There isn't a great workaround without forking this repo and remove the metro_code stuff or changing the type on the Int to Long for it. I might suggest raising this with Neustar. They may be able to adjust their MMDB generation so that metro_code matches the type in the MaxMind database.

ethanpaek commented 2 years ago

No worries, I'll reach out to them in that case. Thank you again for all of your help!