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
        • Record the Topology and Symptom
        • Check Links and Addresses
        • Check Routes
        • Check Packet Forwarding
        • Validate the PF Configuration
        • Inspect States
        • Capture Each Hop
        • Confirm the Destination Service
        • Test from the Correct Location
        • Check DNS Separately
        • Apply and Verify One Change

        Troubleshoot PF, NAT, and Routing

        Synopsis #

        Routing and Packet Filter failures often involve several layers at once. A port forward can fail because the interface has no address, the route is wrong, forwarding is disabled, PF loaded a different rule, an old state remains, the service is not listening, or the test never crossed the external interface.

        This guide follows the packet path in order. Begin with read-only checks and change one setting at a time. Keep PF enabled, avoid flushing unrelated states, and retain console access when changing a remote firewall.

        Record the Topology and Symptom #

        Write down:

        • source and destination addresses;
        • source and destination ports;
        • the expected ingress and egress interfaces;
        • the router addresses on each network;
        • whether the failure affects routing, DNS, one protocol, or one direction;
        • the last known-good configuration.

        Test both an IP address and a hostname. If the IP works but the name fails, investigate the resolver before PF.

        Check Links and Addresses #

        Use ifconfig(8) :

        ifconfig
          # Confirm interface flags, link state, addresses, and groups
        ifconfig -A
          # Display aliases and all address families
        

        An interface expected to carry traffic should be UP and normally RUNNING, with the intended address and prefix.

        Check Routes #

        Use route(8) to inspect the selected path:

        route -n show
          # Inspect the complete routing table without DNS lookups
        route -n get 198.51.100.25
          # Show the route selected for one destination
        

        On a client behind the router, confirm that the default gateway is the OpenBSD system. On the OpenBSD router, confirm routes to both the source and destination networks.

        Check Packet Forwarding #

        For an IPv4 router, inspect the forwarding control with sysctl(8) :

        sysctl net.inet.ip.forwarding
        

        The value must be 1 for IPv4 forwarding. IPv6 routing uses a separate control:

        sysctl net.inet6.ip6.forwarding
        

        Enable only the address family that the router is configured to route, and save the setting in /etc/sysctl.conf.

        Validate the PF Configuration #

        Parse the file without loading it:

        doas pfctl -nf /etc/pf.conf
        

        Then inspect the running filter and translation rules with pfctl(8) :

        doas pfctl -si
          # Confirm PF status and global counters
        doas pfctl -vvsr
          # Show filter and translation rules, counters, and evaluations
        

        If the file and active rules differ, determine why before reloading. Rules later in the file can replace earlier decisions unless quick stops evaluation. Translation does not compensate for a missing pass decision.

        Inspect States #

        Display the state table:

        doas pfctl -ss
        

        An established state can preserve behavior after a rule change. Avoid flushing the entire table on a production firewall. Reproduce the test with a new source port or remove only the relevant state after confirming the effect on active users.

        Capture Each Hop #

        tcpdump(8) shows whether the packet reaches and leaves each interface. For an inbound HTTPS forward from vio0 to server 192.168.10.20 on vio1:

        doas tcpdump -n -e -ttt -i vio0 'tcp port 443'
          # Confirm that the external packet reaches the router
        doas tcpdump -n -e -ttt -i vio1 'host 192.168.10.20 and tcp port 443'
          # Confirm that the translated packet leaves toward the server
        

        Run the captures in separate console sessions while generating one controlled test.

        Interpret the first missing observation:

        • absent on ingress: upstream routing, addressing, switch, provider, or client problem;
        • present on ingress but absent on egress: route, forwarding, PF, or translation problem;
        • present on both but no reply: service, host firewall, server route, or server application problem;
        • reply reaches the router but not the source: state, reverse route, or asymmetric-path problem.

        Confirm the Destination Service #

        On the destination host, use netstat(1) to confirm that the application listens on the intended address and port:

        netstat -na -f inet | grep '\.443 .*LISTEN'
        

        A service bound only to 127.0.0.1 cannot receive a forward to the host’s LAN address.

        Test from the Correct Location #

        Test an Internet-facing port forward from a genuinely external network. A client on the LAN that connects to the router’s external address does not traverse the same path. Use split-horizon DNS for internal clients or configure deliberate reflection rules as described in PF NAT .

        Check DNS Separately #

        Compare direct reachability and name resolution:

        ping -c 3 <known-reachable-ip>
          # Test routing without DNS
        host service.example.com
          # Test resolver behavior
        

        Replace <known-reachable-ip> with an address that is expected to answer in the deployment. Documentation prefixes such as 198.51.100.0/24 are not reachability targets.

        Inspect /etc/resolv.conf and current route proposals. Do not make the file immutable; resolvd(8) manages it and preserves user-edited lines.

        Apply and Verify One Change #

        After correcting /etc/pf.conf:

        doas pfctl -nf /etc/pf.conf && doas pfctl -f /etc/pf.conf
          # Load the complete validated ruleset
        doas pfctl -vvsr
          # Confirm the expected active rule and counters
        

        Repeat the same packet capture and client test. Record the change that resolved the failure so that the persistent configuration, monitoring, and recovery notes remain consistent.

        For the configuration itself, see PF NAT , Packet Filter , and Build a Simple Router and Firewall .

        Report a bug
        • Synopsis
        • Record the Topology and Symptom
        • Check Links and Addresses
        • Check Routes
        • Check Packet Forwarding
        • Validate the PF Configuration
        • Inspect States
        • Capture Each Hop
        • Confirm the Destination Service
        • Test from the Correct Location
        • Check DNS Separately
        • Apply and Verify One Change