------------------[ Readings ]------------------

We looked through the skeleton of a UDP server
http://www.cs.dartmouth.edu/~sergey/cs60/udp-echo/udpserver.c in
http://www.cs.dartmouth.edu/~sergey/cs60/udp-echo/ . Read my 
comments on the system calls used (my comments usually start with NOTE:
or Note:, except at the top.)  

We worked through the traffic that a caching, recursive DNS 
server sends to resolve a client's query. The summary
of the traffic with the server's cache empty is in 
http://www.cs.dartmouth.edu/~sergey/cs60/dns/recursive-dns-lookup-noDNSSEC-annotated.txt
and 
http://www.cs.dartmouth.edu/~sergey/cs60/dns/recursive-dns-lookup-noDNSSEC-another.txt.

These files, less my comments, were translated from packet captures (named
http://www.cs.dartmouth.edu/~sergey/cs60/dns/recursive-dns-lookup-noDNSSEC.pcap and
http://www.cs.dartmouth.edu/~sergey/cs60/dns/recursive-dns-lookup-noDNSSEC-another.pcap)
to the representation that the "dig" tool uses for the packets it
sends and receives. You can also look at how tcpdump represents these
packets, with "tcpdump -r <file> -n" (add -n to not perform extra name queries;
don't add n to see how the IP addresses in the capture are resolved. Without
-n, tcpdump will also resolve known port names, so "cs60.cs.dartmouth.edu.domain"
and 129.170.213.53.53 stand for the same thing. Note that tcpdump adds the port
53 to the address over a dot; it's just a formatting idiosyncrasy). 
My script for doing the translation is "dns-pcap-to-dig.py".

We made some captures of my DNS server running at 129.170.213.53 in class.
You will find these in http://www.cs.dartmouth.edu/~sergey/cs60/dns/pcaps-04-18-17/
as dns-req-fresh.{pcap,txt} and dns-req-precached.{pcap.txt}. 

Note that the fresh requests were recorded after I flushed the cache
of the DNS server; this caused it to walk the entire path from the
root zone down. The "precached" versions were recorded with the cache
primed by previous requests; thus, seeing the name for dartmouth.edu,
the server would go straight to the nameserver it was previously 
supplied as authoritative for dartmouth.edu, skipping the root servers
and the EDU zone servers.

------------------[ Reverse DNS resolution ]------------------

Reverse DNS resolution is mapping IP address to an FQDN name---if any. 
Many sites do not actually configure reverse resolution: you may
be able to resolve a name to an address, but not the other way around.
Configuring reverse name resolution typically requires a separate file
("reverse zone file"), and many domain administrators do not bother
to set it up.

Reverse resolution also uses names (recall that RR records must start
with a name; the first byte we expect is the length of the first
element of the name; and if it's 00 then we consider the name to be
".", the root zone itself). For reverse resolution of IPs to FQDNs,
these names are contrived: they end in the imaginary top-level domain
arpa, have a 2nd-level sub-domain in-addr.arpa, and then use the bytes
of the IP address as if these were next-level subdomains, in reverse
order. 

So, for the in-class example of 129.170.17.4, the name in the query is
4.17.170.129.in-addr.arpa.

The type of this query is special, PTR (or type 12), to distinguish it
from requests for addresses (type A, 1) or nameservers authoritative 
for a domain (type NS, 2).

In the captures dns-reverse.{pcap,txt} and dns-reverse-afresh.{pcap,txt}
(also in http://www.cs.dartmouth.edu/~sergey/cs60/dns/pcaps-04-18-17/),
you can see the sequence of requests and delegations ("I don't know,
but ask those servers"). The chain of PTR requests, intermingled with
looking up authoritative nameservers' addresses, looks roughly like this:

[dns-reverse.txt or pcap]:

Root server "E" (192.203.230.10) is asked, who has 4.17.170.129.in-addr.arpa.? 
Root server "E" respond: ask these servers for "in-addr.arpa.", they might know.

My server asks f.in-addr-servers.arpa. aka 193.0.9.1 next. 
That server responds: ask "129.in-addr.arpa." servers, here's a list.
Most of the servers on that list are in "arin.net", one in "ripe.net" 
(look up what ARIN and RIPE mean).

My server now has to resolve these names before it can proceed. It now asks
the root servers (specifically, "J" 192.58.128.30), for the IPs of "u.arin.net", 
"z.arin.net", "r.arin.net", "z.arin.net", "y.arin.net", and "arin.authdns.ripe.net".

The root server J declines to answer directly, but responds back with authoritative
servers for ".net", like "a.gtld-servers.net". Go ask them.

Our server asks "f.gtld-servers.net", 192.35.51.30. That server delegates
to the bunch of servers for  "arin.net".
 
So our server's next requests are to "ns1.arin.net", 199.212.0.108. Remember,
we are still looking for some servers that could help us resolve things in
the "129.in-addr.arpa." zone. It is taking its time, finding out all of these
names!

"ripe.net" throws us a curve ball: some of the servers we get delegated to
are in "verisigndns.com". So now we go back to root servers ("D" this time, 199.7.91.13)
to ask about ".com" and then, to whichever delegate we get, about "verisigndns.com".

While all of this discovery of nameservers is going on, our original objective of the
PTR query for "4.17.170.129.in-addr.arpa." seems forgotten. But it was not forgotten:
it times out on our server! So even though we continue receiving responses for 
the various nameserver names, our server sends back a SERVFAIL to the requester:

-------------------[ 129.170.213.53 -> 129.170.212.20 ]-------------------
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 63134
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;4.17.170.129.in-addr.arpa.     IN      PTR
;; ADDITIONAL SECTION:
;OPT PSEUDOSECTION
;EDNS: version: 0, flags: ; udp: 4096

And that's too bad! We didn't even get to whoever was the authority for 
"170.129.in-addr.arpa.", let alone further! Although we did get to 
"129.in-addr.arpa.", and that is progress :)


The request succeeds after a few more tries, when the server is lucky
to pick the authorities that reply before the timeout. See 
dns-reverse-afresh.txt and dns-reverse-afresh.pcap for the log of another
failed (timed-out) attempt at PTR (search for "PTR" in the txt file), 
then two more failures---because the SERVFAIL result has been cached by
my server (this feature was added in 2014 to curb too many requests, see
https://serverfault.com/questions/426807/how-long-does-negative-dns-caching-typically-last).

Then, finally, it succeeds! First, the server for "170.129.in-addr.arpa." is
discovered. It's ns1.augsburg.edu, along with a couple of Dartmouth servers:

-------------------[ 204.61.216.50 -> 129.170.213.53 ]-------------------
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29128
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 3, ADDITIONAL: 0
;; QUESTION SECTION:
;4.17.170.129.in-addr.arpa.     IN      PTR
;; AUTHORITY SECTION:
170.129.in-addr.arpa.   86400   IN      NS      ns1.augsburg.edu.
170.129.in-addr.arpa.   86400   IN      NS      dns-ext2.dartmouth.edu.
170.129.in-addr.arpa.   86400   IN      NS      dns-ext1.dartmouth.edu.

Then, finally, ns1.augsburg.edu. (141.224.68.1) is nice enough to respond
on time!

-------------------[ 141.224.68.1 -> 129.170.213.53 ]-------------------
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10153
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 3
;; QUESTION SECTION:
;4.17.170.129.in-addr.arpa.     IN      PTR
;; ANSWER SECTION:
4.17.170.129.in-addr.arpa. 259200  IN      PTR     ns1.dartmouth.edu.
;; AUTHORITY SECTION:
170.129.in-addr.arpa.   28800   IN      NS      dns-ext2.dartmouth.edu.
170.129.in-addr.arpa.   28800   IN      NS      dns-ext1.dartmouth.edu.
170.129.in-addr.arpa.   28800   IN      NS      dns-ext3.dartmouth.edu.
;; ADDITIONAL SECTION:
dns-ext1.dartmouth.edu. 28800   IN      A       129.170.170.2
dns-ext2.dartmouth.edu. 28800   IN      A       129.170.170.10
dns-ext3.dartmouth.edu. 28800   IN      A       132.177.102.11

And that is the time (4th in this capture, 5th overall) that our request
for reverse lookup of 129.170.17.4 succeeds:

-------------------[ 129.170.213.53 -> 129.170.212.20 ]-------------------
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13088
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 4
;; QUESTION SECTION:
;4.17.170.129.in-addr.arpa.     IN      PTR
;; ANSWER SECTION:
4.17.170.129.in-addr.arpa. 259200  IN      PTR     ns1.dartmouth.edu.
;; AUTHORITY SECTION:
170.129.in-addr.arpa.   28800   IN      NS      dns-ext1.dartmouth.edu.
170.129.in-addr.arpa.   28800   IN      NS      dns-ext3.dartmouth.edu.
170.129.in-addr.arpa.   28800   IN      NS      dns-ext2.dartmouth.edu.
;; ADDITIONAL SECTION:
dns-ext1.dartmouth.edu. 28800   IN      A       129.170.170.2
dns-ext2.dartmouth.edu. 28800   IN      A       129.170.170.10
dns-ext3.dartmouth.edu. 172800  IN      A       132.177.102.11

So, reverse DNS is harder that forward DNS! This happens for a reason:
whenever we are supplied any authoritative nameserver names, we must
forward-resolve them before we can proceed. If we start down the wrong
path with the slower nameservers involved, our original query times out.

--------------------[ Making DNS requests from C ]--------------------

The two principal functions for this are gethostbyname() for forward
resolution, and gethostbyaddr() for reverse resolution. Calling these
from your code will send DNS requests as above to the DNS server configured
for your system (look in /etc/resolv.conf). Read the manual pages
for these functions.

See udpserver.c lookup_and_log_peer() function for an example, with
comments. Read up on "struct sockaddr" and "struct sockaddr_in" in my
notes http://www.cs.dartmouth.edu/~sergey/cs60/on-sockaddr-structs.txt