mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
netfilter: nft_meta: add double-tagged vlan and pppoe support
Currently: add rule netdev x y ip saddr 1.1.1.1 does not work with neither double-tagged vlan nor pppoe packets. This is because the network and transport header offset are not pointing to the IP and transport protocol headers in the stack. This patch expands NFT_META_PROTOCOL and NFT_META_L4PROTO to parse double-tagged vlan and pppoe packets so matching network and transport header fields becomes possible with the existing userspace generated bytecode. Note that this parser only supports double-tagged vlan which is composed of vlan offload + vlan header in the skb payload area for simplicity. NFT_META_PROTOCOL is used by bridge and netdev family as an implicit dependency in the bytecode to match on network header fields. Similarly, there is also NFT_META_L4PROTO, which is also used as an implicit dependency when matching on the transport protocol header fields. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
This commit is contained in:
committed by
Florian Westphal
parent
a3f1e6a19a
commit
3785091c6c
@@ -31,7 +31,9 @@ struct nft_pktinfo {
|
||||
const struct nf_hook_state *state;
|
||||
u8 flags;
|
||||
u8 tprot;
|
||||
__be16 ethertype;
|
||||
u16 fragoff;
|
||||
u16 nhoff;
|
||||
u16 thoff;
|
||||
u16 inneroff;
|
||||
};
|
||||
@@ -83,6 +85,8 @@ static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt)
|
||||
{
|
||||
pkt->flags = 0;
|
||||
pkt->tprot = 0;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = 0;
|
||||
pkt->thoff = 0;
|
||||
pkt->fragoff = 0;
|
||||
}
|
||||
|
||||
@@ -12,16 +12,19 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt)
|
||||
ip = ip_hdr(pkt->skb);
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = ip->protocol;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = 0;
|
||||
pkt->thoff = ip_hdrlen(pkt->skb);
|
||||
pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
||||
}
|
||||
|
||||
static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
|
||||
int nhoff)
|
||||
{
|
||||
struct iphdr *iph, _iph;
|
||||
u32 len, thoff, skb_len;
|
||||
|
||||
iph = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
|
||||
iph = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb) + nhoff,
|
||||
sizeof(*iph), &_iph);
|
||||
if (!iph)
|
||||
return -1;
|
||||
@@ -31,7 +34,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
|
||||
len = iph_totlen(pkt->skb, iph);
|
||||
thoff = iph->ihl * 4;
|
||||
skb_len = pkt->skb->len - skb_network_offset(pkt->skb);
|
||||
skb_len = pkt->skb->len - skb_network_offset(pkt->skb) - nhoff;
|
||||
|
||||
if (skb_len < len)
|
||||
return -1;
|
||||
@@ -42,7 +45,9 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = iph->protocol;
|
||||
pkt->thoff = skb_network_offset(pkt->skb) + thoff;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = nhoff;
|
||||
pkt->thoff = skb_network_offset(pkt->skb) + nhoff + thoff;
|
||||
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
|
||||
return 0;
|
||||
@@ -50,7 +55,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
|
||||
static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
||||
{
|
||||
if (__nft_set_pktinfo_ipv4_validate(pkt) < 0)
|
||||
if (__nft_set_pktinfo_ipv4_validate(pkt, 0) < 0)
|
||||
nft_set_pktinfo_unspec(pkt);
|
||||
}
|
||||
|
||||
@@ -78,6 +83,8 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
|
||||
}
|
||||
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = 0;
|
||||
pkt->tprot = iph->protocol;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
|
||||
@@ -20,21 +20,23 @@ static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt)
|
||||
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = 0;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
}
|
||||
|
||||
static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt, int nhoff)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unsigned int flags = IP6_FH_F_AUTH;
|
||||
struct ipv6hdr *ip6h, _ip6h;
|
||||
unsigned int thoff = 0;
|
||||
unsigned int thoff = nhoff;
|
||||
unsigned short frag_off;
|
||||
u32 pkt_len, skb_len;
|
||||
int protohdr;
|
||||
|
||||
ip6h = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb),
|
||||
ip6h = skb_header_pointer(pkt->skb, skb_network_offset(pkt->skb) + nhoff,
|
||||
sizeof(*ip6h), &_ip6h);
|
||||
if (!ip6h)
|
||||
return -1;
|
||||
@@ -43,7 +45,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
return -1;
|
||||
|
||||
pkt_len = ipv6_payload_len(pkt->skb, ip6h);
|
||||
skb_len = pkt->skb->len - skb_network_offset(pkt->skb);
|
||||
skb_len = pkt->skb->len - skb_network_offset(pkt->skb) - nhoff;
|
||||
if (pkt_len + sizeof(*ip6h) > skb_len)
|
||||
return -1;
|
||||
|
||||
@@ -53,6 +55,8 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = nhoff;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
||||
@@ -64,7 +68,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
|
||||
static inline void nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
||||
{
|
||||
if (__nft_set_pktinfo_ipv6_validate(pkt) < 0)
|
||||
if (__nft_set_pktinfo_ipv6_validate(pkt, 0) < 0)
|
||||
nft_set_pktinfo_unspec(pkt);
|
||||
}
|
||||
|
||||
@@ -99,6 +103,8 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt)
|
||||
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->ethertype = pkt->skb->protocol;
|
||||
pkt->nhoff = 0;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user