瞻博网络交换机上的MAC地址搜索

在本地网络中,您通常需要找出设备的特定MAC地址位于交换机的哪个端口上。 如果网络中有多个交换机,则可以轻松解决该问题,但是当交换机数量超过30时,一切都会变得更加复杂。 我想共享一个小的Python脚本,该脚本在网络上寻找所需的MAC地址,并返回此MAC在其上注册的交换机的名称和端口。



欢迎进行建设性的批评。 细节剪下。

如果网络设计正确完成,即DS (分发交换机)分发交换机所连接的CORE根交换机,然后是访问级别AS (访问交换机)交换机。 此规则并不总是正确的;访问开关可以串联连接。 无论如何,上游交换机端口都包含连接到下游交换机的设备的所有MAC地址。

例如,如果我们感兴趣的设备连接到AS3交换机, 则从CORE开始搜索,我们将在通向DS1的端口上找到此地址。 转到DS1 ,我们将在通向AS2的端口上找到此MAC,再转到AS2 ,将看到它将我们引至AS3 ,只有在AS3上,我们才能找到目标设备所连接的特定端口。

我不想手动完成所有任务,将所有交换机循环排序,并确定上行链路在哪里,何处不是,所以我想分享下一个解决方案。

有点理论。


要在Juniper交换机上找到MAC 08:62:66:c7:b3:45 ,请运行以下命令:

show ethernet-switching table | match 08:62:66:c7:b3:45 

如果有这样的MAC,答案将如下所示:

 vlan151 08:62:66:c7:b3:45 D - xe-0/0/23.0 

最后一栏将是注册MAC的交换机的接口名称。 但是,如何了解该界面的方向呢? 此处的接口说明可助您一臂之力。 这些是交换机配置文件中的行,允许您为接口分配文本标签。

团队

 show interfaces xe-0/0/23 descriptions 

将显示以下内容:

 Interface Admin Link Description xe-0/0/23 up up SW>DS1 

在配置中,我们指示此接口通向下游交换机:

 set interfaces xe-0/0/23 description SW>DS1 

实作


建议的脚本将执行以下操作:

  1. 通过SSH连接到根交换机
  2. 检查参数中传递的MAC地址位于哪个接口上;
  3. 检查此接口的描述;
  4. 如果接口通向交换机,请递归访问链中的下一个交换机。

 #       searchpass = [] #main      MAC-    checkswitch,           MAC-.       searchpass   json. def main(argv): mac_addr = argv[0] checkswitch('CORE',mac_addr) for switch in searchpass: print (json.dumps(switch, ensure_ascii=False)) if __name__ == "__main__": main(sys.argv[1:]) #   MAC- def checkswitch(hostname,mac_addr): try: #    ,  host    returnvalue = {} returnvalue['host']=hostname #sendCommand      SSH     MAC-    answer = sendCommand(hostname,'show ethernet-switching table | match '+mac_addr) #   ,      #vlan151 08:62:66:c7:b3:45 D - xe-0/0/23.0 if(answer!=0): iface = answer.split()[4] returnvalue['iface']=iface # description ,    2  .0       #xe-0/0/23 up up SW>DS01 answer = sendCommand(hostname,'show interfaces '+iface[:-2]+' descriptions | last 1 | no-more') iface = answer.split() # description   ,      ,     SW>.  ,   3 ,         . if(len(iface)>2): iface=iface[3] returnvalue['description']=iface else: returnvalue['description']='none' searchpass.append(returnvalue) if (iface[:3]=='SW>'): checkswitch(iface[3:],mac_addr) else: returnvalue['iface']='none' searchpass.append(returnvalue) except Exception as e: print(e) 

因此,脚本将从内核开始遍历所有网络交换机,并尝试查找所需的MAC。 为了使操作成功,足以使接口的描述保持最新,并且拓扑几乎可以具有任何复杂性。

脚本示例:

 python findmac.py 00:17:fc:21:e8:f9 {"host": "CORE", "iface": "xe-0/0/23.0", "description": "SW>DS1"} {"host": "DS1", "iface": "xe-0/0/11.0", "description": "SW>AS2"} {"host": "AS2", "iface": "xe-1/0/1.0", "description": "SW>AS3"} {"host": "AS3", "iface": "ge-0/0/26.0", "description": "none"} 

如果没有MAC,我们得到

 {"host": "CORE", "iface": "none"} 

最后一行是我们感兴趣的交换机和端口,但同时我们可以跟踪整个搜索路径。

完整的代码位于破坏者的下面,感谢您的关注。

findmac.py
 import paramiko import time import sys import json import threading import logging login = 'user1' password = 'pass1234' searchpass = [] port = 22 class LogPipe(threading.Thread): def __init__(self, level): threading.Thread.__init__(self) self.daemon = False self.level = level self.fdRead, self.fdWrite = os.pipe() self.pipeReader = os.fdopen(self.fdRead) self.start() def fileno(self): return self.fdWrite def run(self): for line in iter(self.pipeReader.readline, ''): logging.log(self.level, line.strip('\n')) self.pipeReader.close() def close(self): os.close(self.fdWrite) def execute_ssh_command(host, port, username, password, command): try: # Create the SSH client. ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # Connect to the host. ssh.connect(host, port, username, password, look_for_keys=False) # Send the command (non-blocking) stdin, stdout, stderr = ssh.exec_command(command) # Wait for the command to terminate while not stdout.channel.exit_status_ready() and not stdout.channel.recv_ready(): time.sleep(1) stdoutstring = stdout.readlines() stderrstring = stderr.readlines() return stdoutstring, stderrstring finally: if ssh is not None: # Close client connection. ssh.close() def sendCommand (hostname,command): returnvalue = 0 logging.info('Host '+hostname+', command: '+command) Try: #add .mydomain for FQDN (stdoutstring, stderrstring) = execute_ssh_command(hostname+'.mydomain', port, login, password, command+'\n') if (len(stdoutstring)>0): logging.info(stdoutstring[0]) if (len(stderrstring)>0): logging.info(stderrstring[0]) except Exception as e: return returnvalue else: returnvalue = stdoutstring[0] finally: return returnvalue def checkswitch(hostname,mac_addr): try: returnvalue = {} returnvalue['host']=hostname answer = sendCommand(hostname,'show ethernet-switching table | match '+mac_addr) if(answer!=0): iface = answer.split()[4] returnvalue['iface']=iface #cut .0 prefix in the interface name answer = sendCommand(hostname,'show interfaces '+iface[:-2]+' descriptions | last 1 | no-more') iface = answer.split() if(len(iface)>2): iface=iface[3] returnvalue['description']=iface else: returnvalue['description']='none' searchpass.append(returnvalue) if (iface[:3]=='SW>'): checkswitch(iface[3:],mac_addr) else: returnvalue['iface']='none' searchpass.append(returnvalue) except Exception as e: logging.info(e) def main(argv): mac_addr = argv[0] #configure log logging.basicConfig(filename='/var/log/findmac.log', level=logging.INFO, format='%(asctime)s %(message)s') logging.info('Find MAC: '+mac_addr) checkswitch('CORE',mac_addr) for switch in searchpass: print (json.dumps(switch, ensure_ascii=False)) if __name__ == "__main__": main(sys.argv[1:]) 

Source: https://habr.com/ru/post/zh-CN420013/


All Articles