Assignment 2

416 Distributed Systems: Assignment 2

Due: Jan 22nd at 9PM

Winter 2016

In this assignment you will practice even more Go by writing server-side code. In the first assignment you implemented a secure fortune client to retrieve the fortune by communicating with the authentication server (aserver) and the fortune server (fserver). In this assignment you will implement your own versions of the aserver and fserver. This assignment introduces two new concerns on top of the basic protocol from the first assignment: (1) your code must support multiple simultaneous clients, (2) your code must be fault-tolerant and must return error messages to clients that do not follow the protocol.

High-level protocol description

The aserver and fserver must together implement the protocol described in the first assignment. The interactions between the client and the aserver and the client and the fserver were described in the first assignment. All that remains is to describe the interactions between the aserver and fserver (which you will implement as separate go programs).

The aserver and fserver communicate via RPC over TCP. The fserver is the server in this RPC interaction and exports a single method to the aserver, GetFortuneInfo, that takes the address of the client and a pointer to FortuneInfoMessage for the result. The fserver computes a new nonce and returns the filled-in FortuneInfoMessage. The exact declaration of GetFortuneInfo and the input/output types is:

type FortuneServerRPC struct{}

// Message with details for contacting the fortune-server.
type FortuneInfoMessage struct {
	FortuneServer string // e.g., ""
	FortuneNonce  int64  // e.g., 2016

func (this *FortuneServerRPC) GetFortuneInfo(clientAddr string, fInfoMsg *FortuneInfoMessage) error { ... }

This simple RPC interaction is also illustrated in the following diagram:

Implementation requirements

  • Both the fserver and the aserver must support multiple concurrent clients.
  • Your aserver and fserver must follow the RPC specification above (i.e., your aserver must inter-operate with our fserver and vice versa).
  • The aserver nonce and the fserver fortune nonce should be unpredictable (e.g., randomized int64 values).
  • Only the latest nonce and fortune nonce issued to a client should be valid.
  • Nonces should not expire after use (replay attack should be possible).
  • The aserver must use the same hashing code as the released client code.
  • You must use UDP and the message types given out in the first assignment.
  • The servers must implement the following protocol-checks and return an ErrMessage with the error string specified below:
    • fserver: The client sends a malformed message.
      Error string: "could not interpret message"
    • aserver: The client sends a hash from a different address than it used to retrieve the nonce.
      Error string: "unknown remote client address"
    • aserver: The client sends the wrong hash of secret and nonce.
      Error string: "unexpected hash value"
    • fserver: The client sends a fortune nonce from a different address than it used in communicating with the aserver.
      Error string: "unknown remote client address"
    • fserver: The client sends an incorrect fortune nonce.
      Error string: "incorrect fortune nonce"
  • The aserver should respond with a NonceMessage to all UDP packets that are not of HashMessage type.
  • All messages must fit into 1024 bytes.

Assumptions you can make

  • Both servers have an unlimited amount of memory to support an unbounded number of outstanding client connections.
  • The fserver can assume that there is a single connecting aserver (over RPC).
  • Once started the aserver and fserver never fail.
  • The fserver is run before the aserver.
  • Your implementation does not need to survive internal errors, such as errors that arise during marshalling of JSON messages, in RPC communication, etc.

Solution spec

Write two go programs, auth-server.go and fortune-server.go, that implement the description above. These programs must conform to the following command line usage:

go run auth-server.go [aserver UDP ip:port] [fserver RPC ip:port] [secret]

  • [aserver UDP ip:port] : the UDP address on which the aserver receives new client connections
  • [fserver RPC ip:port] : the TCP address on which the fserver listens to RPC connections from the aserver
  • [secret] : an int64 secret

go run fortune-server.go [fserver RPC ip:port] [fserver UDP ip:port] [fortune-string]

  • [fserver RPC ip:port] : the TCP address on which the fserver listens to RPC connections from the aserver
  • [fserver UDP ip:port] : the UDP address on which the fserver receives client connections
  • [fortune-string] : a fortune string that may include spaces, but not other whitespace characters

Testing client: You can use the client.go solution to assignment 1 to test your servers. However, we will test your solution more extensively, employing a variety of faulty clients.

Rough grading scheme

Approximate percentages for different aspects of the solution:

  • 50%: The aserver and fserver properly follow the protocol to allow a single, correct, client to retrieve the fortune.
  • 25%: The aserver and fserver support multiple concurrent, correct, clients.
  • 25%: The servers properly handle misbehaving clients.

Make sure to follow the course collaboration policy and refer to the assignments instructions that detail how to submit your solution.