The reincarnation of OpenVPN’s C++ library
At Mysterium Network we are working on the world’s 1st decentralized VPN. Our project is built on Golang (Go). Go is a statically compiled language, which offers a rich standard library. Go is syntactically similar to C but comes out as the winner when it comes to memory safety, garbage collection, structural typing, and CSP style concurrency.
There are many libraries written in C or C++. When you wish to use these libraries within Golang, there are two approaches:
Rewrite the library in Golang
Several projects have gone down this road. Wireguard® has done this, check out some of their libraries.
Reuse the code in a way that Golang can call it.
There are other tools that can help with calling java or objective C code into Golang, but everything goes through an intermediary. At a fundamental level, there is interoperability between C and Golang.
In this article, we will be talking about integrating C++ OpenVPN 3 library into a Golang Mysterium Node.
As mentioned above, we are using OpenVPN under the hood. This was our first protocol and it was used as an external binary (executable file).
This basically means that a Mysterium Node and OpenVPN are two different processes which communicate using OpenVPN config and IPC (local sockets to be exact).
Now, this has some limitations — for example, software distribution becomes complicated as you also need to distribute OpenVPN binary with each Mysterium Node — two steps, never great for UX.
It was workable for a proof of concept or very early versions, but as we moved to mobile platforms, this approach became very complicated or even not feasible — especially when considering iOS.
To solve this challenge, we decided to find a way to integrate OpenVPN into our Golang project directly. Also, we decided that this package could be useful for others, that’s how this library was born.
Openvpn3 to the rescue.
Openvpn3 is the official library maintained by OpenVPN team and is being used in almost all platforms as client or connector to OpenVPN server. Also, it’s written in C++ which came with some obstacles we needed to solve.
Golang and C++ don’t get along
Our first obstacle was that C++ code cannot be directly called by Golang (Cgo to be exact).
We needed to make small changes to the OpenVPN library itself to export OpenVPN Client as C callable code. This can be found here, and it’s basically a go compatible entry point to the OpenVPN library.
Then there is how Golang treats C code itself (cgo).
The problem was that Golang and it’s package management systems expect that all libraries are source files (i.e. there is no or very limited binary package management). And OpenVPN3 library build process was very over complicated and not easily expressed in a Go way.
So our decision was to compile that library in advance for all platforms we currently support or produce binaries for (arm family (android ios), amd64 family (Windows, Linux, some simulators). As we use Linux for our automatic build system, we had to set up all compilers and SDKs in one place — but that’s for another blog post. Sign up to our newsletter to hear more about what we’re building.
Our heavily patched docker image is heavily borrowed from Karalabe. The result was a single header file (very simple) and a bunch of static libraries for each platform/OS we needed.