TrustTunnel/lib
Sergei Gunchenko 2b1b1421fd Pull request #36: Introduce speedtest support
Merge in ADGUARD-CORE-LIBS/vpn-libs-endpoint from feature/AG-16500 to master

Squashed commit of the following:

commit d0b900ea3a5b3a04cf9c9462a0a8f96491b52cf3
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date:   Fri Nov 18 09:27:57 2022 +0200

    fix docs

commit 7a97b937493fe336f0495e56e6c2d2a3b87c3461
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date:   Fri Nov 18 09:21:50 2022 +0200

    fix docs

commit 4c975945087a3103b423a4d73936dc9958b99a46
Merge: 9d9854d e5a44fd
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date:   Fri Nov 18 09:21:23 2022 +0200

    Merge remote-tracking branch 'origin/master' into feature/AG-16500

commit 9d9854d96481a585d8a45f72f80404f725cbdbbf
Author: Bamboo <Bamboo>
Date:   Wed Nov 16 14:45:14 2022 +0000

    skipci: Automatic version increment by Bamboo

commit dc43c6ab33d3cfd67992848099cca25dadfc4582
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date:   Wed Nov 16 17:44:57 2022 +0300

    Pull request 35: Fix panic while handling ICMP request in case ICMP forwarding is not set up

    Merge in ADGUARD-CORE-LIBS/vpn-libs-endpoint from fix/icmp_unset to master

    Squashed commit of the following:

    commit c47f3a6a92ce90b98e6ab96731038182239621b0
    Author: Sergei Gunchenko <s.gunchenko@adguard.com>
    Date:   Wed Nov 16 16:29:45 2022 +0200

        Fix panic while handling ICMP request in case ICMP forwarding is not set up

    commit 84cda5628b782d4e93b86c9417e5904c3e509200
    Author: Sergei Gunchenko <s.gunchenko@adguard.com>
    Date:   Wed Nov 16 13:46:25 2022 +0200

        fix docs

commit 673d7863894fa9f3b6b473281b264000342b6ff9
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date:   Fri Nov 18 08:58:47 2022 +0200

    Introduce speedtest support

commit 1bd66f158052ea3ef9a9ce0eda5d67a2509c99cb
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date:   Fri Nov 18 08:57:42 2022 +0200

    minor fixes
2022-11-18 16:45:13 +03:00
..
src Pull request #36: Introduce speedtest support 2022-11-18 16:45:13 +03:00
build.rs Pull request #13: Turn the project structure inside out 2022-05-24 12:49:06 +03:00
Cargo.toml Pull request #26: Add bamboo specs for testing and distribution 2022-09-16 12:58:32 +03:00
README.md Pull request #22: Implement custom SOCKS authentication 2022-09-01 17:12:39 +03:00

AdGuard VPN endpoint

Building the library

Prerequisites

Building

Execute the following commands in Terminal:

cargo build

to build the debug version, or

cargo build --release

to build the release version.

Features description

Traffic forwarding

As for now, the endpoint can demultiplex client's connections multiplexed in either HTTP/1, or HTTP/2, or HTTP/3 session. An application can set up how the endpoint forwards the demultiplexed client's connection by setting Settings.forward_protocol. The available options (see settings.ForwardProtocolSettings) are:

  • routing a connection directly to its target host
  • routing a connection though a SOCKS5 proxy

ICMP forwarding

As an optional feature, the endpoint can also forward ICMP packets from a client. This feature can be set up by setting Settings.icmp. An application MUST set up an interface name to bind the ICMP socket to, and MAY tweak some other settings, like the timeouts and message queue size.

Reverse proxy

The traffic received via a TLS session or QUIC connection with the SNI set to the host name equal to Settings.reverse_proxy.tls_info.hostname is interpreted as a reverse proxy stream. The stream is used for mutual client and endpoint notifications and some control messages. The endpoint does TLS termination on such connections and translates HTTP/x traffic into HTTP/1.1 protocol towards the server and back into original HTTP/x towards the client. Like this:

(client) TLS(HTTP/x) <--(endpoint)--> (server) HTTP/1.1

The translated HTTP/1.1 requests have the custom header X-Original-Protocol appended. For now, its value can be either HTTP1, or HTTP3.

Authentication

Client authentication options

SNI authentication

A client connects to the endpoint with SNI set to hash.domain_name, where:

  • hash - md5(application_id + ':' + token + ':' + credentials)
  • domain_name - the endpoint's original domain name (e.g. myvpn.org)
Proxy authentication

A client connects to the endpoint using the proxy HTTP authentication mechanism with the "basic" scheme: Proxy-Authorization: Basic base64(token + ':' + credentials).

Endpoint authentication methods

