コード例 #1
0
ファイル: vrf.c プロジェクト: 513855417/linux
/* called under rcu_read_lock */
static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
{
	struct fib_result res = { .tclassid = 0 };
	struct net *net = dev_net(dev);
	u32 orig_tos = fl4->flowi4_tos;
	u8 flags = fl4->flowi4_flags;
	u8 scope = fl4->flowi4_scope;
	u8 tos = RT_FL_TOS(fl4);
	int rc;

	if (unlikely(!fl4->daddr))
		return 0;

	fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF;
	fl4->flowi4_iif = LOOPBACK_IFINDEX;
	/* make sure oif is set to VRF device for lookup */
	fl4->flowi4_oif = dev->ifindex;
	fl4->flowi4_tos = tos & IPTOS_RT_MASK;
	fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
			     RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);

	rc = fib_lookup(net, fl4, &res, 0);
	if (!rc) {
		if (res.type == RTN_LOCAL)
			fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr;
		else
			fib_select_path(net, &res, fl4, -1);
	}

	fl4->flowi4_flags = flags;
	fl4->flowi4_tos = orig_tos;
	fl4->flowi4_scope = scope;

	return rc;
}
コード例 #2
0
ファイル: ipt_rpfilter.c プロジェクト: 020gzh/linux
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;
}
コード例 #3
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;
}
コード例 #4
0
ファイル: route.c プロジェクト: shattered/linux-m68k
struct rtable * ip_rt_slow_route (__u32 daddr, int local, struct device *dev)
{
	unsigned hash = ip_rt_hash_code(daddr)^local;
	struct rtable * rth;
	struct fib_node * f;
	struct fib_info * fi;
	__u32 saddr;

#if RT_CACHE_DEBUG >= 2
	printk("rt_cache miss @%08x\n", daddr);
#endif

	rth = kmalloc(sizeof(struct rtable), GFP_ATOMIC);
	if (!rth)
	{
		ip_rt_unlock();
		return NULL;
	}

	if (local)
		f = fib_lookup_local(daddr, dev);
	else
		f = fib_lookup (daddr, dev);

	if (f)
	{
		fi = f->fib_info;
		f->fib_use++;
	}

	if (!f || (fi->fib_flags & RTF_REJECT))
	{
#ifdef CONFIG_KERNELD	
		char wanted_route[20];
#endif		
#if RT_CACHE_DEBUG >= 2
		printk("rt_route failed @%08x\n", daddr);
#endif
		ip_rt_unlock();
		kfree_s(rth, sizeof(struct rtable));
#ifdef CONFIG_KERNELD		
		if (MULTICAST(daddr)) 
			return NULL; 
		daddr=ntohl(daddr);
		sprintf(wanted_route, "%d.%d.%d.%d",
			(int)(daddr >> 24) & 0xff, (int)(daddr >> 16) & 0xff,
			(int)(daddr >> 8) & 0xff, (int)daddr & 0xff);
		kerneld_route(wanted_route); 	/* Dynamic route request */
#endif		
		return NULL;
	}
コード例 #5
0
ファイル: host_helper.c プロジェクト: KHATEEBNSIT/AP
static uint32_t get_next_hop( uint32_t daddr , uint32_t saddr )
{
    struct fib_result res;
    struct flowi fl = { .nl_u = { .ip4_u =
            {
                .daddr = daddr,
                .saddr = saddr,
                .tos = 0,
                .scope = RT_SCOPE_UNIVERSE,
            }
        },
        .mark = 0,
        .iif = multi_route_indev->ifindex
    };
    struct net    * net = dev_net(multi_route_indev);
    struct fib_nh *mrnh;

    fib_lookup(net, &fl, &res);
    mrnh = res.fi->fib_nh;

    return mrnh->nh_gw;
}
コード例 #6
0
int
ip_do_nat(struct sk_buff *skb)
{
	struct rtable *rt = (struct rtable*)skb->dst;
	struct iphdr *iph = skb->nh.iph;
	u32 odaddr = iph->daddr;
	u32 osaddr = iph->saddr;
	u16	check;

	IPCB(skb)->flags |= IPSKB_TRANSLATED;

	/* Rewrite IP header */
	iph->daddr = rt->rt_dst_map;
	iph->saddr = rt->rt_src_map;
	iph->check = 0;
	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);

	/* If it is the first fragment, rewrite protocol headers */

	if (!(iph->frag_off & htons(IP_OFFSET))) {
		u16	*cksum;

		switch(iph->protocol) {
		case IPPROTO_TCP:
			cksum  = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
			if ((u8*)(cksum+1) > skb->tail)
				goto truncated;
			check = *cksum;
			if (skb->ip_summed != CHECKSUM_HW)
				check = ~check;
			check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check);
			check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
			if (skb->ip_summed == CHECKSUM_HW)
				check = ~check;
			*cksum = check;
			break;
		case IPPROTO_UDP:
			cksum  = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
			if ((u8*)(cksum+1) > skb->tail)
				goto truncated;
			if ((check = *cksum) != 0) {
				check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
				check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
				*cksum = check ? : 0xFFFF;
			}
			break;
		case IPPROTO_ICMP:
		{
			struct icmphdr *icmph = (struct icmphdr*)((char*)iph + (iph->ihl<<2));
			struct   iphdr *ciph;
			u32 idaddr, isaddr;
			int updated;

			if ((icmph->type != ICMP_DEST_UNREACH) &&
			    (icmph->type != ICMP_TIME_EXCEEDED) &&
			    (icmph->type != ICMP_PARAMETERPROB))
				break;

			ciph = (struct iphdr *) (icmph + 1);

			if ((u8*)(ciph+1) > skb->tail)
				goto truncated;

			isaddr = ciph->saddr;
			idaddr = ciph->daddr;
			updated = 0;

			if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr) {
				ciph->saddr = iph->daddr;
				updated = 1;
			}
			if (rt->rt_flags&RTCF_SNAT) {
				if (ciph->daddr != osaddr) {
					struct   fib_result res;
					struct   rt_key key;
					unsigned flags = 0;

					key.src = ciph->daddr;
					key.dst = ciph->saddr;
					key.iif = skb->dev->ifindex;
					key.oif = 0;
#ifdef CONFIG_IP_ROUTE_TOS
					key.tos = RT_TOS(ciph->tos);
#endif
#ifdef CONFIG_IP_ROUTE_FWMARK
					key.fwmark = 0;
#endif
					/* Use fib_lookup() until we get our own
					 * hash table of NATed hosts -- Rani
				 	 */
					if (fib_lookup(&key, &res) == 0) {
						if (res.r) {
							ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
							if (ciph->daddr != idaddr)
								updated = 1;
						}
						fib_res_put(&res);
					}
				} else {
					ciph->daddr = iph->saddr;
					updated = 1;
				}
			}
			if (updated) {
				cksum  = &icmph->checksum;
				/* Using tcpudp primitive. Why not? */
				check  = csum_tcpudp_magic(ciph->saddr, ciph->daddr, 0, 0, ~(*cksum));
				*cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0, ~check);
			}
			break;
		}
		default:
			break;
		}
コード例 #7
0
ファイル: nft_fib_ipv4.c プロジェクト: Lyude/linux
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;
	}
}