def main(): #YAML file cisco_cfg = CiscoConfParse("./cisco_file.txt") transform_set = cisco_cfg.find_objects(r"^crypto ipsec transform-set") t_set_list = [] for t_set in transform_set: if ('esp-aes' not in t_set.text): t_set_list.append(t_set.text) print 'Transform sets found without AES are:', t_set_list print '\nCrypto Maps without AES are:\n' for t_set in t_set_list: var_tmp1 = t_set.split() reference = var_tmp1[3].strip() #print 'reference es', reference var_tmp1 = cisco_cfg.find_objects_w_child(r"^crypto map ", reference) #print 'var_tmp1 es', var_tmp1[0].text for index in range(0, len(var_tmp1)): config_crypto_map = cisco_cfg.find_children(var_tmp1[index].text) for item in config_crypto_map: print ' ', item
def testValues_insert_after_atomic_factory_01(self): """Ensure that comments which are added, assert is_comment""" with patch('__main__.IOSCfgLine') as mock: # the mock pretends to be an IOSCfgLine so we can test against it result_correct01 = mock result_correct01.linenum = 16 result_correct01.text = ' ! TODO: some note to self' result_correct01.classname = 'IOSCfgLine' result_correct01.is_comment = True result_correct02 = [ 'interface GigabitEthernet4/1', ' ! TODO: some note to self', ' switchport', ' switchport access vlan 100', ' switchport voice vlan 150', ' power inline static max 7000', ] linespec = 'interface GigabitEthernet4/1' cfg = CiscoConfParse(self.c01, factory=True) cfg.insert_after(linespec, ' ! TODO: some note to self', exactmatch=True, atomic=True) test_result01 = cfg.find_objects('TODO')[0] self.assertEqual(result_correct01.linenum, test_result01.linenum) self.assertEqual(result_correct01.text, test_result01.text) self.assertEqual(result_correct01.classname, test_result01.classname) self.assertEqual(result_correct01.is_comment, test_result01.is_comment) # FIXME: this fails... maybe because I don't parse comments as children correctly??? test_result02 = cfg.find_children(linespec) self.assertEqual(result_correct02, test_result02)
def print_lab_ip_management_addresses(self): """ Print to the console information about IP addresses assigned to management interfaces. """ # For each link we need to store 2 values. We use List of Dictionaries for this. Each link is described by # following structure: # { # Device: String, # ManagementIP: String # } TOutput = PrettyTable() TOutput.field_names = ['Device name', 'Management IP'] for nodenum, nodedef in enumerate(self.lab_conf['nodes']): if self._get_node_type(nodenum) in self._node_types_supported: interface_record = { 'Device': nodedef['label'], 'ManagementIPAddress': None } node_config = self._get_node_config(nodenum) node_parsed_config = CiscoConfParse(node_config.split('\n')) if self._iface_ip_addr_defined( node_parsed_config.find_children( r'^interface\s' + self._node_management_interface_name[ self._get_node_type(nodenum)])): interface_record[ 'ManagementIPAddress'] = self._get_iface_ip_addr( node_parsed_config.find_children( r'^interface\s' + self._node_management_interface_name[ self._get_node_type(nodenum)])) else: interface_record['ManagementIPAddress'] = None TOutput.add_row([ interface_record['Device'], interface_record['ManagementIPAddress'] ]) print("\nManagement interfaces addressing") print(TOutput)
class DhcpConfig: def __init__(self, config_file): self.config_file = config_file self.parse = CiscoConfParse(self.config_file) def get_dhcppool_config(self, pool_name): find_result = self.parse.find_children(pool_name) return find_result def get_dhcppoolname_list(self): dhcppoolname_list = [] find_result = self.parse.find_parents_w_child('^ip dhcp pool', 'host') for parent in find_result: dhcppoolname_list.append(parent.split()[3]) return dhcppoolname_list def get_ipaddr(self, pool_name): find_result = self.parse.find_children(pool_name) return find_result[1].split()[1] def get_ipaddrmask(self, pool_name): find_result = self.parse.find_children(pool_name) return find_result[1].split()[2] def get_macaddr(self, pool_name): find_result = self.parse.find_children(pool_name) return find_result[2].split()[1] def get_defaultrouter(self, pool_name): find_result = self.parse.find_children(pool_name) return find_result[3].split()[1] def get_dns(self, pool_name): find_result = self.parse.find_children(pool_name) return [find_result[4].split()[1], find_result[4].split()[2]]
def testValues_insert_after_nonatomic_02(self): """Negative test. We expect insert_after(atomic=False) to miss any children added like this at some point in the future I might fix insert_after so it knows how to correctly parse children""" result_correct = ['interface GigabitEthernet4/1', #' shutdown', <--- Intentionally commented out ' switchport', ' switchport access vlan 100', ' switchport voice vlan 150', ' power inline static max 7000', ] linespec = 'interface GigabitEthernet4/1' cfg = CiscoConfParse(self.c01, factory=False) cfg.insert_after(linespec, ' shutdown', exactmatch=True, atomic=False) test_result = cfg.find_children(linespec) self.assertEqual(result_correct, test_result)
def testValues_insert_after_atomic_01(self): """We expect insert_after(atomic=True) to correctly parse children""" ## See also -> testValues_insert_after_nonatomic_02() result_correct = [ 'interface GigabitEthernet4/1', ' shutdown', ' switchport', ' switchport access vlan 100', ' switchport voice vlan 150', ' power inline static max 7000', ] linespec = 'interface GigabitEthernet4/1' cfg = CiscoConfParse(self.c01, factory=False) cfg.insert_after(linespec, ' shutdown', exactmatch=True, atomic=True) test_result = cfg.find_children(linespec) self.assertEqual(result_correct, test_result)
class IOSDevice: """ Represents an IOS Device. Some helper functions here to assist with common stuff :type hostname: str """ def __init__(self, config_filename): self.parsed_switch_config = CiscoConfParse(config_filename) self.hostname = self._getHostname() self.interfaces = self._getNetworkInterfaces() self.router_id = self._getRouterId() def __repr__(self): return "<IOSDevice: %s>" % self.hostname def _getHostname(self): if not self.parsed_switch_config.find_lines('^hostname'): raise RuntimeError('This device has no hostname. This library requires this device has a hostname') return self.parsed_switch_config.find_lines('^hostname')[0].split()[1] def _getRouterId(self): router_id = None router_ids = self.parsed_switch_config.find_lines('router-id') if len(router_ids) > 0: router_id = self.parsed_switch_config.find_lines('router-id')[0].split()[-1] #Assume all mgmt addresses are the same elif len(self.parsed_switch_config.find_lines('^logging source-interface')) > 0: #Little hack. We don't have a router-id so lets use the logging source-id as the switch identifier for interface in self.getNetworkInterfaces(): if interface.name == self.parsed_switch_config.find_lines('^logging source-interface')[0].split()[-1]: return interface.address else: #There is no explicit mgmt address. # The router-id is set by the highest IP Address of a manually created loopback address highestAddress = IPv4Address(u'0.0.0.0') for interface in self.getNetworkInterfaces(): if "loopback" in interface.name.lower(): address = IPv4Address(unicode(interface.address)) if address > highestAddress: highestAddress = address router_id = interface.address # If there is no configured loopback the router id will be the highest IP address of the fist active (on-boot) # physical interface if router_id is None: for interface in self.getNetworkInterfaces(): address = IPv4Address(unicode(interface.address)) if address > highestAddress: highestAddress = address router_id = interface.address return router_id def _getNetworkInterfaces(self): """ Used to generate a list of NetworkInterface for a given config file :type parsed_switch_config: ciscoconfparse.CiscoConfParse :return list of interfaces """ to_return = [] switch_interfaces = self.parsed_switch_config.find_parents_wo_child("^interface", 'shutdown') for interface in switch_interfaces: #Gets the child config for this interface interface_config = CiscoConfParse(self.parsed_switch_config.find_children(interface, exactmatch=True)) #We are only interested in the interface name, not the entire interface command definition interface_name = interface.split()[1] #VRF is in global by default vrf = None description = None if interface_config.find_lines('description'): description = " ".join(interface_config.find_lines('description')[0].strip().split()[1:]) if interface_config.find_lines('^ ip vrf forwarding'): vrf = interface_config.find_lines('^ ip vrf forwarding')[0].strip().split()[-1] elif interface_config.find_lines('^ vrf forwarding'): vrf = interface_config.find_lines('^ vrf forwarding')[0].strip().split()[-1] #We only really care about this interface if it has an IP address on it #interfaces that have no addresses should be skipped if interface_config.find_lines('no ip address'): continue if interface_config.find_lines('^ ip address'): #Create a new network interface object interface = NetworkInterface(self) #In case we want to skip this interface and not show it for some reason should_add_address = True for address in interface_config.find_lines('^ ip address'): #We can have multiple addresses here, have to allow for secondaries if "secondary" in address: secondary_address = SecondaryAddress(interface) secondary_address.address = address.strip().split('ip address')[1].split()[0] secondary_address.netmask = address.strip().split('ip address')[1].split()[1] interface.secondary.append(secondary_address) else: if "no" in address or "negotiated" in address: should_add_address = False break if len(interface_config.find_lines('channel-group')) > 0: should_add_address = False break interface.address = address.strip().split('ip address')[1].split()[0] interface.name = interface_name interface.netmask = address.strip().split('ip address')[1].split()[1] interface.vrf = vrf interface.description = description to_return.append(interface) return to_return def getNetworkInterfaces(self): """ Used to generate a list of NetworkInterface for a given config file :type parsed_switch_config: ciscoconfparse.CiscoConfParse :return list of interfaces """ if self.interfaces is None: self.interfaces = self._getNetworkInterfaces() return self.interfaces def getHostname(self): """ Returns the hostname on this device :rtype: str """ return self.hostname def getParsedSwitchConfig(self): """ Returns a parsed switch config object (CiscoConfParse) for this device :rtype: CiscoConfParse """ return self.parsed_switch_config()
def print_lab_ip_peer_addresses(self): """ Print to the console information about IP addresses and link of L3 interfaces in the lab. """ # For each link we need to store 6 values. We use List of Dictionaries for this. Each link is described by # following structure: # { # DeviceA: String, # DeviceB: String, # InterfaceA: String, # InterfaceB: String, # IPAddressA: netaddr.IPNetwork, # IPAddressB: netaddr.IPNetwork # } links_database = [] try: for linknum, link in enumerate(self.lab_conf["links"]): # We need to ignore connections to 'external_connector' and 'iosvl2' objects and continue to the # next object on list if self._get_node_type( self._get_node_index_by_id(link['n1']) ) in self._node_types_ignored or self._get_node_type( self._get_node_index_by_id( link['n2'])) in self._node_types_ignored: continue link_record = { 'InterfaceA': self._get_interface_name_by_id( self._get_node_index_by_id(link["n1"]), link["i1"]), 'InterfaceB': self._get_interface_name_by_id( self._get_node_index_by_id(link["n2"]), link["i2"]), 'DeviceA': self._get_node_label_by_id(link["n1"]), 'DeviceB': self._get_node_label_by_id(link["n2"]), 'IPAddressA': None, 'IPAddressB': None, } if self._get_node_type(self._get_node_index_by_id( link["n1"])) in self._node_types_supported: node_config = self._get_node_config( self._get_node_index_by_id(link["n1"])) node_parsed_config = CiscoConfParse( node_config.split('\n')) if self._iface_ip_addr_defined( node_parsed_config.find_children( r'^interface\s' + self._get_interface_name_by_id( self._get_node_index_by_id(link["n1"]), link["i1"]))): link_record['IPAddressA'] = self._get_iface_ip_addr( node_parsed_config.find_children( r'^interface\s' + self._get_interface_name_by_id( self._get_node_index_by_id(link["n1"]), link["i1"]))) if self._get_node_type(self._get_node_index_by_id( link["n2"])) in self._node_types_supported: node_config = self._get_node_config( self._get_node_index_by_id(link["n2"])) node_parsed_config = CiscoConfParse( node_config.split('\n')) if self._iface_ip_addr_defined( node_parsed_config.find_children( r'^interface\s' + self._get_interface_name_by_id( self._get_node_index_by_id(link["n2"]), link["i2"]))): link_record['IPAddressB'] = self._get_iface_ip_addr( node_parsed_config.find_children( r'^interface\s' + self._get_interface_name_by_id( self._get_node_index_by_id(link["n2"]), link["i2"]))) links_database.append(link_record) except IndexError as e: raise IndexError("peer-range: Not enough IP addresses provided") TOutput = PrettyTable() TOutput.field_names = [ 'Device A', 'Interface A', 'IP Address A', 'Device B', 'Interface B', 'IP Address B' ] for r in links_database: TOutput.add_row([ r['DeviceA'], r['InterfaceA'], r['IPAddressA'], r['DeviceB'], r['InterfaceB'], r['IPAddressB'] ]) print("\nL3 interfaces addressing") print(TOutput)
def get_asa_net_obj(asa_config): ''' receives a text asa configuration file as a string, returns a list with network object definitions Network objects include: FQDNs Network Objects Host Objects IP Address Ranges ''' # create the CiscoConfParse class object parsed_conf = CiscoConfParse(asa_config.splitlines()) # create a list containg the network object lines and thier children obj_list = parsed_conf.find_children( "^object network\s" ) # network object name regex string _RE_NETOBJ_NAME_STR = r'^object\s+network\s+(.*)' # compiled network object name compiled regex _RE_NETOBJ_NAME = re.compile(_RE_NETOBJ_NAME_STR) #network object type regex string, returns the type and data from this string _RE_NETOBJ_TYPE_STR = r'^(subnet|range|host|fqdn)\s+(.*)' #network compiled regex _RE_NETOBJ_TYPE = re.compile(_RE_NETOBJ_TYPE_STR) #network object description regex _RE_NETOBJ_DESC_STR = r'^description\s(.*)' #network object description _RE_NETOBJ_DESC = re.compile(_RE_NETOBJ_DESC_STR) #\s+(subnet|range|host|fqdn)\s+(.*) # dictionary of objects obj_dict = {} for line in obj_list: # for each object in the list line = line.lstrip() #remove the leading whitespace #get the important facts from the configuration lines if re.search(_RE_NETOBJ_NAME, line): obj_name = re.search(_RE_NETOBJ_NAME, line).group(1) obj_dict[obj_name] = {} elif re.search(_RE_NETOBJ_TYPE_STR, line): obj_type, obj_data = re.search(_RE_NETOBJ_TYPE_STR, line).group(1, 2) obj_dict[obj_name]['type'] = obj_type #obj_data needs to be further parsed if obj_type == "fqdn": obj_dict[obj_name]["fqdn"] = re.split("\s|/", obj_data).pop() elif obj_type == "host": obj_dict[obj_name]["host"] = obj_data elif obj_type == "subnet": network, subnet = re.split("\s|/", obj_data) obj_dict[obj_name]["network"] = network obj_dict[obj_name]["prefixlen"] = str(ipaddress.ip_network(network + '/' + subnet).prefixlen) #works for ipv4 and 6 elif obj_type == "range": range_first, range_last = obj_data.split(" ") obj_dict[obj_name]["range first"] = range_first obj_dict[obj_name]["range last"] = range_last elif re.search(_RE_NETOBJ_DESC, line): obj_desc = re.search(_RE_NETOBJ_DESC, line).group(1) obj_dict[obj_name]["desc"] = obj_desc # return the dictionary of objects return obj_dict
# Search the config for Interfaces, QoS and ACLs class_map_p = [] interfaces = [obj for obj in parse.find_objects("^interface") if obj.re_search_children(r"service-policy\soutput\s") ] # Create a regex that matches service policy but groups the policy-map name SERVICEPOLICY_RE = re.compile(r'service-policy\soutput\s(\S+)') INTERFACE_RE = re.compile(r'^interface\s(\S+)') CLASS_MAP_RE = re.compile(r'^class-map\smatch-any\s(\S+)') # Loop through the interfaces, looking for service-policy output. for intobj in interfaces: # if the interface has an output service-policy jump in if intobj.re_search_children("service-policy output"): # Find the class-map children of the policy-map - line terminated to stop half matches class_maps_t = parse.find_children("policy-map " + intobj.re_match_iter_typed(SERVICEPOLICY_RE, result_type=str) + "$") # CiscoConfParse helpfully includes the parent config, which we don't need so we remove it. class_maps_t.remove ("policy-map " + intobj.re_match_iter_typed(SERVICEPOLICY_RE, result_type=str)) # If there's only on class-map, it's a parent policy in a hirearchical shaper if len(class_maps_t) == 1: policy_map_parent = intobj.re_match_iter_typed(SERVICEPOLICY_RE, result_type=str) # Find all the children of the parent policy policy_map_c = parse.find_all_children("policy-map " + intobj.re_match_iter_typed(SERVICEPOLICY_RE, result_type=str)) # Step through them looking for the child policy-map name for pmap_p_child in policy_map_c: pmap_p_child_policy = re.search(r"service-policy (\S+)", pmap_p_child) if pmap_p_child_policy: # We've found it - set the child policy name child_policy = pmap_p_child_policy.group(1) class_maps_t = [] # Get the class maps for the policy-map
###################### ### install necessary modules ###################### import os from ciscoconfparse import CiscoConfParse import pprint # Enter your TFTP server path here tftp_path = '/var/lib/tftpboot/' ####################### ### Begin parsing through configurations ####################### #create empty dictionary testdict = {} #change working directory to TFTP server location os.chdir(tftp_path) #look in each file for the parent's stanza text for filename in os.listdir(tftp_path): parse = CiscoConfParse(filename) line_con = parse.find_children("line con 0") # this is the "parent" text you are looking for testdict[filename] = line_con pprint.pprint(testdict)
def testValues_find_children(self): ## test find_chidren for config, args, result_correct in self.find_children_Values: cfg = CiscoConfParse(config) test_result = cfg.find_children(**args) self.assertEqual(result_correct, test_result)
#Purpose: Compare latest Pingdom probe IP's to ASA configs and print if any differences are seen from ciscoconfparse import CiscoConfParse pingdom = [] sensors = [] ip = [] ips = [] with open('/mnt/c/users/me/Documents/misc/asa-configs') as configs: config_parse = CiscoConfParse(configs.readlines()) with open('/mnt/c/users/me/Documents/misc/pingdom-ips.txt') as ping: ping_ips = ping.readlines() pingdom = config_parse.find_children( "object-group network Pingdom_NA_Probes_grp") for item in pingdom: if "network-object object" in item: object = "object network " + item.split().pop() if object.split().pop() == item.split().pop(): sensors.append(config_parse.find_children(object)) for line in sensors: ip.append(line[1].strip().split().pop()) for line in ping_ips: ips.append(line.split("\",\"").pop().strip("\"\n")) print("IP's added: " + " ".join(set(ips).difference(set(ip)))) print("IP's removed: " + " ".join(set(ip).difference(set(ips))))
'peer': linelist[index + 4].strip(), 'map_id': linelist[index + 1] }) for line in crypto_maps: linelist = line.text.split(" ") index = linelist.index("Outside_map") for vpn in vpns: if linelist[index + 1] == vpn.get('map_id'): vpn['crypto_map'] = linelist[index + 4].strip() for vpn in vpns: vpn['groups'] = [] vpn['grp_obj'] = [] vpn['legacy'] = False for item in config_parse.find_children(vpn['crypto_map']): if len(item) >= 7 and item.split().pop(6) == "Prod_grp": vpn['legacy'] = True if item.split().pop(1) == vpn['crypto_map'] and item.split().pop( 8) and item.split().pop(8) not in vpn[ 'groups'] and item.strip().split().pop() != "inactive": vpn['groups'].append(item.split().pop(8)) for vpn in vpns: for grp in vpn['groups']: vpn['grp_obj'].append(grp_search(grp)) for vpn in vpns: print("*** Peer: " + vpn['peer'] + " Map-Seq: " + vpn['map_id'] + " LegacyIP: " + str(vpn['legacy']) + " Groups: " + " ".join(vpn['groups']) + " ***")
result_dict[switch] = output_list target.disconnect() for key in result_dict.keys(): outputfile = open('{0}.cfg'.format(key),'w') for line in result_dict[key]: outputfile.write(line + '\n') outputfile.close() parsed_switch_config = CiscoConfParse('{0}.cfg'.format(device_list[0])) parsed_fex_config = CiscoConfParse('{0}.cfg'.format(device_list[1])) switch_config_list = parsed_switch_config.find_children('^interface GigabitEthernet{0}/0/[0-9][0-9]*'.format(stack_number)) fex_config_list = parsed_fex_config.find_children('^interface') sw_intf_dict = {} fex_intf_dict = {} for line in switch_config_list: if 'interface' in line: i,intf = line.split() intf = intf[intf.rfind('/'):].strip('/') sw_intf_dict[intf] = [] else: sw_intf_dict[intf].append(line) for line in fex_config_list: if 'interface' in line:
#print("-------------------Finshed removing -Running.config from file name-------------------") #print(" ") header = "Switch" + " " + "Port W/O Dot1x" + " " + "Port Description" print(header) # #Start Examining configs for missing port security # for host in os.listdir(NEW_DIR): if host.startswith("p"): config_path = os.path.join(NEW_DIR, host) parse = CiscoConfParse(config_path) all_intfs = parse.find_objects(r"^interf") NoDot1x = list() NoDot1x = parse.find_objects_wo_child(r'^interface', r'authentication') #Remove Non Gig Ports because all user ports are 1 gig GigPorts = [ x.text.split()[1] for x in NoDot1x if x.text.startswith("interface Gig") ] #Remove Cisco 3750 Exansion module final_list = [ w for w in GigPorts if not re.match(r'GigabitEthernet./1/.', w) ] #Gets Port Descriptions for ports in final_list: port = "interface" + " " + ports intconfig = parse.find_children(port, exactmatch=True) desc = [x for x in intconfig if re.search("description", x)] result = host + ' ' + ''.join(ports) + ' ' + ''.join(desc) print(result.replace('description', ''))
len(all_addresses)), debug=debug, indent=2) # if "vpnmonitor" in instance: # script_logger(data=interfaces, debug=debug) # script_logger(data=addresses, debug=debug) # script_logger(data=vrf_duplicate, debug=debug) if vrf_duplicate: return all_addresses, vrf_duplicate else: return all_addresses, "NO_DUPLICATES" interfaces = parse.find_children(r"^interfaces ")[1:] print("**Getting All addresses from the configuration") all_addresses = get_all_addresses(interfaces) routing_instances = parse.find_children('^routing-instances') # pprint(routing_instances) ri_vrfs = [] for ri in routing_instances: ri_config = parse.find_children(ri) if "instance-type vrf" in ri_config[1]: ri_vrfs.append(ri) last_instance = ri_vrfs[-1]