sslip.io
_sslip.io_ is a DNS server that maps specially-crafted DNS A records to IP addresses (e.g. "127-0-0-1.sslip.io" maps to 127.0.0.1). It is similar to, and inspired by the now-defunct xip.io.
If you'd like to use sslip.io _as a service_, refer to the website (nip.io) for more information. This README targets developers; the website targets users.
Quick Start
git clone https://github.com/cunnie/sslip.io.git
cd sslip.io
go mod tidy
sudo go run .
# sudo is required to bind to privileged port 53
In another window:
dig @localhost 192.168.0.1.sslip.io +short
# should return "192.168.0.1"
Quick Start Tests
go mod tidy
go generate
go install github.com/onsi/ginkgo/v2/ginkgo
go get github.com/onsi/gomega/...
# exclude subdir "spec/", used for testing sslip.io service not code
~/go/bin/ginkgo -r -p --skip-package=spec .
Running Your Own Nameservers
We can customize our nameserver and address records (NS, A, and AAAA). This can
be done with a combination of the -ns, -a, and -aaaa flags.
For example, let's say we're the DNS admin for pivotal.io and our email is dns-admin\@pivotal.io, and we'd like to have a subdomain, "xip.pivotal.io", that does sslip.io-style lookups (e.g. "127.0.0.1.xip.pivotal.io" would resolve to "127.0.0.1"). Let's say we have two servers that we've set aside for this purpose:
- ns-ip-0.pivotal.io, 10.8.8.8 (IPv4)
- ns-ip-1.pivotal.io, fc88:: (IPv6)
# after we've cloned our repo & cd'ed into it
go run . \
-ns=.=ns-ip-0.pivotal.io \
-ns=.=ns-ip-1.pivotal.io \
-a=ns-ip-0.pivotal.io=10.8.8.8 \
-aaaa=ns-ip-1.pivotal.io=fc88:: \
-soa=ns-ip-0.pivotal.io,dns-admin.pivotal.io,20261024,900,900,604800,180 \
-blocklistURL=file:///dev/null \
-ptr-domain=xip.pivotal.io
Note: These nameservers are not general-purpose nameservers; for example, they won't look up google.com. They are not recursive. **Don't ever configure a client to use these nameservers**.
Running with Docker
Probably the easiest way to run the nameserver is with the official Docker image, cunnie/sslip.io-dns-server. Using our DNS servers from the previous example, we run the following, setting our port to 5553 so we can run unprivileged:
docker run \
-it \
--rm \
-p 5553:53/udp \
cunnie/sslip.io-dns-server \
-ns=.=ns-ip-0.pivotal.io \
-ns=.=ns-ip-1.pivotal.io \
-a=ns-ip-0.pivotal.io=10.8.8.8 \
-aaaa=ns-ip-1.pivotal.io=fc88:: \
-soa=ns-ip-0.pivotal.io,dns-admin.pivotal.io,20261024,900,900,604800,180 \
-blocklistURL=file:///dev/null \
-ptr-domain=xip.pivotal.io
From our machine, we look up the DNS NS records for "127.0.0.1.com", and we see the expected reply:
dig ns 127.0.0.1.com @localhost -p 5553
...
;; ANSWER SECTION:
127.0.0.1.com. 604800 IN NS ns-ip-1.pivotal.io.
127.0.0.1.com. 604800 IN NS ns-ip-0.pivotal.io.
;; ADDITIONAL SECTION:
ns-ip-0.pivotal.io. 604800 IN A 10.8.8.8
ns-ip-1.pivotal.io. 604800 IN AAAA fc88::
The Docker image is multi-platform, supporting both x86_64 architecture as well as ARM64 (AWS Graviton, Apple M1–M6).
Command-line Flags
-portoverrides the default port, 53, which the server binds to. This can
listen udp :53: bind: permission denied"). For
example, to run the server on port 9553: go run main.go -port 9553. To
query, dig @localhost 127.0.0.1.sslip.io -p 9553
-nssets NS records asdomain=nameserver. If the domain is., it sets
-ns=.=ns1.example.com
-ns=.=ns2.example.com. If you're running your own nameservers, you probably
want to set this; otherwise no NS records are returned. Don't forget to set
address records for your nameservers with the -a and -aaaa flags (see
below). For any other domain, -ns delegates that domain and its subdomains
to the nameserver, often used to acquire wildcard certificates from Let's
Encrypt via the DNS-01 challenge, e.g.
-ns=_acme-challenge.73-189-219-4.xip.nono.io=ns-437.awsdns-54.com
-asets an A (IPv4) record ashostname=ipv4, e.g.
-a=ns1.example.com=10.8.8.8. Repeat the flag to set many addresses for a
single host, e.g. -a=ns1.example.com=1.1.1.1 -a=ns1.example.com=8.8.8.8
-aaaasets an AAAA (IPv6) record ashostname=ipv6, e.g.
-aaaa=ns1.example.com=fc::8888
-soasets the SOA record returned for every domain as
mname,rname,serial,refresh,retry,expire,minimum, e.g.
-soa=ns1.example.com,dns-admin.example.com,20261024,900,900,604800,180.
Unlike the other record flags, there's only one SOA, and it always has a
default: ns-01.nip.io.,dns.nip.io.,20261024,900,900,604800,180
-mxsets an MX record asdomain=preference,host, e.g.
-mx=example.com=10,mail.example.com -mx=example.com=20,mail2.example.com.
Without it, the MX record is the queried hostname with a preference of 0
-txtsets a TXT record asdomain=text; the surrounding double quotes are
-txt=example.com="v=spf1 mx -all". Text longer than 255
bytes is split into multiple strings within the record
-cnamesets a CNAME record asdomain=target, e.g.
-cname=www.example.com=example.com. A domain can have only one CNAME
-blocklistURLoverrides the default block list,
-ptr-domainthe domain to use for PTR records. For example, if you set
-ptr-domain=ip.example.com and then do a reverse-lookup (PTR record), e.g.
dig -x 127.0.0.1, the result will be 127-0-0-1.ip.example.com. Best
practice: make sure the forward lookup matches the reverse lookup, e.g. dig
127-0-0-1.ip.example.com should return an A record of 127.0.0.1.
-publiccontrols whether public addresses are resolved. If unsure, set
-public=false, which means only private IP addresses will resolve, e.g.
10.9.9.30, 192.168.0.1, 169.254.169.254. Let's say you run a bank, and
your nip.io-style subdomain is ip.wellsfargo.com, you don't a phisher
scammer to spin up a VM with a public IP address and get a certificate for
that IP address's hostname 52-0-56-137.ip.wellsfargo.com and use it to
phish your customers. -public=false prevents that scenario.
-quietsuppresses logging of each DNS response, which can save you money
-dnstapenables dnstap logging of queries that
/var/run/dnstap.sock) or a TCP address (e.g.
127.0.0.1:6000)
In the record flags (-ns, -a, -aaaa, -soa, -mx, -txt, -cname),
names are case-insensitive, and the trailing dot is optional. You can repeat
-ns, -a, -aaaa, -mx, and -txt to set several records for the same
domain.
DNS Server Miscellany
- It binds to both UDP and TCP.
- It returns the same SOA record for every domain (see
-soa). - There are no SRV records
Running Tests
spec/contains the tests for the production nameservers. To ensure the production nameservers are running properly:
DOMAINS=nip.io,sslip.io ginkgo -r -p spec/
- To test the code (if you've made changes) without testing the production nameservers:
ginkgo -r -p --skip-package=spec
k8s/document_root_nip.io/contains the HTML content of the nip.io
Acknowledgements
- The late, great Roopinder Singh (nip.io), Sam Stephenson (xip.io), and the
- The contributors (@normanr, @jpambrun come to mind) who improved sslip.io
- Let's Encrypt for bumping our rate limits many, many times