ip_nat_dumb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:4k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * INET An implementation of the TCP/IP protocol suite for the LINUX
  3.  * operating system.  INET is implemented using the  BSD Socket
  4.  * interface as the means of communication with the user level.
  5.  *
  6.  * Dumb Network Address Translation.
  7.  *
  8.  * Version: $Id: ip_nat_dumb.c,v 1.11 2000/12/13 18:31:48 davem Exp $
  9.  *
  10.  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  11.  *
  12.  * This program is free software; you can redistribute it and/or
  13.  * modify it under the terms of the GNU General Public License
  14.  * as published by the Free Software Foundation; either version
  15.  * 2 of the License, or (at your option) any later version.
  16.  *
  17.  * Fixes:
  18.  * Rani Assaf : A zero checksum is a special case
  19.  * only in UDP
  20.  *  Rani Assaf : Added ICMP messages rewriting
  21.  *  Rani Assaf : Repaired wrong changes, made by ANK.
  22.  *
  23.  *
  24.  * NOTE: It is just working model of real NAT.
  25.  */
  26. #include <linux/config.h>
  27. #include <linux/types.h>
  28. #include <linux/mm.h>
  29. #include <linux/sched.h>
  30. #include <linux/skbuff.h>
  31. #include <linux/ip.h>
  32. #include <linux/icmp.h>
  33. #include <linux/netdevice.h>
  34. #include <net/sock.h>
  35. #include <net/ip.h>
  36. #include <net/icmp.h>
  37. #include <linux/tcp.h>
  38. #include <linux/udp.h>
  39. #include <net/checksum.h>
  40. #include <linux/route.h>
  41. #include <net/route.h>
  42. #include <net/ip_fib.h>
  43. int
  44. ip_do_nat(struct sk_buff *skb)
  45. {
  46. struct rtable *rt = (struct rtable*)skb->dst;
  47. struct iphdr *iph = skb->nh.iph;
  48. u32 odaddr = iph->daddr;
  49. u32 osaddr = iph->saddr;
  50. u16 check;
  51. IPCB(skb)->flags |= IPSKB_TRANSLATED;
  52. /* Rewrite IP header */
  53. iph->daddr = rt->rt_dst_map;
  54. iph->saddr = rt->rt_src_map;
  55. iph->check = 0;
  56. iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
  57. /* If it is the first fragment, rewrite protocol headers */
  58. if (!(iph->frag_off & htons(IP_OFFSET))) {
  59. u16 *cksum;
  60. switch(iph->protocol) {
  61. case IPPROTO_TCP:
  62. cksum  = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
  63. if ((u8*)(cksum+1) > skb->tail)
  64. goto truncated;
  65. check = *cksum;
  66. if (skb->ip_summed != CHECKSUM_HW)
  67. check = ~check;
  68. check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check);
  69. check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
  70. if (skb->ip_summed == CHECKSUM_HW)
  71. check = ~check;
  72. *cksum = check;
  73. break;
  74. case IPPROTO_UDP:
  75. cksum  = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
  76. if ((u8*)(cksum+1) > skb->tail)
  77. goto truncated;
  78. if ((check = *cksum) != 0) {
  79. check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
  80. check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
  81. *cksum = check ? : 0xFFFF;
  82. }
  83. break;
  84. case IPPROTO_ICMP:
  85. {
  86. struct icmphdr *icmph = (struct icmphdr*)((char*)iph + (iph->ihl<<2));
  87. struct   iphdr *ciph;
  88. u32 idaddr, isaddr;
  89. int updated;
  90. if ((icmph->type != ICMP_DEST_UNREACH) &&
  91.     (icmph->type != ICMP_TIME_EXCEEDED) &&
  92.     (icmph->type != ICMP_PARAMETERPROB))
  93. break;
  94. ciph = (struct iphdr *) (icmph + 1);
  95. if ((u8*)(ciph+1) > skb->tail)
  96. goto truncated;
  97. isaddr = ciph->saddr;
  98. idaddr = ciph->daddr;
  99. updated = 0;
  100. if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr) {
  101. ciph->saddr = iph->daddr;
  102. updated = 1;
  103. }
  104. if (rt->rt_flags&RTCF_SNAT) {
  105. if (ciph->daddr != osaddr) {
  106. struct   fib_result res;
  107. struct   rt_key key;
  108. unsigned flags = 0;
  109. key.src = ciph->daddr;
  110. key.dst = ciph->saddr;
  111. key.iif = skb->dev->ifindex;
  112. key.oif = 0;
  113. #ifdef CONFIG_IP_ROUTE_TOS
  114. key.tos = RT_TOS(ciph->tos);
  115. #endif
  116. #ifdef CONFIG_IP_ROUTE_FWMARK
  117. key.fwmark = 0;
  118. #endif
  119. /* Use fib_lookup() until we get our own
  120.  * hash table of NATed hosts -- Rani
  121.    */
  122. if (fib_lookup(&key, &res) == 0) {
  123. if (res.r) {
  124. ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
  125. if (ciph->daddr != idaddr)
  126. updated = 1;
  127. }
  128. fib_res_put(&res);
  129. }
  130. } else {
  131. ciph->daddr = iph->saddr;
  132. updated = 1;
  133. }
  134. }
  135. if (updated) {
  136. cksum  = &icmph->checksum;
  137. /* Using tcpudp primitive. Why not? */
  138. check  = csum_tcpudp_magic(ciph->saddr, ciph->daddr, 0, 0, ~(*cksum));
  139. *cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0, ~check);
  140. }
  141. break;
  142. }
  143. default:
  144. break;
  145. }
  146. }
  147. return NET_RX_SUCCESS;
  148. truncated:
  149. /* should be return NET_RX_BAD; */
  150. return -EINVAL;
  151. }