Re: IPv6 TCP: first two SYN packets to local v6 unicast addresses ignored

From: Gleb Smirnoff <glebius_at_freebsd.org>
Date: Sat, 23 Apr 2022 00:24:04 UTC
  Michael,

On Sat, Apr 23, 2022 at 01:54:25AM +0200, Michael Tuexen wrote:
M> > here is a patch that should help with the IPv6 problem. I'm not
M> > yet committing it, it might be not final.
M> 
M> when I was looking at the code, I was also wondering if it would make
M> more sense to check for M_LOOP.
M> 
M> However, isn't the rcvif wrong for the first two received packets? I
M> would expect it always to be the loopback interface. Is that expectation
M> wrong?

The IPv6 has a special feature of calling (ifp->if_output)(origifp, ...

I don't fully understand it, but Alexander does.

What I can observe is that it works differently for the original packet,
its first retransmit and second retransmit. Still unclear to me why.

Here is how to observe it:

dtrace
    -n 'fbt::ip6_output:entry
    { printf("ro %p ifp %p\n", args[2], args[2]->ro_nh ? args[2]->ro_nh->nh_ifp : 0); }'
    -n 'fbt::ip6_output_send:entry { printf("ifp %p origifp %p\n", args[1], args[2]); }'

And you will see this:

  1  45625                 ip6_output:entry ro fffff800122c19a0 ifp 0
  1  22539            ip6_output_send:entry ifp fffff800027cb800 origifp fffff800020db000

  0  45625                 ip6_output:entry ro fffff800122c19a0 ifp fffff800027cb800
  0  22539            ip6_output_send:entry ifp fffff800027cb800 origifp fffff800020db000

  0  45625                 ip6_output:entry ro fffff800122c19a0 ifp fffff800027cb800
  0  22539            ip6_output_send:entry ifp fffff800027cb800 origifp fffff800027cb800

So, on packet three (second retransmit) the origifp is equal to ifp (is lo0) and now
packet passes validation. However, the more I read it, the more it seems to me that
actually packet three is incorrect and first two are correct :)

To cope with this self inflicted damage of (ifp->if_output)(origifp, IPV6 introduced
M_LOOP and uses it internally. Looks like a quick solution for IPv6 is to use it.
However, I will commit it only once we got understanding why the hell a second retransmit
is different.

M> I also have an additional question:
M> Why is this check protected by an (ia != NULL) condition? It does not make
M> any use of ia?

It is a host protection feature, so checks only packets that are destined to us.
This allows to do basic antispoof checks for a host not equipped with any firewall.

For a machine acting as a router better behavior is not to drop anything routed
through unless explicitly told so by a filtering policy.

-- 
Gleb Smirnoff