tlstunnel/main.go

106 lines
2.3 KiB
Go
Raw Normal View History

2020-09-08 10:11:32 +00:00
package main
import (
2020-09-08 16:24:16 +00:00
"context"
2020-09-08 15:13:39 +00:00
"fmt"
2020-09-08 10:11:32 +00:00
"log"
2020-09-08 15:13:39 +00:00
"net"
"net/url"
"strings"
2020-09-08 10:11:32 +00:00
)
func main() {
cfg, err := Load("config")
2020-09-08 10:11:32 +00:00
if err != nil {
log.Fatalf("failed to load config file: %v", err)
}
2020-09-08 15:13:39 +00:00
2020-09-08 16:24:16 +00:00
srv := NewServer()
2020-09-08 15:13:39 +00:00
for _, d := range cfg.ChildrenByName("frontend") {
2020-09-08 15:13:39 +00:00
if err := parseFrontend(srv, d); err != nil {
log.Fatalf("failed to parse frontend: %v", err)
}
}
if err := srv.Start(); err != nil {
log.Fatal(err)
}
2020-09-08 15:13:39 +00:00
select {}
}
func parseFrontend(srv *Server, d *Directive) error {
frontend := &Frontend{Server: srv}
srv.Frontends = append(srv.Frontends, frontend)
// TODO: support multiple backends
backendDirective := d.ChildByName("backend")
if backendDirective == nil {
return fmt.Errorf("missing backend directive in frontend block")
}
if err := parseBackend(&frontend.Backend, backendDirective); err != nil {
return err
}
var certNames []string
for _, listenAddr := range d.Params {
2020-09-08 15:13:39 +00:00
host, port, err := net.SplitHostPort(listenAddr)
if err != nil {
return fmt.Errorf("failed to parse listen address %q: %v", listenAddr, err)
}
// TODO: come up with something more robust
var name string
if host != "" && host != "localhost" && net.ParseIP(host) == nil {
name = host
certNames = append(certNames, host)
2020-09-08 15:13:39 +00:00
host = ""
}
addr := net.JoinHostPort(host, port)
2020-09-08 15:13:39 +00:00
ln := srv.RegisterListener(addr)
if err := ln.RegisterFrontend(name, frontend); err != nil {
return err
}
2020-09-08 15:13:39 +00:00
}
if err := srv.certmagic.ManageAsync(context.Background(), certNames); err != nil {
2020-09-08 16:24:16 +00:00
return fmt.Errorf("failed to manage TLS certificates: %v", err)
}
2020-09-08 15:13:39 +00:00
return nil
}
func parseBackend(backend *Backend, d *Directive) error {
var backendURI string
if err := d.ParseParams(&backendURI); err != nil {
return err
}
if !strings.Contains(backendURI, ":/") {
// This is a raw domain name, make it an URL with an empty scheme
backendURI = "//" + backendURI
}
u, err := url.Parse(backendURI)
if err != nil {
return fmt.Errorf("failed to parse backend URI %q: %v", backendURI, err)
}
// TODO: +proxy to use the PROXY protocol
switch u.Scheme {
case "", "tcp":
backend.Network = "tcp"
backend.Address = u.Host
case "unix":
backend.Network = "unix"
backend.Address = u.Host
default:
return fmt.Errorf("failed to setup backend %q: unsupported URI scheme", backendURI)
}
return nil
2020-09-08 10:11:32 +00:00
}