Scaling the Internet === Topics Covered: DNS, CDNs, TCP/UDP ## Why DNS? The primary motivation for DNS (Domain Name System) is, of course, readable domain names to identify websites (servers on the Internet). More importantly, it adds a layer of abstraction between the end client and the server, which is identified by an IP address. IP is not static nor permanent. It changes relatively frequently. Without DNS, you and I would need to memorize and constantly keep track of the current IP address of our favorite websites. ### DNS as a Distributed System DNS needs to be a distributed system, with each node containing duplicate information. Why? Because we need **fault tolerance**, **scalability**, and **load distribution**. Last week in discussion we covered an example where we bottleneck in the CDN due to a single server handling all incoming requests for cached content. What was the solution? Cloudflare's duplication of cache handling servers. DNS needs a similar mechanism. #### Scalability DNS is scalable, because it implements a hierarchical design (tree structure). At the root there are the Root Servers, which are overseen by an international organization. These don't have much of a specific purpose except to delegate to the next level and ensure international information transfer. Next are the TLD (Top Level Domain) servers, which handle domains within `.com`, `.org`, `.net`, etc.. Then SLD (Second Level Domain) servers, which will handle domains like `google.com`, `amazon.com`, and similar. Finally are the subdomains, like `my.ucla.edu` or `cs.ucla.edu`, which are usually managed by the organization network administrator. At each level, the DNS servers can cache the information from lower levels, so clients making repeat requests for `google.com` do not have to go all the way to the Google's DNS server. Like with any cache, there is a TTL, or in other words a time to expiration. In a recursive query, the client will first query the root server, and if it does not have the information you seek, then it will query the TLD server, and so on. Once information is retrieved, it propagates back up through the chain, and each server can cache the information for future clients to access quicker. We can also use iterative queries, where the client directly contacts each server until it finds the authoritative record. Both options are available, since sometimes one is better than the other. Think for yourself, what bottlenecks can occur with each and why? #### Fault Tolerance At each level of the hierachy, there are many possible DNS servers each containing their own cache. If one DNS server goes offline, there are many others to pick up the incoming requests, with enough cache information due to **duplication**. Additionally, since DNS usually uses **UDP**, the resolvers will check for corruption or lossy transmission at the **application layer**. If there is a problem, then it will ask the client to resend. #### Load Distribution Likewise with fault tolerance, since there are many available DNS servers at each layer in the hierarchy, the incoming requests are usually geographically routed to the nearest available server, which reduces the load on other, more distant, servers. For example, the root domain servers have 1810 instances, and 13 authoritative server names. This avoids network congestion and bottlenecking effects and leads to quick response times. ### DNS Record Format (Resource Record or RR) ![image](https://hackmd.io/_uploads/HkCsxUuWR.png) TTL is where the time to expiration is stored. The class should probably be assumed to be `IN` (Internet). Some common types to be familiar with are: - **NS** - contains authoritative DNS server for domain name - RDATA contains the server name - **A** - contains the IPv4 or IPv6 address - stored in RDATA yet again - **CNAME** - contains canonical name - kind of like an alias - for example, you can point `mywebsite.com` to `my-github.github.io` ## CDNs (Content Delivery Networks) CDNs are built on the idea that we want to reduce transmission delay by bringing cached content closer to the client on the network. This could be geographic, but more so a measure of shortest delay. This is "calculated" using protocols like BGP (covered later in the course) or through Anycast (covered in lecture and discussion, so won't go over here). Companies that offer CDN services, like Cloudflare, set up a proxy server (or many) that cache content for end users on behalf of the original server. Think of `cdn.discordapp.com` where your image urls come from! Now how do you get that content from the CDN server? ![image](https://hackmd.io/_uploads/SyqmT8uZC.png) 1. You make the original request to the server you want (WebContent.com). 2. The server fetches the authoritative DNS server which it has a contract with. 3. Authoritative DNS server responds with the IP address of the nearest CDN server. 4. Server responds to the client (you) with the IP address of your nearest CDN server. 5. You fetch the content from the CDN server. Therefore, DNS communication between the server you contact and the CDN provider helps the server provide you with the IP address of the best CDN server for your content. If you're interested in learning more about Cloudflare and how it builds upon classic CDN architecture and its flaws, see [Week 3 Discussion Slides](https://docs.google.com/presentation/d/1btrm1hgYCxwg7GFoI_ZRINcP7a5jfwg24yHNyNoE3MY/edit?usp=sharing). I *really* strongly recommend taking a look, since it gives a glimpse into distributed systems engineering and security! ## Brief Introduction to TCP/UDP TCP and UDP belong to the transport layer, which can be thought of as providing a way to do IPC (interprocess communication) between two networked devices. Remember in Project 1 how your TCP socket belongs to the process, and returns a file descriptor like opening and reading from a file. Same idea works for UDP. The difference is between what each need to identify a connection. ### Demultiplexing Demultiplexing refers to processing incoming packets and deciding which process they should go to. A common analogy is like a post office sorting through mail and deciding who to give it to. #### Connectionless In order to do connectionless demultiplexing, the incoming packet needs to specify the destination IP address and destination port number in the header. Then the operating system knows which process spawned a socket with those characteristics. Therefore, **all packets with the same destination IP address and port go to the same place, regardless of sender**. #### Connection-Oriented Unlike connectionless, we now have to maintain some stream-like connection between two sockets. Like a server and a client which have established a connection through some handshake. In this case, we need to identify incoming packets with the destination IP and port number, but also by who is sending them. So we need a source IP and port as well in the header. You can notice that your TCP socket API is very similar to this. *Hmmm....* ### Multiplexing Depending on whichever demultiplexing strategy is used, the process sending the packets will add the appropriate headers. That's what happens in the multiplexing stage. Not too complicated if you understand demuxing. ### Use Cases for Each Hopefully by now you should see that connectionless mux/demux is used by UDP, and connection-oriented by TCP. TCP establishes a stream connection between two sockets, where each socket wants to know where the incoming packet is coming from, and the sender needs to make sure the packet it sends goes to the right place. Meanwhile, UDP also wants it to get to the right place, but the receiver does not care where it comes from (it doesn't belong to a connection). Hence the differences you see in the BSD socket API! *Next week's notes will cover reliable data transfer and congestion control, as well as QUIC.*