WIP: rebase fork onto upstream/main (v1.103.0) #15

Closed
codinget wants to merge 670 commits from webnet into save/webnet-2026-07-29
10 changed files with 137 additions and 2 deletions
Showing only changes of commit 0433cc6929 - Show all commits
+2 -1
View File
@@ -323,6 +323,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/feature/runtimemetrics from tailscale.com/feature/condregister
L tailscale.com/feature/sdnotify from tailscale.com/feature/condregister
LD tailscale.com/feature/ssh from tailscale.com/cmd/tailscaled
L tailscale.com/feature/syslog from tailscale.com/feature/condregister
tailscale.com/feature/syspolicy from tailscale.com/feature/condregister
tailscale.com/feature/taildrop from tailscale.com/feature/condregister
tailscale.com/feature/tailnetlock from tailscale.com/feature/condregister
@@ -745,7 +746,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
iter from maps+
log from expvar+
log/internal from log
LD log/syslog from tailscale.com/ssh/tailssh
LD log/syslog from tailscale.com/ssh/tailssh+
maps from tailscale.com/clientupdate+
math from archive/tar+
math/big from crypto/dsa+
+15
View File
@@ -33,6 +33,21 @@ func TestOmitSSH(t *testing.T) {
}.Check(t)
}
func TestOmitSyslog(t *testing.T) {
const msg = "unexpected syslog usage with ts_omit_syslog"
deptest.DepChecker{
GOOS: "linux",
GOARCH: "amd64",
// Tailscale SSH's incubator also uses log/syslog, so omit
// SSH too to lock down the standard library package.
Tags: "ts_omit_syslog,ts_omit_ssh,ts_include_cli",
BadDeps: map[string]string{
"log/syslog": msg,
"tailscale.com/feature/syslog": msg,
},
}.Check(t)
}
func TestOmitSyspolicy(t *testing.T) {
const msg = "unexpected syspolicy usage with ts_omit_syspolicy"
deptest.DepChecker{
+7
View File
@@ -233,6 +233,9 @@ store state on filesystem.`)
if f, ok := hookRegisterOutboundProxyFlags.GetOk(); ok {
f()
}
if f, ok := feature.HookRegisterLogSinkFlags.GetOk(); ok {
f()
}
if runtime.GOOS == "plan9" && os.Getenv("_NETSHELL_CHILD_") != "" {
os.Args = []string{"tailscaled", "be-child", "plan9-netshell"}
@@ -261,6 +264,10 @@ store state on filesystem.`)
}
}
if f, ok := feature.HookLogSink.GetOk(); ok {
f() // redirects the default logger (e.g. to syslog) if requested by flags
}
if fd, ok := envknob.LookupInt("TS_PARENT_DEATH_FD"); ok && fd > 2 {
go dieOnPipeReadErrorOfFD(fd)
}
@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build ts_omit_syslog
package buildfeatures
// HasSyslog is whether the binary was built with support for modular feature "tailscaled --syslog flag support to send logs to the system syslog daemon".
// Specifically, it's whether the binary was NOT built with the "ts_omit_syslog" build tag.
// It's a const so it can be used for dead code elimination.
const HasSyslog = false
@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build !ts_omit_syslog
package buildfeatures
// HasSyslog is whether the binary was built with support for modular feature "tailscaled --syslog flag support to send logs to the system syslog daemon".
// Specifically, it's whether the binary was NOT built with the "ts_omit_syslog" build tag.
// It's a const so it can be used for dead code elimination.
const HasSyslog = true
+8
View File
@@ -0,0 +1,8 @@
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
//go:build (linux || freebsd || openbsd) && !ts_omit_syslog
package condregister
import _ "tailscale.com/feature/syslog"
+4
View File
@@ -267,6 +267,10 @@ var Features = map[FeatureTag]FeatureMeta{
Sym: "Synology",
Desc: "Synology NAS integration (applies to Linux builds only)",
},
"syslog": {
Sym: "Syslog",
Desc: "tailscaled --syslog flag support to send logs to the system syslog daemon",
},
"syspolicy": {Sym: "SystemPolicy", Desc: "System policy configuration (MDM) support"},
"systray": {
Sym: "SysTray",
+16
View File
@@ -4,6 +4,7 @@
package feature
import (
"io"
"net/http"
"net/url"
"os"
@@ -13,6 +14,21 @@ import (
"tailscale.com/types/persist"
)
// HookRegisterLogSinkFlags is a hook for the syslog feature to register
// its flags (such as tailscaled's --syslog) with the process's default
// flag set. If set, tailscaled calls it before flag parsing.
var HookRegisterLogSinkFlags Hook[func()]
// HookLogSink is a hook for the syslog feature to redirect the process's
// logs to an alternate sink. If set, tailscaled calls it once early in
// main, after flag parsing; on that first call, if the user requested an
// alternate sink, it points the standard library's default logger at that
// sink. It returns the sink, or nil if logs are not being redirected.
// Later callers (such as logpolicy, which otherwise writes its console
// copy of logs to stderr) use the returned writer to send their logs to
// the same place.
var HookLogSink Hook[func() io.Writer]
// HookCanAutoUpdate is a hook for the clientupdate package
// to conditionally initialize.
var HookCanAutoUpdate Hook[func() bool]
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
//go:build unix
// Package syslog provides the tailscaled --syslog flag, which sends the
// daemon's logs to the system syslog daemon instead of stderr.
package syslog
import (
"flag"
"io"
"log"
"log/syslog"
"sync"
"tailscale.com/feature"
)
func init() {
feature.Register("syslog")
feature.HookRegisterLogSinkFlags.Set(registerFlags)
feature.HookLogSink.Set(logSink)
}
var useSyslog bool
func registerFlags() {
flag.BoolVar(&useSyslog, "syslog", false, "log to the system syslog daemon instead of stderr")
}
// logSink returns the writer to which logs should be sent, pointing the
// standard library's default logger at it on first call. It returns nil if
// syslog logging was not requested or the syslog daemon is unreachable.
var logSink = sync.OnceValue(func() io.Writer {
if !useSyslog {
return nil
}
w, err := syslog.New(syslog.LOG_DAEMON|syslog.LOG_INFO, "tailscaled")
if err != nil {
log.Printf("syslog: connecting to syslog daemon failed; continuing to log to stderr: %v", err)
return nil
}
log.SetFlags(0) // syslog records its own timestamps
log.SetOutput(w)
return w
})
+12 -1
View File
@@ -546,7 +546,18 @@ func (opts Options) init(disableLogging bool) (*logtail.Config, *Policy) {
// anyway, no need to add one.
lflags = 0
}
console := log.New(stderrWriter{}, "", lflags)
var conWriter io.Writer = stderrWriter{}
if buildfeatures.HasSyslog {
if f, ok := feature.HookLogSink.GetOk(); ok {
if w := f(); w != nil {
// Logs are being redirected elsewhere (e.g. to syslog,
// which records its own timestamps).
conWriter = w
lflags = 0
}
}
}
console := log.New(conWriter, "", lflags)
var earlyErrBuf bytes.Buffer
earlyLogf := func(format string, a ...any) {