玩了hostmonitor,老外写的很好。但是不符合国情,只有邮件适合发送。
今天用python 写一个自动发现ip,ping失败报警的程序。(微信和邮件报警)
以前用python写的发微信,发邮件直接导入即可。
# -*- coding: utf-8 -*- # ping for Windows import os import sys import socket import struct import select import time import ConfigParser import weixin import mail class getcfg(object): def __init__(self,filename): self.filename=filename self.cfg=ConfigParser.ConfigParser() self.cfg.read(self.filename) #self.allip=self.cfg.items('allip') self.retry=self.cfg.get('rule','retry') self.timeout=self.cfg.get('rule','timeout') self.reload=self.cfg.get('rule','next_check') self.scan=self.cfg.items('scan_network') self.mailto=self.cfg.items('mail','mail_to') #发送邮件报警 def sendmessage(self,failip): weixin.sendMessage('@all','ping %s failed.'% failip) for key,value in self.mailto: mail.send(value,"ping %s failed." % failip,'python ping fail') #判断要扫描ip def scan_network(self): self.scan.sort() allip=self.cfg.items('allip') i=0 while i < len(self.scan): ipbegin=int(self.scan[i][1].split('.')[-1]) ipend=int(self.scan[i+1][1])+1 for x in range(ipbegin,ipend): ipvalue=self.scan[i][1].split('.')[0]+'.'+self.scan[i][1].split('.')[1]+'.'+self.scan[i][1].split('.')[2]+'.'+str(x) ip_dict=[] for k,v in allip: ip_dict.append(v) if ipvalue in ip_dict: pass else: #执行扫描 self.to_ping(ipvalue,int(self.timeout)) i=i+2 #执行扫描 def to_ping(self,ip_addr,timeout): print 'scan ip ' + ip_addr, try: delay = ping(self.filename).ping_once(ip_addr, timeout) if delay == None: print 'failed. (timeout within %s second.)' % timeout else: print 'get reply in %0.4f ms' % (delay * 1000) self.scan_resule(ip_addr) except socket.gaierror, e: print "failed. (socket error: '%s')" % e[1] #判断扫描结果,如果有新扫描到的ip则保存到配置文件 def scan_resule(self,ip_addr): allip=self.cfg.items('allip') ip_dict=[] for k,v in allip: ip_dict.append(v) if ip_addr in ip_dict: pass else: self.cfg_write(ip_addr) #保存扫描到的ip到配置文件 def cfg_write(self,ipvalue): ipkey='auto_'+str(time.time()) self.cfg.set('allip',ipkey,ipvalue) self.cfg.write(open('ping_monitor.txt','w')) #去执行ping类 def to_ping(self): allip=self.cfg.items('allip') for k,v in allip: if len(v) >0: ping(self.filename).icmp_ping(v,int(self.timeout),int(self.retry)) #下次执行扫描时间 def next_check(self): while True: self.to_ping() print('------------------------------------------------------------') nextcheck=0 while nextcheck < int(self.reload): sys.stdout.write('next check %s second ' % (int(self.reload)-nextcheck)) sys.stdout.flush() time.sleep(1) nextcheck=nextcheck+1 self.scan_network() print('------------------------------------------------------------') class ping(object): def __init__(self,filename): self.ICMP_ECHO_REQUEST = 8 self.filename=filename def receive_ping(self,my_socket, ID, timeout): start_time = timeout while True: start_select = time.clock() what_ready = select.select([my_socket], [], [], start_time) how_long = (time.clock() - start_select) if what_ready[0] == []: #timeout return time_received = time.clock() rec_packet, addr = my_socket.recvfrom(1024) icmp_header = rec_packet[20 : 28] ip_type, code, checksum, packet_ID, sequence = struct.unpack("bbHHh", icmp_header) if ip_type != 8 and packet_ID == ID: # ip_type should be 0 byte_in_double = struct.calcsize("d") time_sent = struct.unpack("d", rec_packet[28 : 28 + byte_in_double])[0] return time_received - time_sent start_time = start_time - how_long if start_time <= 0: return def get_checksum(self,source): checksum = 0 count = (len(source) / 2) * 2 i = 0 while i < count: temp = ord(source[i + 1]) * 256 + ord(source[i]) # 256 = 2^8 checksum = checksum + temp checksum = checksum & 0xffffffff # 4,294,967,296 (2^32) i = i + 2 if i < len(source): checksum = checksum + ord(source[len(source) - 1]) checksum = checksum & 0xffffffff # 32-bit to 16-bit checksum = (checksum >> 16) + (checksum & 0xffff) checksum = checksum + (checksum >> 16) answer = ~checksum answer = answer & 0xffff # why? ans[9:16 1:8] answer = answer >> 8 | (answer << 8 & 0xff00) return answer def send_ping(self,my_socket, ip_addr, ID): ip = socket.gethostbyname(ip_addr) my_checksum = 0 header = struct.pack('bbHHh', self.ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1) byte_in_double = struct.calcsize("d") # C type: double data = (192 - byte_in_double) * "P" # any char is OK, any length is OK data = struct.pack("d", time.clock()) + data my_checksum = self.get_checksum(header + data) header = struct.pack("bbHHh", self.ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1) packet = header + data my_socket.sendto(packet, (ip, 80)) # it seems that 0~65535 is OK (port?) def ping_once(self,ip_addr, timeout): icmp = socket.getprotobyname('icmp') try: my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp) except socket.error: raise my_ID = os.getpid() & 0xFFFF self.send_ping(my_socket, ip_addr, my_ID) delay = self.receive_ping(my_socket, my_ID, timeout) my_socket.close() return delay def icmp_ping(self,ip_addr,timeout,count): number=1 for i in range(count): print 'ping ' + ip_addr, try: delay = self.ping_once(ip_addr, timeout) if delay == None: print 'failed. (timeout within %s second.)' % timeout if number==count: print('The request has failed %s times,Email alerts are being sent' % count) getcfg(self.filename).sendmessage(ip_addr) else: print 'get reply in %0.4f ms' % (delay * 1000) break except socket.gaierror, e: print "failed. (socket error: '%s')" % e[1] break number=number+1 if __name__ == '__main__': weixin=weixin.WeChat() mail=mail.sendmail() cfgname='ping_monitor.txt' ping(cfgname) pingcfg=getcfg(cfgname) pingcfg.next_check()
配置文件
[rule] retry = 4 timeout = 1 next_check = 300 #单位都是秒 [scan_network] 3paragraph_begin = 10.1.3.198 3paragraph_end = 202 2paragraph_begin = 10.1.2.1 2paragraph_end = 10 [mail] mailto1=guoyabin@ccln.gov.cn mailto2=lzt417@126.com [allip] #这里会自动把扫描到的ip写入