我想使用 Python 和正则表达式从 Cisco 配置中提取网络组。 该组以
object-group network Cloudflare
开头,紧接着,有一个或多个子网,如 network-object 173.245.48.0 255.255.240.0
。
文字将是
object-group network Cloudflare
network-object 173.245.48.0 255.255.240.0
network-object 103.21.244.0 255.255.252.0
network-object 103.22.200.0 255.255.252.0
network-object 103.31.4.0 255.255.252.0
network-object 141.101.64.0 255.255.192.0
network-object 108.162.192.0 255.255.192.0
network-object 190.93.240.0 255.255.240.0
network-object 188.114.96.0 255.255.240.0
network-object 197.234.240.0 255.255.252.0
network-object 198.41.128.0 255.255.128.0
network-object 162.158.0.0 255.254.0.0
network-object 104.16.0.0 255.248.0.0
network-object 104.24.0.0 255.252.0.0
network-object 172.64.0.0 255.248.0.0
network-object 131.0.72.0 255.255.252.0
使用此正则表达式时
(?P<name>object-group network Cloudflare)\n(?P<subnets> network-object \d+\.\d+\.\d+\.\d+ \d+\.\d+\.\d+\.\d+\n)*
我得到 3 个匹配组,其中只有第一个可用,但它包含标题 object-group ...
。
可以改进吗?
https://regex101.com/r/s925cq/1
data = """
network-object 1.1.1.1 0.0.0.0
object-group network Cloudflare
network-object 173.245.48.0 255.255.240.0
network-object 103.21.244.0 255.255.252.0
network-object 103.22.200.0 255.255.252.0
network-object 103.31.4.0 255.255.252.0
network-object 141.101.64.0 255.255.192.0
network-object 108.162.192.0 255.255.192.0
network-object 190.93.240.0 255.255.240.0
network-object 188.114.96.0 255.255.240.0
network-object 197.234.240.0 255.255.252.0
network-object 198.41.128.0 255.255.128.0
network-object 162.158.0.0 255.254.0.0
network-object 104.16.0.0 255.248.0.0
network-object 104.24.0.0 255.252.0.0
network-object 172.64.0.0 255.248.0.0
network-object 131.0.72.0 255.255.252.0
access-list outside
"""
regex=r"object-group network (?P<network>\S+)|network-object\s(?P<subnet>\S+?)\s(?P<mask>\S+)"
matches = re.finditer(regex, data)
result = []
network_group = {"network": "Unknown"}
for cnt, match in enumerate(matches):
info = match.groupdict()
info1 = {k: v for k, v in info.items() if v is not None}
if check:=info.get("network"):
network_group = {"network": check} if check else network_group
if not info.get("network"):
result.append(network_group | info1)
result
您可以使用以下命令获取命名组子网中的所有网络对象:
(?P<name>object-group network Cloudflare)\n(?P<subnets>(?: network-object (?:\d+\.){3}\d+ (?:\d+\.){3}\d+\n)+)
解释
(?P<name>object-group network Cloudflare)
命名组名称,字面匹配\n
匹配换行符(?P<subnets>
命名组 子网
(?:
非捕获组作为整体重复
network-object
(?:\d+\.){3}\d+ (?:\d+\.){3}\d+\n
匹配 2 次数字,点部分后跟换行符)+
关闭非捕获组并重复 1 次或多次(以匹配至少 1 行))
关闭组子网查看 regex 101 演示。
正如@Ted Lyngmo提到的上面,最好使用特定于这种网络配置格式的解析器。 一旦这样的解析器是ciscoconfparse2(尽管有这个名字,它读取的内容比思科配置文件要多)。
使用 ciscoconfparse2 相对于原始正则表达式的优点是代码更具可读性和可维护性。
要获取
object-group network Cloudflare
中的子网列表,请使用 ciscoconfparse2 读取格式并构建一个字典来保存网络。 您可以使用以下技术阅读无限的 object-group
语句。
使用 ciscoconfparse2 这非常简单...
from pprint import pprint
from ciscoconfparse2 import CiscoConfParse, IPv4Obj
config = """
network-object 1.1.1.1 0.0.0.0
object-group network Cloudflare
network-object 173.245.48.0 255.255.240.0
network-object 103.21.244.0 255.255.252.0
network-object 103.22.200.0 255.255.252.0
network-object 103.31.4.0 255.255.252.0
network-object 141.101.64.0 255.255.192.0
network-object 108.162.192.0 255.255.192.0
network-object 190.93.240.0 255.255.240.0
network-object 188.114.96.0 255.255.240.0
network-object 197.234.240.0 255.255.252.0
network-object 198.41.128.0 255.255.128.0
network-object 162.158.0.0 255.254.0.0
network-object 104.16.0.0 255.248.0.0
network-object 104.24.0.0 255.252.0.0
network-object 172.64.0.0 255.248.0.0
network-object 131.0.72.0 255.255.252.0
access-list outside
"""
parse = CiscoConfParse(config)
# Store all object-group names in a dict to list mapping
# key the dict by the object-group name and append the networks to each
object_groups = dict()
# If there are multiple object-groups, iterate over each one...
for object_group_cmd in parse.find_objects('^object-group'):
name = object_group_cmd.split()[2]
# Grab all object-group network-object commands at once with this regex...
networks = object_group_cmd.re_list_iter_typed('network-object\s+(\d.+)')
object_groups[name] = list()
for cmd in networks:
tmp = cmd.split()
network, netmask = tmp[0], tmp[1]
# Add each network and netmask to the list...
object_groups[name].append({'network': network, 'netmask': netmask})
pprint(object_groups)
将打印:
{'Cloudflare': [{'netmask': '255.255.240.0', 'network': '173.245.48.0'},
{'netmask': '255.255.252.0', 'network': '103.21.244.0'},
{'netmask': '255.255.252.0', 'network': '103.22.200.0'},
{'netmask': '255.255.252.0', 'network': '103.31.4.0'},
{'netmask': '255.255.192.0', 'network': '141.101.64.0'},
{'netmask': '255.255.192.0', 'network': '108.162.192.0'},
{'netmask': '255.255.240.0', 'network': '190.93.240.0'},
{'netmask': '255.255.240.0', 'network': '188.114.96.0'},
{'netmask': '255.255.252.0', 'network': '197.234.240.0'},
{'netmask': '255.255.128.0', 'network': '198.41.128.0'},
{'netmask': '255.254.0.0', 'network': '162.158.0.0'},
{'netmask': '255.248.0.0', 'network': '104.16.0.0'},
{'netmask': '255.252.0.0', 'network': '104.24.0.0'},
{'netmask': '255.248.0.0', 'network': '172.64.0.0'},
{'netmask': '255.255.252.0', 'network': '131.0.72.0'}]}
应该注意的是,这会立即获取所有
object-group network
语句...