mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
assign ipv6 address to each machine derived from their public keys
This commit is contained in:
@@ -3,6 +3,7 @@ package network
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"uncloud/internal/secret"
|
||||
)
|
||||
|
||||
// MachineIP returns the IP address of the machine which is the first address in the subnet.
|
||||
@@ -10,6 +11,13 @@ func MachineIP(subnet netip.Prefix) netip.Addr {
|
||||
return subnet.Masked().Addr().Next()
|
||||
}
|
||||
|
||||
// PeerIPv6 returns the IPv6 address of a peer derived from the first 14 bytes of its public key.
|
||||
func PeerIPv6(publicKey secret.Secret) netip.Addr {
|
||||
bytes := [16]byte{0xfd, 0xcc}
|
||||
copy(bytes[2:], publicKey[:14])
|
||||
return netip.AddrFrom16(bytes)
|
||||
}
|
||||
|
||||
func prefixToIPNet(prefix netip.Prefix) net.IPNet {
|
||||
return net.IPNet{
|
||||
IP: prefix.Addr().AsSlice(),
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
const (
|
||||
WireGuardInterfaceName = "uncloud"
|
||||
WireGuardPort = 51820
|
||||
// WireGuardKeepaliveInterval is sensible interval that works with a wide variety of firewalls is 25 seconds.
|
||||
// WireGuardKeepaliveInterval is sensible interval that works with a wide variety of firewalls.
|
||||
WireGuardKeepaliveInterval = 25 * time.Second
|
||||
)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
"log/slog"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -101,11 +102,15 @@ func (n *WireGuardNetwork) Configure(config Config) error {
|
||||
}
|
||||
slog.Info("Configured WireGuard interface.", "name", n.link.Attrs().Name)
|
||||
|
||||
if err = n.updateSubnet(config.Subnet); err != nil {
|
||||
machineIP := MachineIP(config.Subnet)
|
||||
machineIPSubnet := netip.PrefixFrom(machineIP, config.Subnet.Bits())
|
||||
machineIPv6 := netip.PrefixFrom(PeerIPv6(config.PublicKey), 128)
|
||||
addrs := []netip.Prefix{machineIPSubnet, machineIPv6}
|
||||
if err = n.updateAddresses(addrs); err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("Updated the subnet of the WireGuard interface.",
|
||||
"name", n.link.Attrs().Name, "subnet", config.Subnet)
|
||||
slog.Info("Updated addresses of the WireGuard interface.",
|
||||
"name", n.link.Attrs().Name, "addrs", addrs)
|
||||
|
||||
// Bring the WireGuard interface up if it's not already up.
|
||||
if n.link.Attrs().Flags&unix.IFF_UP != unix.IFF_UP {
|
||||
@@ -123,27 +128,30 @@ func (n *WireGuardNetwork) Configure(config Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateSubnet assigns the subnet and the first IP address in it to the WireGuard interface.
|
||||
// updateAddresses assigns addresses to the WireGuard interface and removes old ones.
|
||||
// It also removes any other addresses that have been added out of band.
|
||||
func (n *WireGuardNetwork) updateSubnet(subnet netip.Prefix) error {
|
||||
machineIP := MachineIP(subnet)
|
||||
ipSubnet := prefixToIPNet(netip.PrefixFrom(machineIP, subnet.Bits()))
|
||||
if err := netlink.AddrAdd(n.link, &netlink.Addr{IPNet: &ipSubnet}); err != nil {
|
||||
if !errors.Is(err, unix.EEXIST) {
|
||||
return fmt.Errorf("add subnet address to WireGuard link %q: %w", n.link.Attrs().Name, err)
|
||||
func (n *WireGuardNetwork) updateAddresses(addrs []netip.Prefix) error {
|
||||
for _, addr := range addrs {
|
||||
ipNet := prefixToIPNet(addr)
|
||||
if err := netlink.AddrAdd(n.link, &netlink.Addr{IPNet: &ipNet}); err != nil {
|
||||
if !errors.Is(err, unix.EEXIST) {
|
||||
return fmt.Errorf("add subnet address to WireGuard link %q: %w", n.link.Attrs().Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the old subnet address if it has changed and remove any other addresses that have been added out of band.
|
||||
// Remove the old addresses or any other addresses that have been added out of band.
|
||||
linkAddrs, err := netlink.AddrList(n.link, netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("list addresses on WireGuard link %q: %w", n.link.Attrs().Name, err)
|
||||
}
|
||||
for _, addr := range linkAddrs {
|
||||
if addr.IPNet.String() == ipSubnet.String() {
|
||||
for _, linkAddr := range linkAddrs {
|
||||
if slices.ContainsFunc(addrs, func(a netip.Prefix) bool {
|
||||
return linkAddr.IPNet.String() == a.String()
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
if err = netlink.AddrDel(n.link, &addr); err != nil {
|
||||
return fmt.Errorf("remove address %q from WireGuard link %q: %w", addr.IPNet, n.link.Attrs().Name, err)
|
||||
if err = netlink.AddrDel(n.link, &linkAddr); err != nil {
|
||||
return fmt.Errorf("remove address %q from WireGuard link %q: %w", linkAddr.IPNet, n.link.Attrs().Name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user