#!/usr/bin/python # -*- encoding: utf-8 -*- # *************************************************************************************** # get_routing_table.py # Retrieves a list of the router's interfaces and the routing table using SNMP queries. # *************************************************************************************** # v2.0 (c) Jarmo Pietiläinen 2013-2014 # Licensed under the zlib/libpng license. # *************************************************************************************** # Tested with Python 2.7.x under Debian 7 (Wheezy) and 8 (Jessie), XUbuntu 13.10 and # Windows 7. Requires pysnmp and pyasn1 libraries to be installed. # I do not know if this works with Python 3. # *************************************************************************************** import sys from pysnmp.entity.rfc3413.oneliner import cmdgen # subnet mask -> CIDR prefix length lookup table subnet_masks = { "128.0.0.0" : 1, "255.128.0.0" : 9, "255.255.128.0" : 17, "255.255.255.128" : 25, "192.0.0.0" : 2, "255.192.0.0" : 10, "255.255.192.0" : 18, "255.255.255.192" : 26, "224.0.0.0" : 3, "255.224.0.0" : 11, "255.255.224.0" : 19, "255.255.255.224" : 27, "240.0.0.0" : 4, "255.240.0.0" : 12, "255.255.240.0" : 20, "255.255.255.240" : 28, "248.0.0.0" : 5, "255.248.0.0" : 13, "255.255.248.0" : 21, "255.255.255.248" : 29, "252.0.0.0" : 6, "255.252.0.0" : 14, "255.255.252.0" : 22, "255.255.255.252" : 30, "254.0.0.0" : 7, "255.254.0.0" : 15, "255.255.254.0" : 23, "255.255.255.254" : 31, "255.0.0.0" : 8, "255.255.0.0" : 16, "255.255.255.0" : 24, "255.255.255.255" : 32 } # subnet mask -> prefix length, returns 0 if invalid/zero def mask_to_prefix(mask): return subnet_masks.get(mask, 0) # returns True if the IP address is valid, False if not def is_valid_ip(ip_str): try: b = [int(o) for o in ip_str.strip().split(".")] except: return False if (len(b) != 4) or (min(b) < 0) or (max(b) > 255): return False return True # given a dotted OID string, this extracts an IPv4 address from # the end of it (ie. the last four decimals) def extract_ip_from_oid(oid): return ".".join(oid.split(".")[-4:]) # --------------------------------------------------------------------------------------- if len(sys.argv) != 3: quit("Usage: get_routing_table.py ") ip = sys.argv[1] if not is_valid_ip(sys.argv[1]): quit("%s is not a valid IPv4 address" % (ip)) command_generator = cmdgen.CommandGenerator() authentication = cmdgen.CommunityData(sys.argv[2]) target = cmdgen.UdpTransportTarget((ip, 161)) # send a GETBULK request for the OIDs we want snmp_engine_error, error_status, error_index, variables = command_generator.bulkCmd( authentication, target, 0, 25, # destination network <-> subnet mask "1.3.6.1.2.1.4.21.1.11", # destination network <-> next-hop interface address "1.3.6.1.2.1.4.21.1.7", # interface index <-> ip address "1.3.6.1.2.1.4.20.1.2", # interface ip <-> subnet mask "1.3.6.1.2.1.4.20.1.3", # interface index <-> name (MIB extensions) "1.3.6.1.2.1.31.1.1.1.1" ) if snmp_engine_error: quit(snmp_engine_error) if error_status: quit("%s at %s" % (error_status.prettyPrint(), error_index and variables[int(error_index) - 1][0] or '?')) # extract the data we need from the response if_index_to_name = {} if_index_to_address = {} if_ip_to_subnet_mask = {} destination_mask = {} destination_next_hop = {} longest = 0 for r in variables: for name, val in r: oid = name.prettyPrint() value = val.prettyPrint() # == INTERFACES == # 1-based index <-> interface name if oid[0:23] == "1.3.6.1.2.1.31.1.1.1.1.": if_index_to_name[int(oid[oid.rindex(".") + 1:])] = value longest = max(longest, len(value)) # 1-based index <-> interface ip address if oid[0:20] == "1.3.6.1.2.1.4.20.1.2": if_index_to_address[int(value)] = extract_ip_from_oid(oid) # ip address <-> subnet mask if oid[0:20] == "1.3.6.1.2.1.4.20.1.3": if_ip_to_subnet_mask[extract_ip_from_oid(oid)] = value # == ROUTING TABLE == # destination network address <-> subnet mask if oid[0:21] == "1.3.6.1.2.1.4.21.1.11": destination_mask[extract_ip_from_oid(oid)] = value # destination network address <-> next-hop address if oid[0:20] == "1.3.6.1.2.1.4.21.1.7": destination_next_hop[extract_ip_from_oid(oid)] = value # print a list of interfaces print("Interfaces") if len(if_index_to_name) == 0: print("Could not get the interface table, dumping raw data instead") print(if_index_to_address) print(if_ip_to_subnet_mask) for i in if_index_to_name: padded_name = if_index_to_name[i].ljust(longest, ".") + ": " if i not in if_index_to_address: print(" " + padded_name + " (no address)") continue ip = if_index_to_address[i] if ip in if_ip_to_subnet_mask: mask = "/" + str(mask_to_prefix(if_ip_to_subnet_mask[ip])) else: mask = " (unknown subnet mask)" print(" " + padded_name + ip + mask) #print the routing table print("\nRouting table") for d in destination_mask: if d not in destination_next_hop: next_hop = "(unknown)" else: addr = destination_next_hop[d] if addr == "0.0.0.0": next_hop = " (directly connected)" else: next_hop = " via " + addr print(" " + d + "/" + str(mask_to_prefix(destination_mask[d])) + next_hop)