简体   繁体   中英

How to check given IP address range contains only one CIDR?

I trying to write a Python script to convert the range between two IP addresses to CIDR,

# cidr.py
import argparse
import netaddr
import sys

parser = argparse.ArgumentParser()
parser.add_argument('start_addr')
parser.add_argument('end_addr')
args = parser.parse_args()

start_addr = netaddr.IPAddress(args.start_addr)
end_addr = netaddr.IPAddress(args.end_addr)
if end_addr < start_addr:
  print('start address is larger than end address. check arguments.')
  sys.exit()
ip_cidr = netaddr.iprange_to_cidrs(start_addr, end_addr)

print(str(ip_cidr))

For example, execute this script using Salesforce's IP address range as arguments, it returns the correct CIDR expression.

$ python cidr.py 13.108.0.0 13.111.255.255
[IPNetwork('13.108.0.0/14')]

But when I modify the second argument, it returns a couple of CIDRs.

$ python hoge.py 13.108.0.0 13.211.255.255
[IPNetwork('13.108.0.0/14'), IPNetwork('13.112.0.0/12'), IPNetwork('13.128.0.0/10'), IPNetwork('13.192.0.0/12'), IPNetwork('13.208.0.0/14')]

I want to know the address range of 2 IP addresses only contains 1 CIDR expressions. How do I check it?

If iprange_to_cidrs always returns the minimum number of IP ranges needed to span the supplied range (as seems likely) then you only need to test the length of the list which it returns.

However, if you do not want to verify that this is always the case, the following approach could be used.

def ip_to_int(ip):
    return sum(256**i * int(v) for i, v in enumerate(reversed(ip.split('.'))))

def single_cidr(ip1, ip2):
    n1 = ip_to_int(ip1)
    n2 = ip_to_int(ip2)
    xor = n2 ^ n1
    return xor == abs(n2 - n1) and '0' not in bin(xor)[2:]

print(single_cidr('13.108.0.0', '13.111.255.255'))  # True
print(single_cidr('13.108.0.0', '13.211.255.255'))  # False

Here, xor contains a 1 for each bit where the two IPs (when converted to integer) differ. We want this number to be equal to the difference between the values and also one less than a power of two -- so that the two IP addresses in binary start with the same stem and then one has all 0s while the other has all 1s.

In the part '0' not in bin(xor)[2:] we use the fact that the output of bin after the initial 0b will start with the first 1 bit without padding any leading zeros (eg for 65535 it will be '0b11111111' ), so we just need to test that there is no 0 after the initial 0b .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM