sslip.io
![CI Tests](https://github.com/cunnie/sslip.io/actions/workflows/ci-tests.yml/badge.svg)
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, xip.io.
If you'd like to use sslip.io as a service, refer to the website
(sslip.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 main.go
In another window:
dig @localhost 192.168.0.1.sslip.io +short
Quick Start Tests
go mod tidy
go generate
ginkgo -r -p .
Running Your Own Nameservers
We can customize our nameserver and address records (NS, A, and AAAA), which
can be particularly useful in an internetless (air-gapped) environment. This can
be done with a combination of the -nameservers
flag and the -addresses
flag.
For example, let's say we're the DNS admin for 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-sslip-0.pivotal.io, 10.8.8.8 (IPv4)
- ns-sslip-1.pivotal.io, fc88:: (IPv6)
First, we delegate the subdomain "xip.pivotal.io" to our two nameservers, and
then we run the following command run on each of the two servers:
go run main.go \
-nameservers=ns-sslip-0.pivotal.io,ns-sslip-1.pivotal.io \
-addresses ns-sslip-0.pivotal.io=10.8.8.8,ns-sslip-1.pivotal.io=fc88::
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
machine to point to these nameservers.
Running with Docker
Probably the easiest way to run the nameserver is with the official Docker
image,
cunnie/sslip.io-dns-server:
docker run \
-it \
--rm \
-p 53:53/udp \
cunnie/sslip.io-dns-server
If we see the error, "Error starting userland proxy: listen udp4 0.0.0.0:53: bind: address already in use.
", we turn off the systemd resolver: sudo systemctl stop systemd-resolved
Let's try a more complicated setup: we're on our workstation, jammy.nono.io,
whose IP addresses are 10.9.9.114 and 2601:646:0100:69f0:0:ff:fe00:72. We'd like
our workstation to be the DNS server:
docker run \
-it \
--rm \
-p 53:53/udp \
cunnie/sslip.io-dns-server \
-nameservers jammy.nono.io \
-addresses jammy.nono.io=10.9.9.114,jammy.nono.io=2601:646:100:69f0:0:ff:fe00:72
From another machine, we look up the DNS NS record for "127.0.0.1.com", and we
see the expected reply:
dig ns 127.0.0.1.com @jammy.nono.io +short
...
;; ANSWER SECTION:
127.0.0.1.com. 604800 IN NS jammy.nono.io.
;; ADDITIONAL SECTION:
jammy.nono.io. 604800 IN A 10.9.9.114
jammy.nono.io. 604800 IN AAAA 2601:646:100:69f0:0:ff:fe00:72
The Docker image is multi-platform, supporting both x86_64 architecture as well
as ARM64 (AWS Graviton, Apple M1/M2).
Command-line Flags
-port
overrides the default port, 53, which the server binds to. This can
be especially useful when running as a non-privileged user, unable to bind to
privileged ports (<1024) ("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
-nameservers
overrides the default NS records
ns-gce.sslip.io
, ns-hetzner.sslip.io
, and ns-ovh.sslip.io
; flag, e.g. go run main.go -nameservers ns1.example.com,ns2.example.com
). If you're running your own
nameservers, you probably want to set this. Don't forget to set address records
for the new name servers with the -addresses
flag (see below). Exception:
_acme-challenge
records are handled differently to accommodate the
procurement of Let's Encrypt wildcard certificates; you can read more about
that procedure here-addresses
overrides the default A/AAAA (IPv4/IPv6) address records. For
example, here's how we set the IPv4 record & IPv6 record for our nameserver (in
the -nameservers
example above), ns1.example.com: -addresses ns1.example.com=10.8.8.8,ns1.example.com=fc::8888
. Note that you can set many
addresses for a single host, e.g.
ns1.example.com=1.1.1.1,ns1.example.com=8.8.8.8,ns1.example.com=9.9.9.9
-blocklistURL
overrides the default block list,
(https://raw.githubusercontent.com/cunnie/sslip.io/main/etc/blocklist.txt).
It's not necessary to override this if you're in an internetless environment:
if the DNS server can't download the blocklist, it prints out a message and
continues to serve DNS queries
DNS Server Miscellany
- it binds to both UDP and TCP.
- The SOA record is hard-coded except the MNAME (primary master name server)
record, which is set to the queried hostname (e.g.
dig big.apple.com @ns-ovh.nono.io
would return an SOA with an MNAME record of
big.apple.com.
- The MX records are hard-coded to the queried hostname with a preference of 0,
except
sslip.io
itself, which has custom MX records to enable email
delivery to ProtonMail - There are no SRV records
Directory Structure
Acknowledgements
- Sam Stephenson (xip.io), Roopinder Singh (nip.io), and the other DNS
developers out there
- The contributors (@normanr, @jpambrun come to mind) who improved sslip.io
- Jenessa Petersen of Let's Encrypt who bumped the rate limits
- JetBrains who provided a free license for open source
development