From 0fe451eed002c464d39fe25135bd67b253f3a1bb Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Tue, 22 Aug 2023 20:18:08 +0000 Subject: [PATCH] zones: introduce RingInfo.Merge() Signed-off-by: Alejandro Mery --- pkg/zones/rings.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/pkg/zones/rings.go b/pkg/zones/rings.go index fbd6927..7982694 100644 --- a/pkg/zones/rings.go +++ b/pkg/zones/rings.go @@ -1,6 +1,7 @@ package zones import ( + "fmt" "net/netip" "git.jpi.io/amery/jpictl/pkg/wireguard" @@ -24,6 +25,73 @@ type RingInfo struct { Address netip.Addr `toml:"address,omitempty"` } +// Merge attempts to combine two RingInfo structs +func (ri *RingInfo) Merge(alter *RingInfo) error { + switch { + case ri.Ring != alter.Ring: + // different ring + return fmt.Errorf("invalid %s: %v ≠ %v", "ring", ri.Ring, alter.Ring) + case ri.Enabled != alter.Enabled: + // different state + return fmt.Errorf("invalid %s: %v ≠ %v", "enabled", ri.Enabled, alter.Enabled) + case !canMergeAddress(ri.Address, alter.Address): + // different address + return fmt.Errorf("invalid %s: %v ≠ %v", "address", ri.Address, alter.Address) + case !canMergeKeyPairs(ri.Keys, alter.Keys): + // incompatible keypairs + return fmt.Errorf("invalid %s: %s ≠ %s", "keys", ri.Keys, alter.Keys) + } + + switch { + case ri.Keys == nil: + // assign keypair + ri.Keys = alter.Keys + case alter.Keys != nil: + // fill the gaps on our keypair + if ri.Keys.PrivateKey.IsZero() { + ri.Keys.PrivateKey = alter.Keys.PrivateKey + } + if ri.Keys.PublicKey.IsZero() { + ri.Keys.PublicKey = alter.Keys.PublicKey + } + } + + if addressEqual(ri.Address, netip.Addr{}) { + // assign address + ri.Address = alter.Address + } + + return nil +} + +func canMergeAddress(ip1, ip2 netip.Addr) bool { + var zero netip.Addr + + switch { + case addressEqual(ip1, zero) || addressEqual(ip2, zero) || addressEqual(ip1, ip2): + return true + default: + return false + } +} + +func addressEqual(ip1, ip2 netip.Addr) bool { + return ip1.Compare(ip2) == 0 +} + +func canMergeKeyPairs(p1, p2 *wireguard.KeyPair) bool { + switch { + case p1 == nil || p2 == nil: + return true + case !p1.PrivateKey.IsZero() && !p2.PrivateKey.IsZero() && !p1.PrivateKey.Equal(p2.PrivateKey): + return false + case !p1.PublicKey.IsZero() && !p2.PublicKey.IsZero() && !p1.PublicKey.Equal(p2.PublicKey): + return false + default: + return true + } +} + // RingAddressEncoder provides encoder/decoder access for a particular // Wireguard ring type RingAddressEncoder struct {