It’s been awhile since I wrote something. Now I wanna show you how to make changes into DNS records managed by CPanel with Ruby and Mechanize.

Everyone remembers services like dyndns and no-ip, but when we got a hosting and a domain name at some place like Hostmonster, we still want to point a subdomain to our home server. But it’s pretty annoying to log into Cpanel and change the records manually. So I wrote this little tool.

This specific code works for Hostmonster, but it’s easily extensible to any(I guess) Cpanel based hosting.

First you need to install ruby with mechanize and json libraries. In a Debian/Mint/Ubuntu way you can do typing the next on console:

sudo apt-get install ruby ruby-mechanize ruby-json

Next you need the following code:

#!/usr/bin/env ruby

require 'mechanize'
require 'json'

USERNAME	= 'MY_USERNAME'
PASSWORD	= 'MY_PASSWD'
DOMAIN		= 'positrones.net'
SUBDOMAIN	= 'my_subdomain'
ADDRESS		= '0.0.0.0' # If nil then try to get automagicaly

URLS = {
			'login'		=> 'https://login.hostmonster.com/?',
			'drecords'	=> 'https://my.hostmonster.com/cgi/dm/zoneedit/ajax'
		}

USER_AGENT = 'Windows IE 9'

m = Mechanize.new do |a|
	a.verify_mode = OpenSSL::SSL::VERIFY_NONE
	a.user_agent_alias = USER_AGENT
end

def get_ip
  r = Net::HTTP.get('myip.positrones.net', '/')
  ip = r.match(/\d{1,4}\.\d{1,4}\.\d{1,4}\.\d{1,4}/)

  ip[0].to_s
end

# Do the login stuff
print "Checking user and password... "
page = m.get( URLS['login'] );
form = page.form_with( :name => 'theform' )
form['login'] = USERNAME
form['password'] = PASSWORD
send_button = form.button_with(:value => 'Login')
form.click_button(send_button)
page = page.links[0].click
puts "done!"

# Edit the DNS Zone
page = page.link_with(:text => 'DNS Zone Editor').click
print "Getting old zone records... "
json = JSON.parse( m.post( URLS['drecords'], {'op' => 'getzonerecords', 'domain' => DOMAIN} ).body )
puts "done!"

print "Trying to get subdomain old info... "
json['data'].each do |r|
	if r['name'] == SUBDOMAIN
		print "done!\nSaving new address[#{r['address']} => #{ADDRESS||get_ip}]... "
		json = m.post( URLS['drecords'], {'op'		=> 'editzonerecord',
									'domain'		=> DOMAIN,
									'name'			=> SUBDOMAIN,
									'orig__name'	=> SUBDOMAIN,
									'address'		=> ADDRESS||get_ip,
									'orig__adress'	=> r['address'],
									'ttl'			=> r['ttl'],
									'orig__ttl'		=> r['ttl'],
									'Line'			=> r['Line'],
									'type'			=> r['type']}
			)
		json = JSON.parse(json.body)

		if( json['result'] == 1 )
			puts "done!\nAddress changed succesfully!"
			Kernel::exit(0)
		else
			puts "\nAn error has ocurred trying to save new address :("
			Kernel::exit(1)
		end
	end
end

puts "The subdomain #{SUBDOMAIN} cannot be found!"
Kernel::exit(1)

The first lines just load the libraries «mechanize» and «json».
Then we stablish the data of the hosting provider, the names are self explanatory, just few points:

  1. The domain must not have the www
  2. The subdomain must be alone. If you wanna change «code.positrones.net» just type «code»
  3. You can specify the new IP address of the A record. If you wanna use your public IP address to be detected, change to nil

The URLS hash contains the information of the login page and the ajax DNS editor of the Cpanel, change it to fit your needs😉

The USER_AGENT it’s an id defined in the Mechanize library, in this case we want to identify as IE 9.

The login process usually takes place through an encrypted connection(HTTPS), then, for reasons not exposed here, we deactivate the verification of the SSL certificate and then set the USER_AGENT.

Then we define a method called get_ip, this method connects to a site which only returns the IP address of the client.

The rest of code log in into Cpanel, go to DNS Zone Editor and change the information of the given subdomain. The use Mechanize library it’s exposed in other post, you can read it if you wanna know the details.

The program returns 0 if everything goes fine, 1 in other case. By the way, I didn’t write some error management sentences, so be careful when use this code.

You can download from here.

Enjoy.🙂

Comments are closed.