geoip/src/utils.py
"""
Shared datastructures and constants.
"""
from dataclasses import dataclass
from ipaddress import IPv4Address, IPv4Network
from typing import Dict, List, Final, Any, Union
@dataclass(frozen=True)
class IPv4Range:
start: IPv4Address
end: IPv4Address
@classmethod
def from_str(cls, start: str, end: str) -> 'IPv4Range':
return cls(start=IPv4Address(start), end=IPv4Address(end))
@classmethod
def from_mask_str(cls, net: str, strict=True) -> 'IPv4Range':
prefix: IPv4Network = IPv4Network(net, strict=strict)
return cls(start=prefix.network_address, end=prefix.broadcast_address)
@classmethod
def from_range_str(cls, net: str) -> 'IPv4Range':
parts: List[str] = net.split("-", maxsplit=1)
return cls.from_str(parts[0].strip(), parts[1].strip())
def __post_init__(self) -> None:
if self.start > self.end:
raise ValueError(str(self))
def __str__(self) -> str:
return f"{self.start}-{self.end}"
def __lt__(self, other: 'IPv4Range') -> bool:
return (self.start, self.end) < (other.start, other.end)
def __contains__(self, other: Union[IPv4Address, 'IPv4Range']) -> bool:
if isinstance(other, IPv4Address):
return self.start <= other <= self.end
return self.start <= other.start and other.end <= self.end
@dataclass(frozen=True)
class Entry:
address_range: IPv4Range
country: str
source: str
@classmethod
def from_dict(cls, dct: Dict[str, Any]) -> 'Entry':
return cls(address_range=IPv4Range.from_str(str(dct["start"]), str(dct["end"])),
country=str(dct["country"]),
source=str(dct["source"]))
def to_dict(self) -> Dict[str, Any]:
return {
"start": str(self.address_range.start),
"end": str(self.address_range.end),
"country": self.country,
"source": self.source,
}
@dataclass(frozen=True)
class Transfer:
address_range: IPv4Range
source: str
recipient: str
timestamp: int
@classmethod
def from_dict(cls, dct: Dict[str, Any]) -> 'Transfer':
return cls(address_range=IPv4Range.from_str(str(dct["start"]), str(dct["end"])),
source=str(dct["source"]),
recipient=str(dct["recipient"]),
timestamp=int(dct["timestamp"]))
def to_dict(self) -> Dict[str, Any]:
return {
"start": str(self.address_range.start),
"end": str(self.address_range.end),
"source": self.source,
"recipient": self.recipient,
"timestamp": self.timestamp,
}
@dataclass(frozen=True)
class Geofeed:
address_range: IPv4Range
geofeed: str
@classmethod
def from_dict(cls, dct: Dict[str, Any]) -> 'Geofeed':
return cls(address_range=IPv4Range.from_str(str(dct["start"]), str(dct["end"])),
geofeed=str(dct["geofeed"]))
def to_dict(self) -> Dict[str, Any]:
return {
"start": str(self.address_range.start),
"end": str(self.address_range.end),
"geofeed": self.geofeed,
}
REGISTRIES: Final[Dict[str, str]] = {
"AFRINIC": "AFRINIC",
"APNIC": "APNIC",
"ARIN": "ARIN",
"IANA": "IANA",
"LACNIC": "LACNIC",
"RESERVED": "RESERVED",
"RIPE": "RIPE",
"RIPENCC": "RIPE",
"RIPE NCC": "RIPE",
}
RESERVED_NETWORKS: Final[List[str]] = [
"0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/29",
"192.0.0.170/31", "192.0.2.0/24", "192.168.0.0/16", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24",
"224.0.0.0/4", "240.0.0.0/4", "255.255.255.255/32",
]
EU_MEMBERS: Final[List[str]] = [
"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT",
"NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "EU",
]
COUNTRY_ALIASES: Final[Dict[str, str]] = {
"UK": "GB",
}
CONTINENTS: Final[Dict[str, Dict[str, str]]] = {
"AF": {"geoname_id": "6255146", "continent_code": "AF", "continent_name": "Africa"},
"AS": {"geoname_id": "6255147", "continent_code": "AS", "continent_name": "Asia"},
"EU": {"geoname_id": "6255148", "continent_code": "EU", "continent_name": "Europe"},
"NA": {"geoname_id": "6255149", "continent_code": "NA", "continent_name": "North America"},
"OC": {"geoname_id": "6255151", "continent_code": "OC", "continent_name": "Oceania"},
"SA": {"geoname_id": "6255150", "continent_code": "SA", "continent_name": "South America"},
"AN": {"geoname_id": "6255152", "continent_code": "AN", "continent_name": "Antarctica"},
}
LOCATIONS: Final[List[Dict[str, str]]] = [
{"geoname_id": "6695072", "continent_code": "EU", "continent_name": "Europe",
"country_iso_code": "EU", "country_name": "European Union"},
]
REGISTRY_CONTINENTS: Final[Dict[str, str]] = {
"AFRINIC": "AF",
"APNIC": "AS",
"ARIN": "NA",
"LACNIC": "SA",
"RIPE": "EU",
"RESERVED": "",
}