In the pf firewall, the pf.conf man page 'parameters' section states that "protocol" is anything from /etc/protocols, and that it's distinct from "address family" ("<af>") which is inet or inet6. /etc/protocols in turn includes "IPv6" as a protocols, and in applications based on BSD such as the pfSense firewall, IPv6 is sometimes listed as a protocol as distinct from an IP family (eg in NAT rule definitions).

But IPv6 isn't a protocol in the sense that tcp/udp/icmp are. There's a clear logical and functional distinction between IPv4/IPv6 as the two IP address families (the underlying transport), and the many protocols transported within IPv4/IPv6.

(If it were then
nat on em1 inet proto ipv6 from to any -> port 2000:2999 and
block drop in inet proto ipv6 from to any
would be meaningful and comparable to
nat on em1 inet proto tcp from to any -> port 2000:2999 and
block drop in inet proto tcp from to any )

When would IPv6 be meaningful or used in the "protocol" field in a PF rule, as opposed to specifying it as the address family? (And could NAT being almost always used for IPv4 only, have anything to do with it?)

2 Answers 2


IPv6 is a protocol in the sense that TCP/UDP/ICMP are. While they work on different layers, there's nothing that stops you from layering IP on top of IP in order to get a simple VPN-like tunnel. (Compare this with IP inside GRE inside IP.) For this reason both IPv4 and IPv6 have protocol number assignments – a nested IPv4 packet is "protocol 4", IPv6 is "protocol 41".

More specifically, IPv6-over-IPv4 is also known as "6in4" or "proto41", a common transition mechanism used for obtaining IPv6 connectivity from a tunnel provider through an IPv4-only network. (Hurricane Electric is a popular one; there is also automatic "6to4" using anycast relays.)

pfSense has documentation for configuring such a tunnel – in FreeBSD this would be done using a gif(4) interface; on Linux, using sit or ipip. The tunnel provider has identical (but mirrored) configuration which unpacks the inner IP packet and forwards it to its native IPv6 network.

This isn't the most ideal tunnel method compared to e.g. GRE, L2TP (only one tunnel per outer src/dst pair); or FOU, GUE (many home routers don't allow port-forwarding anything that's not TCP or UDP); or special VPN protocols (no authentication, no encryption). It is however the simplest possible tunnel, and one with the least overhead (only 20 bytes).

Obligatory "Inception" reference: IPv4 requires a minimum MTU of 68 bytes, while IPv6 bumps it to 1280 bytes. With default Ethernet MTU of 1500, the maximum number of times you can stack IPv4 tunnels is ~70, and likewise ~5 layers for IPv6.

  • If that was the reason, I'd have expected to see it identified as "encapsulated IPv6" to distinguish it from the underlying transport. Its unlike computer standards to create ambiguity in this way. So does this mean that filtering inet proto ipv6 will capture only IPv6 which has been encapsulated over IPv4 in some manner?
    – Stilez
    Oct 3, 2016 at 14:48
  • Well, it's already identified as "encapsulated IPv6" based on the fact that proto always matches the (outer) IP header's protocol field, not the Ethernet header's ethertype. So pass etc. inet proto ipv6 is indeed something you'd use to match only 6to4 tunnels.
    – user1686
    Oct 3, 2016 at 14:52

Because Pf itself works not in channel layer. For e. g., it won't intercept no RAW sockets communications, ARP's ones and so on.

It's already in Networking level — by its design.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.