feat(client): Add RDAP support for domain expiration (#1181)
Fixes #1083 Fixes #1254 Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
@@ -21,6 +21,8 @@ import (
|
||||
"github.com/ishidawataru/sctp"
|
||||
"github.com/miekg/dns"
|
||||
ping "github.com/prometheus-community/pro-bing"
|
||||
"github.com/registrobr/rdap"
|
||||
"github.com/registrobr/rdap/protocol"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
@@ -35,6 +37,7 @@ var (
|
||||
|
||||
whoisClient = whois.NewClient().WithReferralCache(true)
|
||||
whoisExpirationDateCache = gocache.NewCache().WithMaxSize(10000).WithDefaultTTL(24 * time.Hour)
|
||||
rdapClient = rdap.NewClient(nil)
|
||||
)
|
||||
|
||||
// GetHTTPClient returns the shared HTTP client, or the client from the configuration passed
|
||||
@@ -62,7 +65,12 @@ func GetDomainExpiration(hostname string) (domainExpiration time.Duration, err e
|
||||
return domainExpiration, nil
|
||||
}
|
||||
}
|
||||
if whoisResponse, err := whoisClient.QueryAndParse(hostname); err != nil {
|
||||
whoisResponse, err := rdapQuery(hostname)
|
||||
if err != nil {
|
||||
// fallback to WHOIS protocol
|
||||
whoisResponse, err = whoisClient.QueryAndParse(hostname)
|
||||
}
|
||||
if err != nil {
|
||||
if !retrievedCachedValue { // Add an error unless we already retrieved a cached value
|
||||
return 0, fmt.Errorf("error querying and parsing hostname using whois client: %w", err)
|
||||
}
|
||||
@@ -453,3 +461,23 @@ func QueryDNS(queryType, queryName, url string) (connected bool, dnsRcode string
|
||||
func InjectHTTPClient(httpClient *http.Client) {
|
||||
injectedHTTPClient = httpClient
|
||||
}
|
||||
|
||||
// rdapQuery returns domain expiration via RDAP protocol
|
||||
func rdapQuery(hostname string) (*whois.Response, error) {
|
||||
data, _, err := rdapClient.Query(hostname, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domain, ok := data.(*protocol.Domain)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid domain type")
|
||||
}
|
||||
response := whois.Response{}
|
||||
for _, e := range domain.Events {
|
||||
if e.Action == "expiration" {
|
||||
response.ExpirationDate = e.Date.Time
|
||||
break
|
||||
}
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@@ -39,6 +39,20 @@ func TestGetHTTPClient(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRdapQuery(t *testing.T) {
|
||||
if _, err := rdapQuery("1.1.1.1"); err == nil {
|
||||
t.Error("expected an error due to the invalid domain type")
|
||||
}
|
||||
if _, err := rdapQuery("eurid.eu"); err == nil {
|
||||
t.Error("expected an error as there is no RDAP support currently in .eu")
|
||||
}
|
||||
if response, err := rdapQuery("example.com"); err != nil {
|
||||
t.Fatal("expected no error, got", err.Error())
|
||||
} else if response.ExpirationDate.Unix() <= 0 {
|
||||
t.Error("expected to have a valid expiry date, got", response.ExpirationDate.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDomainExpiration(t *testing.T) {
|
||||
t.Parallel()
|
||||
if domainExpiration, err := GetDomainExpiration("gatus.io"); err != nil {
|
||||
|
||||
1
go.mod
1
go.mod
@@ -20,6 +20,7 @@ require (
|
||||
github.com/miekg/dns v1.1.68
|
||||
github.com/prometheus-community/pro-bing v0.6.1
|
||||
github.com/prometheus/client_golang v1.23.0
|
||||
github.com/registrobr/rdap v1.1.8
|
||||
github.com/valyala/fasthttp v1.64.0
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.2
|
||||
golang.org/x/crypto v0.40.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -22,6 +22,8 @@ github.com/TwiN/whois v1.1.11 h1:lYiYgPRSQ3kH8sQfgHcBY/uNSGGvWPRikEjn+LJZ9+Q=
|
||||
github.com/TwiN/whois v1.1.11/go.mod h1:TjipCMpJRAJYKmtz/rXQBU6UGxMh6bk8SHazu7OMnQE=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b h1:uUXgbcPDK3KpW29o4iy7GtuappbWT0l5NaMo9H9pJDw=
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
|
||||
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -115,6 +117,8 @@ github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/registrobr/rdap v1.1.8 h1:7egYAM8MsuencdP9mvF/892f8OjXvUFSyp5cT1Lg45U=
|
||||
github.com/registrobr/rdap v1.1.8/go.mod h1:VY2DVrpsJpUfy9gj2QvurGymCgZV11/11cxQz5CxO+w=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
|
||||
Reference in New Issue
Block a user