2020-11-18 00:55:31 +01:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2020-11-19 13:59:03 +01:00
|
|
|
// ErrDNSWithNoQueryName is the error with which gatus will panic if a dns is configured without query name
|
2020-11-20 03:10:59 +01:00
|
|
|
ErrDNSWithNoQueryName = errors.New("you must specify a query name for DNS")
|
2020-11-30 01:03:40 +01:00
|
|
|
|
2020-11-19 13:59:03 +01:00
|
|
|
// ErrDNSWithInvalidQueryType is the error with which gatus will panic if a dns is configured with invalid query type
|
2020-11-18 00:55:31 +01:00
|
|
|
ErrDNSWithInvalidQueryType = errors.New("invalid query type")
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
dnsPort = 53
|
|
|
|
)
|
|
|
|
|
2021-10-23 22:47:12 +02:00
|
|
|
// DNS is the configuration for a Endpoint of type DNS
|
2020-11-18 00:55:31 +01:00
|
|
|
type DNS struct {
|
2020-11-18 18:51:22 +01:00
|
|
|
// QueryType is the type for the DNS records like A, AAAA, CNAME...
|
2020-11-18 00:55:31 +01:00
|
|
|
QueryType string `yaml:"query-type"`
|
2020-11-30 01:03:40 +01:00
|
|
|
|
2020-11-18 00:55:31 +01:00
|
|
|
// QueryName is the query for DNS
|
|
|
|
QueryName string `yaml:"query-name"`
|
|
|
|
}
|
|
|
|
|
2021-05-19 04:29:15 +02:00
|
|
|
func (d *DNS) validateAndSetDefault() error {
|
2020-11-18 00:55:31 +01:00
|
|
|
if len(d.QueryName) == 0 {
|
2021-05-19 04:29:15 +02:00
|
|
|
return ErrDNSWithNoQueryName
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
if !strings.HasSuffix(d.QueryName, ".") {
|
|
|
|
d.QueryName += "."
|
|
|
|
}
|
|
|
|
if _, ok := dns.StringToType[d.QueryType]; !ok {
|
2021-05-19 04:29:15 +02:00
|
|
|
return ErrDNSWithInvalidQueryType
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
2021-05-19 04:29:15 +02:00
|
|
|
return nil
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DNS) query(url string, result *Result) {
|
|
|
|
if !strings.Contains(url, ":") {
|
|
|
|
url = fmt.Sprintf("%s:%d", url, dnsPort)
|
|
|
|
}
|
|
|
|
queryType := dns.StringToType[d.QueryType]
|
|
|
|
c := new(dns.Client)
|
|
|
|
m := new(dns.Msg)
|
|
|
|
m.SetQuestion(d.QueryName, queryType)
|
|
|
|
r, _, err := c.Exchange(m, url)
|
|
|
|
if err != nil {
|
2021-06-06 00:51:51 +02:00
|
|
|
result.AddError(err.Error())
|
2020-11-18 00:55:31 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
result.Connected = true
|
|
|
|
result.DNSRCode = dns.RcodeToString[r.Rcode]
|
|
|
|
for _, rr := range r.Answer {
|
|
|
|
switch rr.Header().Rrtype {
|
|
|
|
case dns.TypeA:
|
|
|
|
if a, ok := rr.(*dns.A); ok {
|
2021-03-09 03:30:11 +01:00
|
|
|
result.body = []byte(a.A.String())
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
case dns.TypeAAAA:
|
|
|
|
if aaaa, ok := rr.(*dns.AAAA); ok {
|
2021-03-09 03:30:11 +01:00
|
|
|
result.body = []byte(aaaa.AAAA.String())
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
case dns.TypeCNAME:
|
|
|
|
if cname, ok := rr.(*dns.CNAME); ok {
|
2021-03-09 03:30:11 +01:00
|
|
|
result.body = []byte(cname.Target)
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
case dns.TypeMX:
|
|
|
|
if mx, ok := rr.(*dns.MX); ok {
|
2021-03-09 03:30:11 +01:00
|
|
|
result.body = []byte(mx.Mx)
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
case dns.TypeNS:
|
|
|
|
if ns, ok := rr.(*dns.NS); ok {
|
2021-03-09 03:30:11 +01:00
|
|
|
result.body = []byte(ns.Ns)
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
default:
|
2021-03-09 03:30:11 +01:00
|
|
|
result.body = []byte("query type is not supported yet")
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|