Writing VPN with Go — 1. Server

Ömer Burak Demirpolat
3 min readOct 20, 2022

--

Hi, this article will be about writing basic VPN server with Go.

For understanding this article, you should have basic level of knowledge about these

  • TCP/IP, Network Layer (Layer 3)
  • Network Interface, ifconfig, routing
  • What is TUN/TAP ?

My purpose is reaching out the to an application which is working at private network with my VPN client and VPN server.

I have a notebook which have 192.168.1.29 IP addr and I will try to reach out Kubernetes node which have 192.168.1.12.

Regarding to image above, my notebook’s subnet and Kubernetes node’s subnet seems same. But don’t let this mistakes you, my notebook and Kubernetes node are in different networks.

Without VPN, when I try to reach out Kubernetes node with curl I can not get response.

The story

In order to access the Kubernetes cluster from my notebook, when I send a request to the address 192.168.1.12 (Kubernetes Node), my VPN Client needs to capture this request and deliver it to my application without forwarding this captured IP packet to the kernel. We will do this with virtual network interfaces called TUN/TAP.

After the IP packet to the address 192.168.1.12 is delivered to my VPN Client application, I will forward the packet to the VPN Server application that listens on port 8990 at 89.55.23.92. I will send a TCP packet with an IP packet, that is, an IP packet with data, to the VPN Server as if I were sending an ordinary TCP packet.

Paket will look like this:

VPN server will take this packet and separate the data part in it, and since the data it allocates is an IP packet, it will write to the TUN/TAP interface that we created on the VPN Server.

Let’s remember again that this package contains an IP packet going from 192.168.1.29 (Notebook) to 192.168.1.12 (K8s Node).

When the TUN/TAP interface on the VPN Server delivers this IP packet to the kernel, the packet will be processed because our VPN Server can access the Kubernetes node 192.168.1.12.

Our IP packet successfully reached 192.168.1.12. Thanks to the TUN/TAP interfaces on the VPN Server, the packets returning from the 192.168.1.12 K8s node will also be delivered to our VPN Server application. The VPN Server will transmit these delivered messages to the client over TCP socket and the client will receive the response of the message it sent.

Let’s Write the Server

We will need to run commands a few times from within the applications for both server and client. I created a simple function for this.

The steps for VPN Server are as follows:

  • Create and make the TUN/TAP interface work.
  • Creating a function that listens for incoming packets to the TUN/TAP interface and sends them to the Client.
  • Creating a TCP Server running on port 8990.
  • Creating listeners for TCP connections from clients.

First I need to do something that will create the TUN/TAP interface and deliver it to my process, when I searched for this I saw the following package github.com/songgao/water I will use this package.

We created an interface with water.New, I said it will be a TUN device with config.

After the interface is created, we need to assign an IP to this interface, with the first command we have assigned an IP with a subnet of 255.255.255.0 and with the second command we have made this device “up”.

Now I need a loop that listens for incoming packets to the interface, let’s write that. It will capture the incoming packets and transmit the IP packet it reads through the package level variable called conn to the Client.

I will share the whole code at the end of the article and you will be able to see the variable named “conn” there.

Now let’s write the TCP server and the listener that will constantly listen for incoming connections.

Simple, we will listen for incoming TCP connections to 89.252.131.88:8990, and we write messages coming over this connection to the interface.

Please click for navigate second article: Writing VPN with Go — 2. Client

--

--