diff --git a/django/contrib/gis/geoip/base.py b/django/contrib/gis/geoip/base.py
index e00e0a4..96fcc7a 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, |
… |
… |
class GeoIP(object):
|
46 | 47 | |
47 | 48 | # Paths to the city & country binary databases. |
48 | 49 | _city_file = '' |
| 50 | _city6_file = '' |
49 | 51 | _country_file = '' |
| 52 | _country6_file = '' |
50 | 53 | |
51 | 54 | # Initially, pointers to GeoIP file references are NULL. |
52 | 55 | _city = None |
| 56 | _city6 = None |
53 | 57 | _country = None |
| 58 | _country6 = None |
54 | 59 | |
55 | 60 | def __init__(self, path=None, cache=0, country=None, city=None): |
56 | 61 | """ |
… |
… |
class GeoIP(object):
|
98 | 103 | self._country = GeoIP_open(country_db, cache) |
99 | 104 | self._country_file = country_db |
100 | 105 | |
| 106 | country6_db = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY6', 'GeoIPv6.dat')) |
| 107 | if os.path.isfile(country6_db): |
| 108 | self._country6 = GeoIP_open(country6_db, cache) |
| 109 | self._country6_file = country6_db |
| 110 | |
101 | 111 | city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat')) |
102 | 112 | if os.path.isfile(city_db): |
103 | 113 | self._city = GeoIP_open(city_db, cache) |
104 | 114 | self._city_file = city_db |
| 115 | |
| 116 | city6_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY6', 'GeoLiteCityv6.dat')) |
| 117 | if os.path.isfile(city6_db): |
| 118 | self._city6 = GeoIP_open(city6_db, cache) |
| 119 | self._city6_file = city6_db |
105 | 120 | elif os.path.isfile(path): |
106 | 121 | # Otherwise, some detective work will be needed to figure |
107 | 122 | # out whether the given database path is for the GeoIP country |
… |
… |
class GeoIP(object):
|
124 | 139 | def __del__(self): |
125 | 140 | # Cleaning any GeoIP file handles lying around. |
126 | 141 | if self._country: GeoIP_delete(self._country) |
| 142 | if self._country6: GeoIP_delete(self._country6) |
127 | 143 | if self._city: GeoIP_delete(self._city) |
| 144 | if self._city6: GeoIP_delete(self._city6) |
128 | 145 | |
129 | 146 | def _check_query(self, query, country=False, city=False, city_or_country=False): |
130 | 147 | "Helper routine for checking the query and database availability." |
… |
… |
class GeoIP(object):
|
156 | 173 | if ipv4_re.match(query): |
157 | 174 | # If an IP address was passed in |
158 | 175 | return GeoIP_record_by_addr(self._city, c_char_p(query)) |
| 176 | elif is_valid_ipv6_address(query): |
| 177 | # If an IPv6 address was passed in |
| 178 | return GeoIP_record_by_addr(self._city6, c_char_p(query)) |
159 | 179 | else: |
160 | 180 | # If a FQDN was passed in. |
161 | 181 | return GeoIP_record_by_name(self._city, c_char_p(query)) |
… |
… |
class GeoIP(object):
|
166 | 186 | if self._country: |
167 | 187 | if ipv4_re.match(query): |
168 | 188 | return GeoIP_country_code_by_addr(self._country, query) |
| 189 | elif is_valid_ipv6_address(query): |
| 190 | return GeoIP_country_code_by_addr(self._country6, query) |
169 | 191 | else: |
170 | 192 | return GeoIP_country_code_by_name(self._country, query) |
171 | 193 | else: |
diff --git a/django/contrib/gis/geoip/tests.py b/django/contrib/gis/geoip/tests.py
index a629d86..6ff86e5 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() |