diff --git a/django/contrib/gis/geoip/base.py b/django/contrib/gis/geoip/base.py
index 944240c..7ae846f 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 | from django.utils import six |
14 | 17 | |
… |
… |
class GeoIP(object):
|
48 | 51 | |
49 | 52 | # Paths to the city & country binary databases. |
50 | 53 | _city_file = '' |
| 54 | _city6_file = '' |
51 | 55 | _country_file = '' |
| 56 | _country6_file = '' |
52 | 57 | |
53 | 58 | # Initially, pointers to GeoIP file references are NULL. |
54 | 59 | _city = None |
| 60 | _city6 = None |
55 | 61 | _country = None |
56 | 62 | |
57 | 63 | def __init__(self, path=None, cache=0, country=None, city=None): |
… |
… |
class GeoIP(object):
|
100 | 106 | self._country = GeoIP_open(country_db, cache) |
101 | 107 | self._country_file = country_db |
102 | 108 | |
| 109 | country6_db = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY6', 'GeoIPv6.dat')) |
| 110 | if os.path.isfile(country6_db): |
| 111 | self._country6 = GeoIP_open(country6_db, cache) |
| 112 | self._country6_file = country6_db |
| 113 | |
103 | 114 | city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat')) |
104 | 115 | if os.path.isfile(city_db): |
105 | 116 | self._city = GeoIP_open(city_db, cache) |
106 | 117 | self._city_file = city_db |
| 118 | |
| 119 | city6_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY6', 'GeoLiteCityv6.dat')) |
| 120 | if os.path.isfile(city6_db): |
| 121 | self._city6 = GeoIP_open(city6_db, cache) |
| 122 | self._city6_file = city6_db |
| 123 | |
107 | 124 | elif os.path.isfile(path): |
108 | 125 | # Otherwise, some detective work will be needed to figure |
109 | 126 | # out whether the given database path is for the GeoIP country |
… |
… |
class GeoIP(object):
|
126 | 143 | def __del__(self): |
127 | 144 | # Cleaning any GeoIP file handles lying around. |
128 | 145 | if self._country: GeoIP_delete(self._country) |
| 146 | if self._country6: GeoIP_delete(self._country6) |
129 | 147 | if self._city: GeoIP_delete(self._city) |
| 148 | if self._city6: GeoIP_delete(self._city6) |
130 | 149 | |
131 | 150 | def _check_query(self, query, country=False, city=False, city_or_country=False): |
132 | 151 | "Helper routine for checking the query and database availability." |
… |
… |
class GeoIP(object):
|
158 | 177 | if ipv4_re.match(query): |
159 | 178 | # If an IP address was passed in |
160 | 179 | return GeoIP_record_by_addr(self._city, c_char_p(query)) |
| 180 | elif is_valid_ipv6_address(query) and self._city6: |
| 181 | # If an IPv6 address was passed in |
| 182 | return GeoIP_record_by_addr_v6(self._city6, c_char_p(query)) |
161 | 183 | else: |
162 | 184 | # If a FQDN was passed in. |
163 | 185 | return GeoIP_record_by_name(self._city, c_char_p(query)) |
… |
… |
class GeoIP(object):
|
165 | 187 | def country_code(self, query): |
166 | 188 | "Returns the country code for the given IP Address or FQDN." |
167 | 189 | query = self._check_query(query, city_or_country=True) |
168 | | if self._country: |
| 190 | if self._country6 and is_valid_ipv6_address(query): |
| 191 | return GeoIP_country_code_by_addr_v6(self._country6, query) |
| 192 | elif self._country: |
169 | 193 | if ipv4_re.match(query): |
170 | 194 | return GeoIP_country_code_by_addr(self._country, query) |
171 | 195 | else: |
… |
… |
class GeoIP(object):
|
176 | 200 | def country_name(self, query): |
177 | 201 | "Returns the country name for the given IP Address or FQDN." |
178 | 202 | query = self._check_query(query, city_or_country=True) |
179 | | if self._country: |
| 203 | if self._country6 and is_valid_ipv6_address(query): |
| 204 | return GeoIP_country_name_by_addr_v6(self._country6, query) |
| 205 | elif self._country: |
180 | 206 | if ipv4_re.match(query): |
181 | 207 | return GeoIP_country_name_by_addr(self._country, query) |
182 | 208 | else: |
diff --git a/django/contrib/gis/geoip/prototypes.py b/django/contrib/gis/geoip/prototypes.py
index 1cec0d5..0bbea3d 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 | | |
| 76 | GeoIP_record_by_addr_v6 = record_output(lgeoip.GeoIP_record_by_addr_v6) |
77 | 77 | |
78 | 78 | # For opening & closing GeoIP database files. |
79 | 79 | GeoIP_open = lgeoip.GeoIP_open |
… |
… |
def string_output(func):
|
106 | 106 | GeoIP_country_code_by_addr = string_output(lgeoip.GeoIP_country_code_by_addr) |
107 | 107 | GeoIP_country_code_by_name = string_output(lgeoip.GeoIP_country_code_by_name) |
108 | 108 | GeoIP_country_name_by_addr = string_output(lgeoip.GeoIP_country_name_by_addr) |
| 109 | GeoIP_country_code_by_addr_v6 = string_output(lgeoip.GeoIP_country_code_by_addr_v6) |
| 110 | GeoIP_country_name_by_addr_v6 = string_output(lgeoip.GeoIP_country_name_by_addr_v6) |
109 | 111 | GeoIP_country_name_by_name = string_output(lgeoip.GeoIP_country_name_by_name) |
diff --git a/django/contrib/gis/geoip/tests.py b/django/contrib/gis/geoip/tests.py
index e53230d..f20e363 100644
a
|
b
|
class GeoIPTest(unittest.TestCase):
|
105 | 105 | d = g.city('62.224.93.23') |
106 | 106 | self.assertEqual('Schümberg', d['city']) |
107 | 107 | |
| 108 | def test07_ipv6_query(self): |
| 109 | "Testing that GeoIP can lookup ipv6 addresses." |
| 110 | g = GeoIP() |
| 111 | d = g.city('2a03:2880:2110:3f01:face:b00c::') |
| 112 | self.assertNotEqual(d, None) |
| 113 | |
108 | 114 | def test06_unicode_query(self): |
109 | 115 | "Testing that GeoIP accepts unicode string queries, see #17059." |
110 | 116 | g = GeoIP() |