From a93937abc333fe286579f9d8dea7aeaf8ad7b5df Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 12 Jan 2022 13:48:20 -0800 Subject: [PATCH] wgengine/netstack: make userspace ping work when tailscaled has CAP_NET_RAW Updates #3710 Change-Id: Ief56c7ac20f5f09a2f940a1906b9efbf1b0d6932 Signed-off-by: Brad Fitzpatrick --- wgengine/netstack/netstack.go | 21 +++++++++++++++++++-- wgengine/netstack/netstack_linux.go | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 wgengine/netstack/netstack_linux.go diff --git a/wgengine/netstack/netstack.go b/wgengine/netstack/netstack.go index eb2ff2598..3022ba520 100644 --- a/wgengine/netstack/netstack.go +++ b/wgengine/netstack/netstack.go @@ -41,6 +41,7 @@ import ( "tailscale.com/syncs" "tailscale.com/types/logger" "tailscale.com/types/netmap" + "tailscale.com/version/distro" "tailscale.com/wgengine" "tailscale.com/wgengine/filter" "tailscale.com/wgengine/magicsock" @@ -394,8 +395,14 @@ 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 + // userPing tried to ping dstIP and if it succeeds, injects pingResPkt // 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() 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) 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 } if debugNetstack { diff --git a/wgengine/netstack/netstack_linux.go b/wgengine/netstack/netstack_linux.go new file mode 100644 index 000000000..a90d62450 --- /dev/null +++ b/wgengine/netstack/netstack_linux.go @@ -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}, + } + } +}