CIDR 是无类别域间路由的意思,以前会用A类、B类、C类地址来表示一个网段。在 CIDR 的概念里没有ABC类地址的概念,所有地址段都可以用 a.b.c.d/m 的形式来表示。其中 a.b.c.d 是 IP 地址,m 是子网掩码。这类IP段的表示法就叫 CIDR 表示法。
如何将 IP 地址范围(以开始和结束 IP 地址的形式)转换成 CIDR 表示法,这是一个常见需求。有些防火墙和 ipset 操作不支持使用不连续的网段来表示一个集合,比如 192.168.1.1-192.168.1.10 是没法转换成单一的 CIDR 的,它如果转换成 CIDR 格式,会转换成多个 CIDR 地址段,比如:
$ python3 ip_merge2.py -t ip 192.168.1.1-192.168.1.10192.168.1.1/32192.168.1.2/31192.168.1.4/30192.168.1.8/31192.168.1.10/32
即一个 IP 段是由多个 CIDR 段组成。Github 上有一个 Go 语言写的工具可以处理这种 IP 段到 CIDR 的转换,项目地址为:
https://github.com/zhanhb/cidr-merger
之前也写过文章介绍过这款工具,文章地址:
这里介绍一种在 Python 下的解决方案,这样就不需要调用第三方工具了,直接在代码中即可处理 IP 段到 CIDR 的转换。后面会贴出代码,将函数包装成命令行工具后,使用方法下:
$ python3 ip_merge2.pyusage: ip_merge2.py [-h] -t {cidr,ip} inputip_merge2.py: error: the following arguments are required: input, -t/--type$ python3 ip_merge2.py -t ip 0.0.0.0-9.255.255.2550.0.0.0/58.0.0.0/7
使用前要先安装 netaddr 模块:
$ pip install netaddr
用到的关键函数如下:
>>> from netaddr import IPRange>>> def ip_range_to_cidr(ip_start, ip_end):... cidr_list = IPRange(ip_start, ip_end)... return cidr_list...>>> ip_range_to_cidr('192.168.1.1', '192.168.1.10')IPRange('192.168.1.1', '192.168.1.10')>>> from netaddr import IPSet>>> IPSet(ip_range_to_cidr('192.168.1.1', '192.168.1.10'))IPSet(['192.168.1.1/32', '192.168.1.2/31', '192.168.1.4/30', '192.168.1.8/31', '192.168.1.10/32'])>>>
Python 代码如下:
import argparseimport ipaddressfrom netaddr import IPSet, IPRangedef debug(func):def wrapper(*args, **kwargs):print(f"Function: {func.__name__}")print(f"Arguments: {args}")print(f"Keyword Arguments: {kwargs}")print()result = func(*args, **kwargs)return resultreturn wrapperdef ip_to_cidr(ip):ip_network = ipaddress.ip_network(ip, strict=False)return str(ip_network)# @debugdef ip_range_to_cidr(ip_start, ip_end):cidr_list = IPRange(ip_start, ip_end)return cidr_listdef cidr_to_ip_range(cidr):ip_network = ipaddress.ip_network(cidr, strict=False)ip_range = (str(ip_network.network_address), str(ip_network.broadcast_address))return ip_rangedef main():parser = argparse.ArgumentParser(description="Convert between CIDR and IP range")parser.add_argument("input", help="Input CIDR, IP address, or IP range")parser.add_argument("-t", "--type", choices=["cidr", "ip"], help="Specify input type (cidr or ip)", required=True)args = parser.parse_args()if args.type == "cidr":if "/" not in args.input:print("Error: Invalid CIDR input. Make sure to include the subnet mask.")returnresult = cidr_to_ip_range(args.input)print(f"CIDR to IP Range: {args.input} -> {result}")elif args.type == "ip":if "-" in args.input:ip_start, ip_end = map(str.strip, args.input.split("-"))result = ip_range_to_cidr(ip_start, ip_end)# print(f"IP Range to CIDR: {args.input} -> {IPSet(result)}")for i in result.cidrs():print(i)elif "/" in args.input:print("Error: Invalid IP input. Remove the subnet mask for IP address input.")returnelse:result = ip_to_cidr(args.input)print(f"IP to CIDR: {args.input} -> {result}")if __name__ == "__main__":main()
全文完。
如果转发本文,文末务必注明:“转自微信公众号:生有可恋”。
文章转载自生有可恋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




