Next generation dynamic tunnel proxy service
Tags: tutorial, linux, opensource, microservices
Published: 2023-02-20 07:35:12

## Overview

Speaking of tunnel proxy, familiar friends will definitely think of `frp`, which is a well-known open source tunnel proxy. And this product has also built its own ecosystem around the tunnel agency service.

This article is to throw out an idea and use an experimental open source project for demonstration.

As early as a few years ago, some people may have noticed that some software has begun to try to support dynamic updates, especially in cloud-native environments. For example: Nginx's dyups module, Nginx's Unit service, Kong's location hot update, etc.

Therefore, for tunnel proxy services such as frp, I also want to try the hot update mode. So there is this experimental project - [Menet](https://github.com/Water-Melon/Menet).

This is an experimental project, the experiment lies in two aspects:

- Use Melang language development to verify the ability and stability of Melang language
- Supports dynamic update of configuration to realize the dynamic establishment and disconnection of upstream, downstream and tunnels

This project is not recommended for production environments, this article is only used to demonstrate the dynamic update effect.

## Usage

To use Menet, you only need to install the Melang script interpreter, and then execute Menet.

```
$ melang menet.m
```

Here, there are two configurations that need to be given before startup:

- Management port, used to deliver configuration to this proxy service
- Tunnel port, the tunnel listening port of each service is determined at startup, and the remaining listening ports or remote connections are dynamically created at runtime

In the default example, the content of the configuration file is as follows:

```
//conf.m

conf = [
     'admin': [ //HTTP API listen address
         'ip': '0.0.0.0',
         'port': '1234'
     ],
     'tunnel': [ //tunnel server listen address
         'ip': '0.0.0.0',
         'port': '4321'
     ],
];
```

You can edit the `conf.m` file if these two addresses should be modified.

After the service starts, you will see that two listening addresses are output to the terminal, which means that the service is ready.

## Example

Below we give an example, assuming we have the following network structure:

```
                  |---------------|                      |------------------|
    service1      |192.168.1.2    |        tunnel1       |192.168.1.3       |   service1
----------------> |8080    Menet  |--------------------->|4321      Menet   |-------------->192.168.1.3:80
                  |admin port:1234|                      |admin port:1234   |
                  |---------------|                      |------------------|
```

Briefly describe:

We have a real 80 service running on 192.168.1.3, and we expect to use the tunnel proxy to access this service from port 8080 of 192.168.1.2.

We can use the curl command to issue 5 HTTP requests to complete this topology deployment, and we will explain them one by one:

1. ```
   $ curl -XPOST -d '{"name":"tunnel1", "dest":["192.168.1.3", "4321"]}' http://192.168.1.2:1234/tunnel
   ```

   This request is sent to Menet of 192.168.1.2, the purpose is to let 1.2 establish a TCP connection to port 4321 (tunnel port) of 1.3, so that a tunnel (`tunnel1`) is established. **Note: This is just an example. In practice, you can also send a request to 1.3 to establish a TCP to the tunnel port of 1.2. **

2. ```
   $ curl -XPOST -d '{"name":"service1", "key":"UHI@&s8sa*S", "type": "local", "addr":["0.0.0.0", "8080" ]}' http://192.168.1.2:1234/service
   ```

   This request is used to tell the 1.2 Menet service to establish a local port 8080 for listening (`type` is `local`), and name the listening service `service1`, and the tunnel uses RC4 encryption, so `key` is the encryption key.

3. ```
   $ curl -XPOST -d '{"name":"service1", "key":"UHI@&s8sa*S", "type": "remote", "addr":["192.168.1.3", "80" ]}' http://192.168.1.3:1234/service
   ```

   This request is used to tell the 1.3 Menet service to establish a connection to the `192.168.1.3:80` port and forward it when receiving `service1` data from the tunnel.

4. ```
   $ curl -XPOST -d '{"tunnel": "tunnel1", "service": "service1", "type": "local"}' http://192.168.1.2:1234/bind
   ```

   This request is to inform the Menet service of 1.2 to establish a mapping relationship between `tunnel1` and `service1`.

5. ```
   $ curl -XPOST -d '{"tunnel": "tunnel1", "service": "service1", "type": "remote"}' http://192.168.1.3:1234/bind
   ```

   This request is to inform the 1.3 Menet service to establish a mapping relationship between `tunnel1` and `service1`.

After performing these 5 steps, we can use curl to access `192.168.1.2:8080` to indirectly access the `192.168.1.3:80` service.