Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: flowtable: Fix QinQ and pppoe support for inet table

nf_flow_offload_inet_hook() does not check for 802.1q and PPPoE.
Fetch inner ethertype from these encapsulation protocols.

Fixes: 72efd585f714 ("netfilter: flowtable: add pppoe support")
Fixes: 4cd91f7c290f ("netfilter: flowtable: add vlan support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+35 -18
+18
include/net/netfilter/nf_flow_table.h
··· 10 10 #include <linux/netfilter/nf_conntrack_tuple_common.h> 11 11 #include <net/flow_offload.h> 12 12 #include <net/dst.h> 13 + #include <linux/if_pppox.h> 14 + #include <linux/ppp_defs.h> 13 15 14 16 struct nf_flowtable; 15 17 struct nf_flow_rule; ··· 318 316 319 317 int nf_flow_table_offload_init(void); 320 318 void nf_flow_table_offload_exit(void); 319 + 320 + static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) 321 + { 322 + __be16 proto; 323 + 324 + proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + 325 + sizeof(struct pppoe_hdr))); 326 + switch (proto) { 327 + case htons(PPP_IP): 328 + return htons(ETH_P_IP); 329 + case htons(PPP_IPV6): 330 + return htons(ETH_P_IPV6); 331 + } 332 + 333 + return 0; 334 + } 321 335 322 336 #endif /* _NF_FLOW_TABLE_H */
+17
net/netfilter/nf_flow_table_inet.c
··· 6 6 #include <linux/rhashtable.h> 7 7 #include <net/netfilter/nf_flow_table.h> 8 8 #include <net/netfilter/nf_tables.h> 9 + #include <linux/if_vlan.h> 9 10 10 11 static unsigned int 11 12 nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb, 12 13 const struct nf_hook_state *state) 13 14 { 15 + struct vlan_ethhdr *veth; 16 + __be16 proto; 17 + 14 18 switch (skb->protocol) { 19 + case htons(ETH_P_8021Q): 20 + veth = (struct vlan_ethhdr *)skb_mac_header(skb); 21 + proto = veth->h_vlan_encapsulated_proto; 22 + break; 23 + case htons(ETH_P_PPP_SES): 24 + proto = nf_flow_pppoe_proto(skb); 25 + break; 26 + default: 27 + proto = skb->protocol; 28 + break; 29 + } 30 + 31 + switch (proto) { 15 32 case htons(ETH_P_IP): 16 33 return nf_flow_offload_ip_hook(priv, skb, state); 17 34 case htons(ETH_P_IPV6):
-18
net/netfilter/nf_flow_table_ip.c
··· 8 8 #include <linux/ipv6.h> 9 9 #include <linux/netdevice.h> 10 10 #include <linux/if_ether.h> 11 - #include <linux/if_pppox.h> 12 - #include <linux/ppp_defs.h> 13 11 #include <net/ip.h> 14 12 #include <net/ipv6.h> 15 13 #include <net/ip6_route.h> ··· 235 237 skb_dst_set_noref(skb, dst); 236 238 dst_output(state->net, state->sk, skb); 237 239 return NF_STOLEN; 238 - } 239 - 240 - static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) 241 - { 242 - __be16 proto; 243 - 244 - proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + 245 - sizeof(struct pppoe_hdr))); 246 - switch (proto) { 247 - case htons(PPP_IP): 248 - return htons(ETH_P_IP); 249 - case htons(PPP_IPV6): 250 - return htons(ETH_P_IPV6); 251 - } 252 - 253 - return 0; 254 240 } 255 241 256 242 static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,