~emersion/tlstunnel

a2bf967da74fb45bfd5c32a64f47a5b08c3a201f — Simon Ser 6 months ago aae3588
Switch to scfg

And we get nested blocks for free.
6 files changed, 15 insertions(+), 117 deletions(-)

M cmd/tlstunnel/main.go
D config.go
M directives.go
M go.mod
M go.sum
M server.go
M cmd/tlstunnel/main.go => cmd/tlstunnel/main.go +2 -1
@@ 4,6 4,7 @@ import (
	"flag"
	"log"

	"git.sr.ht/~emersion/go-scfg"
	"git.sr.ht/~emersion/tlstunnel"
	"github.com/caddyserver/certmagic"
)


@@ 17,7 18,7 @@ func main() {
	flag.StringVar(&configPath, "config", configPath, "path to configuration file")
	flag.Parse()

	cfg, err := tlstunnel.LoadConfig(configPath)
	cfg, err := scfg.Load(configPath)
	if err != nil {
		log.Fatalf("failed to load config file: %v", err)
	}

D config.go => config.go +0 -109
@@ 1,109 0,0 @@
package tlstunnel

import (
	"bufio"
	"fmt"
	"io"
	"os"

	"github.com/google/shlex"
)

type Directive struct {
	Name     string
	Params   []string
	Children []*Directive
}

func (d *Directive) ParseParams(params ...*string) error {
	if len(d.Params) < len(params) {
		return fmt.Errorf("directive %q: want %v params, got %v", d.Name, len(params), len(d.Params))
	}
	for i, ptr := range params {
		if ptr == nil {
			continue
		}
		*ptr = d.Params[i]
	}
	return nil
}

func (d *Directive) ChildrenByName(name string) []*Directive {
	l := make([]*Directive, 0, len(d.Children))
	for _, child := range d.Children {
		if child.Name == name {
			l = append(l, child)
		}
	}
	return l
}

func (d *Directive) ChildByName(name string) *Directive {
	for _, child := range d.Children {
		if child.Name == name {
			return child
		}
	}
	return nil
}

func LoadConfig(path string) (*Directive, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return ParseConfig(f)
}

func ParseConfig(r io.Reader) (*Directive, error) {
	scanner := bufio.NewScanner(r)

	var directives []*Directive
	var cur *Directive
	for scanner.Scan() {
		l := scanner.Text()
		words, err := shlex.Split(l)
		if err != nil {
			return nil, fmt.Errorf("failed to parse config file: %v", err)
		} else if len(words) == 0 {
			continue
		}

		if len(words) == 1 && l[len(l)-1] == '}' {
			if cur == nil {
				return nil, fmt.Errorf("unexpected '}'")
			}
			cur = nil
			continue
		}

		var d *Directive
		if words[len(words)-1] == "{" && l[len(l)-1] == '{' {
			words = words[:len(words)-1]

			var name string
			params := words
			if len(words) > 0 {
				name, params = words[0], words[1:]
			}

			d = &Directive{Name: name, Params: params}
			cur = d
			directives = append(directives, d)
		} else {
			d = &Directive{Name: words[0], Params: words[1:]}
			if cur != nil {
				cur.Children = append(cur.Children, d)
			} else {
				directives = append(directives, d)
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("failed to read config file: %v", err)
	}

	return &Directive{Children: directives}, nil
}

M directives.go => directives.go +8 -6
@@ 5,10 5,12 @@ import (
	"net"
	"net/url"
	"strings"

	"git.sr.ht/~emersion/go-scfg"
)

func parseConfig(srv *Server, cfg *Directive) error {
	for _, d := range cfg.Children {
func parseConfig(srv *Server, cfg scfg.Block) error {
	for _, d := range cfg {
		var err error
		switch d.Name {
		case "frontend":


@@ 25,12 27,12 @@ func parseConfig(srv *Server, cfg *Directive) error {
	return nil
}

func parseFrontend(srv *Server, d *Directive) error {
func parseFrontend(srv *Server, d *scfg.Directive) error {
	frontend := &Frontend{Server: srv}
	srv.Frontends = append(srv.Frontends, frontend)

	// TODO: support multiple backends
	backendDirective := d.ChildByName("backend")
	backendDirective := d.Children.Get("backend")
	if backendDirective == nil {
		return fmt.Errorf("missing backend directive in frontend block")
	}


@@ 60,7 62,7 @@ func parseFrontend(srv *Server, d *Directive) error {
	return nil
}

func parseBackend(backend *Backend, d *Directive) error {
func parseBackend(backend *Backend, d *scfg.Directive) error {
	var backendURI string
	if err := d.ParseParams(&backendURI); err != nil {
		return err


@@ 94,7 96,7 @@ func parseBackend(backend *Backend, d *Directive) error {
	return nil
}

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

M go.mod => go.mod +1 -0
@@ 3,6 3,7 @@ module git.sr.ht/~emersion/tlstunnel
go 1.15

require (
	git.sr.ht/~emersion/go-scfg v0.0.0-20201019141958-764b187dbd52
	github.com/caddyserver/certmagic v0.12.0
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
	github.com/klauspost/cpuid v1.3.1 // indirect

M go.sum => go.sum +2 -0
@@ 1,3 1,5 @@
git.sr.ht/~emersion/go-scfg v0.0.0-20201019141958-764b187dbd52 h1:4+M83ExDGB+goSgq+q+c1aMA43GRLsItdN23fTDjKZ4=
git.sr.ht/~emersion/go-scfg v0.0.0-20201019141958-764b187dbd52/go.mod h1:t+Ww6SR24yYnXzEWiNlOY0AFo5E9B73X++10lrSpp4U=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/caddyserver/certmagic v0.12.0 h1:1f7kxykaJkOVVpXJ8ZrC6RAO5F6+kKm9U7dBFbLNeug=

M server.go => server.go +2 -1
@@ 9,6 9,7 @@ import (
	"net"
	"strings"

	"git.sr.ht/~emersion/go-scfg"
	"github.com/caddyserver/certmagic"
	"github.com/pires/go-proxyproto"
	"github.com/pires/go-proxyproto/tlvparse"


@@ 39,7 40,7 @@ func NewServer() *Server {
	}
}

func (srv *Server) Load(cfg *Directive) error {
func (srv *Server) Load(cfg scfg.Block) error {
	return parseConfig(srv, cfg)
}