Skip to content

Commit

Permalink
Rework (#1)
Browse files Browse the repository at this point in the history
* Added configuration file.
* Added DNS server implementation.
* Added prometheus metrics.
  • Loading branch information
ameshkov authored Jun 16, 2024
1 parent 778e3e6 commit 9911dc7
Show file tree
Hide file tree
Showing 27 changed files with 2,087 additions and 317 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
/build
/relay
/snirelay
/sni_mapping.csv

# For local testing.
/config.yaml
/example.crt
/example.key
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ issues:
# We don't need it since the SNI proxy should be able to tunnel TLS
# connections of any version.
- G402
# gosec: Use of weak random number generator
# We only use it in tests.
- G404
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ adheres to [Semantic Versioning][semver].

## [Unreleased]

### Added

* Added configuration file.
* Added DNS server implementation.
* Added prometheus metrics.

### Removed

* Removed `sni-mappings-path` functionality.

[unreleased]: https://github.com/ameshkov/snirelay/compare/v1.0.0...HEAD

## [1.0.0] - 2024-03-25
Expand Down
26 changes: 23 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,28 @@ COPY --from=builder /app/snirelay /
# Copy the CA certificates from the certs image.
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Expose listen ports.
# Exposing ports.

# Plain DNS.
EXPOSE 53/udp
EXPOSE 53/tcp

# DNS-over-TLS.
EXPOSE 853/tcp

# DNS-over-QUIC.
EXPOSE 853/udp

# DNS-over-HTTPS.
EXPOSE 8443/tcp
EXPOSE 8080/tcp

ENTRYPOINT ["/snirelay", "-l", "0.0.0.0", "-p", "8080:8443"]
# SNI relay for plain HTTP.
EXPOSE 80/tcp

# SNI relay for HTTPS.
EXPOSE 443/tcp

# Prometheus metrics endpoint.
EXPOSE 8123/tcp

ENTRYPOINT ["/snirelay", "-c", "/app/config.yaml"]
157 changes: 122 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,162 @@ Simple SNI relay server written in Go.

What it does:

1. Listens for incoming HTTP or HTTPS connections.
2. Parses the hostname from the HTTP request or TLS ClientHello.
3. Proxies the traffic further to that hostname.
1. Provides a DNS server that can re-route domains to the SNI relay server.
2. Listens for incoming HTTP or HTTPS connections.
3. Parses the hostname from the HTTP request or TLS ClientHello.
4. Proxies the traffic further to that hostname.

Why would you need it? For instance, if you operate a DNS server, and you want
to relay some domains to an intermediate server (effectively, change your IP
address).

## How to build
## How to use it

1. Get the version for you OS/arch from the [Releases][releases] page. If you
prefer Docker, you can find it below.
2. Create a configuration file. Read the comments in
[./config.yaml.dist][configyaml] to learn about configuration.
3. Run `snirelay`:
```shell
snirelay -c /path/to/config.yaml
```

You may need to run it with `sudo` since it needs to use privileged ports.

[releases]: https://github.com/ameshkov/snirelay/releases

[configyaml]: ./config.yaml.dist

### Usage

```shell
make
Usage:
snirelay [OPTIONS]
Application Options:
-c, --config-path= Path to the config file.
-v, --verbose Verbose output (optional).
Help Options:
-h, --help Show this help message
```

### How to run it locally
## Docker

The docker image [is available][dockerregistry]. In order to use it, you need to
supply a configuration file, and you may need to also supply the TLS cert/key
if you're going to use encrypted DNS.
The image exposes a number of ports that needs to be mapped to the host machine
depending on what parts of the functionality you're using.

* Port `53`: plain DNS server, usually needs to be mapped to port `53` of the
host machine.
* Port `853/tcp`: DNS-over-TLS server, usually needs to be mapped to port `853`
of the host machine.
* Port `853/udp`: DNS-over-QUIC server, usually needs to be mapped to port
`853` of the host machine.
* Port `8443/tcp`: DNS-over-HTTPS server. **Do not expose to `443` as this port
is required by the SNI relay server**. Try a different port and don't forget
to use it in the server address.
* Port `80/tcp`: SNI relay port for plain HTTP connections. Map it to port
`80` of the host machine.
* Port `443/tcp`: SNI relay port for HTTPS connections. Map it to port `443` of
the host machine.
* Port `8123/tcp`: Prometheus metrics endpoint. Map it if you use prometheus.
So imagine we have a configuration file `config.yaml` and the TLS configuration
files in the same directory in `example.crt` and `example.key`. In this case the
configuration section should look like this:
```yaml
dns:
# ... omitted other ...
tls-cert-path: "/app/example.crt"
tls-key-path: "/app/example.key"
# ... omitted other ...
```
And then run it like this:
```shell
./snirelay -l 127.0.0.1 -p 80:443
docker run -d --name snirelay \
-p 53:53/tcp -p 53:53/udp \
-p 853:853/tcp -p 853:853/udp \
-p 8443:8443/tcp \
-p 8123:8123/tcp \
-p 80:80/tcp -p 443:443/tcp \
-v $(pwd)/config.yaml:/app/config.yaml \
-v $(pwd)/example.crt:/app/example.crt \
-v $(pwd)/example.key:/app/example.key \
ghcr.io/ameshkov/snirelay
```
Alternatively, you can supply a list of custom domain<->IP mappings:
[dockerregistry]: https://github.com/ameshkov/snirelay/pkgs/container/snirelay
## How to build
```shell
./snirelay -l 127.0.0.1 -p 80:443 --sni-mappings-path=sni_mapping.csv

make
```
### How to test
### How to run it locally
See the [`config.yaml.dist`][configyaml] for more information on what can be
configured. In normal environment you want to change ports there.
```shell
# Simple connect via relay:
gocurl --connect-to="example.org:443:127.0.0.1:80" -I https://example.org/
./snirelay -c config.yaml
```
## Docker
[configyaml]: ./config.yaml.dist
### How to test
Note that instructions here use [dnslookup][dnslookup] and [gocurl][gocurl].
The docker image [is available][dockerregistry]. `snirelay` listens to the
ports `8080` and `8443` inside the container, so you don't have to specify the
listen address and ports, other arguments are available.
#### DNS queries
Run `snirelay` as a background service in server mode and expose on the host's
ports `80` and `443` (tcp):
Plain DNS:
```shell
docker run -d --name snirelay \
-p 80:8443/tcp -p 443:8443/tcp \
ghcr.io/ameshkov/snirelay
# IPv4 will be redirected to 127.0.0.1.
dnslookup www.google.com 127.0.0.1:5353
# IPv6 will be redirected to ::.
RRTYPE=AAAA dnslookup www.google.com 127.0.0.1:5353
# HTTPS will be suppressed.
RRTYPE=HTTPS dnslookup www.google.com 127.0.0.1:5353
```
[dockerregistry]: https://github.com/ameshkov/snirelay/pkgs/container/snirelay
Encrypted DNS:
## Usage
```shell
# DNS-over-TLS.
VERIFY=0 dnslookup www.google.com tls://127.0.0.1:8853
```text
Usage:
snirelay [OPTIONS]
# DNS-over-QUIC.
VERIFY=0 dnslookup www.google.com quic://127.0.0.1:8853
Application Options:
-l, --listen=<IP> Address the tool will be listening to (required).
-p, --ports=<PLAIN_PORT:TLS_PORT> Port for accepting plain HTTP (required).
--proxy=[protocol://username:password@]host[:port] Proxy URL (optional).
--sni-mappings-path= Path to the file with SNI mappings (optional).
-v, --verbose Verbose output (optional).
# DNS-over-HTTPS.
VERIFY=0 dnslookup www.google.com https://127.0.0.1:8443/dns-query
Help Options:
-h, --help Show this help message
```
#### SNI relay
```shell
# Relay for plain HTTP:
gocurl --connect-to="example.org:443:127.0.0.1:9080" -I http://example.org/
# Relay for HTTPS:
gocurl --connect-to="example.org:443:127.0.0.1:9443" -I https://example.org/
```
[dnslookup]: https://github.com/ameshkov/dnslookup
[gocurl]: https://github.com/ameshkov/gocurl
2 changes: 1 addition & 1 deletion cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// is done in the cmd package.
package main

import "bit.int.agrd.dev/relay/internal/cmd"
import "github.com/ameshkov/snirelay/internal/cmd"

func main() {
cmd.Main()
Expand Down
98 changes: 98 additions & 0 deletions config.yaml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# DNS server section of the configuration file. Optional, if not specified the
# DNS server will not be started.
dns:
# listen-addr is the address where the DNS server will listen to incoming
# requests. Must be specified.
listen-addr: "0.0.0.0"

# redirect-addr-v4 is the IPv4 address where the DNS server will re-route
# type=A queries for domains listed in domain-rules. Must be specified.
redirect-addr-v4: "127.0.0.1"

# redirect-addr-v6 is the IPv4 address where the DNS server will re-route
# type=AAAA queries for domains listed in domain-rules. If not specified,
# the DNS server will respond with empty NOERROR to AAAA queries.
redirect-addr-v6: "::"

# plain-port is the port for plain DNS server. Optional, if not specified,
# the plain DNS server will not be started.
plain-port: 53

# tls-port is the port for DNS-over-TLS server. Optional, if not specified,
# the plain DNS-over-TLS server will not be started.
tls-port: 853

# https-port is the port for DNS-over-HTTPS server. Optional, if not
# specified, the plain DNS-over-HTTPS server will not be started. It is
# usually supposed to be 443, but this way it will clash with the SNI relay
# HTTPS port.
https-port: 8443

# quic-port is the port for DNS-over-QUIC server. Optional, if not
# specified, the plain DNS-over-QUIC server will not be started.
quic-port: 853

# upstream-addr is the address of the upstream DNS server. This server will
# be used for queries that shouldn't be re-routed. Must be specified.
upstream-addr: "8.8.8.8:53"

# RateLimit is the maximum number of requests per second for a plain DNS
# server. If 0 or not specified, there will be no rate limit.
rate-limit: 50

# rate-limit-allowlist is a list of IP addresses excluded from rate limiting.
rate-limit-allowlist:
- "127.0.0.1"

# tls-cert-path is the path to the TLS certificate. It is only required if
# one of the following properties are specified: TLSPort, HTTPSPort,
# QUICPort.
tls-cert-path: "./example.crt"

# tls-key-path is the path to the TLS private key. It is only required if
# one of the following properties are specified: TLSPort, HTTPSPort,
# QUICPort.
tls-key-path: "./example.key"

# Relay is the SNI relay server section of the configuration file. Must be
# specified.
relay:
# listen-addr is the address where the Relay server will listen to incoming
# connections.
listen-addr: "0.0.0.0"

# http-port is the port where relay will expect to receive plain HTTP
# connections.
http-port: 80

# https-port is the port where relay will expect to receive HTTPS
# connections.
https-port: 443

# proxy-url is the optional port for upstream connections by the relay.
# Format of the URL: [protocol://username:password@]host[:port]
proxy-url: ""

# domain-rules is the map that controls what the snirelay does with the
# domains. The key of this map is a wildcard and the value is the action.
# Must be specified.
#
# If the domain is not specified in domain-rules, DNS queries for it will
# be simply proxied to the upstream DNS server and no re-routing occurs.
# Connections to the relay server for domains that are not listed will not
# be accepted.
#
# If the action is "relay" then the DNS server will respond to A/AAAA
# queries and re-route traffic to the relay server. HTTPS queries will be
# suppressed in this case.
domain-rules:
# Re-route all domains.
"*": "relay"

# prometheus is a section for prometheus configuration.
prometheus:
# addr is the address where prometheus metrics are exposed.
addr: "0.0.0.0"

# port where prometheus metrics are exposed.
port: 8123
Loading

0 comments on commit 9911dc7

Please sign in to comment.