def parseIPPart(ipx, shift):
if ipx is None:
return 0
return int(ipx) << shift
def parseIP(ipString):
(ip0, ip1, ip2, ip3) = ipString.split(".")
addr = parseIPPart(ip0, 24) + parseIPPart(ip1, 16) + parseIPPart(ip2, 8) + parseIPPart(ip3, 0)
return addr
def parseCIDR(cidr):
(addrString, bitsString) = cidr.split('/')
bits = 32
if bitsString is not None:
bits = int(bitsString)
addr = parseIP(addrString)
return [addr, bits]
class CIDRTree:
class CIDRNode:
def __init__(self, depth):
self.depth = depth
self.isset = None
self.unset = None
self.leaf = False
def __init__(self):
self.root = CIDRTree.CIDRNode(-1)
def addCIDR(self, cidr):
(ip, bits) = parseCIDR(cidr)
node = self.root
for b in range(bits):
if node.leaf:
# Previous bigger CIDR Covers this subnet
return
mask = 1 << (31 - b)
val = (ip & mask) != 0
kid = None
if val:
if node.isset is None:
node.isset = CIDRTree.CIDRNode(b)
kid = node.isset
else:
if node.unset is None:
node.unset = CIDRTree.CIDRNode(b)
kid = node.unset
node = kid
# node is now a representation of the leaf that comes from this CIDR.
# Clear out any more specific CIDRs that are no longer relevant (this CIDR includes a previous CIDR)
node.isset = None
node.unset = None
node.leaf = True
#print("Added CIDR ", ip, " and bits ", bits)
def matches(self, ipString):
ip = parseIP(ipString)
node = self.root
shift = 0
while node is not None and not node.leaf:
shift+=1
mask = 1 << (32 - shift)
val = (ip & mask) != 0
node = node.isset if val else node.unset
return node is not None and node.leaf
if __name__ == "__main__":
cidrTree = CIDRTree()
cidrTree.addCIDR("8.0.0.0/8")
cidrTree.addCIDR("9.8.7.0/24")
print ("Tree matches 8.8.8.8:", cidrTree.matches("8.8.8.8"))
print ("Tree matches 9.9.9.9:", cidrTree.matches("9.9.9.9"))
print ("Tree matches 9.8.7.6:", cidrTree.matches("9.8.7.6"))
ZGVmIHBhcnNlSVBQYXJ0KGlweCwgc2hpZnQpOgogICAgaWYgaXB4IGlzIE5vbmU6CiAgICAgICAgcmV0dXJuIDAKICAgIHJldHVybiBpbnQoaXB4KSA8PCBzaGlmdAoKZGVmIHBhcnNlSVAoaXBTdHJpbmcpOgogICAgKGlwMCwgaXAxLCBpcDIsIGlwMykgPSBpcFN0cmluZy5zcGxpdCgiLiIpCiAgICBhZGRyID0gcGFyc2VJUFBhcnQoaXAwLCAyNCkgKyBwYXJzZUlQUGFydChpcDEsIDE2KSArIHBhcnNlSVBQYXJ0KGlwMiwgOCkgKyBwYXJzZUlQUGFydChpcDMsIDApCiAgICByZXR1cm4gYWRkcgogICAgCgpkZWYgcGFyc2VDSURSKGNpZHIpOgogICAgKGFkZHJTdHJpbmcsIGJpdHNTdHJpbmcpID0gY2lkci5zcGxpdCgnLycpCiAgICBiaXRzID0gMzIKICAgIGlmIGJpdHNTdHJpbmcgaXMgbm90IE5vbmU6CiAgICAgICAgYml0cyA9IGludChiaXRzU3RyaW5nKQogICAgYWRkciA9IHBhcnNlSVAoYWRkclN0cmluZykKICAgIHJldHVybiBbYWRkciwgYml0c10KICAgIAoKY2xhc3MgQ0lEUlRyZWU6CiAgICBjbGFzcyBDSURSTm9kZToKICAgICAgICBkZWYgX19pbml0X18oc2VsZiwgZGVwdGgpOgogICAgICAgICAgICBzZWxmLmRlcHRoID0gZGVwdGgKICAgICAgICAgICAgc2VsZi5pc3NldCA9IE5vbmUKICAgICAgICAgICAgc2VsZi51bnNldCA9IE5vbmUKICAgICAgICAgICAgc2VsZi5sZWFmID0gRmFsc2UKCiAgICBkZWYgX19pbml0X18oc2VsZik6CiAgICAgICAgc2VsZi5yb290ID0gQ0lEUlRyZWUuQ0lEUk5vZGUoLTEpCgogICAgZGVmIGFkZENJRFIoc2VsZiwgY2lkcik6CiAgICAgICAgKGlwLCBiaXRzKSA9IHBhcnNlQ0lEUihjaWRyKQogICAgICAgIG5vZGUgPSBzZWxmLnJvb3QKICAgICAgICBmb3IgYiBpbiByYW5nZShiaXRzKToKICAgICAgICAgICAgaWYgbm9kZS5sZWFmOgogICAgICAgICAgICAgICAgIyBQcmV2aW91cyBiaWdnZXIgQ0lEUiBDb3ZlcnMgdGhpcyBzdWJuZXQKICAgICAgICAgICAgICAgIHJldHVybgogICAgICAgICAgICBtYXNrID0gMSA8PCAoMzEgLSBiKQogICAgICAgICAgICB2YWwgPSAoaXAgJiBtYXNrKSAhPSAwCiAgICAgICAgICAgIGtpZCA9IE5vbmUKICAgICAgICAgICAgaWYgdmFsOgogICAgICAgICAgICAgICAgaWYgbm9kZS5pc3NldCBpcyBOb25lOgogICAgICAgICAgICAgICAgICAgIG5vZGUuaXNzZXQgPSBDSURSVHJlZS5DSURSTm9kZShiKQogICAgICAgICAgICAgICAga2lkID0gbm9kZS5pc3NldAogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgaWYgbm9kZS51bnNldCBpcyBOb25lOgogICAgICAgICAgICAgICAgICAgIG5vZGUudW5zZXQgPSBDSURSVHJlZS5DSURSTm9kZShiKQogICAgICAgICAgICAgICAga2lkID0gbm9kZS51bnNldAogICAgICAgICAgICBub2RlID0ga2lkCiAgICAgICAgIyBub2RlIGlzIG5vdyBhIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBsZWFmIHRoYXQgY29tZXMgZnJvbSB0aGlzIENJRFIuCiAgICAgICAgIyBDbGVhciBvdXQgYW55IG1vcmUgc3BlY2lmaWMgQ0lEUnMgdGhhdCBhcmUgbm8gbG9uZ2VyIHJlbGV2YW50ICh0aGlzIENJRFIgaW5jbHVkZXMgYSBwcmV2aW91cyBDSURSKQogICAgICAgIG5vZGUuaXNzZXQgPSBOb25lCiAgICAgICAgbm9kZS51bnNldCA9IE5vbmUKICAgICAgICBub2RlLmxlYWYgPSBUcnVlCiAgICAgICAgI3ByaW50KCJBZGRlZCBDSURSICIsIGlwLCAiIGFuZCBiaXRzICIsIGJpdHMpCgogICAgZGVmIG1hdGNoZXMoc2VsZiwgaXBTdHJpbmcpOgoKICAgICAgICBpcCA9IHBhcnNlSVAoaXBTdHJpbmcpCiAgICAgICAgbm9kZSA9IHNlbGYucm9vdAogICAgICAgIHNoaWZ0ID0gMAogICAgICAgIHdoaWxlIG5vZGUgaXMgbm90IE5vbmUgYW5kIG5vdCBub2RlLmxlYWY6CiAgICAgICAgICAgIHNoaWZ0Kz0xCiAgICAgICAgICAgIG1hc2sgPSAxIDw8ICgzMiAtIHNoaWZ0KQogICAgICAgICAgICB2YWwgPSAoaXAgJiBtYXNrKSAhPSAwCiAgICAgICAgICAgIG5vZGUgPSBub2RlLmlzc2V0IGlmIHZhbCBlbHNlIG5vZGUudW5zZXQKCiAgICAgICAgcmV0dXJuIG5vZGUgaXMgbm90IE5vbmUgYW5kIG5vZGUubGVhZgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIGNpZHJUcmVlID0gQ0lEUlRyZWUoKQogICAgY2lkclRyZWUuYWRkQ0lEUigiOC4wLjAuMC84IikKICAgIGNpZHJUcmVlLmFkZENJRFIoIjkuOC43LjAvMjQiKQoKICAgIHByaW50ICgiVHJlZSBtYXRjaGVzIDguOC44Ljg6IiwgY2lkclRyZWUubWF0Y2hlcygiOC44LjguOCIpKQogICAgcHJpbnQgKCJUcmVlIG1hdGNoZXMgOS45LjkuOToiLCBjaWRyVHJlZS5tYXRjaGVzKCI5LjkuOS45IikpCiAgICBwcmludCAoIlRyZWUgbWF0Y2hlcyA5LjguNy42OiIsIGNpZHJUcmVlLm1hdGNoZXMoIjkuOC43LjYiKSkKCgo=