From: Eric Woudstra <ericwouds@gmail.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>,
Jozsef Kadlecsik <kadlec@netfilter.org>,
Florian Westphal <fw@strlen.de>, Phil Sutter <phil@nwl.cc>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Nikolay Aleksandrov <razor@blackwall.org>,
Ido Schimmel <idosch@nvidia.com>
Cc: netfilter-devel@vger.kernel.org, netdev@vger.kernel.org,
bridge@lists.linux.dev, Eric Woudstra <ericwouds@gmail.com>
Subject: [PATCH v17 nf-next 2/4] netfilter: bridge: Add conntrack double vlan and pppoe
Date: Sun, 9 Nov 2025 20:24:25 +0100 [thread overview]
Message-ID: <20251109192427.617142-3-ericwouds@gmail.com> (raw)
In-Reply-To: <20251109192427.617142-1-ericwouds@gmail.com>
In a bridge, until now, it is possible to track connections of plain
ip(v6) and ip(v6) encapsulated in single 802.1q or 802.1ad.
This patch adds the capability to track connections when the connection
is (also) encapsulated in PPPoE. It also adds the capability to track
connections that are encapsulated in an inner 802.1q, combined with an
outer 802.1ad or 802.1q encapsulation.
To prevent mixing connections that are tagged differently in the L2
encapsulations, one should separate them using conntrack zones.
Using a conntrack zone is a hard requirement for the newly added
encapsulations of the tracking capability inside a bridge.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/bridge/netfilter/nf_conntrack_bridge.c | 92 ++++++++++++++++++----
1 file changed, 75 insertions(+), 17 deletions(-)
diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c
index 6482de4d8750..39e844b3d3c4 100644
--- a/net/bridge/netfilter/nf_conntrack_bridge.c
+++ b/net/bridge/netfilter/nf_conntrack_bridge.c
@@ -237,58 +237,116 @@ static int nf_ct_br_ipv6_check(const struct sk_buff *skb)
return 0;
}
+static int nf_ct_bridge_pre_inner(struct sk_buff *skb, __be16 *proto, u32 *len)
+{
+ switch (*proto) {
+ case htons(ETH_P_PPP_SES): {
+ struct ppp_hdr {
+ struct pppoe_hdr hdr;
+ __be16 proto;
+ } *ph;
+
+ if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
+ return -1;
+ ph = (struct ppp_hdr *)(skb->data);
+ switch (ph->proto) {
+ case htons(PPP_IP):
+ *proto = htons(ETH_P_IP);
+ *len = ntohs(ph->hdr.length) - 2;
+ skb_set_network_header(skb, PPPOE_SES_HLEN);
+ return PPPOE_SES_HLEN;
+ case htons(PPP_IPV6):
+ *proto = htons(ETH_P_IPV6);
+ *len = ntohs(ph->hdr.length) - 2;
+ skb_set_network_header(skb, PPPOE_SES_HLEN);
+ return PPPOE_SES_HLEN;
+ }
+ break;
+ }
+ case htons(ETH_P_8021Q): {
+ struct vlan_hdr *vhdr;
+
+ if (!pskb_may_pull(skb, VLAN_HLEN))
+ return -1;
+ vhdr = (struct vlan_hdr *)(skb->data);
+ *proto = vhdr->h_vlan_encapsulated_proto;
+ skb_set_network_header(skb, VLAN_HLEN);
+ return VLAN_HLEN;
+ }
+ }
+ return 0;
+}
+
static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct nf_hook_state bridge_state = *state;
+ int ret = NF_ACCEPT, offset = 0;
enum ip_conntrack_info ctinfo;
+ u32 len, pppoe_len = 0;
struct nf_conn *ct;
- u32 len;
- int ret;
+ __be16 proto;
ct = nf_ct_get(skb, &ctinfo);
if ((ct && !nf_ct_is_template(ct)) ||
ctinfo == IP_CT_UNTRACKED)
return NF_ACCEPT;
- switch (skb->protocol) {
- case htons(ETH_P_IP):
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ proto = skb->protocol;
+
+ if (ct && nf_ct_zone_id(nf_ct_zone(ct), CTINFO2DIR(ctinfo)) !=
+ NF_CT_DEFAULT_ZONE_ID) {
+ offset = nf_ct_bridge_pre_inner(skb, &proto, &pppoe_len);
+ if (offset < 0)
return NF_ACCEPT;
+ }
+
+ switch (proto) {
+ case htons(ETH_P_IP):
+ if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
+ goto do_not_track;
len = skb_ip_totlen(skb);
- if (pskb_trim_rcsum(skb, len))
- return NF_ACCEPT;
+ if (pppoe_len && pppoe_len != len)
+ goto do_not_track;
+ if (pskb_trim_rcsum(skb, offset + len))
+ goto do_not_track;
if (nf_ct_br_ip_check(skb))
- return NF_ACCEPT;
+ goto do_not_track;
bridge_state.pf = NFPROTO_IPV4;
ret = nf_ct_br_defrag4(skb, &bridge_state);
break;
case htons(ETH_P_IPV6):
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
- return NF_ACCEPT;
+ if (!pskb_may_pull(skb, offset + sizeof(struct ipv6hdr)))
+ goto do_not_track;
len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
- if (pskb_trim_rcsum(skb, len))
- return NF_ACCEPT;
+ if (pppoe_len && pppoe_len != len)
+ goto do_not_track;
+ if (pskb_trim_rcsum(skb, offset + len))
+ goto do_not_track;
if (nf_ct_br_ipv6_check(skb))
- return NF_ACCEPT;
+ goto do_not_track;
bridge_state.pf = NFPROTO_IPV6;
ret = nf_ct_br_defrag6(skb, &bridge_state);
break;
default:
nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
- return NF_ACCEPT;
+ goto do_not_track;
}
- if (ret != NF_ACCEPT)
- return ret;
+ if (ret == NF_ACCEPT)
+ ret = nf_conntrack_in(skb, &bridge_state);
+
+do_not_track:
+ if (offset && ret == NF_ACCEPT)
+ skb_reset_network_header(skb);
- return nf_conntrack_in(skb, &bridge_state);
+ return ret;
}
static unsigned int nf_ct_bridge_in(void *priv, struct sk_buff *skb,
--
2.50.0
next prev parent reply other threads:[~2025-11-09 19:24 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-09 19:24 [PATCH v17 nf-next 0/4] conntrack: bridge: add double vlan, pppoe and pppoe-in-q Eric Woudstra
2025-11-09 19:24 ` [PATCH v17 nf-next 1/4] netfilter: utils: nf_checksum(_partial) correct data!=networkheader Eric Woudstra
2025-11-09 19:24 ` Eric Woudstra [this message]
2025-11-09 19:24 ` [PATCH v17 nf-next 3/4] netfilter: nft_set_pktinfo_ipv4/6_validate: Add nhoff argument Eric Woudstra
2025-11-09 19:24 ` [PATCH v17 nf-next 4/4] netfilter: nft_chain_filter: Add bridge double vlan and pppoe Eric Woudstra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251109192427.617142-3-ericwouds@gmail.com \
--to=ericwouds@gmail.com \
--cc=bridge@lists.linux.dev \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kadlec@netfilter.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=phil@nwl.cc \
--cc=razor@blackwall.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).