Skip to content

Commit 08b3f5f

Browse files
committed
wgengine/wgint: add shady temporary package to get at wireguard internals
For tailscale#5451 Change-Id: I43482289e323ba9142a446d551ab7a94a467c43a Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
1 parent 66d7d25 commit 08b3f5f

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

wgengine/wgint/wgint.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package wgint provides somewhat shady access to wireguard-go
6+
// internals that don't (yet) have public APIs.
7+
package wgint
8+
9+
import (
10+
"reflect"
11+
"sync/atomic"
12+
"unsafe"
13+
14+
"golang.zx2c4.com/wireguard/device"
15+
)
16+
17+
var (
18+
offHandshake = getPeerStatsOffset("lastHandshakeNano")
19+
offRxBytes = getPeerStatsOffset("rxBytes")
20+
offTxBytes = getPeerStatsOffset("txBytes")
21+
)
22+
23+
func getPeerStatsOffset(name string) uintptr {
24+
peerType := reflect.TypeOf(device.Peer{})
25+
sf, ok := peerType.FieldByName("stats")
26+
if !ok {
27+
panic("no stats field in device.Peer")
28+
}
29+
if sf.Type.Kind() != reflect.Struct {
30+
panic("stats field is not a struct")
31+
}
32+
base := sf.Offset
33+
34+
st := sf.Type
35+
field, ok := st.FieldByName(name)
36+
if !ok {
37+
panic("no " + name + " field in device.Peer.stats")
38+
}
39+
if field.Type.Kind() != reflect.Int64 && field.Type.Kind() != reflect.Uint64 {
40+
panic("unexpected kind of " + name + " field in device.Peer.stats")
41+
}
42+
return base + field.Offset
43+
}
44+
45+
// PeerLastHandshakeNano returns the last handshake time in nanoseconds since the
46+
// unix epoch.
47+
func PeerLastHandshakeNano(peer *device.Peer) int64 {
48+
return atomic.LoadInt64((*int64)(unsafe.Add(unsafe.Pointer(peer), offHandshake)))
49+
}
50+
51+
// PeerRxBytes returns the number of bytes received from this peer.
52+
func PeerRxBytes(peer *device.Peer) uint64 {
53+
return atomic.LoadUint64((*uint64)(unsafe.Add(unsafe.Pointer(peer), offRxBytes)))
54+
}
55+
56+
// PeerTxBytes returns the number of bytes sent to this peer.
57+
func PeerTxBytes(peer *device.Peer) uint64 {
58+
return atomic.LoadUint64((*uint64)(unsafe.Add(unsafe.Pointer(peer), offTxBytes)))
59+
}

wgengine/wgint/wgint_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package wgint
6+
7+
import (
8+
"testing"
9+
10+
"golang.zx2c4.com/wireguard/device"
11+
)
12+
13+
func TestPeerStats(t *testing.T) {
14+
peer := new(device.Peer)
15+
if got := PeerLastHandshakeNano(peer); got != 0 {
16+
t.Errorf("PeerLastHandshakeNano = %v, want 0", got)
17+
}
18+
if got := PeerRxBytes(peer); got != 0 {
19+
t.Errorf("PeerRxBytes = %v, want 0", got)
20+
}
21+
if got := PeerTxBytes(peer); got != 0 {
22+
t.Errorf("PeerTxBytes = %v, want 0", got)
23+
}
24+
}

0 commit comments

Comments
 (0)