Updated bundled version of PyGeoIP

This commit is contained in:
Luke Rogers 2013-07-14 22:12:31 +12:00
parent 487ee03e6c
commit b0e43c0aea
6 changed files with 1718 additions and 1422 deletions

165
lib/pygeoip/COPYING Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

21
lib/pygeoip/DEVELOPER Normal file
View File

@ -0,0 +1,21 @@
Bootstrap manual for developers of pygeoip
Dependencies: tox, nose, epydoc
For testing we are using tox virtualenv-based Python version testing
and nose as test framwork.
Tox will create virtualenvs for all Python version pygeoip supports
and installs the current working tree using the setup.py install script.
Running the tests requires a couple of sample databases found on the
link below.
Maxmind sample databases for testing can be downloaded here:
http://www.defunct.cc/maxmind-geoip-samples.tar.gz (58 MB)
Extract the tarball in the tests directory and run tox from the root directory.
Please make sure your code passes all tests before opening pull requests.
All the best,
William Tisäter

View File

@ -1,17 +1,13 @@
# -*- coding: utf-8 -*-
"""
Pure Python GeoIP API. The API is based off of U{MaxMind's C-based Python API<http://www.maxmind.com/app/python>},
but the code itself is based on the U{pure PHP5 API<http://pear.php.net/package/Net_GeoIP/>}
by Jim Winstead and Hans Lellelid.
Pure Python GeoIP API
It is mostly a drop-in replacement, except the
C{new} and C{open} methods are gone. You should instantiate the L{GeoIP} class yourself:
The API is based on MaxMind's C-based Python API, but the code itself is
ported from the Pure PHP GeoIP API by Jim Winstead and Hans Lellelid.
C{gi = GeoIP('/path/to/GeoIP.dat', pygeoip.MEMORY_CACHE)}
@author: Jennifer Ennis <zaylea@gmail.com>
@author: Jennifer Ennis <zaylea at gmail dot com>
@license:
Copyright(C) 2004 MaxMind LLC
@license: Copyright(C) 2004 MaxMind LLC
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
@ -27,39 +23,43 @@ 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>.
"""
from __future__ import with_statement, absolute_import, division
import os
import math
import socket
import mmap
import gzip
import codecs
from StringIO import StringIO
from threading import Lock
from . import const
from .util import ip2long
from .timezone import time_zone_by_country_and_region
try:
from StringIO import StringIO
except ImportError:
from io import StringIO, BytesIO
import six
from pygeoip import util, const
from pygeoip.const import PY2, PY3
from pygeoip.timezone import time_zone_by_country_and_region
STANDARD = const.STANDARD
MMAP_CACHE = const.MMAP_CACHE
MEMORY_CACHE = const.MEMORY_CACHE
STANDARD = const.STANDARD
ENCODING = const.ENCODING
class GeoIPError(Exception):
pass
class GeoIPMetaclass(type):
class GeoIPMetaclass(type):
def __new__(cls, *args, **kwargs):
"""
Singleton method to gets an instance without reparsing the db. Unique
instances are instantiated based on the filename of the db. Flags are
ignored for this, i.e. if you initialize one with STANDARD flag (default)
and then try later to initialize with MEMORY_CACHE, it will still
return the STANDARD one.
ignored for this, i.e. if you initialize one with STANDARD
flag (default) and then try later to initialize with MEMORY_CACHE, it
will still return the STANDARD one.
"""
if not hasattr(cls, '_instances'):
cls._instances = {}
@ -68,25 +68,25 @@ class GeoIPMetaclass(type):
elif 'filename' in kwargs:
filename = kwargs['filename']
if not filename in cls._instances:
if filename not in cls._instances:
cls._instances[filename] = type.__new__(cls, *args, **kwargs)
return cls._instances[filename]
GeoIPBase = GeoIPMetaclass('GeoIPBase', (object,), {})
class GeoIP(GeoIPBase):
class GeoIP(GeoIPBase):
def __init__(self, filename, flags=0):
"""
Initialize the class.
@param filename: path to a geoip database. If MEMORY_CACHE is used,
the file can be gzipped.
@param filename: Path to a geoip database.
@type filename: str
@param flags: flags that affect how the database is processed.
Currently the only supported flags are STANDARD (the default),
MEMORY_CACHE (preload the whole file into memory), and
@param flags: Flags that affect how the database is processed.
Currently supported flags are STANDARD (the default),
MEMORY_CACHE (preload the whole file into memory) and
MMAP_CACHE (access the file via mmap).
@type flags: int
"""
@ -94,42 +94,71 @@ class GeoIP(GeoIPBase):
self._flags = flags
if self._flags & const.MMAP_CACHE:
with open(filename, 'rb') as f:
self._filehandle = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
f = open(filename, 'rb')
access = mmap.ACCESS_READ
self._filehandle = mmap.mmap(f.fileno(), 0, access=access)
f.close()
elif self._flags & const.MEMORY_CACHE:
if filename.endswith('.gz'):
opener = gzip.open
else:
opener = open
f = open(filename, 'rb')
self._memoryBuffer = f.read()
iohandle = BytesIO if PY3 else StringIO
self._filehandle = iohandle(self._memoryBuffer)
f.close()
with opener(filename, 'rb') as f:
self._memoryBuffer = f.read()
self._filehandle = StringIO(self._memoryBuffer)
else:
self._filehandle = codecs.open(filename, 'rb','latin_1')
self._filehandle = codecs.open(filename, 'rb', ENCODING)
self._lock = Lock()
self._setup_segments()
def _setup_segments(self):
"""
Parses the database file to determine what kind of database is being used and setup
segment sizes and start points that will be used by the seek*() methods later.
Parses the database file to determine what kind of database is
being used and setup segment sizes and start points that will
be used by the seek*() methods later.
Supported databases:
* COUNTRY_EDITION
* COUNTRY_EDITION_V6
* REGION_EDITION_REV0
* REGION_EDITION_REV1
* CITY_EDITION_REV0
* CITY_EDITION_REV1
* CITY_EDITION_REV1_V6
* ORG_EDITION
* ISP_EDITION
* ASNUM_EDITION
* ASNUM_EDITION_V6
"""
self._databaseType = const.COUNTRY_EDITION
self._recordLength = const.STANDARD_RECORD_LENGTH
self._databaseSegments = const.COUNTRY_BEGIN
self._lock.acquire()
filepos = self._filehandle.tell()
self._filehandle.seek(-3, os.SEEK_END)
for i in range(const.STRUCTURE_INFO_MAX_SIZE):
chars = chr(255) * 3
delim = self._filehandle.read(3)
if delim == six.u(chr(255) * 3):
self._databaseType = ord(self._filehandle.read(1))
if PY3 and type(delim) is bytes:
delim = delim.decode(ENCODING)
if PY2:
chars = chars.decode(ENCODING)
if type(delim) is str:
delim = delim.decode(ENCODING)
if delim == chars:
byte = self._filehandle.read(1)
self._databaseType = ord(byte)
# Compatibility with databases from April 2003 and earlier
if (self._databaseType >= 106):
# backwards compatibility with databases from April 2003 and earlier
self._databaseType -= 105
if self._databaseType == const.REGION_EDITION_REV0:
@ -140,51 +169,29 @@ class GeoIP(GeoIPBase):
elif self._databaseType in (const.CITY_EDITION_REV0,
const.CITY_EDITION_REV1,
const.CITY_EDITION_REV1_V6,
const.ORG_EDITION,
const.ISP_EDITION,
const.ASNUM_EDITION):
const.ASNUM_EDITION,
const.ASNUM_EDITION_V6):
self._databaseSegments = 0
buf = self._filehandle.read(const.SEGMENT_RECORD_LENGTH)
if PY3 and type(buf) is bytes:
buf = buf.decode(ENCODING)
for j in range(const.SEGMENT_RECORD_LENGTH):
self._databaseSegments += (ord(buf[j]) << (j * 8))
if self._databaseType in (const.ORG_EDITION, const.ISP_EDITION):
LONG_RECORDS = (const.ORG_EDITION, const.ISP_EDITION)
if self._databaseType in LONG_RECORDS:
self._recordLength = const.ORG_RECORD_LENGTH
break
else:
self._filehandle.seek(-4, os.SEEK_CUR)
if self._databaseType == const.COUNTRY_EDITION:
self._databaseSegments = const.COUNTRY_BEGIN
self._filehandle.seek(filepos, os.SEEK_SET)
def _lookup_country_id(self, addr):
"""
Get the country index.
This method is called by the _lookupCountryCode and _lookupCountryName
methods. It looks up the index ('id') for the country which is the key
for the code and name.
@param addr: The IP address
@type addr: str
@return: network byte order 32-bit integer
@rtype: int
"""
ipnum = ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
if self._databaseType != const.COUNTRY_EDITION:
raise GeoIPError('Invalid database type; country_* methods expect '\
'Country database')
return self._seek_country(ipnum) - const.COUNTRY_BEGIN
self._lock.release()
def _seek_country(self, ipnum):
"""
@ -196,117 +203,119 @@ class GeoIP(GeoIPBase):
@return: offset of start of record
@rtype: int
"""
offset = 0
try:
offset = 0
seek_depth = 127 if len(str(ipnum)) > 10 else 31
for depth in range(31, -1, -1):
for depth in range(seek_depth, -1, -1):
if self._flags & const.MEMORY_CACHE:
startIndex = 2 * self._recordLength * offset
endIndex = startIndex + (2 * self._recordLength)
buf = self._memoryBuffer[startIndex:endIndex]
else:
startIndex = 2 * self._recordLength * offset
readLength = 2 * self._recordLength
self._lock.acquire()
self._filehandle.seek(startIndex, os.SEEK_SET)
buf = self._filehandle.read(readLength)
self._lock.release()
if self._flags & const.MEMORY_CACHE:
startIndex = 2 * self._recordLength * offset
length = 2 * self._recordLength
endIndex = startIndex + length
buf = self._memoryBuffer[startIndex:endIndex]
else:
self._filehandle.seek(2 * self._recordLength * offset, os.SEEK_SET)
buf = self._filehandle.read(2 * self._recordLength)
if PY3 and type(buf) is bytes:
buf = buf.decode(ENCODING)
x = [0,0]
x = [0, 0]
for i in range(2):
for j in range(self._recordLength):
byte = buf[self._recordLength * i + j]
x[i] += ord(byte) << (j * 8)
if ipnum & (1 << depth):
if x[1] >= self._databaseSegments:
return x[1]
offset = x[1]
else:
if x[0] >= self._databaseSegments:
return x[0]
offset = x[0]
except:
pass
for i in range(2):
for j in range(self._recordLength):
x[i] += ord(buf[self._recordLength * i + j]) << (j * 8)
if ipnum & (1 << depth):
if x[1] >= self._databaseSegments:
return x[1]
offset = x[1]
else:
if x[0] >= self._databaseSegments:
return x[0]
offset = x[0]
raise Exception('Error traversing database - perhaps it is corrupt?')
raise GeoIPError('Corrupt database')
def _get_org(self, ipnum):
"""
Seek and return organization (or ISP) name for converted IP addr.
Seek and return organization or ISP name for ipnum.
@param ipnum: Converted IP address
@type ipnum: int
@return: org/isp name
@rtype: str
"""
seek_org = self._seek_country(ipnum)
if seek_org == self._databaseSegments:
return None
record_pointer = seek_org + (2 * self._recordLength - 1) * self._databaseSegments
read_length = (2 * self._recordLength - 1) * self._databaseSegments
self._lock.acquire()
self._filehandle.seek(seek_org + read_length, os.SEEK_SET)
buf = self._filehandle.read(const.MAX_ORG_RECORD_LENGTH)
self._lock.release()
self._filehandle.seek(record_pointer, os.SEEK_SET)
if PY3 and type(buf) is bytes:
buf = buf.decode(ENCODING)
org_buf = self._filehandle.read(const.MAX_ORG_RECORD_LENGTH)
return org_buf[:org_buf.index(chr(0))]
return buf[:buf.index(chr(0))]
def _get_region(self, ipnum):
"""
Seek and return the region info (dict containing country_code and region_name).
Seek and return the region info (dict containing country_code
and region_name).
@param ipnum: converted IP address
@param ipnum: Converted IP address
@type ipnum: int
@return: dict containing country_code and region_name
@rtype: dict
"""
country_code = ''
region = ''
country_code = ''
seek_country = self._seek_country(ipnum)
def get_region_name(offset):
region1 = chr(offset // 26 + 65)
region2 = chr(offset % 26 + 65)
return ''.join([region1, region2])
if self._databaseType == const.REGION_EDITION_REV0:
seek_country = self._seek_country(ipnum)
seek_region = seek_country - const.STATE_BEGIN_REV0
if seek_region >= 1000:
country_code = 'US'
region = ''.join([chr((seek_region // 1000) // 26 + 65), chr((seek_region // 1000) % 26 + 65)])
region = get_region_name(seek_region - 1000)
else:
country_code = const.COUNTRY_CODES[seek_region]
region = ''
elif self._databaseType == const.REGION_EDITION_REV1:
seek_country = self._seek_country(ipnum)
seek_region = seek_country - const.STATE_BEGIN_REV1
if seek_region < const.US_OFFSET:
country_code = '';
region = ''
pass
elif seek_region < const.CANADA_OFFSET:
country_code = 'US'
region = ''.join([chr((seek_region - const.US_OFFSET) // 26 + 65), chr((seek_region - const.US_OFFSET) % 26 + 65)])
elif seek_region < const.WORLD_OFFSET:
region = get_region_name(seek_region - const.US_OFFSET)
elif seek_region < const.WORLD_OFFSET:
country_code = 'CA'
region = ''.join([chr((seek_region - const.CANADA_OFFSET) // 26 + 65), chr((seek_region - const.CANADA_OFFSET) % 26 + 65)])
region = get_region_name(seek_region - const.CANADA_OFFSET)
else:
i = (seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE
if i < len(const.COUNTRY_CODES):
#country_code = const.COUNTRY_CODES[(seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE]
country_code = const.COUNTRY_CODES[i]
else:
country_code = ''
region = ''
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
index = (seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE
if index in const.COUNTRY_CODES:
country_code = const.COUNTRY_CODES[index]
elif self._databaseType in const.CITY_EDITIONS:
rec = self._get_record(ipnum)
country_code = rec['country_code'] if 'country_code' in rec else ''
region = rec['region_name'] if 'region_name' in rec else ''
region = rec.get('region_name', '')
country_code = rec.get('country_code', '')
return {'country_code' : country_code, 'region_name' : region }
return {'country_code': country_code, 'region_name': region}
def _get_record(self, ipnum):
"""
Populate location dict for converted IP.
@param ipnum: converted IP address
@param ipnum: Converted IP address
@type ipnum: int
@return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
@ -315,107 +324,115 @@ class GeoIP(GeoIPBase):
"""
seek_country = self._seek_country(ipnum)
if seek_country == self._databaseSegments:
return None
return {}
record_pointer = seek_country + (2 * self._recordLength - 1) * self._databaseSegments
read_length = (2 * self._recordLength - 1) * self._databaseSegments
self._lock.acquire()
self._filehandle.seek(seek_country + read_length, os.SEEK_SET)
buf = self._filehandle.read(const.FULL_RECORD_LENGTH)
self._lock.release()
self._filehandle.seek(record_pointer, os.SEEK_SET)
record_buf = self._filehandle.read(const.FULL_RECORD_LENGTH)
if PY3 and type(buf) is bytes:
buf = buf.decode(ENCODING)
record = {}
record_buf_pos = 0
char = ord(record_buf[record_buf_pos])
#char = record_buf[record_buf_pos] if six.PY3 else ord(record_buf[record_buf_pos])
record['country_code'] = const.COUNTRY_CODES[char]
record['country_code3'] = const.COUNTRY_CODES3[char]
record['country_name'] = const.COUNTRY_NAMES[char]
record_buf_pos += 1
str_length = 0
# get region
char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
if str_length > 0:
record['region_name'] = record_buf[record_buf_pos:record_buf_pos+str_length]
record_buf_pos += str_length + 1
str_length = 0
# get city
char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
if str_length > 0:
record['city'] = record_buf[record_buf_pos:record_buf_pos+str_length]
else:
record['city'] = ''
record_buf_pos += str_length + 1
str_length = 0
# get the postal code
char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
if str_length > 0:
record['postal_code'] = record_buf[record_buf_pos:record_buf_pos+str_length]
else:
record['postal_code'] = None
record_buf_pos += str_length + 1
str_length = 0
record = {
'dma_code': 0,
'area_code': 0,
'metro_code': '',
'postal_code': ''
}
latitude = 0
longitude = 0
buf_pos = 0
# Get country
char = ord(buf[buf_pos])
record['country_code'] = const.COUNTRY_CODES[char]
record['country_code3'] = const.COUNTRY_CODES3[char]
record['country_name'] = const.COUNTRY_NAMES[char]
record['continent'] = const.CONTINENT_NAMES[char]
buf_pos += 1
def get_data(buf, buf_pos):
offset = buf_pos
char = ord(buf[offset])
while (char != 0):
offset += 1
char = ord(buf[offset])
if offset > buf_pos:
return (offset, buf[buf_pos:offset])
return (offset, '')
offset, record['region_name'] = get_data(buf, buf_pos)
offset, record['city'] = get_data(buf, offset + 1)
offset, record['postal_code'] = get_data(buf, offset + 1)
buf_pos = offset + 1
for j in range(3):
char = ord(record_buf[record_buf_pos])
record_buf_pos += 1
char = ord(buf[buf_pos])
buf_pos += 1
latitude += (char << (j * 8))
record['latitude'] = (latitude/10000.0) - 180.0
for j in range(3):
char = ord(record_buf[record_buf_pos])
record_buf_pos += 1
char = ord(buf[buf_pos])
buf_pos += 1
longitude += (char << (j * 8))
record['longitude'] = (longitude/10000.0) - 180.0
record['latitude'] = (latitude / 10000.0) - 180.0
record['longitude'] = (longitude / 10000.0) - 180.0
if self._databaseType == const.CITY_EDITION_REV1:
if self._databaseType in (const.CITY_EDITION_REV1, const.CITY_EDITION_REV1_V6):
dmaarea_combo = 0
if record['country_code'] == 'US':
for j in range(3):
char = ord(record_buf[record_buf_pos])
record_buf_pos += 1
dmaarea_combo += (char << (j*8))
char = ord(buf[buf_pos])
dmaarea_combo += (char << (j * 8))
buf_pos += 1
record['dma_code'] = int(math.floor(dmaarea_combo/1000))
record['area_code'] = dmaarea_combo%1000
else:
record['dma_code'] = 0
record['area_code'] = 0
record['dma_code'] = int(math.floor(dmaarea_combo / 1000))
record['area_code'] = dmaarea_combo % 1000
if 'dma_code' in record and record['dma_code'] in const.DMA_MAP:
record['metro_code'] = const.DMA_MAP[record['dma_code']]
else:
record['metro_code'] = ''
if 'country_code' in record:
record['time_zone'] = time_zone_by_country_and_region(
record['country_code'], record.get('region_name')) or ''
else:
record['time_zone'] = ''
record['metro_code'] = const.DMA_MAP.get(record['dma_code'])
params = (record['country_code'], record['region_name'])
record['time_zone'] = time_zone_by_country_and_region(*params)
return record
def _gethostbyname(self, hostname):
if self._databaseType in const.IPV6_EDITIONS:
try:
response = socket.getaddrinfo(hostname, 0, socket.AF_INET6)
family, socktype, proto, canonname, sockaddr = response[0]
address, port, flow, scope = sockaddr
return address
except socket.gaierror:
return ''
else:
return socket.gethostbyname(hostname)
def id_by_addr(self, addr):
"""
Get the country index.
Looks up the index for the country which is the key for
the code and name.
@param addr: The IP address
@type addr: str
@return: network byte order 32-bit integer
@rtype: int
"""
ipnum = util.ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
COUNTY_EDITIONS = (const.COUNTRY_EDITION, const.COUNTRY_EDITION_V6)
if self._databaseType not in COUNTY_EDITIONS:
message = 'Invalid database type, expected Country'
raise GeoIPError(message)
return self._seek_country(ipnum) - const.COUNTRY_BEGIN
def country_code_by_addr(self, addr):
"""
Returns 2-letter country code (e.g. 'US') for specified IP address.
@ -427,31 +444,38 @@ class GeoIP(GeoIPBase):
@rtype: str
"""
try:
if self._databaseType == const.COUNTRY_EDITION:
country_id = self._lookup_country_id(addr)
return const.COUNTRY_CODES[country_id]
elif self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
return self.region_by_addr(addr)['country_code']
else:
raise GeoIPError('Invalid database type; country_* methods expect '\
'Country, City, or Region database')
VALID_EDITIONS = (const.COUNTRY_EDITION, const.COUNTRY_EDITION_V6)
if self._databaseType in VALID_EDITIONS:
ipv = 6 if addr.find(':') >= 0 else 4
if ipv == 4 and self._databaseType != const.COUNTRY_EDITION:
message = 'Invalid database type; expected IPv6 address'
raise ValueError(message)
if ipv == 6 and self._databaseType != const.COUNTRY_EDITION_V6:
message = 'Invalid database type; expected IPv4 address'
raise ValueError(message)
country_id = self.id_by_addr(addr)
return const.COUNTRY_CODES[country_id]
elif self._databaseType in const.REGION_CITY_EDITIONS:
return self.region_by_addr(addr).get('country_code')
message = 'Invalid database type, expected Country, City or Region'
raise GeoIPError(message)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
raise GeoIPError('Failed to lookup address %s' % addr)
def country_code_by_name(self, hostname):
"""
Returns 2-letter country code (e.g. 'US') for specified hostname.
Use this method if you have a Country, Region, or City database.
@param hostname: host name
@param hostname: Hostname
@type hostname: str
@return: 2-letter country code
@rtype: str
"""
addr = socket.gethostbyname(hostname)
addr = self._gethostbyname(hostname)
return self.country_code_by_addr(addr)
def country_name_by_addr(self, addr):
@ -465,34 +489,35 @@ class GeoIP(GeoIPBase):
@rtype: str
"""
try:
if self._databaseType == const.COUNTRY_EDITION:
country_id = self._lookup_country_id(addr)
VALID_EDITIONS = (const.COUNTRY_EDITION, const.COUNTRY_EDITION_V6)
if self._databaseType in VALID_EDITIONS:
country_id = self.id_by_addr(addr)
return const.COUNTRY_NAMES[country_id]
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
return self.record_by_addr(addr)['country_name']
elif self._databaseType in const.CITY_EDITIONS:
return self.record_by_addr(addr).get('country_name')
else:
raise GeoIPError('Invalid database type; country_* methods expect '\
'Country or City database')
message = 'Invalid database type, expected Country or City'
raise GeoIPError(message)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
raise GeoIPError('Failed to lookup address %s' % addr)
def country_name_by_name(self, hostname):
"""
Returns full country name for specified hostname.
Use this method if you have a Country database.
@param hostname: host name
@param hostname: Hostname
@type hostname: str
@return: country name
@rtype: str
"""
addr = socket.gethostbyname(hostname)
addr = self._gethostbyname(hostname)
return self.country_name_by_addr(addr)
def org_by_addr(self, addr):
"""
Lookup the organization (or ISP) for given IP address.
Use this method if you have an Organization/ISP database.
Lookup Organization, ISP or ASNum for given IP address.
Use this method if you have an Organization, ISP or ASNum database.
@param addr: IP address
@type addr: str
@ -500,31 +525,30 @@ class GeoIP(GeoIPBase):
@rtype: str
"""
try:
ipnum = ip2long(addr)
ipnum = util.ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
raise ValueError('Invalid IP address')
if self._databaseType not in (const.ORG_EDITION, const.ISP_EDITION, const.ASNUM_EDITION):
raise GeoIPError('Invalid database type; org_* methods expect '\
'Org/ISP database')
valid = (const.ORG_EDITION, const.ISP_EDITION, const.ASNUM_EDITION, const.ASNUM_EDITION_V6)
if self._databaseType not in valid:
message = 'Invalid database type, expected Org, ISP or ASNum'
raise GeoIPError(message)
return self._get_org(ipnum)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
raise GeoIPError('Failed to lookup address %s' % addr)
def org_by_name(self, hostname):
"""
Lookup the organization (or ISP) for hostname.
Use this method if you have an Organization/ISP database.
@param hostname: host name
@param hostname: Hostname
@type hostname: str
@return: organization or ISP name
@return: Organization or ISP name
@rtype: str
"""
addr = socket.gethostbyname(hostname)
addr = self._gethostbyname(hostname)
return self.org_by_addr(addr)
def record_by_addr(self, addr):
@ -534,38 +558,41 @@ class GeoIP(GeoIPBase):
@param addr: IP address
@type addr: str
@return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
@return: Dictionary with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude, dma_code,
metro_code, area_code, region_name, time_zone
@rtype: dict
"""
try:
ipnum = ip2long(addr)
ipnum = util.ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
raise ValueError('Invalid IP address')
if not self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; record_* methods expect City database')
if self._databaseType not in const.CITY_EDITIONS:
message = 'Invalid database type, expected City'
raise GeoIPError(message)
return self._get_record(ipnum)
rec = self._get_record(ipnum)
if not rec:
return None
return rec
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
raise GeoIPError('Failed to lookup address %s' % addr)
def record_by_name(self, hostname):
"""
Look up the record for a given hostname.
Use this method if you have a City database.
@param hostname: host name
@param hostname: Hostname
@type hostname: str
@return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
@return: Dictionary with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude, dma_code,
metro_code, area_code, region_name, time_zone
@rtype: dict
"""
addr = socket.gethostbyname(hostname)
addr = self._gethostbyname(hostname)
return self.record_by_addr(addr)
def region_by_addr(self, addr):
@ -575,37 +602,33 @@ class GeoIP(GeoIPBase):
@param addr: IP address
@type addr: str
@return: dict containing country_code, region,
and region_name
@return: Dictionary containing country_code, region and region_name
@rtype: dict
"""
try:
ipnum = ip2long(addr)
ipnum = util.ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
raise ValueError('Invalid IP address')
if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; region_* methods expect '\
'Region or City database')
if self._databaseType not in const.REGION_CITY_EDITIONS:
message = 'Invalid database type, expected Region or City'
raise GeoIPError(message)
return self._get_region(ipnum)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
raise GeoIPError('Failed to lookup address %s' % addr)
def region_by_name(self, hostname):
"""
Lookup the region for given hostname.
Use this method if you have a Region database.
@param hostname: host name
@param hostname: Hostname
@type hostname: str
@return: dict containing country_code, region,
and region_name
@return: Dictionary containing country_code, region, and region_name
@rtype: dict
"""
addr = socket.gethostbyname(hostname)
addr = self._gethostbyname(hostname)
return self.region_by_addr(addr)
def time_zone_by_addr(self, addr):
@ -613,35 +636,33 @@ class GeoIP(GeoIPBase):
Look up the time zone for a given IP address.
Use this method if you have a Region or City database.
@param hostname: IP address
@type hostname: str
@param addr: IP address
@type addr: str
@return: Time zone
@rtype: str
"""
try:
ipnum = ip2long(addr)
ipnum = util.ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
raise ValueError('Invalid IP address')
if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; region_* methods expect '\
'Region or City database')
if self._databaseType not in const.CITY_EDITIONS:
message = 'Invalid database type, expected City'
raise GeoIPError(message)
return self._get_record(ipnum)['time_zone']
return self._get_record(ipnum).get('time_zone')
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
raise GeoIPError('Failed to lookup address %s' % addr)
def time_zone_by_name(self, hostname):
"""
Look up the time zone for a given hostname.
Use this method if you have a Region or City database.
@param hostname: host name
@param hostname: Hostname
@type hostname: str
@return: Time zone
@rtype: str
"""
addr = socket.gethostbyname(hostname)
addr = self._gethostbyname(hostname)
return self.time_zone_by_addr(addr)

View File

@ -1,382 +1,431 @@
"""
Constants needed for parsing binary GeoIP databases. It is part of the pygeoip
package.
@author: Jennifer Ennis <zaylea at gmail dot com>
@license:
Copyright(C) 2004 MaxMind LLC
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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>.
"""
GEOIP_STANDARD = 0
GEOIP_MEMORY_CACHE = 1
DMA_MAP = {
500 : 'Portland-Auburn, ME',
501 : 'New York, NY',
502 : 'Binghamton, NY',
503 : 'Macon, GA',
504 : 'Philadelphia, PA',
505 : 'Detroit, MI',
506 : 'Boston, MA',
507 : 'Savannah, GA',
508 : 'Pittsburgh, PA',
509 : 'Ft Wayne, IN',
510 : 'Cleveland, OH',
511 : 'Washington, DC',
512 : 'Baltimore, MD',
513 : 'Flint, MI',
514 : 'Buffalo, NY',
515 : 'Cincinnati, OH',
516 : 'Erie, PA',
517 : 'Charlotte, NC',
518 : 'Greensboro, NC',
519 : 'Charleston, SC',
520 : 'Augusta, GA',
521 : 'Providence, RI',
522 : 'Columbus, GA',
523 : 'Burlington, VT',
524 : 'Atlanta, GA',
525 : 'Albany, GA',
526 : 'Utica-Rome, NY',
527 : 'Indianapolis, IN',
528 : 'Miami, FL',
529 : 'Louisville, KY',
530 : 'Tallahassee, FL',
531 : 'Tri-Cities, TN',
532 : 'Albany-Schenectady-Troy, NY',
533 : 'Hartford, CT',
534 : 'Orlando, FL',
535 : 'Columbus, OH',
536 : 'Youngstown-Warren, OH',
537 : 'Bangor, ME',
538 : 'Rochester, NY',
539 : 'Tampa, FL',
540 : 'Traverse City-Cadillac, MI',
541 : 'Lexington, KY',
542 : 'Dayton, OH',
543 : 'Springfield-Holyoke, MA',
544 : 'Norfolk-Portsmouth, VA',
545 : 'Greenville-New Bern-Washington, NC',
546 : 'Columbia, SC',
547 : 'Toledo, OH',
548 : 'West Palm Beach, FL',
549 : 'Watertown, NY',
550 : 'Wilmington, NC',
551 : 'Lansing, MI',
552 : 'Presque Isle, ME',
553 : 'Marquette, MI',
554 : 'Wheeling, WV',
555 : 'Syracuse, NY',
556 : 'Richmond-Petersburg, VA',
557 : 'Knoxville, TN',
558 : 'Lima, OH',
559 : 'Bluefield-Beckley-Oak Hill, WV',
560 : 'Raleigh-Durham, NC',
561 : 'Jacksonville, FL',
563 : 'Grand Rapids, MI',
564 : 'Charleston-Huntington, WV',
565 : 'Elmira, NY',
566 : 'Harrisburg-Lancaster-Lebanon-York, PA',
567 : 'Greenville-Spartenburg, SC',
569 : 'Harrisonburg, VA',
570 : 'Florence-Myrtle Beach, SC',
571 : 'Ft Myers, FL',
573 : 'Roanoke-Lynchburg, VA',
574 : 'Johnstown-Altoona, PA',
575 : 'Chattanooga, TN',
576 : 'Salisbury, MD',
577 : 'Wilkes Barre-Scranton, PA',
581 : 'Terre Haute, IN',
582 : 'Lafayette, IN',
583 : 'Alpena, MI',
584 : 'Charlottesville, VA',
588 : 'South Bend, IN',
592 : 'Gainesville, FL',
596 : 'Zanesville, OH',
597 : 'Parkersburg, WV',
598 : 'Clarksburg-Weston, WV',
600 : 'Corpus Christi, TX',
602 : 'Chicago, IL',
603 : 'Joplin-Pittsburg, MO',
604 : 'Columbia-Jefferson City, MO',
605 : 'Topeka, KS',
606 : 'Dothan, AL',
609 : 'St Louis, MO',
610 : 'Rockford, IL',
611 : 'Rochester-Mason City-Austin, MN',
612 : 'Shreveport, LA',
613 : 'Minneapolis-St Paul, MN',
616 : 'Kansas City, MO',
617 : 'Milwaukee, WI',
618 : 'Houston, TX',
619 : 'Springfield, MO',
620 : 'Tuscaloosa, AL',
622 : 'New Orleans, LA',
623 : 'Dallas-Fort Worth, TX',
624 : 'Sioux City, IA',
625 : 'Waco-Temple-Bryan, TX',
626 : 'Victoria, TX',
627 : 'Wichita Falls, TX',
628 : 'Monroe, LA',
630 : 'Birmingham, AL',
631 : 'Ottumwa-Kirksville, IA',
632 : 'Paducah, KY',
633 : 'Odessa-Midland, TX',
634 : 'Amarillo, TX',
635 : 'Austin, TX',
636 : 'Harlingen, TX',
637 : 'Cedar Rapids-Waterloo, IA',
638 : 'St Joseph, MO',
639 : 'Jackson, TN',
640 : 'Memphis, TN',
641 : 'San Antonio, TX',
642 : 'Lafayette, LA',
643 : 'Lake Charles, LA',
644 : 'Alexandria, LA',
646 : 'Anniston, AL',
647 : 'Greenwood-Greenville, MS',
648 : 'Champaign-Springfield-Decatur, IL',
649 : 'Evansville, IN',
650 : 'Oklahoma City, OK',
651 : 'Lubbock, TX',
652 : 'Omaha, NE',
656 : 'Panama City, FL',
657 : 'Sherman, TX',
658 : 'Green Bay-Appleton, WI',
659 : 'Nashville, TN',
661 : 'San Angelo, TX',
662 : 'Abilene-Sweetwater, TX',
669 : 'Madison, WI',
670 : 'Ft Smith-Fay-Springfield, AR',
671 : 'Tulsa, OK',
673 : 'Columbus-Tupelo-West Point, MS',
675 : 'Peoria-Bloomington, IL',
676 : 'Duluth, MN',
678 : 'Wichita, KS',
679 : 'Des Moines, IA',
682 : 'Davenport-Rock Island-Moline, IL',
686 : 'Mobile, AL',
687 : 'Minot-Bismarck-Dickinson, ND',
691 : 'Huntsville, AL',
692 : 'Beaumont-Port Author, TX',
693 : 'Little Rock-Pine Bluff, AR',
698 : 'Montgomery, AL',
702 : 'La Crosse-Eau Claire, WI',
705 : 'Wausau-Rhinelander, WI',
709 : 'Tyler-Longview, TX',
710 : 'Hattiesburg-Laurel, MS',
711 : 'Meridian, MS',
716 : 'Baton Rouge, LA',
717 : 'Quincy, IL',
718 : 'Jackson, MS',
722 : 'Lincoln-Hastings, NE',
724 : 'Fargo-Valley City, ND',
725 : 'Sioux Falls, SD',
734 : 'Jonesboro, AR',
736 : 'Bowling Green, KY',
737 : 'Mankato, MN',
740 : 'North Platte, NE',
743 : 'Anchorage, AK',
744 : 'Honolulu, HI',
745 : 'Fairbanks, AK',
746 : 'Biloxi-Gulfport, MS',
747 : 'Juneau, AK',
749 : 'Laredo, TX',
751 : 'Denver, CO',
752 : 'Colorado Springs, CO',
753 : 'Phoenix, AZ',
754 : 'Butte-Bozeman, MT',
755 : 'Great Falls, MT',
756 : 'Billings, MT',
757 : 'Boise, ID',
758 : 'Idaho Falls-Pocatello, ID',
759 : 'Cheyenne, WY',
760 : 'Twin Falls, ID',
762 : 'Missoula, MT',
764 : 'Rapid City, SD',
765 : 'El Paso, TX',
766 : 'Helena, MT',
767 : 'Casper-Riverton, WY',
770 : 'Salt Lake City, UT',
771 : 'Yuma, AZ',
773 : 'Grand Junction, CO',
789 : 'Tucson, AZ',
790 : 'Albuquerque, NM',
798 : 'Glendive, MT',
800 : 'Bakersfield, CA',
801 : 'Eugene, OR',
802 : 'Eureka, CA',
803 : 'Los Angeles, CA',
804 : 'Palm Springs, CA',
807 : 'San Francisco, CA',
810 : 'Yakima-Pasco, WA',
811 : 'Reno, NV',
813 : 'Medford-Klamath Falls, OR',
819 : 'Seattle-Tacoma, WA',
820 : 'Portland, OR',
821 : 'Bend, OR',
825 : 'San Diego, CA',
828 : 'Monterey-Salinas, CA',
839 : 'Las Vegas, NV',
855 : 'Santa Barbara, CA',
862 : 'Sacramento, CA',
866 : 'Fresno, CA',
868 : 'Chico-Redding, CA',
881 : 'Spokane, WA'
}
COUNTRY_CODES = (
'', 'AP', 'EU', 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ',
'AR', 'AS', 'AT', 'AU', 'AW', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH',
'BI', 'BJ', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ', 'CA',
'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',
'CV', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG',
'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'FX', 'GA', 'GB',
'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT',
'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN',
'IO', 'IQ', 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM',
'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS',
'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN',
'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA',
'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA',
'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY',
'QA', 'RE', 'RO', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI',
'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY', 'SZ', 'TC', 'TD',
'TF', 'TG', 'TH', 'TJ', 'TK', 'TM', 'TN', 'TO', 'TL', 'TR', 'TT', 'TV', 'TW',
'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN',
'VU', 'WF', 'WS', 'YE', 'YT', 'RS', 'ZA', 'ZM', 'ME', 'ZW', 'A1', 'A2', 'O1',
'AX', 'GG', 'IM', 'JE', 'BL', 'MF'
)
COUNTRY_CODES3 = (
'','AP','EU','AND','ARE','AFG','ATG','AIA','ALB','ARM','ANT','AGO','AQ','ARG',
'ASM','AUT','AUS','ABW','AZE','BIH','BRB','BGD','BEL','BFA','BGR','BHR','BDI',
'BEN','BMU','BRN','BOL','BRA','BHS','BTN','BV','BWA','BLR','BLZ','CAN','CC',
'COD','CAF','COG','CHE','CIV','COK','CHL','CMR','CHN','COL','CRI','CUB','CPV',
'CX','CYP','CZE','DEU','DJI','DNK','DMA','DOM','DZA','ECU','EST','EGY','ESH',
'ERI','ESP','ETH','FIN','FJI','FLK','FSM','FRO','FRA','FX','GAB','GBR','GRD',
'GEO','GUF','GHA','GIB','GRL','GMB','GIN','GLP','GNQ','GRC','GS','GTM','GUM',
'GNB','GUY','HKG','HM','HND','HRV','HTI','HUN','IDN','IRL','ISR','IND','IO',
'IRQ','IRN','ISL','ITA','JAM','JOR','JPN','KEN','KGZ','KHM','KIR','COM','KNA',
'PRK','KOR','KWT','CYM','KAZ','LAO','LBN','LCA','LIE','LKA','LBR','LSO','LTU',
'LUX','LVA','LBY','MAR','MCO','MDA','MDG','MHL','MKD','MLI','MMR','MNG','MAC',
'MNP','MTQ','MRT','MSR','MLT','MUS','MDV','MWI','MEX','MYS','MOZ','NAM','NCL',
'NER','NFK','NGA','NIC','NLD','NOR','NPL','NRU','NIU','NZL','OMN','PAN','PER',
'PYF','PNG','PHL','PAK','POL','SPM','PCN','PRI','PSE','PRT','PLW','PRY','QAT',
'REU','ROU','RUS','RWA','SAU','SLB','SYC','SDN','SWE','SGP','SHN','SVN','SJM',
'SVK','SLE','SMR','SEN','SOM','SUR','STP','SLV','SYR','SWZ','TCA','TCD','TF',
'TGO','THA','TJK','TKL','TLS','TKM','TUN','TON','TUR','TTO','TUV','TWN','TZA',
'UKR','UGA','UM','USA','URY','UZB','VAT','VCT','VEN','VGB','VIR','VNM','VUT',
'WLF','WSM','YEM','YT','SRB','ZAF','ZMB','MNE','ZWE','A1','A2','O1',
'ALA','GGY','IMN','JEY','BLM','MAF'
)
COUNTRY_NAMES = (
"", "Asia/Pacific Region", "Europe", "Andorra", "United Arab Emirates",
"Afghanistan", "Antigua and Barbuda", "Anguilla", "Albania", "Armenia",
"Netherlands Antilles", "Angola", "Antarctica", "Argentina", "American Samoa",
"Austria", "Australia", "Aruba", "Azerbaijan", "Bosnia and Herzegovina",
"Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria", "Bahrain",
"Burundi", "Benin", "Bermuda", "Brunei Darussalam", "Bolivia", "Brazil",
"Bahamas", "Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize",
"Canada", "Cocos (Keeling) Islands", "Congo, The Democratic Republic of the",
"Central African Republic", "Congo", "Switzerland", "Cote D'Ivoire", "Cook Islands",
"Chile", "Cameroon", "China", "Colombia", "Costa Rica", "Cuba", "Cape Verde",
"Christmas Island", "Cyprus", "Czech Republic", "Germany", "Djibouti",
"Denmark", "Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia",
"Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia", "Finland", "Fiji",
"Falkland Islands (Malvinas)", "Micronesia, Federated States of", "Faroe Islands",
"France", "France, Metropolitan", "Gabon", "United Kingdom",
"Grenada", "Georgia", "French Guiana", "Ghana", "Gibraltar", "Greenland",
"Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece",
"South Georgia and the South Sandwich Islands",
"Guatemala", "Guam", "Guinea-Bissau",
"Guyana", "Hong Kong", "Heard Island and McDonald Islands", "Honduras",
"Croatia", "Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "India",
"British Indian Ocean Territory", "Iraq", "Iran, Islamic Republic of",
"Iceland", "Italy", "Jamaica", "Jordan", "Japan", "Kenya", "Kyrgyzstan",
"Cambodia", "Kiribati", "Comoros", "Saint Kitts and Nevis",
"Korea, Democratic People's Republic of",
"Korea, Republic of", "Kuwait", "Cayman Islands",
"Kazakstan", "Lao People's Democratic Republic", "Lebanon", "Saint Lucia",
"Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg",
"Latvia", "Libyan Arab Jamahiriya", "Morocco", "Monaco", "Moldova, Republic of",
"Madagascar", "Marshall Islands", "Macedonia",
"Mali", "Myanmar", "Mongolia", "Macau", "Northern Mariana Islands",
"Martinique", "Mauritania", "Montserrat", "Malta", "Mauritius", "Maldives",
"Malawi", "Mexico", "Malaysia", "Mozambique", "Namibia", "New Caledonia",
"Niger", "Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway",
"Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru", "French Polynesia",
"Papua New Guinea", "Philippines", "Pakistan", "Poland", "Saint Pierre and Miquelon",
"Pitcairn Islands", "Puerto Rico", "Palestinian Territory",
"Portugal", "Palau", "Paraguay", "Qatar", "Reunion", "Romania",
"Russian Federation", "Rwanda", "Saudi Arabia", "Solomon Islands",
"Seychelles", "Sudan", "Sweden", "Singapore", "Saint Helena", "Slovenia",
"Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino", "Senegal",
"Somalia", "Suriname", "Sao Tome and Principe", "El Salvador", "Syrian Arab Republic",
"Swaziland", "Turks and Caicos Islands", "Chad", "French Southern Territories",
"Togo", "Thailand", "Tajikistan", "Tokelau", "Turkmenistan",
"Tunisia", "Tonga", "Timor-Leste", "Turkey", "Trinidad and Tobago", "Tuvalu",
"Taiwan", "Tanzania, United Republic of", "Ukraine",
"Uganda", "United States Minor Outlying Islands", "United States", "Uruguay",
"Uzbekistan", "Holy See (Vatican City State)", "Saint Vincent and the Grenadines",
"Venezuela", "Virgin Islands, British", "Virgin Islands, U.S.",
"Vietnam", "Vanuatu", "Wallis and Futuna", "Samoa", "Yemen", "Mayotte",
"Serbia", "South Africa", "Zambia", "Montenegro", "Zimbabwe",
"Anonymous Proxy","Satellite Provider","Other",
"Aland Islands","Guernsey","Isle of Man","Jersey","Saint Barthelemy","Saint Martin"
)
# storage / caching flags
STANDARD = 0
MEMORY_CACHE = 1
MMAP_CACHE = 8
# Database structure constants
COUNTRY_BEGIN = 16776960
STATE_BEGIN_REV0 = 16700000
STATE_BEGIN_REV1 = 16000000
STRUCTURE_INFO_MAX_SIZE = 20
DATABASE_INFO_MAX_SIZE = 100
# Database editions
COUNTRY_EDITION = 1
REGION_EDITION_REV0 = 7
REGION_EDITION_REV1 = 3
CITY_EDITION_REV0 = 6
CITY_EDITION_REV1 = 2
ORG_EDITION = 5
ISP_EDITION = 4
PROXY_EDITION = 8
ASNUM_EDITION = 9
NETSPEED_EDITION = 11
COUNTRY_EDITION_V6 = 12
SEGMENT_RECORD_LENGTH = 3
STANDARD_RECORD_LENGTH = 3
ORG_RECORD_LENGTH = 4
MAX_RECORD_LENGTH = 4
MAX_ORG_RECORD_LENGTH = 300
FULL_RECORD_LENGTH = 50
US_OFFSET = 1
CANADA_OFFSET = 677
WORLD_OFFSET = 1353
FIPS_RANGE = 360
# -*- coding: utf-8 -*-
"""
Constants needed for the binary parser. Part of the pygeoip package.
@author: Jennifer Ennis <zaylea@gmail.com>
@license: Copyright(C) 2004 MaxMind LLC
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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>.
"""
from platform import python_version_tuple
PY2 = python_version_tuple()[0] == '2'
PY3 = python_version_tuple()[0] == '3'
GEOIP_STANDARD = 0
GEOIP_MEMORY_CACHE = 1
DMA_MAP = {
500: 'Portland-Auburn, ME',
501: 'New York, NY',
502: 'Binghamton, NY',
503: 'Macon, GA',
504: 'Philadelphia, PA',
505: 'Detroit, MI',
506: 'Boston, MA',
507: 'Savannah, GA',
508: 'Pittsburgh, PA',
509: 'Ft Wayne, IN',
510: 'Cleveland, OH',
511: 'Washington, DC',
512: 'Baltimore, MD',
513: 'Flint, MI',
514: 'Buffalo, NY',
515: 'Cincinnati, OH',
516: 'Erie, PA',
517: 'Charlotte, NC',
518: 'Greensboro, NC',
519: 'Charleston, SC',
520: 'Augusta, GA',
521: 'Providence, RI',
522: 'Columbus, GA',
523: 'Burlington, VT',
524: 'Atlanta, GA',
525: 'Albany, GA',
526: 'Utica-Rome, NY',
527: 'Indianapolis, IN',
528: 'Miami, FL',
529: 'Louisville, KY',
530: 'Tallahassee, FL',
531: 'Tri-Cities, TN',
532: 'Albany-Schenectady-Troy, NY',
533: 'Hartford, CT',
534: 'Orlando, FL',
535: 'Columbus, OH',
536: 'Youngstown-Warren, OH',
537: 'Bangor, ME',
538: 'Rochester, NY',
539: 'Tampa, FL',
540: 'Traverse City-Cadillac, MI',
541: 'Lexington, KY',
542: 'Dayton, OH',
543: 'Springfield-Holyoke, MA',
544: 'Norfolk-Portsmouth, VA',
545: 'Greenville-New Bern-Washington, NC',
546: 'Columbia, SC',
547: 'Toledo, OH',
548: 'West Palm Beach, FL',
549: 'Watertown, NY',
550: 'Wilmington, NC',
551: 'Lansing, MI',
552: 'Presque Isle, ME',
553: 'Marquette, MI',
554: 'Wheeling, WV',
555: 'Syracuse, NY',
556: 'Richmond-Petersburg, VA',
557: 'Knoxville, TN',
558: 'Lima, OH',
559: 'Bluefield-Beckley-Oak Hill, WV',
560: 'Raleigh-Durham, NC',
561: 'Jacksonville, FL',
563: 'Grand Rapids, MI',
564: 'Charleston-Huntington, WV',
565: 'Elmira, NY',
566: 'Harrisburg-Lancaster-Lebanon-York, PA',
567: 'Greenville-Spartenburg, SC',
569: 'Harrisonburg, VA',
570: 'Florence-Myrtle Beach, SC',
571: 'Ft Myers, FL',
573: 'Roanoke-Lynchburg, VA',
574: 'Johnstown-Altoona, PA',
575: 'Chattanooga, TN',
576: 'Salisbury, MD',
577: 'Wilkes Barre-Scranton, PA',
581: 'Terre Haute, IN',
582: 'Lafayette, IN',
583: 'Alpena, MI',
584: 'Charlottesville, VA',
588: 'South Bend, IN',
592: 'Gainesville, FL',
596: 'Zanesville, OH',
597: 'Parkersburg, WV',
598: 'Clarksburg-Weston, WV',
600: 'Corpus Christi, TX',
602: 'Chicago, IL',
603: 'Joplin-Pittsburg, MO',
604: 'Columbia-Jefferson City, MO',
605: 'Topeka, KS',
606: 'Dothan, AL',
609: 'St Louis, MO',
610: 'Rockford, IL',
611: 'Rochester-Mason City-Austin, MN',
612: 'Shreveport, LA',
613: 'Minneapolis-St Paul, MN',
616: 'Kansas City, MO',
617: 'Milwaukee, WI',
618: 'Houston, TX',
619: 'Springfield, MO',
620: 'Tuscaloosa, AL',
622: 'New Orleans, LA',
623: 'Dallas-Fort Worth, TX',
624: 'Sioux City, IA',
625: 'Waco-Temple-Bryan, TX',
626: 'Victoria, TX',
627: 'Wichita Falls, TX',
628: 'Monroe, LA',
630: 'Birmingham, AL',
631: 'Ottumwa-Kirksville, IA',
632: 'Paducah, KY',
633: 'Odessa-Midland, TX',
634: 'Amarillo, TX',
635: 'Austin, TX',
636: 'Harlingen, TX',
637: 'Cedar Rapids-Waterloo, IA',
638: 'St Joseph, MO',
639: 'Jackson, TN',
640: 'Memphis, TN',
641: 'San Antonio, TX',
642: 'Lafayette, LA',
643: 'Lake Charles, LA',
644: 'Alexandria, LA',
646: 'Anniston, AL',
647: 'Greenwood-Greenville, MS',
648: 'Champaign-Springfield-Decatur, IL',
649: 'Evansville, IN',
650: 'Oklahoma City, OK',
651: 'Lubbock, TX',
652: 'Omaha, NE',
656: 'Panama City, FL',
657: 'Sherman, TX',
658: 'Green Bay-Appleton, WI',
659: 'Nashville, TN',
661: 'San Angelo, TX',
662: 'Abilene-Sweetwater, TX',
669: 'Madison, WI',
670: 'Ft Smith-Fay-Springfield, AR',
671: 'Tulsa, OK',
673: 'Columbus-Tupelo-West Point, MS',
675: 'Peoria-Bloomington, IL',
676: 'Duluth, MN',
678: 'Wichita, KS',
679: 'Des Moines, IA',
682: 'Davenport-Rock Island-Moline, IL',
686: 'Mobile, AL',
687: 'Minot-Bismarck-Dickinson, ND',
691: 'Huntsville, AL',
692: 'Beaumont-Port Author, TX',
693: 'Little Rock-Pine Bluff, AR',
698: 'Montgomery, AL',
702: 'La Crosse-Eau Claire, WI',
705: 'Wausau-Rhinelander, WI',
709: 'Tyler-Longview, TX',
710: 'Hattiesburg-Laurel, MS',
711: 'Meridian, MS',
716: 'Baton Rouge, LA',
717: 'Quincy, IL',
718: 'Jackson, MS',
722: 'Lincoln-Hastings, NE',
724: 'Fargo-Valley City, ND',
725: 'Sioux Falls, SD',
734: 'Jonesboro, AR',
736: 'Bowling Green, KY',
737: 'Mankato, MN',
740: 'North Platte, NE',
743: 'Anchorage, AK',
744: 'Honolulu, HI',
745: 'Fairbanks, AK',
746: 'Biloxi-Gulfport, MS',
747: 'Juneau, AK',
749: 'Laredo, TX',
751: 'Denver, CO',
752: 'Colorado Springs, CO',
753: 'Phoenix, AZ',
754: 'Butte-Bozeman, MT',
755: 'Great Falls, MT',
756: 'Billings, MT',
757: 'Boise, ID',
758: 'Idaho Falls-Pocatello, ID',
759: 'Cheyenne, WY',
760: 'Twin Falls, ID',
762: 'Missoula, MT',
764: 'Rapid City, SD',
765: 'El Paso, TX',
766: 'Helena, MT',
767: 'Casper-Riverton, WY',
770: 'Salt Lake City, UT',
771: 'Yuma, AZ',
773: 'Grand Junction, CO',
789: 'Tucson, AZ',
790: 'Albuquerque, NM',
798: 'Glendive, MT',
800: 'Bakersfield, CA',
801: 'Eugene, OR',
802: 'Eureka, CA',
803: 'Los Angeles, CA',
804: 'Palm Springs, CA',
807: 'San Francisco, CA',
810: 'Yakima-Pasco, WA',
811: 'Reno, NV',
813: 'Medford-Klamath Falls, OR',
819: 'Seattle-Tacoma, WA',
820: 'Portland, OR',
821: 'Bend, OR',
825: 'San Diego, CA',
828: 'Monterey-Salinas, CA',
839: 'Las Vegas, NV',
855: 'Santa Barbara, CA',
862: 'Sacramento, CA',
866: 'Fresno, CA',
868: 'Chico-Redding, CA',
881: 'Spokane, WA'
}
COUNTRY_CODES = (
'',
'AP', 'EU', 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ',
'AR', 'AS', 'AT', 'AU', 'AW', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG',
'BH', 'BI', 'BJ', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY',
'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN',
'CO', 'CR', 'CU', 'CV', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO',
'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM',
'FO', 'FR', 'FX', 'GA', 'GB', 'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM',
'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN',
'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT',
'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW',
'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV',
'LY', 'MA', 'MC', 'MD', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP',
'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC',
'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA',
'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW',
'PY', 'QA', 'RE', 'RO', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG',
'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY',
'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TM', 'TN', 'TO', 'TL',
'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA',
'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'RS', 'ZA',
'ZM', 'ME', 'ZW', 'A1', 'A2', 'O1', 'AX', 'GG', 'IM', 'JE', 'BL', 'MF',
'BQ', 'SS'
)
COUNTRY_CODES3 = (
'', 'AP', 'EU', 'AND', 'ARE', 'AFG', 'ATG', 'AIA', 'ALB', 'ARM', 'ANT',
'AGO', 'AQ', 'ARG', 'ASM', 'AUT', 'AUS', 'ABW', 'AZE', 'BIH', 'BRB', 'BGD',
'BEL', 'BFA', 'BGR', 'BHR', 'BDI', 'BEN', 'BMU', 'BRN', 'BOL', 'BRA',
'BHS', 'BTN', 'BV', 'BWA', 'BLR', 'BLZ', 'CAN', 'CC', 'COD', 'CAF', 'COG',
'CHE', 'CIV', 'COK', 'CHL', 'CMR', 'CHN', 'COL', 'CRI', 'CUB', 'CPV', 'CX',
'CYP', 'CZE', 'DEU', 'DJI', 'DNK', 'DMA', 'DOM', 'DZA', 'ECU', 'EST',
'EGY', 'ESH', 'ERI', 'ESP', 'ETH', 'FIN', 'FJI', 'FLK', 'FSM', 'FRO',
'FRA', 'FX', 'GAB', 'GBR', 'GRD', 'GEO', 'GUF', 'GHA', 'GIB', 'GRL', 'GMB',
'GIN', 'GLP', 'GNQ', 'GRC', 'GS', 'GTM', 'GUM', 'GNB', 'GUY', 'HKG', 'HM',
'HND', 'HRV', 'HTI', 'HUN', 'IDN', 'IRL', 'ISR', 'IND', 'IO', 'IRQ', 'IRN',
'ISL', 'ITA', 'JAM', 'JOR', 'JPN', 'KEN', 'KGZ', 'KHM', 'KIR', 'COM',
'KNA', 'PRK', 'KOR', 'KWT', 'CYM', 'KAZ', 'LAO', 'LBN', 'LCA', 'LIE',
'LKA', 'LBR', 'LSO', 'LTU', 'LUX', 'LVA', 'LBY', 'MAR', 'MCO', 'MDA',
'MDG', 'MHL', 'MKD', 'MLI', 'MMR', 'MNG', 'MAC', 'MNP', 'MTQ', 'MRT',
'MSR', 'MLT', 'MUS', 'MDV', 'MWI', 'MEX', 'MYS', 'MOZ', 'NAM', 'NCL',
'NER', 'NFK', 'NGA', 'NIC', 'NLD', 'NOR', 'NPL', 'NRU', 'NIU', 'NZL',
'OMN', 'PAN', 'PER', 'PYF', 'PNG', 'PHL', 'PAK', 'POL', 'SPM', 'PCN',
'PRI', 'PSE', 'PRT', 'PLW', 'PRY', 'QAT', 'REU', 'ROU', 'RUS', 'RWA',
'SAU', 'SLB', 'SYC', 'SDN', 'SWE', 'SGP', 'SHN', 'SVN', 'SJM', 'SVK',
'SLE', 'SMR', 'SEN', 'SOM', 'SUR', 'STP', 'SLV', 'SYR', 'SWZ', 'TCA',
'TCD', 'TF', 'TGO', 'THA', 'TJK', 'TKL', 'TLS', 'TKM', 'TUN', 'TON', 'TUR',
'TTO', 'TUV', 'TWN', 'TZA', 'UKR', 'UGA', 'UM', 'USA', 'URY', 'UZB', 'VAT',
'VCT', 'VEN', 'VGB', 'VIR', 'VNM', 'VUT', 'WLF', 'WSM', 'YEM', 'YT', 'SRB',
'ZAF', 'ZMB', 'MNE', 'ZWE', 'A1', 'A2', 'O1', 'ALA', 'GGY', 'IMN', 'JEY',
'BLM', 'MAF', 'BES', 'SSD'
)
COUNTRY_NAMES = (
'', 'Asia/Pacific Region', 'Europe', 'Andorra', 'United Arab Emirates',
'Afghanistan', 'Antigua and Barbuda', 'Anguilla', 'Albania', 'Armenia',
'Netherlands Antilles', 'Angola', 'Antarctica', 'Argentina',
'American Samoa', 'Austria', 'Australia', 'Aruba', 'Azerbaijan',
'Bosnia and Herzegovina', 'Barbados', 'Bangladesh', 'Belgium',
'Burkina Faso', 'Bulgaria', 'Bahrain', 'Burundi', 'Benin', 'Bermuda',
'Brunei Darussalam', 'Bolivia', 'Brazil', 'Bahamas', 'Bhutan',
'Bouvet Island', 'Botswana', 'Belarus', 'Belize', 'Canada',
'Cocos (Keeling) Islands', 'Congo, The Democratic Republic of the',
'Central African Republic', 'Congo', 'Switzerland', 'Cote D\'Ivoire',
'Cook Islands', 'Chile', 'Cameroon', 'China', 'Colombia', 'Costa Rica',
'Cuba', 'Cape Verde', 'Christmas Island', 'Cyprus', 'Czech Republic',
'Germany', 'Djibouti', 'Denmark', 'Dominica', 'Dominican Republic',
'Algeria', 'Ecuador', 'Estonia', 'Egypt', 'Western Sahara', 'Eritrea',
'Spain', 'Ethiopia', 'Finland', 'Fiji', 'Falkland Islands (Malvinas)',
'Micronesia, Federated States of', 'Faroe Islands', 'France',
'France, Metropolitan', 'Gabon', 'United Kingdom', 'Grenada', 'Georgia',
'French Guiana', 'Ghana', 'Gibraltar', 'Greenland', 'Gambia', 'Guinea',
'Guadeloupe', 'Equatorial Guinea', 'Greece',
'South Georgia and the South Sandwich Islands', 'Guatemala', 'Guam',
'Guinea-Bissau', 'Guyana', 'Hong Kong',
'Heard Island and McDonald Islands', 'Honduras', 'Croatia', 'Haiti',
'Hungary', 'Indonesia', 'Ireland', 'Israel', 'India',
'British Indian Ocean Territory', 'Iraq', 'Iran, Islamic Republic of',
'Iceland', 'Italy', 'Jamaica', 'Jordan', 'Japan', 'Kenya', 'Kyrgyzstan',
'Cambodia', 'Kiribati', 'Comoros', 'Saint Kitts and Nevis',
'Korea, Democratic People\'s Republic of', 'Korea, Republic of', 'Kuwait',
'Cayman Islands', 'Kazakhstan', 'Lao People\'s Democratic Republic',
'Lebanon', 'Saint Lucia', 'Liechtenstein', 'Sri Lanka', 'Liberia',
'Lesotho', 'Lithuania', 'Luxembourg', 'Latvia', 'Libya', 'Morocco',
'Monaco', 'Moldova, Republic of', 'Madagascar', 'Marshall Islands',
'Macedonia', 'Mali', 'Myanmar', 'Mongolia', 'Macau',
'Northern Mariana Islands', 'Martinique', 'Mauritania', 'Montserrat',
'Malta', 'Mauritius', 'Maldives', 'Malawi', 'Mexico', 'Malaysia',
'Mozambique', 'Namibia', 'New Caledonia', 'Niger', 'Norfolk Island',
'Nigeria', 'Nicaragua', 'Netherlands', 'Norway', 'Nepal', 'Nauru', 'Niue',
'New Zealand', 'Oman', 'Panama', 'Peru', 'French Polynesia',
'Papua New Guinea', 'Philippines', 'Pakistan', 'Poland',
'Saint Pierre and Miquelon', 'Pitcairn Islands', 'Puerto Rico',
'Palestinian Territory', 'Portugal', 'Palau', 'Paraguay', 'Qatar',
'Reunion', 'Romania', 'Russian Federation', 'Rwanda', 'Saudi Arabia',
'Solomon Islands', 'Seychelles', 'Sudan', 'Sweden', 'Singapore',
'Saint Helena', 'Slovenia', 'Svalbard and Jan Mayen', 'Slovakia',
'Sierra Leone', 'San Marino', 'Senegal', 'Somalia', 'Suriname',
'Sao Tome and Principe', 'El Salvador', 'Syrian Arab Republic',
'Swaziland', 'Turks and Caicos Islands', 'Chad',
'French Southern Territories', 'Togo', 'Thailand', 'Tajikistan', 'Tokelau',
'Turkmenistan', 'Tunisia', 'Tonga', 'Timor-Leste', 'Turkey',
'Trinidad and Tobago', 'Tuvalu', 'Taiwan', 'Tanzania, United Republic of',
'Ukraine', 'Uganda', 'United States Minor Outlying Islands',
'United States', 'Uruguay', 'Uzbekistan', 'Holy See (Vatican City State)',
'Saint Vincent and the Grenadines', 'Venezuela', 'Virgin Islands, British',
'Virgin Islands, U.S.', 'Vietnam', 'Vanuatu', 'Wallis and Futuna', 'Samoa',
'Yemen', 'Mayotte', 'Serbia', 'South Africa', 'Zambia', 'Montenegro',
'Zimbabwe', 'Anonymous Proxy', 'Satellite Provider', 'Other',
'Aland Islands', 'Guernsey', 'Isle of Man', 'Jersey', 'Saint Barthelemy',
'Saint Martin', 'Bonaire, Sint Eustatius and Saba', 'South Sudan'
)
CONTINENT_NAMES = (
'--', 'AS', 'EU', 'EU', 'AS', 'AS', 'NA', 'NA', 'EU', 'AS', 'NA', 'AF',
'AN', 'SA', 'OC', 'EU', 'OC', 'NA', 'AS', 'EU', 'NA', 'AS', 'EU', 'AF',
'EU', 'AS', 'AF', 'AF', 'NA', 'AS', 'SA', 'SA', 'NA', 'AS', 'AN', 'AF',
'EU', 'NA', 'NA', 'AS', 'AF', 'AF', 'AF', 'EU', 'AF', 'OC', 'SA', 'AF',
'AS', 'SA', 'NA', 'NA', 'AF', 'AS', 'AS', 'EU', 'EU', 'AF', 'EU', 'NA',
'NA', 'AF', 'SA', 'EU', 'AF', 'AF', 'AF', 'EU', 'AF', 'EU', 'OC', 'SA',
'OC', 'EU', 'EU', 'NA', 'AF', 'EU', 'NA', 'AS', 'SA', 'AF', 'EU', 'NA',
'AF', 'AF', 'NA', 'AF', 'EU', 'AN', 'NA', 'OC', 'AF', 'SA', 'AS', 'AN',
'NA', 'EU', 'NA', 'EU', 'AS', 'EU', 'AS', 'AS', 'AS', 'AS', 'AS', 'EU',
'EU', 'NA', 'AS', 'AS', 'AF', 'AS', 'AS', 'OC', 'AF', 'NA', 'AS', 'AS',
'AS', 'NA', 'AS', 'AS', 'AS', 'NA', 'EU', 'AS', 'AF', 'AF', 'EU', 'EU',
'EU', 'AF', 'AF', 'EU', 'EU', 'AF', 'OC', 'EU', 'AF', 'AS', 'AS', 'AS',
'OC', 'NA', 'AF', 'NA', 'EU', 'AF', 'AS', 'AF', 'NA', 'AS', 'AF', 'AF',
'OC', 'AF', 'OC', 'AF', 'NA', 'EU', 'EU', 'AS', 'OC', 'OC', 'OC', 'AS',
'NA', 'SA', 'OC', 'OC', 'AS', 'AS', 'EU', 'NA', 'OC', 'NA', 'AS', 'EU',
'OC', 'SA', 'AS', 'AF', 'EU', 'EU', 'AF', 'AS', 'OC', 'AF', 'AF', 'EU',
'AS', 'AF', 'EU', 'EU', 'EU', 'AF', 'EU', 'AF', 'AF', 'SA', 'AF', 'NA',
'AS', 'AF', 'NA', 'AF', 'AN', 'AF', 'AS', 'AS', 'OC', 'AS', 'AF', 'OC',
'AS', 'EU', 'NA', 'OC', 'AS', 'AF', 'EU', 'AF', 'OC', 'NA', 'SA', 'AS',
'EU', 'NA', 'SA', 'NA', 'NA', 'AS', 'OC', 'OC', 'OC', 'AS', 'AF', 'EU',
'AF', 'AF', 'EU', 'AF', '--', '--', '--', 'EU', 'EU', 'EU', 'EU', 'NA',
'NA', 'NA', 'AF'
)
# storage / caching flags
STANDARD = 0
MEMORY_CACHE = 1
MMAP_CACHE = 8
# Database structure constants
COUNTRY_BEGIN = 16776960
STATE_BEGIN_REV0 = 16700000
STATE_BEGIN_REV1 = 16000000
STRUCTURE_INFO_MAX_SIZE = 20
DATABASE_INFO_MAX_SIZE = 100
# Database editions
COUNTRY_EDITION = 1
COUNTRY_EDITION_V6 = 12
REGION_EDITION_REV0 = 7
REGION_EDITION_REV1 = 3
CITY_EDITION_REV0 = 6
CITY_EDITION_REV1 = 2
CITY_EDITION_REV1_V6 = 30
ORG_EDITION = 5
ISP_EDITION = 4
ASNUM_EDITION = 9
ASNUM_EDITION_V6 = 21
# Not yet supported databases
PROXY_EDITION = 8
NETSPEED_EDITION = 11
# Collection of databases
IPV6_EDITIONS = (COUNTRY_EDITION_V6, ASNUM_EDITION_V6, CITY_EDITION_REV1_V6)
CITY_EDITIONS = (CITY_EDITION_REV0, CITY_EDITION_REV1, CITY_EDITION_REV1_V6)
REGION_EDITIONS = (REGION_EDITION_REV0, REGION_EDITION_REV1)
REGION_CITY_EDITIONS = REGION_EDITIONS + CITY_EDITIONS
SEGMENT_RECORD_LENGTH = 3
STANDARD_RECORD_LENGTH = 3
ORG_RECORD_LENGTH = 4
MAX_RECORD_LENGTH = 4
MAX_ORG_RECORD_LENGTH = 300
FULL_RECORD_LENGTH = 50
US_OFFSET = 1
CANADA_OFFSET = 677
WORLD_OFFSET = 1353
FIPS_RANGE = 360
ENCODING = 'iso-8859-1'

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +1,36 @@
"""
Misc. utility functions. It is part of the pygeoip package.
@author: Jennifer Ennis <zaylea at gmail dot com>
@license:
Copyright(C) 2004 MaxMind LLC
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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>.
"""
import six
def ip2long(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
# -*- coding: utf-8 -*-
"""
Utility functions. Part of the pygeoip package.
@author: Jennifer Ennis <zaylea@gmail.com>
@license: Copyright(C) 2004 MaxMind LLC
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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>.
"""
import socket
import binascii
def ip2long(ip):
"""
Wrapper function for IPv4 and IPv6 converters
@param ip: IPv4 or IPv6 address
@type ip: str
"""
try:
return int(binascii.hexlify(socket.inet_aton(ip)), 16)
except socket.error:
return int(binascii.hexlify(socket.inet_pton(socket.AF_INET6, ip)), 16)