Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3c52b01

Browse files
authored
chore: add tailscale magicsock debug logging controls (coder#8982)
1 parent a5c59b9 commit 3c52b01

File tree

3 files changed

+157
-8
lines changed

3 files changed

+157
-8
lines changed

agent/agent.go

+41-7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"time"
2323

2424
"github.com/armon/circbuf"
25+
"github.com/go-chi/chi/v5"
2526
"github.com/google/uuid"
2627
"github.com/prometheus/client_golang/prometheus"
2728
"github.com/spf13/afero"
@@ -1408,24 +1409,57 @@ func (a *agent) isClosed() bool {
14081409
}
14091410

14101411
func (a *agent) HTTPDebug() http.Handler {
1411-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1412+
r := chi.NewRouter()
1413+
1414+
requireNetwork := func(w http.ResponseWriter) (*tailnet.Conn, bool) {
14121415
a.closeMutex.Lock()
14131416
network := a.network
14141417
a.closeMutex.Unlock()
14151418

14161419
if network == nil {
1417-
w.WriteHeader(http.StatusOK)
1420+
w.WriteHeader(http.StatusNotFound)
14181421
_, _ = w.Write([]byte("network is not ready yet"))
1422+
return nil, false
1423+
}
1424+
1425+
return network, true
1426+
}
1427+
1428+
r.Get("/debug/magicsock", func(w http.ResponseWriter, r *http.Request) {
1429+
network, ok := requireNetwork(w)
1430+
if !ok {
14191431
return
14201432
}
1433+
network.MagicsockServeHTTPDebug(w, r)
1434+
})
14211435

1422-
if r.URL.Path == "/debug/magicsock" {
1423-
network.MagicsockServeHTTPDebug(w, r)
1424-
} else {
1425-
w.WriteHeader(http.StatusNotFound)
1426-
_, _ = w.Write([]byte("404 not found"))
1436+
r.Get("/debug/magicsock/debug-logging/{state}", func(w http.ResponseWriter, r *http.Request) {
1437+
state := chi.URLParam(r, "state")
1438+
stateBool, err := strconv.ParseBool(state)
1439+
if err != nil {
1440+
w.WriteHeader(http.StatusBadRequest)
1441+
_, _ = fmt.Fprintf(w, "invalid state %q, must be a boolean", state)
1442+
return
1443+
}
1444+
1445+
network, ok := requireNetwork(w)
1446+
if !ok {
1447+
return
14271448
}
1449+
1450+
network.MagicsockSetDebugLoggingEnabled(stateBool)
1451+
a.logger.Info(r.Context(), "updated magicsock debug logging due to debug request", slog.F("new_state", stateBool))
1452+
1453+
w.WriteHeader(http.StatusOK)
1454+
_, _ = fmt.Fprintf(w, "updated magicsock debug logging to %v", stateBool)
14281455
})
1456+
1457+
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
1458+
w.WriteHeader(http.StatusNotFound)
1459+
_, _ = w.Write([]byte("404 not found"))
1460+
})
1461+
1462+
return r
14291463
}
14301464

14311465
func (a *agent) Close() error {

agent/agent_test.go

+91-1
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,96 @@ func TestAgent_WriteVSCodeConfigs(t *testing.T) {
19321932
}, testutil.WaitShort, testutil.IntervalFast)
19331933
}
19341934

