Alejandro Mery
1 year ago
4 changed files with 210 additions and 1 deletions
@ -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() |
||||||
|
} |
Loading…
Reference in new issue