2222
2323import ipaddress
2424import random
25- import socket
2625from functools import lru_cache
27- from typing import TYPE_CHECKING , Any , Dict , List , Optional , Set , Union , cast
26+ from typing import TYPE_CHECKING , Dict , List , Optional , Set , Union , cast
2827
2928from .._dns import (
3029 DNSAddress ,
4039from .._updates import RecordUpdate , RecordUpdateListener
4140from .._utils .asyncio import get_running_loop , run_coro_with_timeout
4241from .._utils .name import service_type_name
43- from .._utils .net import IPVersion , _encode_address , _is_v6_address
42+ from .._utils .net import IPVersion , _encode_address
4443from .._utils .time import current_time_millis
4544from ..const import (
4645 _CLASS_IN ,
@@ -223,7 +222,14 @@ def properties(self) -> Dict:
223222 return self ._properties
224223
225224 def addresses_by_version (self , version : IPVersion ) -> List [bytes ]:
226- """List addresses matching IP version."""
225+ """List addresses matching IP version.
226+
227+ Addresses are guaranteed to be returned in LIFO (last in, first out)
228+ order with IPv4 addresses first and IPv6 addresses second.
229+
230+ This means the first address will always be the most recently added
231+ address of the given IP version.
232+ """
227233 if version == IPVersion .V4Only :
228234 return [addr .packed for addr in self ._ipv4_addresses ]
229235 if version == IPVersion .V6Only :
@@ -236,35 +242,47 @@ def addresses_by_version(self, version: IPVersion) -> List[bytes]:
236242 def ip_addresses_by_version (
237243 self , version : IPVersion
238244 ) -> Union [List [ipaddress .IPv4Address ], List [ipaddress .IPv6Address ], List [ipaddress ._BaseAddress ]]:
239- """List ip_address objects matching IP version."""
245+ """List ip_address objects matching IP version.
246+
247+ Addresses are guaranteed to be returned in LIFO (last in, first out)
248+ order with IPv4 addresses first and IPv6 addresses second.
249+
250+ This means the first address will always be the most recently added
251+ address of the given IP version.
252+ """
240253 if version == IPVersion .V4Only :
241254 return self ._ipv4_addresses
242255 if version == IPVersion .V6Only :
243256 return self ._ipv6_addresses
244257 return [* self ._ipv4_addresses , * self ._ipv6_addresses ]
245258
246259 def parsed_addresses (self , version : IPVersion = IPVersion .All ) -> List [str ]:
247- """List addresses in their parsed string form."""
248- result = self .addresses_by_version (version )
249- return [
250- socket .inet_ntop (socket .AF_INET6 if _is_v6_address (addr ) else socket .AF_INET , addr )
251- for addr in result
252- ]
260+ """List addresses in their parsed string form.
261+
262+ Addresses are guaranteed to be returned in LIFO (last in, first out)
263+ order with IPv4 addresses first and IPv6 addresses second.
264+
265+ This means the first address will always be the most recently added
266+ address of the given IP version.
267+ """
268+ return [str (addr ) for addr in self .ip_addresses_by_version (version )]
253269
254270 def parsed_scoped_addresses (self , version : IPVersion = IPVersion .All ) -> List [str ]:
255271 """Equivalent to parsed_addresses, with the exception that IPv6 Link-Local
256272 addresses are qualified with %<interface_index> when available
273+
274+ Addresses are guaranteed to be returned in LIFO (last in, first out)
275+ order with IPv4 addresses first and IPv6 addresses second.
276+
277+ This means the first address will always be the most recently added
278+ address of the given IP version.
257279 """
258280 if self .interface_index is None :
259281 return self .parsed_addresses (version )
260-
261- def is_link_local (addr_str : str ) -> Any :
262- addr = _cached_ip_addresses (addr_str )
263- return addr .version == 6 and addr .is_link_local
264-
265- ll_addrs = list (filter (is_link_local , self .parsed_addresses (version )))
266- other_addrs = list (filter (lambda addr : not is_link_local (addr ), self .parsed_addresses (version )))
267- return [f"{ addr } %{ self .interface_index } " for addr in ll_addrs ] + other_addrs
282+ return [
283+ f"{ addr } %{ self .interface_index } " if addr .version == 6 and addr .is_link_local else str (addr )
284+ for addr in self .ip_addresses_by_version (version )
285+ ]
268286
269287 def _set_properties (self , properties : Dict ) -> None :
270288 """Sets properties and text of this info from a dictionary"""
@@ -399,13 +417,13 @@ def dns_addresses(
399417 return [
400418 DNSAddress (
401419 self .server ,
402- _TYPE_AAAA if _is_v6_address ( address ) else _TYPE_A ,
420+ _TYPE_AAAA if address . version == 6 else _TYPE_A ,
403421 _CLASS_IN | _CLASS_UNIQUE ,
404422 override_ttl if override_ttl is not None else self .host_ttl ,
405- address ,
423+ address . packed ,
406424 created = created ,
407425 )
408- for address in self .addresses_by_version (version )
426+ for address in self .ip_addresses_by_version (version )
409427 ]
410428
411429 def dns_pointer (self , override_ttl : Optional [int ] = None , created : Optional [float ] = None ) -> DNSPointer :
0 commit comments