diff --git a/go.mod b/go.mod index 7df5c79..88d0994 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22.0 require ( github.com/beevik/ntp v1.3.1 + github.com/cloudflare/roughtime v0.0.0-20240215174733-272e9cc087a4 github.com/coreos/go-semver v0.3.1 github.com/google/go-cmp v0.6.0 github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e diff --git a/go.sum b/go.sum index 585b4a6..b7bb8b2 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudflare/roughtime v0.0.0-20240215174733-272e9cc087a4 h1:h3AYDwN79+xlvBbAKvGCOF9WMXN60HRQp904L49If4M= +github.com/cloudflare/roughtime v0.0.0-20240215174733-272e9cc087a4/go.mod h1:kUOtXhq8fgugSYCZu9NJk3WHWmtvo6SwbJ2FtootHxI= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/trusted_applet/main.go b/trusted_applet/main.go index cfc7440..0b6b9a1 100644 --- a/trusted_applet/main.go +++ b/trusted_applet/main.go @@ -243,18 +243,6 @@ func runWithNetworking(ctx context.Context) error { // the witness etc. below. coldStart := time.Now().Before(time.Date(2024, time.January, 1, 0, 0, 0, 0, time.UTC)) - select { - case <-runNTP(ctx): - if coldStart { - klog.Info("Large NTP date change detected, waiting for network to restart...") - // Give a bit of space so we don't spin while we wait for DHCP to do its thing. - time.Sleep(time.Second) - return nil - } - case <-ctx.Done(): - return ctx.Err() - } - // TODO(al): figure out where & how frequently we should be doing this. // For now, since we're still developing/testing this, we'll be very aggressive // checking for and installing updates. @@ -290,6 +278,19 @@ func runWithNetworking(ctx context.Context) error { } }() + select { + case <-runRoughTime(ctx): + //case <-runNTP(ctx): + case <-ctx.Done(): + return ctx.Err() + } + if coldStart { + klog.Info("Large NTP date change detected, waiting for network to restart...") + // Give a bit of space so we don't spin while we wait for DHCP to do its thing. + time.Sleep(time.Second) + return nil + } + listenCfg := &net.ListenConfig{} sshListener, err := listenCfg.Listen(ctx, "tcp", ":22") diff --git a/trusted_applet/net.go b/trusted_applet/net.go index 421a5fb..7fe5ee4 100644 --- a/trusted_applet/net.go +++ b/trusted_applet/net.go @@ -39,6 +39,8 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "github.com/beevik/ntp" + "github.com/cloudflare/roughtime" + "github.com/cloudflare/roughtime/client" "github.com/transparency-dev/armored-witness-applet/third_party/dhcp" "github.com/transparency-dev/armored-witness-os/api" "go.mercari.io/go-dnscache" @@ -272,6 +274,53 @@ func runNTP(ctx context.Context) chan bool { return r } +// runRoughTime starts periodically attempting to sync time with RoughTime. +// Returns a channel which becomes closed once we have obtained an initial time. +func runRoughTime(ctx context.Context) chan bool { + log.Print("Starting roughtime") + r := make(chan bool) + rtMaxRadius := 10 * time.Second + + go func(ctx context.Context) { + // Get the system clock's current time, then immediately query the Roughtime + // servers. + t0 := time.Now() + + // i specifies the interval between checking in with the RoughTime servers. + i := 10 * time.Second // time.Hour + for { + log.Print("Starting roughtime loop") + select { + case <-ctx.Done(): + return + case <-time.After(i): + } + + log.Print("Roughtime querying...") + res := client.Do(roughtime.Ecosystem, client.DefaultQueryAttempts, 10*time.Second, nil) + + // Compute the average difference between t0 and the time reported by each + // server, rejecting those responses whose radii are too large. (Note that + // this accounts for network delay.) + delta, err := client.AvgDeltaWithRadiusThresh(res, t0, rtMaxRadius) + if err != nil { + log.Printf("Failed to calculate RoughTime average delta: %v", err) + } + rt := time.Now().Add(delta) + log.Printf("RoughTime: %v", rt) + applet.ARM.SetTimer(rt.UnixNano()) + + if r != nil { + // Signal that we've got an initial time. + close(r) + r = nil + } + } + }(ctx) + + return r +} + func dnsCmd(_ *term.Terminal, arg []string) (res string, err error) { if iface == nil { return "", errors.New("network is unavailable")