使用 CiscoConfParse 查找应用于 VTY 的 ACL,然后检查 ACL 中的日志语句
using CiscoConfParse to find ACL applied to VTY and then check ACL for log statement
我有代码可以在 'line vty'
上找到 'access-class' 的名称
之后我可以找到 ACL,但我想检查 ACL 的每一行以验证 'deny' 和 'permit' 语句是否具有 'log' 关键字。如果没有 'log' 语句,则打印 OPEN 报告;如果条目上有 'log' 语句,则打印 NOT A FINDING 报告。
这就是我对如何解析 ACL 语句不知所措的地方,我是否可以使用 CiscoConfParse 或更标准的东西 python 来完成这项工作?
#Importing the necessary modules.
import sys
from sys import argv
#Importing the necessary modules.
from ciscoconfparse import CiscoConfParse
import sys
import argparse
def check_VTY_ACL_NET1637():
## Search for LINE VTY access-list name then check if that ACL has log keyword
#
for VTY_ACL in parse.find_children_w_parents('line vty', 'access-class'):
#print(VTY_ACL[14])
VTY_ACL = VTY_ACL.lstrip('access-class ')
#print (VTY_ACL)
VTY_ACL_2 = VTY_ACL.rstrip(' in')
#print(VTY_ACL_R)
#has_ACL_in = VTY_ACL.find_lines(r'access-class')
#print(has_ACL_in)
#for IP_ACL_LIST in parse.find_objects_w_child(VTY_ACL_R, 'log'):
#for IP_ACL_LIST in parse.find_lines(VTY_ACL_R):
for IP_ACL_LIST in parse.find_parents_w_child(VTY_ACL_2, ''):
#print(IP_ACL_LIST)
#IP_ACL_ACE = parse.has_line_with(' log')
IP_ACL_ACE = parse.find_children_w_parents(IP_ACL_LIST, '')
#print(IP_ACL_ACE)
has_log_keyword = parse.has_line_with(r' log')
#print(has_log_keyword)
#
#has_log_keyword = has_log_keyword.split()
for log in IP_ACL_ACE:
#print (log)
#has_not_log_keyword = parse.has_line_with(r'. log')
#print(has_not_log_keyword)
keyword_log = 'log'
keyword_permit = 'permit'
keyword_deny = 'deny'
log = log.split()
print (log)
if (not keyword_log):
print('OPEN LINE VTY')
else:
print("Not a Finding: 'NET-VLAN-023'" )
# Main starting of script
def start():
script, input_file = argv
global parse
parse = CiscoConfParse (input_file)
print("Opening config file: %r\n" % input_file)
check_VTY_ACL_NET1637()
def main():
args = sys.argv[1:]
if len(args) == 1:
start()
#else:
#usage()
if __name__ == "__main__":
main()
这是我在 VTY 上使用 ACL 的示例配置文件
Current configuration : 25432 bytes
!
ip access-list extended SSH2-IN
remark ///\\///\\///\\///\\///\\///\\///
remark ///\\***DEC 8 2015***///\\
remark SomeSite //VoSIP //
remark ******************************************
permit ip 10.227.2.128 0.0.0.63 any
permit tcp 43.81.133.0 0.0.0.255 any eq 22 log
deny ip any any
!
line vty 0 4
access-class SSH2-IN in
line vty 5 15
access-class SSH2-IN in
!
end
我写了一个概念证明:
#!/usr/bin/env python
import re
from ciscoconfparse import CiscoConfParse
def main():
cisco_file = 'cisco_ipsec.txt'
cisco_cfg = CiscoConfParse(cisco_file)
vty_acl = cisco_cfg.find_objects(r'access-class')
# Find the ACL name
acl_name = ''
for entry in vty_acl:
if 'line vty' in entry.parent.text:
match = re.search(r'access-class (.*) in', entry.text)
if not acl_name:
acl_name = match.group(1)
else:
new_acl_name = match.group(1)
if new_acl_name != acl_name:
raise ValueError("ACL names do not match")
if not acl_name:
raise ValueError("ACL not found under line vty")
the_acl = r"ip access-list extended {}".format(acl_name)
acl_object = cisco_cfg.find_objects(the_acl)[0]
# Parse the ACL lines looking for 'log' keyword
log_lines = []
no_log_lines = []
for line in acl_object.all_children:
if 'permit' in line.text or 'deny' in line.text:
if 'log' in line.text:
log_lines.append(line.text)
else:
no_log_lines.append(line.text)
print "\nLines with log"
print '#' * 50
for line in log_lines:
print line
print '#' * 50
print "\nLines without log"
print '#' * 50
for line in no_log_lines:
print line
print '#' * 50
print
if __name__ == "__main__":
main()
一般来说,我首先找到ACL名称。然后,我遍历 ACL 的每一行以查找 permit 或 deny,然后是 log 关键字。由此我创建了两个列表:"log_lines" 和 "no_log_lines"。最后,我将这两个打印在屏幕上。
仅供参考,在发布上述代码时删除注释代码会有所帮助。它只会打乱你正在做的事情。
from ciscoconfparse import CiscoConfParse
input_file = 'some_site.conf'
parse = CiscoConfParse(input_file)
## Build a list of vty ACLs here (and flag if a vty doesn't have one)
vty_acl_names = set([])
for vtyobj in parse.find_objects(r'^line\svty'):
vty_acl_name = vtyobj.re_match_iter_typed('access-class\s+(\S+)\s+in',
result_type=str, default="")
if not vty_acl_name:
print "FAIL: '{0}' doesn't have an ACL".format(vtyobj.text)
else:
vty_acl_names.add(vty_acl_name)
## Check ACL log compliance here (and ensure the ACL is even in the config)
for vty_acl_name in vty_acl_names:
try:
aclobj = parse.find_objects(r'ip\s+access-list\s+extended\s+{0}'.format(vty_acl_name))[0]
except IndexError:
print "FAIL: ACL {0} is applied to a vty, but it's missing from the config!".format(vty_acl_name)
## NOTE: this only works if you are using extended ACLs on the VTY
for ace in aclobj.children:
if 'remark' in ace.text:
continue
if 'log' in ace.text:
print "NOT A FINDING - ACL {0}, ACE: {1}".format(vty_acl_name, ace.text)
else:
print "OPEN (no log) - ACL {0}, ACE: {1}".format(vty_acl_name, ace.text)
当我 运行 它在你的配置上时,我得到这个输出:
(py27_default) mpenning@MPENNING-BRIX C:\Users\mpenning
> python garrybaker.py
FAIL: 'line vty 5 15' doesn't have an ACL
OPEN (no log) - ACL SSH2-IN, ACE: permit ip 10.227.2.128 0.0.0.63 any
NOT A FINDING - ACL SSH2-IN, ACE: permit tcp 43.81.133.0 0.0.0.255 any eq 22 log
OPEN (no log) - ACL SSH2-IN, ACE: deny ip any any
(py27_default) mpenning@MPENNING-BRIX C:\Users\mpenning
>
我冒昧地添加了您的要求...我标记了没有 ACL 的 vty 线路。
现在,您可能会问“为什么说 'line vty 5 15' 没有 ACL,因为我把它放在配置中了?因为我使用了 re_match_iter_typed()
,它只搜索子项父线路的...当您输入这样的配置时,CiscoConfParse 不会将 access-class 与 5 15 上的父 vty 线路相关联,因为 access-class 线路不是 缩进 多于line vty 5 15
:
line vty 0 4
access-class SSH2-IN in
line vty 5 15
access-class SSH2-IN in
!
缩进对 CiscoConfParse 很重要……你必须知道你的输入……如果你不能依赖人们缩进他们的配置,那么使用 Kirk 的回答中的方法:-)
我有代码可以在 'line vty'
上找到 'access-class' 的名称之后我可以找到 ACL,但我想检查 ACL 的每一行以验证 'deny' 和 'permit' 语句是否具有 'log' 关键字。如果没有 'log' 语句,则打印 OPEN 报告;如果条目上有 'log' 语句,则打印 NOT A FINDING 报告。
这就是我对如何解析 ACL 语句不知所措的地方,我是否可以使用 CiscoConfParse 或更标准的东西 python 来完成这项工作?
#Importing the necessary modules.
import sys
from sys import argv
#Importing the necessary modules.
from ciscoconfparse import CiscoConfParse
import sys
import argparse
def check_VTY_ACL_NET1637():
## Search for LINE VTY access-list name then check if that ACL has log keyword
#
for VTY_ACL in parse.find_children_w_parents('line vty', 'access-class'):
#print(VTY_ACL[14])
VTY_ACL = VTY_ACL.lstrip('access-class ')
#print (VTY_ACL)
VTY_ACL_2 = VTY_ACL.rstrip(' in')
#print(VTY_ACL_R)
#has_ACL_in = VTY_ACL.find_lines(r'access-class')
#print(has_ACL_in)
#for IP_ACL_LIST in parse.find_objects_w_child(VTY_ACL_R, 'log'):
#for IP_ACL_LIST in parse.find_lines(VTY_ACL_R):
for IP_ACL_LIST in parse.find_parents_w_child(VTY_ACL_2, ''):
#print(IP_ACL_LIST)
#IP_ACL_ACE = parse.has_line_with(' log')
IP_ACL_ACE = parse.find_children_w_parents(IP_ACL_LIST, '')
#print(IP_ACL_ACE)
has_log_keyword = parse.has_line_with(r' log')
#print(has_log_keyword)
#
#has_log_keyword = has_log_keyword.split()
for log in IP_ACL_ACE:
#print (log)
#has_not_log_keyword = parse.has_line_with(r'. log')
#print(has_not_log_keyword)
keyword_log = 'log'
keyword_permit = 'permit'
keyword_deny = 'deny'
log = log.split()
print (log)
if (not keyword_log):
print('OPEN LINE VTY')
else:
print("Not a Finding: 'NET-VLAN-023'" )
# Main starting of script
def start():
script, input_file = argv
global parse
parse = CiscoConfParse (input_file)
print("Opening config file: %r\n" % input_file)
check_VTY_ACL_NET1637()
def main():
args = sys.argv[1:]
if len(args) == 1:
start()
#else:
#usage()
if __name__ == "__main__":
main()
这是我在 VTY 上使用 ACL 的示例配置文件
Current configuration : 25432 bytes
!
ip access-list extended SSH2-IN
remark ///\\///\\///\\///\\///\\///\\///
remark ///\\***DEC 8 2015***///\\
remark SomeSite //VoSIP //
remark ******************************************
permit ip 10.227.2.128 0.0.0.63 any
permit tcp 43.81.133.0 0.0.0.255 any eq 22 log
deny ip any any
!
line vty 0 4
access-class SSH2-IN in
line vty 5 15
access-class SSH2-IN in
!
end
我写了一个概念证明:
#!/usr/bin/env python
import re
from ciscoconfparse import CiscoConfParse
def main():
cisco_file = 'cisco_ipsec.txt'
cisco_cfg = CiscoConfParse(cisco_file)
vty_acl = cisco_cfg.find_objects(r'access-class')
# Find the ACL name
acl_name = ''
for entry in vty_acl:
if 'line vty' in entry.parent.text:
match = re.search(r'access-class (.*) in', entry.text)
if not acl_name:
acl_name = match.group(1)
else:
new_acl_name = match.group(1)
if new_acl_name != acl_name:
raise ValueError("ACL names do not match")
if not acl_name:
raise ValueError("ACL not found under line vty")
the_acl = r"ip access-list extended {}".format(acl_name)
acl_object = cisco_cfg.find_objects(the_acl)[0]
# Parse the ACL lines looking for 'log' keyword
log_lines = []
no_log_lines = []
for line in acl_object.all_children:
if 'permit' in line.text or 'deny' in line.text:
if 'log' in line.text:
log_lines.append(line.text)
else:
no_log_lines.append(line.text)
print "\nLines with log"
print '#' * 50
for line in log_lines:
print line
print '#' * 50
print "\nLines without log"
print '#' * 50
for line in no_log_lines:
print line
print '#' * 50
print
if __name__ == "__main__":
main()
一般来说,我首先找到ACL名称。然后,我遍历 ACL 的每一行以查找 permit 或 deny,然后是 log 关键字。由此我创建了两个列表:"log_lines" 和 "no_log_lines"。最后,我将这两个打印在屏幕上。
仅供参考,在发布上述代码时删除注释代码会有所帮助。它只会打乱你正在做的事情。
from ciscoconfparse import CiscoConfParse
input_file = 'some_site.conf'
parse = CiscoConfParse(input_file)
## Build a list of vty ACLs here (and flag if a vty doesn't have one)
vty_acl_names = set([])
for vtyobj in parse.find_objects(r'^line\svty'):
vty_acl_name = vtyobj.re_match_iter_typed('access-class\s+(\S+)\s+in',
result_type=str, default="")
if not vty_acl_name:
print "FAIL: '{0}' doesn't have an ACL".format(vtyobj.text)
else:
vty_acl_names.add(vty_acl_name)
## Check ACL log compliance here (and ensure the ACL is even in the config)
for vty_acl_name in vty_acl_names:
try:
aclobj = parse.find_objects(r'ip\s+access-list\s+extended\s+{0}'.format(vty_acl_name))[0]
except IndexError:
print "FAIL: ACL {0} is applied to a vty, but it's missing from the config!".format(vty_acl_name)
## NOTE: this only works if you are using extended ACLs on the VTY
for ace in aclobj.children:
if 'remark' in ace.text:
continue
if 'log' in ace.text:
print "NOT A FINDING - ACL {0}, ACE: {1}".format(vty_acl_name, ace.text)
else:
print "OPEN (no log) - ACL {0}, ACE: {1}".format(vty_acl_name, ace.text)
当我 运行 它在你的配置上时,我得到这个输出:
(py27_default) mpenning@MPENNING-BRIX C:\Users\mpenning
> python garrybaker.py
FAIL: 'line vty 5 15' doesn't have an ACL
OPEN (no log) - ACL SSH2-IN, ACE: permit ip 10.227.2.128 0.0.0.63 any
NOT A FINDING - ACL SSH2-IN, ACE: permit tcp 43.81.133.0 0.0.0.255 any eq 22 log
OPEN (no log) - ACL SSH2-IN, ACE: deny ip any any
(py27_default) mpenning@MPENNING-BRIX C:\Users\mpenning
>
我冒昧地添加了您的要求...我标记了没有 ACL 的 vty 线路。
现在,您可能会问“为什么说 'line vty 5 15' 没有 ACL,因为我把它放在配置中了?因为我使用了 re_match_iter_typed()
,它只搜索子项父线路的...当您输入这样的配置时,CiscoConfParse 不会将 access-class 与 5 15 上的父 vty 线路相关联,因为 access-class 线路不是 缩进 多于line vty 5 15
:
line vty 0 4
access-class SSH2-IN in
line vty 5 15
access-class SSH2-IN in
!
缩进对 CiscoConfParse 很重要……你必须知道你的输入……如果你不能依赖人们缩进他们的配置,那么使用 Kirk 的回答中的方法:-)