Friday 3 April 2015

Configure NAT

Configuring NAT

NAT is specified as an optional nat-to parameter to an outbound pass rule. Often, rather than being set directly on the pass rule, a match rule is used. When a packet is selected by a match rule, parameters (e.g. nat-to) in that rule are remembered and are applied to the packet when a pass rule matching the packet is reached. This permits a whole class of packets to be handled by a single match rule and then specific decisions on whether to allow the traffic can be made with block and pass rules.
The general format in pf.conf looks something like this:
match out on interface [af] \

   from src_addr to dst_addr \
   nat-to ext_addr [pool_type] [static-port]
...
pass out [log] on interface [af] [proto protocol] \
   from ext_addr [port src_port] \
   to dst_addr [port dst_port]
match
When a packet traverses the ruleset and matches a match rule, any optional parameters specified in that rule are remembered for future use (made "sticky").
pass
This rule allows the packet to be transmitted. If the packet was previously matched by a match rule where parameters were specified, they will be applied to this packet. pass rules may have their own parameters; these take priority over parameters specified in a match rule.
out
Specifies the direction of packet flow where this rule applies. nat-to may only be specified for outbound packets.
log
Log matching packets via pflogd(8). Normally only the first packet that matches will be logged. To log all matching packets, use log (all).
interface
The name or group of the network interface to transmit packets on.
af
The address family, either inet for IPv4 or inet6 for IPv6. PF is usually able to determine this parameter based on the source/destination address(es).
protocol
The protocol (e.g. tcp, udp, icmp) of packets to allow. If src_port or dst_port is specified, the protocol must also be given.
src_addr
The source (internal) address of packets that will be translated. The source address can be specified as:
  • A single IPv4 or IPv6 address.
  • A CIDR network block.
  • A fully qualified domain name that will be resolved via DNS when the ruleset is loaded. All resulting IP addresses will be substituted into the rule.
  • The name or group of a network interface. Any IPv4 and IPv6 addresses assigned to the interface will be substituted into the rule at load time.
  • The name of a network interface followed by /netmask (e.g. /24). Each IP address on the interface is combined with the netmask to form a CIDR network block which is substituted into the rule.
  • The name or group of a network interface followed by any one of these modifiers:
    • :network - substitutes the CIDR network block (e.g., 192.168.0.0/24)
    • :broadcast - substitutes the network broadcast address (e.g., 192.168.0.255)
    • :peer - substitutes the peer's IP address on a point-to-point link
    In addition, the :0 modifier can be appended to either an interface name/group or to any of the above modifiers to indicate that PF should not include aliased IP addresses in the substitution. These modifiers can also be used when the interface is contained in parentheses. Example: fxp0:network:0
  • A table.
  • Any of the above but negated using the ! ("not") modifier.
  • A set of addresses using a list.
  • The keyword any meaning all addresses
src_port
The source port in the Layer 4 packet header. Ports can be specified as:
  • A number between 1 and 65535
  • A valid service name from /etc/services
  • A set of ports using a list
  • A range:
    • != (not equal)
    • < (less than)
    • > (greater than)
    • <= (less than or equal)
    • >= (greater than or equal)
    • >< (range)
    • <> (inverse range)
      The last two are binary operators (they take two arguments) and do not include the arguments in the range.
    • : (inclusive range)
      The inclusive range operator is also a binary operator and does include the arguments in the range.

The port option is not usually used in nat rules because the goal is usually to NAT all traffic regardless of the port(s) being used.
dst_addr
The destination address of packets to be translated. The destination address is specified in the same way as the source address.
dst_port
The destination port in the Layer 4 packet header. This port is specified in the same way as the source port.
ext_addr
The external (translation) address on the NAT gateway that packets will be translated to. The external address can be specified as:
  • A single IPv4 or IPv6 address.
  • A CIDR network block.
  • A fully qualified domain name that will be resolved via DNS when the ruleset is loaded.
  • The name or group of the external network interface. Any IP addresses assigned to the interface will be substituted into the rule at load time.
  • The name or group of the external network interface in parentheses ( ). This tells PF to update the rule if the IP address(es) on the named interface changes. This is highly useful when the external interface gets its IP address via DHCP or dial-up as the ruleset doesn't have to be reloaded each time the address changes.
  • The name or group of a network interface followed by either one of these modifiers:
    • :network - substitutes the CIDR network block (e.g., 192.168.0.0/24)
    • :peer - substitutes the peer's IP address on a point-to-point link
    In addition, the :0 modifier can be appended to either an interface name/group or to any of the above modifiers to indicate that PF should not include aliased IP addresses in the substitution. These modifiers can also be used when the interface is contained in parentheses. Example: fxp0:network:0
  • A set of addresses using a list.
