Python 路由器IP变更邮件通知
最近遇到一个问题:实验室内部的网络是通过路由器分配IP的,但是经常又需要通过校园网远程实验室内部的电脑,而路由器的外网IP是由DHCP服务器动态分配的,IP地址无法绑定成静态的。RadminViewer远程的速度比较快,但是没办法穿墙,必须知道直连的IP地址,通过在实验室的路由器上设置转发端口,就可以实现实验室内部多台电脑同时远程。但是由于路由器上IP会变,自然想到在服务器上运行一个程序,每隔一段时间监测下路由器的IP,如果变化,就发送邮件通知。
使用Python编写,由于是一个后台的程序,自然想到要做出服务,就不会有窗口一直显示。将Python程序以Windows 服务方式启动,需要用到pywin32。
本来想实现可以获取每一层的IP,因为网络可能经过了多层的IP地址转换。但还不知道怎么做,最后参考了这里的方法后,目前是只能针对TP-Link的路由器获取外网IP,其他路由器没测试过。
后面还可以进一步扩展,实现很多功能,然后可以发邮件通知。使用的时候,需要先安装服务,然后再启动。服务安装后,默认是手动启动,如果需要设置为自动启动,还需要到Windows管理工具,服务设置中,将该服务设置为自动启动。
1 #-*- encoding: utf-8 -*- 2 3 #Service install 安装 4 #Service start 启动 5 #Service stop 停止 6 #Service debug 调试 7 #Service remove 删除 8 9 import win32serviceutil 10 import win32service 11 import win32event 12 import smtplib 13 import time, traceback 14 import threading 15 import logging 16 import win32evtlogutil 17 18 class Service(win32serviceutil.ServiceFramework): 19 _svc_name_ = "IPDetector" 20 _svc_display_name_ = "IPDetector" 21 _svc_description_ = "Detect the change status of router IP, and send mail to notify user." 22 _svc_deps_ = ["EventLog"] 23 _sleep_time_ = 20 * 60 #时间以秒为单位 24 _username_ = 'admin'#路由器用户名 25 _password_ = 'admin'#路由器密码 26 _routerIP_ = '192.168.1.1'#路由器内部IP 27 _mail_list_ = [ 28 "mail1@qq.com", 29 "mail2@qq.com" 30 ] 31 _currentIP_ = '' 32 33 def __init__(self, args): 34 win32serviceutil.ServiceFramework.__init__(self, args) 35 self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) 36 print u'Service is running...' 37 38 def SvcDoRun(self): 39 import servicemanager 40 timer = threading.Timer(self._sleep_time_, self.process()) 41 timer.start() 42 # Write a 'started' event to the event log... 43 win32evtlogutil.ReportEvent(self._svc_name_, 44 servicemanager.PYS_SERVICE_STARTED, 45 0, # category 46 servicemanager.EVENTLOG_INFORMATION_TYPE, 47 (self._svc_name_, '')) 48 # wait for beeing stopped... 49 win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE) 50 51 # and write a 'stopped' event to the event log. 52 win32evtlogutil.ReportEvent(self._svc_name_, 53 servicemanager.PYS_SERVICE_STOPPED, 54 0, # category 55 servicemanager.EVENTLOG_INFORMATION_TYPE, 56 (self._svc_name_, '')) 57 return 58 59 def SvcStop(self): 60 # Before we do anything, tell SCM we are starting the stop process. 61 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 62 # And set my event 63 win32event.SetEvent(self.hWaitStop) 64 return 65 66 def send_mail(self, mail_list, msg): 67 try: 68 handle = smtplib.SMTP('smtp.163.com', 25) 69 handle.login('mail@163.com','password') 70 for mail in mail_list: 71 send_msg = "To:" + mail + "\r\nFrom:mail@163.com\r\nSubject: The latest router IP \r\n\r\n"\ 72 + msg +"\r\n" 73 handle.sendmail('mail@163.com', mail, send_msg) 74 handle.close() 75 return True 76 except: 77 print traceback.format_exc() 78 return False 79 80 def getRouterPublicIP(self, username, password, routerIP): 81 # this provide a way to get public ip address from tp-link 82 import httplib, re, base64 83 showErrorMessage = 0 84 85 # 192.168.1.1 86 conn = httplib.HTTPConnection(routerIP) 87 # set request headers 88 headers = {"User-Agent": "python host", 89 "Content-type": "application/x-www-form-urlencoded", 90 "Authorization": "Basic %s" % base64.encodestring('%s:%s' % (username, password))[:-1], 91 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 92 "Accept-Language": "zh-cn,zh;q=0.5", 93 "Accept-Encoding": "gzip, deflate", 94 "Accept-Charset": "GB2312,utf-8;q=0.7,*;q=0.7", 95 "Connection": "keep-alive"} 96 97 # get status page 98 conn.request("GET", "/userRpm/StatusRpm.htm", "", headers) 99 response = conn.getresponse() 100 keyword = re.search(' wanPara [^\)]*?\)', response.read()) 101 response.close() 102 conn.close() 103 104 # search the public ip address 105 found = 0 106 publicIP = "" 107 if keyword: 108 arr = re.findall('([\d]*?,)|(\"[^\"]*?\",)', keyword.group(0)) 109 if arr: 110 if len(arr) > 3: 111 publicIP = re.search('(?<=\")[^\"]*?(?=\")', arr[2][1]) 112 if publicIP: 113 publicIP = publicIP.group(0) 114 found = 1 115 116 if found == 1: 117 return publicIP 118 else: 119 if showErrorMessage == 1: 120 logging.info('router public ip address not found.') 121 #print "router public ip address not found." 122 123 def process(self): 124 latestIP = self.getRouterPublicIP(self._username_, self._password_, self._routerIP_) 125 logging.info('the latest router ip is: ' + latestIP) 126 #print 'the latest router ip is: ' + latestIP 127 if self._currentIP_ != latestIP: 128 _currentIP_ = latestIP 129 msg = u'The latest router IP is: ' + str(_currentIP_) 130 print time.strftime('%Y-%m-%d %X',time.localtime(time.time())) 131 if self.send_mail(self._mail_list_, msg): 132 logging.info('send mail success') 133 #print 'send mail success' 134 else: 135 #print 'send mail failed' 136 logging.info('send mail failed') 137 138 if __name__ == '__main__': 139 win32serviceutil.HandleCommandLine(Service)