Some clients query us for the A records of our nameservers even though
our nameservers aren't in our domain; the nameservers are in the
`nono.io` domain, not in the `sslip.io` domain.
Our new code returns the A records of our nameservers:
previously:
```
2020/11/28 21:57:38 190.113.222.130.55236 TypeA ns-aws.nono.io. ? nil, SOA
2020/11/28 21:57:38 190.113.222.130.49919 TypeA ns-azure.nono.io. ? nil, SOA
2020/11/28 21:57:38 190.113.222.130.8090 TypeA ns-gce.nono.io. ? nil, SOA
```
now:
```
2020/11/30 13:20:10 127.0.0.1.58410 TypeA ns-aws.nono.io. ? 52.0.56.137
2020/11/30 13:20:20 127.0.0.1.54717 TypeA ns-azure.nono.io. ? 52.187.42.158
2020/11/30 13:20:28 127.0.0.1.62487 TypeA ns-gce.nono.io. ? 104.155.144.4
```
I learned about Golang maps while implementing this feature.
The nameservers only use the pipe backend because they are no longer
acting as secondaries for the "regular" domains.
They are now exclusively serving sslip.io domain (and whitelabels).
I had accidentally swapped the SOA & hostmaster. This didn't break
anything, but it's very embarrassing.
fixes <http://www.webdnstools.com/dnstools/domain_check>:
> Checking DNS contact email address is valid. ns-he@nono.io is not valid. Mail server returned 'no such user'.
> Your SOA record lists briancunnie.gmail.com as the Primary nameserver. This server is not listed as a valid nameserver at the parent servers.
The packaging script is a bit of a hack: we create the `src/` directory
and move our source into it. 🤮
The source should have been in the proper directory to begin with, but
I'm too tired to fight with directory structures right now.
fixes:
```
main.go:7:2: module github.com/cunnie/sslip.io@latest found (v0.0.0-20201126193932-8400f99e37d2), but does not contain package github.com/cunnie/sslip.io/src/xip
```
This is a bittersweet moment—it's likely the last BOSH release I'll ever
write, and in some ways is closing a chapter of my life that I found
incredibly fun, exciting, and educational.
Why write a BOSH Release? Because the sslip.io infrastructure, or at
least three of the four nameservers, are BOSH-deployed.
Why write a DNS server? Why not continue with the existing PowerDNS
server + BASH backend? Because I'm stuck at the 4.2.2 PowerDNS release,
and I was unable to get 4.3+ to compile in the BOSH way. Let's be
honest: converting an application to a BOSH package is like doing a
port, a difficult port, and it was easier to write my own DNS server
than port PowerDNS 4.3+ to BOSH.
There's only one job in this commit (`sslip.io-dns-server`), which is
clearly named to avoid confusing with the at least 3 other DNS servers
(BOSH's DNS, BIND, and PowerDNS) that have BOSH releases. The BOSH
package will be in an upcoming commit.
I used a shorthand logging which extracts the info I'm interested in:
- IP of the asker (e.g. 10.0.9.30)
- Port of the asker (e.g. 59036)
- Type of the question (e.g. TypeA)
- Name of the question (e.g. 127.0.0.1.nono.io)
- Question mark (a delimiter)
- one of the following
- answer (e.g. 127.0.0.1, MX, NS, SOA)
- or no answer, but an authority section (e.g. nil, SOA)
We want to log queries (mostly because I'd like some metric of how many
queries people are making, what those queries are, and what my answers
are).
I also put a guard against one of the error conditions (I had assumed
only one type of error would ever be returned; I believe that assumption
is naïve)
- Unlike MX and SOA records, NS records are an array.
- Moved the variables into a block `var ( ... )`, reads more easily.
- `processQuestion()` answers MX & SOA records (and of course NS
records)
Sure, they have unit tests, but the methods are so simple I'm not sure
they're worth testing.
I changed the hostmaster to `yoyo@nono.io` because I felt more
comfortable having the email on ProtonMail in lieu of Gmail.
- Refactored the tests, but they're still hard to follow
Todo:
- break out the case statement to a separate method in `QueryResponse()`
- add NS, MX records
- Change Ginkgo's `To(Not(` to use the shorter `ToNot(`
- did fewer initializations in the `vars` block and moved them to the
`BeforeEach()` blocks.
The `QueryResponse()` test is too long & convoluted; even I have a hard
time understanding them, and I wrote them! The tests & code should be
re-written, but that's for another day.
- It automatically populates the header for us, which would have been a
big headache to do manually.
- Switched `ENOTFOUND` to `ErrNotFound`, and updated the error message
as well. As sad as it was to make this switch, I must acknowledge that
I'm coding in Go, not C, and I should follow its conventions.
- TWO OF THE TESTS ARE BROKEN. I know, I'll fix them soon. I should have
fixed the tests first, then the code, but I was overeager.
- it resolves `127.0.0.1.sslip.io`
- it ranges through all the questions in query, even though, IIRC, only
the first one is ever populated.
- ran both `gofmt` and `goimports`
- currently hard-coded. And I didn't think too hard about how I could
make it more flexible in the future.
- various times stolen from the domain `google.com`, with the exception
of `minTTL`, which I bumped from 60 to 300.
- I called variable names that are arrays "...Array" because they're so
rare--slices are much more common.
- fixed a bug in main.go where the error-logic was inverted.
`QueryResponse()` takes a byte array and returns a byte array. It's a
black box that `main.go` can use to input the DNS query and get back the
DNS response. This enables us to have a very lean `main.go`, which means
we can put much of the processing into the library, and which means we
can unit-test the components.
- A better-late-than-never `gofmt -w .` included cosmetic changes.
IPv6 only works on dashes, not dots. Mostly because the double-colon:
`--1` → `::1`. The double-colon, in dot-notation, would be `..`, which
is invalid in DNS.
- tested with ginkgo
- The primary method, `NameToA`, returns a resource and an error.
The error can be one value, "ENOTFOUND". I was not sure about the
returning the error—maybe I could return nil (not possible) when
I can't find the IP, or maybe return a 0.0.0.0 IP, but 0.0.0.0 is a
valid IP, so I use the error as out-of-band signaling.
ns-vultr.nono.io is a bad nameserver because it's shut down for ~8 days
each month (when the unbelievable Singapore hunger for NTP uses up my
monthly allowance of 3TB)
Besides, three nameservers is enough.