An application can set up the authentication method being used by the endpoint by setting Settings.authenticator. The application can provide its own authenticator implementation (see the authentication.Authenticator trait), or use one of the implementations provided by the library:

  • authentication.DummyAuthenticator - authenticates any request
  • authentication.file_based.FileBasedAuthenticator - authenticates a request basing on the file containing credentials (see here)
  • authentication.radius.RadiusAuthenticator - delegates authentication to an authenticator communicating with it by the RADIUS protocol (see here)
  • SOCKS5 authentication - delegates authentication to the SOCKS5 forwarder (see here)

Please note, that the first 2 are very simple authenticator implementations which are intended mostly for testing purposes and do not respect network security practices.

File based authenticator

The file must contain an application id (applicationId: <string>), token (token: <string>), and credentials (credentials: <string>). Each one must be on a new line. The order does not matter.

RADIUS authenticator

This authenticator implementation communicates with an authentication server by the Microsoft EAP CHAP Extensions Protocol, Version 2 over the Extensible Authentication Protocol over the RADIUS protocol.

Successful authentication procedure diagram:

sequenceDiagram
    participant Endpoint
    participant Authenticator

    Endpoint ->> Authenticator: RADIUS: code=AccessRequest[EAP: code=Response, type=Identity, user_name]
    Authenticator ->> Endpoint: RADIUS: code=AccessChallenge[EAP: code=Request, type=MsAuth[MS-CHAP-V2: code=Challenge]]
    Endpoint ->> Endpoint: MS-CHAP-V2::GenerateNTResponse()
    Endpoint ->> Authenticator: RADIUS: code=AccessRequest[EAP: code=Response, type=MsAuth[MS-CHAP-V2: code=Response]]
    Authenticator ->> Authenticator: Verify MS-CHAP-V2 response
    Authenticator ->> Authenticator: Authenticate
    Authenticator ->> Endpoint: RADIUS: code=AccessChallenge[EAP: code=Request, type=MsAuth[MS-CHAP-V2: code=SuccessRequest]]
    Endpoint ->> Endpoint: MS-CHAP-V2::CheckAuthenticatorResponse()
    Endpoint ->> Authenticator: RADIUS: code=AccessRequest[EAP: code=Response, type=MsAuth[MS-CHAP-V2: code=SuccessResponse]]
    Authenticator ->> Endpoint: RADIUS: code=AccessAccept[EAP: code=Success, type=MsAuth]

Depending on the client-side authentication way, the user_name and password are as follows:

  • SNI authentication:
    • user_name = sni@<id>@<hash[0..6]> - a special value which indicates the authentication way
      • <id> - the id of the current authentication session
      • <hash[0..6]> - the first 6 characters of the SNI
    • password = hash - corresponds to hash, as in SNI authentication
  • Proxy authentication:

The endpoint caches the authentication status and repeats the procedure for the client after the cache TTL (see RadiusAuthenticatorSettings.cache_ttl).

SOCKS5 authenticator
Standard authentication

In case Socks5ForwarderSettings.extended_auth is set to false, the endpoint performs the standard authentication procedure according to the RFC 1929.

Depending on the client-side authentication way, the username and password are as follows:

Extended authentication

The extended authentication uses 0x80 as an authentication method. After a server selects this authentication method, a client sends an authentication request in the following format:

+-----+-----------+-----+--------+
| VER |   EXT(0)  |     | EXT(n) |
+-----+-----------+ ... +--------+
|  1  | see below |     |        |
+-----+-----------+-----+--------+

Where:

  • VER - the current extended authentication version: 0x01
  • EXT[i] - an extension in the following format:
    +------+--------+----------+
    | TYPE | LENGTH |   VALUE  |
    +------+--------+----------+
    |  1   |    2   | Variable |
    +------+--------+----------+
    
    Where:
    • TYPE - a type of the extension value (see [ExtendedAuthenticationValue])
    • LENGTH - the length of the extension value
    • VALUE - the extension value

Available extensions:

  • TERM: type = 0x00, length = 0 - terminating extension, marks a message end
  • DOMAIN: type = 0x01, length = (0..MAX], value = UTF-8 string - hostname which a client used for the TLS session (SNI)
  • CLIENT_ADDRESS: type = 0x02, length = [4|16], value = Bytes - public IP address of the VPN client
  • USER_AGENT: type = 0x03, length = (0..MAX], value = UTF-8 string - user agent of the VPN client
  • PROXY_AUTH: type = 0x04, length = (0..MAX], value = base64 string - <credentials> part of the Proxy-Authorization header
  • SNI_AUTH: type = 0x05, length = 0 - marks that the VPN client tries to authenticate using SNI

A message MUST end with the TERM extension.

The server responds with a standard message as in the RFC.

Metrics collecting

In order to collect some metrics of a running endpoint, an application can set up it to listen for the metrics collecting requests (see Settings.metrics). An endpoint running with this feature will listen on the configured address (MetricsSettings.address) for plain HTTP/1 requests. The following paths are available:

  • /health-check - used for pinging the endpoint, so it will respond with 200 OK
  • /metrics - used for metrics collecting, so it will respond with a bunch of values accoring to the prometheus specification

License

Apache 2.0