On OpenBSD, I can successfully & transparently forward ports 80 and 443 to services running on custom, unprivileged ports using the following /etc/pf.conf
:
tcp_pass = "{ 22 80 123 443 }"
block all
pass out log on egress proto tcp to any port $tcp_pass keep state
pass in log on egress proto tcp from any to any port 80 rdr-to 127.0.0.1 port 3080 keep state
pass in log on egress proto tcp from any to any port 443 rdr-to 127.0.0.1 port 3443 keep state
I tested this by loading up a static file server bound to 3080
, then doing a cURL call to the server from another machine like so:
curl -v 192.168.1.xxx
... and I got back a 200 status code and the HTML content I'd expect. ?
Now I'd like to do the same with DNS. First I updated the tcp_pass
macro to include 53
and created a second macro for udp_pass
and put 53
in that too, followed by a udp
rule.
Then I tried adding the following rules (see comment in code block below):
tcp_pass = "{ 22 53 80 123 443 }"
udp_pass = "{ 53 }"
# ...
pass out log on egress proto udp to any port $udp_pass keep state
# ...
# the new rules I added -- emulating the http(s) rules from before
pass in log on egress proto tcp from any to any port 53 rdr-to 127.0.0.1 port 5353 keep state
pass in log on egress proto udp from any to any port 53 rdr-to 127.0.0.1 port 5353 keep state
I started up a DNS server on port 5353
and tried making a request from an external machine to this one:
dig @192.168.1.xxx -p 5353 cnn.com
works as expected: returns instantly with the correct responsedig @192.168.1.xxx cnn.com
hangs, then times out with the following error; <<>> DiG 9.10.6 <<>> @192.168.1.xxx cnn.com ; (1 server found) ;; global options: +cmd ;; connection timed out; no servers could be reached
I follow the pf
logs with tcpdump -nettti pflog0
when I make the DNS queries and I see only the following entries when requesting on port 53
:
Jun 09 17:15:22.513529 rule 10/(match) pass in on iwm0: 192.168.1.yyy.58201 > 192.168.1.xxx.53: 64594+ [1au] A? cnn.com.(36)
Jun 09 17:15:22.513933 rule 6/(match) pass out on iwm0: 192.168.1.xxx.47191 > 9.9.9.9.53: 64594+ [1au] A? cnn.com.(36)
If I rebind the DNS server to port 53
directly using root
, resolution works, so I know the problem is with my PF configuration and not my network.
My goal is to run my DNS server on an unprivileged port and port forward 53
to that port. I'm not sure what to try next and would appreciate any insight.
I think I solved it!
The crux of my problem—as I understand it—is that my initial rule worked for
53
but I had no rules allowing traffic in & out of5353
, so I was effectively redirecting to a dead-end. I realized my original question did mention my locally-running nameserver, but neglected to mention it is resolved/queried/whatever by way of another daemon (Tailscale)... and traffic out of that daemon was getting blocked. ?♂️Here's my up-to-date
pf.conf
(note that I switched to using service names instead of numerical ports, but the two are interchangeable AFAIK):This configuration appears to work as I desire, allowing me to serve
www
,https
, anddomain
on custom, unprivileged ports transparently. ?Other notes:
/etc/pf.conf
and applying my updates withpfctl -f /etc/pf.conf
and not seeing the changes I had expected, only to remember hours later that I had previously disabled pf usingpfctl -d
! I re-enabled pf withpfctl -e
and saw results matching my expectations, after which I stepped outside, touched some grass, drank a ?, and watched some ☁️s.tcpdump
, I was overly focused on53
and didn't consider my issue could've been related to5353
. In the future, I'll remember to check all the ports in play.127/8
ips; the above solution required no extra system configuration changes on OpenBSD 7.3.pf.conf(5)
,tcpdump(8)
, Chapters 21 & 22 of Absolute OpenBSD, and the pf guide on openbsd.org. My epiphany arrived after a rule change blocked a request on localhost to the admin api for my http server on a custom port, and I thought to check if pf was blocking5353
too.