[Bug 289612] divert(4) may not work correctly on gif(4) interface

From: <bugzilla-noreply_at_freebsd.org>
Date: Sun, 14 Sep 2025 22:16:01 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289612

            Bug ID: 289612
           Summary: divert(4) may not work correctly on gif(4) interface
           Product: Base System
           Version: 14.3-RELEASE
          Hardware: amd64
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: pmc@citylink.dinoex.sub.org

I receive data from the Internet via HE tunnels. These are gif(4) interfaces.
I tried to put suricata onto it, inside ipfw via divert(4), and the divert did
not 
work. 

Analysis showed that the packets arriving from the internet "in via gif0",
destined for local delivery, are suddenly routed "out via lo0" after returning
from the divert (one_pass = 0):

kernel: [43188] ipfw: 3952 Count UDP [2003:e7:***::4102]:5912
[2001:470:***::0]:5006 in via gif0
kernel: [43188] ipfw: 3962 Count UDP [2003:e7:***::4102]:5912
[2001:470:***::0]:5006 out via lo0
kernel: [43188] ipfw: 6027 Unreach 1 UDP [2003:e7:***::4102]:5912
[2001:470:***::0]:5006 in via lo0

My ipfw rules do not allow that, and it is bogus.

I wrote a little loopback program as replacement for the suricata (actually AI
wrote it :=), it shows the same effect. But now the problem gets visible:

Listening on divert socket...
Family 2
Port   3957
Addr   0.0.0.0
Ifname gif0
Hex    10 02 75 0f 00 00 00 00 67 69 66 30 00 00 00 00
Received packet of length: 62

The Addr 0.0.0.0 is wrong here. There should be the first IPv4 address of the
receiving interface, as a marker to flag this packet as incoming. 
With 0.0.0.0 the packet is considered outgoing (according to man 4 divert), and
that explains the behaviour.

The problem is, a gif(4) interface does not necessarily have such an IPv4
address:

gif0: flags=1008051<UP,POINTOPOINT,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu
1480
        options=80000<LINKSTATE>
        tunnel inet 195.**.**.** --> 216.**.**.**
        inet6 2001:470:***::2 --> 2001:470:***::1 prefixlen 128
        groups: gif
        nd6 options=1<PERFORMNUD>

I found that I can make things work:

root@pole:~ # ifconfig gif0 inet 127.0.0.4/32 127.0.0.5
root@pole:~ # ifconfig gif0
gif0: flags=1008051<UP,POINTOPOINT,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu
1480
        options=80000<LINKSTATE>
        tunnel inet 195.**.**.** --> 216.**.**.**
        inet 127.0.0.4 --> 127.0.0.5 netmask 0xffffffff
        inet6 2001:470:***::2 --> 2001:470:***::1 prefixlen 128
        groups: gif
        nd6 options=1<PERFORMNUD>

This is apparently legal, gif(4) seems to be able to handle one link of each
IPv4 and IPv6 at the same time. But it took me a good day to figure that out,
so maybe there is a way for improvement.
In any case a writeup might be useful.

-- 
You are receiving this mail because:
You are the assignee for the bug.