cjheath / geoip

The Ruby gem for querying Maxmind.com's GeoIP database, which returns the geographic location of a server given its IP address

Home Page:http://geoip.rubyforge.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

GeoIP.asn incorrect parsing of some records

gconklin opened this issue · comments

irb(main):008:0>     @mm_asn = GeoIP.new( 'GeoIPASNum.dat' )
=> #<GeoIP:0x2b1a1e0 @mutex=#<Mutex:0x2b1a1b0>, @use_pread=false, @options={}, @database_type=9, @record_length=3, @file=#<File:GeoIPASNum.dat>, @ip_bits=32, @database_segments=[365984]>

# Good: Returns ASN struct
irb(main):009:0> x = @mm_asn.asn( "195.238.18.26")
=> #<struct GeoIP::ASN number="AS5432", asn="BELGACOM S.A.">

# Bad: Returns the raw record (because of leading *)
irb(main):010:0> x = @mm_asn.asn( "195.238.181.26")
=> "*AS18144 Energia Communications,Inc."

I can't reproduce your problem using the currently available GeoIPASNum.dat, the current geoip and that IP address (nor any other). Please ensure you have the latest and I'll try again.
The problem you mention likely has its origin here, but I can't verify that:
https://github.com/cjheath/geoip/blob/master/lib/geoip.rb#L721

I worked around it by seeing if the returned result was a string and manually parsing it.

The commands below were executed today, so the database is current as far as I know.

gconklin@generics:~/tmp$ wget http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
--2015-04-30 17:50:50--  http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
Resolving download.maxmind.com (download.maxmind.com)... 141.101.114.190, 141.101.115.190, 2400:cb00:2048:1::8d65:73be, ...
Connecting to download.maxmind.com (download.maxmind.com)|141.101.114.190|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2117807 (2.0M) [application/octet-stream]
Saving to: `GeoIPASNum.dat.gz'

100%[===================================================================================================================>] 2,117,807   2.24M/s   in 0.9s

2015-04-30 17:50:51 (2.24 MB/s) - `GeoIPASNum.dat.gz' saved [2117807/2117807]

gconklin@generics:~/tmp$ ls -alt GeoIPASNum.dat.gz
-rw-r--r-- 1 gconklin gconklin 2117807 Apr 20 14:20 GeoIPASNum.dat.gz
gconklin@generics:~/tmp$ gzip -d GeoIPASNum.dat.gz
gconklin@generics:~/tmp$ ls -alt GeoIPASNum.dat
-rw-r--r-- 1 gconklin gconklin 3876886 Apr 20 14:20 GeoIPASNum.dat

gconklin@generics:~/dev/ruby$ gem list --local |grep geoip
geoip (1.5.0)
gconklin@generics:~/dev/ruby$ irb
2.1.1 :001 > require 'geoip'
 => true

2.1.1 :002 > GeoIP::VERSION
 => "1.5.0"

2.1.1 :003 > asn = GeoIP.new( 'GeoIPASNum.dat' )
 => #<GeoIP:0x00000002c53008 @mutex=#<Mutex:0x00000002c52fb8>, @use_pread=false, @options={}, @database_type=9, @record_length=3, @file=#<File:GeoIPASNum.dat>, @ip_bits=32, @database_segments=[373915]>

2.1.1 :004 > r = asn.asn( '173.212.202.96' )
 => "*AS18144 Energia Communications,Inc."

2.1.1 :005 > r.class
 => String

2.1.1 :006 > r = asn.asn( '8.8.8.8' )
 => #<struct GeoIP::ASN number="AS15169", asn="Google Inc.">
2.1.1 :007 > r.class
 => GeoIP::ASN

Here's a list of IPs I've recently seen with this behavior:
Some IP: 173.212.202.96 = *AS18144 Energia Communications,Inc.
Some IP: 184.82.40.4 = *AS18144 Energia Communications,Inc.
Some IP: 194.58.78.19 = *AS18144 Energia Communications,Inc.
Some IP: 195.16.88.15 = *AS18144 Energia Communications,Inc.
Some IP: 68.180.151.76 = *AS18144 Energia Communications,Inc.
Some IP: 74.114.116.105 = *AS18144 Energia Communications,Inc.
Some IP: 91.193.194.214 = *AS18144 Energia Communications,Inc.
Some IP: 91.213.217.196 = *AS18144 Energia Communications,Inc.
Some IP: 91.217.249.168 = *AS18144 Energia Communications,Inc.
Some IP: 93.188.242.139 = *AS18144 Energia Communications,Inc.

Thanks. I reproduced your problem. This lookup should have failed; the IP address is in an unallocated range. However, the file index for this failing query is not zero, but one; the first valid value appears to be two, so we read from the byte before the very first entry. I'm not sure why Maxmind did that, but I can now prevent the incorrect behaviour and just return nil as I should. Thanks for giving me a reproducible case.

Fixed, and the fix is pushed (will be geoip 1.6.0). The problem is caused by unallocated IP ranges in the database, resulting in an offset of zero (meaning missing). This offset is one byte before the first record, which for ASN happens to be Energia Comms.