Class: GeoIP

Inherits:
Object
  • Object
show all
Defined in:
lib/geoip.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename, flags = 0) ⇒ GeoIP

Open the GeoIP database and determine the file format version

filename is a String holding the path to the GeoIP.dat file options is an integer holding caching flags (unimplemented)



423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
# File 'lib/geoip.rb', line 423

def initialize(filename, flags = 0)
	@flags = flags
	@databaseType = GEOIP_COUNTRY_EDITION
	@record_length = STANDARD_RECORD_LENGTH
	@file = File.open(filename, 'rb')
	@file.seek(-3, IO::SEEK_END)
	0.upto(STRUCTURE_INFO_MAX_SIZE-1) { |i|
 if @file.read(3) == "\xFF\xFF\xFF"
		@databaseType = @file.getc
		@databaseType -= 105 if @databaseType >= 106

		if (@databaseType == GEOIP_REGION_EDITION_REV0)
  # Region Edition, pre June 2003
  @databaseSegments = [ STATE_BEGIN_REV0 ]
		elsif (@databaseType == GEOIP_REGION_EDITION_REV1)
  # Region Edition, post June 2003
  @databaseSegments = [ STATE_BEGIN_REV1 ]
		elsif (@databaseType == GEOIP_CITY_EDITION_REV0 ||
     @databaseType == GEOIP_CITY_EDITION_REV1 ||
     @databaseType == GEOIP_ORG_EDITION ||
     @databaseType == GEOIP_ISP_EDITION ||
     @databaseType == GEOIP_ASNUM_EDITION)
  # City/Org Editions have two segments, read offset of second segment
  @databaseSegments = [ 0 ]
  sr = @file.read(3).unpack("C*")
  @databaseSegments[0] += le_to_ui(sr)

  if (@databaseType == GEOIP_ORG_EDITION ||
			@databaseType == GEOIP_ISP_EDITION)
			@record_length = 4
  end
		end
		break

 else
		@file.seek(-4, IO::SEEK_CUR)
 end
	}
	if (@databaseType == GEOIP_COUNTRY_EDITION ||
 @databaseType == GEOIP_PROXY_EDITION ||
 @databaseType == GEOIP_NETSPEED_EDITION)
 @databaseSegments = [ COUNTRY_BEGIN ]
	end
end

Instance Attribute Details

#databaseTypeObject (readonly)

Returns the value of attribute databaseType.



418
419
420
# File 'lib/geoip.rb', line 418

def databaseType
  @databaseType
end

Instance Method Details

#city(hostname) ⇒ Object

Search the GeoIP database for the specified host, returning city info.

hostname is a String holding the host’s DNS name or numeric IP address. Return an array of twelve or fourteen elements:

  • The host or IP address string as requested

  • The IP address string after looking up the host

  • The GeoIP country-ID as an integer

  • The ISO3166-1 two-character country code

  • The ISO3166-2 three-character country code

  • The ISO3166 English-language name of the country

  • The two-character continent code

  • The region name

  • The city name

  • The postal code

  • The latitude

  • The longitude

  • The USA dma_code and area_code, if available (REV1 City database)



607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# File 'lib/geoip.rb', line 607

def city(hostname)
    ip = hostname
    if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
        # Lookup IP address, we were given a name
        ip = IPSocket.getaddress(hostname)
    end

    # Convert numeric IP address to an integer
    ipnum = iptonum(ip)
    if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
        @databaseType != GEOIP_CITY_EDITION_REV1)
        throw "Invalid GeoIP database type, can't look up City by IP"
    end
    pos = seek_record(ipnum);
    read_city(pos, hostname, ip)
end

#country(hostname) ⇒ Object

Search the GeoIP database for the specified host, returning country info

hostname is a String holding the host’s DNS name or numeric IP address. Return an array of seven elements:

  • The host or IP address string as requested

  • The IP address string after looking up the host

  • The GeoIP country-ID as an integer

  • The ISO3166-1 two-character country code

  • The ISO3166-2 three-character country code

  • The ISO3166 English-language name of the country

  • The two-character continent code



480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/geoip.rb', line 480

def country(hostname)
	if (@databaseType == GEOIP_CITY_EDITION_REV0 ||
 @databaseType == GEOIP_CITY_EDITION_REV1)
 return city(hostname)
	end

	ip = hostname
	if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
 # Lookup IP address, we were given a name
 ip = IPSocket.getaddress(hostname)
	end

	# Convert numeric IP address to an integer
	ipnum = iptonum(ip)
	if (@databaseType != GEOIP_COUNTRY_EDITION && 
 @databaseType != GEOIP_PROXY_EDITION &&
 @databaseType != GEOIP_NETSPEED_EDITION)
 throw "Invalid GeoIP database type, can't look up Country by IP"
	end
	code = seek_record(ipnum) - COUNTRY_BEGIN;
	[   hostname,			# Requested hostname
 ip,				# Ip address as dotted quad
 code,			# GeoIP's country code
 CountryCode[code],		# ISO3166-1 code
 CountryCode3[code],		# ISO3166-2 code
 CountryName[code],		# Country name, per IS03166
 CountryContinent[code] ]	# Continent code.
end

#eachObject

Iterate through a GeoIP city database



625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
# File 'lib/geoip.rb', line 625

def each
    if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
        @databaseType != GEOIP_CITY_EDITION_REV1)
        throw "Invalid GeoIP database type, can't iterate thru non-City database"
    end

    @iter_pos = @databaseSegments[0] + 1
    num = 0
    until((rec = read_city(@iter_pos)).nil?)
        yield(rec)
        print "#{num}: #{@iter_pos}\n" if((num += 1) % 1000 == 0)
    end
    @iter_pos = nil
    self
end