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
| 1 | package main |
| 2 | |
| 3 | import ( |
| 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. |
| 14 | func 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 | |
| 46 | func 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 | } |