class IPIPX::IPv4DatabaseX

Database for search IPv4 address.

The IPIP.net data file(ipip.datx) format in bytes::

   ----------------------------------
   | 4 bytes                        |             <- offset number
   ----------------------------------
   | 256 * 1024 bytes               |             <- first ip number index
   ----------------------------------
   | offset - 256 * 1024 - 4 bytes  |             <- ip index
   ----------------------------------
   | data  storage                  |
   ----------------------------------

Constants

FIRST_IP_NUMBER_INDEX_SIZE
IP_BLOCK_SIZE
OFFSET_NUMBER_SIZE

Public Class Methods

new(data_file) click to toggle source
# File lib/ipip/ipv4_database_x.rb, line 26
def initialize(data_file)
  @data_file = data_file
end

Public Instance Methods

find(ip) click to toggle source
# File lib/ipip/ipv4_database_x.rb, line 30
def find(ip)
  ip = IPSocket::getaddress(ip)
  lookup_ipv4(ip)
end

Private Instance Methods

binread(length, offset) click to toggle source
# File lib/ipip/ipv4_database_x.rb, line 45
def binread(length, offset)
  IO.binread(@data_file, length, offset)
end
buffer() click to toggle source
# File lib/ipip/ipv4_database_x.rb, line 41
def buffer
  @buffer ||= binread(nil, OFFSET_NUMBER_SIZE)
end
lookup_ipv4(ip) click to toggle source
# File lib/ipip/ipv4_database_x.rb, line 49
def lookup_ipv4(ip)
  ip = IPAddr.new(ip)
  return unless ip.ipv4?

  nip = ip.hton
  first_ip = unpack_C(nip)
  ipdot = ip.to_s.split('.')
  first_ip_offset = (first_ip * 256 + ipdot[1].to_i) * 4

  start = unpack_V(buffer[first_ip_offset, 4])
  start_offset = start * IP_BLOCK_SIZE + FIRST_IP_NUMBER_INDEX_SIZE
  end_offset = offset - FIRST_IP_NUMBER_INDEX_SIZE - OFFSET_NUMBER_SIZE
  lo, hi = 0, (end_offset - start_offset) / IP_BLOCK_SIZE

  while lo < hi
    mid = (lo + hi) / 2
    mid_offset = start_offset + mid * IP_BLOCK_SIZE
    mid_val = buffer[mid_offset, 4]

    if mid_val < nip
      lo = mid + 1
    else
      hi = mid
    end
  end

  start_offset += lo * IP_BLOCK_SIZE
  return if start_offset == offset

  data_pos = unpack_V(buffer[start_offset + 4, 3] + 0.chr)
  data_length = unpack_C(buffer[start_offset + 8])

  data_offset = offset + data_pos - FIRST_IP_NUMBER_INDEX_SIZE - OFFSET_NUMBER_SIZE
  data = buffer[data_offset, data_length].to_s.encode('UTF-8', 'UTF-8')
end
offset() click to toggle source
# File lib/ipip/ipv4_database_x.rb, line 37
def offset
  @offset ||= unpack_N(binread(OFFSET_NUMBER_SIZE, 0))
end