Unix: split-horizon dns

This commit is contained in:
Akemi Izuko 2024-07-07 16:17:37 -06:00
parent bd305cb283
commit eca17022b0
Signed by: akemi
GPG key ID: 8DE0764E1809E9FC

View file

@ -0,0 +1,191 @@
---
title: 'Reaching Yourself Over the Internet'
description: 'SOCKS5 and DNSmasq'
updateDate: 'July 07 2024'
---
As I've started hosting more and more services on my home network, I've
increasingly found the need to contact myself over the internet.
For example, I host Forgejo locally at git.mami2.moe. The problem is that from
*my* computer, I can't type `git.mami2.moe` in the address bar and get on
Forgejo, I need something like `localhost:8080` on my computer or
`10.0.0.2:8080` on my laptop.
The problems become compounded with some services like Cvat, which only
allowlist a specific set of domains in the header. This means I can't even reach
Cvat on `localhost:8080` from my own computer, as Cvat will deny that request.
Additionally, it's important to make sure your DNS settings are correct, so
people on the internet can reach Cvat, but that's not possible to test on your
home network.
In this article I'll go over my solutions to this problem. Hopefully you learn
some networking on the way!
## /etc/hosts
The easiest way to go about this is the most basic DNS possible: `/etc/hosts`.
Simply add a line to redirect to the loopback, and your reverse proxy should
handle it from there. Systemd-resolved reads `/etc/hosts` without even needing
to reload!
```
127.0.0.1 git.mami2.moe
```
## SOCKS
SOCKet Secure is a widely-available TCP/UDP proxy, which is even baked into
OpenSSH! This means any computer you can SSH into can become your SOCKS proxy.
In my case, I found this to be by far the easiest solution.
Start by adding dynamic forwarding to your `~/.ssh/config`. Below we specify
9042, but this can be any open port:
```ssh-config
Host orca
IdentitiesOnly=yes
Hostname 123.4.23.84
User emiliko
DynamicForward 8081
Compression yes
LogLevel QUIET
```
Connect to your proxy `ssh orca`. Now start chromium with this proxy:
```bash
chromium --proxy-server='socks5://localhost:8081'
```
However, I often find I also want to still be able to use a browser without this
proxy. In this case, I start up two distinct chromium sessions. For example:
```bash
chromium # Leave this one open for yourself
chromium --proxy-server='socks5://localhost:8081' --user-data-dir=/dev/shm/chromium_socks
```
From this, my first browser can reach Forgejo only on `localhost:8080`, while the
second one will only reach it on `git.mami2.moe`, allowing me to develop locally
but still test changes from an external user's perspective!
## Cellular Connection
This one is a bit silly, but also the least technical option. If you need to
help someone with limited technical expertise, this is the best option to
suggest.
You can access your website (git.mami2.moe) from your phone when wifi is turned
off! Throw up a hotspot and any computer connected through this hotspot has
access too!
The major limitations are that you still can't access git.mami2.moe on the
computer actually hosting git.mami2.moe and you're now using more expensive
data.
## Hairpin NAT
If you have access to your router/modem and it has Hairpin NAT support, enable
it and everything should just work. Hairpin NAT makes the router analyse where
an outbound request is being sent. If the request is trying to reach that
router's IP address, it'll simply reflect the packet, acting as if it came over
the internet.
While this seems like the ideal solution, most residential internet service
providers [do not provide Hairpin
NAT](https://forum.telus.com/t5/Internet-Home-Phone/Hairpin-Nat-on-Telus-WIFI-hub-modem/m-p/112975/highlight/true#M27472)
on their modems. I don't know why... Additionally, most commercial networks have
moved away from this solution replacing it instead with Split-horizon DNS.
# Split-horizon DNS
Split-horizon DNS allows for multiple layers of DNS resolution to be present on
your network. This is the most complicated setup, but also the most flexible, as
it allows us to become the DNS resolver for the entire network.
We'll go through a simple setup, which will function similarly to the
`/etc/hosts` solution, then step it up to work on all devices on this network.
## Local Setup
We'll use `dnsmasq` as it's the easiest to deal with. Place the following in
`/etc/dnsmasq.conf`, modifying as needed
```ini
# Must match with /etc/resolv.conf
listen-address=127.0.0.1
# Don't look any further in /etc/resolv.conf
no-resolv
# DNS Servers
server=9.9.9.9
server=149.112.112.112
server=2620:fe::fe
server=2620:fe::9
# Local resolution. Relies on a reverse proxy to choose the port (Caddy)
# Both ipv4/6 just in case
address=/git.mami2.moe/127.0.0.1
address=/git.mami2.moe/::1
```
There's a good chance you have `systemd-resolved` or some other sort of DNS
resolver running (NetworkManager does something along these lines too). Kill all
competing DNS resolvers:
```bash
systemctl disable --now systemd-resolved.service
systemctl enable --now dnsmasq.service
```
Now you should be able to resolve external domains `example.com` as well as
override the resolution for your local domains `git.mami2.moe`. Try both in
chromium, it should just work.
## Full Network
Let's first modify our `/etc/dnsmasq.conf` a little bit. We want to replace the
loopback with your LAN interface's IP. Often, `eth0` will hold this address. You
need both the static IPv4 address and the link-local IPv6. In these examples, my
static IPv4 is `10.0.0.2` and my linklocal is `fe80::200:ff:fe00:40`:
```ini
# For the server itself
listen-address=127.0.0.1
# For all other devices on the network contacting the server
interface=eth0
# Don't look any further in /etc/resolv.conf
no-resolv
# DNS Servers
server=9.9.9.9
server=149.112.112.112
server=2620:fe::fe
server=2620:fe::9
# Local resolution. Relies on a reverse proxy to choose the port (Caddy)
# Both ipv4/6 just in case. Notice, you'll need your linklocal
address=/git.mami2.moe/10.0.0.40
address=/git.mami2.moe/fe80::200:ff:fe00:40
```
You may need to open up your firewall (see `firewall-cmd`), but it's often
already open to the local network.
Login to your router and set the IPv4/6 DNS servers to point to the IPs of your
server. You could also add a fallback DNS server, but I've found that one might
take precedence, circumventing the whole split-horizon.
DHCP leases are held for several hours usually, so to test it, "forget" the
network and reconnect. Try accessing git.mami2.moe and something like
example.com, which isn't in your dnsmasq records.
For devices using `systemd-resolved`, you must accept DNS records from DHCP. You
can do this by explicitly leaving `DNS` and `FallbackDNS` blank:
```ini
[Resolve]
DNS=
FallbackDNS=9.9.9.9
```