On Fri, 30 Jan 2026 08:05:20 +0000
Martin Mayer <[email protected]> wrote:
> Hello,
>
> I'm currently searching for a root cause for a certain behavior in ethernet
> packet handling and want to ask some things to be sure.
>
> Let me begin with a short description:
> Consider an interface in promiscuous mode. A packet ingressing the interface
> is prevented from reaching upper layers by camparing the destination address
> with the local one and by checking for multicast and CARP. If I am right,
> this pre-filtering happens in ether_input_internal() (if_ethersubr.c) and
> the packet is later dropped by ether_demux() if IFF_PPROMISC is not set.
>
> Now, consider the following netgraph with the interface above:
> if:lower <-> tee <-> if:upper
>
> In this case, ingressing and egressing traffic is not manipulated in any
> way. The difference to the packet handling described before is the existence
> of ng_hooks. This leads to the fact that netgraph gets the packet without
> the destination address checks executed. When the packet reaches
> ether_demux(), M_PROMISC is never set in m->m_flags.
>
> Am I right?
>
> The background to my question is the following:
> When netgraph is being used, I've noticed that packets which are not
> destined to the host are being handled by the host's upper layers when
> attached to a non-switched network and promiscous mode is enabled.
Interesting question. There are settings documented in man page:
NGM_ETHER_SET_PROMISC (setpromisc)
Enable or disable promiscuous mode. This message includes a single
32 bit integer flag that enables or disables promiscuous mode on the
interface. Any non-zero value enables promiscuous mode.
NGM_ETHER_GET_PROMISC (getpromisc)
Get the current value of the node's promiscuous flag. The returned
value is always either one or zero. Note that this flag reflects
the node's own promiscuous setting and does not necessarily reflect
the promiscuous state of the actual interface, which can be affected
by other means (e.g., bpf(4)).
and the former also tries to actually enable it on interface:
want = !!*((u_int32_t *)msg->data);
if (want ^ priv->promisc) {
if ((error = ifpromisc(priv->ifp, want)) != 0)
break;
priv->promisc = want;
Also description of "orphan" hook is about passing packets to it which would
be otherwise discarded, but promisc case is not amongst them (I don't know if
intent would be to "goto discard" in such case):
ether_demux():
{
...
if ((ifp->if_flags & IFF_PPROMISC) == 0 && (m->m_flags & M_PROMISC)) {
m_freem(m);
return;
}
...
discard:
/*
* Packet is to be discarded. If netgraph is present,
* hand the packet to it for last chance processing;
* otherwise dispose of it.
*/
if (ifp->if_l2com != NULL) {
KASSERT(ng_ether_input_orphan_p != NULL,
("ng_ether_input_orphan_p is NULL"));
(*ng_ether_input_orphan_p)(ifp, m);
return;
}
m_freem(m);
}
Which behaviour you'd expect to be right?
--
WBR, @nuclight