11package strongswan
22
33import (
4+ "crypto/x509"
45 "strings"
6+ "time"
57
68 "github.com/prometheus/client_golang/prometheus"
79 "github.com/strongswan/govici/vici"
@@ -55,6 +57,9 @@ type Collector struct {
5557 saEstablishSecs * prometheus.Desc
5658 saRekeySecs * prometheus.Desc
5759 saLifetimeSecs * prometheus.Desc
60+
61+ crtCnt * prometheus.Desc
62+ crtValid * prometheus.Desc
5863}
5964
6065func NewCollector (viciClientFn viciClientFn ) * Collector {
@@ -198,6 +203,17 @@ func NewCollector(viciClientFn viciClientFn) *Collector {
198203 "Seconds until the lifetime expires" ,
199204 []string {"ike_name" , "ike_id" , "child_name" , "child_id" }, nil ,
200205 ),
206+
207+ crtCnt : prometheus .NewDesc (
208+ prefix + "crt_count" ,
209+ "Number of X509 certificates" ,
210+ nil , nil ,
211+ ),
212+ crtValid : prometheus .NewDesc (
213+ prefix + "crt_valid" ,
214+ "X509 certificate validity" ,
215+ []string {"serial_number" , "subject" , "alternate_names" , "not_before" , "not_after" }, nil ,
216+ ),
201217 }
202218}
203219
@@ -230,6 +246,9 @@ func (c *Collector) Describe(ch chan<- *prometheus.Desc) {
230246 ch <- c .saEstablishSecs
231247 ch <- c .saRekeySecs
232248 ch <- c .saLifetimeSecs
249+
250+ ch <- c .crtCnt
251+ ch <- c .crtValid
233252}
234253
235254func (c * Collector ) Collect (ch chan <- prometheus.Metric ) {
@@ -240,6 +259,11 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
240259 prometheus .GaugeValue ,
241260 float64 (0 ),
242261 )
262+ ch <- prometheus .MustNewConstMetric (
263+ c .crtCnt ,
264+ prometheus .GaugeValue ,
265+ float64 (0 ),
266+ )
243267 return
244268 }
245269 ch <- prometheus .MustNewConstMetric (
@@ -253,6 +277,18 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
253277 c .collectIkeChildMetrics (ikeSa .Name , ikeSa .UniqueID , child , ch )
254278 }
255279 }
280+
281+ crts , err := c .listCrts ()
282+ if err != nil {
283+ ch <- prometheus .MustNewConstMetric (
284+ c .crtCnt ,
285+ prometheus .GaugeValue ,
286+ float64 (0 ),
287+ )
288+ return
289+ }
290+
291+ c .collectCrtMetrics (crts , ch )
256292}
257293
258294func (c * Collector ) collectIkeMetrics (ikeSa IkeSa , ch chan <- prometheus.Metric ) {
@@ -475,3 +511,122 @@ func viciStateToInt(v string) connectionStatus {
475511 return unknown
476512 }
477513}
514+
515+ func alternateNames (cert * x509.Certificate ) string {
516+ const AlternateNamesTypes = 4
517+ altNames := make ([]string , 0 , AlternateNamesTypes )
518+
519+ dnsNames := make ([]string , 0 , len (cert .DNSNames ))
520+ for _ , dns := range cert .DNSNames {
521+ dnsNames = append (dnsNames , "DNS=" + dns )
522+ }
523+ dnsMerged := strings .Join (dnsNames , "+" )
524+ if dnsMerged != "" {
525+ altNames = append (altNames , dnsMerged )
526+ }
527+
528+ emails := make ([]string , 0 , len (cert .EmailAddresses ))
529+ for _ , dns := range cert .EmailAddresses {
530+ emails = append (emails , "EM=" + dns )
531+ }
532+ emailsMerged := strings .Join (emails , "+" )
533+ if emailsMerged != "" {
534+ altNames = append (altNames , emailsMerged )
535+ }
536+
537+ ips := make ([]string , 0 , len (cert .IPAddresses ))
538+ for _ , ip := range cert .IPAddresses {
539+ ips = append (ips , "IP=" + ip .String ())
540+ }
541+ ipsMerged := strings .Join (ips , "+" )
542+ if ipsMerged != "" {
543+ altNames = append (altNames , ipsMerged )
544+ }
545+
546+ uris := make ([]string , 0 , len (cert .URIs ))
547+ for _ , uri := range cert .URIs {
548+ uris = append (uris , "URI=" + uri .String ())
549+ }
550+ urisMerged := strings .Join (uris , "+" )
551+ if urisMerged != "" {
552+ altNames = append (altNames , urisMerged )
553+ }
554+
555+ return strings .Join (altNames , "," )
556+ }
557+
558+ func (c * Collector ) collectCrtMetrics (crts []Crt , ch chan <- prometheus.Metric ) {
559+ var x509Crts uint
560+
561+ for _ , crt := range crts {
562+ if crt .Type != "X509" {
563+ continue
564+ }
565+
566+ cert , err := x509 .ParseCertificate ([]byte (crt .Data ))
567+ if err != nil {
568+ log .Logger .Warnf ("Certificate parse error: %v" , err )
569+ continue
570+ }
571+
572+ now := time .Now ()
573+ valid := 0
574+ if now .After (cert .NotBefore ) && now .Before (cert .NotAfter ) {
575+ valid = 1
576+ }
577+
578+ ch <- prometheus .MustNewConstMetric (
579+ c .crtValid ,
580+ prometheus .GaugeValue ,
581+ float64 (valid ),
582+ cert .SerialNumber .String (),
583+ cert .Subject .String (),
584+ alternateNames (cert ),
585+ cert .NotBefore .Format (time .RFC3339 ),
586+ cert .NotAfter .Format (time .RFC3339 ),
587+ )
588+
589+ x509Crts ++
590+ }
591+
592+ ch <- prometheus .MustNewConstMetric (
593+ c .crtCnt ,
594+ prometheus .GaugeValue ,
595+ float64 (x509Crts ),
596+ )
597+ }
598+
599+ func (c * Collector ) listCrts () ([]Crt , error ) {
600+ s , err := c .viciClientFn ()
601+ if err != nil {
602+ return nil , err
603+ }
604+ defer s .Close ()
605+
606+ req := vici .NewMessage ()
607+ req .Set ("type" , "X509" )
608+ req .Set ("flag" , "ANY" )
609+
610+ msgs , err := s .StreamedCommandRequest ("list-certs" , "list-cert" , req )
611+ if err != nil {
612+ return nil , err
613+ }
614+
615+ res := []Crt {}
616+ for _ , m := range msgs {
617+ if err = m .Err (); err != nil {
618+ log .Logger .Warnf ("Message error: %v" , err )
619+ return nil , err
620+ }
621+
622+ var crt Crt
623+ if e := vici .UnmarshalMessage (m , & crt ); e != nil {
624+ log .Logger .Warnf ("Message unmarshal error: %v" , e )
625+ return nil , err
626+ }
627+
628+ res = append (res , crt )
629+ }
630+
631+ return res , nil
632+ }
0 commit comments