Tuesday, December 11, 2007

easier networking with hamachi

Sorry for the crappy formatting. Blogger is doing too much for me and thereby preventing me from doing what I want easily, css-wise. So I've hacked styles into spans manually for now. I'll get this fixed later.

I'm a big fan of hamachi. It's an easy way to access all of your machines whether they have a static IP address or not and it's probably more secure than setting something up with a dynamic IP address and port forwarding.

Hamachi is a "zero-config, centrally managed VPN" that allows you to setup networks and join them with some simple client software. I won't go into the details of how to install and set it up. There's a pretty good description for Mac OS X and for linux. Once you've gotten your machines logged into the same network and given each a name with hamachi set-nick, you should be able to get a list of machines in your virtual network with their names like this:


[aykroyd@entoto ~]$ hamachi get-nicks
Retrieving peers' nicknames ..
[aykroyd@entoto ~]$ hamachi list
* [aykroyd-network]
* 5.71.134.95 electric-monk 71.200.230.164:33000
* 5.22.143.15 entoto 192.160.10.100:52000


You can now use the first IP address to get to your other machines. This is pretty cool, but the obvious next step is to want those nicknames to be in your /etc/hosts file so that you can refer to them by their name rather than the IP. To that end, I've put together a python script that I run in my system crontab every 15 minutes.


refresh-hosts.py
#!/usr/local/bin/python

import re
import subprocess

start_comment = "### start auto-generated hamachi hosts"
end_comment = "### end auto-generated hamachi hosts"

start_pattern = re.compile("^" + start_comment)
end_pattern = re.compile("^" + end_comment)

hostfile = "/etc/hosts"
username = "aykroyd"

def command_output(cmd):
" Capture a command's standard output. "
import subprocess
return subprocess.Popen(cmd.split(), stdout=subprocess.PIPE).communicate()[0]

def get_hamachi_hosts():
" Returns a list of (ip,name) tuples. "
output = command_output("sudo -H -u " + username + " hamachi list")
hosts = list()
for line in output.splitlines():
values = line.split()
if len(values) == 4:
hosts.append((values[1], values[2]))
return hosts

def main():
# make sure that hamachi is started and logged in
status = subprocess.call(("sudo -H -u " + username + " hamachi start").split())
if status != 0 and status != 255:
print "ERROR: problem starting hamachi status " + str(status)
return 1

status = subprocess.call(("sudo -H -u " + username + " hamachi login").split())
if status != 0:
print "ERROR: problem logging into hamachi"
return 1

# populate the nicknames so that we can create host entries
status = subprocess.call(("sudo -H -u " + username + " hamachi get-nicks").split())
if status != 0:
print "ERROR: problem getting nicknames from hamachi"
return 1

buffer = ""
in_hamachi_hosts = False

file = open(hostfile)
for line in file.readlines():
if not in_hamachi_hosts and start_pattern.match(line) != None:
in_hamachi_hosts = True
elif in_hamachi_hosts and end_pattern.match(line) != None:
in_hamachi_hosts = False
elif not in_hamachi_hosts:
buffer += line

file.close()

buffer += start_comment + '\n'

hosts = get_hamachi_hosts()
for host in hosts:
buffer += host[0] + '\t' + host[1] + '\n'

buffer += end_comment + '\n'

file = open(hostfile, 'w')
file.write(buffer)

return 0

if __name__ == "__main__":
import sys
sys.exit(main())


This setup has made life a lot easier for me. I can always get to my server at home and scripts to rsync my development environment now can refer to just a host name, instead of a parameterized IP that I figure out at the time that I run it.