From 8f5fed654d54a9ae9c4eb95425d857e9524b803c Mon Sep 17 00:00:00 2001 From: Calvin Morrison Date: Tue, 18 Aug 2026 23:21:41 -0400 Subject: ether: a frame addressed to somebody else is not ours fw asks the card for promiscuous mode and then hands the protected stack every IP frame that arrives on it, whoever it was for. On a switched network that is mostly nothing; on anything else it is the neighbours' traffic, judged against the rules, counted in stats, and entered in the flow table as conversations that were never ours. A flow created that way outlives the packet that made it and will let traffic past that no rule was asked about. Promiscuous is still needed. The stack behind fw joins multicast groups on a pkt interface, which has no way to tell a card about them, so without it the groups would never be received at all. What it costs is the filter ethermux would otherwise have applied: if(!tome && !multi && !f->prom) continue; Frames addressed to this card, plus broadcast and multicast, would have arrived for nothing. So etherin puts that test back itself: the destination is ours, or it is a group address, or the frame is not ours to look at. No test. This is on the wire side of card mode, and the suite can take a spare card but cannot make a neighbour send to it. Reproducing it needs a second machine on the same segment, which is on the list of things never tested and stays there. Co-Authored-By: Claude Opus 5 --- fw/src/ether.c | 23 +++++++++++++++++++++++ fw/src/fw.c | 3 +++ 2 files changed, 26 insertions(+) diff --git a/fw/src/ether.c b/fw/src/ether.c index d77143a..48f69b9 100644 --- a/fw/src/ether.c +++ b/fw/src/ether.c @@ -292,6 +292,29 @@ arpin(uchar *f, int n) write(efd, r, sizeof r); } +/* + * Is this frame ours to look at? + * + * The card is promiscuous and has to be: the stack behind fw joins + * multicast groups on a pkt interface, which has no way to tell a card + * about them, so without it the groups would never be received. What + * promiscuous adds beyond that is other machines' unicast, and handing + * that to the protected stack means judging it, counting it and + * tracking flows for conversations that were never ours. ethermux + * would have given us frames addressed to this card plus broadcast and + * multicast for nothing; this puts back the filter that asking for + * promiscuous took away. + */ +int +etherforme(uchar *f, int n) +{ + if(n < Ehdrlen) + return 0; + if((f[0] & 1) != 0) /* group: broadcast or multicast */ + return 1; + return memcmp(f, ourmac, Eaddrlen) == 0; +} + int etherisarp(uchar *f, int n) { diff --git a/fw/src/fw.c b/fw/src/fw.c index 8901c2a..6ae38df 100644 --- a/fw/src/fw.c +++ b/fw/src/fw.c @@ -378,6 +378,7 @@ flowadd(Pkt *p) void servenet(char*, char*, char*); int etheropen(char*, uchar*); void ethersetaddr(uchar*, uchar*, int); +int etherforme(uchar*, int); int etherisarp(uchar*, int); int etherisip(uchar*, int); int etherwriteip(uchar*, int, uchar*, int, uchar*); @@ -1093,6 +1094,8 @@ etherin(void *a) } if(debug > 1) fprint(2, "wire: %d bytes type %.4ux\n", n, (buf[12]<<8)|buf[13]); + if(!etherforme(buf, n)) /* the wire's, not ours */ + continue; if(etherisarp(buf, n)) continue; if(!etherisip(buf, n)) -- cgit v1.2.3