Re: promisc/netgraph question
Martin Mayer <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.net |
|---|---|
| Message-ID | <FR2PPF447E0FD2FF81BF6D4A7538B0D0894BC9CA@FR2PPF447E0FD2F.DEUP281.PROD.OUTLOOK.COM> |
Let me explain my intend from a higher level and forget about the code details for a moment.
If a packet ingresses an interface where
( dst MAC != interface MAC ) &&
( dst MAC != multicast joined groups ) &&
( dst MAC != broadcast )
I'd expect
- the packet to be directly discarded if !( IFF_PROMISC || IFF_PPROMISC )
- the packet to be accepted but not passed to upper layers if ( IFF_PROMISC || IFF_PPROMISC )
A special case is CARP where IFF_PROMISC is set and should be passed to upper layers if
( dst MAC == CARP instance MAC && CARP enabled )
I think we have a consensus until here. This is the current (normal) behavior.
This behavior changes as soon as netgraph is involved.
If ng_ether hooks are connected, the host skips these checks and passes the packet to the upper layers.
The practical issue to my question is:
https://github.com/opnsense/src/issues/279
I want to understand the root cause of this behavior and want to identify if this is intentionally or if it's a bug.
As per my understanding, this happens in if_ethersubr.c because the hook for the packet to be claimed by netgraph is BEFORE the destination addresses are checked.
[...]
/* Allow ng_ether(4) to claim this frame. */
if (ifp->if_l2com != NULL) {
KASSERT(ng_ether_input_p != NULL,
("%s: ng_ether_input_p is NULL", __func__));
m->m_flags &= ~M_PROMISC;
(*ng_ether_input_p)(ifp, &m);
if (m == NULL) {
CURVNET_RESTORE();
return;
}
eh = mtod(m, struct ether_header *);
}
[...]
if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) {
m->m_flags &= ~M_PROMISC;
} else {
/*
* If the frame received was not for our MAC address, set the
* M_PROMISC flag on the mbuf chain. The frame may need to
* be seen by the rest of the Ethernet input path in case of
* re-entry (e.g. bridge, vlan, netgraph) but should not be
* seen by upper protocol layers.
*/
if (!ETHER_IS_MULTICAST(eh->ether_dhost) &&
memcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN) != 0)
m->m_flags |= M_PROMISC;
}
ether_demux(ifp, m);
[...]
ether_demux() (which is the re-entry point from ng_ether) won't be able to correctly evaluate (m->m_flags & M_PROMISC).
Thanks, Martin