Skip to content

Commit 77123a5

Browse files
authored
wgengine/netlog: include node OS in logged attributes (tailscale#17755)
Include the node's OS with network flow log information. Refactor the JSON-length computation to be a bit more precise. Updates tailscale/corp#33352 Fixes tailscale/corp#34030 Signed-off-by: Joe Tsai <[email protected]>
1 parent db7dcd5 commit 77123a5

File tree

7 files changed

+31
-19
lines changed

7 files changed

+31
-19
lines changed

cmd/k8s-operator/depaware.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
825825
tailscale.com/tsweb from tailscale.com/util/eventbus
826826
tailscale.com/tsweb/varz from tailscale.com/util/usermetric+
827827
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal+
828-
tailscale.com/types/bools from tailscale.com/tsnet
828+
tailscale.com/types/bools from tailscale.com/tsnet+
829829
tailscale.com/types/dnstype from tailscale.com/ipn/ipnlocal+
830830
tailscale.com/types/empty from tailscale.com/ipn+
831831
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+

cmd/tailscaled/depaware.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
392392
tailscale.com/tsweb from tailscale.com/util/eventbus
393393
tailscale.com/tsweb/varz from tailscale.com/cmd/tailscaled+
394394
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal+
395+
tailscale.com/types/bools from tailscale.com/wgengine/netlog
395396
tailscale.com/types/dnstype from tailscale.com/ipn/ipnlocal+
396397
tailscale.com/types/empty from tailscale.com/ipn+
397398
tailscale.com/types/flagtype from tailscale.com/cmd/tailscaled

cmd/tsidp/depaware.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
230230
tailscale.com/tsweb from tailscale.com/util/eventbus
231231
tailscale.com/tsweb/varz from tailscale.com/tsweb+
232232
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal+
233-
tailscale.com/types/bools from tailscale.com/tsnet
233+
tailscale.com/types/bools from tailscale.com/tsnet+
234234
tailscale.com/types/dnstype from tailscale.com/client/local+
235235
tailscale.com/types/empty from tailscale.com/ipn+
236236
tailscale.com/types/ipproto from tailscale.com/ipn+

tsnet/depaware.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
225225
LDW tailscale.com/tsweb from tailscale.com/util/eventbus
226226
tailscale.com/tsweb/varz from tailscale.com/tsweb+
227227
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal+
228-
tailscale.com/types/bools from tailscale.com/tsnet
228+
tailscale.com/types/bools from tailscale.com/tsnet+
229229
tailscale.com/types/dnstype from tailscale.com/client/local+
230230
tailscale.com/types/empty from tailscale.com/ipn+
231231
tailscale.com/types/ipproto from tailscale.com/ipn+

types/netlogtype/netlogtype.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,6 @@ const (
4444
// Each [ConnectionCounts] occupies at most [MaxConnectionCountsJSONSize].
4545
MinMessageJSONSize = len(messageJSON)
4646

47-
nodeJSON = `{"nodeId":` + maxJSONStableID + `,"name":"","addresses":` + maxJSONAddrs + `,"user":"","tags":[]}`
48-
maxJSONAddrV4 = `"255.255.255.255"`
49-
maxJSONAddrV6 = `"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"`
50-
maxJSONAddrs = `[` + maxJSONAddrV4 + `,` + maxJSONAddrV6 + `]`
51-
52-
// MinNodeJSONSize is the overhead size of Node when it is
53-
// serialized as JSON assuming that each field is minimally populated.
54-
// It does not account for bytes occupied by
55-
// [Node.Name], [Node.User], or [Node.Tags]. The [Node.Addresses]
56-
// is assumed to contain a pair of IPv4 and IPv6 address.
57-
MinNodeJSONSize = len(nodeJSON)
58-
5947
maxJSONConnCounts = `{` + maxJSONConn + `,` + maxJSONCounts + `}`
6048
maxJSONConn = `"proto":` + maxJSONProto + `,"src":` + maxJSONAddrPort + `,"dst":` + maxJSONAddrPort
6149
maxJSONProto = `255`
@@ -82,6 +70,9 @@ type Node struct {
8270
// Addresses are the Tailscale IP addresses of the node.
8371
Addresses []netip.Addr `json:"addresses,omitempty"`
8472

73+
// OS is the operating system of the node.
74+
OS string `json:"os,omitzero"` // e.g., "linux"
75+
8576
// User is the user that owns the node.
8677
// It is not populated if the node is tagged.
8778
User string `json:"user,omitzero"` // e.g., "[email protected]"

wgengine/netlog/record.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"unicode/utf8"
1414

1515
"tailscale.com/tailcfg"
16+
"tailscale.com/types/bools"
1617
"tailscale.com/types/netlogtype"
1718
"tailscale.com/util/set"
1819
)
@@ -134,17 +135,31 @@ func compareConnCnts(x, y netlogtype.ConnectionCounts) int {
134135
}
135136

136137
// jsonLen computes an upper-bound on the size of the JSON representation.
137-
func (nu nodeUser) jsonLen() int {
138+
func (nu nodeUser) jsonLen() (n int) {
138139
if !nu.Valid() {
139140
return len(`{"nodeId":""}`)
140141
}
141-
n := netlogtype.MinNodeJSONSize + jsonQuotedLen(nu.Name())
142+
n += len(`{}`)
143+
n += len(`"nodeId":`) + jsonQuotedLen(string(nu.StableID())) + len(`,`)
144+
if len(nu.Name()) > 0 {
145+
n += len(`"name":`) + jsonQuotedLen(nu.Name()) + len(`,`)
146+
}
147+
if nu.Addresses().Len() > 0 {
148+
n += len(`"addresses":[]`)
149+
for _, addr := range nu.Addresses().All() {
150+
n += bools.IfElse(addr.Addr().Is4(), len(`"255.255.255.255"`), len(`"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"`)) + len(",")
151+
}
152+
}
153+
if nu.Hostinfo().Valid() && len(nu.Hostinfo().OS()) > 0 {
154+
n += len(`"os":`) + jsonQuotedLen(nu.Hostinfo().OS()) + len(`,`)
155+
}
142156
if nu.Tags().Len() > 0 {
157+
n += len(`"tags":[]`)
143158
for _, tag := range nu.Tags().All() {
144159
n += jsonQuotedLen(tag) + len(",")
145160
}
146-
} else if nu.user.Valid() && nu.user.ID() == nu.User() {
147-
n += jsonQuotedLen(nu.user.LoginName())
161+
} else if nu.user.Valid() && nu.user.ID() == nu.User() && len(nu.user.LoginName()) > 0 {
162+
n += len(`"user":`) + jsonQuotedLen(nu.user.LoginName()) + len(",")
148163
}
149164
return n
150165
}
@@ -166,6 +181,9 @@ func (nu nodeUser) toNode() netlogtype.Node {
166181
}
167182
n.Addresses = []netip.Addr{ipv4, ipv6}
168183
n.Addresses = slices.DeleteFunc(n.Addresses, func(a netip.Addr) bool { return !a.IsValid() })
184+
if nu.Hostinfo().Valid() {
185+
n.OS = nu.Hostinfo().OS()
186+
}
169187
if nu.Tags().Len() > 0 {
170188
n.Tags = nu.Tags().AsSlice()
171189
slices.Sort(n.Tags)

wgengine/netlog/record_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ func TestToNode(t *testing.T) {
190190
node: &tailcfg.Node{
191191
StableID: "n123456CNTL",
192192
Addresses: []netip.Prefix{prefix("100.1.2.3")},
193+
Hostinfo: (&tailcfg.Hostinfo{OS: "linux"}).View(),
193194
User: 12345,
194195
},
195196
user: &tailcfg.UserProfile{
@@ -199,6 +200,7 @@ func TestToNode(t *testing.T) {
199200
want: netlogtype.Node{
200201
NodeID: "n123456CNTL",
201202
Addresses: []netip.Addr{addr("100.1.2.3")},
203+
OS: "linux",
202204
User: "user@domain",
203205
},
204206
},

0 commit comments

Comments
 (0)