pool_type
Specifies the type of address pool to use for translation.
static-port
Tells PF not to translate the source port in TCP and UDP packets.
This would lead to a most basic form of these lines similar to this:
match out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1

pass on tl0 from 192.168.1.0/24 to any
or you may simply use
pass out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1
This rule says to perform NAT on the tl0 interface for any packets coming from 192.168.1.0/24 and to replace the source IP address with 198.51.100.1.
While the above rule is correct, it is not recommended form. Maintenance could be difficult as any change of the external or internal network numbers would require the line be changed. Compare instead with this easier to maintain line (tl0 is external, dc0 internal):
pass out on tl0 inet from dc0:network to any nat-to tl0
The advantage should be fairly clear: you can change the IP addresses of either interface without changing this rule. Note that inet should be specified in this case to ensure that only IPv4 addresses are used, avoiding unexpected surprises.
When specifying an interface name for the translation address as above, the IP address is determined at pf.conf load time, not on the fly. If you are using DHCP to configure your external interface, this can be a problem. If your assigned IP address changes, NAT will continue translating outgoing packets using the old IP address. This will cause outgoing connections to stop functioning. To get around this, you can tell PF to automatically update the translation address by putting parentheses around the interface name:
pass out on tl0 inet from dc0:network to any nat-to (tl0)
This method works for translation to both IPv4 and IPv6 addresses.

Bidirectional Mapping (1:1 mapping)

A bidirectional mapping can be established by using the binat-to parameter. A binat-to rule establishes a one to one mapping between an internal IP address and an external address. This can be useful, for example, to provide a web server on the internal network with its own external IP address. Connections from the Internet to the external address will be translated to the internal address and connections from the web server (such as DNS requests) will be translated to the external address. TCP and UDP ports are never modified with binat-to rules as they are with nat rules.
Example:
web_serv_int = "192.168.1.100"

web_serv_ext = "198.51.100.6"

pass on tl0 from $web_serv_int to any binat-to $web_serv_ext

Translation Rule Exceptions

If you need to translate most traffic, but provide exceptions in some cases, make sure that the exceptions are handled by a filter rule which does not include the nat-to parameter. For example, if the NAT example above was modified to look like this:
pass out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.79

pass out on tl0 from 192.168.1.208 to any
Then the entire 192.168.1.0/24 network would have its packets translated to the external address 198.51.100.79 except for 192.168.1.208.

Checking NAT Status

To view the active NAT translations pfctl(8) is used with the -s state option. This option will list all the current NAT sessions:
# pfctl -s state
fxp0 tcp 192.168.1.35:2132 (198.51.100.1:53136) -> 198.51.100.10:22 TIME_WAIT:TIME_WAIT
fxp0 udp 192.168.1.35:2491 (198.51.100.1:60527) -> 198.51.100.33:53 MULTIPLE:SINGLE
Explanations (first line only):
fxp0
Indicates the interface that the state is bound to. The word self will appear if the state is floating.
TCP
The protocol being used by the connection.
192.168.1.35:2132
The IP address (192.168.1.35) of the machine on the internal network. The source port (2132) is shown after the address. This is also the address that is replaced in the IP header.
198.51.100.1:53136
The IP address (198.51.100.1) and port (53136) on the gateway that packets are being translated to.
198.51.100.10:22
The IP address (198.51.100.10) and the port (22) that the internal machine is connecting to.
TIME_WAIT:TIME_WAIT
This indicates what state PF believes the TCP connection to be in.

No comments:

Post a Comment