tstest/natlab: get tailscaled logs from gokrazy via syslog

Using https://github.com/gokrazy/gokrazy/pull/275

This is much lower latency than logcatcher, which is higher latency
and chunkier. And this is better than getting it via 'tailscale debug
daemon-logs', which misses early interesting logs.

Updates #13038

Change-Id: I499ec254c003a9494c0e9910f9c650c8ac44ef33
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2024-08-12 21:39:28 -07:00
committed by Brad Fitzpatrick
parent 10662c4282
commit 10d0ce8dde
6 changed files with 53 additions and 55 deletions

View File

@@ -73,9 +73,12 @@ func (c *Config) AddNode(opts ...any) *Node {
case TailscaledEnv:
n.env = append(n.env, o)
case NodeOption:
if o == HostFirewall {
switch o {
case HostFirewall:
n.hostFW = true
} else {
case VerboseSyslog:
n.verboseSyslog = true
default:
if n.err == nil {
n.err = fmt.Errorf("unknown NodeOption %q", o)
}
@@ -93,7 +96,8 @@ func (c *Config) AddNode(opts ...any) *Node {
type NodeOption string
const (
HostFirewall NodeOption = "HostFirewall"
HostFirewall NodeOption = "HostFirewall"
VerboseSyslog NodeOption = "VerboseSyslog"
)
// TailscaledEnv is а option that can be passed to Config.AddNode
@@ -148,8 +152,9 @@ type Node struct {
err error
n *node // nil until NewServer called
env []TailscaledEnv
hostFW bool
env []TailscaledEnv
hostFW bool
verboseSyslog bool
// TODO(bradfitz): this is halfway converted to supporting multiple NICs
// but not done. We need a MAC-per-Network.
@@ -171,6 +176,14 @@ func (n *Node) HostFirewall() bool {
return n.hostFW
}
func (n *Node) VerboseSyslog() bool {
return n.verboseSyslog
}
func (n *Node) SetVerboseSyslog(v bool) {
n.verboseSyslog = v
}
// Network returns the first network this node is connected to,
// or nil if none.
func (n *Node) Network() *Network {
@@ -277,8 +290,9 @@ func (s *Server) initFromConfig(c *Config) error {
return conf.err
}
n := &node{
mac: conf.mac,
net: netOfConf[conf.Network()],
mac: conf.mac,
net: netOfConf[conf.Network()],
verboseSyslog: conf.VerboseSyslog(),
}
n.interfaceID = must.Get(s.pcapWriter.AddInterface(pcapgo.NgInterface{
Name: fmt.Sprintf("node%d", i+1),

View File

@@ -397,10 +397,10 @@ func (n *network) serveLogCatcherConn(clientRemoteIP netip.Addr, c net.Conn) {
if node != nil {
node.logMu.Lock()
defer node.logMu.Unlock()
node.logCatcherWrites++
for _, lg := range logs {
tStr := lg.Logtail.Client_Time.Round(time.Millisecond).Format(time.RFC3339Nano)
fmt.Fprintf(&node.logBuf, "[%v] %s\n", tStr, lg.Text)
log.Printf("LOG %v [%v] %s\n", clientRemoteIP, tStr, lg.Text)
}
}
})
@@ -416,6 +416,7 @@ var (
fakeDERP1IP = netip.AddrFrom4([4]byte{33, 4, 0, 1}) // 3340=DERP; 1=derp 1
fakeDERP2IP = netip.AddrFrom4([4]byte{33, 4, 0, 2}) // 3340=DERP; 1=derp 1
fakeLogCatcherIP = netip.AddrFrom4([4]byte{52, 52, 0, 4})
fakeSyslogIP = netip.AddrFrom4([4]byte{52, 52, 0, 9})
)
type EthernetPacket struct {
@@ -501,16 +502,18 @@ func (n *network) MACOfIP(ip netip.Addr) (_ MAC, ok bool) {
}
type node struct {
mac MAC
interfaceID int
net *network
lanIP netip.Addr // must be in net.lanIP prefix + unique in net
mac MAC
interfaceID int
net *network
lanIP netip.Addr // must be in net.lanIP prefix + unique in net
verboseSyslog bool
// logMu guards logBuf.
// TODO(bradfitz): conditionally write these out to separate files at the end?
// Currently they only hold logcatcher logs.
logMu sync.Mutex
logBuf bytes.Buffer
logMu sync.Mutex
logBuf bytes.Buffer
logCatcherWrites int
}
type derpServer struct {
@@ -1007,6 +1010,19 @@ func (n *network) HandleEthernetIPv4PacketForRouter(ep EthernetPacket) {
return
}
if isUDP && dstIP == fakeSyslogIP {
node, ok := n.nodesByIP[srcIP]
if !ok {
return
}
if node.verboseSyslog {
// TODO(bradfitz): parse this and capture it, structured, into
// node's log buffer.
log.Printf("syslog from %v: %s", srcIP, udp.Payload)
}
return
}
if !toForward && isNATPMP(packet) {
n.handleNATPMPRequest(UDPPacket{
Src: netip.AddrPortFrom(srcIP, uint16(udp.SrcPort)),