Due: Fri, Nov 15, 7:00am
In this project, you will implement a client (adns_lookup) and server (adns) which speak an "almost DNS" protocol. The Domain Name System, or DNS, is the "phone book of the Internet": whenever you browse to a URL (e.g., https://www.wm.edu/as/computerscience/resources/index.php) your browser must first lookup the IP address for the URL's domain name (e.g., www.wm.edu) so that it can make a connection to that site's webserver. The nitty-gritty details of the DNS protocol are specified in RFC 1034 and RFC 1035, but the gist is that the client sends the DNS server a domain name, and the server sends the client back the IP address, or an error indicating that the IP address can't be found. For our ADNS, we'll keep the spirit of this protocol, but implement a simpler on-the-wire protocol than what is specified in the RFCs. The real DNS can use either UDP or TCP, and likewise our ADNS client and server will support both transport protocols.
In our ADNS protocol, every message (request and response) has the same format:
In particular, each message has an 8-byte header consisting of an id, a type, and a body_len, all of which are big-endian. After the header, a message has a body that is body_len bytes long.
The id is randomly chosen by the client for its request message (for this project, you can simply hardcode a value). When responding to a request, the server sets the response's id to that of the request's.
The message type. For requests, there is only one type:
Responses can have one of the following types;
The IPv4 address of the ADNS server (e.g., 127.0.0.1).
The domain name to resolve (e.g., leo).
Print a usage statement to stdout and exit with status 0.
The ADNS server's port. (default: 9514)
Use TCP instead of UDP.
File that maps domain names to IPv4 addresses. Each line of the file contains two fields -- (1) the domain name and (2) the IPv4 dotted-decimal address -- separated by one or more spaces.
Print a usage statement to stdout and exit with status 0.
The interface to listen on. (default: INADDR_ANY)
The port to listen on. (default: 9514)
Use TCP instead of UDP.
To help get started, please use the following skeleton code: adns_skeleton.zip.
For the adns server, the skeleton code currently implements the getopt_long option parsing, reads in the zone file, and then prints the zone file. adns.c reads the zone file into a hash table. For representing the zone file, the adns server uses uthash -- a popular hash table implementation. Since the skeleton code already initializes this hash table, there is very little that you have to do with respect to uthash. The function zone_get_rr in adns.c is a wrapper for looking up a value in the hash table. If you are attempting bonus1, you will want to consult the uthash user guide to learn how to iterate over the hash table.To help you develop the projects, you can use the following Python versions of the client and server:
The Python implementations have the same command-line usage as the C-versions that you will implement. Many of the automated tests will use these scripts to separately test your client and your server.
Note that after you download these scripts, you should make them executable:
chmod +x adns_lookup.py adns.py
Implement the QTYPE_PTR (12) message type: the request's body is a dotted-decimal IP address, and the the response's body is the domain name. In other words, QTYPE_PTR signifies a reverse lookup. If the server cannot resolve the lookup, it should return NXDOMAIN (and a zero-length body).
The command-line usage of the adns does not change. For adns_lookup, a short option of -r or a long option of --reverse indicates a reverse lookup.
Implement the QTYPE_TXT (16) message type: the request's body is an arbitrary key, and the the response's body is the associated value. Normal DNS uses TXT resource records as a generic "catch-all" for data that doesn't match any existing record type. Our ADNS server will only implement one key: "version", and should respond with "adns v1.0". If the ADNS server receives any other key, it should respond with NXDOMAIN (and a zero-length body).
The command-line usage of the adns does not change. For adns_lookup, a short option of -x or a long option of --txt indicates a reverse lookup.
Submit your project as a zip file via gradescope. Your project must include a Makefile that builds two executables: adns_lookup and adns. Please refer to the instructions for submitting an assignment for details on how to login to gradescope and properly zip your project.
./adns zone.conf
./adns_lookup.py 127.0.0.1 leo
1.2.3.5
./adns zone.conf
./adns_lookup.py 127.0.0.1 tiger
not found
./adns zone.conf
./adns_lookup.py 127.0.0.1 ''
malformed request
./adns -t zone.conf
./adns_lookup.py -t 127.0.0.1 pisces
1.2.3.12
./adns -t zone.conf
./adns_lookup.py -t 127.0.0.1 pig
not found
./adns -t zone.conf
./adns_lookup.py -t 127.0.0.1 ''
malformed request
./adns.py zone.conf
./adns_lookup 127.0.0.1 libra
1.2.3.7
./adns.py zone.conf
./adns_lookup 127.0.0.1 libra
1.2.3.7
echo $?
0
./adns.py zone.conf
./adns_lookup.py 127.0.0.1 horse
not found
./adns.py zone.conf
./adns_lookup.py 127.0.0.1 ''
malformed request
./adns.py -t zone.conf
./adns_lookup -t 127.0.0.1 gemini
1.2.3.3
./adns.py -t zone.conf
./adns_lookup.py -t 127.0.0.1 rabbit
not found
./adns.py -t zone.conf
./adns_lookup.py -t 127.0.0.1 rabbit
not found
echo $?
1 # or any non-zero value
./adns.py -t zone.conf
./adns_lookup.py -t 127.0.0.1 ''
malformed request
./adns -p 9553 zone.conf
./adns_lookup.py -p 9553 127.0.0.1 leo
1.2.3.5
./adns.py -t --port 9553 zone.conf
./adns_lookup -t --port 9553 127.0.0.1 aquarius
1.2.3.11
./adns zone.conf
./adns_lookup.py -r 127.0.0.1 1.2.3.5
leo
./adns.py -t zone.conf
./adns_lookup -t -r 127.0.0.1 1.2.3.8
scorpio
./adns zone.conf
./adns_lookup.py -r 127.0.0.1 4.5.6.7
not found
./adns zone.conf
./adns_lookup.py -x 127.0.0.1 version
adns v1.0
./adns.py -t zone.conf
./adns_lookup -t -x 127.0.0.1 version
adns v1.0
./adns zone.conf
./adns_lookup.py -x 127.0.0.1 foo
not found