Esempio n. 1
0
static inline unsigned __inet_dev_addr_type(struct net *net,
					    const struct net_device *dev,
					    __be32 addr)
{
	struct flowi		fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
	struct fib_result	res;
	unsigned ret = RTN_BROADCAST;
	struct fib_table *local_table;

	if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
		return RTN_BROADCAST;
	if (ipv4_is_multicast(addr))
		return RTN_MULTICAST;

#ifdef CONFIG_IP_MULTIPLE_TABLES
	res.r = NULL;
#endif

	local_table = fib_get_table(net, RT_TABLE_LOCAL);
	if (local_table) {
		ret = RTN_UNICAST;
		if (!local_table->tb_lookup(local_table, &fl, &res)) {
			if (!dev || dev == res.fi->fib_dev)
				ret = res.type;
			fib_res_put(&res);
		}
	}
	return ret;
}
Esempio n. 2
0
unsigned inet_addr_type(u32 addr)
{
	struct flowi		fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
	struct fib_result	res;
	unsigned ret = RTN_BROADCAST;

	if (ZERONET(addr) || BADCLASS(addr))
		return RTN_BROADCAST;
	if (MULTICAST(addr))
		return RTN_MULTICAST;

#ifdef CONFIG_IP_MULTIPLE_TABLES
	res.r = NULL;
#endif
	
	if (ip_fib_local_table) {
		ret = RTN_UNICAST;
		if (!ip_fib_local_table->tb_lookup(ip_fib_local_table,
						   &fl, &res)) {
			ret = res.type;
			fib_res_put(&res);
		}
	}
	return ret;
}
Esempio n. 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;
}
Esempio n. 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;
}
Esempio n. 5
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;
		}