snid is a lightweight proxy server that forwards TLS connections based on the server name indication (SNI) hostname. snid favors convention over configuration - backend addresses are not configured individually, but rather constructed based on DNS record lookups or filesystem locations. This makes snid deployments easy to manage.
If you have the latest version of Go installed, you can run:
go install src.agwa.name/snid@latest
Or, you can download a binary from the GitHub Releases Page.
snid is a single statically-linked binary so using Docker or a similar technology is superfluous.
Listen on the given address, provided in go-listener syntax. You can specify the -listen
flag multiple times to listen on multiple addresses.
Examples:
-listen tcp:443
to listen on TCP port 443, all interfaces.-listen tcp:0.0.0.0:443
to listen on TCP port 443, all IPv4 interfaces.-listen tcp:192.0.2.4:443
to listen on TCP port 443 on 192.0.2.4.
Use the given mode, described below.
Use the given hostname if a client does not include the SNI extension. If this flag is not specified, then SNI-less connections will be terminated with a TLS alert.
In NAT46 mode, snid does a DNS lookup on the SNI hostname to determine its IPv6 address and forwards the connection there, as long as the IPv6 address is within one of the networks specified by -backend-cidr
. The client's IPv4 address is embedded in the lower 4 bytes of the source address used for connecting to the backend, with the prefix specified by -nat46-prefix
.
Note: in NAT46 mode, clients which connect to snid over IPv6 will be disconnected. Instead, IPv6 clients should connect directly to the backend.
The following flags can be specified in NAT46 mode:
Use the given prefix for the source address when connecting to the backend. Specifically, the source address is constructed by taking the IPv6 address specified by -nat46-prefix
and placing the client's IPv4 address in the lower 4 bytes.
It is recommended that you use one of the prefixes reserved by RFC 8215 for IPv4/IPv6 translation mechanisms, such as 64:ff9b:1::
.
Example: -nat46-prefix 64:ff9b:1::
Important: the prefix which you use for -nat46-prefix
MUST be routed to the local host so that return packets can reach snid. On Linux, the necessary route entry can be added by running:
ip route add local 64:ff9b:1::/96 dev lo
Only forward connections to addresses within the given subnet. This option can be specified multiple times to allow multiple subnets.
Example: -backend-cidr 2001:db8::/64
In TCP mode, snid does a DNS record lookup on the SNI hostname to determine its IPv4 or IPv6 address and forwards the connection there, as long as the IP address is within one of the networks specified by -backend-cidr
.
The following flags can be specified in TCP mode:
Only forward connections to addresses within the given subnet. This option can be specified multiple times to allow multiple subnets.
Examples:
-backend-cidr 192.0.2.0/24
-backend-cidr 2001:db8::/64
Connect to the given port number on the backend.
If this option is omitted, then snid will use the same port number that the inbound connection arrived on.
Use PROXY protocol v2 to convey the client IP address to the backend.
In UNIX mode, snid forwards connections to a UNIX domain socket whose filename is the SNI hostname, in the directory specified by -unix-directory
.
The following flags can be specified with UNIX mode:
The path to the directory containing UNIX domain sockets.
Use PROXY protocol v2 to convey the client IP address to the backend.
In NAT46 and TCP modes, snid does a DNS lookup on the SNI hostname to determine the backend's IP address. snid attempts to emulate the DNS lookup behavior that a TLS client would use if connecting directly to the backend. Normally, snid does an A/AAAA record lookup directly on the hostname, but if the TLS handshake specifies exactly one ALPN value for a protocol which uses SRV records, then snid will do a SRV record lookup instead.
The following ALPN values are recognized:
Sole ALPN Value | SRV Service |
---|---|
xmpp-client |
_xmpps-client._tcp |
xmpp-server |
_xmpps-server._tcp |
For example, if the handshake specifies the SNI hostname example.com
and the ALPN protcols h2
and http/1.1
, then snid will look up the A/AAAA records for example.com
and forward the connection there, since that's how an HTTP client works.
If the handshake specifies the SNI hostname example.com
and the ALPN protcol xmpp-client
, then snid will do a SRV record lookup for _xmpps-client._tcp.example.com
'. If this returns a SRV record for xmpp.example.com
, then snid will look up the A/AAAA records for xmpp.example.com
and forward the connection there, since that's how an XMPP client works.