Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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 = &regs->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;
	}
}