static bool rpfilter_lookup_reverse(struct net *net, struct flowi4 *fl4, const struct net_device *dev, u8 flags) { struct fib_result res; bool dev_match; int ret __maybe_unused; if (fib_lookup(net, fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE)) return false; if (res.type != RTN_UNICAST) { if (res.type != RTN_LOCAL || !(flags & XT_RPFILTER_ACCEPT_LOCAL)) return false; } dev_match = false; #ifdef CONFIG_IP_ROUTE_MULTIPATH for (ret = 0; ret < res.fi->fib_nhs; ret++) { struct fib_nh *nh = &res.fi->fib_nh[ret]; if (nh->nh_dev == dev) { dev_match = true; break; } } #else if (FIB_RES_DEV(res) == dev) dev_match = true; #endif return dev_match || flags & XT_RPFILTER_LOOSE; }
static bool rpfilter_lookup_reverse(struct flowi4 *fl4, const struct net_device *dev, u8 flags) { struct fib_result res; bool dev_match; struct net *net = dev_net(dev); int ret __maybe_unused; if (fib_lookup(net, fl4, &res)) return false; if (res.type != RTN_UNICAST) { if (res.type != RTN_LOCAL || !(flags & XT_RPFILTER_ACCEPT_LOCAL)) return false; } dev_match = false; //#ifdef CONFIG_IP_ROUTE_MULTIPATH #if (defined CONFIG_IP_ROUTE_MULTIPATH) || (defined CONFIG_IP_ROUTE_DEFLECTION) for (ret = 0; ret < res.fi->fib_nhs; ret++) { struct fib_nh *nh = &res.fi->fib_nh[ret]; if (nh->nh_dev == dev) { dev_match = true; break; } } #else if (FIB_RES_DEV(res) == dev) dev_match = true; #endif if (dev_match || flags & XT_RPFILTER_LOOSE) return FIB_RES_NH(res).nh_scope <= RT_SCOPE_HOST; return dev_match; }
struct net_device * ip_dev_find(u32 addr) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; struct net_device *dev = NULL; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) { return NULL; } if (res.type != RTN_LOCAL) goto out; dev = FIB_RES_DEV(res); if (dev) atomic_inc(&dev->refcnt); out: fib_res_put(&res); return dev; }
struct net_device * ip_dev_find(struct net *net, __be32 addr) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; struct net_device *dev = NULL; struct fib_table *local_table; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif local_table = fib_get_table(net, RT_TABLE_LOCAL); if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) return NULL; if (res.type != RTN_LOCAL) goto out; dev = FIB_RES_DEV(res); if (dev) dev_hold(dev); out: fib_res_put(&res); return dev; }
void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { const struct nft_fib *priv = nft_expr_priv(expr); int noff = skb_network_offset(pkt->skb); u32 *dest = ®s->data[priv->dreg]; struct iphdr *iph, _iph; struct fib_result res; struct flowi4 fl4 = { .flowi4_scope = RT_SCOPE_UNIVERSE, .flowi4_iif = LOOPBACK_IFINDEX, }; const struct net_device *oif; struct net_device *found; #ifdef CONFIG_IP_ROUTE_MULTIPATH int i; #endif /* * Do not set flowi4_oif, it restricts results (for example, asking * for oif 3 will get RTN_UNICAST result even if the daddr exits * on another interface. * * Search results for the desired outinterface instead. */ if (priv->flags & NFTA_FIB_F_OIF) oif = nft_out(pkt); else if (priv->flags & NFTA_FIB_F_IIF) oif = nft_in(pkt); else oif = NULL; if (nft_hook(pkt) == NF_INET_PRE_ROUTING && nft_fib_is_loopback(pkt->skb, nft_in(pkt))) { nft_fib_store_result(dest, priv, pkt, nft_in(pkt)->ifindex); return; } iph = skb_header_pointer(pkt->skb, noff, sizeof(_iph), &_iph); if (!iph) { regs->verdict.code = NFT_BREAK; return; } if (ipv4_is_zeronet(iph->saddr)) { if (ipv4_is_lbcast(iph->daddr) || ipv4_is_local_multicast(iph->daddr)) { nft_fib_store_result(dest, priv, pkt, get_ifindex(pkt->skb->dev)); return; } } if (priv->flags & NFTA_FIB_F_MARK) fl4.flowi4_mark = pkt->skb->mark; fl4.flowi4_tos = iph->tos & DSCP_BITS; if (priv->flags & NFTA_FIB_F_DADDR) { fl4.daddr = iph->daddr; fl4.saddr = get_saddr(iph->saddr); } else { fl4.daddr = iph->saddr; fl4.saddr = get_saddr(iph->daddr); } *dest = 0; if (fib_lookup(nft_net(pkt), &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE)) return; switch (res.type) { case RTN_UNICAST: break; case RTN_LOCAL: /* Should not see RTN_LOCAL here */ return; default: break; } if (!oif) { found = FIB_RES_DEV(res); goto ok; } #ifdef CONFIG_IP_ROUTE_MULTIPATH for (i = 0; i < res.fi->fib_nhs; i++) { struct fib_nh *nh = &res.fi->fib_nh[i]; if (nh->nh_dev == oif) { found = nh->nh_dev; goto ok; } } return; #else found = FIB_RES_DEV(res); if (found != oif) return; #endif ok: switch (priv->result) { case NFT_FIB_RESULT_OIF: *dest = found->ifindex; break; case NFT_FIB_RESULT_OIFNAME: strncpy((char *)dest, found->name, IFNAMSIZ); break; default: WARN_ON_ONCE(1); break; } }