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

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

Version: ~ [ linux-5.13-rc7 ] ~ [ linux-5.12.12 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.45 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.127 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.195 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.237 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.273 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.273 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
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.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 
 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 = *cksum;
 74                         if (skb->ip_summed != CHECKSUM_HW)
 75                                 check = ~check;
 76                         check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check);
 77                         check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
 78                         if (skb->ip_summed == CHECKSUM_HW)
 79                                 check = ~check;
 80                         *cksum = check;
 81                         break;
 82                 case IPPROTO_UDP:
 83                         cksum  = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
 84                         if ((u8*)(cksum+1) > skb->tail)
 85                                 goto truncated;
 86                         if ((check = *cksum) != 0) {
 87                                 check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
 88                                 check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
 89                                 *cksum = check ? : 0xFFFF;
 90                         }
 91                         break;
 92                 case IPPROTO_ICMP:
 93                 {
 94                         struct icmphdr *icmph = (struct icmphdr*)((char*)iph + (iph->ihl<<2));
 95                         struct   iphdr *ciph;
 96                         u32 idaddr, isaddr;
 97                         int updated;
 98 
 99                         if ((icmph->type != ICMP_DEST_UNREACH) &&
100                             (icmph->type != ICMP_TIME_EXCEEDED) &&
101                             (icmph->type != ICMP_PARAMETERPROB))
102                                 break;
103 
104                         ciph = (struct iphdr *) (icmph + 1);
105 
106                         if ((u8*)(ciph+1) > skb->tail)
107                                 goto truncated;
108 
109                         isaddr = ciph->saddr;
110                         idaddr = ciph->daddr;
111                         updated = 0;
112 
113                         if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr) {
114                                 ciph->saddr = iph->daddr;
115                                 updated = 1;
116                         }
117                         if (rt->rt_flags&RTCF_SNAT) {
118                                 if (ciph->daddr != osaddr) {
119                                         struct   fib_result res;
120                                         unsigned flags = 0;
121                                         struct flowi fl = {
122                                                 .iif = skb->dev->ifindex,
123                                                 .nl_u =
124                                                 { .ip4_u =
125                                                   { .daddr = ciph->saddr,
126                                                     .saddr = ciph->daddr,
127 #ifdef CONFIG_IP_ROUTE_TOS
128                                                     .tos = RT_TOS(ciph->tos)
129 #endif
130                                                   } },
131                                                 .proto = ciph->protocol };
132 
133                                         /* Use fib_lookup() until we get our own
134                                          * hash table of NATed hosts -- Rani
135                                          */
136                                         if (fib_lookup(&fl, &res) == 0) {
137                                                 if (res.r) {
138                                                         ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
139                                                         if (ciph->daddr != idaddr)
140                                                                 updated = 1;
141                                                 }
142                                                 fib_res_put(&res);
143                                         }
144                                 } else {
145                                         ciph->daddr = iph->saddr;
146                                         updated = 1;
147                                 }
148                         }
149                         if (updated) {
150                                 cksum  = &icmph->checksum;
151                                 /* Using tcpudp primitive. Why not? */
152                                 check  = csum_tcpudp_magic(ciph->saddr, ciph->daddr, 0, 0, ~(*cksum));
153                                 *cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0, ~check);
154                         }
155                         break;
156                 }
157                 default:
158                         break;
159                 }
160         }
161         return NET_RX_SUCCESS;
162 
163 truncated:
164         /* should be return NET_RX_BAD; */
165         return -EINVAL;
166 }
167 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp