Skip to content

Instantly share code, notes, and snippets.

@nlm
Created October 28, 2016 12:18
Show Gist options
  • Save nlm/eefd9bc6a2557f6f9b24ec412da03e93 to your computer and use it in GitHub Desktop.
Save nlm/eefd9bc6a2557f6f9b24ec412da03e93 to your computer and use it in GitHub Desktop.
Object to sort IP addresses according to a best-match in an ip networks list
from ipaddr import IPv4Network, IPv4Address
"""
A module to sort ip addresses according to the best-match
in an ip networks list. If no matching network is found, ip
is sorted last.
example:
>>> networks = ['10.0.0.0/8', '172.16.0.0/12', '172.16.9.0/24']
>>> addrs = ['192.168.2.1', '10.4.5.6', '172.16.9.9', '10.2.3.4', '172.16.10.10']
>>> ipas = IPv4AddressSorter(networks)
>>> print([ip for ip in ipas.sorted(addrs)])
['10.4.5.6', '10.2.3.4', '172.16.10.10', '172.16.9.9', '192.168.2.1']
- the 10.x.x.x ips are first, because they match 10.0.0.0/8,
their order amongst ips matching 10.0.0.0/8 is unchanged
- the 172.16.9.9 comes after 172.16.10.10 because it also matched
172.16.9.0/24, which has a more-specific prefix (24 > 12)
- 192.168.2.1 comes last, because it matched nothing
you can choose the default position by putting a 0.0.0.0/0 entry in the list
"""
class IPv4AddressSorter(object):
def __init__(self, networks):
"""
:param net_order: list of networks
"""
networks = [net if isinstance(net, IPv4Network) else IPv4Network(net)
for net in networks]
self._networks = networks
@property
def networks(self):
"""
:return: the list of networks used for sorting
"""
for net in self._networks:
yield str(net)
def score(self, ip):
"""
finds the sorting score for this address in the network table
this is the key function to use in sort or sorted
:param ip: the ip address to evaluate
:return: an integer
"""
prefixlen = 0
sortidx = -1
if not isinstance(ip, IPv4Address):
ip = IPv4Address(ip)
for idx, net in enumerate(reversed(self._networks)):
if ip in net and idx > sortidx and net.prefixlen >= prefixlen:
sortidx = idx
prefixlen = net.prefixlen
return -sortidx
def sorted(self, ip_addresses):
"""
:return: the ip_addresses in the list, in sorted order
"""
return sorted(ip_addresses, key=self.score)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment