ALL

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

tunnel/stale_keys_grace_test.go

SHA-256: 2f26fd478d5abf416f6ee3d8fa5e062de4dc6849a79ba6730c3d0054a1770586
62 líneas · 2885 bytes · Ver en GitHub

1package main
2
3import (
4 "crypto/ed25519"
5 "crypto/rand"
6 "strings"
7 "testing"
8 "time"
9)
10
11// A paid device whose RENEW is refused only because the node cannot read the control plane's keys (they are older than the policy's window: the control plane is away) is
12// a device the control plane did not answer: it gets the grace, as a device whose authorize call failed does. Before, the connection closed at valid_until (the chaos suite's
13// real-device outage case): the node refused the session without recording that the control plane was down.
14func TestOutage_ARenewRefusedBecauseTheKeysAreStaleStillEarnsThePaidGrace(t *testing.T) {
15 clk := newFakeClock()
16 // the node's own record of failed authorize calls must not be what gives the grace here (no authorize call is made: the session is refused before one): with it out of the way,
17 // only the refusal itself can say that the control plane is away
18 e, cp := httpNode(t, clk, func(c *Config) { c.DownQuiet = 1000 * time.Hour })
19 o := connectWithStream(t, e, devicePlan{validFor: 3 * time.Hour})
20 validUntil := o.validUntil()
21 cp.setDown(503)
22 e.pass(31*time.Minute, time.Minute) // the node's set of keys is now older than the window it may vouch for
23
24 _, newPriv, _ := ed25519.GenerateKey(rand.Reader)
25 const newKID = "cp-rotated-while-away"
26 o.conn.session = e.sessionSignedBy(newPriv, o.d, func(h, c map[string]any) { h["kid"] = newKID })
27 o.conn.send("RENEW " + o.conn.session)
28 if line := o.conn.recv(); line != "ERR control_unavailable" {
29 t.Fatalf("a RENEW with a key the node cannot vouch for: %q", line)
30 }
31 if !strings.Contains(e.logs.String(), `"reason":"unknown_kid"`) {
32 t.Fatal("the refusal was not the stale-keys one")
33 }
34
35 e.pass(validUntil.Sub(e.now())+time.Second, 30*time.Second)
36 if o.closed("CLOSE") || o.stream.dead(50*time.Millisecond) {
37 t.Fatal("a paid device was cut at valid_until although the control plane was away")
38 }
39 if !strings.Contains(e.logs.String(), `"msg":"control_grace"`) {
40 t.Fatal("no grace was given")
41 }
42 e.pass(policyDataGrace(), time.Minute)
43 eventually(t, "CLOSE expired once the grace is over", 3*time.Second, func() bool { return o.closed("CLOSE expired") })
44}
45
46func TestOutage_AHelloRefusedBecauseTheKeysAreStaleGivesNoGraceToAnythingBecauseThereIsNoConnectionYet(t *testing.T) {
47 clk := newFakeClock()
48 e, cp := httpNode(t, clk, nil)
49 cp.setDown(503)
50 e.pass(31*time.Minute, time.Minute)
51 d := e.newDevice()
52 _, newPriv, _ := ed25519.GenerateKey(rand.Reader)
53 line := e.connect(d).hello(func() string {
54 return e.sessionSignedBy(newPriv, d, func(h, c map[string]any) { h["kid"] = "cp-unknown" })
55 }, func(s, n string) string { return e.proof(d, s, n, nil) })
56 if line != "ERR control_unavailable" {
57 t.Fatalf("a HELLO on stale keys: %q", line)
58 }
59 if strings.Contains(e.logs.String(), `"msg":"control_grace"`) {
60 t.Fatal("a grace for a connection that never existed")
61 }
62}