diff --git a/django/contrib/gis/geoip/base.py b/django/contrib/gis/geoip/base.py
index e00e0a4..6bca923 100644
a
|
b
|
import re
|
3 | 3 | from ctypes import c_char_p |
4 | 4 | |
5 | 5 | from django.core.validators import ipv4_re |
| 6 | from django.utils.ipv6 import is_valid_ipv6_address |
6 | 7 | from django.contrib.gis.geoip.libgeoip import GEOIP_SETTINGS |
7 | 8 | from django.contrib.gis.geoip.prototypes import ( |
8 | 9 | GeoIPRecord, GeoIPTag, GeoIP_open, GeoIP_delete, GeoIP_database_info, |
9 | 10 | GeoIP_lib_version, GeoIP_record_by_addr, GeoIP_record_by_name, |
10 | 11 | GeoIP_country_code_by_addr, GeoIP_country_code_by_name, |
11 | | GeoIP_country_name_by_addr, GeoIP_country_name_by_name) |
| 12 | GeoIP_country_name_by_addr, GeoIP_country_name_by_name, |
| 13 | GeoIP_country_code_by_addr_v6, GeoIP_country_name_by_addr_v6, |
| 14 | GeoIP_record_by_addr_v6) |
12 | 15 | |
13 | 16 | # Regular expressions for recognizing the GeoIP free database editions. |
14 | 17 | free_regex = re.compile(r'^GEO-\d{3}FREE') |
… |
… |
class GeoIP(object):
|
46 | 49 | |
47 | 50 | # Paths to the city & country binary databases. |
48 | 51 | _city_file = '' |
| 52 | _city6_file = '' |
49 | 53 | _country_file = '' |
| 54 | _country6_file = '' |
50 | 55 | |
51 | 56 | # Initially, pointers to GeoIP file references are NULL. |
52 | 57 | _city = None |
| 58 | _city6 = None |
53 | 59 | _country = None |
| 60 | _country6 = None |
54 | 61 | |
55 | 62 | def __init__(self, path=None, cache=0, country=None, city=None): |
56 | 63 | """ |
… |
… |
class GeoIP(object):
|
98 | 105 | self._country = GeoIP_open(country_db, cache) |
99 | 106 | self._country_file = country_db |
100 | 107 | |
| 108 | country6_db = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY6', 'GeoIPv6.dat')) |
| 109 | if os.path.isfile(country6_db): |
| 110 | self._country6 = GeoIP_open(country6_db, cache) |
| 111 | self._country6_file = country6_db |
| 112 | |
101 | 113 | city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat')) |
102 | 114 | if os.path.isfile(city_db): |
103 | 115 | self._city = GeoIP_open(city_db, cache) |
104 | 116 | self._city_file = city_db |
| 117 | |
| 118 | city6_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY6', 'GeoLiteCityv6.dat')) |
| 119 | if os.path.isfile(city6_db): |
| 120 | self._city6 = GeoIP_open(city6_db, cache) |
| 121 | self._city6_file = city6_db |
105 | 122 | elif os.path.isfile(path): |
106 | 123 | # Otherwise, some detective work will be needed to figure |
107 | 124 | # out whether the given database path is for the GeoIP country |
… |
… |
class GeoIP(object):
|
124 | 141 | def __del__(self): |
125 | 142 | # Cleaning any GeoIP file handles lying around. |
126 | 143 | if self._country: GeoIP_delete(self._country) |
| 144 | if self._country6: GeoIP_delete(self._country6) |
127 | 145 | if self._city: GeoIP_delete(self._city) |
| 146 | if self._city6: GeoIP_delete(self._city6) |
128 | 147 | |
129 | 148 | def _check_query(self, query, country=False, city=False, city_or_country=False): |
130 | 149 | "Helper routine for checking the query and database availability." |
… |
… |
class GeoIP(object):
|
156 | 175 | if ipv4_re.match(query): |
157 | 176 | # If an IP address was passed in |
158 | 177 | return GeoIP_record_by_addr(self._city, c_char_p(query)) |
| 178 | elif is_valid_ipv6_address(query) and self._city6: |
| 179 | # If an IPv6 address was passed in |
| 180 | return GeoIP_record_by_addr_v6(self._city6, c_char_p(query)) |
159 | 181 | else: |
160 | 182 | # If a FQDN was passed in. |
161 | 183 | return GeoIP_record_by_name(self._city, c_char_p(query)) |
… |
… |
class GeoIP(object):
|
163 | 185 | def country_code(self, query): |
164 | 186 | "Returns the country code for the given IP Address or FQDN." |
165 | 187 | query = self._check_query(query, city_or_country=True) |
166 | | if self._country: |
| 188 | if self._country6 and is_valid_ipv6_address(query): |
| 189 | return GeoIP_country_code_by_addr_v6(self._country6, query) |
| 190 | elif self._country: |
167 | 191 | if ipv4_re.match(query): |
168 | 192 | return GeoIP_country_code_by_addr(self._country, query) |
169 | 193 | else: |
… |
… |
class GeoIP(object):
|
174 | 198 | def country_name(self, query): |
175 | 199 | "Returns the country name for the given IP Address or FQDN." |
176 | 200 | query = self._check_query(query, city_or_country=True) |
177 | | if self._country: |
| 201 | if self._country6 and is_valid_ipv6_address(query): |
| 202 | return GeoIP_country_name_by_addr_v6(self._country6, query) |
| 203 | elif self._country: |
178 | 204 | if ipv4_re.match(query): |
179 | 205 | return GeoIP_country_name_by_addr(self._country, query) |
180 | 206 | else: |
diff --git a/django/contrib/gis/geoip/prototypes.py b/django/contrib/gis/geoip/prototypes.py
index 1cec0d5..d74ca3e 100644
a
|
b
|
def record_output(func):
|
73 | 73 | return func |
74 | 74 | GeoIP_record_by_addr = record_output(lgeoip.GeoIP_record_by_addr) |
75 | 75 | GeoIP_record_by_name = record_output(lgeoip.GeoIP_record_by_name) |
| 76 | GeoIP_record_by_addr_v6 = record_output(lgeoip.GeoIP_record_by_addr_v6) |
76 | 77 | |
77 | 78 | |
78 | 79 | # For opening & closing GeoIP database files. |
… |
… |
GeoIP_country_code_by_addr = string_output(lgeoip.GeoIP_country_code_by_addr)
|
107 | 108 | GeoIP_country_code_by_name = string_output(lgeoip.GeoIP_country_code_by_name) |
108 | 109 | GeoIP_country_name_by_addr = string_output(lgeoip.GeoIP_country_name_by_addr) |
109 | 110 | GeoIP_country_name_by_name = string_output(lgeoip.GeoIP_country_name_by_name) |
| 111 | GeoIP_country_code_by_addr_v6 = string_output(lgeoip.GeoIP_country_code_by_addr_v6) |
| 112 | GeoIP_country_name_by_addr_v6 = string_output(lgeoip.GeoIP_country_name_by_addr_v6) |
diff --git a/django/contrib/gis/geoip/tests.py b/django/contrib/gis/geoip/tests.py
index 6e1f157..e3be454 100644
a
|
b
|
class GeoIPTest(unittest.TestCase):
|
107 | 107 | d = g.country(u'whitehouse.gov') |
108 | 108 | self.assertEqual(u'US', d['country_code']) |
109 | 109 | |
| 110 | def test07_ipv6_query(self): |
| 111 | "Testing that GeoIP can lookup ipv6 addresses." |
| 112 | g = GeoIP() |
| 113 | d = g.city('2a03:2880:2110:3f01:face:b00c::') |
| 114 | self.assertNotEqual(d, None) |
110 | 115 | |
111 | 116 | def suite(): |
112 | 117 | s = unittest.TestSuite() |