Merge in ADGUARD-CORE-LIBS/vpn-libs-endpoint from feature/AG-15011 to master
Squashed commit of the following:
commit 3169dc88c93db6f4dfde47bc6b2687d76396a9d2
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Mon Aug 15 19:37:55 2022 +0300
fix even more
commit 312bbda2521612b1dec7b01394cf8ec69a1208d8
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Mon Aug 15 16:38:13 2022 +0300
fix udp-over-socks5
commit 01276b4ea32afa48ef723f567fd78d1c4f8a6acb
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Thu Aug 11 14:14:56 2022 +0300
Upgrade tokio
commit 852209044a69d12b28d7c59d0773849dde4100bc
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Thu Aug 11 14:02:09 2022 +0300
Update docs
commit 0d9e262e5d2879bc8efdc7b8b99ef2df4b62c1ca
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Thu Aug 11 12:33:41 2022 +0300
Make authenticator optional, try authencticate via socks if no authenticator specified
commit c433e71fbfc7a114eb11da88c1bf43d1a04520b7
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Mon Jul 11 14:20:20 2022 +0300
Get rid of useless derivation
commit 667821417e9cf9c0914cf2b86f28225a890a7a7f
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Sat Jul 9 10:14:10 2022 +0300
Downstream part refactoring
commit 0b71a5c94fef5b0f31611da538080a3a199743ed
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 18:19:17 2022 +0300
Replace third-party socks library with the custom one
commit 0378761f2220630a56a1b64ed804972e876efd1b
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 18:19:52 2022 +0300
minor clean up
commit 6e243ce9fe1b5e787c93a217934f169a9dcef17d
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 18:18:09 2022 +0300
minor
commit 4d89d710f8f6bea1098832d1da286373b412a34f
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 18:17:51 2022 +0300
Add authentication check for a datagram multiplexer request
commit 00e54947ce9bba2b8eb3b5a968c2dc185edd2e85
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 18:16:27 2022 +0300
Add TLS server name to connection meta
commit 27f6fb64eb03863709e7bdf48237b687d53a28dd
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 17:11:36 2022 +0300
Refactor connection error passing
commit 0953791e692a2cc97acc9c5418330eb6b2a22db2
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 14:28:16 2022 +0300
Minor refactoring of connection forwarders
commit 451a6514e7962d71894ad7b49eb7777122c2d838
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 12:48:12 2022 +0300
Do not split user agent into platform and app name
commit 86a7e7e3d35c61de294c1b6d5009fb5d07d4495d
Author: Sergei Gunchenko <s.gunchenko@adguard.com>
Date: Fri Jul 8 12:36:15 2022 +0300
Pass only an IP address of the client to socks server
8.7 KiB
AdGuard VPN endpoint
Building the library
Prerequisites
- Rust 1.59.0 or higher: use a preferred way from https://www.rust-lang.org/tools/install
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 requestauthentication.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 tohash, as in SNI authentication
- Proxy authentication:
user_nameandpasswordcorrespond totokenandcredentials, as in 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:
-
- both
usernameandpassword=hash- corresponds tohash, as in SNI authentication
- both
-
usernamecorresponds totoken, as in Proxy authenticationpasswordcorresponds tocredentials, as in Proxy authentication
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: 0x01EXT[i]- an extension in the following format:
Where:+------+--------+----------+ | TYPE | LENGTH | VALUE | +------+--------+----------+ | 1 | 2 | Variable | +------+--------+----------+TYPE- a type of the extension value (see [ExtendedAuthenticationValue])LENGTH- the length of the extension valueVALUE- the extension value
Available extensions:
TERM: type = 0x00, length = 0 - terminating extension, marks a message endDOMAIN: 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 clientUSER_AGENT: type = 0x03, length = (0..MAX], value = UTF-8 string - user agent of the VPN clientPROXY_AUTH: type = 0x04, length = (0..MAX], value = base64 string -<credentials>part of the Proxy-Authorization headerSNI_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 with200 OK/metrics- used for metrics collecting, so it will respond with a bunch of values accoring to the prometheus specification
License
Apache 2.0