Files
mesh-catalog/modules/netcheck/cmd/netcheck/tunnel_test.go
T
jschoubben b1280f81a2
mesh/merge-gate pass: builds netcheck → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
Read the tunnel through sudo where the tool runner is not root (hq issue 522)
On novox the tool runner runs as the operator's account, and wg show
answered 'Operation not permitted'. Root is the module's concern: the
command runs as given when the process is root, else through sudo -n,
which the sudo module allows the runtime's account, as nftables does.
2026-10-12 00:05:04 +02:00

91 lines
3.2 KiB
Go

package main
import (
"encoding/json"
"strings"
"testing"
"time"
)
const privateKey = "aPRIVATEkeyThatMustNeverBeSaidAAAAAAAAAAAA="
func dump(now time.Time) string {
fresh := now.Add(-40 * time.Second).Unix()
old := now.Add(-10 * time.Minute).Unix()
return privateKey + "\tPUBkeyOfTheHubAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t51820\toff\n" +
"PUBkeyAceAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t(none)\t84.193.151.6:40122\t10.10.0.2/32\t" + itoa(old) + "\t1000\t2000\t25\n" +
"PUBkeyShanksAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t(none)\t84.193.151.6:51820\t10.10.0.3/32\t" + itoa(fresh) + "\t3000\t4000\toff\n" +
"PUBkeyNewAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t(none)\t(none)\t10.10.0.9/32\t0\t0\t0\toff\n"
}
func itoa(n int64) string { b, _ := json.Marshal(n); return string(b) }
func TestTheDumpIsReadAndNoKeyIsSaid(t *testing.T) {
now := time.Date(2026, 10, 11, 22, 0, 0, 0, time.UTC)
tun, err := parseDump(dump(now), now)
if err != nil {
t.Fatal(err)
}
raw, _ := json.Marshal(tun)
if strings.Contains(string(raw), "PRIVATE") || strings.Contains(string(raw), "PUBkey") {
t.Fatalf("a key is said: %s", raw)
}
if tun.ListenPort != 51820 || len(tun.Peers) != 3 {
t.Fatalf("got %+v", tun)
}
ace, shanks, fresh := tun.Peers[0], tun.Peers[1], tun.Peers[2]
if ace.Endpoint != "84.193.151.6:40122" || ace.HandshakeAge != 600 || !ace.Stale || ace.Keepalive != "25s" || ace.Sent != 2000 {
t.Errorf("ace %+v", ace)
}
if shanks.Stale || shanks.HandshakeAge != 40 || shanks.Keepalive != "" {
t.Errorf("shanks %+v", shanks)
}
if fresh.Endpoint != "" || fresh.HandshakeAge != -1 || !fresh.Stale || fresh.Handshake != "" {
t.Errorf("a peer never heard from %+v", fresh)
}
}
func TestADumpOfAnotherShapeIsRefused(t *testing.T) {
if _, err := parseDump("", time.Now()); err == nil {
t.Error("an empty answer was taken")
}
if _, err := parseDump("a\tb\t1\toff\nshort\tline\n", time.Now()); err == nil {
t.Error("a short peer line was taken")
}
}
func TestEndpointsAndHandshakesAreSaidWhenTheyChange(t *testing.T) {
var said []string
emit := func(event string, body any) error {
b := body.(map[string]any)
said = append(said, event+":"+b["endpoint"].(string)+":"+asString(b["from"]))
return nil
}
p := func(endpoint string, stale bool) Tunnel {
return Tunnel{Peers: []Peer{{AllowedIPs: []string{"10.10.0.2/32"}, Endpoint: endpoint, Stale: stale}}}
}
var w tunnelWatch
w.look(p("1.2.3.4:1", true), emit) // silent: the first look
w.look(p("1.2.3.4:1", true), emit)
w.look(p("1.2.3.4:2", false), emit)
w.look(p("1.2.3.4:2", true), emit)
want := "tunnel.endpoint-changed:1.2.3.4:2:1.2.3.4:1,tunnel.handshake-fresh:1.2.3.4:2:,tunnel.handshake-stale:1.2.3.4:2:"
if strings.Join(said, ",") != want {
t.Errorf("said %v", said)
}
}
func asString(v any) string {
s, _ := v.(string)
return s
}
func TestTheTunnelIsReadAsRootOrThroughSudo(t *testing.T) {
if p, a := escalated("wg", []string{"show", "mesh0", "dump"}, 0); p != "wg" || strings.Join(a, " ") != "show mesh0 dump" {
t.Errorf("as root: %s %v", p, a)
}
if p, a := escalated("wg", []string{"show", "mesh0", "dump"}, 1000); p != "sudo" || strings.Join(a, " ") != "-n wg show mesh0 dump" {
t.Errorf("as an account: %s %v", p, a)
}
}