package main
import (
"crypto/tls"
"fmt"
"net"
"sync"
"time"
)
type CertInfo struct {
Domain string
ExpiryTime time.Time
DaysLeft int
Error error
}
func CheckDomain(domain string, wg *sync.WaitGroup, resultChan chan<- CertInfo) {
defer wg.Done()
info := CertInfo{Domain: domain}
conn, err := tls.DialWithDialer(
&net.Dialer{Timeout: 10 * time.Second},
"tcp",
domain+":443",
&tls.Config{InsecureSkipVerify: true},
)
if err != nil {
info.Error = err
resultChan <- info
return
}
defer conn.Close()
state := conn.ConnectionState()
if len(state.PeerCertificates) == 0 {
info.Error = fmt.Errorf("no certificates found")
resultChan <- info
return
}
cert := state.PeerCertificates[0]
info.ExpiryTime = cert.NotAfter
info.DaysLeft = int(time.Until(cert.NotAfter).Hours() / 24)
resultChan <- info
}
func CheckDomainsConcurrently(domains []string) []CertInfo {
var wg sync.WaitGroup
resultChan := make(chan CertInfo, len(domains))
results := make([]CertInfo, 0, len(domains))
for _, domain := range domains {
wg.Add(1)
go CheckDomain(domain, &wg, resultChan)
}
wg.Wait()
close(resultChan)
for info := range resultChan {
results = append(results, info)
}
return results
}
func main() {
domains := []string{
"www.cnblogs.com",
"www.baidu.com",
"expired.badssl.com",
"google.com",
}
results := CheckDomainsConcurrently(domains)
for _, info := range results {
if info.Error != nil {
fmt.Printf("%-25s ERROR: %v\n", info.Domain, info.Error)
} else {
fmt.Printf("%-25s Expires: %s Days left: %d\n", info.Domain, info.ExpiryTime.Format("2006-01-02 15:04:05"), info.DaysLeft)
}
}
}
类似这种
www.baidu.com Expires: 2025-08-09 01:41:01 Days left: 21
www.cnblogs.com Expires: 2026-02-16 23:59:59 Days left: 213
expired.badssl.com Expires: 2015-04-12 23:59:59 Days left: -3749
google.com ERROR: dial tcp 46.82.174.69:443: i/o timeout