Skip to content

Commit 4d57900

Browse files
Merge pull request #34 from ipdata/claude/fix-api-key-env-var-j6bTt
Fix _normalize_ip_key to properly normalize IP addresses
2 parents 15c5f89 + 3ee3829 commit 4d57900

File tree

1 file changed

+30
-9
lines changed

1 file changed

+30
-9
lines changed

src/ipdata/iptrie.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
from __future__ import annotations
1717

18-
import ipaddress
1918
import socket
2019
from collections.abc import Iterator
2120
from typing import TypeVar, Generic
@@ -53,18 +52,40 @@ def _normalize_ip_key(key: str) -> tuple[str, bool]:
5352
if not key:
5453
raise InvalidIPError("Key cannot be empty")
5554

56-
addr = key.rsplit("/", 1)[0] if "/" in key else key
57-
55+
if "/" in key:
56+
addr_str, sep, prefix_str = key.rpartition("/")
57+
try:
58+
prefix_len = int(prefix_str)
59+
except ValueError:
60+
raise InvalidIPError(f"Invalid IP address or network: {key!r}")
61+
else:
62+
addr_str = key
63+
prefix_len = -1
64+
65+
# Try IPv4
5866
try:
59-
socket.inet_pton(socket.AF_INET, addr)
60-
return key, False
61-
except socket.error:
67+
packed = socket.inet_pton(socket.AF_INET, addr_str)
68+
if prefix_len >= 0:
69+
if prefix_len > 32:
70+
raise InvalidIPError(f"Invalid IP address or network: {key!r}")
71+
mask = (0xFFFFFFFF << (32 - prefix_len)) & 0xFFFFFFFF
72+
masked = (int.from_bytes(packed, "big") & mask).to_bytes(4, "big")
73+
return f"{socket.inet_ntop(socket.AF_INET, masked)}/{prefix_len}", False
74+
return addr_str, False
75+
except OSError:
6276
pass
6377

78+
# Try IPv6
6479
try:
65-
socket.inet_pton(socket.AF_INET6, addr)
66-
return key, True
67-
except socket.error:
80+
packed = socket.inet_pton(socket.AF_INET6, addr_str)
81+
if prefix_len >= 0:
82+
if prefix_len > 128:
83+
raise InvalidIPError(f"Invalid IP address or network: {key!r}")
84+
mask = ((1 << 128) - 1) << (128 - prefix_len)
85+
masked = (int.from_bytes(packed, "big") & mask).to_bytes(16, "big")
86+
return f"{socket.inet_ntop(socket.AF_INET6, masked)}/{prefix_len}", True
87+
return socket.inet_ntop(socket.AF_INET6, packed), True
88+
except OSError:
6889
raise InvalidIPError(f"Invalid IP address or network: {key!r}")
6990

7091

0 commit comments

Comments
 (0)