diff --git a/ccat.py b/ccat.py index 94e7123..010bc73 100755 --- a/ccat.py +++ b/ccat.py @@ -15,8 +15,8 @@ vlanmap = parsing.vlanmap_parse(filenames.pop(0)) # variables for html output option -html_directory = None -html_file = None +html_directory = None +html_file = None config_directory = args.args.config # Create directory for html files output or check its existence if args.args.o: @@ -44,7 +44,7 @@ config_number = len(filenames[0]) config_checked = 0 bar = progressbar.ProgressBar(maxval=config_number, widgets=[ - progressbar.Bar(left='[', marker='=', right=']'), # Прогресс + progressbar.Bar(left='[', marker='=', right=']'), # Прогресс progressbar.SimpleProgress(), ]).start() @@ -63,10 +63,10 @@ # getting parse output global_params = parsing.iface_global - interfaces = parsing.iface_local + interfaces = parsing.iface_local # debug output - if(args.args.debug): + if (args.args.debug): print("\n\n[DEBUG] args:") print(args.args) print("\n\n[DEBUG] global:") @@ -81,47 +81,52 @@ result_dict = {} # global checks - result_dict.update(checks.services .check(global_params)) - result_dict.update(checks.users .check(global_params)) - result_dict.update(checks.ip_global .check(global_params)) + result_dict.update(checks.services.check(global_params)) + result_dict.update(checks.users.check(global_params)) + result_dict.update(checks.ip_global.check(global_params)) result_dict.update(checks.console_vty.check(global_params)) - result_dict.update(checks.lldp .check(global_params)) + result_dict.update(checks.lldp.check(global_params)) - result_cdp,cdp_flag=checks.cdp.global_check(global_params) + result_cdp, cdp_flag = checks.cdp.global_check(global_params) if result_cdp: result_dict.update(result_cdp) - result_vtp=checks.vtp.check(global_params) + result_vtp = checks.vtp.check(global_params) if result_vtp: result_dict.update(result_vtp) # global checks with necessary flags for further interface checks - result, bpdu_flag = checks.stp .global_check(global_params) + result, bpdu_flag = checks.stp.global_check(global_params) result_dict.update(result) - result_arp, arp_flag = checks.arp_inspection.check_global(global_params,result_dict) + result_arp, arp_flag = checks.arp_inspection.check_global(global_params, result_dict) result_dict.update(result_arp) - result_dhcp, dhcp_flag = checks.dhcp_snooping.check_global(global_params,result_dict) + result_dhcp, dhcp_flag = checks.dhcp_snooping.check_global(global_params, result_dict) result_dict.update(result_dhcp) - result_dict['IPv6 options']={} + result_dict['IPv6 options'] = {} - result_raguard, raguard_flag = checks.ipv6.raguard_global(global_params,result_dict) + result_raguard, raguard_flag = checks.ipv6.raguard_global(global_params, result_dict) result_dict.update(result_raguard) - result_snooping, snooping_flag = checks.ipv6.snooping_global(global_params,result_dict) + result_snooping, snooping_flag = checks.ipv6.snooping_global(global_params, result_dict) result_dict.update(result_snooping) - result_sourceguard, sourceguard_flag = checks.ipv6.sourceguard_global(global_params,result_dict) + result_sourceguard, sourceguard_flag = checks.ipv6.sourceguard_global(global_params, result_dict) result_dict.update(result_sourceguard) - result_dhcpguard, dhcpguard_flag = checks.ipv6.dhcpguard_global(global_params,result_dict) + result_dhcpguard, dhcpguard_flag = checks.ipv6.dhcpguard_global(global_params, result_dict) result_dict.update(result_dhcpguard) - result_destinationguard, destinationguard_flag = checks.ipv6.destinationguard_global(global_params,result_dict) + result_destinationguard, destinationguard_flag = checks.ipv6.destinationguard_global(global_params, result_dict) result_dict.update(result_destinationguard) + arp_proxy_flag, arp_proxy = checks.arp_proxy.global_check(global_params) + + if arp_proxy_flag: + result_dict.update(arp_proxy) + # interface checks for iface in interfaces: @@ -132,18 +137,19 @@ if 'loop' not in iface.lower() and 'vlan' not in iface.lower(): # skip shutdown interfaces if there was not --disabled-interfaces argument - if interfaces[iface]['shutdown'] == 'yes' and not check_disabled: + if interfaces[iface]['shutdown'] == 'yes' and not check_disabled: continue result_dict[iface] = {} # set DISABLE status if interface is shutdown and disabled-interfaces argument is true if interfaces[iface]['shutdown'] == 'yes' and check_disabled: - result_dict[iface]['status'] = [3,'SHUTDOWN'] + result_dict[iface]['status'] = [3, 'SHUTDOWN'] # If type is not defined - interface is working in Dynamic Auto mode if 'type' not in interfaces[iface]: - result_dict[iface]['mode'] = [0, 'DYNAMIC', 'The interfaces of your switches must be in trunk or access mode.'] + result_dict[iface]['mode'] = [0, 'DYNAMIC', + 'The interfaces of your switches must be in trunk or access mode.'] # determine vlanmap type (critical/unknown/trusted) if vlanmap defined and interface has at least 1 vlan if vlanmap and interfaces[iface]['vlans']: @@ -153,16 +159,15 @@ else: vlanmap_result = None - # access/trunk mode check result_dict[iface].update(checks.mode.check(interfaces[iface])) # check cdp, dtp, mop and source guard options on current interface - result_dict[iface].update(checks.dtp .check(global_params,interfaces[iface],vlanmap_result)) - result_dict[iface].update(checks.mop .check(interfaces[iface], vlanmap_result, iface)) - result_dict[iface].update(checks.source_guard.check(interfaces[iface],dhcp_flag, vlanmap_result)) + result_dict[iface].update(checks.dtp.check(global_params, interfaces[iface], vlanmap_result)) + result_dict[iface].update(checks.mop.check(interfaces[iface], vlanmap_result, iface)) + result_dict[iface].update(checks.source_guard.check(interfaces[iface], dhcp_flag, vlanmap_result)) - cdp_result=checks.cdp.iface_check(interfaces[iface], vlanmap_result, cdp_flag) + cdp_result = checks.cdp.iface_check(interfaces[iface], vlanmap_result, cdp_flag) if cdp_result: result_dict[iface].update(cdp_result) @@ -171,39 +176,51 @@ if stp_result: result_dict[iface].update(stp_result) - dhcp_result = checks.dhcp_snooping.check_iface(interfaces[iface], vlanmap_result, args.args.disabled_interfaces,dhcp_flag) + dhcp_result = checks.dhcp_snooping.check_iface(interfaces[iface], vlanmap_result, + args.args.disabled_interfaces, dhcp_flag) if dhcp_result: result_dict[iface].update(dhcp_result) - arp_result = checks.arp_inspection.check_iface(interfaces[iface], vlanmap_result, args.args.disabled_interfaces, - arp_flag) + if arp_proxy_flag == 0: + arp_proxy_result = checks.arp_proxy.iface_check(interfaces[iface], vlanmap_result) + result_dict[iface].update(arp_proxy_result) + arp_result = checks.arp_inspection.check_iface(interfaces[iface], vlanmap_result, + args.args.disabled_interfaces, + arp_flag) if arp_result: result_dict[iface].update(arp_result) - result_dict[iface]['IPv6']={} - sourceguard_result = checks.ipv6.sourceguard_iface(interfaces[iface], vlanmap_result, args.args.disabled_interfaces,sourceguard_flag) + result_dict[iface]['IPv6'] = {} + sourceguard_result = checks.ipv6.sourceguard_iface(interfaces[iface], vlanmap_result, + args.args.disabled_interfaces, sourceguard_flag) if sourceguard_result: result_dict[iface]['IPv6'].update(sourceguard_result) - raguard_result = checks.ipv6.raguard_iface(interfaces[iface], vlanmap_result, args.args.disabled_interfaces,raguard_flag) + raguard_result = checks.ipv6.raguard_iface(interfaces[iface], vlanmap_result, + args.args.disabled_interfaces, raguard_flag) if raguard_result: result_dict[iface]['IPv6'].update(raguard_result) - destinationguard_result = checks.ipv6.destinationguard_iface(interfaces[iface], vlanmap_result, args.args.disabled_interfaces,destinationguard_flag) + destinationguard_result = checks.ipv6.destinationguard_iface(interfaces[iface], vlanmap_result, + args.args.disabled_interfaces, + destinationguard_flag) if destinationguard_result: result_dict[iface]['IPv6'].update(destinationguard_result) - dhcpguard_result = checks.ipv6.dhcpguard_iface(interfaces[iface], vlanmap_result, args.args.disabled_interfaces,dhcpguard_flag) + dhcpguard_result = checks.ipv6.dhcpguard_iface(interfaces[iface], vlanmap_result, + args.args.disabled_interfaces, dhcpguard_flag) if dhcpguard_result: result_dict[iface]['IPv6'].update(dhcpguard_result) - + if args.args.storm_level: - result_dict[iface].update(checks.storm_control.check(interfaces[iface], vlanmap_result, args.args.storm_level)) + result_dict[iface].update( + checks.storm_control.check(interfaces[iface], vlanmap_result, args.args.storm_level)) else: result_dict[iface].update(checks.storm_control.check(interfaces[iface], vlanmap_result)) if args.args.max_number_mac: - port_result = checks.port_security.check(interfaces[iface], vlanmap_result, args.args.max_number_mac) + port_result = checks.port_security.check(interfaces[iface], vlanmap_result, + args.args.max_number_mac) else: - port_result=checks.port_security.check(interfaces[iface], vlanmap_result) + port_result = checks.port_security.check(interfaces[iface], vlanmap_result) if port_result: result_dict[iface].update(port_result) @@ -213,7 +230,7 @@ result_dict[iface] = {'Unused Interface': [0, 'ENABLED', 'An interface that is not used must be disabled']} # processing results - display.display_results(result_dict,html_file, no_console_display) + display.display_results(result_dict, html_file, no_console_display) # update progress bar if it is enabled if no_console_display: @@ -224,7 +241,6 @@ if no_console_display: bar.finish() - # Do we really need scoring system ? # # Scoring system. diff --git a/checks/__init__.py b/checks/__init__.py index 225a5f6..9bc9587 100644 --- a/checks/__init__.py +++ b/checks/__init__.py @@ -1,2 +1,2 @@ -__all__ = ["arp_inspection", "cdp", "console_vty", "dhcp_snooping", "dtp", "ip_global", "mode", "port_security", +__all__ = ["arp_inspection","arp_proxy", "cdp", "console_vty", "dhcp_snooping", "dtp", "ip_global", "mode", "port_security", "services", "storm_control", "stp", "stp_global", "users","port_security","source_guard","vtp", "mop", "ipv6","lldp"] \ No newline at end of file diff --git a/checks/arp_proxy.py b/checks/arp_proxy.py new file mode 100644 index 0000000..150f34f --- /dev/null +++ b/checks/arp_proxy.py @@ -0,0 +1,43 @@ +# ARP-proxy options check +# Input: +# interface dictionary +# interface type from vlanmap +# Output: +# result dictionary +# {'ARP-proxy': {'ARP-proxy': [severity(int), 'message', 'best practice']} +# + +def global_check(global_dct): + if 'arp_proxy' in global_dct: + if global_dct['arp_proxy']=='disable': + return 1,{'ARP-proxy': {'ARP-proxy': [2,'DISABLED']}} + else: + return 0, {'ARP-proxy': {'ARP-proxy': [0, 'enabled','ghj']}} + return 0, 0 + + +def _iface_check__proxy_check(iface_dct,result,scale): + if 'arp_proxy' in iface_dct: + if iface_dct['arp_proxy']=='no': + return {'ARP-proxy':[scale[1],'ENABLED']} + else: + return {'ARP-proxy': [scale[0], 'DISABLED','ARP-proxy should be disabled']} + + + + +def iface_check(iface_dct, vlanmap_type): + result = {} + + # If this network segment is TRUSTED - enabled cdp is not a red type of threat, it will be colored in orange + if vlanmap_type == 'TRUSTED': + return _iface_check__proxy_check(iface_dct, result, [1, 2]) + + # Otherwise if network segment is CRITICAL or UNKNOWN or vlanmap is not defined - enabled cdp is a red type of threat + else: + return _iface_check__proxy_check(iface_dct, result, [0, 2]) + + + + + diff --git a/parsing.py b/parsing.py index 8f53ef2..634988c 100644 --- a/parsing.py +++ b/parsing.py @@ -42,8 +42,11 @@ parse_vtp = Suppress('vtp ') + restOfLine parse_line = Suppress('line ') + restOfLine parse_ip_ssh = Suppress('ip ssh ') + restOfLine +parse_arp_proxy = Suppress('ip arp proxy ') + restOfLine parse_vstack = Suppress('no') + 'vstack' + + parse_enable_password = Suppress('enable') + MatchFirst(['secret', 'password']) + Optional(Word(nums) + Suppress(White(exact=1))) + Suppress(restOfLine) parse_ip_dhcp = NotAny(White()) + Suppress('ip dhcp snooping') + Optional(Suppress('vlan') + Word(nums) + ZeroOrMore(Suppress(',') + Word(nums))) parse_ip_arp = NotAny(White()) + Suppress('ip arp inspection') + Suppress('vlan') + Word(nums) + ZeroOrMore(Suppress(',') + Word(nums)) @@ -254,6 +257,12 @@ def global_parse(config): except ParseException: pass + try: + iface_global['arp_proxy'] = parse_arp_proxy.parseString(line).asList()[-1] + continue + except ParseException: + pass + try: while line != '!': item = parse_line.parseString(line).asList()[-1] @@ -280,14 +289,15 @@ def _interfaceParse___iface_attributes(config, check_disabled): vlan_num = Word(nums + '-') + ZeroOrMore(Suppress(',') + Word(nums + '-')) - parse_description = Suppress('description ') + restOfLine - parse_type = Suppress('switchport mode ') + restOfLine - parse_storm = Suppress('storm-control ') + restOfLine - parse_port_sec = Suppress('switchport port-security ') + restOfLine - parse_stp_port = Suppress('spanning-tree ') + restOfLine - parse_dhcp_snoop = Suppress('ip dhcp snooping ') + restOfLine - parse_arp_insp = Suppress('ip arp inspection ') + restOfLine - parse_source_guard = Suppress('ip verify source ') + restOfLine + parse_description = Suppress('description ') + restOfLine + parse_type = Suppress('switchport mode ') + restOfLine + parse_storm = Suppress('storm-control ') + restOfLine + parse_port_sec = Suppress('switchport port-security ') + restOfLine + parse_stp_port = Suppress('spanning-tree ') + restOfLine + parse_dhcp_snoop = Suppress('ip dhcp snooping ') + restOfLine + parse_arp_insp = Suppress('ip arp inspection ') + restOfLine + parse_source_guard = Suppress('ip verify source ') + restOfLine + parse_arp_proxy_iface = Optional(Word(alphas)) + Suppress('ip proxy-arp') parse_vlans = Suppress('switchport ') + Suppress(MatchFirst('access vlan ' + ('trunk allowed vlan ' + Optional('add ')))) + vlan_num @@ -379,6 +389,12 @@ def _interfaceParse___iface_attributes(config, check_disabled): continue except ParseException: pass + try: + arp_proxy_iface = parse_arp_proxy_iface.parseString(option).asList()[-1] + iface_dict['arp_proxy'] = arp_proxy_iface + continue + except ParseException: + pass return iface_dict else: