You are expected to understand this. CS 111 Operating Systems Principles, Spring 2006
You are here: CS111: [[2006spring:notes:lec17]]
 
 
 

Lecture 17 Notes

Networking & Distributed Systems

Livelock

.: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

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.

--- 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

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

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. 

--- 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
)

--- Danny

 
2006spring/notes/lec17.txt · Last modified: 2006/09/26 11:42 (external edit)
 
Recent changes RSS feed Driven by DokuWiki