natpmpd

natpmpd is a daemon that can be used on an OpenBSD NAT gateway to provide support for the NAT-PMP protocol on any internal networks which then allows a client to create and maintain rules in pf to map TCP and UDP connections to the external IP address on the NAT gateway to services running on the client itself.

Example

natpmpd is straightforward to get up and running, assume you have a network similar to the following:

                       {Internet}
                           |
                          sis0 x.x.x.x
                           |
                     +-----------+
                     |  OpenBSD  |
                     +-----------+
                           |
                          sis1 192.0.2.254
                           |
                      Internal LAN
                     (192.0.2.0/24)

To clarify:

  • sis0 is your external network interface. This can be configured with either a static address or by DHCP, it’s not important. What is important is that your internal clients are NAT’d to the IPv4 address on this interface.
  • sis1 is your internal network interface. This interface should hold the IPv4 address that your internal clients use as their default gateway.

To match this, create your natpmpd.conf with the following:

interface sis0
listen on 192.0.2.254

If you have multiple internal networks you can specify additional listen on directives, one per gateway address.

You might then also use the following (horribly contrived) pf.conf:

ext_if="sis0"
int_if="sis1"
 
set skip on lo
 
anchor "natpmpd"
 
match out on $ext_if inet from $int_if:network to any nat-to ($ext_if:0)
 
block in log
pass out quick
 
antispoof quick for { lo $int_if }
 
pass in on $int_if

Note the dedicated anchor that natpmpd uses to add its own rules, much like ftp-proxy(8).

Assuming your rules are already loaded and up to date, start up natpmpd. After a short while, you can examine the anchor to see what rules have been created:

# pfctl -a natpmpd -s rules
pass in quick inet proto udp from any to x.x.x.x port = 62638 keep state rdr-to 192.0.2.1 port 5353
pass in quick inet proto udp from any to x.x.x.x port = 64630 keep state rdr-to 192.0.2.1 port 4500

The above rules are typical of a Mac OS X host with the MobileMe^WiCloud feature Back to My Mac enabled.

Features

natpmpd implements the majority of the IETF draft with a couple of small tweaks:

  • The external TCP or UDP port assigned to the client is always randomised rather than giving the first client the port it actually requested and then trying to work out what to do for additional clients that want the same external port.
  • In addition to broadcasting the new external IP address should it change, natpmpd also performs this broadcast on startup, which seems to work well to nudge clients into creating or recreating any mappings should the NAT gateway be rebooted or failed over to a backup machine.

Install

natpmpd is available as a native package since OpenBSD 5.1 so you can install easily with:

# pkg_add natpmpd

You can then configure as normal and update rc.conf.local to start it at boot with the provided rc.d script.

Source

The latest source is available on GitHub: https://github.com/bodgit/natpmpd

  • natpmpd-1.4.tar.gz – improved support for using with dynamic interface types such as pppoe(4). Fixed bug to now ignore 0.0.0.0 as an address (valid initially on pppoe(4) interfaces). Added a signal handler to clean up the pf anchor on exit instead of leaving it in an unknown state
  • natpmpd-1.3.tar.gz – now drops privileges and runs as _natpmpd user. Small fix to natpmpd.conf.5 man page for OpenBSD 4.8
  • natpmpd-1.2.tar.gz – handle situation where a client requesting TCP and UDP mappings for the same port would get different external ports for each, the draft says both mappings should get the same external port
  • natpmpd-1.1.tar.gz – fixed alignment issue for OpenBSD platforms such as armish and sparc64
  • natpmpd-1.0.tar.gz – requires OpenBSD 4.7 due to changes in pf syntax