Unix: split-horizon dns
This commit is contained in:
parent
bd305cb283
commit
eca17022b0
1 changed files with 191 additions and 0 deletions
191
src/content/unix/reaching-yourself-from-wan.md
Normal file
191
src/content/unix/reaching-yourself-from-wan.md
Normal 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
|
||||||
|
```
|
Loading…
Reference in a new issue