~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipv4/ip_nat_dumb.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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.10 2000/10/24 22:54:26 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 
 27 #include <linux/config.h>
 28 #include <linux/types.h>
 29 #include <linux/mm.h>
 30 #include <linux/sched.h>
 31 #include <linux/skbuff.h>
 32 #include <linux/ip.h>
 33 #include <linux/icmp.h>
 34 #include <linux/netdevice.h>
 35 #include <net/sock.h>
 36 #include <net/ip.h>
 37 #include <net/icmp.h>
 38 #include <linux/tcp.h>
 39 #include <linux/udp.h>
 40 #include <net/checksum.h>
 41 #include <linux/route.h>
 42 #include <net/route.h>
 43 #include <net/ip_fib.h>
 44 
 45 
 46 int
 47 ip_do_nat(struct sk_buff *skb)
 48 {
 49         struct rtable *rt = (struct rtable*)skb->dst;
 50         struct iphdr *iph = skb->nh.iph;
 51         u32 odaddr = iph->daddr;
 52         u32 osaddr = iph->saddr;
 53         u16     check;
 54 
 55         IPCB(skb)->flags |= IPSKB_TRANSLATED;
 56 
 57         /* Rewrite IP header */
 58         iph->daddr = rt->rt_dst_map;
 59         iph->saddr = rt->rt_src_map;
 60         iph->check = 0;
 61         iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 62 
 63         /* If it is the first fragment, rewrite protocol headers */
 64 
 65         if (!(iph->frag_off & htons(IP_OFFSET))) {
 66                 u16     *cksum;
 67 
 68                 switch(iph->protocol) {
 69                 case IPPROTO_TCP:
 70                         cksum  = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
 71                         if ((u8*)(cksum+1) > skb->tail)
 72                                 goto truncated;
 73                         check  = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum));
 74                         *cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
 75                         break;
 76                 case IPPROTO_UDP:
 77                         cksum  = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
 78                         if ((u8*)(cksum+1) > skb->tail)
 79                                 goto truncated;
 80                         if ((check = *cksum) != 0) {
 81                                 check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
 82                                 check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
 83                                 *cksum = check ? : 0xFFFF;
 84                         }
 85                         break;
 86                 case IPPROTO_ICMP:
 87                 {
 88                         struct icmphdr *icmph = (struct icmphdr*)((char*)iph + (iph->ihl<<2));
 89                         struct   iphdr *ciph;
 90                         u32 idaddr, isaddr;
 91                         int updated;
 92 
 93                         if ((icmph->type != ICMP_DEST_UNREACH) &&
 94                             (icmph->type != ICMP_TIME_EXCEEDED) &&
 95                             (icmph->type != ICMP_PARAMETERPROB))
 96                                 break;
 97 
 98                         ciph = (struct iphdr *) (icmph + 1);
 99 
100                         if ((u8*)(ciph+1) > skb->tail)
101                                 goto truncated;
102 
103                         isaddr = ciph->saddr;
104                         idaddr = ciph->daddr;
105                         updated = 0;
106 
107                         if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr) {
108                                 ciph->saddr = iph->daddr;
109                                 updated = 1;
110                         }
111                         if (rt->rt_flags&RTCF_SNAT) {
112                                 if (ciph->daddr != osaddr) {
113                                         struct   fib_result res;
114                                         struct   rt_key key;
115                                         unsigned flags = 0;
116 
117                                         key.src = ciph->daddr;
118                                         key.dst = ciph->saddr;
119                                         key.iif = skb->dev->ifindex;
120                                         key.oif = 0;
121 #ifdef CONFIG_IP_ROUTE_TOS
122                                         key.tos = RT_TOS(ciph->tos);
123 #endif
124 #ifdef CONFIG_IP_ROUTE_FWMARK
125                                         key.fwmark = 0;
126 #endif
127                                         /* Use fib_lookup() until we get our own
128                                          * hash table of NATed hosts -- Rani
129                                          */
130                                         if (fib_lookup(&key, &res) == 0) {
131                                                 if (res.r) {
132                                                         ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
133                                                         if (ciph->daddr != idaddr)
134                                                                 updated = 1;
135                                                 }
136                                                 fib_res_put(&res);
137                                         }
138                                 } else {
139                                         ciph->daddr = iph->saddr;
140                                         updated = 1;
141                                 }
142                         }
143                         if (updated) {
144                                 cksum  = &icmph->checksum;
145                                 /* Using tcpudp primitive. Why not? */
146                                 check  = csum_tcpudp_magic(ciph->saddr, ciph->daddr, 0, 0, ~(*cksum));
147                                 *cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0, ~check);
148                         }
149                         break;
150                 }
151                 default:
152                         break;
153                 }
154         }
155         return NET_RX_SUCCESS;
156 
157 truncated:
158         /* should be return NET_RX_BAD; */
159         return -EINVAL;
160 }
161 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.