wireguard: adds wgN.conf parser
Signed-off-by: Alejandro Mery <amery@jpi.io>
This commit is contained in:
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Package wireguard deals with wireguard config
|
||||
package wireguard
|
||||
Reference in New Issue
Block a user