OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction to OpenBSD
      • Installing OpenBSD
      • The X Window System
      • Networking on OpenBSD
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • OpenBSD Desktop Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
      • Security
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • Pure-FTPd
          • TFTP
        • Mail
          • OpenSMTPD Mail Server
          • Dovecot IMAP and POP3 Server
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound DNS Resolver
          • NSD Authoritative DNS Server
          • BIND DNS Server
        • Networking
          • OpenBGPD
          • rad
          • DHCP on OpenBSD
          • slaacd
        • Web
          • Apache HTTP Server
          • nginx Web Server
          • OpenBSD httpd Web Server
          • relayd Reverse Proxy
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • OpenSSH Server
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ Message Broker
        • Time
          • NTP Time Synchronization
        • Load Balancing
          • Build Redundant Load-Balanced Gateways
          • Load Balance Services with NAT or DSR
          • Build an HA HTTPS Load Balancer
      • PF
        • pfctl cheat sheet
        • PF Anchors
        • PF Filter Rules
        • PF Forwarding
        • PF Lists and Macros
        • PF Load Balancing
        • PF Logging
        • PF NAT
        • PF Options
        • PF Policies
        • PF Shortcuts
        • PF Tables
      • Advanced Networking
        • High Availability and State Replication
        • Multi-WAN and Policy-Based Routing
        • VPN and Cryptographic Tunneling
        • Classic and Lightweight Tunnels
        • IPv6 at Scale
        • QoS and Traffic Shaping
        • MPLS and Label Distribution
        • Network Services at Scale
        • Virtualization and Host Networking
        • Large-Scale L2 and L3 Design
        • Telemetry, Logging, and Flow Export
        • Hardening and Operational Safety
        • Reference Architectures
        • Troubleshooting Playbooks
      • Serial Communication
    • Part V. Miscellaneous
      • Virtualization Cheat Sheet
      • OpenBSD Cheatsheet
      • How-to Guides
        • Installation and First Boot
          • Complete the First 30 Minutes After Installation
          • Check Hardware Compatibility Before Installing
          • Bootstrap Wi-Fi Firmware Without Ethernet
          • Run OpenBSD as a Virtual Machine Guest
          • Install OpenBSD on a VPS or Cloud Server
          • Install OpenBSD with Full-Disk Encryption
          • Dual-Boot OpenBSD on a UEFI System
          • Automate OpenBSD Installation with Autoinstall and PXE
        • Desktops and Laptops
          • Set Up OpenBSD as a Laptop or Workstation
          • Configure Laptop Power Management
          • Troubleshoot Web Browsers on OpenBSD
          • Use Plan 9 Tools on OpenBSD
          • Build a Minimal Desktop with suckless Tools
          • Install Z shell (zsh)
        • Networking and Remote Access
          • Create an Administrator Account with doas and SSH Keys
          • Configure Secure Remote Access with OpenSSH
          • Use FIDO Security Keys with OpenSSH
          • Configure Wi-Fi Roaming and Wired Failover
          • Troubleshoot PF, NAT, and Routing
          • Route Multiple VLANs with PF
          • Configure a Road-Warrior WireGuard VPN
          • Route IPv6 Networks without NAT
          • Test OpenBGPD with Two Providers
          • Unlock an Internal Service with an SSH Key
          • Build a Simple Router and Firewall
        • Servers and Services
          • Set Up WordPress on OpenBSD
          • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Security, Maintenance and Recovery
          • Establish a Conservative Security Baseline
          • Recover Access and Reset the Root Password
          • Collect OpenBSD Diagnostic Evidence
          • Troubleshoot Package Installation and Update Failures
          • Schedule Recurring Maintenance
          • Monitor an OpenBSD System
          • Back Up and Restore an OpenBSD System
          • Configure softraid RAID1
          • Recover an OpenBSD System That Does Not Boot
        • Building, Automation and Virtual Machines
          • Manage OpenBSD with Ansible
          • Build Third-Party Software from Ports
          • Build OpenBSD from Source
          • Plan a Docker Workload Migration to OpenBSD
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • OpenBSD Architectures
      • OpenBSD Package Search
        • Synopsis
        • Introduction
        • Security Implications
        • Redirection and Reflection
          • Split-horizon DNS
          • Moving the Server into a Separate Local Network
          • TCP Proxying
          • RDR-TO and NAT-TO Combination

        PF Forwarding

        Synopsis #

        This page describes port redirection. Enable IPv4 forwarding with net.inet.ip.forwarding=1 in /etc/sysctl.conf and at runtime before routing to another host. The target server needs a return route through the firewall.

        Introduction #

        Outbound NAT lets internal clients initiate connections to external servers. Redirection allows external clients to reach a server behind the gateway.

        For example:

        pass in on egress proto tcp from any to any port 80 rdr-to 192.168.1.20
        

        This line redirects TCP port 80 (web server) traffic to a machine inside the network at 192.168.1.20. So, even though 192.168.1.20 is behind your gateway and inside your network, the outside world can access it.

        Restrict the source addresses when only known networks should reach the service:

        pass in on egress proto tcp from 203.0.113.0/24 to any port 80 rdr-to 192.168.1.20
        

        This rule redirects connections from the specified subnet only. Separate source-specific rules can send clients to different internal servers while sharing the same external address and port:

        pass in on egress proto tcp from 203.0.113.14 to any port 80 rdr-to 192.168.1.20
        pass in on egress proto tcp from 198.51.100.89 to any port 80 rdr-to 192.168.1.22
        pass in on egress proto tcp from 198.51.100.178 to any port 80 rdr-to 192.168.1.23
        

        A range of ports can also be redirected within the same rule:

        pass in on egress proto tcp from any to any port 5000:5500 \
           rdr-to 192.168.1.20
        pass in on egress proto tcp from any to any port 5000:5500 \
           rdr-to 192.168.1.20 port 6000
        pass in on egress proto tcp from any to any port 5000:5500 \
           rdr-to 192.168.1.20 port 7000:*
        

        These examples show ports 5000 to 5500 inclusive being redirected to 192.168.1.20.

        • In rule #1, port 5000 is redirected to 5000, 5001 to 5001, etc.
        • In rule #2, the entire port range is redirected to port 6000.
        • And in rule #3, port 5000 is redirected to 7000, 5001 to 7001, etc.

        Security Implications #

        A redirected service is reachable from outside the network. If that service is compromised, the attacker may gain access to other internal systems.

        These risks can be minimized by keeping the externally accessed system tightly confined on a separate network. This network is often referred to as a Demilitarized Zone (DMZ) or a Private Service Network (PSN). This way, if the web server is compromised, the effects can be limited to the DMZ/PSN network by careful filtering of the traffic permitted to and from the DMZ/PSN.

        Redirection and Reflection #

        Often, redirection rules are used to forward incoming connections from the internet to a local server with a private address in the internal network or LAN, as in:

        server = 192.168.1.40
        pass in on egress proto tcp from any to egress port 80 rdr-to $server port 80
        

        But when the redirection rule is tested from a client on the LAN, it doesn’t work. The reason is that redirection rules apply only to packets that pass through the specified interface (egress, the external interface, in the example). Connecting to the external address of the firewall from a host on the LAN, however, does not mean the packets will actually pass through its external interface. The TCP/IP stack on the firewall compares the destination address of incoming packets with its own addresses and aliases and detects connections to itself as soon as they have passed the internal interface. Such packets do not physically pass through the external interface, and the stack does not simulate such a passage in any way. Thus, PF never sees these packets on the external interface, and the redirection rule, specifying the external interface, does not apply.

        Adding a second redirection rule for the internal interface does not have the desired effect either. When the local client connects to the external address of the firewall, the initial packet of the TCP handshake reaches the firewall through the internal interface. The redirection rule does apply and the destination address gets replaced with that of the internal server. The packet gets forwarded back through the internal interface and reaches the internal server. But the source address has not been translated, and still contains the local client’s address, so the server sends its replies directly to the client. The firewall never sees the reply and has no chance to properly reverse the translation. The client receives a reply from a source it never expected and drops it. The TCP handshake then fails and no connection can be established.

        LAN clients may need to use the same service name or address as external clients. The following designs support that access:

        Split-horizon DNS #

        Configure DNS to return the internal server address to local clients and the external address to other clients. Local clients then connect directly to the server without passing through the firewall.

        Moving the Server into a Separate Local Network #

        Adding an additional network interface to the firewall and moving the local server from the client’s network into a dedicated network (DMZ) allows redirecting of connections from local clients in the same way as the redirection of external connections. Use of separate networks has several advantages, including improving security by isolating the server from the remaining local hosts. Should the server (which in our case is reachable from the Internet) ever become compromised, it can’t access other local hosts directly as all connections have to pass through the firewall.

        TCP Proxying #

        A generic TCP proxy can be setup on the firewall, either listening on the port to be forwarded or getting connections on the internal interface redirected to the port it’s listening on. When a local client connects to the firewall, the proxy accepts the connection, establishes a second connection to the internal server, and forwards data between those two connections.

        RDR-TO and NAT-TO Combination #

        With an additional NAT rule on the internal interface, the lacking source address translation described above can be achieved.

        pass in on $int_if proto tcp from $int_net to egress port 80 rdr-to $server
        pass out on $int_if proto tcp to $server port 80 received-on $int_if nat-to $int_if
        

        This will cause the initial packet from the client to be translated again when it’s forwarded back through the internal interface, replacing the client’s source address with the firewall’s internal address. The internal server will reply back to the firewall, which can reverse both NAT and RDR translations when forwarding to the local client. This construct is rather complex as it creates two separate states for each reflected connection. Care must be taken to prevent the NAT rule from applying to other traffic, for instance connections originating from external hosts (through other redirections) or the firewall itself. Note that the ‘rdr-to’ rule above will cause the TCP/IP stack to see packets arriving on the internal interface with a destination address inside the internal network.

        Report a bug
        • Synopsis
        • Introduction
        • Security Implications
        • Redirection and Reflection
          • Split-horizon DNS
          • Moving the Server into a Separate Local Network
          • TCP Proxying
          • RDR-TO and NAT-TO Combination