wgengine/netstack: make userspace ping work when tailscaled has CAP_NET_RAW

Updates #3710

Change-Id: Ief56c7ac20f5f09a2f940a1906b9efbf1b0d6932
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/3720/head
Brad Fitzpatrick 3 years ago committed by Brad Fitzpatrick
parent 26d4ccb816
commit a93937abc3

@ -41,6 +41,7 @@ import (
"tailscale.com/syncs" "tailscale.com/syncs"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/version/distro"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
"tailscale.com/wgengine/magicsock" "tailscale.com/wgengine/magicsock"
@ -394,8 +395,14 @@ func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool {
return false 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 userPingSem = syncs.NewSemaphore(20) // 20 child ping processes at once
var isSynology = runtime.GOOS == "linux" && distro.Get() == distro.Synology
// userPing tried to ping dstIP and if it succeeds, injects pingResPkt // userPing tried to ping dstIP and if it succeeds, injects pingResPkt
// into the tundev. // into the tundev.
// //
@ -426,11 +433,21 @@ func (ns *Impl) userPing(dstIP netaddr.IP, pingResPkt []byte) {
} }
err = exec.Command(ping, "-c", "1", "-w", "3", dstIP.String()).Run() err = exec.Command(ping, "-c", "1", "-w", "3", dstIP.String()).Run()
default: default:
err = exec.Command("ping", "-c", "1", "-W", "3", dstIP.String()).Run() 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()
} }
d := time.Since(t0) d := time.Since(t0)
if err != nil { if err != nil {
ns.logf("exec ping of %v failed in %v", dstIP, d) ns.logf("exec ping of %v failed in %v: %v", dstIP, d, err)
return return
} }
if debugNetstack { if debugNetstack {

@ -0,0 +1,20 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package netstack
import (
"os/exec"
"syscall"
"golang.org/x/sys/unix"
)
func init() {
setAmbientCapsRaw = func(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{
AmbientCaps: []uintptr{unix.CAP_NET_RAW},
}
}
}
Loading…
Cancel
Save