Last updated
Last updated
This assignment has automated tests! Make sure to read the and to download the framework before starting
How many web pages do you visit in a day? Would you be able to remember all their IP addresses? Probably not. It turns out that humans are bad at remembering arbitrary sequences of numbers, but reasonably good at remembering names. By assigning names to IP addresses, web browsing becomes doable for humans. Instead of having to remember the sequence “216.58.211.110,” you only need to remember “www.google.com.” Your browser automatically translates this into the correct IP address.
Another, more compelling, reason not to use IP addresses to identify Web pages is that it makes the assumption a Web page is tied to a single machine, or network device. More generally, it creates a dependency between an entity on one layer, and the implementation of a lower layer. Naming entities on their own layer solves this problem, but the Domain Name System (DNS) does not do this. Instead, it translates a human-readable domain name into an Internet address. I.e., it simply provides global, mutable, and easy-to-remember aliases for network devices. The Web browser has to guess the right transport-layer address (port number) to find the right entity. This system works because it relies on hard-coded port numbers. If you want to run your Web server on a different port number, users have to enter it in their browser manually. This shows that, although we have DNS, there is still a dependency between implementations across layers. This is not so much a shortcoming of DNS, as a shortcoming of the design of the upper layers of the Internet.
However, this automated translation increases the complexity of the system, which now needs to translate a name into an IP address before it can establish a connection. It would be infeasible for every computer to keep a local, up-to-date copy, of all name-to-address mappings. Instead, computers depend on a globally distributed system called the Domain Name System (DNS) to look up these mappings dynamically.
This system contains a large hierarchy of servers called DNS servers. A DNS server is a computer that keeps track of IP addresses and their associated domain names. DNS servers can ask each other for the IP address matching a certain domain name. It then resolves, or translates, this name into an IP address by looking it up in its local database, or by contacting other DNS servers higher up in the hierarchy.
Important: due to the limited availability of IPv6 support in a dockerized environment, this assignment asks you to implement a --ipv4only
switch to your DNS server. This switch will communicate to your server to use only IPv4 requests. Without the switch, your DNS server will fail on CodeGrade with Network is unreachable
error when attempting to make an IPv6 request. Tests in the test suit can be configured to either pass or not pass --ipv4only
option to your script, so thus you can test whether your IPv6 works before the TA hand-in. Tests will expect a server to start at address 127.0.0.1 and port 8000 (even though you can develop your server using another address and port). The address and port will be, as well, supplied via test script when starting your server script using the --address
and --port
. Thus tests will start your server script as python3 dns.py --address "127.0.0.1" --port 8000
.
DNS servers communicate with each other using their protocol. It is your job to implement your own DNS server that adheres to this protocol and performs recursive queries. Your server should be able to resolve both IPv4 and IPv6 addresses. All the information you need is specified in and .
Start by reading section 2.1 (RFC 1035. Overview). It will give you a high-level operational model of your future DNS server. Then, to get a high-level overview of what DNS responses, requests, and communication between the other DNS servers are see sections 7.1 (RFC 1035. Transforming a user request into a query), 7.2 (RFC 1035. Sending the queries), and 7.3 (RFC 1035. Processing responses).
To construct a DNS request or parse a DNS response, read the structure of a DNS message in section 4 (RFC 1035. Message). Every message contains a set of records called RRs. There you will find the most interesting information regarding the requested resource. Read how it is structured in section 3.2 (RR definitions). Each record has its type and your server should support at least NS, A, CNAME, MX, and AAAA. The definition of NS can be found in section 3.3.11 (RFC 1035. NS RDATA format), A in 3.4.1 (RFC 1035. A RDATA format), CNAME in 3.3.1 (RFC 1035. CNAME RDATA format), MX in 3.3.9 (RFC 1035. MX RDATA format), and AAAA in section 2 (RFC 3596. New resource record definitions and domain).
Your DNS has to implement mail requests. Check section 8 (Mail Support) and in particular section 8.1 (Mail Exchange Binding).
Finally, your server should implement caching as it is prescribed in sections 7.1, 7.2, and 7.3. However, there are exceptions to this rule described in section 7.4 (Use of cache).
Typically, a client application forwards a domain name to the operating system, which in turn forwards it to a DNS server that performs recursive queries. Performing a recursive query means that the DNS server will query other DNS servers until it finds the address that belongs to the given domain name. This address is then returned to the application via the operating system.
Protocol Requirements
PR1: The server must support IPv4.
PR2: The server must support IPv6.
Record Requirements
RR1: The server must support NS records.
RR2: The server must support A records.
RR3: The server must support CNAME records.
RR4: The server must support MX records.
RR5: The server must support AAAA records.
RR6: The server must support mail exchange requests.
Cache Requirements
CR1: The server must maintain a cache of recently resolved requests.
CR2: Stale cache entries must be removed after a set amount of time.
Technical Requirements
TR1: The server must be able to perform recursive DNS queries.
TR2: The server must work on Linux. (for CodeGrade tests)
TR3: The server must print informative messages as it processes requests and manipulates the cache. (for when you sign off the assignment with your TA)
Your implementation is evaluated by the TAs. To test your server implementation, you can configure your Web browser or operating system to use it as its DNS server. Make sure that your server can handle requests from different operating systems. Your implementation must resolve requests by communicating with the root server and the servers it lists in its replies. You cannot pass the assignment if you simply forward requests to another DNS server that performs recursive queries.
Below is a list of free, popular, and public DNS servers. You can analyze their responses to learn more about how to implement your own server.
Google (8.8.8.8 and 8.8.4.4)
Quad9 (9.9.9.9 and 149.112.112.112)
OpenDNS (208.67.222.222 and 208.67.220.220)
You can find the addresses of the DNS root servers at .