~emersion/tlstunnel

b5b6bba5e405bb62e080596e3d2e8cb6f1f7cca1 — Simon Ser 6 months ago a2bf967
Add "tls load" frontend directive
3 files changed, 59 insertions(+), 7 deletions(-)

M directives.go
M server.go
M tlstunnel.1.scd
M directives.go => directives.go +35 -1
@@ 1,6 1,7 @@
package tlstunnel

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/url"


@@ 40,13 41,23 @@ func parseFrontend(srv *Server, d *scfg.Directive) error {
		return err
	}

	unmanaged := false
	tlsDirective := d.Children.Get("tls")
	if tlsDirective != nil {
		var err error
		unmanaged, err = parseFrontendTLS(srv, tlsDirective)
		if err != nil {
			return err
		}
	}

	for _, addr := range d.Params {
		host, port, err := net.SplitHostPort(addr)
		if err != nil {
			return fmt.Errorf("failed to parse frontend address %q: %v", addr, err)
		}

		if host != "" {
		if host != "" && !unmanaged {
			srv.ManagedNames = append(srv.ManagedNames, host)
		}



@@ 96,6 107,29 @@ func parseBackend(backend *Backend, d *scfg.Directive) error {
	return nil
}

func parseFrontendTLS(srv *Server, d *scfg.Directive) (unmanaged bool, err error) {
	for _, child := range d.Children {
		switch child.Name {
		case "load":
			var certPath, keyPath string
			if err := child.ParseParams(&certPath, &keyPath); err != nil {
				return false, err
			}

			cert, err := tls.LoadX509KeyPair(certPath, keyPath)
			if err != nil {
				return false, fmt.Errorf("directive \"load\": %v", err)
			}

			srv.UnmanagedCerts = append(srv.UnmanagedCerts, cert)
			unmanaged = true
		default:
			return false, fmt.Errorf("unknown %q directive", child.Name)
		}
	}
	return unmanaged, nil
}

func parseTLS(srv *Server, d *scfg.Directive) error {
	for _, child := range d.Children {
		switch child.Name {

M server.go => server.go +14 -5
@@ 16,11 16,14 @@ import (
)

type Server struct {
	Listeners    map[string]*Listener // indexed by listening address
	Frontends    []*Frontend
	ManagedNames []string
	ACMEManager  *certmagic.ACMEManager
	ACMEConfig   *certmagic.Config
	Listeners map[string]*Listener // indexed by listening address
	Frontends []*Frontend

	ManagedNames   []string
	UnmanagedCerts []tls.Certificate

	ACMEManager *certmagic.ACMEManager
	ACMEConfig  *certmagic.Config
}

func NewServer() *Server {


@@ 55,6 58,12 @@ func (srv *Server) RegisterListener(addr string) *Listener {
}

func (srv *Server) Start() error {
	for _, cert := range srv.UnmanagedCerts {
		if err := srv.ACMEConfig.CacheUnmanagedTLSCertificate(cert, nil); err != nil {
			return err
		}
	}

	if err := srv.ACMEConfig.ManageAsync(context.Background(), srv.ManagedNames); err != nil {
		return fmt.Errorf("failed to manage TLS certificates: %v", err)
	}

M tlstunnel.1.scd => tlstunnel.1.scd +10 -1
@@ 55,9 55,18 @@ The following directives are supported:
		The _+proxy_ suffix can be added to the URI scheme to forward
		connection metadata via the PROXY protocol.

	*tls* { ... }
		Customise frontend-specific TLS configuration.

		The tls directive supports the following sub-directives:

		*load* <cert> <key>
			Load certificates and private keys from PEM files.

			This disables automatic TLS.

*tls* { ... }
	Customise TLS configuration.
	Customise global TLS configuration.

	The tls directive supports the following sub-directives: