Python Training: DynDNS auto-login

It's been a while, I know. For one reason or another I haven't been getting round to updating the blog lately. Worst thing is I do have a bunch of stuff to post, so I hope to keep it coming in the near future. Anyway, I've been trying to polish my python skills a little bit, because I have to admit, it has to be one of the sweetest scripting languages out there: tons of support, and libraries, really doesn't have a steep learning curve at all, object oriented (if you wish).... there's really nothing much I can say in the negative aspect.

For this second lil' script I figured we could do something helpful once again. Many of you might host a little web server at home, or like ssh access to your machine, but keep forgetting you static ip, or even worst, get a dynamic ip from you ISP. I use DynDNS to help me get around these small IP troubles. And as helpful as it is, it also comes with one fairly annoying string attached, when you get yourself the free account, you need to login once a month to avoid your name address from expiring. I just want a name for my IP, and I tend to keep forgetting to do these things. So every month or so, two if I was lucky, I'd find my name address gone. Python script to the rescue. You can add this script to your crontab, and it will login automatically for you with the username and password provided to the script. Not rocket science, but definitely helpful.

The most relevant stuff here is the use of urllib and urllib2, which allow us to encode parameters for an HTTP POST request, and perform the actual page requests. The whole login process also uses a cookie, which made us have to use the cookielib to set up a cookiejar. Before you login, you are given a cookie, which you need to store for the process to succeed. Once you have that sorted, you can submit that form together with the right parameters (including a hidden one you need to parse from the HTML output). I figured out my explanation isn't too clarifying, so without further ado, here's the script:

#!/usr/bin/python
import urllib
import urllib2
import cookielib
import getopt
import sys
def getRandHTMLResponse(response):
	target = "<form id=\'login"
	targetresponse = "<div id=\'loginbox\'"
	response = response[response.find(targetresponse):len(response)]
	return response[response.find(target)+len(target):response.find(target)+len(target):response.find(target)+len(target)+4]

def getHiddenRandHTMLResponse(response):
	target = "<input type=\'hidden\' name=\'multiform\' value=\'"
	targetresponse = "<div id=\'loginbox\'"
	parsedres = response[response.find(targetresponse):len(response)]
	return parsedres[parsedres.find(target)+len(target):parsedres.find(target)+len(target)+34]

def checkLogin(response):
	target = "<title>DynDNS.com - My Account</title>"
	if response.find(target) == -1:
		return False
	return True

class HTMLSession:
	cj = None
	opener = None
	txHeaders = None
	def __init__(self, txHeaders):
		#The CookieJar will hold any cookies necessary throughout the login process.
		self.cj = cookielib.MozillaCookieJar()
		self.txHeaders = txHeaders
		self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj))
		urllib2.install_opener(self.opener)
		
	def setHeaders(self, txheaders):
		self.txHeaders = txHeaders

	def getHeaders(self):
		return self.txHeaders

	def openURI(self, uri, txdata):
		try:
			req = urllib2.Request(uri, txdata, self.txHeaders)
			# create a request object
			handle = urllib2.urlopen(req)
			# and open it to return a handle on the url
		except IOError as e:
			print \'we failed to open "%s".\' % uri
			if hasattr(e, \'code\'):
				print \'We failed with error code - %s.\' % e.code
			elif hasattr(e, \'reason\'):
				print "The error object has the following \'reason\' attribute :"
				print e.reason
				print "This usually means the server doesn\'t exist,\'"
				print "is down, or we don\'t have an internet connection."
			return None
		return handle.read()

def main(argv):
	username = ""
	password = ""
	hiddenval = ""
	theurl = "https://www.dyndns.com/account/entrance/"
	thelogouturl = "https://www.dyndns.com/account/entrance/?__logout=1"
	txdata = None
	txheaders =  {\'User-agent\' : \'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)\'}
	# fake a user agent, some websites (like google) don\'t like automated exploration
	try:
		opts, args = getopt.getopt(argv, "hu:p:", ["help", "username=","password="])
	except getopt.GetoptError:
		usage()
		exit(2)
		
	for opt, arg in opts:
		if opt in ("-h", "--help"):
			usage()
			exit(2)
		elif opt in ("-u", "--username"):
			username = arg
		elif opt in ("-p", "--password"):
			password = arg
	myhtmlsession = HTMLSession(txheaders)
	response = myhtmlsession.openURI(theurl, None)
	if response == None:
		sys.exit(0)
	hiddenval = getHiddenRandHTMLResponse(response)
	txdata = urllib.urlencode({\'username\':username, \'password\':password, \'multiform\':hiddenval, \'submit\': "Log in"})
	response = myhtmlsession.openURI(theurl, txdata)
	if response == None:
		sys.exit(0)
	#we should sleep here for about 10 seconds.
	if checkLogin(response):
		print(\'We have succesfully logged into DynDNS.\')
		response = myhtmlsession.openURI(thelogouturl, None)
	if response == None:
		sys.exit(0)

if __name__ == "__main__":
	main(sys.argv[1:])
Written on December 31, 2010