Commit 55d3de43 by William Tisäter

Merge branch 'master' of https://github.com/tiwilliam/pygeoip

Conflicts:
	pygeoip/__init__.py
	tests/config.py
	tests/test_pygeoip.py
parents 6c7a2aec 025ff47f
...@@ -187,7 +187,9 @@ class GeoIP(GeoIPBase): ...@@ -187,7 +187,9 @@ class GeoIP(GeoIPBase):
@rtype: int @rtype: int
""" """
offset = 0 offset = 0
for depth in range(31, -1, -1): seek_depth = 127 if len(str(ipnum)) > 10 else 31
for depth in range(seek_depth, -1, -1):
if self._flags & const.MEMORY_CACHE: if self._flags & const.MEMORY_CACHE:
startIndex = 2 * self._recordLength * offset startIndex = 2 * self._recordLength * offset
endIndex = startIndex + (2 * self._recordLength) endIndex = startIndex + (2 * self._recordLength)
...@@ -202,7 +204,6 @@ class GeoIP(GeoIPBase): ...@@ -202,7 +204,6 @@ class GeoIP(GeoIPBase):
for i in range(2): for i in range(2):
for j in range(self._recordLength): for j in range(self._recordLength):
x[i] += ord(buf[self._recordLength * i + j]) << (j * 8) x[i] += ord(buf[self._recordLength * i + j]) << (j * 8)
if ipnum & (1 << depth): if ipnum & (1 << depth):
if x[1] >= self._databaseSegments: if x[1] >= self._databaseSegments:
return x[1] return x[1]
...@@ -379,7 +380,8 @@ class GeoIP(GeoIPBase): ...@@ -379,7 +380,8 @@ class GeoIP(GeoIPBase):
if not ipnum: if not ipnum:
raise ValueError("Invalid IP address: %s" % addr) raise ValueError("Invalid IP address: %s" % addr)
if self._databaseType != const.COUNTRY_EDITION: COUNTY_EDITIONS = (const.COUNTRY_EDITION, const.COUNTRY_EDITION_V6)
if self._databaseType not in COUNTY_EDITIONS:
message = 'Invalid database type, expected Country' message = 'Invalid database type, expected Country'
raise GeoIPError(message) raise GeoIPError(message)
...@@ -396,8 +398,17 @@ class GeoIP(GeoIPBase): ...@@ -396,8 +398,17 @@ class GeoIP(GeoIPBase):
@rtype: str @rtype: str
""" """
try: try:
if self._databaseType == const.COUNTRY_EDITION: COUNTRY_EDITIONS = (const.COUNTRY_EDITION, const.COUNTRY_EDITION_V6)
return const.COUNTRY_CODES[self.id_by_addr(addr)] if self._databaseType in COUNTRY_EDITIONS:
ipv = 6 if addr.find(':') >= 0 else 4
if ipv == 4 and self._databaseType != const.COUNTRY_EDITION:
raise ValueError('Invalid database type; expected IPv6 address')
if ipv == 6 and self._databaseType != const.COUNTRY_EDITION_V6:
raise ValueError('Invalid database type; expected IPv4 address')
country_id = self.id_by_addr(addr)
return const.COUNTRY_CODES[country_id]
elif self._databaseType in const.REGION_CITY_EDITIONS: elif self._databaseType in const.REGION_CITY_EDITIONS:
return self.region_by_addr(addr)['country_code'] return self.region_by_addr(addr)['country_code']
...@@ -416,9 +427,24 @@ class GeoIP(GeoIPBase): ...@@ -416,9 +427,24 @@ class GeoIP(GeoIPBase):
@return: 2-letter country code @return: 2-letter country code
@rtype: str @rtype: str
""" """
if self._databaseType == const.COUNTRY_EDITION_V6:
return self._country_code_by_name_v6(hostname)
else:
return self._country_code_by_name_v4(hostname)
def _country_code_by_name_v4(self, hostname):
addr = socket.gethostbyname(hostname) addr = socket.gethostbyname(hostname)
return self.country_code_by_addr(addr) return self.country_code_by_addr(addr)
def _country_code_by_name_v6(self, hostname):
try:
response = socket.getaddrinfo(hostname, 0, socket.AF_INET6)
except socket.gaierror:
return ''
family, socktype, proto, canonname, sockaddr = response[0]
address, port, flow, scope = sockaddr
return self.country_code_by_addr(address)
def country_name_by_addr(self, addr): def country_name_by_addr(self, addr):
""" """
Returns full country name for specified IP address. Returns full country name for specified IP address.
......
""" """
Misc. utility functions. It is part of the pygeoip package. Misc. utility functions. It is part of the pygeoip package.
@author: Jennifer Ennis <zaylea at gmail dot com> @author: Jennifer Ennis <zaylea at gmail dot com>
@license: @license:
Copyright(C) 2004 MaxMind LLC Copyright(C) 2004 MaxMind LLC
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>. along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
""" """
import six import six
import struct
def ip2long(ip): import socket
""" from array import array
Convert a IPv4 address into a 32-bit integer.
@param ip: quad-dotted IPv4 address def ip2long(ip):
@type ip: str """
@return: network byte order 32-bit integer Wrapper function for IPv4 and IPv6 converters
@rtype: int @param ip: IPv4 or IPv6 address
""" @type ip: str
ip_array = ip.split('.') """
if ip.find(':') >= 0:
if six.PY3: return ip2long_v6(ip)
# int and long are unified in py3 else:
ip_long = int(ip_array[0]) * 16777216 + int(ip_array[1]) * 65536 + int(ip_array[2]) * 256 + int(ip_array[3]) return ip2long_v4(ip)
else:
ip_long = long(ip_array[0]) * 16777216 + long(ip_array[1]) * 65536 + long(ip_array[2]) * 256 + long(ip_array[3])
return ip_long def ip2long_v4(ip):
"""
Convert a IPv4 address into a 32-bit integer.
@param ip: quad-dotted IPv4 address
@type ip: str
@return: network byte order 32-bit integer
@rtype: int
"""
ip_array = ip.split('.')
if six.PY3:
# int and long are unified in py3
ip_long = int(ip_array[0]) * 16777216 + int(ip_array[1]) * 65536 + int(ip_array[2]) * 256 + int(ip_array[3])
else:
ip_long = long(ip_array[0]) * 16777216 + long(ip_array[1]) * 65536 + long(ip_array[2]) * 256 + long(ip_array[3])
return ip_long
def ip2long_v6(ip):
"""
Convert a IPv6 address into long.
@param ip: IPv6 address
@type ip: str
@return: network byte order long
@rtype: long
"""
ipbyte = socket.inet_pton(socket.AF_INET6, ip)
ipnum = array('L', struct.unpack('!4L', ipbyte))
max_index = len(ipnum) - 1
return sum(ipnum[max_index - i] << (i * 32) for i in range(len(ipnum)))
...@@ -3,6 +3,7 @@ import os.path as path ...@@ -3,6 +3,7 @@ import os.path as path
DATA_DIR = path.join(path.dirname(path.realpath(__file__)), 'data') DATA_DIR = path.join(path.dirname(path.realpath(__file__)), 'data')
COUNTRY_DB_PATH = path.join(DATA_DIR, 'GeoIP.dat') COUNTRY_DB_PATH = path.join(DATA_DIR, 'GeoIP.dat')
COUNTRY_V6_DB_PATH = path.join(DATA_DIR, 'GeoIPv6.dat')
REGION_DB_PATH = path.join(DATA_DIR, 'GeoIPRegion.dat') REGION_DB_PATH = path.join(DATA_DIR, 'GeoIPRegion.dat')
CITY_DB_PATH = path.join(DATA_DIR, 'GeoLiteCity.dat') CITY_DB_PATH = path.join(DATA_DIR, 'GeoLiteCity.dat')
ORG_DB_PATH = path.join(DATA_DIR, 'GeoIPOrg.dat') ORG_DB_PATH = path.join(DATA_DIR, 'GeoIPOrg.dat')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment