We played with a bunch of tools:
We discussed DNS
We played with Wireshark, which let us put the network card into promiscuous mode and observe lots of traffic. You are encouraged to download and play on your own.
We looked at /etc/services, which contains a list of the well-known port numbers
vi /etc/services
We played with traceroute, which lists the routers that a packet traverses while en route to a given destination:
$ traceroute google.com
traceroute to google.com (74.125.228.206), 30 hops max, 60 byte packets
1 rhodes1-6500-vl2729.net.cornell.edu (10.148.0.1) 3.986 ms 3.971 ms 3.961 ms
2 core2-6500-te3-3.net.cornell.edu (132.236.222.161) 3.954 ms 3.947 ms 3.944 ms
3 nat1-3700d-vl25-inside.net.cornell.edu (10.253.34.5) 3.259 ms 3.617 ms 3.751 ms
4 core1-6500-vl26.net.cornell.edu (128.253.34.34) 4.379 ms 4.374 ms 4.367 ms
5 cornellnet4-te1-1.net.cornell.edu (128.253.222.10) 4.478 ms 4.844 ms 5.155 ms
6 te0-0-1-2.rcr11.syr01.atlas.cogentco.com (38.122.120.21) 7.435 ms 4.738 ms 4.649 ms
7 te0-0-0-16.ccr21.alb02.atlas.cogentco.com (154.54.27.165) 8.045 ms 6.841 ms 8.184 ms
8 be2106.ccr41.jfk02.atlas.cogentco.com (154.54.3.49) 11.533 ms 12.145 ms 11.771 ms
9 be2148.ccr41.dca01.atlas.cogentco.com (154.54.31.117) 17.926 ms 19.359 ms 19.488 ms
10 be2171.ccr41.iad02.atlas.cogentco.com (154.54.31.106) 19.074 ms 20.259 ms 20.430 ms
11 38.88.214.50 (38.88.214.50) 18.550 ms 17.633 ms 17.164 ms
12 209.85.252.46 (209.85.252.46) 18.011 ms 18.002 ms 17.809 ms
13 72.14.233.91 (72.14.233.91) 18.482 ms 17.847 ms 18.244 ms
14 iad23s23-in-f14.1e100.net (74.125.228.206) 17.366 ms 18.360 ms 19.814 ms
We showed the netstat
tool, which gives information about all currently open sockets.
We played with telnet
tool, which creates a TCP connection to a given host and port and simply forwards the users terminal to that connection. We used it to perform HTTP requests from google:
$ telnet google.com 80
GET / HTTP/1.1
<enter>
We also played with the python socket API:
$ python
>>> from socket import *
>>> x = socket(AF_INET,SOCK_STREAM)
>>> x.bind(('localhost', 41100))
>>> x.listen(1)
>>> y = x.accept()
We were able to connect to our server using telnet in a different terminal:
$ telnet localhost 41100
Which caused the call to accept to return:
>>> y
(<socket._socketobject object at 0x7fdce8387670>, ('127.0.0.1', 40951))
>>> y[0].send("greetings\n")
10
>>> y[0].recv(30)
The call to send
printed out "greetings" on our telnet terminal; typing a response in telnet caused recv
to return.
We discussed DNS (the domain name service), an important application-layer protocol for converting human-readable domain names (such as cs.cornell.edu) to IP addresses. Domain names are hierarchical: the cs.cornell.edu domain is contained in the cornell.edu domain which is in turn a part of the .edu domain.
To resolve a domain name (e.g. www.cs.cornell.edu), you first query your local caching name server. In principle, your name server will first query one of the (small number of well-known) root name servers to find the .edu authoritative name server. This is the server that is responsible for storing the IP addresses of all name servers of subdomains of the .edu domain.
The .edu nameserver will respond with the IP address of the cornell.edu authoritative nameserver. In turn, this will respond with the IP address of the cs.cornell.edu nameserver. Finally, your caching nameserver will query the cs.cornell.edu nameserver to find the IP of the www host.
The caching nameserver may cache any of the addresses that it learns as part of this process. Once it has resolved the name, the address will be returned to the requesting application.