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

netfilter: nf_tables: fib: use skb_header_pointer

This is a preparatory patch for adding fib support to the netdev family.

The netdev family receives the packets from ingress hook. At this point
we have no guarantee that the ip header is linear. So this patch
replaces ip_hdr with skb_header_pointer in order to address that
possible situation.

Signed-off-by: Pablo M. Bermudo Garay <pablombg@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Pablo M. Bermudo Garay and committed by
Pablo Neira Ayuso
f347ec85 784b4e61

+39 -10
+16 -4
net/ipv4/netfilter/nft_fib_ipv4.c
··· 32 32 const struct nft_pktinfo *pkt) 33 33 { 34 34 const struct nft_fib *priv = nft_expr_priv(expr); 35 + int noff = skb_network_offset(pkt->skb); 35 36 u32 *dst = &regs->data[priv->dreg]; 36 37 const struct net_device *dev = NULL; 37 - const struct iphdr *iph; 38 + struct iphdr *iph, _iph; 38 39 __be32 addr; 39 40 40 41 if (priv->flags & NFTA_FIB_F_IIF) ··· 43 42 else if (priv->flags & NFTA_FIB_F_OIF) 44 43 dev = nft_out(pkt); 45 44 46 - iph = ip_hdr(pkt->skb); 45 + iph = skb_header_pointer(pkt->skb, noff, sizeof(_iph), &_iph); 46 + if (!iph) { 47 + regs->verdict.code = NFT_BREAK; 48 + return; 49 + } 50 + 47 51 if (priv->flags & NFTA_FIB_F_DADDR) 48 52 addr = iph->daddr; 49 53 else ··· 67 61 const struct nft_pktinfo *pkt) 68 62 { 69 63 const struct nft_fib *priv = nft_expr_priv(expr); 64 + int noff = skb_network_offset(pkt->skb); 70 65 u32 *dest = &regs->data[priv->dreg]; 71 - const struct iphdr *iph; 66 + struct iphdr *iph, _iph; 72 67 struct fib_result res; 73 68 struct flowi4 fl4 = { 74 69 .flowi4_scope = RT_SCOPE_UNIVERSE, ··· 102 95 return; 103 96 } 104 97 105 - iph = ip_hdr(pkt->skb); 98 + iph = skb_header_pointer(pkt->skb, noff, sizeof(_iph), &_iph); 99 + if (!iph) { 100 + regs->verdict.code = NFT_BREAK; 101 + return; 102 + } 103 + 106 104 if (ipv4_is_zeronet(iph->saddr)) { 107 105 if (ipv4_is_lbcast(iph->daddr) || 108 106 ipv4_is_local_multicast(iph->daddr)) {
+23 -6
net/ipv6/netfilter/nft_fib_ipv6.c
··· 25 25 26 26 static int nft_fib6_flowi_init(struct flowi6 *fl6, const struct nft_fib *priv, 27 27 const struct nft_pktinfo *pkt, 28 - const struct net_device *dev) 28 + const struct net_device *dev, 29 + struct ipv6hdr *iph) 29 30 { 30 - const struct ipv6hdr *iph = ipv6_hdr(pkt->skb); 31 31 int lookup_flags = 0; 32 32 33 33 if (priv->flags & NFTA_FIB_F_DADDR) { ··· 55 55 } 56 56 57 57 static u32 __nft_fib6_eval_type(const struct nft_fib *priv, 58 - const struct nft_pktinfo *pkt) 58 + const struct nft_pktinfo *pkt, 59 + struct ipv6hdr *iph) 59 60 { 60 61 const struct net_device *dev = NULL; 61 62 const struct nf_ipv6_ops *v6ops; ··· 78 77 else if (priv->flags & NFTA_FIB_F_OIF) 79 78 dev = nft_out(pkt); 80 79 81 - nft_fib6_flowi_init(&fl6, priv, pkt, dev); 80 + nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph); 82 81 83 82 v6ops = nf_get_ipv6_ops(); 84 83 if (dev && v6ops && v6ops->chk_addr(nft_net(pkt), &fl6.daddr, dev, true)) ··· 132 131 const struct nft_pktinfo *pkt) 133 132 { 134 133 const struct nft_fib *priv = nft_expr_priv(expr); 134 + int noff = skb_network_offset(pkt->skb); 135 135 u32 *dest = &regs->data[priv->dreg]; 136 + struct ipv6hdr *iph, _iph; 136 137 137 - *dest = __nft_fib6_eval_type(priv, pkt); 138 + iph = skb_header_pointer(pkt->skb, noff, sizeof(_iph), &_iph); 139 + if (!iph) { 140 + regs->verdict.code = NFT_BREAK; 141 + return; 142 + } 143 + 144 + *dest = __nft_fib6_eval_type(priv, pkt, iph); 138 145 } 139 146 EXPORT_SYMBOL_GPL(nft_fib6_eval_type); 140 147 ··· 150 141 const struct nft_pktinfo *pkt) 151 142 { 152 143 const struct nft_fib *priv = nft_expr_priv(expr); 144 + int noff = skb_network_offset(pkt->skb); 153 145 const struct net_device *oif = NULL; 154 146 u32 *dest = &regs->data[priv->dreg]; 147 + struct ipv6hdr *iph, _iph; 155 148 struct flowi6 fl6 = { 156 149 .flowi6_iif = LOOPBACK_IFINDEX, 157 150 .flowi6_proto = pkt->tprot, ··· 166 155 else if (priv->flags & NFTA_FIB_F_OIF) 167 156 oif = nft_out(pkt); 168 157 169 - lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif); 158 + iph = skb_header_pointer(pkt->skb, noff, sizeof(_iph), &_iph); 159 + if (!iph) { 160 + regs->verdict.code = NFT_BREAK; 161 + return; 162 + } 163 + 164 + lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph); 170 165 171 166 if (nft_hook(pkt) == NF_INET_PRE_ROUTING && 172 167 nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {