pdisc: add first version of peer discovery

Signed-off-by: Steffen Vogel <post@steffenvogel.de>
This commit is contained in:
Steffen Vogel
2022-08-29 17:52:16 +02:00
parent c4653ddd42
commit ddbd577e49
11 changed files with 632 additions and 21 deletions

View File

@@ -3,15 +3,18 @@ package core
import (
"fmt"
"io"
"net"
"os"
"time"
"go.uber.org/zap"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"riasc.eu/wice/pkg/crypto"
"riasc.eu/wice/pkg/device"
"riasc.eu/wice/pkg/util"
"riasc.eu/wice/pkg/util/buildinfo"
"riasc.eu/wice/pkg/wg"
proto "riasc.eu/wice/pkg/proto"
@@ -254,16 +257,17 @@ func (i *Interface) Configure(cfg *wg.Config) error {
return nil
}
func (i *Interface) AddPeer(pk crypto.Key) error {
cfg := wgtypes.Config{
Peers: []wgtypes.PeerConfig{
{
PublicKey: wgtypes.Key(pk),
},
},
func (i *Interface) AddPeer(pcfg *wgtypes.PeerConfig) error {
return i.client.ConfigureDevice(i.Name(), wgtypes.Config{
Peers: []wgtypes.PeerConfig{*pcfg},
})
}
return i.client.ConfigureDevice(i.Name(), cfg)
func (i *Interface) UpdatePeer(pcfg *wgtypes.PeerConfig) error {
pcfg2 := *pcfg
pcfg2.UpdateOnly = true
return i.AddPeer(&pcfg2)
}
func (i *Interface) RemovePeer(pk crypto.Key) error {
@@ -344,13 +348,41 @@ func (i *Interface) MarshalWithPeers(cb func(p *Peer) *coreproto.Peer) *coreprot
return q
}
func (i *Interface) MarshalDescription() (*pdiscproto.PeerDescription, error) {
func (i *Interface) MarshalDescription(chg pdiscproto.PeerDescriptionChange, pkOld *crypto.Key) (*pdiscproto.PeerDescription, error) {
allowedIPs := []*net.IPNet{
i.PublicKey().IPv6Address(),
i.PublicKey().IPv4Address(),
}
// Only allow a single IP from the network
for _, allowedIP := range allowedIPs {
for i := range allowedIP.Mask {
allowedIP.Mask[i] = 0xff
}
}
hn, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("failed to get hostname: %w", err)
}
return &pdiscproto.PeerDescription{
pd := &pdiscproto.PeerDescription{
Change: chg,
Hostname: hn,
}, nil
AllowedIps: util.StringSlice(allowedIPs),
BuildInfo: buildinfo.BuildInfo(),
}
if pkOld != nil {
if pd.Change != pdiscproto.PeerDescriptionChange_PEER_UPDATE {
return nil, fmt.Errorf("can not change public key in non-update message")
}
pd.PublicKeyNew = i.PublicKey().Bytes()
pd.PublicKey = pkOld.Bytes()
} else {
pd.PublicKey = i.PublicKey().Bytes()
}
return pd, nil
}

View File

@@ -142,6 +142,12 @@ func (d *Daemon) Restart() {
}
func (d *Daemon) Close() error {
for _, dev := range d.devices {
if err := dev.Close(); err != nil {
return fmt.Errorf("failed to delete device: %w", err)
}
}
if err := d.Watcher.Close(); err != nil {
return fmt.Errorf("failed to close interface: %w", err)
}
@@ -156,12 +162,6 @@ func (d *Daemon) Close() error {
return fmt.Errorf("failed to close WireGuard client: %w", err)
}
for _, dev := range d.devices {
if err := dev.Close(); err != nil {
return fmt.Errorf("failed to delete device: %w", err)
}
}
d.logger.Debug("Closed daemon")
if d.reexecOnClose {

View File

@@ -8,6 +8,7 @@ import (
"riasc.eu/wice/pkg/feat/cfgsync"
"riasc.eu/wice/pkg/feat/epdisc"
"riasc.eu/wice/pkg/feat/hsync"
"riasc.eu/wice/pkg/feat/pdisc"
"riasc.eu/wice/pkg/feat/rtsync"
"riasc.eu/wice/pkg/signaling"
"riasc.eu/wice/pkg/watcher"
@@ -43,5 +44,9 @@ func NewFeatures(w *watcher.Watcher, cfg *config.Config, c *wgctrl.Client, b sig
feats = append(feats, ep)
}
if cfg.Community != "" {
feats = append(feats, pdisc.New(w, c, b, cfg.Community))
}
return feats, ep
}

214
pkg/feat/pdisc/pdisc.go Normal file
View File

@@ -0,0 +1,214 @@
// Package pdisc implements peer discovery based on a shared community passphrase.
package pdisc
import (
"context"
"fmt"
"time"
"go.uber.org/zap"
"golang.zx2c4.com/wireguard/wgctrl"
"riasc.eu/wice/pkg/core"
"riasc.eu/wice/pkg/crypto"
"riasc.eu/wice/pkg/signaling"
"riasc.eu/wice/pkg/watcher"
"riasc.eu/wice/pkg/wg"
pdiscproto "riasc.eu/wice/pkg/proto/feat/pdisc"
)
type PeerDiscovery struct {
backend signaling.Backend
watcher *watcher.Watcher
community crypto.Key
logger *zap.Logger
}
func New(w *watcher.Watcher, c *wgctrl.Client, b signaling.Backend, community string) *PeerDiscovery {
pd := &PeerDiscovery{
backend: b,
watcher: w,
community: crypto.GenerateKeyFromPassword(community),
logger: zap.L().Named("pdisc"),
}
w.OnInterface(pd)
return pd
}
func (pd *PeerDiscovery) Start() error {
pd.logger.Info("Started peer discovery")
// Subscribe to peer updates
// TODO: Support per-interface communities
kp := &crypto.KeyPair{
Ours: pd.community,
Theirs: signaling.AnyKey,
}
if _, err := pd.backend.Subscribe(context.Background(), kp, pd); err != nil {
return fmt.Errorf("failed to subscribe on peer discovery channel: %w", err)
}
return nil
}
func (pd *PeerDiscovery) Close() error {
return nil
}
func (pd *PeerDiscovery) OnInterfaceAdded(i *core.Interface) {
i.OnModified(pd)
// Ignore interface which dont have a private key yet
if !i.PrivateKey().IsSet() {
return
}
if err := pd.sendPeerDescription(i, pdiscproto.PeerDescriptionChange_PEER_ADD, nil); err != nil {
pd.logger.Error("Failed to send peer description", zap.Error(err))
}
}
func (pd *PeerDiscovery) OnInterfaceRemoved(i *core.Interface) {
// Ignore interface which dont have a private key yet
if !i.PrivateKey().IsSet() {
return
}
if err := pd.sendPeerDescription(i, pdiscproto.PeerDescriptionChange_PEER_REMOVE, nil); err != nil {
pd.logger.Error("Failed to send peer description", zap.Error(err))
}
}
func (pd *PeerDiscovery) OnInterfaceModified(i *core.Interface, old *wg.Device, m core.InterfaceModifier) {
// Ignore interface which dont have a private key yet
if !i.PrivateKey().IsSet() {
return
}
// Only send an update if the private key changed.
// There are currently no other attributes which would need to be reannounced
if m.Is(core.InterfaceModifiedPrivateKey) {
if skOld := crypto.Key(old.PrivateKey); skOld.IsSet() {
pkOld := skOld.PublicKey()
if err := pd.sendPeerDescription(i, pdiscproto.PeerDescriptionChange_PEER_UPDATE, &pkOld); err != nil {
pd.logger.Error("Failed to send peer description", zap.Error(err))
}
}
}
}
func (pd *PeerDiscovery) OnSignalingMessage(kp *crypto.PublicKeyPair, msg *signaling.Message) {
if msg.Peer != nil {
if i := pd.watcher.Interfaces.ByPublicKey(kp.Theirs); i != nil {
// Received our own peer description. Ignoring...
return
}
if err := pd.onPeerDescription(msg.Peer); err != nil {
pd.logger.Error("Failed to handle peer description", zap.Error(err), zap.Any("pd", msg.Peer))
}
}
}
func (pd *PeerDiscovery) onPeerDescription(pdisc *pdiscproto.PeerDescription) error {
pk, err := crypto.ParseKeyBytes(pdisc.PublicKey)
if err != nil {
return fmt.Errorf("invalid public key: %w", err)
}
p := pd.watcher.PeerByKey(&pk)
cfg := pdisc.Config()
switch pdisc.Change {
case pdiscproto.PeerDescriptionChange_PEER_ADD:
if p != nil {
pd.logger.Warn("Peer already exists. Updating it instead", zap.String("intf", p.Interface.Name()))
pdisc.Change = pdiscproto.PeerDescriptionChange_PEER_UPDATE
}
case pdiscproto.PeerDescriptionChange_PEER_UPDATE:
if p == nil {
pd.logger.Warn("Peer does not exist exists yet. Adding it instead")
pdisc.Change = pdiscproto.PeerDescriptionChange_PEER_ADD
}
default:
if p == nil {
return fmt.Errorf("cant remove non-existing peer")
}
}
switch pdisc.Change {
case pdiscproto.PeerDescriptionChange_PEER_ADD:
for _, i := range pd.watcher.Interfaces {
if err := i.AddPeer(&cfg); err != nil {
return fmt.Errorf("failed to add peer: %w", err)
}
}
case pdiscproto.PeerDescriptionChange_PEER_UPDATE:
if pdisc.PublicKeyNew != nil {
// Remove old peer
if err := p.Interface.RemovePeer(pk); err != nil {
return fmt.Errorf("failed to remove peer: %w", err)
}
// Re-add peer with new public key
if err := p.Interface.AddPeer(&cfg); err != nil {
return fmt.Errorf("failed to add peer: %w", err)
}
} else {
if err := p.Interface.UpdatePeer(&cfg); err != nil {
return fmt.Errorf("failed to remove peer: %w", err)
}
}
case pdiscproto.PeerDescriptionChange_PEER_REMOVE:
if err := p.Interface.RemovePeer(pk); err != nil {
return fmt.Errorf("failed to remove peer: %w", err)
}
}
// Re-announce ourself in case this is a new peer we didnt knew already
if p == nil {
time.AfterFunc(1*time.Second, func() {
for _, i := range pd.watcher.Interfaces {
if err := pd.sendPeerDescription(i, pdiscproto.PeerDescriptionChange_PEER_ADD, nil); err != nil {
pd.logger.Error("Failed to send peer description", zap.Error(err))
}
}
})
}
return nil
}
func (pd *PeerDiscovery) sendPeerDescription(i *core.Interface, chg pdiscproto.PeerDescriptionChange, pkOld *crypto.Key) error {
d, err := i.MarshalDescription(chg, pkOld)
if err != nil {
return fmt.Errorf("failed to generate peer description: %w", err)
}
msg := &signaling.Message{
Peer: d,
}
kp := &crypto.KeyPair{
Ours: i.PrivateKey(),
Theirs: pd.community.PublicKey(),
}
if err := pd.backend.Publish(context.Background(), kp, msg); err != nil {
return err
}
pd.logger.Debug("Send peer description", zap.Any("description", d))
return nil
}

View File

@@ -0,0 +1,34 @@
package pdisc
import (
"fmt"
"net"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"riasc.eu/wice/pkg/crypto"
)
func (pd *PeerDescription) Config() wgtypes.PeerConfig {
var pk crypto.Key
if pd.PublicKeyNew != nil {
pk, _ = crypto.ParseKeyBytes(pd.PublicKeyNew)
} else {
pk, _ = crypto.ParseKeyBytes(pd.PublicKey)
}
allowedIPs := []net.IPNet{}
for _, allowedIP := range pd.AllowedIps {
_, ipnet, err := net.ParseCIDR(allowedIP)
if err != nil {
panic(fmt.Errorf("failed to parse WireGuard AllowedIP: %w", err))
}
allowedIPs = append(allowedIPs, *ipnet)
}
return wgtypes.PeerConfig{
ReplaceAllowedIPs: true,
PublicKey: wgtypes.Key(pk),
AllowedIPs: allowedIPs,
}
}

View File

@@ -0,0 +1,266 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.6.1
// source: feat/pdisc.proto
package pdisc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
proto "riasc.eu/wice/pkg/proto"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type PeerDescriptionChange int32
const (
PeerDescriptionChange_PEER_ADD PeerDescriptionChange = 0
PeerDescriptionChange_PEER_REMOVE PeerDescriptionChange = 1
PeerDescriptionChange_PEER_UPDATE PeerDescriptionChange = 2
)
// Enum value maps for PeerDescriptionChange.
var (
PeerDescriptionChange_name = map[int32]string{
0: "PEER_ADD",
1: "PEER_REMOVE",
2: "PEER_UPDATE",
}
PeerDescriptionChange_value = map[string]int32{
"PEER_ADD": 0,
"PEER_REMOVE": 1,
"PEER_UPDATE": 2,
}
)
func (x PeerDescriptionChange) Enum() *PeerDescriptionChange {
p := new(PeerDescriptionChange)
*p = x
return p
}
func (x PeerDescriptionChange) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (PeerDescriptionChange) Descriptor() protoreflect.EnumDescriptor {
return file_feat_pdisc_proto_enumTypes[0].Descriptor()
}
func (PeerDescriptionChange) Type() protoreflect.EnumType {
return &file_feat_pdisc_proto_enumTypes[0]
}
func (x PeerDescriptionChange) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use PeerDescriptionChange.Descriptor instead.
func (PeerDescriptionChange) EnumDescriptor() ([]byte, []int) {
return file_feat_pdisc_proto_rawDescGZIP(), []int{0}
}
// A PeerDescription is an announcement of a peer which is distributed to
type PeerDescription struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Change PeerDescriptionChange `protobuf:"varint,1,opt,name=change,proto3,enum=wice.pdisc.PeerDescriptionChange" json:"change,omitempty"`
// Hostname of the node
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"`
// Public WireGuard Curve25519 key
PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// A new public WireGuard Curve25519 key
// Only valid for change == PEER_UPDATE
PublicKeyNew []byte `protobuf:"bytes,4,opt,name=public_key_new,json=publicKeyNew,proto3" json:"public_key_new,omitempty"`
// List of allowed IPs
AllowedIps []string `protobuf:"bytes,5,rep,name=allowed_ips,json=allowedIps,proto3" json:"allowed_ips,omitempty"`
// wice build information
BuildInfo *proto.BuildInfo `protobuf:"bytes,6,opt,name=build_info,json=buildInfo,proto3" json:"build_info,omitempty"`
}
func (x *PeerDescription) Reset() {
*x = PeerDescription{}
if protoimpl.UnsafeEnabled {
mi := &file_feat_pdisc_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerDescription) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerDescription) ProtoMessage() {}
func (x *PeerDescription) ProtoReflect() protoreflect.Message {
mi := &file_feat_pdisc_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerDescription.ProtoReflect.Descriptor instead.
func (*PeerDescription) Descriptor() ([]byte, []int) {
return file_feat_pdisc_proto_rawDescGZIP(), []int{0}
}
func (x *PeerDescription) GetChange() PeerDescriptionChange {
if x != nil {
return x.Change
}
return PeerDescriptionChange_PEER_ADD
}
func (x *PeerDescription) GetHostname() string {
if x != nil {
return x.Hostname
}
return ""
}
func (x *PeerDescription) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *PeerDescription) GetPublicKeyNew() []byte {
if x != nil {
return x.PublicKeyNew
}
return nil
}
func (x *PeerDescription) GetAllowedIps() []string {
if x != nil {
return x.AllowedIps
}
return nil
}
func (x *PeerDescription) GetBuildInfo() *proto.BuildInfo {
if x != nil {
return x.BuildInfo
}
return nil
}
var File_feat_pdisc_proto protoreflect.FileDescriptor
var file_feat_pdisc_proto_rawDesc = []byte{
0x0a, 0x10, 0x66, 0x65, 0x61, 0x74, 0x2f, 0x70, 0x64, 0x69, 0x73, 0x63, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x0a, 0x77, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x64, 0x69, 0x73, 0x63, 0x1a, 0x0c,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfe, 0x01, 0x0a,
0x0f, 0x50, 0x65, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x12, 0x39, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x21, 0x2e, 0x77, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x64, 0x69, 0x73, 0x63, 0x2e, 0x50, 0x65,
0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68,
0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68,
0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x65, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c,
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x4e, 0x65, 0x77, 0x12, 0x1f, 0x0a, 0x0b,
0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x12, 0x2e, 0x0a,
0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x0f, 0x2e, 0x77, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e,
0x66, 0x6f, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2a, 0x47, 0x0a,
0x15, 0x50, 0x65, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x41,
0x44, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x52, 0x45, 0x4d,
0x4f, 0x56, 0x45, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x55, 0x50,
0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x24, 0x5a, 0x22, 0x72, 0x69, 0x61, 0x73, 0x63, 0x2e,
0x65, 0x75, 0x2f, 0x77, 0x69, 0x63, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2f, 0x66, 0x65, 0x61, 0x74, 0x2f, 0x70, 0x64, 0x69, 0x73, 0x63, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_feat_pdisc_proto_rawDescOnce sync.Once
file_feat_pdisc_proto_rawDescData = file_feat_pdisc_proto_rawDesc
)
func file_feat_pdisc_proto_rawDescGZIP() []byte {
file_feat_pdisc_proto_rawDescOnce.Do(func() {
file_feat_pdisc_proto_rawDescData = protoimpl.X.CompressGZIP(file_feat_pdisc_proto_rawDescData)
})
return file_feat_pdisc_proto_rawDescData
}
var file_feat_pdisc_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_feat_pdisc_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_feat_pdisc_proto_goTypes = []interface{}{
(PeerDescriptionChange)(0), // 0: wice.pdisc.PeerDescriptionChange
(*PeerDescription)(nil), // 1: wice.pdisc.PeerDescription
(*proto.BuildInfo)(nil), // 2: wice.BuildInfo
}
var file_feat_pdisc_proto_depIdxs = []int32{
0, // 0: wice.pdisc.PeerDescription.change:type_name -> wice.pdisc.PeerDescriptionChange
2, // 1: wice.pdisc.PeerDescription.build_info:type_name -> wice.BuildInfo
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_feat_pdisc_proto_init() }
func file_feat_pdisc_proto_init() {
if File_feat_pdisc_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_feat_pdisc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PeerDescription); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_feat_pdisc_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_feat_pdisc_proto_goTypes,
DependencyIndexes: file_feat_pdisc_proto_depIdxs,
EnumInfos: file_feat_pdisc_proto_enumTypes,
MessageInfos: file_feat_pdisc_proto_msgTypes,
}.Build()
File_feat_pdisc_proto = out.File
file_feat_pdisc_proto_rawDesc = nil
file_feat_pdisc_proto_goTypes = nil
file_feat_pdisc_proto_depIdxs = nil
}

View File

@@ -5,7 +5,7 @@ package proto
//go:generate protoc --proto_path=../../proto --go_out=. --go_opt=paths=import,module=riasc.eu/wice/pkg/proto core/peer.proto core/interface.proto
//go:generate protoc --proto_path=../../proto --go_out=. --go_opt=paths=import,module=riasc.eu/wice/pkg/proto signaling/signaling.proto
//go:generate protoc --proto_path=../../proto --go_out=. --go_opt=paths=import,module=riasc.eu/wice/pkg/proto rpc/daemon.proto rpc/epdisc.proto rpc/event.proto rpc/signaling.proto rpc/watcher.proto
//go:generate protoc --proto_path=../../proto --go_out=. --go_opt=paths=import,module=riasc.eu/wice/pkg/proto feat/epdisc.proto feat/epdisc_candidate.proto
//go:generate protoc --proto_path=../../proto --go_out=. --go_opt=paths=import,module=riasc.eu/wice/pkg/proto feat/epdisc.proto feat/epdisc_candidate.proto feat/pdisc.proto
//go:generate protoc --proto_path=../../proto --go-grpc_out=. --go-grpc_opt=paths=import,module=riasc.eu/wice/pkg/proto rpc/daemon.proto rpc/epdisc.proto rpc/signaling.proto rpc/watcher.proto
//go:generate protoc --proto_path=../../proto --go-grpc_out=. --go-grpc_opt=paths=import,module=riasc.eu/wice/pkg/proto signaling/signaling.proto

View File

@@ -1,6 +1,7 @@
package util
import (
"fmt"
"math/rand"
"golang.org/x/exp/slices"
@@ -77,3 +78,13 @@ func MapSlice[T any](s []T, cb func(T) T) []T {
return n
}
func StringSlice[T any](s []T) []string {
n := []string{}
for _, t := range s {
n = append(n, fmt.Sprintf("%v", t))
}
return n
}

View File

@@ -86,6 +86,10 @@ func New(client *wgctrl.Client, interval time.Duration, filter *regexp.Regexp) (
}
func (w *Watcher) Close() error {
if err := w.Sync(); err != nil {
return fmt.Errorf("final sync failed")
}
close(w.stop)
return nil
@@ -222,3 +226,13 @@ func (w *Watcher) Peer(intf string, pk *crypto.Key) *core.Peer {
return nil
}
func (w *Watcher) PeerByKey(pk *crypto.Key) *core.Peer {
for _, i := range w.Interfaces {
if p, ok := i.Peers[*pk]; ok {
return p
}
}
return nil
}

View File

@@ -112,7 +112,9 @@ var _ = Describe("watcher", func() {
sk, err := crypto.GenerateKey()
Expect(err).To(Succeed())
err = i.AddPeer(sk.PublicKey())
err = i.AddPeer(&wgtypes.PeerConfig{
PublicKey: wgtypes.Key(sk.PublicKey()),
})
Expect(err).To(Succeed())
Eventually(func(g Gomega) {

33
proto/feat/pdisc.proto Normal file
View File

@@ -0,0 +1,33 @@
syntax = "proto3";
package wice.pdisc;
option go_package = "riasc.eu/wice/pkg/proto/feat/pdisc";
import "common.proto";
enum PeerDescriptionChange {
PEER_ADD = 0;
PEER_REMOVE = 1;
PEER_UPDATE = 2;
}
// A PeerDescription is an announcement of a peer which is distributed to
message PeerDescription {
PeerDescriptionChange change = 1;
// Hostname of the node
string hostname = 2;
// Public WireGuard Curve25519 key
bytes public_key = 3;
// A new public WireGuard Curve25519 key
// Only valid for change == PEER_UPDATE
bytes public_key_new = 4;
// List of allowed IPs
repeated string allowed_ips = 5;
// wice build information
BuildInfo build_info = 6;
}