🐞 Don't panic() invoking a customized TXT

We made a mistake: we blindly invoked a function that was sometimes
`nil`. Specifically, if we had a customized domain (e.g. `ns.sslip.io`)
that didn't have a TXT record (a function), we'd try to invoke it
anyway. Bad move.

Now we ensure the function is there before we try to invoke it.

This is a curious affirmation of installing metrics: if we hadn't seen
that the server had been restarted because uptime was too low, we
wouldn't have caught this bug.

Drive-by: we made the lengths of TXT records of `version.status.sslip.io`
exactly match what we replace them with during the linking phase. We
hope that this fixes the wrong-line-numbers we see in the `panic()`
messages.

[fixes #14]
This commit is contained in:
Brian Cunnie
2022-01-20 07:43:51 -08:00
parent b119442a37
commit e215c4fda4
4 changed files with 19 additions and 10 deletions

View File

@@ -111,8 +111,8 @@ var _ = Describe("sslip.io-dns-server", func() {
`TypeSRV example.com. \? nil, SOA example.com. briancunnie.gmail.com. 2022011900 900 900 1800 180\n$`), `TypeSRV example.com. \? nil, SOA example.com. briancunnie.gmail.com. 2022011900 900 900 1800 180\n$`),
Entry(`TXT for version.status.sslip.io is the version number of the xip software (which gets overwritten during linking)`, Entry(`TXT for version.status.sslip.io is the version number of the xip software (which gets overwritten during linking)`,
"@127.0.0.1 version.status.sslip.io txt +short", "@127.0.0.1 version.status.sslip.io txt +short",
`\A"dev"\n"today"\n"xxx"\n\z`, `\A"0.0.0"\n"0001/01/01-99:99:99-0800"\n"cafexxx"\n\z`,
`TypeTXT version.status.sslip.io. \? \["dev"\], \["today"\], \["xxx"\]`), `TypeTXT version.status.sslip.io. \? \["0.0.0"\], \["0001/01/01-99:99:99-0800"\], \["cafexxx"\]`),
Entry(`TXT is the querier's IPv4 address and the domain "ip.sslip.io"`, Entry(`TXT is the querier's IPv4 address and the domain "ip.sslip.io"`,
"@127.0.0.1 ip.sslip.io txt +short", "@127.0.0.1 ip.sslip.io txt +short",
`127.0.0.1`, `127.0.0.1`,

View File

@@ -105,9 +105,9 @@ var (
dkim2, _ = dnsmessage.NewName("protonmail2.domainkey.dw4gykv5i2brtkjglrf34wf6kbxpa5hgtmg2xqopinhgxn5axo73a.domains.proton.ch.") dkim2, _ = dnsmessage.NewName("protonmail2.domainkey.dw4gykv5i2brtkjglrf34wf6kbxpa5hgtmg2xqopinhgxn5axo73a.domains.proton.ch.")
dkim3, _ = dnsmessage.NewName("protonmail3.domainkey.dw4gykv5i2brtkjglrf34wf6kbxpa5hgtmg2xqopinhgxn5axo73a.domains.proton.ch.") dkim3, _ = dnsmessage.NewName("protonmail3.domainkey.dw4gykv5i2brtkjglrf34wf6kbxpa5hgtmg2xqopinhgxn5axo73a.domains.proton.ch.")
VersionSemantic = "dev" VersionSemantic = "0.0.0"
VersionDate = "today" VersionDate = "0001/01/01-99:99:99-0800"
VersionGitHash = "xxx" VersionGitHash = "cafexxx"
TxtKvCustomizations = KvCustomizations{} TxtKvCustomizations = KvCustomizations{}
Customizations = DomainCustomizations{ Customizations = DomainCustomizations{
@@ -748,8 +748,10 @@ func (x Xip) TXTResources(fqdn string) ([]dnsmessage.TXTResource, error) {
if domain, ok := Customizations[strings.ToLower(fqdn)]; ok { if domain, ok := Customizations[strings.ToLower(fqdn)]; ok {
// Customizations[strings.ToLower(fqdn)] returns a _function_, // Customizations[strings.ToLower(fqdn)] returns a _function_,
// we call that function, which has the same return signature as this method // we call that function, which has the same return signature as this method
if domain.TXT != nil {
return domain.TXT(x) return domain.TXT(x)
} }
}
return nil, nil return nil, nil
} }

View File

@@ -161,6 +161,13 @@ var _ = Describe("Xip", func() {
Expect(txts[0].TXT[0]).To(MatchRegexp("^1.1.1.1$")) Expect(txts[0].TXT[0]).To(MatchRegexp("^1.1.1.1$"))
}) })
}) })
When(`a customized domain without a TXT entry is queried`, func() {
It("returns no records (and doesn't panic, either)", func() {
txts, err := x.TXTResources("ns.sslip.io.")
Expect(err).To(Not(HaveOccurred()))
Expect(len(txts)).To(Equal(0))
})
})
When(`the domain "k-v.io is queried"`, func() { When(`the domain "k-v.io is queried"`, func() {
txtTests := func() { txtTests := func() {
DescribeTable(`the domain "k-v.io" is queried for TXT records`, DescribeTable(`the domain "k-v.io" is queried for TXT records`,

View File

@@ -109,19 +109,19 @@ describe domain do
expect(`dig @#{whois_nameserver} TXT ip.#{domain} +short`).to match(/^"([0-9]+\.[0-9]+\.[0-9]+\.[0-9+])|(([0-9a-fA-F]*:){2,7}[0-9a-fA-F]*)"$/) expect(`dig @#{whois_nameserver} TXT ip.#{domain} +short`).to match(/^"([0-9]+\.[0-9]+\.[0-9]+\.[0-9+])|(([0-9a-fA-F]*:){2,7}[0-9a-fA-F]*)"$/)
end end
it "sets a key-value @#{whois_nameserver} sslipio-spec.kv.sslip.io" do it "sets a key-value @#{whois_nameserver} sslipio-spec.k-v.io" do
expect(`dig @#{whois_nameserver} put.MyKey.sslipio-spec.kv.#{domain} TXT +short`).to match(/^"MyKey"$/) expect(`dig @#{whois_nameserver} put.MyKey.sslipio-spec.kv.#{domain} TXT +short`).to match(/^"MyKey"$/)
end end
it "gets a key-value @#{whois_nameserver} sslipio-spec.kv.sslip.io" do it "gets a key-value @#{whois_nameserver} sslipio-spec.k-v.io" do
expect(`dig @#{whois_nameserver} sslipio-spec.kv.#{domain} TXT +short`).to match(/^"MyKey"$/) expect(`dig @#{whois_nameserver} sslipio-spec.kv.#{domain} TXT +short`).to match(/^"MyKey"$/)
end end
it "deletes a key-value @#{whois_nameserver} sslipio-spec.kv.sslip.io" do it "deletes a key-value @#{whois_nameserver} sslipio-spec.k-v.io" do
expect(`dig @#{whois_nameserver} delete.sslipio-spec.kv.#{domain} TXT +short`).to match(/^"MyKey"$/) expect(`dig @#{whois_nameserver} delete.sslipio-spec.kv.#{domain} TXT +short`).to match(/^"MyKey"$/)
end end
it "gets a key-value @#{whois_nameserver} sslipio-spec.kv.sslip.io" do it "gets a key-value @#{whois_nameserver} sslipio-spec.k-v.io" do
expect(`dig @#{whois_nameserver} sslipio-spec.kv.#{domain} TXT +short`).to match(/^$/) expect(`dig @#{whois_nameserver} sslipio-spec.kv.#{domain} TXT +short`).to match(/^$/)
end end
end end