#!/usr/bin/env python
#
# ecpZoneUpdate 0.2
# for more information, visit http://www.ecpsoftware.com
# or contact douglas.savitsky@ecpsoftware.com
#
# ecpZoneUpdate (c) 2003 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()