IP 地址段到 CIDR 格式的转换

admin 2024年1月13日20:31:21评论30 views字数 2791阅读9分18秒阅读模式

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 result    return 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.")            return        result = 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.")            return        else:            result = ip_to_cidr(args.input)            print(f"IP to CIDR: {args.input} -> {result}")if __name__ == "__main__":    main()

全文完。

如果转发本文,文末务必注明:“转自微信公众号:生有可恋”。

原文始发于微信公众号(生有可恋):IP 地址段到 CIDR 格式的转换

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月13日20:31:21
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   IP 地址段到 CIDR 格式的转换http://cn-sec.com/archives/2389390.html

发表评论

匿名网友 填写信息