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; }
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; }
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; }
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; }