OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv4/] [ip_nat_dumb.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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.1.1.1 2004-04-15 01:13:46 phoenix 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
                                        struct   rt_key key;
121
                                        unsigned flags = 0;
122
 
123
                                        key.src = ciph->daddr;
124
                                        key.dst = ciph->saddr;
125
                                        key.iif = skb->dev->ifindex;
126
                                        key.oif = 0;
127
#ifdef CONFIG_IP_ROUTE_TOS
128
                                        key.tos = RT_TOS(ciph->tos);
129
#endif
130
#ifdef CONFIG_IP_ROUTE_FWMARK
131
                                        key.fwmark = 0;
132
#endif
133
                                        /* Use fib_lookup() until we get our own
134
                                         * hash table of NATed hosts -- Rani
135
                                         */
136
                                        if (fib_lookup(&key, &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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.