I have a configuration on my box running OpenBSD 5.6 with errata that is supposed to tunnel IPv4 over IPv6. However, due to bugged RFC 2473 implementations shared across ALL BSD systems, pf's af-to comes into play when I decide to navigate through the abhorrent path MTU discovery issue found in gif. As a result, please do not blame me for reinventing the wheel, since RFC 2473 tunnels implemented in gif ALWAYS outputs at the MTU of 1280 REGARDLESS of the mtu option in ifconfig/hostname.if.
The configuration requires two af-to lines in pf.conf, one from inet6 to inet4, so as to listen for incoming protocol 4 from IPv6 and then translate the packet to IPv4, and the other from inet4 to inet6, which listens for inbound protocol 4 IPv4 packets and translate the packet to IPv6. The REAL problem is on the latter part. Before the pf.conf lines, let me outline my configuration here. I have global IPv6 access through gif0, which is an RFC 4213 tunnel. And a copy of hostname.gif0 is as follows: ----------BEGIN hostname.gif0---------- tunnel 146.185.21.99 216.66.88.98 inet6 2001:470:1f1c:10b::2 64 mtu 1480 inet 192.168.0.98 255.255.255.255 NONE group egress !/sbin/route -n -q add -mpath -inet6 default -host -inet6 2001:470:1f1c:10b::1 ----------END hostname.gif0---------- My local end of the quasi-RFC2473 tunnel sits on vether0, with associating hostname.vether0 as follows: ----------BEGIN hostname.vether0---------- inet 192.168.0.97 255.255.255.255 NONE up ----------END hostname.vether0---------- And now we are onto the quasi-RFC2472 tunnel, with associating hostname.gif2 as follows: ----------BEGIN hostname.gif2---------- tunnel 192.168.0.97 192.168.0.98 inet 172.31.255.253 255.255.255.252 NONE mtu 1280 up !/sbin/route -n -q add -host -inet 172.31.255.254 -host -inet 172.31.255.254 ----------END hostname.gif2---------- And the two lines below in my pf.conf is supposed to hook everything up: ----------BEGIN pf.conf---------- pass in quick inet proto 4 from 192.168.0.97 to 192.168.0.98 \ af-to inet6 from 2001:470:1f1c:10b::2 to 2001:470:c:6fa::2 pass in quick inet6 proto 4 from 2001:470:c:6fa::2 to 2001:470:1f1c:10b::2 \ af-to inet from 192.168.0.98 to 192.168.0.97 ----------END pf.conf---------- And for your cynicists, there's the sentence in 'man pf.conf', "The optional second argument is the host or subnet the original addresses are translated into for the destination." This is also supported by tcpdump results. The OpenBSD box peers with a Linux box, whose address family translation in this case is performed by socat with the following lines: ----------BEGIN socat-46.sh---------- /usr/local/bin/socat \ IP4-RECVFROM:4,bind=192.168.0.97,fork \ IP6-SENDTO:[2001:470:1f1c:10b::2]:4,bind=[2001:470:c:6fa::2],reuseaddr ----------END socat-46.sh---------- ----------BEGIN socat-64.sh---------- /usr/local/bin/socat \ IP6-RECVFROM:4,bind=[2001:470:c:6fa::2],fork \ IP4-SENDTO:192.168.0.98:4,bind=192.168.0.97,reuseaddr ----------END socat-46.sh---------- If you wanna have a further look for the setup on the Linux box, the equivalent Vyatta setup lines is as follows ----------BEGIN edit interface tunnel tun4---------- set address 172.31.255.254/30 set disable-link-detect set encapsulation ipip set local-ip 192.168.0.98 set mtu 1280 set multicast disable set remote-ip 192.168.0.97 ----------END edit interface tunnel tun4---------- ----------BEGIN edit interface ethernet eth1---------- set vif 0 address 192.168.0.97/32 set vif 1 address 192.168.0.98/32 ----------ENDedit interface ethernet eth1---------- Again, the IPv6 access on the Linux box is provided by an RFC 4213 tunnel, whose Vyatta-equivalent setup lines is as follows: ----------BEGIN edit interface tunnel tun2---------- set address 2001:470:c:6fa::2/64 set disable-link-detect set encapsulation sit set local-ip 0.0.0.0 set mtu 1480 set multicast disable set remote-ip 66.220.18.42 set ttl 255 ----------END edit interface tunnel tun2---------- Now, we run on the Linux box "ping -I 172.31.255.254 172.31.255.253", and on the OpenBSD box "tcpdump -i gif2". The following is a sample output on the OpenBSD box: ----------BEGIN tcpdump -i gif2---------- # tcpdump -i gif2 tcpdump: listening on gif2, link-type LOOP 02:50:02.673576 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) 02:50:02.673978 172.31.255.253 > 172.31.255.254: icmp: echo reply (DF) 02:50:03.664722 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) 02:50:03.665036 172.31.255.253 > 172.31.255.254: icmp: echo reply (DF) 02:50:04.664823 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) 02:50:04.665148 172.31.255.253 > 172.31.255.254: icmp: echo reply (DF) 02:50:05.664215 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) 02:50:05.664539 172.31.255.253 > 172.31.255.254: icmp: echo reply (DF) 02:50:06.664375 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) 02:50:06.664721 172.31.255.253 > 172.31.255.254: icmp: echo reply (DF) 02:50:07.664206 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) 02:50:07.664546 172.31.255.253 > 172.31.255.254: icmp: echo reply (DF) ^C 12 packets received by filter 0 packets dropped by kernel ----------END tcpdump -i gif2---------- No ICMP replies are ever received on the Linux box. And "tcpdump -i gif0 'proto 4'" on the OpenBSD box can confirm this: ----------BEGIN tcpdump -i gif0 'proto 4'---------- # tcpdump -i gif0 'proto 4' tcpdump: listening on gif0, link-type LOOP 02:52:53.663779 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:52:54.663889 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:52:55.663693 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:52:56.663644 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:52:57.663761 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:52:58.663805 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:52:59.664058 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:53:00.663951 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:53:01.664333 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:53:02.663995 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:53:03.663991 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) 02:53:04.663993 172.31.255.254 > 172.31.255.253: icmp: echo request (DF) (encap) ^C 41 packets received by filter 0 packets dropped by kernel ----------END tcpdump -i gif0 'proto 4'---------- Allow to me sum up what happened in the tcpdump results here. The Linux box generate an ICMP echo request from 172.31.255.254 to 172.31.255.253, wraps it in an IP-in-IP packet from 192.168.0.98 to 192.168.0.97, and sends it to 192.168.0.97. socat takes the protocol 4 IPv4 packet at 192.168.0.98, decapsulates the packet, and re-encapsulates it as an protocol 4 IPv6 packet from 2001:470:c:6fa::2 to 2001:470:1f1c:10b::2. And then the OpenBSD box gets the packet and address-family-translates it to an protocol 4 IPv4 packet from 192.168.0.98 to 192.168.0.97, which is received on vether0. The packet is then decapsulated and reveals the original ICMP echo request. And then gif2 generates a reply, and all ends up in a blackhole. Note that for the ICMP replies to generate, the line "!/sbin/route -n -q add -host -inet 172.31.255.254 -host -inet 172.31.255.254" in hostname.gif2 is mandatory. And I have several questions here: 1) how do I get the ICMP echo reply properly encapsulated? 2) if ever the ICMP echo reply is properly encapsulated, why did pf fail to translate the protocol 4 IPv4 packet back to the equivalent IPv6 packet? 3) is this a pf or gif bug, or else? 4) how am I supposed to get the setup to work here? 5) are there any suggestion on tunneling IPv4 over IPv6 that circumvents the dreaded fixed-MTU-at-1280 issue, first between two OpenBSD hosts, and a second between an OpenBSD and a Linux host? Thank you. Best, Jing Zhou