Chris Lamb

Matching IPs with regexes conCIDRd harmful

Some rather unfriendly software (Munin, lighttpd, etc.) require that IP ranges are specified using regexes instead of the usually more convenient CIDR notation. The following code converts instances of that notation to a regular expression.

The generated pattern assumes that the input is a valid IPv4 address; that is to say, matching 0.0.0.0/0. Patches for common prefix optimisation greatly appreciated.

def cidr_to_regex(cidr):
    ip, prefix = cidr.split('/')

    base = 0
    for val in map(int, ip.split('.')):
        base = (base << 8) | val

    shift = 32 - int(prefix)
    start = base >> shift << shift
    end = start | (1 << shift) - 1

    def regex(lower, upper):
        if lower == upper:
            return str(lower)

        from math import log10
        exp = int(log10(upper - lower))
        delta = 10 ** exp

        if lower == 0 and upper == 255:
            return "\d+"

        if delta == 1:
            val = ""
            for a, b in zip(str(lower), str(upper)):
                if a == b:
                    val += str(a)
                elif (a, b) == ("0", "9"):
                    val += '\d'
                elif int(b) - int(a) == 1:
                    val += '[%s%s]' % (a, b)
                else:
                    val += '[%s-%s]' % (a, b)
            return val

        def gen_classes():
            floor_ = lambda x: int(round(x / delta, 0) * delta)

            xs = range(floor_(upper) - delta, floor_(lower), -delta)
            for x in map(str, xs):
                yield '%s%s' % (x[:-exp], r'\d' * exp)

            yield regex(lower, floor_(lower) + (delta - 1))
            yield regex(floor_(upper), upper)

        return '|'.join(gen_classes())

    def get_parts():
        for x in range(24, -1, -8):
            yield regex(start >> x & 255, end >> x & 255)

    return '^%s$' % r'\.'.join(get_parts())

Chris Lamb is a freelance software developer and the current Debian Project Leader. You can read other posts by me, see software I have written or read more about me. You can also follow me @lolamby.


Tags: Hacks

Planets: ALUG UWCS Debian WUGLUG

Sunday 25th January 2009


Three comments