mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-26 03:25:35 +00:00
wgengine/router: windows: set SkipAsSource on IPv6 LL addresses
Link-local addresses on the Tailscale interface are not routable. Ideally they would be removed, however, a concern exists that the operating system will attempt to re-add them which would lead to thrashing. Setting SkipAsSource attempts to avoid production of packets using the address as a source in any default behaviors. Before, in powershell: `ping (hostname)` would ping the link-local address of the Tailscale interface, and fail. After: `ping (hostname)` now pings the link-local address on the next highest priority metric local interface. Fixes #4647 Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
parent
8c5c87be26
commit
76256d22d8
@ -574,26 +574,8 @@ func deltaNets(a, b []*net.IPNet) (add, del []*net.IPNet) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func excludeIPv6LinkLocal(in []*net.IPNet) (out []*net.IPNet) {
|
func isIPv6LinkLocal(in *net.IPNet) bool {
|
||||||
out = in[:0]
|
return len(in.IP) == 16 && in.IP.IsLinkLocalUnicast()
|
||||||
for _, n := range in {
|
|
||||||
if len(n.IP) == 16 && n.IP.IsLinkLocalUnicast() {
|
|
||||||
// Windows creates a fixed link-local address for wintun,
|
|
||||||
// which doesn't seem to route correctly. Unfortunately, LLMNR returns this
|
|
||||||
// address for lookups by the hostname, and Windows prefers using it.
|
|
||||||
// This means that local traffic addressed to the machine's hostname breaks.
|
|
||||||
//
|
|
||||||
// While we otherwise preserve link-local addresses, we delete
|
|
||||||
// this one to force lookups to use a working address.
|
|
||||||
//
|
|
||||||
// See: https://github.com/tailscale/tailscale/issues/4647
|
|
||||||
if ip, ok := netaddr.FromStdIP(n.IP); !ok || wintunLinkLocal != ip {
|
|
||||||
continue // filter this IPNet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out = append(out, n)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ipAdapterUnicastAddressToIPNet converts windows.IpAdapterUnicastAddress to net.IPNet.
|
// ipAdapterUnicastAddressToIPNet converts windows.IpAdapterUnicastAddress to net.IPNet.
|
||||||
@ -622,14 +604,27 @@ func unicastIPNets(ifc *winipcfg.IPAdapterAddresses) []*net.IPNet {
|
|||||||
// doing the minimum number of AddAddresses & DeleteAddress calls.
|
// doing the minimum number of AddAddresses & DeleteAddress calls.
|
||||||
// This avoids the full FlushAddresses.
|
// This avoids the full FlushAddresses.
|
||||||
//
|
//
|
||||||
// Any IPv6 link-local addresses are not deleted.
|
// Any IPv6 link-local addresses are not deleted out of caution as some
|
||||||
|
// configurations may repeatedly re-add them. Link-local addresses are adjusted
|
||||||
|
// to set SkipAsSource. SkipAsSource prevents the addresses from being addded to
|
||||||
|
// DNS locally or remotely and from being picked as a source address for
|
||||||
|
// outgoing packets with unspecified sources. See #4647 and
|
||||||
|
// https://web.archive.org/web/20200912120956/https://devblogs.microsoft.com/scripting/use-powershell-to-change-ip-behavior-with-skipassource/
|
||||||
func syncAddresses(ifc *winipcfg.IPAdapterAddresses, want []*net.IPNet) error {
|
func syncAddresses(ifc *winipcfg.IPAdapterAddresses, want []*net.IPNet) error {
|
||||||
var erracc error
|
var erracc error
|
||||||
|
|
||||||
got := unicastIPNets(ifc)
|
got := unicastIPNets(ifc)
|
||||||
add, del := deltaNets(got, want)
|
add, del := deltaNets(got, want)
|
||||||
del = excludeIPv6LinkLocal(del)
|
|
||||||
|
ll := make([]*net.IPNet, 0)
|
||||||
for _, a := range del {
|
for _, a := range del {
|
||||||
|
// do not delete link-local addresses, and collect them for later
|
||||||
|
// applying SkipAsSource.
|
||||||
|
if isIPv6LinkLocal(a) {
|
||||||
|
ll = append(ll, a)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
err := ifc.LUID.DeleteIPAddress(*a)
|
err := ifc.LUID.DeleteIPAddress(*a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
erracc = fmt.Errorf("deleting IP %q: %w", *a, err)
|
erracc = fmt.Errorf("deleting IP %q: %w", *a, err)
|
||||||
@ -643,6 +638,20 @@ func syncAddresses(ifc *winipcfg.IPAdapterAddresses, want []*net.IPNet) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, a := range ll {
|
||||||
|
mib, err := ifc.LUID.IPAddress(a.IP)
|
||||||
|
if err != nil {
|
||||||
|
erracc = fmt.Errorf("setting skip-as-source on IP %q: unable to retrieve MIB: %w", *a, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !mib.SkipAsSource {
|
||||||
|
mib.SkipAsSource = true
|
||||||
|
if err := mib.Set(); err != nil {
|
||||||
|
erracc = fmt.Errorf("setting skip-as-source on IP %q: unable to set MIB: %w", *a, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return erracc
|
return erracc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,11 +163,6 @@ func TestDeltaNets(t *testing.T) {
|
|||||||
b: nets("100.84.36.11/32[4]"),
|
b: nets("100.84.36.11/32[4]"),
|
||||||
wantDel: nets("fe80::99d0:ec2d:b2e7:536b/64"),
|
wantDel: nets("fe80::99d0:ec2d:b2e7:536b/64"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
a: excludeIPv6LinkLocal(nets("100.84.36.11/32", "fe80::99d0:ec2d:b2e7:536b/64")),
|
|
||||||
b: nets("100.84.36.11/32"),
|
|
||||||
wantDel: nets("fe80::99d0:ec2d:b2e7:536b/64"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
a: []*net.IPNet{
|
a: []*net.IPNet{
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user