profile picture

Parth Desai

Blog about Software engineering

Linkedin Github

© 2015. Parth Desai All rights reserved.

How to build RPC server in golang (step by step with examples)

Overview

Remote procedure call (RPC) is basically a form of inter-process communication. It is widely used in distributed computing.

In this blog post, We will build a simple RPC server step by step.

1. Define an interface and shared structs

For sake of simplicity, we will choose an interface with two methods: Multiply and Divide, which perform * and / operations respectively.

There will be only two shared structs called Args and Quotient that will be used to pass arguments from client to server and represent the output of Multiply and Divide respectively.

2. Write implementation for the interface

Now, we will write struct which implements two methods we mentioned above: Multiply and Divide.

3. Implement a RPC server

Two ways we can implement a RPC server in golang:

3.1 HTTP RPC

In this case server will be listening for incoming connection using HTTP protocol, and will switch to RPC protocol afterwards.

Benefit of this approach is, you can perform authentication of client easily, before allowing RPC, using any authentication method supported by HTTP.

Internally, server listens for HTTP CONNECT method, and then uses http.Hijacker to hijack the connection.

3.2 TCP RPC

In this case server will be listening for incoming connection directly, instead of relying on HTTP protocol.

4. Implement a RPC client

We need to implement RPC client, based on which way we chose to build our server.

4.1 HTTP RPC

4.2 TCP RPC

Design generic functions in golang

Overview

Starting from golang 1.1, it offers reflection support to do almost anything dynamically. Combine that with functional programming support, and you can write generic functions that operate on combination of any data type and function.

In this article, I will describe how to write generic functions in golang, as well as disadvantages of it, compared to static functions.

Functional Programming in Golang

Golang supports first class functions, higher-order functions, user-defined function types, function literals, closures, and multiple return values.

For scope of this article, I will demonstrate three of the above features: function literals, function types and higher order functions.

In this example, we implemented filter function, that takes two arguments, slice of integer and a function. And filter the slice using the function passed.

As you can see, we call filter function, two times with different function literals, first literal filters out odd numbers, while second removes even numbers.

But, this is not enough to write truly generic code, as you can see, we can only pass integer slice and only functions who are compatible with function type that we declared beforehand.

Enter reflection!!

Reflection in Golang

Unlike C/C++, in golang every object retains associated type information, even if it is assigned to a variable with interface{} type. This feature plays key part, while using reflection.

Reflection apis are exposed in golang, through built-in package called reflect.

Official reflect package documentation: Reflect Documentation

There are two central concepts, in context of reflect package which we need to understand before diving into the code:

  • Type: It is an Object that represent go types as well as user defined types. For example: int, string, map, func.

  • Value: It is an Object, which encapsulates and act as an interface to the underlying Go Object. It is useful when we want to do some common operation on the object of particular kind (i.e array or map).

With help of reflection and functional programming, we can write a generic function in go, with run-time type safety.

By run-time type safety, I mean that the types of a function’s arguments are consistent with semantics of function or else the function predictably fails at run time with a reasonable error message.

As you can see in this example, we have used Value, and Type cleverly, to check if input parameters confirms the semantics of mapping, and to construct output argument.

Word of Caution

There are certain disadvantages of using generic functions:

  • They are very very slow: Generic functions are quite slow. For example map function in previous example, is almost 100x time slower than its static counterpart.

  • You lose on compile time error checking: As you can see, the function we have written accepts anything for its parameters, thanks to interface{} type. This makes it very flexible to use this function for different data types. But, that also mean that now the compiler, cannot point out error at compile time. Probability of writing erroneous code also increases in this case. So for large generic program, we must rely on extensive testing to make sure, it works properly.

Sneaky security vulnerability to watch out for while developing server side OAuth2.0a

Timing attack

This attack is quite common and is applicable to every situation where user sends certain information to the server, and it needs to verify this information by matching it to the information stored in server, or via any cryptographic algorithm whose execution time directly depend upon the input data.

This attack is dependent upon implementation of OAuth2.0, and not the protocol itself.

Timing attack can be used in many ways in Oauth2.0 process. I am giving here an example of one of the simplest scenario.

Example

In the server side OAuth2.0a process, the last call is to exchange authorisation code for an access token. On server side, code will first verify the authorisation code, and then compare received client secret to the stored client secret.

Now, Attacker wants to gain access to this server as this client. She knows the client id, but does not know authorisation code and client secret.

In this case, timing attack would work as follows:

  • Attacker sends request using valid client id. And authorisation code and client secret are some random string. Attacker receives the response and measure the time required for that response.

  • Now, as you know a standard comparison routine in most programming language is implemented in such a fashion that, they check two byte sequence byte-by-byte and return false, immediately when it found different byte.

  • The key concept here is that for typical string comparision routine the time required to execute is propotional to the position of the first non-matching byte from start of the byte sequence.

  • So, Now all attacker needs to do is change first byte again and again until the time to return error response slightly increases or decreases (if she have used correct byte in first time, time will decrease otherwise it will increase.) After verifying that, she just needs to keep that byte as it is, and change the next byte. This process is continued for rest of the bytes.

One aspect of this attack, that makes it dangerous is that, we don’t even need to brute force the code and secret anymore. We can just measure time, and predict that whether current byte is valid or not. This can also be easily automated.

Prevention

  • Use constant time compare functions: Nowadays, many programming language provide library function that uses constant time to compare two byte sequence, instead of returning decision immediately whenever wrong byte appears.

  • Time-out authorisation code: Authorisation code should time-out after some reasonable time limit (from 5 minutes to 45 minutes.)

Further Information