mirror of
https://github.com/cunnie/sslip.io.git
synced 2025-10-06 16:18:00 +08:00
DNS: sslip.io's MXes are protonmail's servers
...and everyone else's are themselves, e.g. `127.0.0.1.sslip.io`'s MX
record is `127.0.0.1.sslip.io` with a preference of 0. This allows me to
get email for sslip.io without worrying about email for every sslip.io
subdomain.
- Refactor: the global variable `NameServers` no longer holds the IP
addresses of the nameservers, merely their names. The addresses are now
held in the `Customizations` variable, the more appropriate place. We
only want one source of truth wherever possible.
- 🐞 The original Go Playground for creating `dnsmessage.Name`s was
wrong: it said to NOT put a dot at the end. You need the dot at the end.
The MX records for `sslip.io` now have dots at the end.
- The above bug caused `processQuestion()` to return an unexpected
error, but without the underlying error message. Now, when
`processQuestion()` errors in an unexpected manner, it logs the
underlying error message, which makes debugging much easier.
- Richer logging for MX queries: we now return the servers and
preferences rather than the terse `MX`.
- We use specific `fqdnString` rather than the generic `domain`
as a variable for consistency, which is the hobgoblin of small minds.
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
@@ -39,10 +40,10 @@ var (
|
||||
ipv4RE = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])[.-]){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))($|[.-])`)
|
||||
ipv6RE = regexp.MustCompile(`(^|[.-])(([0-9a-fA-F]{1,4}-){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}-){1,7}-|([0-9a-fA-F]{1,4}-){1,6}-[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}-){1,5}(-[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}-){1,4}(-[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}-){1,3}(-[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}-){1,2}(-[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}-((-[0-9a-fA-F]{1,4}){1,6})|-((-[0-9a-fA-F]{1,4}){1,7}|-)|fe80-(-[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|--(ffff(-0{1,4}){0,1}-){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}-){1,4}-((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))($|[.-])`)
|
||||
ErrNotFound = errors.New("record not found")
|
||||
NameServers = map[string]dnsmessage.AResource{
|
||||
"ns-aws.nono.io.": {A: [4]byte{52, 0, 56, 137}},
|
||||
"ns-azure.nono.io.": {A: [4]byte{52, 187, 42, 158}},
|
||||
"ns-gce.nono.io.": {A: [4]byte{104, 155, 144, 4}},
|
||||
NameServers = []string{
|
||||
"ns-aws.nono.io.",
|
||||
"ns-azure.nono.io.",
|
||||
"ns-gce.nono.io.",
|
||||
}
|
||||
|
||||
Customizations = DomainCustomizations{
|
||||
@@ -57,22 +58,22 @@ var (
|
||||
// mail.protonmail.ch
|
||||
{
|
||||
Pref: 10,
|
||||
// Use The Go Playground https://play.golang.org/p/knv3Jbkq0DP
|
||||
// Use The Go Playground https://play.golang.org/p/tM4y1eLJ1dg
|
||||
// to convert strings to dnsmessage.Name for easy cut-and-paste
|
||||
MX: dnsmessage.Name{
|
||||
Length: 18,
|
||||
Length: 19,
|
||||
Data: [255]byte{
|
||||
109, 97, 105, 108, 46, 112, 114, 111, 116, 111, 110, 109, 97, 105, 108, 46, 99, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 97, 105, 108, 46, 112, 114, 111, 116, 111, 110, 109, 97, 105, 108, 46, 99, 104, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
// mailsec.protonmail.ch
|
||||
{
|
||||
Pref: 10,
|
||||
Pref: 20,
|
||||
MX: dnsmessage.Name{
|
||||
Length: 21,
|
||||
Length: 22,
|
||||
Data: [255]byte{
|
||||
109, 97, 105, 108, 115, 101, 99, 46, 112, 114, 111, 116, 111, 110, 109, 97, 105, 108, 46, 99, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 97, 105, 108, 115, 101, 99, 46, 112, 114, 111, 116, 111, 110, 109, 97, 105, 108, 46, 99, 104, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -151,7 +152,7 @@ func QueryResponse(queryBytes []byte) (responseBytes []byte, logMessage string,
|
||||
} else {
|
||||
// processQuestion shouldn't return any error but DNSError,
|
||||
// but who knows? Someone might break contract. This is the guard.
|
||||
err = errors.New("processQuestion() returned unexpected error type")
|
||||
err = fmt.Errorf("processQuestion() returned unexpected error type: %s", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -268,17 +269,22 @@ func processQuestion(q dnsmessage.Question, b *dnsmessage.Builder) (logMessage s
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = b.MXResource(dnsmessage.ResourceHeader{
|
||||
Name: q.Name,
|
||||
Type: dnsmessage.TypeMX,
|
||||
Class: dnsmessage.ClassINET,
|
||||
TTL: 604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
|
||||
Length: 0,
|
||||
}, MXResource())
|
||||
if err != nil {
|
||||
return
|
||||
mailExchangers := MXResource(q.Name.String())
|
||||
var logMessages []string
|
||||
for _, mailExchanger := range mailExchangers {
|
||||
err = b.MXResource(dnsmessage.ResourceHeader{
|
||||
Name: q.Name,
|
||||
Type: dnsmessage.TypeMX,
|
||||
Class: dnsmessage.ClassINET,
|
||||
TTL: 604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
|
||||
Length: 0,
|
||||
}, mailExchanger)
|
||||
logMessages = append(logMessages, strconv.Itoa(int(mailExchanger.Pref))+" "+string(mailExchanger.MX.Data[:]))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
logMessage += "MX"
|
||||
logMessage += strings.Join(logMessages, ", ")
|
||||
}
|
||||
case dnsmessage.TypeNS:
|
||||
{
|
||||
@@ -406,7 +412,7 @@ func NameToAAAA(fqdnString string) (*dnsmessage.AAAAResource, error) {
|
||||
|
||||
func NSResources() map[string]dnsmessage.NSResource {
|
||||
nsResources := make(map[string]dnsmessage.NSResource)
|
||||
for nameServer, _ := range NameServers {
|
||||
for _, nameServer := range NameServers {
|
||||
var nameServerBytes [255]byte
|
||||
copy(nameServerBytes[:], nameServer)
|
||||
nsResources[nameServer] = dnsmessage.NSResource{
|
||||
@@ -419,28 +425,35 @@ func NSResources() map[string]dnsmessage.NSResource {
|
||||
return nsResources
|
||||
}
|
||||
|
||||
func MXResource() dnsmessage.MXResource {
|
||||
func MXResource(fqdnString string) []dnsmessage.MXResource {
|
||||
if domain, ok := Customizations[fqdnString]; ok {
|
||||
if len(domain.MX) > 0 {
|
||||
return domain.MX
|
||||
}
|
||||
}
|
||||
var mxHostBytes [255]byte
|
||||
copy(mxHostBytes[:], MxHost)
|
||||
return dnsmessage.MXResource{
|
||||
Pref: 0,
|
||||
MX: dnsmessage.Name{
|
||||
Data: mxHostBytes,
|
||||
Length: uint8(len(MxHost)),
|
||||
copy(mxHostBytes[:], fqdnString)
|
||||
return []dnsmessage.MXResource{
|
||||
{
|
||||
Pref: 0,
|
||||
MX: dnsmessage.Name{
|
||||
Data: mxHostBytes,
|
||||
Length: uint8(len(fqdnString)),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SOAResource returns the hard-coded SOA
|
||||
func SOAResource(domain string) dnsmessage.SOAResource {
|
||||
func SOAResource(fqdnString string) dnsmessage.SOAResource {
|
||||
var domainBytes [255]byte
|
||||
copy(domainBytes[:], domain)
|
||||
copy(domainBytes[:], fqdnString)
|
||||
var mboxArray [255]byte
|
||||
copy(mboxArray[:], Hostmaster)
|
||||
return dnsmessage.SOAResource{
|
||||
NS: dnsmessage.Name{
|
||||
Data: domainBytes,
|
||||
Length: uint8(len(domain)),
|
||||
Length: uint8(len(fqdnString)),
|
||||
},
|
||||
MBox: dnsmessage.Name{
|
||||
Data: mboxArray,
|
||||
|
@@ -290,18 +290,28 @@ var _ = Describe("Xip", func() {
|
||||
})
|
||||
|
||||
Describe("MXResource()", func() {
|
||||
It("returns the MX resource (go ProtonMail!)", func() {
|
||||
mx := xip.MXResource()
|
||||
It("returns the MX resource", func() {
|
||||
query := "xyz"
|
||||
mx := xip.MXResource(query)
|
||||
var mxHostBytes [255]byte
|
||||
copy(mxHostBytes[:], xip.MxHost)
|
||||
Expect(mx.MX.Data).To(Equal(mxHostBytes))
|
||||
copy(mxHostBytes[:], query)
|
||||
Expect(len(mx)).To(Equal(1))
|
||||
Expect(mx[0].MX.Length).To(Equal(uint8(3))) // "xyz" has 3 letters
|
||||
Expect(mx[0].MX.Data).To(Equal(mxHostBytes))
|
||||
})
|
||||
When("sslip.io is the domain being queried", func() {
|
||||
It("returns sslip.io's custom MX records", func() {
|
||||
mx := xip.MXResource("sslip.io.")
|
||||
Expect(len(mx)).To(Equal(2))
|
||||
Expect(mx[0].MX.Data).To(Equal(xip.Customizations["sslip.io."].MX[0].MX.Data))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NSResources()", func() {
|
||||
It("returns a map of the name servers", func() {
|
||||
ns := xip.NSResources()
|
||||
for nameServer, _ := range xip.NameServers {
|
||||
for _, nameServer := range xip.NameServers {
|
||||
var nameServerBytes [255]byte
|
||||
copy(nameServerBytes[:], nameServer)
|
||||
Expect(ns[nameServer].NS.Data).To(Equal(nameServerBytes))
|
||||
|
Reference in New Issue
Block a user