Skip to content

Commit

Permalink
AddressNotFoundError: add .network (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
illes committed Jun 21, 2022
1 parent 115d1ed commit 845eaca
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 2 deletions.
25 changes: 25 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,31 @@ or there is a bug in the reader, a ``maxminddb.InvalidDatabaseError`` will be
raised with a description of the problem. If an IP address is not in the
database, a ``AddressNotFoundError`` will be raised.

``AddressNotFoundError`` references the largest subnet where no address would be
found. This can be used to efficiently enumerate entire subnets:

.. code-block:: python
import geoip2.database
import geoip2.errors
import ipaddress
# This creates a Reader object. You should use the same object
# across multiple requests as creation of it is expensive.
with geoip2.database.Reader('/path/to/GeoLite2-ASN.mmdb') as reader:
network = ipaddress.ip_network("192.128.0.0/15")
ip_address = network[0]
while ip_address in network:
try:
response = reader.asn(ip_address)
response_network = response.network
except geoip2.errors.AddressNotFoundError as e:
response = None
response_network = e.network
print(f"{response_network}: {response!r}")
ip_address = response_network[-1] + 1 # move to next subnet
Values to use for Database or Dictionary Keys
---------------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions geoip2/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ def _get(self, database_type: str, ip_address: IPAddress) -> Any:
if record is None:
raise geoip2.errors.AddressNotFoundError(
f"The address {ip_address} is not in the database.",
str(ip_address),
prefix_len,
)
return record, prefix_len

Expand Down
39 changes: 37 additions & 2 deletions geoip2/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"""

from typing import Optional
import ipaddress

from typing import Optional, Union


class GeoIP2Error(RuntimeError):
Expand All @@ -17,7 +19,40 @@ class GeoIP2Error(RuntimeError):


class AddressNotFoundError(GeoIP2Error):
"""The address you were looking up was not found."""
"""The address you were looking up was not found.
.. attribute:: ip_address
The IP address used in the lookup.
:type: str
.. attribute:: network
The network associated with the error. In particular, this is the
largest network where no address would be found.
:type: ipaddress.IPv4Network or ipaddress.IPv6Network
"""

def __init__(
self,
message: str,
ip_address: Optional[str] = None,
prefix_len: Optional[int] = None,
) -> None:
super().__init__(message)
self.ip_address = ip_address
self._prefix_len = prefix_len

@property
def network(self) -> Optional[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
"""The network for the error"""

if self.ip_address is None or self._prefix_len is None:
return None
return ipaddress.ip_network(f"{self.ip_address}/{self._prefix_len}", False)


class AuthenticationError(GeoIP2Error):
Expand Down
13 changes: 13 additions & 0 deletions tests/database_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
sys.path.append("..")

import geoip2.database
import geoip2.errors
import maxminddb

try:
Expand Down Expand Up @@ -38,6 +39,18 @@ def test_unknown_address(self) -> None:
reader.city("10.10.10.10")
reader.close()

def test_unknown_address_network(self) -> None:
reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb")
try:
reader.city("10.10.10.10")
self.fail("Expected AddressNotFoundError")
except geoip2.errors.AddressNotFoundError as e:
self.assertEqual(e.network, ipaddress.ip_network("10.0.0.0/8"))
except Exception as e:
self.fail(f"Expected AddressNotFoundError, got {type(e)}: {str(e)}")
finally:
reader.close()

def test_wrong_database(self) -> None:
reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb")
with self.assertRaisesRegex(
Expand Down

0 comments on commit 845eaca

Please sign in to comment.