ALL

Solo para leer y verificar. No puedes copiar, usar, modificar ni redistribuir este código. Aviso completo en la página principal.

tunnel/statement_test.go

SHA-256: 68d4c6d268cea8f14b9238587ab3df73c4835922388b7437626462b45b87c42c
98 líneas · 3914 bytes · Ver en GitHub

1package main
2
3import (
4 "strings"
5 "testing"
6 "time"
7)
8
9// STATEMENT: the control plane's signed access statement, forwarded as it is, right after the OK, before any stream can be opened on the connection.
10
11const testStatement = "eyJhbGciOiJFZERTQSIsInR5cCI6ImRldmljZS1hY2Nlc3MifQ.eyJzZXEiOjEyMzQ1fQ.c2lnbmF0dXJlLXNpZ25hdHVyZS1zaWduYXR1cmUtc2lnbmF0dXJl"
12
13func statementPlan(e *testEnv, d *testDevice, access string) *devicePlan {
14 return &devicePlan{host: d.host, answer: func(int) AuthorizeResponse {
15 now := e.now()
16 return AuthorizeResponse{DeviceID: d.id, Label: d.label, Host: d.host, Status: statusActive, Plan: "paid", ValidUntil: now.Unix() + 3600, ServerTime: now.Unix(),
17 Policy: okPolicy{20, 45, 1800, 14400, 300}, Nodes: []any{}, Access: access}
18 }}
19}
20
21func TestStatement_IsForwardedUnchangedRightAfterTheOKOfAHelloAndOfARenew(t *testing.T) {
22 e := newTestEnv(t, nil)
23 d := e.newDeviceNoPlan()
24 e.cp.set(d.id, statementPlan(e, d, testStatement))
25 dc := e.connect(d)
26 dc.session = e.session(d, nil)
27 dc.send("HELLO 2 " + dc.session)
28 m, _ := parseLine(dc.recv(), dirN2D)
29 dc.send("PROOF " + e.proof(d, dc.session, m.str("nonce"), nil))
30 if line := dc.recv(); !strings.HasPrefix(line, "OK ") {
31 t.Fatalf("%q", line)
32 }
33 if line := dc.recv(); line != "STATEMENT "+testStatement {
34 t.Fatalf("the line after the OK: %q", line)
35 }
36 // a client stream opened now reaches a device that has the statement already: the OPEN comes after it
37 ds := dc.serve(nil)
38 c, err := e.clientTLS(d)
39 if err != nil {
40 t.Fatal(err)
41 }
42 _ = c.Close()
43 if ds.openCount() != 1 {
44 t.Fatalf("opens %d", ds.openCount())
45 }
46
47 // and at every RENEW, with the control plane's newer statement
48 const newer = "eyJhbGciOiJFZERTQSJ9.eyJzZXEiOjEyMzQ2fQ.c2lnbmF0dXJl"
49 e.cp.set(d.id, statementPlan(e, d, newer))
50 if r := dc.renew(); !strings.HasPrefix(r, "OK ") {
51 t.Fatalf("%q", r)
52 }
53 eventually(t, "the newer statement", 2*time.Second, func() bool { return containsLine(ds.otherLines(), "STATEMENT "+newer) })
54 e.checkTranscript()
55}
56
57func TestStatement_NoStatementNoLineAndABadOneIsDroppedNeverRelayedNeverAPanic(t *testing.T) {
58 e := newTestEnv(t, nil)
59 for name, access := range map[string]string{
60 "none": "",
61 "not a jws": "this is not a token",
62 "two segments": "aaaa.bbbb",
63 "too long": strings.Repeat("a", policyData.Protocol.StatementLineMaxBytes) + ".b.c",
64 "a space in it": "aaaa.bb bb.cccc",
65 } {
66 d := e.newDeviceNoPlan()
67 e.cp.set(d.id, statementPlan(e, d, access))
68 dc := e.connectOK(d)
69 ds := dc.serve(nil)
70 time.Sleep(60 * time.Millisecond)
71 for _, line := range ds.otherLines() {
72 if strings.HasPrefix(line, "STATEMENT") {
73 t.Errorf("%s: forwarded %.40q", name, line)
74 }
75 }
76 if !e.srv.Online(d.host) {
77 t.Errorf("%s: the connection did not come up", name)
78 }
79 }
80 // the longest line the grammar allows is forwarded
81 d := e.newDeviceNoPlan()
82 longest := strings.Repeat("a", policyData.Protocol.StatementLineMaxBytes-len("STATEMENT ")-1-4) + ".b.c"
83 if statementLine(longest) == "" {
84 t.Fatal("the longest statement the grammar allows was refused")
85 }
86 e.cp.set(d.id, statementPlan(e, d, longest))
87 dc := e.connectOK(d)
88 ds := dc.serve(nil)
89 eventually(t, "the longest statement", 3*time.Second, func() bool { return containsLine(ds.otherLines(), "STATEMENT "+longest) })
90}
91
92func TestStatement_AnAccessTheControlPlaneSendsThatTheGrammarRefusesIsABadAnswerOverHTTP(t *testing.T) {
93 bad := `{"ok":true,"v":1,"device_id":"` + randomHex(16) + `","label":"` + label20() + `","host":"x","status":"active","plan":"paid","valid_until":1793000000,"server_time":1793000000,` +
94 `"policy":{"ping_interval_s":20,"dead_peer_s":45,"stream_idle_s":1800,"stream_max_age_s":14400,"renew_before_valid_until_s":300},"nodes":[],"access":"not a jws"}`
95 if _, err := parseAuthorizeResponse([]byte(bad)); err == nil {
96 t.Fatal("an answer with a statement that is not a JWS was accepted")
97 }
98}