Python - ipaddress - How to loop efficiently over ipv6 addresses filtered by partial suffix?

308 Views Asked by At

I'm looking for a way to loop over specific hosts filtered by partial suffix. Since the ipv6 networks are huge, my actual implementation is time-consuming and looking for a best solution to achieve the same result.

This is an example of my actual test to achieve what I need :


import ipaddress
from itertools import islice

for address, suffix in zip(['10.10.0.0/16','2A00:7E40:F020::/64'],['.1',':00FF:FE00:0003']):

    print('===============')
    network = ipaddress.ip_network(address)

    print(str(network.num_addresses) + ' addresses available')

    print('suffix ' + suffix)
    print('===============')

    for ip in islice(filter(lambda x: str(x.exploded).endswith(suffix),network.hosts()),0,2):
        print(ip)

Actual output :

===============
65536 addresses available
suffix .1
===============
10.10.0.1
10.10.1.1
===============
18446744073709551616 addresses available
suffix :00FF:FE00:0003
===============
^C

Regards,

1

There are 1 best solutions below

0
rockandska On

Tried to figure out how to speed up the filtering and the slicing, I've come to this solution who seems to do the job pretty fast even if we start in the middle of a huge IPV6 block

#!/usr/bin/env python3

import ipaddress
from itertools import islice

def newv6hosts(self,start=None,limit=None,suffix=None):

    # - start is the index of the ip from where we should start
    # - limit is the number of ip we want
    # - if suffix is specified, only ips respecting this suffix will be
    #   generated. start / limit will be updated to corresponding to the index
    #   of thoses ip.
    range_start = int(self.network_address) + 1
    range_end = int(self.broadcast_address)
    range_step = 1

    if suffix:
        if suffix.find('::') != -1:
            raise ValueError('Suffix should not contain "::"')
        suffix_address = ipaddress.ip_address(''.join([str(self.network_address),suffix]))
        if int(suffix_address) < int(self.network_address):
            raise ValueError('Suffix index is lower than Network adress')
        suffix_len = len(suffix.replace(':',''))
        range_start = int(suffix_address)
        range_step = 16 ** suffix_len

    if start:
        new_start = range_start + (start * int(range_step or 1))
        if new_start < range_end:
            range_start = new_start
        else:
            range_start = range_end

    if limit:
        new_end = range_start + (limit * int(range_step or 1))
        if new_end < range_end:
            range_end = new_end

    for x in range(range_start, range_end, range_step):
        yield self._address_class(x)

# Replace default method to :
#  - have a start / limit without relaying on islice (faster)
#  - filter ips generated based on a suffix
ipaddress.IPv6Network.hosts = newv6hosts

for address, suffix in zip(['10.10.0.0/16','2A00:7E40:F020::/64'],['.1','00FF:FE00:0003']):

    print('===============')
    network = ipaddress.ip_network(address)

    print(str(network.num_addresses) + ' addresses available')

    print('suffix ' + suffix)
    print('===============')

    if network.version == 4:
        for ip in islice(filter(lambda x: str(x.exploded).endswith(suffix),network.hosts()),0,2):
            print(ip)
    else:
        for ip in network.hosts(start=500,limit=2,suffix=suffix):
            print(ip)

Output :

===============
65536 addresses available
suffix .1
===============
10.10.0.1
10.10.1.1
===============
18446744073709551616 addresses available
suffix 00FF:FE00:0003
===============
2a00:7e40:f020:0:1f4:ff:fe00:3
2a00:7e40:f020:0:1f5:ff:fe00:3