diff --git a/go.sum b/go.sum index b9a1de6..c5ba350 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,11 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4 h1:nwOc1YaOrYJ37sEBrtWZrdqzK22hiJs3GpDmP3sR2Yw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= @@ -18,7 +16,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0 h1:vySPY5Oxnn/8lxAPn2cK6kAzcZzYJl3KriSLO46OT18= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -38,7 +35,6 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200520041808-52d707b772fe h1:mjAZxE1nh8yvuwhGHpdDqdhtNu2dgbpk93TwoXuk5so= github.com/vishvananda/netns v0.0.0-20200520041808-52d707b772fe/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= @@ -72,7 +68,6 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/pkg/wgembed/config.go b/pkg/wgembed/config.go index 525e5f7..1d3a780 100644 --- a/pkg/wgembed/config.go +++ b/pkg/wgembed/config.go @@ -19,7 +19,7 @@ type ConfigFile struct { type IfaceConfig struct { PrivateKey string - Address string + Address []string ListenPort *int DNS []string } diff --git a/pkg/wgembed/config_test.go b/pkg/wgembed/config_test.go new file mode 100644 index 0000000..b36c6bd --- /dev/null +++ b/pkg/wgembed/config_test.go @@ -0,0 +1,77 @@ +package wgembed + +import ( + "reflect" + "testing" +) + +func TestReadConfig(t *testing.T) { + type args struct { + path string + } + tests := []struct { + name string + args args + want *ConfigFile + wantErr bool + }{ + { + "dual-stack config file", + args{"testdata/dualstack.conf"}, + &ConfigFile{ + Interface: IfaceConfig{ + PrivateKey: "wPNV/LaCgF5yx7bAotuxaaQ6jxsy1H7zs8LuNYzOXHQ=", + Address: []string{"10.44.0.1/24", "fd48:4c4:7aa9::1/64"}, + DNS: []string{}, + }, + Peers: []PeerConfig{{PublicKey: "gysKSkCS/VeAyHIAVtf8B/sbQnEd5FYogtj7kO4d4zY=", AllowedIPs: []string{"10.44.0.2/32", "fd48:4c4:7aa9::2/128"}}}, + wgconfig: nil, + }, + false, + }, + { + "IPv4-only config file", + args{"testdata/ipv4-only.conf"}, + &ConfigFile{ + Interface: IfaceConfig{ + PrivateKey: "wPNV/LaCgF5yx7bAotuxaaQ6jxsy1H7zs8LuNYzOXHQ=", + Address: []string{"10.44.0.1/24"}, + DNS: []string{}, + }, + Peers: []PeerConfig{{PublicKey: "gysKSkCS/VeAyHIAVtf8B/sbQnEd5FYogtj7kO4d4zY=", AllowedIPs: []string{"10.44.0.2/32"}}}, + wgconfig: nil, + }, + false, + }, + { + "IPv6-only config file", + args{"testdata/ipv6-only.conf"}, + &ConfigFile{ + Interface: IfaceConfig{ + PrivateKey: "wPNV/LaCgF5yx7bAotuxaaQ6jxsy1H7zs8LuNYzOXHQ=", + Address: []string{"fd48:4c4:7aa9::1/64"}, + DNS: []string{}, + }, + Peers: []PeerConfig{{PublicKey: "gysKSkCS/VeAyHIAVtf8B/sbQnEd5FYogtj7kO4d4zY=", AllowedIPs: []string{"fd48:4c4:7aa9::2/128"}}}, + wgconfig: nil, + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.want.load(); err != nil { + t.Errorf("wanted ConfigFile not valid") + } + + got, err := ReadConfig(tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("ReadConfig() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Error("ReadConfig() result does not match wanted config") + } + }) + } +} diff --git a/pkg/wgembed/iface.go b/pkg/wgembed/iface.go index 269a70c..060b8a7 100644 --- a/pkg/wgembed/iface.go +++ b/pkg/wgembed/iface.go @@ -22,7 +22,7 @@ import ( type WireGuardInterface interface { LoadConfig(config *ConfigFile) error - AddPeer(publicKey string, addressCIDR string) error + AddPeer(publicKey string, addressCIDR []string) error ListPeers() ([]wgtypes.Peer, error) RemovePeer(publicKey string) error PublicKey() (string, error) @@ -87,8 +87,8 @@ func New(interfaceName string) (WireGuardInterface, error) { return wg, nil } -// LoadConfig reads the given wireguard config file -// and configured the interface +// LoadConfigFile reads the given wireguard config file +// and configures the interface func (wg *WireGuardInterfaceImpl) LoadConfigFile(path string) error { config, err := ReadConfig(path) if err != nil { @@ -97,6 +97,8 @@ func (wg *WireGuardInterfaceImpl) LoadConfigFile(path string) error { return wg.LoadConfig(config) } +// LoadConfig takes the given wireguard config object +// and configures the interface func (wg *WireGuardInterfaceImpl) LoadConfig(config *ConfigFile) error { c, err := config.Config() if err != nil { @@ -109,8 +111,10 @@ func (wg *WireGuardInterfaceImpl) LoadConfig(config *ConfigFile) error { return errors.Wrap(err, "failed to configure wireguard") } - if err := wg.setIP(config.Interface.Address); err != nil { - return errors.Wrap(err, "failed to set interface ip address") + for _, addr := range config.Interface.Address { + if err := wg.setIP(addr); err != nil { + return errors.Wrap(err, "failed to set interface ip address") + } } if err := wg.Up(); err != nil { diff --git a/pkg/wgembed/management.go b/pkg/wgembed/management.go index 443eedf..ae5e131 100644 --- a/pkg/wgembed/management.go +++ b/pkg/wgembed/management.go @@ -9,15 +9,22 @@ import ( "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) -func (wg *WireGuardInterfaceImpl) AddPeer(publicKey string, addressCIDR string) error { +// AddPeer adds a new peer to the interface. +// The subnet sizes in addressCIDR should be /32 for IPv4 and /128 for IPv6, +// as the whole subnet will be added to AllowedIPs for this device. +func (wg *WireGuardInterfaceImpl) AddPeer(publicKey string, addressCIDR []string) error { key, err := wgtypes.ParseKey(publicKey) if err != nil { return errors.Wrapf(err, "bad public key %v", publicKey) } - _, allowedIPs, err := net.ParseCIDR(addressCIDR) - if err != nil || allowedIPs == nil { - return errors.Wrap(err, "bad CIDR value for AllowedIPs") + parsedAddresses := make([]net.IPNet, 0, len(addressCIDR)) + for _, addr := range addressCIDR { + _, allowedIPs, err := net.ParseCIDR(addr) + if err != nil || allowedIPs == nil { + return errors.Wrap(err, "bad CIDR value for AllowedIPs") + } + parsedAddresses = append(parsedAddresses, *allowedIPs) } return wg.configure(func(config *wgtypes.Config) error { @@ -25,7 +32,7 @@ func (wg *WireGuardInterfaceImpl) AddPeer(publicKey string, addressCIDR string) config.Peers = []wgtypes.PeerConfig{ { PublicKey: key, - AllowedIPs: []net.IPNet{*allowedIPs}, + AllowedIPs: parsedAddresses, ReplaceAllowedIPs: true, }, } diff --git a/pkg/wgembed/noop.go b/pkg/wgembed/noop.go index a9a2a71..453561a 100644 --- a/pkg/wgembed/noop.go +++ b/pkg/wgembed/noop.go @@ -13,7 +13,7 @@ func (wg *NoOpWireguardInterface) LoadConfig(config *ConfigFile) error { return nil } -func (wg *NoOpWireguardInterface) AddPeer(publicKey string, addressCIDR string) error { +func (wg *NoOpWireguardInterface) AddPeer(publicKey string, addressCIDR []string) error { return nil } diff --git a/pkg/wgembed/testdata/dualstack.conf b/pkg/wgembed/testdata/dualstack.conf new file mode 100644 index 0000000..d5fa387 --- /dev/null +++ b/pkg/wgembed/testdata/dualstack.conf @@ -0,0 +1,7 @@ +[Interface] +PrivateKey = wPNV/LaCgF5yx7bAotuxaaQ6jxsy1H7zs8LuNYzOXHQ= +Address = 10.44.0.1/24, fd48:4c4:7aa9::1/64 + +[Peer] +PublicKey = gysKSkCS/VeAyHIAVtf8B/sbQnEd5FYogtj7kO4d4zY= +AllowedIPs = 10.44.0.2/32, fd48:4c4:7aa9::2/128 diff --git a/pkg/wgembed/testdata/ipv4-only.conf b/pkg/wgembed/testdata/ipv4-only.conf new file mode 100644 index 0000000..ab3b54b --- /dev/null +++ b/pkg/wgembed/testdata/ipv4-only.conf @@ -0,0 +1,7 @@ +[Interface] +PrivateKey = wPNV/LaCgF5yx7bAotuxaaQ6jxsy1H7zs8LuNYzOXHQ= +Address = 10.44.0.1/24 + +[Peer] +PublicKey = gysKSkCS/VeAyHIAVtf8B/sbQnEd5FYogtj7kO4d4zY= +AllowedIPs = 10.44.0.2/32 diff --git a/pkg/wgembed/testdata/ipv6-only.conf b/pkg/wgembed/testdata/ipv6-only.conf new file mode 100644 index 0000000..deb8662 --- /dev/null +++ b/pkg/wgembed/testdata/ipv6-only.conf @@ -0,0 +1,7 @@ +[Interface] +PrivateKey = wPNV/LaCgF5yx7bAotuxaaQ6jxsy1H7zs8LuNYzOXHQ= +Address = fd48:4c4:7aa9::1/64 + +[Peer] +PublicKey = gysKSkCS/VeAyHIAVtf8B/sbQnEd5FYogtj7kO4d4zY= +AllowedIPs = fd48:4c4:7aa9::2/128