-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xcode: allow ICMP ping relay on macOS + iOS platforms
Fixes #10393 Fixes tailscale/corp#15412 Fixes tailscale/corp#19808 On Apple platforms, exit nodes and subnet routers have been unable to relay pings from Tailscale devices to non-Tailscale devices due to sandbox restrictions imposed on our network extensions by Apple. The sandbox prevented the code in netstack.go from spawning the `ping` process which we were using. Replace that exec call with logic to send an ICMP echo request directly, which appears to work in userspace, and not trigger a sandbox violation in the syslog. Signed-off-by: Andrea Gottardo <andrea@gottardo.me>
- Loading branch information
Showing
6 changed files
with
113 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright (c) Tailscale Inc & AUTHORS | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
//go:build !darwin && !ios | ||
|
||
package netstack | ||
|
||
import ( | ||
"net/netip" | ||
"os" | ||
"os/exec" | ||
"runtime" | ||
"time" | ||
|
||
"tailscale.com/version/distro" | ||
) | ||
|
||
// setAmbientCapsRaw is non-nil on Linux for Synology, to run ping with | ||
// CAP_NET_RAW from tailscaled's binary. | ||
var setAmbientCapsRaw func(*exec.Cmd) | ||
|
||
var isSynology = runtime.GOOS == "linux" && distro.Get() == distro.Synology | ||
|
||
// sendOutboundUserPing sends a non-privileged ICMP (or ICMPv6) ping to dstIP with the given timeout. | ||
func (ns *Impl) sendOutboundUserPing(dstIP netip.Addr, timeout time.Duration) error { | ||
var err error | ||
switch runtime.GOOS { | ||
case "windows": | ||
err = exec.Command("ping", "-n", "1", "-w", "3000", dstIP.String()).Run() | ||
case "freebsd": | ||
// Note: 2000 ms is actually 1 second + 2,000 | ||
// milliseconds extra for 3 seconds total. | ||
// See https://github.com/tailscale/tailscale/pull/3753 for details. | ||
ping := "ping" | ||
if dstIP.Is6() { | ||
ping = "ping6" | ||
} | ||
err = exec.Command(ping, "-c", "1", "-W", "2000", dstIP.String()).Run() | ||
case "openbsd": | ||
ping := "ping" | ||
if dstIP.Is6() { | ||
ping = "ping6" | ||
} | ||
err = exec.Command(ping, "-c", "1", "-w", "3", dstIP.String()).Run() | ||
case "android": | ||
ping := "/system/bin/ping" | ||
if dstIP.Is6() { | ||
ping = "/system/bin/ping6" | ||
} | ||
err = exec.Command(ping, "-c", "1", "-w", "3", dstIP.String()).Run() | ||
default: | ||
ping := "ping" | ||
if isSynology { | ||
ping = "/bin/ping" | ||
} | ||
cmd := exec.Command(ping, "-c", "1", "-W", "3", dstIP.String()) | ||
if isSynology && os.Getuid() != 0 { | ||
// On DSM7 we run as non-root and need to pass | ||
// CAP_NET_RAW if our binary has it. | ||
setAmbientCapsRaw(cmd) | ||
} | ||
err = cmd.Run() | ||
} | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) Tailscale Inc & AUTHORS | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
//go:build darwin || ios | ||
|
||
package netstack | ||
|
||
import ( | ||
"github.com/prometheus-community/pro-bing" | ||
"net/netip" | ||
"time" | ||
) | ||
|
||
// sendOutboundUserPing sends a non-privileged ICMP (or ICMPv6) ping to dstIP with the given timeout. | ||
func (ns *Impl) sendOutboundUserPing(dstIP netip.Addr, timeout time.Duration) error { | ||
p, err := probing.NewPinger(dstIP.String()) | ||
if err != nil { | ||
ns.logf("sendICMPPingToIP failed to create pinger: %v", err) | ||
return err | ||
} | ||
|
||
p.Timeout = timeout | ||
p.Count = 1 | ||
p.SetPrivileged(false) | ||
|
||
p.OnSend = func(pkt *probing.Packet) { | ||
ns.logf("sendICMPPingToIP: forwarding ping to %s:", p.Addr()) | ||
} | ||
p.OnRecv = func(pkt *probing.Packet) { | ||
ns.logf("sendICMPPingToIP: %d bytes pong from %s: icmp_seq=%d time=%v", pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt) | ||
} | ||
p.OnFinish = func(stats *probing.Statistics) { | ||
ns.logf("sendICMPPingToIP: done, %d replies received", stats.PacketsRecv) | ||
} | ||
|
||
return p.Run() | ||
} |