From 5d946e4e9385c0087dac512470bd76f675c70468 Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Tue, 22 Aug 2023 01:34:58 +0000 Subject: [PATCH] wireguard: adds wgN.conf parser Signed-off-by: Alejandro Mery --- go.mod | 4 +- go.sum | 4 + pkg/wireguard/config.go | 201 +++++++++++++++++++++++++++++++++++++ pkg/wireguard/wireguard.go | 2 + 4 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 pkg/wireguard/config.go create mode 100644 pkg/wireguard/wireguard.go diff --git a/go.mod b/go.mod index d9bbacd..e1342ef 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,17 @@ module git.jpi.io/amery/jpictl go 1.19 require ( + darvaza.org/core v0.9.5 darvaza.org/resolver v0.5.2 darvaza.org/sidecar v0.0.0-20230721122716-b9c54b8adbaf darvaza.org/slog v0.5.2 github.com/burntSushi/toml v0.3.1 github.com/mgechev/revive v1.3.2 github.com/spf13/cobra v1.7.0 + gopkg.in/gcfg.v1 v1.2.3 ) require ( - darvaza.org/core v0.9.5 // indirect darvaza.org/slog/handlers/filter v0.4.4 // indirect darvaza.org/slog/handlers/zerolog v0.4.4 // indirect github.com/BurntSushi/toml v1.3.2 // indirect @@ -36,4 +37,5 @@ require ( golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/tools v0.12.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index b810d46..d82aadb 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,10 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/wireguard/config.go b/pkg/wireguard/config.go new file mode 100644 index 0000000..9af6902 --- /dev/null +++ b/pkg/wireguard/config.go @@ -0,0 +1,201 @@ +package wireguard + +import ( + "encoding/base64" + "errors" + "io" + "net/netip" + "strconv" + "strings" + + "darvaza.org/core" + "gopkg.in/gcfg.v1" +) + +// Config represents a wgN.conf file +type Config struct { + Interface InterfaceConfig + Peer []PeerConfig +} + +// GetAddress is a shortcut to the interface's address +func (f *Config) GetAddress() netip.Addr { + return f.Interface.Address +} + +// Peers tells how many peers are described +func (f *Config) Peers() int { + return len(f.Peer) +} + +// InterfaceConfig represents the [Interface] section +type InterfaceConfig struct { + Address netip.Addr + PrivateKey []byte + ListenPort uint16 +} + +// PeerConfig represents a [Peer] section +type PeerConfig struct { + PublicKey []byte + Endpoint EndpointAddress + AllowedIPs []netip.Prefix +} + +// EndpointAddress is a host:port pair to reach the Peer +type EndpointAddress struct { + Name string + Port uint16 +} + +// FromString sets the EndpointAddress from a given "[host]:port" +func (ep *EndpointAddress) FromString(s string) error { + host, port, err := core.SplitHostPort(s) + if err != nil { + return err + } + + ep.Name = host + + switch { + case port != "": + n, _ := strconv.ParseUint(port, 10, 16) + ep.Port = uint16(n) + default: + ep.Port = 0 + } + + return nil +} + +type intermediateConfig struct { + Interface interfaceConfig + Peer peersConfig +} + +func (v *intermediateConfig) Export() (*Config, error) { + var out Config + var err error + + // Interface + out.Interface, err = v.Interface.Export() + if err != nil { + return nil, err + } + + // Peers + peers, ok := v.PeersCount() + if !ok { + return nil, errors.New("inconsistent Peer data") + } + + for i := 0; i < peers; i++ { + p, err := v.ExportPeer(i) + if err != nil { + err = core.Wrapf(err, "Peer[%v]:", i) + return nil, err + } + + out.Peer = append(out.Peer, p) + } + + return &out, nil +} + +type interfaceConfig struct { + Address netip.Addr + PrivateKey string + ListenPort uint16 +} + +func (p interfaceConfig) Export() (InterfaceConfig, error) { + out := InterfaceConfig{ + Address: p.Address, + ListenPort: p.ListenPort, + } + + b, err := base64.StdEncoding.DecodeString(p.PrivateKey) + if err != nil { + err = core.Wrap(err, "PrivateKey") + return InterfaceConfig{}, err + } + + out.PrivateKey = b + + return out, nil +} + +type peersConfig struct { + PublicKey []string + Endpoint []string + AllowedIPs []string +} + +func (v *intermediateConfig) ExportPeer(i int) (PeerConfig, error) { + var out PeerConfig + + // Endpoint + s := v.Peer.Endpoint[i] + err := out.Endpoint.FromString(s) + if err != nil { + err = core.Wrap(err, "Endpoint") + return out, err + } + + // PublicKey + s = v.Peer.PublicKey[i] + out.PublicKey, err = base64.StdEncoding.DecodeString(s) + if err != nil { + err = core.Wrap(err, "PublicKey") + return out, err + } + + // AllowedIPs + s = v.Peer.AllowedIPs[i] + out.AllowedIPs, err = parseAllowedIPs(s) + if err != nil { + err = core.Wrap(err, "AllowedIPs") + return out, err + } + + return out, nil +} + +func parseAllowedIPs(data string) ([]netip.Prefix, error) { + var out []netip.Prefix + + for _, s := range strings.Split(data, ",") { + s = strings.TrimSpace(s) + p, err := netip.ParsePrefix(s) + if err != nil { + return out, err + } + + out = append(out, p) + } + + return out, nil +} + +func (v *intermediateConfig) PeersCount() (int, bool) { + c0 := len(v.Peer.Endpoint) + c1 := len(v.Peer.PublicKey) + c2 := len(v.Peer.AllowedIPs) + + if c0 != c1 || c1 != c2 { + return 0, false + } + + return c0, true +} + +// NewConfigFromReader parses a wgN.conf file +func NewConfigFromReader(r io.Reader) (*Config, error) { + temp := &intermediateConfig{} + + if err := gcfg.ReadInto(temp, r); err != nil { + return nil, err + } + + return temp.Export() +} diff --git a/pkg/wireguard/wireguard.go b/pkg/wireguard/wireguard.go new file mode 100644 index 0000000..2ada48f --- /dev/null +++ b/pkg/wireguard/wireguard.go @@ -0,0 +1,2 @@ +// Package wireguard deals with wireguard config +package wireguard