From 222b28f4f4d0a955adef80b8b9256fc4a85ca5d6 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 3 Jan 2016 01:10:23 -0500 Subject: [PATCH] Show IP range; tweaks. --- earwigbot/commands/cidr.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/earwigbot/commands/cidr.py b/earwigbot/commands/cidr.py index 6b832fa..a1a2013 100644 --- a/earwigbot/commands/cidr.py +++ b/earwigbot/commands/cidr.py @@ -27,7 +27,8 @@ from socket import AF_INET, AF_INET6 from earwigbot.commands import Command -_Range = namedtuple("_Range", ["family", "range", "size", "addresses"]) +_Range = namedtuple("_Range", [ + "family", "range", "low", "high", "size", "addresses"]) class CIDR(Command): """Calculates the smallest CIDR range that encompasses a list of IP @@ -62,9 +63,10 @@ class CIDR(Command): cidr = self._calculate_range(ips[0][0], [ip[1] for ip in ips]) descr = self._describe(cidr.family, cidr.size) - msg = "Smallest CIDR range is \x02{0}\x0F ({1}){2}" + msg = "Smallest CIDR range is \x02{0}\x0F ({1}: {2} – {3}){4}." self.reply(data, msg.format( - cidr.range, cidr.addresses, " – " + descr if descr else "")) + cidr.range, cidr.addresses, cidr.low, cidr.high, + "; " + descr if descr else "")) def _parse_arg(self, arg): """Converts an argument into an IP address.""" @@ -110,23 +112,30 @@ class CIDR(Command): size = i break - mask = bin_ips[0][:size].ljust(len(bin_ips[0]), "0") - packed = "".join( - chr(int(mask[i:i + 8], 2)) for i in xrange(0, len(mask), 8)) + bin_low = bin_ips[0][:size].ljust(len(bin_ips[0]), "0") + bin_high = bin_ips[0][:size].ljust(len(bin_ips[0]), "1") + low = self._format_bin(family, bin_low) + high = self._format_bin(family, bin_high) + return _Range( - family, - socket.inet_ntop(family, packed) + "/" + str(size), - size, + family, low + "/" + str(size), low, high, size, self._format_count(2 ** (len(bin_ips[0]) - size))) - def _format_count(self, count): + @staticmethod + def _format_bin(family, binary): + """Convert an IP's binary representation to presentation format.""" + return socket.inet_ntop(family, "".join( + chr(int(binary[i:i + 8], 2)) for i in xrange(0, len(binary), 8))) + + @staticmethod + def _format_count(count): """Nicely format a number of addresses affected by a range block.""" if count > 2 ** 32: base = "{0:.2E} addresses".format(count) if count > 2 ** 96: return base + ", {0:.2E} /64 subnets".format(count >> 64) if count > 2 ** 63: - return base + ", {0} /64 subnets".format(count >> 64) + return base + ", {0:,} /64 subnets".format(count >> 64) return base if count == 1: return "1 address"