Skip to content

Commit

Permalink
Return NS records randomly
Browse files Browse the repository at this point in the history
Previously when the NS records were returned, ns-aws was always returned
first. Coincidentally, 64% of the queries were directed to ns-aws. And
once I exceeded AWS's 10 TB bandwidth limit, AWS began gouging me for
bandwidth charges, and $12.66/month rapidly climbed to $62.30

I'm hoping that by randomly rotating the order of nameservers, the
traffic will balance across the nameservers.

Current snapshot (already ns-ovh is helping):

ns-aws.sslip.io
"Queries: 237744377 (1800.6/s)"
"Answered Queries: 63040894 (477.5/s)"

ns-azure.sslip.io
"Queries: 42610823 (323.4/s)"
"Answered Queries: 14660603 (111.3/s)"

ns-gce.sslip.io
"Queries: 59734371 (454.1/s)"
"Answered Queries: 17636444 (134.1/s)"

ns-ovh.sslip.io
"Queries: 135897332 (1034.4/s)"
"Answered Queries: 36010164 (274.1/s)"
  • Loading branch information
cunnie committed Sep 17, 2024
1 parent 73df72a commit 1b5f4d6
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 9 deletions.
7 changes: 4 additions & 3 deletions integration_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ var _ = Describe("flags", func() {
Expect(err).ToNot(HaveOccurred())
Eventually(digSession).Should(Say(`flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0`))
Eventually(digSession).Should(Say(`;; ANSWER SECTION:`))
Eventually(digSession).Should(Say(`mickey.minnie.\n`))
Eventually(digSession).Should(Say(`daffy.duck.\n`))
Eventually(digSession, 1).Should(Exit(0))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`mickey.minnie.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`daffy.duck.\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`Adding nameserver "mickey\.minnie\."\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`Adding nameserver "daffy\.duck\."\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeNS example.com. \? mickey\.minnie\., daffy\.duck\.\n`))
// we don't know the order in which the nameservers will be returned, so we try both
Eventually(string(serverSession.Err.Contents())).Should(Or(MatchRegexp(`TypeNS example.com. \? mickey\.minnie\., daffy\.duck\.\n`), MatchRegexp(`TypeNS example.com. \? daffy\.duck\., mickey\.minnie\.\n`)))
})
When("a nameserver is an empty string", func() {
BeforeEach(func() {
Expand Down
12 changes: 7 additions & 5 deletions integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,6 @@ var _ = Describe("sslip.io-dns-server", func() {
Expect(err).ToNot(HaveOccurred())
Eventually(digSession).Should(Say(`flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 7`))
Eventually(digSession).Should(Say(`;; ANSWER SECTION:`))
Eventually(digSession).Should(Say(`ns-aws.sslip.io.\n`))
Eventually(digSession).Should(Say(`ns-azure.sslip.io.\n`))
Eventually(digSession).Should(Say(`ns-gce.sslip.io.\n`))
Eventually(digSession).Should(Say(`ns-ovh.sslip.io.\n`))
Eventually(digSession).Should(Say(`;; ADDITIONAL SECTION:`))
Eventually(digSession).Should(Say(`ns-aws.sslip.io..*52.0.56.137\n`))
Eventually(digSession).Should(Say(`ns-aws.sslip.io..*2600:1f18:aaf:6900::a\n`))
Expand All @@ -281,6 +277,11 @@ var _ = Describe("sslip.io-dns-server", func() {
Eventually(digSession).Should(Say(`ns-ovh.sslip.io..*51.75.53.19\n`))
Eventually(digSession).Should(Say(`ns-ovh.sslip.io..*2001:41d0:602:2313::1\n`))
Eventually(digSession, 1).Should(Exit(0))
// the server names may appear out-of-order
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-aws.sslip.io.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-azure.sslip.io.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-gce.sslip.io.\n`))
Eventually(string(digSession.Out.Contents())).Should(MatchRegexp(`NS\tns-ovh.sslip.io.\n`))
Eventually(string(serverSession.Err.Contents())).Should(MatchRegexp(`TypeNS example.com. \? ns-aws.sslip.io., ns-azure.sslip.io., ns-gce.sslip.io., ns-ovh.sslip.io.\n`))
})
})
Expand Down Expand Up @@ -400,9 +401,10 @@ var _ = Describe("sslip.io-dns-server", func() {
"@localhost international-raiffeisen-bank.fc00--.sslip.io aaaa +short",
`\Afc00::\n\z`,
`TypeAAAA international-raiffeisen-bank.fc00--.sslip.io. \? fc00::\n$`),
// use regex to account for rotated nameserver order
Entry("an NS record with acme_challenge with a forbidden string is not delegated",
"@localhost _acme-challenge.raiffeisen.fe80--.sslip.io ns +short",
`\Ans-aws.sslip.io.\nns-azure.sslip.io.\nns-gce.sslip.io.\nns-ovh.sslip.io.\n\z`,
`\Ans-[a-z]+.sslip.io.\nns-[a-z]+.sslip.io.\nns-[a-z]+.sslip.io.\nns-[a-z]+.sslip.io.\n\z`,
`TypeNS _acme-challenge.raiffeisen.fe80--.sslip.io. \? ns-aws.sslip.io., ns-azure.sslip.io., ns-gce.sslip.io., ns-ovh.sslip.io.\n$`),
Entry("an A record with a forbidden CIDR is redirected",
"@localhost nf.43.134.66.67.sslip.io +short",
Expand Down
6 changes: 5 additions & 1 deletion xip/xip.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,9 +647,13 @@ func (x *Xip) NSResponse(name dnsmessage.Name, response Response, logMessage str
var logMessages []string
if response.Header.Authoritative {
// we're authoritative, so we reply with the answers
// but we rotate the nameservers every second so ns-aws doesn't bear the brunt (64%) of the traffic
epoch := time.Now().UTC().Unix()
index := int(epoch) % len(x.NameServers)
rotatedNameservers := append(x.NameServers[index:], x.NameServers[0:index]...)
response.Answers = append(response.Answers,
func(b *dnsmessage.Builder) error {
return buildNSRecords(b, name, x.NameServers)
return buildNSRecords(b, name, rotatedNameservers)
})
} else {
// we're NOT authoritative, so we reply who is authoritative
Expand Down

0 comments on commit 1b5f4d6

Please sign in to comment.