mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-28 20:45:34 +00:00
wf/firewall: allow link-local multicast for permitted local routes when the killswitch is on on Windows
When an Exit Node is used, we create a WFP rule to block all inbound and outbound traffic, along with several rules to permit specific types of traffic. Notably, we allow all inbound and outbound traffic to and from LocalRoutes specified in wgengine/router.Config. The list of allowed routes always includes routes for internal interfaces, such as loopback and virtual Hyper-V/WSL2 interfaces, and may also include LAN routes if the "Allow local network access" option is enabled. However, these permitting rules do not allow link-local multicast on the corresponding interfaces. This results in broken mDNS/LLMNR, and potentially other similar issues, whenever an exit node is used. In this PR, we update (*wf.Firewall).UpdatePermittedRoutes() to create rules allowing outbound and inbound link-local multicast traffic to and from the permitted IP ranges, partially resolving the mDNS/LLMNR and *.local name resolution issue. Since Windows does not attempt to send mDNS/LLMNR queries if a catch-all NRPT rule is present, it is still necessary to disable the creation of that rule using the disable-local-dns-override-via-nrpt nodeAttr. Updates #13571 Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
parent
b8af93310a
commit
d837e0252f
@ -13,5 +13,8 @@ reference to an issue or PR about the feature.
|
||||
|
||||
# The list
|
||||
|
||||
- ...
|
||||
- Link-local multicast, and mDNS/LLMNR specifically, when an exit node is used,
|
||||
both with and without the "Allow local network access" option enabled.
|
||||
When the option is disabled, we should still permit it for internal interfaces,
|
||||
such as Hyper-V/WSL2 on Windows.
|
||||
|
||||
|
@ -22,6 +22,9 @@
|
||||
linkLocalDHCPMulticast = netip.MustParseAddr("ff02::1:2")
|
||||
siteLocalDHCPMulticast = netip.MustParseAddr("ff05::1:3")
|
||||
linkLocalRouterMulticast = netip.MustParseAddr("ff02::2")
|
||||
|
||||
linkLocalMulticastIPv4Range = netip.MustParsePrefix("224.0.0.0/24")
|
||||
linkLocalMulticastIPv6Range = netip.MustParsePrefix("ff02::/16")
|
||||
)
|
||||
|
||||
type direction int
|
||||
@ -224,15 +227,67 @@ func (f *Firewall) UpdatePermittedRoutes(newRoutes []netip.Prefix) error {
|
||||
} else {
|
||||
p = protocolV6
|
||||
}
|
||||
rules, err := f.addRules("local route", weightKnownTraffic, conditions, wf.ActionPermit, p, directionBoth)
|
||||
name := "local route - " + r.String()
|
||||
rules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionBoth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = "link-local multicast - " + r.String()
|
||||
conditions = matchLinkLocalMulticast(r, false)
|
||||
multicastRules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionOutbound)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rules = append(rules, multicastRules...)
|
||||
|
||||
conditions = matchLinkLocalMulticast(r, true)
|
||||
multicastRules, err = f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionInbound)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rules = append(rules, multicastRules...)
|
||||
|
||||
f.permittedRoutes[r] = rules
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// matchLinkLocalMulticast returns a list of conditions that match
|
||||
// outbound or inbound link-local multicast traffic to or from the
|
||||
// specified network.
|
||||
func matchLinkLocalMulticast(pfx netip.Prefix, inbound bool) []*wf.Match {
|
||||
var linkLocalMulticastRange netip.Prefix
|
||||
if pfx.Addr().Is4() {
|
||||
linkLocalMulticastRange = linkLocalMulticastIPv4Range
|
||||
} else {
|
||||
linkLocalMulticastRange = linkLocalMulticastIPv6Range
|
||||
}
|
||||
var localAddr, remoteAddr netip.Prefix
|
||||
if inbound {
|
||||
localAddr, remoteAddr = linkLocalMulticastRange, pfx
|
||||
} else {
|
||||
localAddr, remoteAddr = pfx, linkLocalMulticastRange
|
||||
}
|
||||
return []*wf.Match{
|
||||
{
|
||||
Field: wf.FieldIPProtocol,
|
||||
Op: wf.MatchTypeEqual,
|
||||
Value: wf.IPProtoUDP,
|
||||
},
|
||||
{
|
||||
Field: wf.FieldIPLocalAddress,
|
||||
Op: wf.MatchTypeEqual,
|
||||
Value: localAddr,
|
||||
},
|
||||
{
|
||||
Field: wf.FieldIPRemoteAddress,
|
||||
Op: wf.MatchTypeEqual,
|
||||
Value: remoteAddr,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Firewall) newRule(name string, w weight, layer wf.LayerID, conditions []*wf.Match, action wf.Action) (*wf.Rule, error) {
|
||||
id, err := windows.GenerateGUID()
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user