lib/discover: Filter locally announced addresses (fixes #7289) (#8302)

This commit is contained in:
Jakob Borg 2022-05-04 18:43:00 +02:00 committed by GitHub
parent 16c0c2f7a7
commit f8c51d801a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 0 deletions

View File

@ -109,6 +109,13 @@ func (c *localClient) Error() error {
// send. // send.
func (c *localClient) announcementPkt(instanceID int64, msg []byte) ([]byte, bool) { func (c *localClient) announcementPkt(instanceID int64, msg []byte) ([]byte, bool) {
addrs := c.addrList.AllAddresses() addrs := c.addrList.AllAddresses()
// The list of all addresses can include unspecified addresses intended
// for a discovery server to complete, based on the packet source. We
// don't do that for local discovery, so filter out addresses that are
// usable as-is.
addrs = filterUnspecifiedLocal(addrs)
if len(addrs) == 0 { if len(addrs) == 0 {
// Nothing to announce // Nothing to announce
return msg, false return msg, false
@ -281,3 +288,30 @@ func (c *localClient) registerDevice(src net.Addr, device Announce) bool {
return isNewDevice return isNewDevice
} }
// filterUnspecifiedLocal returns the list of addresses after removing any
// unspecified, localhost, multicast, broadcast or port-zero addresses.
func filterUnspecifiedLocal(addrs []string) []string {
filtered := addrs[:0]
for _, addr := range addrs {
u, err := url.Parse(addr)
if err != nil {
continue
}
tcpAddr, err := net.ResolveTCPAddr("tcp", u.Host)
if err != nil {
continue
}
switch {
case len(tcpAddr.IP) == 0:
case tcpAddr.Port == 0:
case tcpAddr.IP.IsUnspecified():
case !tcpAddr.IP.IsGlobalUnicast() && !tcpAddr.IP.IsLinkLocalUnicast():
default:
filtered = append(filtered, addr)
}
}
return filtered
}

View File

@ -9,6 +9,7 @@ package discover
import ( import (
"bytes" "bytes"
"context" "context"
"fmt"
"net" "net"
"testing" "testing"
@ -89,3 +90,33 @@ func TestLocalInstanceIDShouldTriggerNew(t *testing.T) {
t.Fatal("new instance ID should be new") t.Fatal("new instance ID should be new")
} }
} }
func TestFilterUnspecified(t *testing.T) {
addrs := []string{
"quic://[2001:db8::1]:22000", // OK
"tcp://192.0.2.42:22000", // OK
"quic://[2001:db8::1]:0", // remove, port zero
"tcp://192.0.2.42:0", // remove, port zero
"quic://[::]:22000", // remove, unspecified
"tcp://0.0.0.0:22000", // remove, unspecified
"tcp://[2001:db8::1]", // remove, no port
"tcp://192.0.2.42", // remove, no port
"tcp://foo:bar", // remove, host/port does not resolve
"tcp://127.0.0.1:22000", // remove, not usable from outside
"tcp://[::1]:22000", // remove, not usable from outside
"tcp://224.1.2.3:22000", // remove, not usable from outside (multicast)
"tcp://[fe80::9ef:dff1:b332:5e56]:55681", // OK
"pure garbage", // remove, garbage
"", // remove, garbage
}
exp := []string{
"quic://[2001:db8::1]:22000",
"tcp://192.0.2.42:22000",
"tcp://[fe80::9ef:dff1:b332:5e56]:55681",
}
res := filterUnspecifiedLocal(addrs)
if fmt.Sprint(res) != fmt.Sprint(exp) {
t.Log(res)
t.Error("filterUnspecified returned invalid addresses")
}
}