metrics.status.sslip.io includes blocked queries

I've refactored the metrics: where I previously used the term
"successful", I now use the term "answered". "Answered" means there was
at least one record in the Answer section of the response to the DNS
query. This is a more precise description.

I re-arranged the metrics integration test. Now it's sorted by type of
record queried (A, AAAA, MX, etc.). It's easier for me to follow.
This commit is contained in:
Brian Cunnie
2022-02-06 18:40:31 -08:00
parent 5398c543e7
commit 5afb911f50
3 changed files with 157 additions and 90 deletions

View File

@@ -17,77 +17,131 @@ var _ = Describe("IntegrationMetrics", func() {
When("the server is queried", func() {
// One big `It()` block because these tests cannot be run in parallel (singleton)
It("should update metrics", func() {
var actualMetrics xip.Metrics
expectedMetrics := getMetrics()
// non-existent record updates .Queries
expectedMetrics.Queries += 2 // two queries: nonexistent.sslip.io, metrics.status.sslip.io
expectedMetrics.SuccessfulQueries += 1 // metrics.status.sslip.io
actualMetrics := digAndGetMetrics("@localhost non-existent.sslip.io +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// MX record updates .Queries, .SuccessfulQueries
expectedMetrics.Queries += 2
expectedMetrics.SuccessfulQueries += 2
actualMetrics = digAndGetMetrics("@localhost sslip.io mx +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// A record updates .Queries, .SuccessfulQueries, .SuccessfulAQueries
expectedMetrics.Queries += 2
expectedMetrics.SuccessfulQueries += 2
expectedMetrics.SuccessfulAQueries += 1
// A updates .Queries, .AnsweredQueries, .AnsweredAQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics.AnsweredAQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost 127.0.0.1.sslip.io +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// AAAA record updates .Queries, .SuccessfulQueries, .SuccessfulAAAAQueries
expectedMetrics.Queries += 2
expectedMetrics.SuccessfulQueries += 2
expectedMetrics.SuccessfulAAAAQueries += 1
// A (non-existent) record updates .Queries
expectedMetrics.Queries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost non-existent.sslip.io +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// A blocked updates .Queries, .AnsweredQueries, .AnsweredBlockedQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics.AnsweredBlockedQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
dig("@localhost bank-of-raiffeisen.127.0.0.1.sslip.io +short")
actualMetrics = getMetrics()
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// AAAA updates .Queries, .AnsweredQueries, .AnsweredAAAAQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics.AnsweredAAAAQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost 2600--.sslip.io aaaa +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// source IP TXT record updates .Queries, .SuccessfulQueries, .SuccessfulTXTSrcIPQueries
expectedMetrics.Queries += 2
expectedMetrics.SuccessfulQueries += 2
expectedMetrics.SuccessfulTXTSrcIPQueries += 1
actualMetrics = digAndGetMetrics("@localhost ip.sslip.io txt +short")
// AAAA (non-existent) updates .Queries
expectedMetrics.Queries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost non-existent.sslip.io aaaa +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// version TXT record updates .Queries, .SuccessfulQueries, .SuccessfulTXTVersionQueries
expectedMetrics.Queries += 2
expectedMetrics.SuccessfulQueries += 2
expectedMetrics.SuccessfulTXTVersionQueries += 1
actualMetrics = digAndGetMetrics("@localhost version.status.sslip.io txt +short")
// MX (customized) updates .Queries, .AnsweredQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost sslip.io mx +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// DNS-01 challenge N record updates .Queries, .SuccessfulQueries, .SuccessfulNSDNS01ChallengeQueries
expectedMetrics.Queries += 2
// MX updates .Queries, AnsweredQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost non-existent.sslip.io mx +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// NS updates .Queries, AnsweredQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost non-existent.sslip.io ns +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// NS DNS-01 challenge record updates .Queries, .AnsweredNSDNS01ChallengeQueries
expectedMetrics.Queries += 1
// DNS-01 challenges don't count as successful because we're not authoritative; we're delegating
expectedMetrics.SuccessfulQueries += 1
expectedMetrics.SuccessfulNSDNS01ChallengeQueries += 1
expectedMetrics.AnsweredNSDNS01ChallengeQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost _acme-challenge.fe80--.sslip.io NS +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// 3 failed lookups + metrics
expectedMetrics.Queries += 4
expectedMetrics.SuccessfulQueries += 1
dig("@localhost non-existent.sslip.io +short")
dig("@localhost non-existent.sslip.io aaaa +short")
dig("@localhost non-existent.sslip.io txt +short")
// Always successful: SOA
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
dig("@localhost non-existent.sslip.io soa +short")
actualMetrics = getMetrics()
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// Always successful: SOA MX NS
expectedMetrics.Queries += 4
expectedMetrics.SuccessfulQueries += 4
dig("@localhost non-existent.sslip.io soa +short")
dig("@localhost non-existent.sslip.io mx +short")
dig("@localhost non-existent.sslip.io ns +short")
actualMetrics = getMetrics()
// TXT sslip.io (customized) updates .Queries, .AnsweredQueries,
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost sslip.io txt +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// TXT sslip.io (non-existent) updates .Queries, .AnsweredQueries,
expectedMetrics.Queries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost non-existent.sslip.io txt +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// TXT ip.sslip.io updates .Queries, .AnsweredQueries, .AnsweredTXTSrcIPQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics.AnsweredTXTSrcIPQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost ip.sslip.io txt +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// TXT version.sslip.io updates .Queries, .AnsweredQueries, .AnsweredXTVersionQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredQueries += 1
expectedMetrics.AnsweredXTVersionQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost version.status.sslip.io txt +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
// TXT DNS-01 challenge record updates .Queries, .AnsweredNSDNS01ChallengeQueries
expectedMetrics.Queries += 1
expectedMetrics.AnsweredNSDNS01ChallengeQueries += 1
expectedMetrics = bumpExpectedToAccountForMetricsQuery(expectedMetrics)
actualMetrics = digAndGetMetrics("@localhost _acme-challenge.fe80--.sslip.io txt +short")
Expect(expectedMetrics.MostlyEquals(actualMetrics)).To(BeTrue())
})
})
})
// bumpExpectedToAccountForMetricsQuery takes into account that
// digging for the metrics endpoint affects the metrics. It's like
// the Heisenberg uncertainty principle (observing changes the values)
func bumpExpectedToAccountForMetricsQuery(metrics xip.Metrics) xip.Metrics {
metrics.Queries += 1
metrics.AnsweredQueries += 1
return metrics
}
func digAndGetMetrics(digArgs string) xip.Metrics {
dig(digArgs)
return getMetrics()
@@ -119,18 +173,20 @@ func getMetrics() (m xip.Metrics) {
"\"- AAAA: %d\"\n"+
"\"- source IP TXT: %d\"\n"+
"\"- version TXT: %d\"\n"+
"\"- DNS-01 challenge: %d\"\n",
"\"- DNS-01 challenge: %d\"\n"+
"\"- blocked: %d\"\n",
&uptime,
&junk,
&m.Queries,
&junk,
&m.SuccessfulQueries,
&m.AnsweredQueries,
&junk,
&m.SuccessfulAQueries,
&m.SuccessfulAAAAQueries,
&m.SuccessfulTXTSrcIPQueries,
&m.SuccessfulTXTVersionQueries,
&m.SuccessfulNSDNS01ChallengeQueries,
&m.AnsweredAQueries,
&m.AnsweredAAAAQueries,
&m.AnsweredTXTSrcIPQueries,
&m.AnsweredXTVersionQueries,
&m.AnsweredNSDNS01ChallengeQueries,
&m.AnsweredBlockedQueries,
)
Expect(err).ToNot(HaveOccurred())
m.Start = time.Now().Add(-time.Duration(uptime) * time.Second)

View File

@@ -1,7 +1,6 @@
package main_test
import (
"fmt"
"os/exec"
"strings"
"time"
@@ -28,7 +27,7 @@ var _ = BeforeSuite(func() {
// takes 1.312s to start up on macOS Big Sur 2.0GHz quad-core 10th-generation Intel Core i5 processor (2020 13" MacBook Pro)
// round up to 3 seconds to account for slow container-on-a-VM-with-shared-core
time.Sleep(3 * time.Second) // takes 0.455s to start up on macOS Big Sur 4-core Xeon
fmt.Println(string(serverSession.Err.Contents()))
// fmt.Println(string(serverSession.Err.Contents())) // only print this out to debug--it clutters the output
})
var _ = AfterSuite(func() {

View File

@@ -42,14 +42,15 @@ type Xip struct {
}
type Metrics struct {
Start time.Time
Queries int
SuccessfulQueries int
SuccessfulAQueries int
SuccessfulAAAAQueries int
SuccessfulTXTSrcIPQueries int
SuccessfulTXTVersionQueries int
SuccessfulNSDNS01ChallengeQueries int
Start time.Time
Queries int
AnsweredQueries int
AnsweredAQueries int
AnsweredAAAAQueries int
AnsweredTXTSrcIPQueries int
AnsweredXTVersionQueries int
AnsweredNSDNS01ChallengeQueries int
AnsweredBlockedQueries int
}
// DomainCustomization is a value that is returned for a specific query.
@@ -182,7 +183,7 @@ var (
},
"version.status.sslip.io.": {
TXT: func(x Xip) ([]dnsmessage.TXTResource, error) {
x.Metrics.SuccessfulTXTVersionQueries += 1
x.Metrics.AnsweredXTVersionQueries += 1
return []dnsmessage.TXTResource{
{TXT: []string{VersionSemantic}}, // e.g. "2.2.1'
{TXT: []string{VersionDate}}, // e.g. "2021/10/03-15:08:54+0100"
@@ -336,7 +337,7 @@ func (x Xip) processQuestion(q dnsmessage.Question) (response Response, logMessa
})
return response, logMessage + "nil, SOA " + soaLogMessage(soaResource), nil
}
x.Metrics.SuccessfulQueries += 1
x.Metrics.AnsweredQueries += 1
response.Answers = append(response.Answers,
// 1 CNAME record, via Customizations
func(b *dnsmessage.Builder) error {
@@ -363,7 +364,7 @@ func (x Xip) processQuestion(q dnsmessage.Question) (response Response, logMessa
if len(mailExchangers) == 0 {
return response, "", errors.New("no MX records, but there should be one")
}
x.Metrics.SuccessfulQueries += 1
x.Metrics.AnsweredQueries += 1
response.Answers = append(response.Answers,
// 1 or more A records; A records > 1 only available via Customizations
func(b *dnsmessage.Builder) error {
@@ -388,12 +389,11 @@ func (x Xip) processQuestion(q dnsmessage.Question) (response Response, logMessa
}
case dnsmessage.TypeNS:
{
x.Metrics.SuccessfulQueries += 1
return x.NSResponse(q.Name, response, logMessage)
}
case dnsmessage.TypeSOA:
{
x.Metrics.SuccessfulQueries += 1
x.Metrics.AnsweredQueries += 1
soaResource := SOAResource(q.Name)
response.Answers = append(response.Answers,
func(b *dnsmessage.Builder) error {
@@ -447,7 +447,7 @@ func (x Xip) processQuestion(q dnsmessage.Question) (response Response, logMessa
return response, "", err
}
if len(txts) > 0 {
x.Metrics.SuccessfulQueries += 1
x.Metrics.AnsweredQueries += 1
}
response.Answers = append(response.Answers,
// 1 or more TXT records via Customizations
@@ -668,12 +668,18 @@ func IsAcmeChallenge(fqdnString string) bool {
}
func (x Xip) NSResources(fqdnString string) []dnsmessage.NSResource {
if IsAcmeChallenge(fqdnString) && !x.blocklist(fqdnString) {
x.Metrics.SuccessfulNSDNS01ChallengeQueries += 1
if x.blocklist(fqdnString) {
x.Metrics.AnsweredQueries += 1
x.Metrics.AnsweredBlockedQueries += 1
return NameServers
}
if IsAcmeChallenge(fqdnString) {
x.Metrics.AnsweredNSDNS01ChallengeQueries += 1
strippedFqdn := dns01ChallengeRE.ReplaceAllString(fqdnString, "")
ns, _ := dnsmessage.NewName(strippedFqdn)
return []dnsmessage.NSResource{{NS: ns}}
}
x.Metrics.AnsweredQueries += 1
return NameServers
}
@@ -720,7 +726,7 @@ func SOAResource(name dnsmessage.Name) dnsmessage.SOAResource {
// when TXT for "ip.sslip.io" is queried, return the IP address of the querier
func ipSslipIo(x Xip) ([]dnsmessage.TXTResource, error) {
x.Metrics.SuccessfulTXTSrcIPQueries += 1
x.Metrics.AnsweredTXTSrcIPQueries += 1
return []dnsmessage.TXTResource{{TXT: []string{x.SrcAddr.String()}}}, nil
}
@@ -738,13 +744,14 @@ func metricsSslipIo(x Xip) (txtResources []dnsmessage.TXTResource, err error) {
metrics = append(metrics, fmt.Sprintf("queries: %d", x.Metrics.Queries))
metrics = append(metrics, fmt.Sprintf("queries/second: %.1f", float64(x.Metrics.Queries)/uptime.Seconds()))
metrics = append(metrics, "successful:")
metrics = append(metrics, fmt.Sprintf("- queries: %d", x.Metrics.SuccessfulQueries))
metrics = append(metrics, fmt.Sprintf("- queries/second: %.1f", float64(x.Metrics.SuccessfulQueries)/uptime.Seconds()))
metrics = append(metrics, fmt.Sprintf("- A: %d", x.Metrics.SuccessfulAQueries))
metrics = append(metrics, fmt.Sprintf("- AAAA: %d", x.Metrics.SuccessfulAAAAQueries))
metrics = append(metrics, fmt.Sprintf("- source IP TXT: %d", x.Metrics.SuccessfulTXTSrcIPQueries))
metrics = append(metrics, fmt.Sprintf("- version TXT: %d", x.Metrics.SuccessfulTXTVersionQueries))
metrics = append(metrics, fmt.Sprintf("- DNS-01 challenge: %d", x.Metrics.SuccessfulNSDNS01ChallengeQueries))
metrics = append(metrics, fmt.Sprintf("- queries: %d", x.Metrics.AnsweredQueries))
metrics = append(metrics, fmt.Sprintf("- queries/second: %.1f", float64(x.Metrics.AnsweredQueries)/uptime.Seconds()))
metrics = append(metrics, fmt.Sprintf("- A: %d", x.Metrics.AnsweredAQueries))
metrics = append(metrics, fmt.Sprintf("- AAAA: %d", x.Metrics.AnsweredAAAAQueries))
metrics = append(metrics, fmt.Sprintf("- source IP TXT: %d", x.Metrics.AnsweredTXTSrcIPQueries))
metrics = append(metrics, fmt.Sprintf("- version TXT: %d", x.Metrics.AnsweredXTVersionQueries))
metrics = append(metrics, fmt.Sprintf("- DNS-01 challenge: %d", x.Metrics.AnsweredNSDNS01ChallengeQueries))
metrics = append(metrics, fmt.Sprintf("- blocked: %d", x.Metrics.AnsweredBlockedQueries))
for _, metric := range metrics {
txtResources = append(txtResources, dnsmessage.TXTResource{TXT: []string{metric}})
}
@@ -869,12 +876,13 @@ func soaLogMessage(soaResource dnsmessage.SOAResource) string {
// MostlyEquals compares all fields except `Start` (timestamp)
func (a Metrics) MostlyEquals(b Metrics) bool {
if a.Queries == b.Queries &&
a.SuccessfulQueries == b.SuccessfulQueries &&
a.SuccessfulAQueries == b.SuccessfulAQueries &&
a.SuccessfulAAAAQueries == b.SuccessfulAAAAQueries &&
a.SuccessfulTXTSrcIPQueries == b.SuccessfulTXTSrcIPQueries &&
a.SuccessfulTXTVersionQueries == b.SuccessfulTXTVersionQueries &&
a.SuccessfulNSDNS01ChallengeQueries == b.SuccessfulNSDNS01ChallengeQueries {
a.AnsweredQueries == b.AnsweredQueries &&
a.AnsweredAQueries == b.AnsweredAQueries &&
a.AnsweredAAAAQueries == b.AnsweredAAAAQueries &&
a.AnsweredTXTSrcIPQueries == b.AnsweredTXTSrcIPQueries &&
a.AnsweredXTVersionQueries == b.AnsweredXTVersionQueries &&
a.AnsweredNSDNS01ChallengeQueries == b.AnsweredNSDNS01ChallengeQueries &&
a.AnsweredBlockedQueries == b.AnsweredBlockedQueries {
return true
}
return false
@@ -951,6 +959,8 @@ func (x Xip) nameToAwithBlocklist(q dnsmessage.Question, response Response, logM
return response, logMessage + "nil, SOA " + soaLogMessage(soaResource), nil
}
if x.blocklist(q.Name.String()) {
x.Metrics.AnsweredQueries += 1
x.Metrics.AnsweredBlockedQueries += 1
response.Answers = append(response.Answers,
// 1 or more A records; A records > 1 only available via Customizations
func(b *dnsmessage.Builder) error {
@@ -968,8 +978,8 @@ func (x Xip) nameToAwithBlocklist(q dnsmessage.Question, response Response, logM
})
return response, logMessage + net.IP(Customizations["ns-aws.sslip.io."].A[0].A[:]).String(), nil
}
x.Metrics.SuccessfulQueries += 1
x.Metrics.SuccessfulAQueries += 1
x.Metrics.AnsweredQueries += 1
x.Metrics.AnsweredAQueries += 1
response.Answers = append(response.Answers,
// 1 or more A records; A records > 1 only available via Customizations
func(b *dnsmessage.Builder) error {
@@ -1011,6 +1021,8 @@ func (x Xip) nameToAAAAwithBlocklist(q dnsmessage.Question, response Response, l
return response, logMessage + "nil, SOA " + soaLogMessage(soaResource), nil
}
if x.blocklist(q.Name.String()) {
x.Metrics.AnsweredQueries += 1
x.Metrics.AnsweredBlockedQueries += 1
response.Answers = append(response.Answers,
// 1 or more A records; A records > 1 only available via Customizations
func(b *dnsmessage.Builder) error {
@@ -1028,8 +1040,8 @@ func (x Xip) nameToAAAAwithBlocklist(q dnsmessage.Question, response Response, l
})
return response, logMessage + net.IP(Customizations["ns-aws.sslip.io."].AAAA[0].AAAA[:]).String(), nil
}
x.Metrics.SuccessfulQueries += 1
x.Metrics.SuccessfulAAAAQueries += 1
x.Metrics.AnsweredQueries += 1
x.Metrics.AnsweredAAAAQueries += 1
response.Answers = append(response.Answers,
// 1 or more AAAA records; AAAA records > 1 only available via Customizations
func(b *dnsmessage.Builder) error {