Use external resolvers to validate the signatures.
This commit is contained in:
parent
969171cea8
commit
caa7d89b2d
23
README.md
23
README.md
@ -13,8 +13,8 @@ Check for validity and expiration in DNSSEC signatures and expose metrics for Pr
|
|||||||
Configuration file (default "/etc/dnssec-checks")
|
Configuration file (default "/etc/dnssec-checks")
|
||||||
-listen-address string
|
-listen-address string
|
||||||
Prometheus metrics port (default ":9204")
|
Prometheus metrics port (default ":9204")
|
||||||
-resolver string
|
-resolvers string
|
||||||
Resolver to use (default "8.8.8.8:53")
|
Resolvers to use (comma separated) (default "8.8.8.8:53,1.1.1.1:53")
|
||||||
-timeout duration
|
-timeout duration
|
||||||
Timeout for network operations (default 10s)
|
Timeout for network operations (default 10s)
|
||||||
|
|
||||||
@ -30,12 +30,13 @@ Labels:
|
|||||||
* `record`
|
* `record`
|
||||||
* `type`
|
* `type`
|
||||||
|
|
||||||
### Gauge: `dnssec_zone_record_valid`
|
### Gauge: `dnssec_zone_record_resolves`
|
||||||
|
|
||||||
Does this record pass DNSSEC validation.
|
Does the record resolve using the specified DNSSEC enabled resolvers.
|
||||||
|
|
||||||
Labels:
|
Labels:
|
||||||
|
|
||||||
|
* `resolver`
|
||||||
* `zone`
|
* `zone`
|
||||||
* `record`
|
* `record`
|
||||||
* `type`
|
* `type`
|
||||||
@ -44,12 +45,14 @@ Labels:
|
|||||||
|
|
||||||
# HELP dnssec_zone_record_days_left Number of days the signature will be valid
|
# HELP dnssec_zone_record_days_left Number of days the signature will be valid
|
||||||
# TYPE dnssec_zone_record_days_left gauge
|
# TYPE dnssec_zone_record_days_left gauge
|
||||||
dnssec_zone_record_days_left{record="@",type="SOA",zone="ietf.org"} 357.5
|
dnssec_zone_record_days_left{record="@",type="SOA",zone="ietf.org"} 320.3333333333333
|
||||||
dnssec_zone_record_days_left{record="@",type="SOA",zone="verisigninc.com"} 11.333333333333334
|
dnssec_zone_record_days_left{record="@",type="SOA",zone="verisigninc.com"} 9.333333333333334
|
||||||
# HELP dnssec_zone_record_valid Does this record pass DNSSEC validation
|
# HELP dnssec_zone_record_resolves Does the record resolve using the specified DNSSEC enabled resolvers
|
||||||
# TYPE dnssec_zone_record_valid gauge
|
# TYPE dnssec_zone_record_resolves gauge
|
||||||
dnssec_zone_record_valid{record="@",type="SOA",zone="ietf.org"} 1
|
dnssec_zone_record_resolves{record="@",resolver="1.1.1.1:53",type="SOA",zone="ietf.org"} 1
|
||||||
dnssec_zone_record_valid{record="@",type="SOA",zone="verisigninc.com"} 1
|
dnssec_zone_record_resolves{record="@",resolver="1.1.1.1:53",type="SOA",zone="verisigninc.com"} 1
|
||||||
|
dnssec_zone_record_resolves{record="@",resolver="8.8.8.8:53",type="SOA",zone="ietf.org"} 1
|
||||||
|
dnssec_zone_record_resolves{record="@",resolver="8.8.8.8:53",type="SOA",zone="verisigninc.com"} 1
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ groups:
|
|||||||
description: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} type {{$labels.type}}) expires in {{$value}} day(s)
|
description: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} type {{$labels.type}}) expires in {{$value}} day(s)
|
||||||
title: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} is expiring
|
title: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} is expiring
|
||||||
- alert: DNSSECSignatureInvalid
|
- alert: DNSSECSignatureInvalid
|
||||||
expr: dnssec_zone_record_valid == 0
|
expr: dnssec_zone_record_resolves == 0
|
||||||
for: 1m
|
for: 1m
|
||||||
labels:
|
labels:
|
||||||
urgency: immediate
|
urgency: immediate
|
||||||
annotations:
|
annotations:
|
||||||
description: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} type {{$labels.type}}) is invalid
|
description: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} type {{$labels.type}}) on resolver {{$labels.resolver}} is invalid
|
||||||
title: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} is invalid
|
title: The DNSSEC signature for the {{$labels.record}} in {{$labels.zone}} on resolver {{$labels.resolver}} is invalid
|
||||||
|
119
main.go
119
main.go
@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ import (
|
|||||||
|
|
||||||
var addr = flag.String("listen-address", ":9204", "Prometheus metrics port")
|
var addr = flag.String("listen-address", ":9204", "Prometheus metrics port")
|
||||||
var conf = flag.String("config", "/etc/dnssec-checks", "Configuration file")
|
var conf = flag.String("config", "/etc/dnssec-checks", "Configuration file")
|
||||||
var resolver = flag.String("resolver", "8.8.8.8:53", "Resolver to use")
|
var resolvers = flag.String("resolvers", "8.8.8.8:53,1.1.1.1:53", "Resolvers to use (comma separated)")
|
||||||
var timeout = flag.Duration("timeout", 10*time.Second, "Timeout for network operations")
|
var timeout = flag.Duration("timeout", 10*time.Second, "Timeout for network operations")
|
||||||
|
|
||||||
type Records struct {
|
type Records struct {
|
||||||
@ -35,15 +36,15 @@ type Exporter struct {
|
|||||||
Records []Records
|
Records []Records
|
||||||
|
|
||||||
records *prometheus.GaugeVec
|
records *prometheus.GaugeVec
|
||||||
valid *prometheus.GaugeVec
|
resolves *prometheus.GaugeVec
|
||||||
|
|
||||||
resolver string
|
resolvers []string
|
||||||
dnsClient *dns.Client
|
dnsClient *dns.Client
|
||||||
|
|
||||||
logger Logger
|
logger Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDNSSECExporter(timeout time.Duration, resolver string, logger Logger) *Exporter {
|
func NewDNSSECExporter(timeout time.Duration, resolvers []string, logger Logger) *Exporter {
|
||||||
return &Exporter{
|
return &Exporter{
|
||||||
records: prometheus.NewGaugeVec(
|
records: prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
@ -58,14 +59,15 @@ func NewDNSSECExporter(timeout time.Duration, resolver string, logger Logger) *E
|
|||||||
"type",
|
"type",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
valid: prometheus.NewGaugeVec(
|
resolves: prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Namespace: "dnssec",
|
Namespace: "dnssec",
|
||||||
Subsystem: "zone",
|
Subsystem: "zone",
|
||||||
Name: "record_valid",
|
Name: "record_resolves",
|
||||||
Help: "Does this record pass DNSSEC validation",
|
Help: "Does the record resolve using the specified DNSSEC enabled resolvers",
|
||||||
},
|
},
|
||||||
[]string{
|
[]string{
|
||||||
|
"resolver",
|
||||||
"zone",
|
"zone",
|
||||||
"record",
|
"record",
|
||||||
"type",
|
"type",
|
||||||
@ -75,97 +77,88 @@ func NewDNSSECExporter(timeout time.Duration, resolver string, logger Logger) *E
|
|||||||
Net: "tcp",
|
Net: "tcp",
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
},
|
},
|
||||||
resolver: resolver,
|
resolvers: resolvers,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
||||||
e.records.Describe(ch)
|
e.records.Describe(ch)
|
||||||
e.valid.Describe(ch)
|
e.resolves.Describe(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
wg.Add(len(e.Records))
|
wg.Add(len(e.Records) * (len(e.resolvers) + 1))
|
||||||
|
|
||||||
for _, rec := range e.Records {
|
for _, rec := range e.Records {
|
||||||
|
|
||||||
rec := rec
|
rec := rec
|
||||||
|
|
||||||
|
// Check the expiration
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
||||||
valid, exp := e.collectRecord(rec.Zone, rec.Record, rec.Type)
|
exp := e.expiration(rec.Zone, rec.Record, rec.Type)
|
||||||
|
|
||||||
e.valid.WithLabelValues(
|
|
||||||
rec.Zone, rec.Record, rec.Type,
|
|
||||||
).Set(map[bool]float64{true: 1}[valid])
|
|
||||||
|
|
||||||
e.records.WithLabelValues(
|
e.records.WithLabelValues(
|
||||||
rec.Zone, rec.Record, rec.Type,
|
rec.Zone, rec.Record, rec.Type,
|
||||||
).Set(float64(time.Until(exp)/time.Hour) / 24)
|
).Set(float64(time.Until(exp)/time.Hour) / 24)
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Check the configured resolvers
|
||||||
|
|
||||||
|
for _, resolver := range e.resolvers {
|
||||||
|
|
||||||
|
resolver := resolver
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
|
||||||
|
resolves := e.resolve(rec.Zone, rec.Record, rec.Type, resolver)
|
||||||
|
|
||||||
|
e.resolves.WithLabelValues(
|
||||||
|
resolver, rec.Zone, rec.Record, rec.Type,
|
||||||
|
).Set(map[bool]float64{true: 1}[resolves])
|
||||||
|
|
||||||
|
wg.Done()
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
e.records.Collect(ch)
|
e.records.Collect(ch)
|
||||||
e.valid.Collect(ch)
|
e.resolves.Collect(ch)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exporter) collectRecord(zone, record, recordType string) (valid bool, exp time.Time) {
|
func (e *Exporter) expiration(zone, record, recordType string) (exp time.Time) {
|
||||||
|
|
||||||
// Start by finding the DNSKEY
|
|
||||||
|
|
||||||
msg := &dns.Msg{}
|
msg := &dns.Msg{}
|
||||||
msg.SetQuestion(fmt.Sprintf("%s.", zone), dns.TypeDNSKEY)
|
|
||||||
|
|
||||||
response, _, err := e.dnsClient.Exchange(msg, e.resolver)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Printf("while looking up DNSKEY for %v: %v", zone, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found keys are mapped by tag -> key
|
|
||||||
keys := make(map[uint16]*dns.DNSKEY)
|
|
||||||
|
|
||||||
for _, rr := range response.Answer {
|
|
||||||
if dnskey, ok := rr.(*dns.DNSKEY); ok && dnskey.Flags&dns.ZONE != 0 {
|
|
||||||
keys[dnskey.KeyTag()] = dnskey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(keys) == 0 {
|
|
||||||
e.logger.Printf("didn't find DNSKEY for %v", zone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now lookup the signature
|
|
||||||
|
|
||||||
msg = &dns.Msg{}
|
|
||||||
msg.SetQuestion(hostname(zone, record), dns.TypeRRSIG)
|
msg.SetQuestion(hostname(zone, record), dns.TypeRRSIG)
|
||||||
|
|
||||||
response, _, err = e.dnsClient.Exchange(msg, e.resolver)
|
response, _, err := e.dnsClient.Exchange(msg, e.resolvers[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Printf("while looking up RRSIG for %v: %v", hostname(zone, record), err)
|
e.logger.Printf("while looking up RRSIG for %v: %v", hostname(zone, record), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var sig *dns.RRSIG
|
var sig *dns.RRSIG
|
||||||
var key *dns.DNSKEY
|
|
||||||
|
|
||||||
for _, rr := range response.Answer {
|
for _, rr := range response.Answer {
|
||||||
|
|
||||||
if rrsig, ok := rr.(*dns.RRSIG); ok &&
|
if rrsig, ok := rr.(*dns.RRSIG); ok &&
|
||||||
rrsig.TypeCovered == dns.StringToType[recordType] &&
|
rrsig.TypeCovered == dns.StringToType[recordType] {
|
||||||
keys[rrsig.KeyTag] != nil {
|
|
||||||
|
|
||||||
sig = rrsig
|
sig = rrsig
|
||||||
key = keys[rrsig.KeyTag]
|
|
||||||
break
|
break
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -182,29 +175,25 @@ func (e *Exporter) collectRecord(zone, record, recordType string) (valid bool, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, lookup the records to validate
|
|
||||||
|
|
||||||
if key == nil {
|
|
||||||
e.valid.WithLabelValues(zone, record, recordType).Set(0)
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
msg = &dns.Msg{}
|
}
|
||||||
|
|
||||||
|
func (e *Exporter) resolve(zone, record, recordType, resolver string) (resolves bool) {
|
||||||
|
|
||||||
|
msg := &dns.Msg{}
|
||||||
msg.SetQuestion(hostname(zone, record), dns.StringToType[recordType])
|
msg.SetQuestion(hostname(zone, record), dns.StringToType[recordType])
|
||||||
|
msg.SetEdns0(4096, true)
|
||||||
|
|
||||||
response, _, err = e.dnsClient.Exchange(msg, e.resolver)
|
response, _, err := e.dnsClient.Exchange(msg, resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Printf("while looking up RRSet for %v type %v: %v", hostname(zone, record), recordType, err)
|
e.logger.Printf("while resolving for %v: %v", hostname(zone, record), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sig.Verify(key, response.Answer); err == nil {
|
return response.AuthenticatedData &&
|
||||||
valid = true
|
!response.CheckingDisabled &&
|
||||||
} else {
|
response.Rcode == dns.RcodeSuccess
|
||||||
e.logger.Printf("verify error for %v type %v): %v", hostname(zone, record), recordType, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +218,9 @@ func main() {
|
|||||||
|
|
||||||
logger := log.New(os.Stderr, "", log.LstdFlags)
|
logger := log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
|
||||||
exporter := NewDNSSECExporter(*timeout, *resolver, logger)
|
r := strings.Split(*resolvers, ",")
|
||||||
|
|
||||||
|
exporter := NewDNSSECExporter(*timeout, r, logger)
|
||||||
|
|
||||||
if err := toml.NewDecoder(f).Decode(exporter); err != nil {
|
if err := toml.NewDecoder(f).Decode(exporter); err != nil {
|
||||||
log.Fatalf("couldn't parse configuration file: %v", err)
|
log.Fatalf("couldn't parse configuration file: %v", err)
|
||||||
|
108
main_test.go
108
main_test.go
@ -1,10 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -17,14 +14,15 @@ import (
|
|||||||
type opts struct {
|
type opts struct {
|
||||||
signed time.Time
|
signed time.Time
|
||||||
expires time.Time
|
expires time.Time
|
||||||
privkey crypto.PrivateKey
|
rcode int
|
||||||
|
unauthenticated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func nullLogger() *log.Logger {
|
func nullLogger() *log.Logger {
|
||||||
return log.New(ioutil.Discard, "", log.LstdFlags)
|
return log.New(ioutil.Discard, "", log.LstdFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServer(t *testing.T, opts opts) (string, func()) {
|
func runServer(t *testing.T, opts opts) ([]string, func()) {
|
||||||
|
|
||||||
if opts.signed.IsZero() {
|
if opts.signed.IsZero() {
|
||||||
opts.signed = time.Now().Add(-time.Hour)
|
opts.signed = time.Now().Add(-time.Hour)
|
||||||
@ -45,10 +43,6 @@ func runServer(t *testing.T, opts opts) (string, func()) {
|
|||||||
t.Fatalf("couldn't generate private key: %v", err)
|
t.Fatalf("couldn't generate private key: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.privkey != nil {
|
|
||||||
privkey = opts.privkey
|
|
||||||
}
|
|
||||||
|
|
||||||
h := dns.NewServeMux()
|
h := dns.NewServeMux()
|
||||||
h.HandleFunc("example.org.", func(rw dns.ResponseWriter, msg *dns.Msg) {
|
h.HandleFunc("example.org.", func(rw dns.ResponseWriter, msg *dns.Msg) {
|
||||||
|
|
||||||
@ -72,25 +66,6 @@ func runServer(t *testing.T, opts opts) (string, func()) {
|
|||||||
|
|
||||||
switch q.Qtype {
|
switch q.Qtype {
|
||||||
|
|
||||||
case dns.TypeDNSKEY:
|
|
||||||
|
|
||||||
rrHeader := dns.RR_Header{
|
|
||||||
Name: q.Name,
|
|
||||||
Rrtype: dns.TypeDNSKEY,
|
|
||||||
Class: dns.ClassINET,
|
|
||||||
Ttl: 3600,
|
|
||||||
}
|
|
||||||
|
|
||||||
answer := &dns.DNSKEY{
|
|
||||||
Hdr: rrHeader,
|
|
||||||
Algorithm: dnskey.Algorithm,
|
|
||||||
Flags: dnskey.Flags,
|
|
||||||
Protocol: dnskey.Protocol,
|
|
||||||
PublicKey: dnskey.PublicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Answer = append(msg.Answer, answer)
|
|
||||||
|
|
||||||
case dns.TypeRRSIG:
|
case dns.TypeRRSIG:
|
||||||
|
|
||||||
rrHeader := dns.RR_Header{
|
rrHeader := dns.RR_Header{
|
||||||
@ -124,6 +99,9 @@ func runServer(t *testing.T, opts opts) (string, func()) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg.AuthenticatedData = !opts.unauthenticated
|
||||||
|
msg.Rcode = opts.rcode
|
||||||
|
|
||||||
rw.WriteMsg(msg)
|
rw.WriteMsg(msg)
|
||||||
|
|
||||||
})
|
})
|
||||||
@ -150,24 +128,20 @@ func runServer(t *testing.T, opts opts) (string, func()) {
|
|||||||
ln.Close()
|
ln.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return ln.Addr().String(), func() {
|
return []string{ln.Addr().String()}, func() {
|
||||||
done <- true
|
done <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCollectionOK(t *testing.T) {
|
func TestExpirationOK(t *testing.T) {
|
||||||
|
|
||||||
addr, cancel := runServer(t, opts{})
|
addr, cancel := runServer(t, opts{})
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
||||||
|
|
||||||
valid, exp := e.collectRecord("example.org", "@", "SOA")
|
exp := e.expiration("example.org", "@", "SOA")
|
||||||
|
|
||||||
if !valid {
|
|
||||||
t.Fatal("expected record to be valid")
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp.Before(time.Now()) {
|
if exp.Before(time.Now()) {
|
||||||
t.Fatalf("expected expiration to be in the future, was: %v", exp)
|
t.Fatalf("expected expiration to be in the future, was: %v", exp)
|
||||||
@ -175,7 +149,7 @@ func TestCollectionOK(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCollectionExpired(t *testing.T) {
|
func TestExpired(t *testing.T) {
|
||||||
|
|
||||||
addr, cancel := runServer(t, opts{
|
addr, cancel := runServer(t, opts{
|
||||||
signed: time.Now().Add(14 * 24 * time.Hour),
|
signed: time.Now().Add(14 * 24 * time.Hour),
|
||||||
@ -186,11 +160,7 @@ func TestCollectionExpired(t *testing.T) {
|
|||||||
|
|
||||||
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
||||||
|
|
||||||
valid, exp := e.collectRecord("example.org", "@", "SOA")
|
exp := e.expiration("example.org", "@", "SOA")
|
||||||
|
|
||||||
if !valid {
|
|
||||||
t.Fatal("expected record to be valid")
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp.After(time.Now()) {
|
if exp.After(time.Now()) {
|
||||||
t.Fatalf("expected expiration to be in the past, was: %v", exp)
|
t.Fatalf("expected expiration to be in the past, was: %v", exp)
|
||||||
@ -198,29 +168,57 @@ func TestCollectionExpired(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCollectionInvalid(t *testing.T) {
|
func TestValid(t *testing.T) {
|
||||||
|
|
||||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("couldn't generate fake private key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, cancel := runServer(t, opts{
|
addr, cancel := runServer(t, opts{
|
||||||
privkey: priv,
|
signed: time.Now().Add(14 * 24 * time.Hour),
|
||||||
|
expires: time.Now().Add(-time.Hour),
|
||||||
})
|
})
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
||||||
|
|
||||||
valid, exp := e.collectRecord("example.org", "@", "SOA")
|
valid := e.resolve("example.org", "@", "SOA", addr[0])
|
||||||
|
|
||||||
if valid {
|
if !valid {
|
||||||
t.Fatal("expected record to be invalid")
|
t.Fatal("expected valid result")
|
||||||
}
|
}
|
||||||
|
|
||||||
if exp.Before(time.Now()) {
|
}
|
||||||
t.Fatalf("expected expiration to be in the future, was: %v", exp)
|
|
||||||
|
func TestInvalidError(t *testing.T) {
|
||||||
|
|
||||||
|
addr, cancel := runServer(t, opts{
|
||||||
|
rcode: dns.RcodeServerFailure,
|
||||||
|
})
|
||||||
|
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
||||||
|
|
||||||
|
valid := e.resolve("example.org", "@", "SOA", addr[0])
|
||||||
|
|
||||||
|
if valid {
|
||||||
|
t.Fatal("expected invalid result")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidUnauthenticated(t *testing.T) {
|
||||||
|
|
||||||
|
addr, cancel := runServer(t, opts{
|
||||||
|
unauthenticated: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
e := NewDNSSECExporter(time.Second, addr, nullLogger())
|
||||||
|
|
||||||
|
valid := e.resolve("example.org", "@", "SOA", addr[0])
|
||||||
|
|
||||||
|
if valid {
|
||||||
|
t.Fatal("expected invalid result")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user