#_*_ coding:utf8 _*_
import paramiko # SSH 登录操作模块
import time
import re # 字符匹配查找模块
import logging # 日志
Log = logging.getLogger("__name__") # 获取实例
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s') # 指定logger输出格式
file_handler = logging.FileHandler("Network_H3C.log") # 日志文件路径
file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式
Log.addHandler(file_handler) # 为logger添加的日志处理器
# 设置记录的日志级别
Log.setLevel(logging.DEBUG)
#Log.setLevel(logging.INFO)
#Log.setLevel(logging.WARNING)
#Log.setLevel(logging.ERROR)
#Log.setLevel(logging.CRITICAL)
## 各交换机信息字典,用于判断查到的接口是接的交换机还是电脑
S1 = {
'Version':'H3C Sxxxx-xx-xx',
'GigabitEthernet1/0/1':['防火墙'],
'GigabitEthernet1/0/2':['Switch','192.168.0.2'],
'GigabitEthernet1/0/2':['Switch','192.168.0.3'],
'GigabitEthernet1/0/3':['Null'],
'GigabitEthernet1/0/4':['Host'],
'GigabitEthernet1/0/19':['2F']
}
S2 = {
'Ethernet1/0/1':['核心'],
'Ethernet1/0/2':['Switch','192.168.0.21'],
'Ethernet1/0/3':['Host']
}
S3 = {
'Ethernet1/0/1':['核心'],
'Ethernet1/0/2':['Switch','192.168.0.31'],
'Ethernet1/0/3':['Host']
}
S21 = {
'Ethernet1/0/1':['Host'],
'Ethernet1/0/2':['Host'],
'GigabitEthernet1/0/25':['上级Switch','192.168.0.2'],
'GigabitEthernet1/0/26':['Host']
}
S31 = {
'Ethernet1/0/1':['Host'],
'Ethernet1/0/2':['Host'],
'GigabitEthernet1/0/25':['上级Switch','192.168.0.3'],
'GigabitEthernet1/0/26':['Host']
}
## 全部交换机的对应信息
SWITCH = {
'192.168.0.1':S1, '192.168.0.2':S2, '192.168.0.3':S3, '192.168.0.21':S21, '192.168.0.31':S31}
## 功能
def 查找MAC(深度,IP,mac):
if 深度 > 0:
print("剩余深度",深度)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(IP, 22, '用户名', '密码') # 这里设置填写交换机的地址端口用户名和密码,要根据实际情况设置
switch = ssh.invoke_shell()
time.sleep(1)
#print(switch.recv(1024))
r = '' # r 用来存储查找结果,先设置为空
CMD = 'display mac-address ' + mac # 组装执行的命令
switch.sendall(CMD + '\n')
time.sleep(1) # 各交换机1秒反应时间
r = switch.recv(1024).decode('utf-8') # 把执行结果全部保存到 r
print(r)
Log.debug(r)
PORT = re.search(r"[G|E](.*)[0-9]", r) # 匹配G或E开头数字结尾的内容:GigabitEthernet1/0/1 or Ethernet1/0/1
if PORT:
DEBUG = "发现 MAC" + str(PORT)
print(DEBUG)
Log.debug(DEBUG)
ssh.close() # 交换机上的操作已经完成,可以关闭连接
if SWITCH[IP][PORT.group()][0] == 'Switch': # 如果查到的接口是接的交换机
深度 = 深度 -1 # 准备继续查询下一级的交换机,设置深度,防止错误设置造成无限循环
IP = SWITCH[IP][PORT.group()][1] # 从设置的交换机信息字典中查询下一级交换机的IP地址
R = 查找MAC(深度,IP,mac) # 迭代执行,接收返回值
return(R) # 迭代执行必须每次都有返回给上级,不然外部接收不到返回内容,出现返回为 "None"
else: # 如果不是交换机
return(0,IP,PORT.group()) # 返回状态码(可以0表示)、MAC所在的交换机IP、端口
else:
INFO = '在 ' + IP + ' 未发现 ' + MAC
ssh.close()
Log.info(INFO)
return(1,INFO)
else:
ERROR = IP + '的 ' + PORT.group() + ' 超出深度'
Log.error(ERROR)
return(1,ERROR)
## 把用户输入的MAC地址格式转换为交换机使用的格式
def New_MAC(MAC):
mac = re.sub('[^a-fA-F0-9]', '', MAC) # 删除不是16进制范围内容
print(MAC)
print(mac)
print(len(mac))
if len(mac) == 12:
new_mac = mac[0:4] + '-' + mac[4:8] + '-' + mac[8:12] # 改成新格式 xxxx-xxxx-xxxx
print(new_mac)
print(new_mac.lower())
return(0, new_mac.lower())
else:
print("ERROR", mac)
return(1,'')
深度 = 3 # 设置本此最深可以进入第3级交换机
IP = '192.168.0.1' # 起始查找位置,使用核心交换机IP比较好
## 使用 CLI 命令行模式运行比较方便
import sys
if len(sys.argv) == 2:
MAC = sys.argv[1]
X = New_MAC(MAC)
if X[0] == 0:
R = 查找MAC(深度,IP,X[1])
print(R)
if R[0] == 0:
IP = R[1]
PORT = R[2]
INFO = '已找到,在 ' + str(IP) + ' 的 ' + str(PORT) + ' 详细信息 ' + str(SWITCH[IP][PORT])
Log.info(INFO)
print('V', INFO)
else:
INFO = R[1]
Log.info(INFO)
print('X',R[1])
else:
WARNING = "MAC有误,程序终止"
Log.warning(WARNING)
print(WARNING)
else:
WARNING = "参数有误,参数只能一个MAC地址"
Log.warning(WARNING)
print(WARNING)