mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-14 23:17:29 +00:00
xcode: allow ICMP ping relay on macOS + iOS platforms (#12048)
Fixes tailscale/tailscale#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>
This commit is contained in:
@@ -15,8 +15,6 @@ import (
|
||||
"math"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -55,7 +53,6 @@ import (
|
||||
"tailscale.com/types/nettype"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/version"
|
||||
"tailscale.com/version/distro"
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/magicsock"
|
||||
@@ -916,14 +913,8 @@ func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 userPingSem = syncs.NewSemaphore(20) // 20 child ping processes at once
|
||||
|
||||
var isSynology = runtime.GOOS == "linux" && distro.Get() == distro.Synology
|
||||
|
||||
type userPingDirection int
|
||||
|
||||
const (
|
||||
@@ -944,6 +935,8 @@ const (
|
||||
// it bounds the number of pings going on at once. The idea is that
|
||||
// people only use ping occasionally to see if their internet's working
|
||||
// so this doesn't need to be great.
|
||||
// On Apple platforms, this function doesn't run the ping command. Instead,
|
||||
// it sends a non-privileged ping.
|
||||
//
|
||||
// The 'direction' parameter is used to determine where the response "pong"
|
||||
// packet should be written, if the ping succeeds. See the documentation on the
|
||||
@@ -958,44 +951,7 @@ func (ns *Impl) userPing(dstIP netip.Addr, pingResPkt []byte, direction userPing
|
||||
defer userPingSem.Release()
|
||||
|
||||
t0 := time.Now()
|
||||
var err error
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
err = exec.Command("ping", "-n", "1", "-w", "3000", dstIP.String()).Run()
|
||||
case "darwin", "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()
|
||||
}
|
||||
err := ns.sendOutboundUserPing(dstIP, 3*time.Second)
|
||||
d := time.Since(t0)
|
||||
if err != nil {
|
||||
if d < time.Second/2 {
|
||||
|
Reference in New Issue
Block a user