|
|
|
@ -9,7 +9,9 @@ import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
crand "crypto/rand"
|
|
|
|
|
"crypto/x509"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"html"
|
|
|
|
@ -33,11 +35,21 @@ var (
|
|
|
|
|
listen = flag.String("listen", ":8030", "HTTP listen address")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// certReissueAfter is the time after which we expect all certs to be
|
|
|
|
|
// reissued, at minimum.
|
|
|
|
|
//
|
|
|
|
|
// This is currently set to the date of the LetsEncrypt ALPN revocation event of Jan 2022:
|
|
|
|
|
// https://community.letsencrypt.org/t/questions-about-renewing-before-tls-alpn-01-revocations/170449
|
|
|
|
|
//
|
|
|
|
|
// If there's another revocation event, bump this again.
|
|
|
|
|
var certReissueAfter = time.Unix(1643226768, 0)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
mu sync.Mutex
|
|
|
|
|
state = map[nodePair]pairStatus{}
|
|
|
|
|
lastDERPMap *tailcfg.DERPMap
|
|
|
|
|
lastDERPMapAt time.Time
|
|
|
|
|
certs = map[string]*x509.Certificate{}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
@ -46,6 +58,12 @@ func main() {
|
|
|
|
|
log.Fatal(http.ListenAndServe(*listen, http.HandlerFunc(serve)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setCert(name string, cert *x509.Certificate) {
|
|
|
|
|
mu.Lock()
|
|
|
|
|
defer mu.Unlock()
|
|
|
|
|
certs[name] = cert
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type overallStatus struct {
|
|
|
|
|
good, bad []string
|
|
|
|
|
}
|
|
|
|
@ -93,6 +111,27 @@ func getOverallStatus() (o overallStatus) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var subjs []string
|
|
|
|
|
for k := range certs {
|
|
|
|
|
subjs = append(subjs, k)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(subjs)
|
|
|
|
|
|
|
|
|
|
soon := time.Now().Add(14 * 24 * time.Hour) // in 2 weeks; autocert does 30 days by default
|
|
|
|
|
for _, s := range subjs {
|
|
|
|
|
cert := certs[s]
|
|
|
|
|
if cert.NotBefore.Before(certReissueAfter) {
|
|
|
|
|
o.addBadf("cert %q needs reissuing; NotBefore=%v", s, cert.NotBefore.Format(time.RFC3339))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if cert.NotAfter.Before(soon) {
|
|
|
|
|
o.addBadf("cert %q expiring soon (%v); wasn't auto-refreshed", s, cert.NotAfter.Format(time.RFC3339))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
o.addGoodf("cert %q good %v - %v", s, cert.NotBefore.Format(time.RFC3339), cert.NotAfter.Format(time.RFC3339))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -359,6 +398,21 @@ func newConn(ctx context.Context, dm *tailcfg.DERPMap, n *tailcfg.DERPNode) (*de
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cs, ok := dc.TLSConnectionState()
|
|
|
|
|
if !ok {
|
|
|
|
|
dc.Close()
|
|
|
|
|
return nil, errors.New("no TLS state")
|
|
|
|
|
}
|
|
|
|
|
if len(cs.PeerCertificates) == 0 {
|
|
|
|
|
dc.Close()
|
|
|
|
|
return nil, errors.New("no peer certificates")
|
|
|
|
|
}
|
|
|
|
|
if cs.ServerName != n.HostName {
|
|
|
|
|
dc.Close()
|
|
|
|
|
return nil, fmt.Errorf("TLS server name %q != derp hostname %q", cs.ServerName, n.HostName)
|
|
|
|
|
}
|
|
|
|
|
setCert(cs.ServerName, cs.PeerCertificates[0])
|
|
|
|
|
|
|
|
|
|
errc := make(chan error, 1)
|
|
|
|
|
go func() {
|
|
|
|
|
m, err := dc.Recv()
|
|
|
|
|