====== Lecture 17 Notes ====== ===== Networking & Distributed Systems ===== ==== Livelock ==== {{.:livelock.gif|.:livelock.gif}} From this graph we can see that polling allows for the processing of five times the number of packets as an interrupt driven implementation! **performance = robustness!** In implementing robustness to stop an attacker from driving the processing rate to zero, we also get better performance! === Denial of Service (DoS) attack === A denial of service attack is essentially an attack on performance. The attacker aims to bring the network performance to its knees. We can use a polling solution to solve this problem and improve on both the performance and robustness of the system. DoS attacks are commonly used for extortion purposes, frequently targeting weakly secured pornography and gambling websites. Polling removes the interrupt rate from an attacker's control. However, there is an important problem with polling, namely busy-waiting. There are several solutions available to solve this problem. 1. Perform polling at only system calls and timer interrupt. 2. Use polling exclusively which would result in latency. 3. Use a limited interrupt rate that only switches to polling when a particular threshold value of the interrupt rate is reached. The third option is ideal. ==== Goal of Networking ==== The goal of networking is to provide access to the resources of multiple computers. This leads us to the **Network Effect** which states that the value of a network is proportional to the size of the network. An example of effect can be seen in using Google search which utilizes thousands of computers and large volumes of data to provide search results to your computer. This leads us to an obvious question. How can we best harness the power of these vast computing resources? What OS mechanisms provide easy, robust, well-performing access to these resources? A Client/Server Architecture, of course! === Client/Server Architecture === This mechanism limits communication and sets defined client and server roles. The client plays an **active** role in contacting the server and then making a request, while the server plays a **passive** role in waiting for client requests and responding accordingly. The advantages of using such an architecture are a **clean connection pattern** and **modularity**. {{.:client_server_arch.gif|.:client_server_arch.gif}} A clean connection pattern involves a client contacting a server, the client making a request, and finally the server responding to each request. Modularity is achieved because of the "req-resp" client-server interaction being similar to that of a system call interface. This allows for independent evolution of the client and server while still maintaining normal operation. ==== Network Connections -> Files ==== It is possible to implement a special file system for opening network conections. open("/net/18.26.4.9/80",O_RDWR) This was the goal of **Plan 9**, which was to be a successor to the UNIX OS. It aimed to completely fulfill the UNIX "Big Idea" by treating everything as a file stored in namespace. ==== Actual network system calls ==== Real network system calls use a socket abstraction. socket(address family,protocol family,flags) This creates a new networking-type file descriptor. **Clients** connect(): Creates an active connection. **Servers** listen(): Sets up a passive connection. accept(): Waits for a client connection and then returns a new connection for the client. --- //[[eooi@ucla.edu|Eric Ooi]] 2006/06/01 23:00// ==== Impacts of Attack & Latency on File API & Server Structures ==== **Simple Server** This is an example of a very simple server. It first listens for the client and then accepts it giving it a fd. Then it receives data from the client through read and sends acknowledgement through the write. It then closes the client. fd = listen(); while(1) { client_fd = accept(fd); read(client_fd, ...); write(client_fd,...); close(client_fd); } However, this server leaves itself open to attack in a number of ways. === Denial of Service Attack === 1. Connect and then send no data - An attacker could open up a connection to the server, but then send no data. This would cause the server to block forever on the read. 2. Connect and send a request but don't allow response - An attacker could connect to the server and then send a request. But, it could then choose not to allow a response from the server. This deals with the flow control and again causes the server to be unable to service any other clients. In both of these attacks the attacker exhausts the program count. ==== Multiprocess Service ==== The **idea** for a multiprocess service is to have each client served by separate prcoess. This way only the malicious client that tries to take over the server gets blocked while other clients are still able to be served. fd = listen(); while(1) { client_fd = accept(fd); p = fork(); if(p == 0) { read(client_fd, ...); write(client_fd, ...); close(client_fd); exit(0); } close(client_fd); } Here the simple server is made to fork every listen() finds a new client trying to talk to the server. This creates a new child process for each client. When the client is done, the child closes the socket and the parent closes the client fd. {{.:multiprocess.gif|.:multiprocess.gif}} **Issues with this implementation** 1. Many connections (DoS) - An attacker takes up all of the server resources through connecting with many clients. 2. Process are expensive - new processes are expensive and each client causes a new process to be created. {{.:multiprocess2.gif|.:multiprocess2.gif}} The output of a multiprocess service would look similar to this graph. ==== Multi-threaded Server ==== The **idea** here is to use threads instead of processes. fork -> pthread_create would be utilized so that each client would make a new thread. The negative side is that there would be synchronization issues The good thing is that resources are better utilized (shared address space) but it still isn't perfect. --- //[[ahndrew@ucla.edu|Andrew Ahn]] // ==== Event Driven Programming ==== The sequence of operations is determine by the user's interaction (event) * Solve issue by removing blocking * One process => smaller * Handle attacks that try to starve the server by opening thousands of connections with out sending request * Prevent slow read clients, who request a large file and then keep the connection open by reading the data slowly. Fcntl(fd, F_SETFL, O_NONBLOCK) Fd = listen(); NOBLOCK While (1) { Cfd = connect(); //if (success) add connection fd, cfd. For (each cfd) { If (cfd is on request state) Read(); //might gets respond If (cfd is in respond) Write(); //might close If (timeout expire) Close(fd); } Busy waits! Need a system call that can block on a Set of fds Poll(…) ==== Networking & Distributed Systems ==== **Remote Procedures Call (RPC)** * Client server * Makes it easy to communicate Pixel(int x, int y, int color) { Marshal argument into a message Send a message Wait reply ) --- //[[dannyc525@yahoo.com|Danny]] //