Created
October 28, 2016 12:18
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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