interloper
interloper

Reputation: 73

Pythonic way to find if an IP in a list belongs to a different subnet

I have a script that generates the configuration for some campus wireless mobility switches. The user needs to supply a set of IP addresses for the configuration.

Among other constraints, these IP's must all be in the same /24 subnet (always /24). To avoid typos where an IP is in a different subnet (which messes up the configuration and it happened already), I would like to tell the user which IP is at fault. I wrote the following, but I feel there could be a better way to do it.

Suppose the list is this, where the 3rd IP is wrong:

ips = ['10.0.0.1', '10.0.0.2', '10.0.10.3', '10.0.0.4', '10.0.0.5']

The following gets the job done:

subnets = set()
for ip in ips:
    subnets.add('.'.join(ip.split('.')[0:3]))
    # This would result in subnet being set(['10.0.10', '10.0.0'])
if len(subnets) > 1:
    seen_subnets = defaultdict(list)

    for sn in subnets:
        for ip in ips:
            if sn in ip:
                seen_subnets[sn].append(ip)

    suspect = ''
    for sn in seen_subnets.keys():
        if len(seen_subnets[sn]) == 1:
            suspect = seen_subnets[sn][0]
    if not suspect:
        # Do something to tell the user one or more IP's are incorrect
        # but I couldn't tell which ones

NOTE: The smallest list that I could have has 3 items, and I'm basing this on the assumption that probably most if not all mistakes will be just 1 IP.

Is there perhaps a more straightforward way to do this? I feel the solution has to be based on using a set either way but it didn't seem to me any of its methods would be more helpful than this.

Upvotes: 0

Views: 51

Answers (1)

Gerrat
Gerrat

Reputation: 29690

Something like this would work:

from itertools import groupby

ips = ['10.0.0.1', '10.0.0.2', '10.0.10.3', '10.0.0.4', '10.0.0.5']

def get_subnet(ip):
    return '.'.join(ip.split('.')[:3])

groups = {}  # group ips by subnet
for k, g in groupby(sorted(ips), key=get_subnet):
    groups[k] = list(g)

# Sort the groups by most common first
for row, (subnet, ips) in enumerate(
    sorted(groups.iteritems(), key=lambda (k, v): len(v), reverse=True)
):
    if row > 0:  # not the most common subnet
        print('You probably entered these incorrectly: {}'.format(ips))

Upvotes: 1

Related Questions