#!/usr/bin/env python # # ecpZoneUpdate 0.2 # for more information, visit http://www.ecpsoftware.com # or contact douglas.savitsky@ecpsoftware.com # # ecpZoneUpdate (c) 2002 ecpsoftware, douglas savitsky # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # Tested to run under Windows 2000, FreeBSD 4.7 # # Last updated 01/28/2002 # # This software borrows somewhat from zoneclient.py # available from http://zoneclient.sourceforge.net # which is (c) kal@users.sourceforge.net # (as of this writing, an unreachable address) # # Thanks to Will Gunadi for a D-Link router patch. import base64 import httplib import os import re import time import urllib _uagent = 'ecpZoneUpdate' _version = '0.2' # this re finds ip numbers, but also can find incorrect ones! # the more correct re is much longer, however, and this # should be sufficient here. _ip_regex = "(?:\d{1,3}\.){3}\d{1,3}" # defines specific router things. This will expand as more routers # are added. _router_options = { 'Netgear RT311' : {'path' : '/mtenSysStatus.html'}, 'D-Link DI-604' : {'path' : '/st_devic.html'} } # USER OPTIONS # the INTERNAL ip of the router, this defaults to the, well, to the default. _router_ip = '192.168.0.1' # your router's model. Options are # 'Netgear RT311' or 'D-Link DI-604' # to skip the router and get the IP from the web, use 'zoneedit.com' here _router_model = 'Netgear RT311' # where to write logs and store the IP. Change this to suit your OS _path = '/usr/local/ecpZoneUpdate' #_path = 'C:\\ecpZoneUpdate' # where to store the last reported ip _ip_file = 'ip.txt' # set to '' to turn off logging _log_file = 'ecpZU.log' # router username # if you are using 'zoneedit.com' as your _router_model # you can ignore this option _runame = 'admin' # router password # if you are using 'zoneedit.com' as your _router_model # you can ignore this option _rpassword = '1234' # zoneedit username _zuname = 'username' # zoneedit password _zpassword = '********' # zones (must be in a list or tuple) _zones = ['MyDomain.com'] # IP's you can't have (filtered out from the page returned by the router) _bad_ip_list = ['0.0.0.0', '255.255.255.0', '255.255.255.255', _router_ip] def get_current_zip(file): # this is longer than necessary in case there is other crap in the file try: f = open(file, 'r') except: # the file does not exist yet so send no ip return '0.0.0.0' ipd = f.read() f.close() ip = re.findall(_ip_regex, ipd) for i in ip: if i not in _bad_ip_list: return i break return '0.0.0.0' def get_ip(uname, pw): if _router_model == 'zoneedit.com': ip = _get_zedynamic_ip() else: # we'll try 5 times to get the ip as my router is spotty # i've never seen it take more than 3 tries though ;-) tries = 5 while 1: ip = _get_router_ip(uname, pw) if tries == 0: break else: if ip == '0.0.0.0': tries -= 1 else: break # if the router has failed to give the IP, try to get # it from zoneedit's site if ip == '0.0.0.0': ip = _get_zedynamic_ip() return ip def _get_router_ip(uname, pw): # more or less lifted from zoneclient.py h = httplib.HTTP(_router_ip) h.putrequest('GET', _router_options[_router_model]['path']) h.putheader('USER-AGENT', '%s/%s' % (_uagent, _version)) a = base64.encodestring("%s:%s" % (uname, pw)) h.putheader('AUTHORIZATION', 'Basic %s' % a) h.endheaders() a,b,c = h.getreply() f = h.getfile() ipd = f.read() f.close() l = re.findall(_ip_regex, ipd) ip = '0.0.0.0' for i in l: if i not in _bad_ip_list: ip = i return ip def _get_zedynamic_ip(): try: f = urllib.urlopen('http://dynamic.zoneedit.com/checkip.html') s = f.read() l = re.findall(_ip_regex, s) if len(l) == 0: l = ['0.0.0.0'] except: l = ['0.0.0.0'] return l[0] # this page should only produce one IP number def set_zoneedit(uname, password, zones, ip): # XXX -> this should be changed to use https..., # XXX -> and probably to use urllib as well. h = httplib.HTTP('www.zoneedit.com') h.putrequest('GET', '/auth/dynamic.html?host=%s&dnsto=%s' % (','.join(zones), ip)) h.putheader('HOST', 'www.zoneedit.com') h.putheader('USER-AGENT', '%s/%s' % (_uagent, _version)) a = base64.encodestring('%s:%s' % (uname, password)) h.putheader('AUTHORIZATION', 'Basic %s' % a) h.endheaders() errcode, errmsg, headers = h.getreply() # is this next step necessary to do? try: f = h.getfile() dta = f.read() f.close() except: pass return errcode def set_current_zip(file, ip): f = open(file, 'w') f.write(ip) f.close() def main(times=75): file_ip = get_current_zip(os.path.join(_path, _ip_file)) if _log_file == '': import StringIO log = StringIO.StringIO() else: log = open(os.path.join(_path, _log_file), 'a') new_ip = get_ip(uname=_runame, pw=_rpassword) if new_ip == '0.0.0.0': print >>log, '%s :: Router = 0.0.0.0, sleeping for retry' % time.ctime() log.flush() log.close() times -= 1 if times > 0: time.sleep(30) main(times) elif file_ip == new_ip: print >>log, '%s :: No updates made (%s == %s).' % (time.ctime(time.time()), file_ip, new_ip) else: print >>log, '%s :: Setting IP [%s >> %s]' % (time.ctime(time.time()), file_ip, new_ip) try: zu = set_zoneedit(_zuname, _zpassword, _zones, new_ip) print >>log, ' Zoneedit return -> %s' % zu set_current_zip(os.path.join(_path,_ip_file), new_ip) print >>log, ' Update succeeded.' print 'IP Updated to %s' % new_ip except: print >>log, ' Failed' print 'IP Update failed' log.flush() log.close() if __name__ == '__main__': main()