Accessing firewalled services using PF on OpenBSD
Consider a scenario where all hosts in a network have public IP
addresses, but only one subnet is accessible from the Internet because
of a corporate firewall. Internal hosts communicate with each other
normally. In order to access the SSH port of a firewalled machine, say
with the hostname
hidden, you may use another host, say
belonging in the accessible subnet, at a different port, and redirect
traffic to and from
hidden. Most of this is described in
PF User's Guide, but the
manual assumes a public and a private interface with NAT between the two.
This guide is about using the same interface to do the forwarding.
It can be done using a user-level proxy or completely in-kernel with PF.
The configuration of the
middle host is found below.
User-level proxy with inetd and netcat
# Proxy SSH to other machines with inetd pass in quick on egress proto tcp from any to any port 1337 rdr-to (lo)
# SSH proxy using nc 127.0.0.1:1337 stream tcp nowait proxy /usr/bin/nc nc hidden 22
Kernel-level proxy only with PF rules
# Proxy SSH to other machines pass in quick on egress proto tcp to port 1337 rdr-to hidden port ssh pass out quick on egress proto tcp to hidden port ssh nat-to (egress)
Tips for SSH access
For seamless SSH access to the
hidden host you can alias it to the
middle host, and use the appropriate port like this.
Host hidden HostName middle Port 1337
The aliasing can also be done at the
/etc/hosts or DNS level using a
CNAME record for
hidden.example.org that points to
middle.example.org and use:
Host hidden.example.org Port 1337
A rough benchmarking of the two methods shows that the PF-only setup
performs slightly better probably because it generates less local traffic
and context switches. Throughput and latency was measured over ssh as
shown below. The tests are a single large file transfer and the timing
of login and logout. The load on the
middle host is also displayed
broken down as interrupts and system time.
# large file transfer $ time scp install54.iso hidden: # login operation $ time ssh hidden echo
And the results:
# throughput latency ints system user-level: 3.9MB/s 0.6461s 35% 5% kernel-only: 3.9MB/s 0.6220s 23% 0%
Choose your destiny!