diff --git a/cmd/stdiscosrv/apisrv.go b/cmd/stdiscosrv/apisrv.go index dae695d2..2aa7b5ca 100644 --- a/cmd/stdiscosrv/apisrv.go +++ b/cmd/stdiscosrv/apisrv.go @@ -335,7 +335,21 @@ func fixupAddresses(remote net.IP, addresses []string) []string { } ip := net.ParseIP(host) + + // Some classes of IP are no-go. + if ip.IsLoopback() || ip.IsMulticast() { + continue + } + if host == "" || ip.IsUnspecified() { + // Replace the unspecified IP with the request source. + + // ... unless the request source is the loopback address or + // multicast/unspecified (can't happen, really). + if remote.IsLoopback() || remote.IsMulticast() || remote.IsUnspecified() { + continue + } + // Do not use IPv6 remote address if requested scheme is ...4 // (i.e., tcp4, etc.) if strings.HasSuffix(uri.Scheme, "4") && remote.To4() == nil { diff --git a/cmd/stdiscosrv/apisrv_test.go b/cmd/stdiscosrv/apisrv_test.go new file mode 100644 index 00000000..3323eedd --- /dev/null +++ b/cmd/stdiscosrv/apisrv_test.go @@ -0,0 +1,65 @@ +// Copyright (C) 2018 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +package main + +import ( + "fmt" + "net" + "testing" +) + +func TestFixupAddresses(t *testing.T) { + cases := []struct { + remote net.IP + in []string + out []string + }{ + { // verbatim passthrough + in: []string{"tcp://1.2.3.4:22000"}, + out: []string{"tcp://1.2.3.4:22000"}, + }, { // unspecified replaced by remote + remote: net.ParseIP("1.2.3.4"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://1.2.3.4:22000", "tcp://192.0.2.42:22000"}, + }, { // unspecified not used as replacement + remote: net.ParseIP("0.0.0.0"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, { // unspecified not used as replacement + remote: net.ParseIP("::"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, { // localhost not used as replacement + remote: net.ParseIP("127.0.0.1"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, { // localhost not used as replacement + remote: net.ParseIP("::1"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, { // multicast not used as replacement + remote: net.ParseIP("224.0.0.1"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, { // multicast not used as replacement + remote: net.ParseIP("ff80::42"), + in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, { // explicitly announced weirdness is also filtered + remote: net.ParseIP("192.0.2.42"), + in: []string{"tcp://:22000", "tcp://127.1.2.3:22000", "tcp://[::1]:22000", "tcp://[ff80::42]:22000"}, + out: []string{"tcp://192.0.2.42:22000"}, + }, + } + + for _, tc := range cases { + out := fixupAddresses(tc.remote, tc.in) + if fmt.Sprint(out) != fmt.Sprint(tc.out) { + t.Errorf("fixupAddresses(%v, %v) => %v, expected %v", tc.remote, tc.in, out, tc.out) + } + } +}