net/tsdial: partially fix "tailscale nc" (UserDial) on macOS

At least in the case of dialing a Tailscale IP.

Updates #4529

Change-Id: I9fd667d088a14aec4a56e23aabc2b1ffddafa3fe
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-04-07 14:25:11 -07:00 committed by Brad Fitzpatrick
parent a5e1f7d703
commit b0fbd85592
3 changed files with 25 additions and 8 deletions

View File

@ -106,10 +106,8 @@ func runSSH(ctx context.Context, args []string) error {
"-o", "CanonicalizeHostname no", // https://github.com/tailscale/tailscale/issues/10348 "-o", "CanonicalizeHostname no", // https://github.com/tailscale/tailscale/issues/10348
) )
// TODO(bradfitz): nc is currently broken on macOS: // MagicDNS is usually working on macOS anyway and they're not in userspace
// https://github.com/tailscale/tailscale/issues/4529 // mode, so 'nc' isn't very useful.
// So don't use it for now. MagicDNS is usually working on macOS anyway
// and they're not in userspace mode, so 'nc' isn't very useful.
if runtime.GOOS != "darwin" { if runtime.GOOS != "darwin" {
socketArg := "" socketArg := ""
if rootArgs.socket != "" && rootArgs.socket != paths.DefaultTailscaledSocket() { if rootArgs.socket != "" && rootArgs.socket != paths.DefaultTailscaledSocket() {

View File

@ -21,10 +21,12 @@
"tailscale.com/net/netknob" "tailscale.com/net/netknob"
"tailscale.com/net/netmon" "tailscale.com/net/netmon"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/tsaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/util/clientmetric" "tailscale.com/util/clientmetric"
"tailscale.com/util/mak" "tailscale.com/util/mak"
"tailscale.com/version"
) )
// Dialer dials out of tailscaled, while taking care of details while // Dialer dials out of tailscaled, while taking care of details while
@ -337,6 +339,14 @@ func (d *Dialer) UserDial(ctx context.Context, network, addr string) (net.Conn,
} }
return d.NetstackDialTCP(ctx, ipp) return d.NetstackDialTCP(ctx, ipp)
} }
// Workaround for macOS for now: dial Tailscale IPs with peer dialer.
// TODO(bradfitz): fix dialing subnet routers, public IPs via exit nodes,
// etc. This is a temporary partial for macOS. We need to plumb ART tables &
// prefs & host routing table updates around in more places. We just don't
// know from the limited context here how to dial properly.
if version.IsMacGUIVariant() && tsaddr.IsTailscaleIP(ipp.Addr()) {
return d.getPeerDialer().DialContext(ctx, network, ipp.String())
}
// TODO(bradfitz): netns, etc // TODO(bradfitz): netns, etc
var stdDialer net.Dialer var stdDialer net.Dialer
return stdDialer.DialContext(ctx, network, ipp.String()) return stdDialer.DialContext(ctx, network, ipp.String())
@ -365,14 +375,14 @@ func (d *Dialer) dialPeerAPI(ctx context.Context, network, addr string) (net.Con
return d.getPeerDialer().DialContext(ctx, network, addr) return d.getPeerDialer().DialContext(ctx, network, addr)
} }
// getPeerDialer returns the *net.Dialer to use to dial peers to use // getPeerDialer returns the *net.Dialer to use to dial peers (e.g. for peerapi,
// PeerAPI. // or "tailscale nc")
// //
// This is not used in netstack mode. // This is not used in netstack mode.
// //
// The primary function of this is to work on macOS & iOS's in the // The primary function of this is to work on macOS & iOS's in the
// Network/System Extension so it can mark the dialer as staying // Network/System Extension so it can mark the dialer as staying within the
// within the network namespace/sandbox. // network namespace/sandbox.
func (d *Dialer) getPeerDialer() *net.Dialer { func (d *Dialer) getPeerDialer() *net.Dialer {
d.peerDialerOnce.Do(func() { d.peerDialerOnce.Do(func() {
d.peerDialer = &net.Dialer{ d.peerDialer = &net.Dialer{

View File

@ -40,6 +40,15 @@ func OS() string {
return runtime.GOOS return runtime.GOOS
} }
// IsMacGUIVariant reports whether runtime.GOOS=="darwin" and this one of the
// two GUI variants (that is, not tailscaled-on-macOS).
// This predicate should not be used to determine sandboxing properties. It's
// meant for callers to determine whether the NetworkExtension-like auto-netns
// is in effect.
func IsMacGUIVariant() bool {
return IsMacAppStore() || IsMacSysExt()
}
// IsSandboxedMacOS reports whether this process is a sandboxed macOS // IsSandboxedMacOS reports whether this process is a sandboxed macOS
// process (either the app or the extension). It is true for the Mac App Store // process (either the app or the extension). It is true for the Mac App Store
// and macsys (System Extension) version on macOS, and false for // and macsys (System Extension) version on macOS, and false for