mirror of
https://github.com/tailscale/tailscale.git
synced 2026-02-07 14:32:32 -05:00
wf: allow limited broadcast to/from permitted interfaces when using an exit node on Windows
Similarly to allowing link-local multicast in #13661, we should also allow broadcast traffic on permitted interfaces when the killswitch is enabled due to exit node usage on Windows. This always includes internal interfaces, such as Hyper-V/WSL2, and also the LAN when "Allow local network access" is enabled in the client. Updates #18504 Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
@@ -18,3 +18,6 @@ reference to an issue or PR about the feature.
|
||||
When the option is disabled, we should still permit it for internal interfaces,
|
||||
such as Hyper-V/WSL2 on Windows.
|
||||
|
||||
- Inbound and outbound broadcasts 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 traffic on internal interfaces, such as Hyper-V/WSL2 on Windows.
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
linkLocalMulticastIPv4Range = netip.MustParsePrefix("224.0.0.0/24")
|
||||
linkLocalMulticastIPv6Range = netip.MustParsePrefix("ff02::/16")
|
||||
|
||||
limitedBroadcast = netip.MustParsePrefix("255.255.255.255/32")
|
||||
)
|
||||
|
||||
type direction int
|
||||
@@ -233,26 +235,41 @@ func (f *Firewall) UpdatePermittedRoutes(newRoutes []netip.Prefix) error {
|
||||
return err
|
||||
}
|
||||
|
||||
name = "link-local multicast - " + r.String()
|
||||
conditions = matchLinkLocalMulticast(r, false)
|
||||
multicastRules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionOutbound)
|
||||
multicastRules, err := f.addLinkLocalMulticastRules(p, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rules = append(rules, multicastRules...)
|
||||
|
||||
conditions = matchLinkLocalMulticast(r, true)
|
||||
multicastRules, err = f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionInbound)
|
||||
broadcastRules, err := f.addLimitedBroadcastRules(p, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rules = append(rules, multicastRules...)
|
||||
rules = append(rules, broadcastRules...)
|
||||
|
||||
f.permittedRoutes[r] = rules
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addLinkLocalMulticastRules adds rules to allow inbound and outbound
|
||||
// link-local multicast traffic to or from the specified network.
|
||||
// It returns the added rules, or an error.
|
||||
func (f *Firewall) addLinkLocalMulticastRules(p protocol, r netip.Prefix) ([]*wf.Rule, error) {
|
||||
name := "link-local multicast - " + r.String()
|
||||
conditions := matchLinkLocalMulticast(r, false)
|
||||
outboundRules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionOutbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conditions = matchLinkLocalMulticast(r, true)
|
||||
inboundRules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionInbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(outboundRules, inboundRules...), nil
|
||||
}
|
||||
|
||||
// matchLinkLocalMulticast returns a list of conditions that match
|
||||
// outbound or inbound link-local multicast traffic to or from the
|
||||
// specified network.
|
||||
@@ -288,6 +305,59 @@ func matchLinkLocalMulticast(pfx netip.Prefix, inbound bool) []*wf.Match {
|
||||
}
|
||||
}
|
||||
|
||||
// addLimitedBroadcastRules adds rules to allow inbound and outbound
|
||||
// limited broadcast traffic to or from the specified network,
|
||||
// if the network is IPv4. It returns the added rules, or an error.
|
||||
func (f *Firewall) addLimitedBroadcastRules(p protocol, r netip.Prefix) ([]*wf.Rule, error) {
|
||||
if !r.Addr().Is4() {
|
||||
return nil, nil
|
||||
}
|
||||
name := "broadcast - " + r.String()
|
||||
conditions := matchLimitedBroadcast(r, false)
|
||||
outboundRules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionOutbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conditions = matchLimitedBroadcast(r, true)
|
||||
inboundRules, err := f.addRules(name, weightKnownTraffic, conditions, wf.ActionPermit, p, directionInbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(outboundRules, inboundRules...), nil
|
||||
}
|
||||
|
||||
// matchLimitedBroadcast returns a list of conditions that match
|
||||
// outbound or inbound limited broadcast traffic to or from the
|
||||
// specified network. It panics if the pfx is not IPv4.
|
||||
func matchLimitedBroadcast(pfx netip.Prefix, inbound bool) []*wf.Match {
|
||||
if !pfx.Addr().Is4() {
|
||||
panic("limited broadcast is only applicable to IPv4")
|
||||
}
|
||||
var localAddr, remoteAddr netip.Prefix
|
||||
if inbound {
|
||||
localAddr, remoteAddr = limitedBroadcast, pfx
|
||||
} else {
|
||||
localAddr, remoteAddr = pfx, limitedBroadcast
|
||||
}
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user