route-to rule

Daniel Hartmeier daniel at
Thu Sep 8 14:27:59 UTC 2011

On Thu, Sep 08, 2011 at 02:47:29PM +0200, Dag-Erling Sm??rgrav wrote:

> According to the pf.conf(5) man page in FreeBSD 8.2, the address part of
> but pf complains of a syntax error if I leave it out, so
>  pass in on $lan2 route-to ($ext2) from ($lan2:network)
> doesn't work, while
>  pass in on $lan2 route-to ($ext2 from ($lan2:network)
> does.

The BNF syntax is slighty wrong, the parentheses are needed when
both interface and address are specified. If only the interface is
specified, no parentheses are needed or allowed, i.e. try

  pass in on $lan2 route-to $ext2 from ($lan2:network)

> I realize that pf can't *know* the correct next-hop address for the
> specified interface, but it can make a reasonable guess (first non-zero
> address in $ext2:network), so hard-coding would only be required in
> cases where the "reasonable guess" is incorrect or $ext2 has multiple IP
> addresses.

There is no guessing involved. If you specify the addresses, this
address is used for an arp lookup, and the ethernet frame will have
this IP address' MAC address as destination.

If you don't specify the address, the destination IP address of the
matching packet is used for the arp lookup instead!

If that destination IP address is not local (i.e. must be sent through
a next-hop), you MUST specify the next-hop address, or the packet will
be dropped, as arp resolution will fail.

So, specifying the next-hop address is not really "optional". You may
even have to split a route-to rule into two separate rules (one with and
the other without specifying the next-hop), when some (but not all)
possibly matching destinations are local (arp resolvable).

> so you can say
>  { $lan1:network, $lan2:network }
> but not
>  ! { $lan1:network, $lan2:network }

The reason this is not supported is purely technical, as a single rule with
an address list expands to multiple rules internally.

And this particular construct would expand to the two rules

  pass ... from ! $lan1:network
  pass ... from ! $lan2:network

which would match every possible source, not what any user whould ever
expect the construct to do.

More details on

search for "negated list".

Short answer: usually an address table can be used instead of an address
list, i.e.

  table <foo> const { $lan1:network $lan2:network }
  pass ... from ! <foo>

Kind regards,

More information about the freebsd-pf mailing list