Iterative vs Recursive DNS resolver

There are two kinds of strategies that DNS resolvers can employ when answering a query. Recursive name resolvers effectively pass the query down the DNS hierarchy to find a server that contains the necessary information to answer the query. For example, let’s say we wanted to find the IP address of students.cs.ubc.ca. We’ll start by sending the query to some well known name server, like 1.1.1.1. It may not have the answer, so it will pass it on to another server (perhaps, the .ca nameserver, or the ubc.ca nameserver). This will continue until an answer is found, at which point the answer is passed back down the chain of requests to the client that initiated the query. This method of resolution is convenient for the client as it only has to make a single request - the complexity of resolution is pushed onto the hierarchy of DNS servers.

In assignment 2, you will be implementing a resolver that uses the iterative technique. Rather than letting the DNS server(s) handle all the hard work, you need to traverse the DNS hierarchy yourself to find the answer you’re looking for. When evaluating a DNS query you’ll need to begin at the top of the DNS hierarchy: the root DNS servers. It’s unlikely that the root servers will have the answer you’re looking for, but they will point you in the right direction. You’ll follow these breadcrumbs until you find the authoritative name server for the domain name that you’re looking up.

To help familiarize yourself with iterative name lookup, let’s work through an example using dig. Starting at one of the root name servers, try to find an IPv4 address for students.cs.ubc.ca. Record the dig commands that you use as well as the response you get for each command. How many requests does it take to get the answer you’re looking for? Remember, the syntax for querying a specific name server with dig is: dig @<nameserver> <hostname> <record type>

UDP Sockets in Java

The DNS client you’ll be implementing in assignment 2 will use UDP as the main transport protocol, so today we’ll practice sending and receiving simple UDP messages in Java. Just as Java provides the Socket class for creating TCP connections, Java also has a DatagramSocket class for sending and receiving UDP datagrams. The DatagramSocket API is slightly different than the Socket API so we encourage you to skim the documentation before starting on the activity.

We’ve provided a complete UDP echo server as well as the scaffold of a UDP client. Your job is to implement the ping method in the UDP client. The zip archive includes a Makefile which will compile the server and client for you. If you don’t have make installed, simply run javac Echo[Server|Client].java to compile the source code. To run the server, open a terminal window and run java EchoServer <port-number>. To run the client, open a separate terminal window and run java EchoClient <host> <port-number> (if the Echo client and server are running on the same machine, the host argument should be localhost). If your implementation is correct, the client will output to the terminal before exiting. If you’re wondering what output you should expect, check out the run method in the EchoClient.

Sample Solution

   String ping(String hostname, int port, String msg) throws UnknownHostException, IOException {
        byte[] buf = msg.getBytes();
        byte[] recvbuf = new byte[256];
        InetAddress address = InetAddress.getByName(hostname);
        DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
        socket.send(packet);
        packet = new DatagramPacket(recvbuf, recvbuf.length);
        socket.receive(packet);
        String received = new String(packet.getData(), 0, packet.getLength());
        return received;
    }