1935+
func TestAgent_DebugServer(t *testing.T) {
1936+
t.Parallel()
1937+
1938+
derpMap, _ := tailnettest.RunDERPAndSTUN(t)
1939+
//nolint:dogsled
1940+
conn, _, _, _, agnt := setupAgent(t, agentsdk.Manifest{
1941+
DERPMap: derpMap,
1942+
}, 0)
1943+
1944+
awaitReachableCtx := testutil.Context(t, testutil.WaitLong)
1945+
ok := conn.AwaitReachable(awaitReachableCtx)
1946+
require.True(t, ok)
1947+
_ = conn.Close()
1948+
1949+
srv := httptest.NewServer(agnt.HTTPDebug())
1950+
t.Cleanup(srv.Close)
1951+
1952+
t.Run("MagicsockDebug", func(t *testing.T) {
1953+
t.Parallel()
1954+
1955+
ctx := testutil.Context(t, testutil.WaitLong)
1956+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/debug/magicsock", nil)
1957+
require.NoError(t, err)
1958+
1959+
res, err := srv.Client().Do(req)
1960+
require.NoError(t, err)
1961+
defer res.Body.Close()
1962+
require.Equal(t, http.StatusOK, res.StatusCode)
1963+
1964+
resBody, err := io.ReadAll(res.Body)
1965+
require.NoError(t, err)
1966+
require.Contains(t, string(resBody), "<h1>magicsock</h1>")
1967+
})
1968+
1969+
t.Run("MagicsockDebugLogging", func(t *testing.T) {
1970+
t.Parallel()
1971+
1972+
t.Run("Enable", func(t *testing.T) {
1973+
t.Parallel()
1974+
1975+
ctx := testutil.Context(t, testutil.WaitLong)
1976+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/debug/magicsock/debug-logging/t", nil)
1977+
require.NoError(t, err)
1978+
1979+
res, err := srv.Client().Do(req)
1980+
require.NoError(t, err)
1981+
defer res.Body.Close()
1982+
require.Equal(t, http.StatusOK, res.StatusCode)
1983+
1984+
resBody, err := io.ReadAll(res.Body)
1985+
require.NoError(t, err)
1986+
require.Contains(t, string(resBody), "updated magicsock debug logging to true")
1987+
})
1988+
1989+
t.Run("Disable", func(t *testing.T) {
1990+
t.Parallel()
1991+
1992+
ctx := testutil.Context(t, testutil.WaitLong)
1993+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/debug/magicsock/debug-logging/0", nil)
1994+
require.NoError(t, err)
1995+
1996+
res, err := srv.Client().Do(req)
1997+
require.NoError(t, err)
1998+
defer res.Body.Close()
1999+
require.Equal(t, http.StatusOK, res.StatusCode)
2000+
2001+
resBody, err := io.ReadAll(res.Body)
2002+
require.NoError(t, err)
2003+
require.Contains(t, string(resBody), "updated magicsock debug logging to false")
2004+
})
2005+
2006+
t.Run("Invalid", func(t *testing.T) {
2007+
t.Parallel()
2008+
2009+
ctx := testutil.Context(t, testutil.WaitLong)
2010+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/debug/magicsock/debug-logging/blah", nil)
2011+
require.NoError(t, err)
2012+
2013+
res, err := srv.Client().Do(req)
2014+
require.NoError(t, err)
2015+
defer res.Body.Close()
2016+
require.Equal(t, http.StatusBadRequest, res.StatusCode)
2017+
2018+
resBody, err := io.ReadAll(res.Body)
2019+
require.NoError(t, err)
2020+
require.Contains(t, string(resBody), `invalid state "blah", must be a boolean`)
2021+
})
2022+
})
2023+
}
2024+
19352025
func setupSSHCommand(t *testing.T, beforeArgs []string, afterArgs []string) (*ptytest.PTYCmd, pty.Process) {
19362026
//nolint:dogsled
19372027
agentConn, _, _, _, _ := setupAgent(t, agentsdk.Manifest{}, 0)
@@ -2013,7 +2103,7 @@ func setupAgent(t *testing.T, metadata agentsdk.Manifest, ptyTimeout time.Durati
20132103
*agenttest.Client,
20142104
<-chan *agentsdk.Stats,
20152105
afero.Fs,
2016-
io.Closer,
2106+
agent.Agent,
20172107
) {
20182108
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
20192109
if metadata.DERPMap == nil {

tailnet/conn.go

+25
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net"
99
"net/http"
1010
"net/netip"
11+
"os"
1112
"reflect"
1213
"strconv"
1314
"sync"
@@ -51,6 +52,14 @@ const (
5152
WorkspaceAgentSpeedtestPort = 3
5253
)
5354

55+
// EnvMagicsockDebugLogging enables super-verbose logging for the magicsock
56+
// internals. A logger must be supplied to the connection with the debug level
57+
// enabled.
58+
//
59+
// With this disabled, you still get a lot of output if you have a valid logger
60+
// with the debug level enabled.
61+
const EnvMagicsockDebugLogging = "CODER_MAGICSOCK_DEBUG_LOGGING"
62+
5463
func init() {
5564
// Globally disable network namespacing. All networking happens in
5665
// userspace.
@@ -175,6 +184,18 @@ func NewConn(options *Options) (conn *Conn, err error) {
175184
magicConn.SetDERPHeader(options.DERPHeader.Clone())
176185
}
177186

187+
if v, ok := os.LookupEnv(EnvMagicsockDebugLogging); ok {
188+
vBool, err := strconv.ParseBool(v)
189+
if err != nil {
190+
options.Logger.Debug(context.Background(), fmt.Sprintf("magicsock debug logging disabled due to invalid value %s=%q, use true or false", EnvMagicsockDebugLogging, v))
191+
} else {
192+
magicConn.SetDebugLoggingEnabled(vBool)
193+
options.Logger.Debug(context.Background(), fmt.Sprintf("magicsock debug logging set by %s=%t", EnvMagicsockDebugLogging, vBool))
194+
}
195+
} else {
196+
options.Logger.Debug(context.Background(), fmt.Sprintf("magicsock debug logging disabled, use %s=true to enable", EnvMagicsockDebugLogging))
197+
}
198+
178199
// Update the keys for the magic connection!
179200
err = magicConn.SetPrivateKey(nodePrivateKey)
180201
if err != nil {
@@ -361,6 +382,10 @@ type Conn struct {
361382
trafficStats *connstats.Statistics
362383
}
363384

385+
func (c *Conn) MagicsockSetDebugLoggingEnabled(enabled bool) {
386+
c.magicConn.SetDebugLoggingEnabled(enabled)
387+
}
388+
364389
func (c *Conn) SetAddresses(ips []netip.Prefix) error {
365390
c.mutex.Lock()
366391
defer c.mutex.Unlock()

0 commit comments

Comments
 (0)