-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck.go
More file actions
121 lines (101 loc) · 2.51 KB
/
Copy pathcheck.go
File metadata and controls
121 lines (101 loc) · 2.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"context"
"crypto/tls"
"math"
"net"
"strings"
"sync"
"time"
"go.uber.org/zap"
)
type certErrors struct {
commonName string
errs []error
}
type hostResult struct {
address string
err error
certs []certErrors
}
func processHosts(ctx context.Context) {
results := make(chan hostResult)
var wg sync.WaitGroup
wg.Add(config.Concurrency)
for i := 0; i < config.Concurrency; i++ {
go func() {
processQueue(ctx, hostQueue, results)
wg.Done()
}()
}
go func() {
wg.Wait()
close(results)
}()
for r := range results {
if r.err != nil {
logger.Warn("cert err", zap.Error(r.err), zap.String("address", r.address))
continue
}
for _, cert := range r.certs {
for _, err := range cert.errs {
logger.Warn("cert err", zap.Error(err), zap.String("address", r.address))
}
}
}
}
func processQueue(ctx context.Context, hosts <-chan Host, results chan<- hostResult) {
hostQueueLen.WithLabelValues(config.ListenAddress).Set(float64(len(hostQueue)))
ticker := time.NewTicker(time.Minute * 5)
defer ticker.Stop()
for host := range hosts {
select {
case results <- checkHost(host):
case <-ticker.C:
hostQueueLen.WithLabelValues(config.ListenAddress).Set(float64(len(hostQueue)))
case <-ctx.Done():
logger.Info("proccessQueue ctx done")
return
}
}
}
func checkHost(host Host) (result hostResult) {
logger.Info("checkhost", zap.String("address", host.Address))
result = hostResult{
address: host.Address,
certs: []certErrors{},
}
var address = host.Address
if !strings.Contains(address, ":") {
address += ":443"
}
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 10 * time.Second}, "tcp", address, nil)
if err != nil {
result.err = err
return
}
defer conn.Close()
var notAfterUnix = math.MaxInt64
checkedCerts := make(map[string]struct{})
for _, chain := range conn.ConnectionState().VerifiedChains {
for _, cert := range chain {
if _, checked := checkedCerts[string(cert.Signature)]; checked {
continue
}
checkedCerts[string(cert.Signature)] = struct{}{}
cErrs := []error{}
// Check the expiration, find out the shortest expiration in the chain
if !cert.NotAfter.IsZero() && int(cert.NotAfter.Unix()) < notAfterUnix {
notAfterUnix = int(cert.NotAfter.Unix())
}
result.certs = append(result.certs, certErrors{
commonName: cert.Subject.CommonName,
errs: cErrs,
})
}
}
for _, e := range host.AlertEmails {
notAfter.WithLabelValues(address, e).Set(float64(notAfterUnix))
}
return
}