Assignment 7 FAQ

Due April 3, 2016 11:59pm via sakai

Assignment 7 FAQ & Addenda

Latest update: Sun Jun 26 19:29:27 EDT 2016

Back to assignment 7

Addenda

Typos

I had two typos. In Step 3b, I mentioned that the query type should be 0. That is incorrect. It should be 1, which signifies an A (address) record query.

In the submission, I mentioned that you should test multithreading. You do not need to do this. Your assignment only has to be single threaded (although making it multithreaded is fine).

Warning about third party libraries!

You should not have a need for third-party libraries for this assignment. If you do use any, you should include the source and clear compilation instructions (preferably a makefile). You should also clearly document your use of such a librry in your code. If the source is more than a small file, don’t use it. We will not install any third party packages to compile and run your code. For example, something like the Click python package for processing a command line is complete overkill for the assignment.

Also, you should, of course, not use any DNS libraries. The point of the assignment is for you to extract DNS query data and assemble a response. Using somebody else’s code to do so invalidates the point of the assignment.

Dig complains with a message: “WARNING: Message has NN extra bytes at end”

I noticed a possible problem with using the most recent version of the dig command. Following the prescribed protoocl, dig may not print the answer section of your response and may instead complain about “extra bytes at the end.” I know that at least one student had this issue and I was able to reproduce it on a couple of my Linux systems, which run Ubuntu and dig version DiG 9.9.5–3ubuntu0.8-Ubuntu. This problem does not occur on the iLab machines (which run DiG 9.8.2rc1-RedHat–9.8.2–0.37.rc1.el6_7.7) or on Macs (which run DiG 9.8.3-P1). If you are experiencing this problem, the easiest workaround seems to be to send back a response that does not contain the query section. This should not be necessary but it does work and keeps dig from complaining. I suggest that you try this code on the iLab machines as a final test.

FAQ

We haven’t been able to figure out how to test opcodes other than the standard query, so we are unsure if our unimplemented return works properly. What commands could we use to do that?

You can use dig to try other queries. For example, the -x option enables reverse DNS queries:

dig -x 128.6.4.1

but you really need not worry about this. The key things you should check are that you can query names in your hosts file and give a reasonable error for hosts that are not.

If a host name is not found, I we set the rcode to 3 but does that mean we should no longer show the answer section or should we show the answer section with a 0.0.0.0 IP address?

You don’t need an answer section then. Set an_count=0.

What should I set the TTL field for the response?

You can set it to pretty much any value. It doesn’t matter since you’re not caching the results. It’s a value in seconds. 300 (5 minutes) is a good value for sites that handle failover or live in a dynamic environment. 3600 (1 hour) is good for non-critical services with dyamic DNS.

Should our DNS server be case insensitive to domain name queries (e.g., if ibm.com is an entry in the hosts.txt file and the server gets a query for IBm.CoM, should it return the address for ibm.com)?

Case should not matter for domain names. You should be case insensitive.

When comparing the results of running DIG on my code vs running DIG from the cmd I saw some differences and wanted to know if we should correct them. When we run our DIG we get a warning saying recursion requested but not available.

dig requests recursion. You should say it’s not available. That’s perfectly fine.

Why do you use a char * to store the query and not struct dns_question?

Because the domain name isn’t part of dos_question. That follows the domain name. When you get past parsing the name, you can set

dns_question *dns_q = (dns_question *)wherever_i_am;

Is the dns server supposed to process two forms of query such as the IP address and also the URL such as google.com? And would we have to process different forms of the same webpage such as www.google.com, google.com, etc.?

First, google.com is not a URL; it is a domain name (http://www.google.com is a URL). You need to answer queries about domain names, which can have an arbitrary number of components and return the corresponding address. You do not implement inverse queries (queries by address).

What do we do with the hosts file?

When your program starts up, you’ll open the file and read/parse its contents to build up a list of name-address mappings. You’ll use this list to look up a name and find the corresponding address when you get an incoming query.

Is the hosts.txt file you provided the default file that we are using if a file is not specified?

The hosts file I provided is an example. Your program should have a default name for a hosts file (hosts.txt) if it’s not specified with the -f parameter and you should assume it’s in the current directory.

What error do I generate?

If you receive a query (qr=0) with an opcode of Query (opcode=0, standard query) then:

- if you look up the name successfully return a response (qr=1) with an rcode=0 and the appropriate answer data 
- otherwise return a response (qr=1) with an rcode=3 (name error) and no answer data

If you receive a query with any other opcode then

- return a response (qr=1) with an rcode=4 (not implemented) and no answer data

You should never receive a response (qr=1).

So we need to check the native machine for endianess for us to decide whether to flip the bytes that are incoming or not? And would all incoming bytes guaranteed to be in big endian or little endian?​

No, you don’t unless you plan to convert the byte array into an array of shorts, for example. In that case, you’d use ByteBuffer.wrap and specify ByteOrder.BIG_ENDIAN as in the sample code. Internet protocols use big endian representation of integers. That’s what you’ll have in your incoming data and that’s what you’ll return.

If you are NOT reading ints/longs/shorts directly from an array of bytes then you do not have to flip bytes around. Any data in the packet should have the most significant byte before the least significant byte, so you can read or store the bytes explicitly that way as in the sample code.

Does the server have to be multi-threaded.

No.

Do I have to deal queries with multiple questions?

You do not have to handle queries with multiple questions.

When there’s a query with 0 questions do I reply with 0 answer or just ignore it?

A query with 0 questions does not really make sense and should not be issued, but you can reply with a 0 answer if you get it.

What do I return if I can’t find an entry in the host file that matches with the query string?

The best thing to return is a return code (rcode) of 3, which is a Name Error. See RFC 1035 and search for RCODE or “Name Error”.

How do I work with fields in Java?

I did the assignment in C, which makes working with bit fields really easy. If you use Java, you’ll read your data as a byte array. Then you’ll have to do your own shifting and masking to extract individual bits or bit ranges. You’ll have to combine bytes if you need 16 bit quantities. If you are unfamiliar with this, you’ll need to use the web and study up. You can also look at things like ByteBuffer or ShortBuffer to covert to shorts in a way that takes the endianess of the data into account. To help you, you can download an example Java program. This simply reads in a UDP packet, dumps its contents, and demonstrates how to get various bit fields.

How do I work with fields in C?

Use the DNS header file. Your buffer will be in a char array called, for example, buf. To access each field, point to the part of the buffer that contains the start of the data that you need and set the type to the appropriate structure. For example, the DNS information starts with type dns_heaader, so you can define a pointer to dns_header that points to the start of your buffer

dns_header *dns = (dns_header *)buf;

Then you can access bit fields directly:

dns->qr contains the query/response flag
dns->rd contains the recursion request

For 16-bit quantities, convert them to the native format upon reading:

query_count = htons(dns->qd_count);

And convert them the the Internet format for writing them back to the packet buffer:

dns->an_count = htons(1);