Skip to content

Commit

Permalink
GO-3908 localdiscovery: sort ip addresses received from multicast acc…
Browse files Browse the repository at this point in the history
…ording to sorted interfaces
  • Loading branch information
requilence committed Aug 12, 2024
1 parent 3aa2832 commit a579929
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 9 deletions.
96 changes: 92 additions & 4 deletions net/addrs/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,45 @@ type InterfaceAddr struct {
Prefix int
}

type InterfaceWithAddr struct {
net.Interface
cachedAddrs []net.Addr // ipv4 addresses
cachedErr error
}
type InterfacesAddrs struct {
Interfaces []net.Interface
Addrs []net.Addr
Interfaces []InterfaceWithAddr
Addrs []net.Addr // addrs without attachment to specific interface. Used as a fallback mechanism
}

func WrapInterfaces(ifaces []net.Interface) []InterfaceWithAddr {
var m = make([]InterfaceWithAddr, 0, len(ifaces))
for i := range ifaces {
m = append(m, InterfaceWithAddr{
Interface: ifaces[i],
})
}
return m
}

// GetAddr returns ipv4 only addresses for interface or cached one if set
func (i InterfaceWithAddr) GetAddr() []net.Addr {
if i.cachedAddrs != nil {
return i.cachedAddrs
}
if i.cachedErr != nil {
return nil
}
i.cachedAddrs, i.cachedErr = i.Addrs()
// filter-out ipv6
i.cachedAddrs = slice.Filter(i.cachedAddrs, func(addr net.Addr) bool {
if ip, ok := addr.(*net.IPNet); ok {
if ip.IP.To4() == nil {
return false
}
}
return true
})
return i.cachedAddrs
}

func (i InterfacesAddrs) Equal(other InterfacesAddrs) bool {
Expand Down Expand Up @@ -71,7 +107,7 @@ func parseInterfaceName(name string) (prefix string, bus int, num int64) {
}

func (i InterfacesAddrs) SortWithPriority(priority []string) {
less := func(a, b net.Interface) bool {
less := func(a, b InterfaceWithAddr) bool {
aPrefix, aBus, aNum := parseInterfaceName(a.Name)
bPrefix, bBus, bNum := parseInterfaceName(b.Name)

Expand Down Expand Up @@ -100,14 +136,22 @@ func (i InterfacesAddrs) SortWithPriority(priority []string) {
return false
}
}
slices.SortFunc(i.Interfaces, func(a, b net.Interface) int {
slices.SortFunc(i.Interfaces, func(a, b InterfaceWithAddr) int {
if less(a, b) {
return -1
}
return 1
})
}

func (i InterfacesAddrs) NetInterfaces() []net.Interface {
var s = make([]net.Interface, 0, len(i.Interfaces))
for _, iface := range i.Interfaces {
s = append(s, iface.Interface)
}
return s
}

func getStrings(i InterfacesAddrs) (allStrings []string) {
for _, i := range i.Interfaces {
allStrings = append(allStrings, i.Name)
Expand All @@ -118,3 +162,47 @@ func getStrings(i InterfacesAddrs) (allStrings []string) {
slices.Sort(allStrings)
return
}

func (i InterfacesAddrs) GetInterfaceByAddr(addr net.Addr) (net.Interface, bool) {
for _, iface := range i.Interfaces {
for _, addrInIface := range iface.GetAddr() {
if addr.String() == addrInIface.String() {
return iface.Interface, true
}
}
}
return net.Interface{}, false
}

func (i InterfacesAddrs) SortIPsLikeInterfaces(ips []net.IP) {
slices.SortFunc(ips, func(a, b net.IP) int {
pa, _ := i.findInterfacePosByIP(a)
pb, _ := i.findInterfacePosByIP(b)

if pa == -1 && pb != -1 {
return 1
}
if pa != -1 && pb == -1 {
return -1
}
if pa < pb {
return -1
} else if pa > pb {
return 1
}
return 0
})
}

func (i InterfacesAddrs) findInterfacePosByIP(ip net.IP) (pos int, equal bool) {
for position, iface := range i.Interfaces {
for _, addr := range iface.GetAddr() {
if ni, ok := addr.(*net.IPNet); ok {
if ni.Contains(ip) {
return position, ni.IP.Equal(ip)
}
}
}
}
return -1, false
}
4 changes: 2 additions & 2 deletions net/addrs/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ func GetInterfacesAddrs() (iAddrs InterfacesAddrs, err error) {
if err != nil {
return
}
iAddrs.Interfaces = ifaces
iAddrs.Interfaces = WrapInterfaces(ifaces)

iAddrs.Interfaces = slice.Filter(iAddrs.Interfaces, func(iface net.Interface) bool {
iAddrs.Interfaces = slice.Filter(iAddrs.Interfaces, func(iface InterfaceWithAddr) bool {
return iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagMulticast != 0
})
return
Expand Down
7 changes: 4 additions & 3 deletions space/spacecore/localdiscovery/localdiscovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (l *localDiscovery) startServer() (err error) {
l.peerId,
l.ipv4, // do not include ipv6 addresses, because they are disabled
nil,
l.interfacesAddrs.Interfaces,
l.interfacesAddrs.NetInterfaces(),
zeroconf.TTL(60),
zeroconf.ServerSelectIPTraffic(zeroconf.IPv4), // disable ipv6 for now
zeroconf.WriteTimeout(time.Second*1),
Expand All @@ -223,6 +223,7 @@ func (l *localDiscovery) readAnswers(ch chan *zeroconf.ServiceEntry) {
continue
}
var portAddrs []string
l.interfacesAddrs.SortIPsLikeInterfaces(entry.AddrIPv4)
for _, a := range entry.AddrIPv4 {
portAddrs = append(portAddrs, fmt.Sprintf("%s:%d", a.String(), entry.Port))
}
Expand Down Expand Up @@ -251,7 +252,7 @@ func (l *localDiscovery) browse(ctx context.Context, ch chan *zeroconf.ServiceEn
newAddrs.SortWithPriority(interfacesSortPriority)
if err := zeroconf.Browse(ctx, serviceName, mdnsDomain, ch,
zeroconf.ClientWriteTimeout(time.Second*1),
zeroconf.SelectIfaces(newAddrs.Interfaces),
zeroconf.SelectIfaces(newAddrs.NetInterfaces()),
zeroconf.SelectIPTraffic(zeroconf.IPv4)); err != nil {
log.Error("browsing failed", zap.Error(err))
}
Expand All @@ -266,7 +267,7 @@ func (l *localDiscovery) notifyPeerToPeerStatus(newAddrs addrs.InterfacesAddrs)
}

func (l *localDiscovery) notifyP2PNotPossible(newAddrs addrs.InterfacesAddrs) bool {
return len(newAddrs.Interfaces) == 0 || addrs.IsLoopBack(newAddrs.Interfaces)
return len(newAddrs.Interfaces) == 0 || addrs.IsLoopBack(newAddrs.NetInterfaces())
}

func (l *localDiscovery) executeHook(hook Hook) {
Expand Down

0 comments on commit a579929

Please sign in to comment.