mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-27 09:09:00 +01:00
be0c5c887c
Fix outdated update coming from management even when it is actually not outdated.
114 lines
2.9 KiB
Go
114 lines
2.9 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"github.com/rs/xid"
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
var (
|
|
upperIPv4 = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 255, 255, 255, 255}
|
|
upperIPv6 = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
|
)
|
|
|
|
type NetworkMap struct {
|
|
Peers []*Peer
|
|
Network *Network
|
|
}
|
|
|
|
type Network struct {
|
|
Id string
|
|
Net net.IPNet
|
|
Dns string
|
|
// Serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
|
|
// Used to synchronize state to the client apps.
|
|
Serial uint64
|
|
|
|
mu sync.Mutex `json:"-"`
|
|
}
|
|
|
|
// NewNetwork creates a new Network initializing it with a Serial=0
|
|
func NewNetwork() *Network {
|
|
return &Network{
|
|
Id: xid.New().String(),
|
|
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
|
|
Dns: "",
|
|
Serial: 0}
|
|
}
|
|
|
|
// IncSerial increments Serial by 1 reflecting that the network state has been changed
|
|
func (n *Network) IncSerial() {
|
|
n.mu.Lock()
|
|
defer n.mu.Unlock()
|
|
n.Serial = n.Serial + 1
|
|
}
|
|
|
|
// CurrentSerial returns the Network.Serial of the network (latest state id)
|
|
func (n *Network) CurrentSerial() uint64 {
|
|
n.mu.Lock()
|
|
defer n.mu.Unlock()
|
|
return n.Serial
|
|
}
|
|
|
|
func (n *Network) Copy() *Network {
|
|
return &Network{
|
|
Id: n.Id,
|
|
Net: n.Net,
|
|
Dns: n.Dns,
|
|
Serial: n.Serial,
|
|
}
|
|
}
|
|
|
|
// AllocatePeerIP pics an available IP from an net.IPNet.
|
|
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps
|
|
// E.g. if ipNet=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.5] then the result would be 100.30.0.2
|
|
func AllocatePeerIP(ipNet net.IPNet, takenIps []net.IP) (net.IP, error) {
|
|
takenIpMap := make(map[string]net.IP)
|
|
takenIpMap[ipNet.IP.String()] = ipNet.IP
|
|
for _, ip := range takenIps {
|
|
takenIpMap[ip.String()] = ip
|
|
}
|
|
for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); ip = GetNextIP(ip) {
|
|
if _, ok := takenIpMap[ip.String()]; !ok {
|
|
return ip, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("failed allocating new IP for the ipNet %s and takenIps %s", ipNet.String(), takenIps)
|
|
}
|
|
|
|
// GetNextIP returns the next IP from the given IP address. If the given IP is
|
|
// the last IP of a v4 or v6 range, the same IP is returned.
|
|
// Credits to Cilium team.
|
|
// Copyright 2017-2020 Authors of Cilium
|
|
func GetNextIP(ip net.IP) net.IP {
|
|
if ip.Equal(upperIPv4) || ip.Equal(upperIPv6) {
|
|
return ip
|
|
}
|
|
|
|
nextIP := make(net.IP, len(ip))
|
|
switch len(ip) {
|
|
case net.IPv4len:
|
|
ipU32 := binary.BigEndian.Uint32(ip)
|
|
ipU32++
|
|
binary.BigEndian.PutUint32(nextIP, ipU32)
|
|
return nextIP
|
|
case net.IPv6len:
|
|
ipU64 := binary.BigEndian.Uint64(ip[net.IPv6len/2:])
|
|
ipU64++
|
|
binary.BigEndian.PutUint64(nextIP[net.IPv6len/2:], ipU64)
|
|
if ipU64 == 0 {
|
|
ipU64 = binary.BigEndian.Uint64(ip[:net.IPv6len/2])
|
|
ipU64++
|
|
binary.BigEndian.PutUint64(nextIP[:net.IPv6len/2], ipU64)
|
|
} else {
|
|
copy(nextIP[:net.IPv6len/2], ip[:net.IPv6len/2])
|
|
}
|
|
return nextIP
|
|
default:
|
|
return ip
|
|
}
|
|
}
|