tlsrp

TLS reverse proxy
git clone git://git.rr3.xyz/tlsrp
Log | Files | Refs | README | LICENSE

commit a487cd4e18fcb0e6ece0fa5e9626ec45ecc41224
parent d39d30828c33885a0642234cc7a214c1de230b3e
Author: Robert Russell <robertrussell.72001@gmail.com>
Date:   Mon, 15 Jul 2024 23:37:21 -0700

Change usage message and add man page

Currently the man page is inaccurate regarding signal usage,
because I want to simplify signal usage as described in the man
page.

Diffstat:
Atlsrp.1 | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtlsrp.go | 20++++----------------
2 files changed, 62 insertions(+), 16 deletions(-)

diff --git a/tlsrp.1 b/tlsrp.1 @@ -0,0 +1,58 @@ +.TH "TLSRP" "1" "2024-07-15" "tlsrp" "User Commands" +.SH NAME +tlsrp \- TLS reverse proxy +.SH SYNOPSIS +\fBtlsrp\fR \fIconfig_path\fR \fIsource\fR... +.P +\fIconfig_path\fR is a file with each line of the following format: +.EX + \fBcert\fR \fIcrt_path\fR \fIkey_path\fR \fIhostname\fR... + \fBsink\fR \fBtcp\fR [\fIhost\fR]\fB:\fIport\fR \fIhostname\fR... + \fBsink\fR \fBunix\fR \fIpath\fR \fIhostname\fR... +.EE +.P +\fIsource\fR += \fBtcp:\fR[\fIhost\fR]\fB:\fR[\fIport\fR] +| \fBunix:\fIpath\fR +.SH DESCRIPTION +tlsrp accepts TLS-secured connections on one or more source sockets and tunnels +the decrypted bytes to one of many sink sockets. tlsrp chooses the certificate +and sink socket for each client (among those listed in the configuration file) +based on the hostname specified by the client using the Server Name Indication +(SNI) TLS extension. More specifically, the first \fBcert\fR (resp., +\fBsink\fR) entry in the configuration file that matches the client's requested +hostname is chosen. Clients without SNI support are handled using the first +\fBcert\fR entry and the first \fBsink\fR entry in the configuration file. +.P +For TCP sinks, \fIhost\fR defaults to the local system. For TCP sources, +\fIhost\fR defaults to all available unicast and anycast IP addresses of the +local system, and \fIport\fR defaults to being automatically chosen (and +logged to stderr). +.P +The entire configuration file (in particular, all certificates within) is +reloaded upon receipt of \fBSIGHUP\fR. +.SH NOTES +While certificates and sinks may be updated dynamically with zero down time by +sending \fBSIGHUP\fR, the same is not possible for sources. Indeed, it's +difficult, if not sometimes impossible, to change source sockets without down +time. Changing sources with zero down time is best handled in other ways. +.SH EXAMPLE +Assume the following situation: +.EX + + $ ls /srv + config.tlsrp crt.pem http.sock key.pem + + $ cat config.tlsrp + cert /srv/crt.pem /srv/key.pem example.com + sink unix /srv/http.sock example.com + +.EE +Then to proxy all local connections at \fBexample.com\fR from TCP port 443 to +the HTTP (not HTTPS!) server listening on \fBhttp.sock\fR, run +.EX + + # tlsrp config.tlsrp tcp::443 +.EE +.SH "SEE ALSO" +RFC 3546 <https://www.rfc-editor.org/rfc/rfc3546> diff --git a/tlsrp.go b/tlsrp.go @@ -1,7 +1,5 @@ package main -// TODO: check log.Printf newlines - import ( "context" "crypto/tls" @@ -489,18 +487,6 @@ func listen(sources []string) ([]net.Listener, error) { return listeners, nil } -func usage() { - format := `Usage: %s CONFIG_PATH SOURCE0 SOURCE1 ... - SOURCEi = tcp:HOST:PORT | unix:PATH -tlsrp is a TLS reverse proxy. tlsrp accepts TLS-secured connections on one or -more source sockets and tunnels the decrypted bytes to one of many specified -sink sockets. The sink socket is chosen based on the hostname specified by the -client using the Server Name Indication TLS extension (RFC 3546). -` - // TODO: more doc - fmt.Fprintf(os.Stderr, format, os.Args[0]) -} - func init() { softExit = make(chan struct{}) hardExit = make(chan struct{}) @@ -510,10 +496,12 @@ func init() { } func main() { - flag.Usage = usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: %s CONFIG_PATH SOURCE...", os.Args[0]) + } flag.Parse() if flag.NArg() < 2 { - log.Fatalln("expected 2 or more arguments") + log.Fatalln("expected at least 2 arguments") } cfgPath := flag.Args()[0]