jwhited / wgsd

A CoreDNS plugin that provides WireGuard peer information via DNS-SD semantics
https://www.jordanwhited.com/posts/wireguard-endpoint-discovery-nat-traversal/
MIT License
814 stars 76 forks source link

Exclude some peers from being propogated #35

Open HarvsG opened 3 years ago

HarvsG commented 3 years ago

In order to see why this might be useful I need to explain the use-case.

Several sites (some with and without NATs) and a cloud hosted registry server all connect via a wgsd generated mesh - great :+1:

Now some road-warriors want access to the networks and devices within the mesh and have their internet traffic encrypted. So their wireguard clients are added to the most readily accessible and fastest node on the mesh - the registry.

But now this very mobile device is being propagated by wgsd and all mesh members are listing it as a peer, but the device is not returning the favour as it is not running wgsd-client.

Now having a load of redundant peers on each mesh node is not the end of the world but it would be neat if there was a way to specify peers that should not be propagated by wgsd - allowing these road-warrior devices to be spikes off one node of the mesh.

I understand this could be done with a separate wireguard interface on the registry that is then bridged but the forwarding/routing of all the AllowedIPs would get confusing.

HarvsG commented 3 years ago

Now the obvious question is how do you identify which peers should be propagated and which shouldn't when all you have access to is the output of wg show forwarded by wgctl. It could just be a compare text file. I think there is a more elegant solution

In my use case all peers that I wish to be fully meshed have additional AllowedIPs configured on the registry. I.e they expose some other devices/subnets AllowedIPs=10.10.0.2/32, 192.168.100.1/24. Whereas all road warrior devices only have their wireguard interface exposed by the registry AllowedIPs=10.10.0.5/32.

So I propose a new flag/option in wgsd --only-propagate-subnets, if enabled wsgd will look at the specified AllowedIPs and if it is something other than a single device it will propagate, otherwise it discards.

Alternatively this could be done in wgsd-client with --only-accept-subnets however this might not scale well once the registry has 10s to 100s of road-warriors that are rarely used.

The end result is that an organisation can have their sites interconnected in a mesh and as many road-warriors as they like connecting via the registry.

HarvsG commented 3 years ago

Here is a go function that I made (not used go before so probably very ugly) that takes a list of CIDRs and returns the a list of the numbers of bits available.

package main

import (
    "fmt"
    "net"
)
// takes a comma separated list of IPv4 or IPv6 CIDRRs 
// and returns a list of the sizes of the networks expressed as unmasked bits
func networkSizes(ips []*net.IPNet) []int {
    var bitsizes []int
    for _, ip := range ips {
        ones, bits := ip.Mask.Size()
        bitsizes = append(bitsizes, (bits - ones))
    }
    return bitsizes
}

func main() {
    var networks []*net.IPNet
    _, n2, _ := net.ParseCIDR("192.168.0.24/31")
    _, n3, _ := net.ParseCIDR("2002::1234:abcd:ffff:c0a8:101/64")
    _, n4, _ := net.ParseCIDR("10.10.0.6/32")
    networks = append(networks ,n2, n3,n4)
    fmt.Println(networkSizes(networks))
}

Output:

[1 64 0]

The total number of addresses covered by the CIDRs would be 21+264+20. I moved away from calculating this total as I quickly overflowed the available bits in int when testing IPv6 addresses.

This function or something similar could be used to test for AllowedIPs that include more than just one address. It could even allow the user to set a threshold.