checker: add DNSSEC test

This commit is contained in:
nemunaire 2021-03-12 12:46:22 +01:00
parent 5d0693180d
commit eab1af36f4
1 changed files with 174 additions and 0 deletions

View File

@ -19,6 +19,7 @@ import (
const (
DEFAULT_RESOLVER = "2a01:e0a:2b:2250::1"
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. Taken from miekg/dns
)
var verbose = false
@ -88,9 +89,11 @@ func check_dns(domain, ip string) (aaaa net.IP, err error) {
if r == nil {
err = errors.New("response is nil")
return
}
if r.Rcode != dns.RcodeSuccess {
err = errors.New("failed to get a valid answer")
return
}
for _, answer := range r.Answer {
@ -102,6 +105,160 @@ func check_dns(domain, ip string) (aaaa net.IP, err error) {
return
}
func check_dnssec(domain, ip string) (err error) {
client := dns.Client{Timeout: time.Second * 5}
// Get DNSKEY
m := new(dns.Msg)
m.SetEdns0(4096, true)
m.SetQuestion(domain, dns.TypeDNSKEY)
var r *dns.Msg
r, _, err = client.Exchange(m, fmt.Sprintf("[%s]:53", ip))
if err != nil {
return
}
if r == nil {
return errors.New("response is nil")
}
if r.Rcode != dns.RcodeSuccess {
return errors.New("failed to get a valid answer when getting DNSKEY")
}
var rrs []dns.RR
var dnskeys []*dns.DNSKEY
var dnskeysig *dns.RRSIG
for _, answer := range r.Answer {
if t, ok := answer.(*dns.DNSKEY); ok {
dnskeys = append(dnskeys, t)
rrs = append(rrs, dns.RR(t))
} else if t, ok := answer.(*dns.RRSIG); ok {
dnskeysig = t
}
}
found := false
for _, dnskey := range dnskeys {
if err = dnskeysig.Verify(dnskey, rrs); err == nil {
found = true
break
}
}
if !found {
return fmt.Errorf("Unable to verify DNSKEY record signature: %w", err)
}
// Check AAAA validity
m = new(dns.Msg)
m.SetEdns0(4096, true)
m.SetQuestion(domain, dns.TypeAAAA)
r, _, err = client.Exchange(m, fmt.Sprintf("[%s]:53", ip))
if err != nil {
return
}
if r == nil {
return errors.New("response is nil")
}
if r.Rcode != dns.RcodeSuccess {
return errors.New("failed to get a valid answer when getting AAAA records")
}
rrs = []dns.RR{}
var aaaas []*dns.AAAA
var aaaasig *dns.RRSIG
for _, answer := range r.Answer {
if t, ok := answer.(*dns.AAAA); ok {
aaaas = append(aaaas, t)
rrs = append(rrs, t)
} else if t, ok := answer.(*dns.RRSIG); ok {
aaaasig = t
}
}
if len(aaaas) == 0 {
return errors.New("")
}
found = false
for _, dnskey := range dnskeys {
if err = aaaasig.Verify(dnskey, rrs); err == nil {
found = true
if !aaaasig.ValidityPeriod(time.Now()) {
utc := time.Now().UTC().Unix()
modi := (int64(aaaasig.Inception) - utc) / year68
ti := int64(aaaasig.Inception) + modi*year68
mode := (int64(aaaasig.Expiration) - utc) / year68
te := int64(aaaasig.Expiration) + mode*year68
if ti > utc {
return fmt.Errorf("Unable to verify AAAA record signature: signature not yet valid")
} else if utc > te {
return fmt.Errorf("Unable to verify AAAA record signature: signature expired")
} else {
return fmt.Errorf("Unable to verify AAAA record signature: signature expired or not yet valid")
}
}
break
}
}
if !found {
return fmt.Errorf("Unable to verify AAAA record signature: %w", err)
}
// Check DS
m = new(dns.Msg)
m.SetQuestion(domain, dns.TypeDS)
m.RecursionDesired = false
m.SetEdns0(4096, true)
r, _, err = client.Exchange(m, "[2a01:e0a:2b:2250::b]:53")
if err != nil {
return
}
if r == nil {
return errors.New("response is nil")
}
if r.Rcode != dns.RcodeSuccess {
return errors.New("failed to get a valid answer when getting DS records in parent server")
}
found = false
for _, answer := range r.Answer {
if t, ok := answer.(*dns.DS); ok {
for _, dnskey := range dnskeys {
expectedDS := dnskey.ToDS(dns.SHA256)
if expectedDS.KeyTag == t.KeyTag && expectedDS.Algorithm == t.Algorithm && expectedDS.DigestType == t.DigestType && expectedDS.Digest == t.Digest {
found = true
err = nil
break
} else {
err = fmt.Errorf("DS record found in parent zone differs from DNSKEY %v vs. %v.", expectedDS, t)
}
}
}
}
if !found {
if err == nil {
return fmt.Errorf("Unable to find a valid DS record in parent zone.")
} else {
return err
}
}
return
}
// PORT 80
func check_http(ip, dn string) (err error) {
@ -367,6 +524,23 @@ func studentsChecker() {
}
}
}
// Check DNSSEC (only if GLUE Ok)
if glueErr == nil {
if err := check_dnssec(std.MyDelegatedDomain(), dnsIP); err == nil {
if verbose {
log.Printf("%s just unlocked DNSSEC challenge\n", std.Login)
}
if _, err := std.UnlockChallenge(100*(tunnel_version-1)+7, ""); err != nil {
log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error())
}
} else {
std.RegisterChallengeError(100*(tunnel_version-1)+7, err)
if verbose {
log.Printf("%s and DNSSEC: %s\n", std.Login, err)
}
}
}
}
} else {
if errreg := std.RegisterChallengeError(100*(tunnel_version-1)+3, err); errreg != nil {