mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-21 06:01:42 +00:00
types/netlogtype: new package for network logging types (#6092)
The netlog.Message type is useful to depend on from other packages,
but doing so would transitively cause gvisor and other large packages
to be linked in.
Avoid this problem by moving all network logging types to a single package.
We also update staticcheck to take in:
003d277bcf
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
parent
a44687e71f
commit
c21a3c4733
@ -39,10 +39,8 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"tailscale.com/net/flowtrack"
|
"tailscale.com/types/netlogtype"
|
||||||
"tailscale.com/net/tunstats"
|
|
||||||
"tailscale.com/util/must"
|
"tailscale.com/util/must"
|
||||||
"tailscale.com/wgengine/netlog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -62,7 +60,7 @@ func main() {
|
|||||||
Logtail struct {
|
Logtail struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
} `json:"logtail"`
|
} `json:"logtail"`
|
||||||
netlog.Message
|
netlogtype.Message
|
||||||
}
|
}
|
||||||
if err := dec.Decode(&msg); err != nil {
|
if err := dec.Decode(&msg); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@ -77,16 +75,16 @@ func main() {
|
|||||||
// Construct a table of network traffic per connection.
|
// Construct a table of network traffic per connection.
|
||||||
rows := [][7]string{{3: "Tx[P/s]", 4: "Tx[B/s]", 5: "Rx[P/s]", 6: "Rx[B/s]"}}
|
rows := [][7]string{{3: "Tx[P/s]", 4: "Tx[B/s]", 5: "Rx[P/s]", 6: "Rx[B/s]"}}
|
||||||
duration := msg.End.Sub(msg.Start)
|
duration := msg.End.Sub(msg.Start)
|
||||||
addRows := func(heading string, traffic []netlog.TupleCounts) {
|
addRows := func(heading string, traffic []netlogtype.ConnectionCounts) {
|
||||||
if len(traffic) == 0 {
|
if len(traffic) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
slices.SortFunc(traffic, func(x, y netlog.TupleCounts) bool {
|
slices.SortFunc(traffic, func(x, y netlogtype.ConnectionCounts) bool {
|
||||||
nx := x.TxPackets + x.TxBytes + x.RxPackets + x.RxBytes
|
nx := x.TxPackets + x.TxBytes + x.RxPackets + x.RxBytes
|
||||||
ny := y.TxPackets + y.TxBytes + y.RxPackets + y.RxBytes
|
ny := y.TxPackets + y.TxBytes + y.RxPackets + y.RxBytes
|
||||||
return nx > ny
|
return nx > ny
|
||||||
})
|
})
|
||||||
var sum tunstats.Counts
|
var sum netlogtype.Counts
|
||||||
for _, cc := range traffic {
|
for _, cc := range traffic {
|
||||||
sum = sum.Add(cc.Counts)
|
sum = sum.Add(cc.Counts)
|
||||||
}
|
}
|
||||||
@ -97,7 +95,7 @@ func main() {
|
|||||||
5: formatSI(float64(sum.RxPackets) / duration.Seconds()),
|
5: formatSI(float64(sum.RxPackets) / duration.Seconds()),
|
||||||
6: formatIEC(float64(sum.RxBytes) / duration.Seconds()),
|
6: formatIEC(float64(sum.RxBytes) / duration.Seconds()),
|
||||||
})
|
})
|
||||||
if len(traffic) == 1 && traffic[0].Tuple == (flowtrack.Tuple{}) {
|
if len(traffic) == 1 && traffic[0].Connection.IsZero() {
|
||||||
return // this is already a summary counts
|
return // this is already a summary counts
|
||||||
}
|
}
|
||||||
formatAddrPort := func(a netip.AddrPort) string {
|
formatAddrPort := func(a netip.AddrPort) string {
|
||||||
|
@ -240,7 +240,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/net/tsdial from tailscale.com/control/controlclient+
|
tailscale.com/net/tsdial from tailscale.com/control/controlclient+
|
||||||
💣 tailscale.com/net/tshttpproxy from tailscale.com/control/controlclient+
|
💣 tailscale.com/net/tshttpproxy from tailscale.com/control/controlclient+
|
||||||
tailscale.com/net/tstun from tailscale.com/net/dns+
|
tailscale.com/net/tstun from tailscale.com/net/dns+
|
||||||
tailscale.com/net/tunstats from tailscale.com/net/tstun+
|
tailscale.com/net/tunstats from tailscale.com/net/tstun
|
||||||
tailscale.com/net/wsconn from tailscale.com/control/controlhttp+
|
tailscale.com/net/wsconn from tailscale.com/control/controlhttp+
|
||||||
tailscale.com/paths from tailscale.com/ipn/ipnlocal+
|
tailscale.com/paths from tailscale.com/ipn/ipnlocal+
|
||||||
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
||||||
@ -262,6 +262,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
||||||
tailscale.com/types/key from tailscale.com/control/controlbase+
|
tailscale.com/types/key from tailscale.com/control/controlbase+
|
||||||
tailscale.com/types/logger from tailscale.com/control/controlclient+
|
tailscale.com/types/logger from tailscale.com/control/controlclient+
|
||||||
|
tailscale.com/types/netlogtype from tailscale.com/net/tstun+
|
||||||
tailscale.com/types/netmap from tailscale.com/control/controlclient+
|
tailscale.com/types/netmap from tailscale.com/control/controlclient+
|
||||||
tailscale.com/types/nettype from tailscale.com/wgengine/magicsock+
|
tailscale.com/types/nettype from tailscale.com/wgengine/magicsock+
|
||||||
tailscale.com/types/opt from tailscale.com/control/controlclient+
|
tailscale.com/types/opt from tailscale.com/control/controlclient+
|
||||||
|
2
go.mod
2
go.mod
@ -67,7 +67,7 @@ require (
|
|||||||
golang.zx2c4.com/wireguard v0.0.0-20220904105730-b51010ba13f0
|
golang.zx2c4.com/wireguard v0.0.0-20220904105730-b51010ba13f0
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||||
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
|
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
|
||||||
honnef.co/go/tools v0.4.0-0.dev.0.20220404092545-59d7a2877f83
|
honnef.co/go/tools v0.4.0-0.dev.0.20220517111757-f4a2f64ce238
|
||||||
inet.af/peercred v0.0.0-20210906144145-0893ea02156a
|
inet.af/peercred v0.0.0-20210906144145-0893ea02156a
|
||||||
inet.af/wf v0.0.0-20220728202103-50d96caab2f6
|
inet.af/wf v0.0.0-20220728202103-50d96caab2f6
|
||||||
nhooyr.io/websocket v1.8.7
|
nhooyr.io/websocket v1.8.7
|
||||||
|
4
go.sum
4
go.sum
@ -1829,8 +1829,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
|||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
|
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
|
||||||
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||||
honnef.co/go/tools v0.4.0-0.dev.0.20220404092545-59d7a2877f83 h1:lZ9GIYaU+o5+X6ST702I/Ntyq9Y2oIMZ42rBQpem64A=
|
honnef.co/go/tools v0.4.0-0.dev.0.20220517111757-f4a2f64ce238 h1:8Vr1KP9OTjoKQSSeLefzibQgDV4s2ujJElKHqMi7nsA=
|
||||||
honnef.co/go/tools v0.4.0-0.dev.0.20220404092545-59d7a2877f83/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70=
|
honnef.co/go/tools v0.4.0-0.dev.0.20220517111757-f4a2f64ce238/go.mod h1:DCQzo6aCmhYDJH+We7BIU38vNvVkaOKa6s57pewKdvI=
|
||||||
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
"golang.zx2c4.com/wireguard/tun"
|
"golang.zx2c4.com/wireguard/tun"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
"tailscale.com/disco"
|
"tailscale.com/disco"
|
||||||
"tailscale.com/net/flowtrack"
|
|
||||||
"tailscale.com/net/packet"
|
"tailscale.com/net/packet"
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
"tailscale.com/net/tunstats"
|
"tailscale.com/net/tunstats"
|
||||||
@ -31,6 +30,7 @@ import (
|
|||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/types/netlogtype"
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
)
|
)
|
||||||
@ -853,7 +853,7 @@ func (t *Wrapper) SetStatisticsEnabled(enable bool) {
|
|||||||
|
|
||||||
// ExtractStatistics extracts and resets the counters for all active connections.
|
// ExtractStatistics extracts and resets the counters for all active connections.
|
||||||
// It must be called periodically otherwise the memory used is unbounded.
|
// It must be called periodically otherwise the memory used is unbounded.
|
||||||
func (t *Wrapper) ExtractStatistics() map[flowtrack.Tuple]tunstats.Counts {
|
func (t *Wrapper) ExtractStatistics() map[netlogtype.Connection]netlogtype.Counts {
|
||||||
return t.stats.Extract()
|
return t.stats.Extract()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,15 +19,14 @@ import (
|
|||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
"golang.zx2c4.com/wireguard/tun/tuntest"
|
"golang.zx2c4.com/wireguard/tun/tuntest"
|
||||||
"tailscale.com/disco"
|
"tailscale.com/disco"
|
||||||
"tailscale.com/net/flowtrack"
|
|
||||||
"tailscale.com/net/netaddr"
|
"tailscale.com/net/netaddr"
|
||||||
"tailscale.com/net/packet"
|
"tailscale.com/net/packet"
|
||||||
"tailscale.com/net/tunstats"
|
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/tstime/mono"
|
"tailscale.com/tstime/mono"
|
||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/types/netlogtype"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -379,17 +378,17 @@ func TestFilter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
got := tun.ExtractStatistics()
|
got := tun.ExtractStatistics()
|
||||||
want := map[flowtrack.Tuple]tunstats.Counts{}
|
want := map[netlogtype.Connection]netlogtype.Counts{}
|
||||||
if !tt.drop {
|
if !tt.drop {
|
||||||
var p packet.Parsed
|
var p packet.Parsed
|
||||||
p.Decode(tt.data)
|
p.Decode(tt.data)
|
||||||
switch tt.dir {
|
switch tt.dir {
|
||||||
case in:
|
case in:
|
||||||
tuple := flowtrack.Tuple{Proto: ipproto.UDP, Src: p.Dst, Dst: p.Src}
|
conn := netlogtype.Connection{Proto: ipproto.UDP, Src: p.Dst, Dst: p.Src}
|
||||||
want[tuple] = tunstats.Counts{RxPackets: 1, RxBytes: uint64(len(tt.data))}
|
want[conn] = netlogtype.Counts{RxPackets: 1, RxBytes: uint64(len(tt.data))}
|
||||||
case out:
|
case out:
|
||||||
tuple := flowtrack.Tuple{Proto: ipproto.UDP, Src: p.Src, Dst: p.Dst}
|
conn := netlogtype.Connection{Proto: ipproto.UDP, Src: p.Src, Dst: p.Dst}
|
||||||
want[tuple] = tunstats.Counts{TxPackets: 1, TxBytes: uint64(len(tt.data))}
|
want[conn] = netlogtype.Counts{TxPackets: 1, TxBytes: uint64(len(tt.data))}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
@ -9,8 +9,8 @@ package tunstats
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"tailscale.com/net/flowtrack"
|
|
||||||
"tailscale.com/net/packet"
|
"tailscale.com/net/packet"
|
||||||
|
"tailscale.com/types/netlogtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Statistics maintains counters for every connection.
|
// Statistics maintains counters for every connection.
|
||||||
@ -18,36 +18,19 @@ import (
|
|||||||
// The zero value is ready for use.
|
// The zero value is ready for use.
|
||||||
type Statistics struct {
|
type Statistics struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
m map[flowtrack.Tuple]Counts
|
m map[netlogtype.Connection]netlogtype.Counts
|
||||||
}
|
|
||||||
|
|
||||||
// Counts are statistics about a particular connection.
|
|
||||||
type Counts struct {
|
|
||||||
TxPackets uint64 `json:"txPkts,omitempty"`
|
|
||||||
TxBytes uint64 `json:"txBytes,omitempty"`
|
|
||||||
RxPackets uint64 `json:"rxPkts,omitempty"`
|
|
||||||
RxBytes uint64 `json:"rxBytes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds the counts from both c1 and c2.
|
|
||||||
func (c1 Counts) Add(c2 Counts) Counts {
|
|
||||||
c1.TxPackets += c2.TxPackets
|
|
||||||
c1.TxBytes += c2.TxBytes
|
|
||||||
c1.RxPackets += c2.RxPackets
|
|
||||||
c1.RxBytes += c2.RxBytes
|
|
||||||
return c1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTx updates the counters for a transmitted IP packet
|
// UpdateTx updates the counters for a transmitted IP packet
|
||||||
// The source and destination of the packet directly correspond with
|
// The source and destination of the packet directly correspond with
|
||||||
// the source and destination in flowtrack.Tuple.
|
// the source and destination in netlogtype.Connection.
|
||||||
func (s *Statistics) UpdateTx(b []byte) {
|
func (s *Statistics) UpdateTx(b []byte) {
|
||||||
s.update(b, false)
|
s.update(b, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRx updates the counters for a received IP packet.
|
// UpdateRx updates the counters for a received IP packet.
|
||||||
// The source and destination of the packet are inverted with respect to
|
// The source and destination of the packet are inverted with respect to
|
||||||
// the source and destination in flowtrack.Tuple.
|
// the source and destination in netlogtype.Connection.
|
||||||
func (s *Statistics) UpdateRx(b []byte) {
|
func (s *Statistics) UpdateRx(b []byte) {
|
||||||
s.update(b, true)
|
s.update(b, true)
|
||||||
}
|
}
|
||||||
@ -55,17 +38,17 @@ func (s *Statistics) UpdateRx(b []byte) {
|
|||||||
func (s *Statistics) update(b []byte, receive bool) {
|
func (s *Statistics) update(b []byte, receive bool) {
|
||||||
var p packet.Parsed
|
var p packet.Parsed
|
||||||
p.Decode(b)
|
p.Decode(b)
|
||||||
tuple := flowtrack.Tuple{Proto: p.IPProto, Src: p.Src, Dst: p.Dst}
|
conn := netlogtype.Connection{Proto: p.IPProto, Src: p.Src, Dst: p.Dst}
|
||||||
if receive {
|
if receive {
|
||||||
tuple.Src, tuple.Dst = tuple.Dst, tuple.Src
|
conn.Src, conn.Dst = conn.Dst, conn.Src
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if s.m == nil {
|
if s.m == nil {
|
||||||
s.m = make(map[flowtrack.Tuple]Counts)
|
s.m = make(map[netlogtype.Connection]netlogtype.Counts)
|
||||||
}
|
}
|
||||||
cnts := s.m[tuple]
|
cnts := s.m[conn]
|
||||||
if receive {
|
if receive {
|
||||||
cnts.RxPackets++
|
cnts.RxPackets++
|
||||||
cnts.RxBytes += uint64(len(b))
|
cnts.RxBytes += uint64(len(b))
|
||||||
@ -73,15 +56,15 @@ func (s *Statistics) update(b []byte, receive bool) {
|
|||||||
cnts.TxPackets++
|
cnts.TxPackets++
|
||||||
cnts.TxBytes += uint64(len(b))
|
cnts.TxBytes += uint64(len(b))
|
||||||
}
|
}
|
||||||
s.m[tuple] = cnts
|
s.m[conn] = cnts
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract extracts and resets the counters for all active connections.
|
// Extract extracts and resets the counters for all active connections.
|
||||||
// It must be called periodically otherwise the memory used is unbounded.
|
// It must be called periodically otherwise the memory used is unbounded.
|
||||||
func (s *Statistics) Extract() map[flowtrack.Tuple]Counts {
|
func (s *Statistics) Extract() map[netlogtype.Connection]netlogtype.Counts {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
m := s.m
|
m := s.m
|
||||||
s.m = make(map[flowtrack.Tuple]Counts)
|
s.m = make(map[netlogtype.Connection]netlogtype.Counts)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"tailscale.com/net/flowtrack"
|
|
||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
|
"tailscale.com/types/netlogtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testPacketV4(proto ipproto.Proto, srcAddr, dstAddr [4]byte, srcPort, dstPort, size uint16) (out []byte) {
|
func testPacketV4(proto ipproto.Proto, srcAddr, dstAddr [4]byte, srcPort, dstPort, size uint16) (out []byte) {
|
||||||
@ -48,17 +48,17 @@ func TestConcurrent(t *testing.T) {
|
|||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
var stats Statistics
|
var stats Statistics
|
||||||
var wants []map[flowtrack.Tuple]Counts
|
var wants []map[netlogtype.Connection]netlogtype.Counts
|
||||||
gots := make([]map[flowtrack.Tuple]Counts, runtime.NumCPU())
|
gots := make([]map[netlogtype.Connection]netlogtype.Counts, runtime.NumCPU())
|
||||||
var group sync.WaitGroup
|
var group sync.WaitGroup
|
||||||
for i := range gots {
|
for i := range gots {
|
||||||
group.Add(1)
|
group.Add(1)
|
||||||
go func(i int) {
|
go func(i int) {
|
||||||
defer group.Done()
|
defer group.Done()
|
||||||
gots[i] = make(map[flowtrack.Tuple]Counts)
|
gots[i] = make(map[netlogtype.Connection]netlogtype.Counts)
|
||||||
rn := rand.New(rand.NewSource(time.Now().UnixNano()))
|
rn := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
var p []byte
|
var p []byte
|
||||||
var t flowtrack.Tuple
|
var t netlogtype.Connection
|
||||||
for j := 0; j < 1000; j++ {
|
for j := 0; j < 1000; j++ {
|
||||||
delay := rn.Intn(10000)
|
delay := rn.Intn(10000)
|
||||||
if p == nil || rn.Intn(64) == 0 {
|
if p == nil || rn.Intn(64) == 0 {
|
||||||
@ -72,7 +72,7 @@ func TestConcurrent(t *testing.T) {
|
|||||||
dstPort := uint16(rand.Intn(16))
|
dstPort := uint16(rand.Intn(16))
|
||||||
size := uint16(64 + rand.Intn(1024))
|
size := uint16(64 + rand.Intn(1024))
|
||||||
p = testPacketV4(proto, srcAddr.As4(), dstAddr.As4(), srcPort, dstPort, size)
|
p = testPacketV4(proto, srcAddr.As4(), dstAddr.As4(), srcPort, dstPort, size)
|
||||||
t = flowtrack.Tuple{Proto: proto, Src: netip.AddrPortFrom(srcAddr, srcPort), Dst: netip.AddrPortFrom(dstAddr, dstPort)}
|
t = netlogtype.Connection{Proto: proto, Src: netip.AddrPortFrom(srcAddr, srcPort), Dst: netip.AddrPortFrom(dstAddr, dstPort)}
|
||||||
}
|
}
|
||||||
t2 := t
|
t2 := t
|
||||||
receive := rn.Intn(2) == 0
|
receive := rn.Intn(2) == 0
|
||||||
@ -102,17 +102,17 @@ func TestConcurrent(t *testing.T) {
|
|||||||
group.Wait()
|
group.Wait()
|
||||||
wants = append(wants, stats.Extract())
|
wants = append(wants, stats.Extract())
|
||||||
|
|
||||||
got := make(map[flowtrack.Tuple]Counts)
|
got := make(map[netlogtype.Connection]netlogtype.Counts)
|
||||||
want := make(map[flowtrack.Tuple]Counts)
|
want := make(map[netlogtype.Connection]netlogtype.Counts)
|
||||||
mergeMaps(got, gots...)
|
mergeMaps(got, gots...)
|
||||||
mergeMaps(want, wants...)
|
mergeMaps(want, wants...)
|
||||||
c.Assert(got, qt.DeepEquals, want)
|
c.Assert(got, qt.DeepEquals, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeMaps(dst map[flowtrack.Tuple]Counts, srcs ...map[flowtrack.Tuple]Counts) {
|
func mergeMaps(dst map[netlogtype.Connection]netlogtype.Counts, srcs ...map[netlogtype.Connection]netlogtype.Counts) {
|
||||||
for _, src := range srcs {
|
for _, src := range srcs {
|
||||||
for tuple, cnts := range src {
|
for conn, cnts := range src {
|
||||||
dst[tuple] = dst[tuple].Add(cnts)
|
dst[conn] = dst[conn].Add(cnts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
types/netlogtype/netlogtype.go
Normal file
58
types/netlogtype/netlogtype.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) 2022 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 netlogtype defines types for network logging.
|
||||||
|
package netlogtype
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tailscale.com/types/ipproto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message is the log message that captures network traffic.
|
||||||
|
type Message struct {
|
||||||
|
Start time.Time `json:"start"` // inclusive
|
||||||
|
End time.Time `json:"end"` // inclusive
|
||||||
|
|
||||||
|
VirtualTraffic []ConnectionCounts `json:"virtualTraffic,omitempty"`
|
||||||
|
SubnetTraffic []ConnectionCounts `json:"subnetTraffic,omitempty"`
|
||||||
|
ExitTraffic []ConnectionCounts `json:"exitTraffic,omitempty"`
|
||||||
|
PhysicalTraffic []ConnectionCounts `json:"physicalTraffic,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectionCounts is a flattened struct of both a connection and counts.
|
||||||
|
type ConnectionCounts struct {
|
||||||
|
Connection
|
||||||
|
Counts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection is a 5-tuple of proto, source and destination IP and port.
|
||||||
|
type Connection struct {
|
||||||
|
Proto ipproto.Proto `json:"proto,omitzero,omitempty"`
|
||||||
|
Src netip.AddrPort `json:"src,omitzero"`
|
||||||
|
Dst netip.AddrPort `json:"dst,omitzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Connection) IsZero() bool { return c == Connection{} }
|
||||||
|
|
||||||
|
// Counts are statistics about a particular connection.
|
||||||
|
type Counts struct {
|
||||||
|
TxPackets uint64 `json:"txPkts,omitzero,omitempty"`
|
||||||
|
TxBytes uint64 `json:"txBytes,omitzero,omitempty"`
|
||||||
|
RxPackets uint64 `json:"rxPkts,omitzero,omitempty"`
|
||||||
|
RxBytes uint64 `json:"rxBytes,omitzero,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Counts) IsZero() bool { return c == Counts{} }
|
||||||
|
|
||||||
|
// Add adds the counts from both c1 and c2.
|
||||||
|
func (c1 Counts) Add(c2 Counts) Counts {
|
||||||
|
c1.TxPackets += c2.TxPackets
|
||||||
|
c1.TxBytes += c2.TxBytes
|
||||||
|
c1.RxPackets += c2.RxPackets
|
||||||
|
c1.RxBytes += c2.RxBytes
|
||||||
|
return c1
|
||||||
|
}
|
@ -20,10 +20,9 @@ import (
|
|||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"tailscale.com/logpolicy"
|
"tailscale.com/logpolicy"
|
||||||
"tailscale.com/logtail"
|
"tailscale.com/logtail"
|
||||||
"tailscale.com/net/flowtrack"
|
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
"tailscale.com/net/tunstats"
|
|
||||||
"tailscale.com/smallzstd"
|
"tailscale.com/smallzstd"
|
||||||
|
"tailscale.com/types/netlogtype"
|
||||||
"tailscale.com/wgengine/router"
|
"tailscale.com/wgengine/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,29 +35,13 @@ const pollPeriod = 5 * time.Second
|
|||||||
// TODO(joetsai): Make *magicsock.Conn implement this interface.
|
// TODO(joetsai): Make *magicsock.Conn implement this interface.
|
||||||
type Device interface {
|
type Device interface {
|
||||||
SetStatisticsEnabled(bool)
|
SetStatisticsEnabled(bool)
|
||||||
ExtractStatistics() map[flowtrack.Tuple]tunstats.Counts
|
ExtractStatistics() map[netlogtype.Connection]netlogtype.Counts
|
||||||
}
|
}
|
||||||
|
|
||||||
type noopDevice struct{}
|
type noopDevice struct{}
|
||||||
|
|
||||||
func (noopDevice) SetStatisticsEnabled(bool) {}
|
func (noopDevice) SetStatisticsEnabled(bool) {}
|
||||||
func (noopDevice) ExtractStatistics() map[flowtrack.Tuple]tunstats.Counts { return nil }
|
func (noopDevice) ExtractStatistics() map[netlogtype.Connection]netlogtype.Counts { return nil }
|
||||||
|
|
||||||
// Message is the log message that captures network traffic.
|
|
||||||
type Message struct {
|
|
||||||
Start time.Time `json:"start"` // inclusive
|
|
||||||
End time.Time `json:"end"` // inclusive
|
|
||||||
VirtualTraffic []TupleCounts `json:"virtualTraffic,omitempty"`
|
|
||||||
SubnetTraffic []TupleCounts `json:"subnetTraffic,omitempty"`
|
|
||||||
ExitTraffic []TupleCounts `json:"exitTraffic,omitempty"`
|
|
||||||
PhysicalTraffic []TupleCounts `json:"physicalTraffic,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TupleCounts is a flattened struct of both a connection and counts.
|
|
||||||
type TupleCounts struct {
|
|
||||||
flowtrack.Tuple
|
|
||||||
tunstats.Counts
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger logs statistics about every connection.
|
// Logger logs statistics about every connection.
|
||||||
// At present, it only logs connections within a tailscale network.
|
// At present, it only logs connections within a tailscale network.
|
||||||
@ -192,8 +175,8 @@ func (nl *Logger) Startup(nodeID, domainID logtail.PrivateID, tun, sock Device)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func recordStatistics(logger *logtail.Logger, start, end time.Time, tunStats, sockStats map[flowtrack.Tuple]tunstats.Counts, addrs map[netip.Addr]bool, prefixes map[netip.Prefix]bool) {
|
func recordStatistics(logger *logtail.Logger, start, end time.Time, tunStats, sockStats map[netlogtype.Connection]netlogtype.Counts, addrs map[netip.Addr]bool, prefixes map[netip.Prefix]bool) {
|
||||||
m := Message{Start: start.UTC(), End: end.UTC()}
|
m := netlogtype.Message{Start: start.UTC(), End: end.UTC()}
|
||||||
|
|
||||||
classifyAddr := func(a netip.Addr) (isTailscale, withinRoute bool) {
|
classifyAddr := func(a netip.Addr) (isTailscale, withinRoute bool) {
|
||||||
// NOTE: There could be mis-classifications where an address is treated
|
// NOTE: There could be mis-classifications where an address is treated
|
||||||
@ -214,23 +197,23 @@ func recordStatistics(logger *logtail.Logger, start, end time.Time, tunStats, so
|
|||||||
dstIsTailscaleIP, dstWithinSubnet := classifyAddr(conn.Dst.Addr())
|
dstIsTailscaleIP, dstWithinSubnet := classifyAddr(conn.Dst.Addr())
|
||||||
switch {
|
switch {
|
||||||
case srcIsTailscaleIP && dstIsTailscaleIP:
|
case srcIsTailscaleIP && dstIsTailscaleIP:
|
||||||
m.VirtualTraffic = append(m.VirtualTraffic, TupleCounts{conn, cnts})
|
m.VirtualTraffic = append(m.VirtualTraffic, netlogtype.ConnectionCounts{Connection: conn, Counts: cnts})
|
||||||
case srcWithinSubnet || dstWithinSubnet:
|
case srcWithinSubnet || dstWithinSubnet:
|
||||||
m.SubnetTraffic = append(m.SubnetTraffic, TupleCounts{conn, cnts})
|
m.SubnetTraffic = append(m.SubnetTraffic, netlogtype.ConnectionCounts{Connection: conn, Counts: cnts})
|
||||||
default:
|
default:
|
||||||
const anonymize = true
|
const anonymize = true
|
||||||
if anonymize {
|
if anonymize {
|
||||||
if len(m.ExitTraffic) == 0 {
|
if len(m.ExitTraffic) == 0 {
|
||||||
m.ExitTraffic = []TupleCounts{{}}
|
m.ExitTraffic = []netlogtype.ConnectionCounts{{}}
|
||||||
}
|
}
|
||||||
m.ExitTraffic[0].Counts = m.ExitTraffic[0].Counts.Add(cnts)
|
m.ExitTraffic[0].Counts = m.ExitTraffic[0].Counts.Add(cnts)
|
||||||
} else {
|
} else {
|
||||||
m.ExitTraffic = append(m.ExitTraffic, TupleCounts{conn, cnts})
|
m.ExitTraffic = append(m.ExitTraffic, netlogtype.ConnectionCounts{Connection: conn, Counts: cnts})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for conn, cnts := range sockStats {
|
for conn, cnts := range sockStats {
|
||||||
m.PhysicalTraffic = append(m.PhysicalTraffic, TupleCounts{conn, cnts})
|
m.PhysicalTraffic = append(m.PhysicalTraffic, netlogtype.ConnectionCounts{Connection: conn, Counts: cnts})
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(m.VirtualTraffic)+len(m.SubnetTraffic)+len(m.ExitTraffic)+len(m.PhysicalTraffic) > 0 {
|
if len(m.VirtualTraffic)+len(m.SubnetTraffic)+len(m.ExitTraffic)+len(m.PhysicalTraffic) > 0 {
|
||||||
|
@ -11,9 +11,8 @@ import (
|
|||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"tailscale.com/logtail"
|
"tailscale.com/logtail"
|
||||||
"tailscale.com/net/flowtrack"
|
|
||||||
"tailscale.com/net/tunstats"
|
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
|
"tailscale.com/types/netlogtype"
|
||||||
"tailscale.com/util/must"
|
"tailscale.com/util/must"
|
||||||
"tailscale.com/wgengine/router"
|
"tailscale.com/wgengine/router"
|
||||||
)
|
)
|
||||||
@ -42,7 +41,7 @@ func (d *fakeDevice) SetStatisticsEnabled(enable bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
func (fakeDevice) ExtractStatistics() map[flowtrack.Tuple]tunstats.Counts {
|
func (fakeDevice) ExtractStatistics() map[netlogtype.Connection]netlogtype.Counts {
|
||||||
// TODO(dsnet): Add a test that verifies that statistics are correctly
|
// TODO(dsnet): Add a test that verifies that statistics are correctly
|
||||||
// extracted from the device and uploaded. Unfortunately,
|
// extracted from the device and uploaded. Unfortunately,
|
||||||
// we can't reliably run this test until we fix http://go/oss/5856.
|
// we can't reliably run this test until we fix http://go/oss/5856.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user