Groovy and DNS query to get your external IP address

I stumbled upon this Stackoverflow question:

and got interested into the way to get your external IP by using a DNS lookup, as presented in this answer:

It’s an interesting idea and implementation and I also agree with the poster:

  • DNS query is a bit faster
  • More importantly, I have a feeling it’s more reliable. I know that sites can be slow, DNS query is less likely to be so
  • Given the investment in hosting the DNS service on a large scale, they service is likely more robust and likely to stay there longer than sites

Anyway, if you are using Oracle Java, then you already have a JNDI DNS provider built-in. You can read more about it here:

This Stackoverflow question:

specifically this answer:

has an example code to query a generic DNS server, provided you know it’s IP address. Below is a Groovy script that combines the information from the above links:

  • Gives an example of how a default way to perform a DNS query would be – getIp method
  • Gives a way to perform DNS query on the specific DNS server – getIpUsingDnsServer method
  • Uses these to query to get your external IP

Read more about OpenDNS myip entry here:

Here’s the script itself:

import javax.naming.Context
import javax.naming.NamingEnumeration

class DnsPrb {
   static main(String[] args) {
      new DnsPrb().run()
   def run() {
      String dnsServer = ''
      String dnsIp = getIp dnsServer
      println("$dnsServer -> $dnsIp")
      def myIps = getIpUsingDnsServer dnsServer, ''
      println("myIps: $myIps")

   String getIpUsingDnsServer(String dnsServer, String name) {
      Properties env = new Properties()
      env.put Context.INITIAL_CONTEXT_FACTORY, 'com.sun.jndi.dns.DnsContextFactory'
      env.put Context.PROVIDER_URL, "dns://$dnsServer".toString()

      DirContext ictx = new InitialDirContext(env)
      String[] types = ["A", "AAAA"]
      Attributes attrs = ictx.getAttributes name, types

      NamingEnumeration<? extends Attribute> e = attrs.all
      def ips = e.collect { it.get() }

   String getIp(String name) {
      InetAddress dnsInetAddress = InetAddress.getByName name
      String ip = dnsInetAddress.hostAddress

Hosting a DNS server on Amazon EC2 micro instance

Amazon has been offering EC2 for a very long time, one thing that’s interesting is that right now they have a “free tier” offer (check this). With this, you get a micro instance free for one year. After that, with basic usage, you should pay no more then $15 a month if you prepay (see their pricing fro more info, especially the reserved instances part). This looked pretty good for me to test it out. I did not expect much, but I did not need much either. Here’s the story.

Sign up

If you don’t have the Amazon AWS account, create one first. You can use your regular Amazon account if you have one or you can create a separate one. After that, sign up for Amazon EC2 here. The process has several steps, but it’s not demanding – you will need about 10 minutes to finish it. Note that you may need to wait for the EC2 subscription to be processed – officially, the word is that you can wait for anything between a few minutes to a few hours. In my case, it was about an hour.

Setting up EC2 instance

All your EC2 management can be done from within AWS Management Console. You can use other tools, I’ve seen many posts about ElasticFox for example. I prefer to use ec2-api-tools from command line, as you will see below.

I use Ubuntu daily, so I naturally wanted to use it in EC2, too. Luckily, Ubuntu supports EC2 officially – take a look here for more info. I went for the 11.04 beta-2, images can be found here. Note that you can install them from within Amazon directly – they are officially on Amazon’s list of images. Just click on any of the ami IDs to see that – it will take you to a page such as this. The last link is what I used. It’s a 32-bit Natty, EBS-rooted image. The last point is important – micro instances do not have instance storage, they have to be backed up by Amazon Elastic Block Store (EBS).

To install it, look at the ec2 command column in Ubuntu’s list of AMIs. I used this:

$ ec2-run-instances ami-4c906c25 --instance-type t1.micro --region us-east-1 --key ec2-keypair

You need to install ec2-api-tools and prepare the ec2-keypair.pem file as per EC2 starter’s guide. In short, you go to AWS home page, go to Account/Security Credentials from the menu, then in Access Credentials part click on X.509 Certificates tab and do a Create a new Certificate (you can also upload your own). Download both the private key and the certificate itself to use with ec2 tools.

To connect to it, you first need to enable SSH port – do this:

$ ec2-authorize default -p 22

where ‘default’ is the default group and 22 is the SSH port. You can get the public IP address by running:

$ ec2-describe-instances

which should show the DNS name such as SSH to it:

$ ssh -i ec2-keypair.pem 

Ubuntu instances are generic, so they need to actually make the things that should be different from instance to instance on boot. One such thing is the SSH RSA host key that is used to connect to the instance via ssh. To see this, type:

$ ec2-get-console-output i-XXX

where i-XXX is the instance name that you can also see from the output of ec2-describe-instances. The fingerprint should be somewhere near the end of the output. You can successfully confirm the fingerprint and ssh now. Note that you need to log in as ubuntu, again that’s the default in Ubuntu’s instance.

One thing that you can do is make an Elastic IP – free of charge as long as it’s tied to a running instance, allows you do basically do internal remapping between instances if you wish. Set this up and use that IP going forward.

DNS server

Using tasksel, select install the DNS server:

sudo tasksel install dns-server

Now configure your DNS server. I won’t go into these details, you can take a look at some DNS configuration examples, such as this or this. For a small domain, it’s fairly simple.

Allow the DNS port to be reachable outside:

$ ec2-authorize default -P udp -p 53

Change your /etc/resolv.conf by adding a new nameserver in from of everything else for testing and then do a sample nslookup. If your server responds, you should be all set.