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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [tags/] [linux-2.6/] [linux-2.6.24_or32_unified_v2.3/] [net/] [ipv4/] [netfilter/] [nf_nat_standalone.c] - Blame information for rev 8

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/* (C) 1999-2001 Paul `Rusty' Russell
2
 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License version 2 as
6
 * published by the Free Software Foundation.
7
 */
8
#include <linux/types.h>
9
#include <linux/icmp.h>
10
#include <linux/ip.h>
11
#include <linux/netfilter.h>
12
#include <linux/netfilter_ipv4.h>
13
#include <linux/module.h>
14
#include <linux/skbuff.h>
15
#include <linux/proc_fs.h>
16
#include <net/ip.h>
17
#include <net/checksum.h>
18
#include <linux/spinlock.h>
19
 
20
#include <net/netfilter/nf_conntrack.h>
21
#include <net/netfilter/nf_conntrack_core.h>
22
#include <net/netfilter/nf_conntrack_extend.h>
23
#include <net/netfilter/nf_nat.h>
24
#include <net/netfilter/nf_nat_rule.h>
25
#include <net/netfilter/nf_nat_protocol.h>
26
#include <net/netfilter/nf_nat_core.h>
27
#include <net/netfilter/nf_nat_helper.h>
28
#include <linux/netfilter_ipv4/ip_tables.h>
29
 
30
#ifdef CONFIG_XFRM
31
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
32
{
33
        struct nf_conn *ct;
34
        struct nf_conntrack_tuple *t;
35
        enum ip_conntrack_info ctinfo;
36
        enum ip_conntrack_dir dir;
37
        unsigned long statusbit;
38
 
39
        ct = nf_ct_get(skb, &ctinfo);
40
        if (ct == NULL)
41
                return;
42
        dir = CTINFO2DIR(ctinfo);
43
        t = &ct->tuplehash[dir].tuple;
44
 
45
        if (dir == IP_CT_DIR_ORIGINAL)
46
                statusbit = IPS_DST_NAT;
47
        else
48
                statusbit = IPS_SRC_NAT;
49
 
50
        if (ct->status & statusbit) {
51
                fl->fl4_dst = t->dst.u3.ip;
52
                if (t->dst.protonum == IPPROTO_TCP ||
53
                    t->dst.protonum == IPPROTO_UDP)
54
                        fl->fl_ip_dport = t->dst.u.tcp.port;
55
        }
56
 
57
        statusbit ^= IPS_NAT_MASK;
58
 
59
        if (ct->status & statusbit) {
60
                fl->fl4_src = t->src.u3.ip;
61
                if (t->dst.protonum == IPPROTO_TCP ||
62
                    t->dst.protonum == IPPROTO_UDP)
63
                        fl->fl_ip_sport = t->src.u.tcp.port;
64
        }
65
}
66
#endif
67
 
68
static unsigned int
69
nf_nat_fn(unsigned int hooknum,
70
          struct sk_buff *skb,
71
          const struct net_device *in,
72
          const struct net_device *out,
73
          int (*okfn)(struct sk_buff *))
74
{
75
        struct nf_conn *ct;
76
        enum ip_conntrack_info ctinfo;
77
        struct nf_conn_nat *nat;
78
        /* maniptype == SRC for postrouting. */
79
        enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
80
 
81
        /* We never see fragments: conntrack defrags on pre-routing
82
           and local-out, and nf_nat_out protects post-routing. */
83
        NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
84
 
85
        ct = nf_ct_get(skb, &ctinfo);
86
        /* Can't track?  It's not due to stress, or conntrack would
87
           have dropped it.  Hence it's the user's responsibilty to
88
           packet filter it out, or implement conntrack/NAT for that
89
           protocol. 8) --RR */
90
        if (!ct) {
91
                /* Exception: ICMP redirect to new connection (not in
92
                   hash table yet).  We must not let this through, in
93
                   case we're doing NAT to the same network. */
94
                if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
95
                        struct icmphdr _hdr, *hp;
96
 
97
                        hp = skb_header_pointer(skb, ip_hdrlen(skb),
98
                                                sizeof(_hdr), &_hdr);
99
                        if (hp != NULL &&
100
                            hp->type == ICMP_REDIRECT)
101
                                return NF_DROP;
102
                }
103
                return NF_ACCEPT;
104
        }
105
 
106
        /* Don't try to NAT if this packet is not conntracked */
107
        if (ct == &nf_conntrack_untracked)
108
                return NF_ACCEPT;
109
 
110
        nat = nfct_nat(ct);
111
        if (!nat) {
112
                nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
113
                if (nat == NULL) {
114
                        pr_debug("failed to add NAT extension\n");
115
                        return NF_ACCEPT;
116
                }
117
        }
118
 
119
        switch (ctinfo) {
120
        case IP_CT_RELATED:
121
        case IP_CT_RELATED+IP_CT_IS_REPLY:
122
                if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
123
                        if (!nf_nat_icmp_reply_translation(ct, ctinfo,
124
                                                           hooknum, skb))
125
                                return NF_DROP;
126
                        else
127
                                return NF_ACCEPT;
128
                }
129
                /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
130
        case IP_CT_NEW:
131
 
132
                /* Seen it before?  This can happen for loopback, retrans,
133
                   or local packets.. */
134
                if (!nf_nat_initialized(ct, maniptype)) {
135
                        unsigned int ret;
136
 
137
                        if (unlikely(nf_ct_is_confirmed(ct)))
138
                                /* NAT module was loaded late */
139
                                ret = alloc_null_binding_confirmed(ct, hooknum);
140
                        else if (hooknum == NF_IP_LOCAL_IN)
141
                                /* LOCAL_IN hook doesn't have a chain!  */
142
                                ret = alloc_null_binding(ct, hooknum);
143
                        else
144
                                ret = nf_nat_rule_find(skb, hooknum, in, out,
145
                                                       ct);
146
 
147
                        if (ret != NF_ACCEPT) {
148
                                return ret;
149
                        }
150
                } else
151
                        pr_debug("Already setup manip %s for ct %p\n",
152
                                 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
153
                                 ct);
154
                break;
155
 
156
        default:
157
                /* ESTABLISHED */
158
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
159
                             ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
160
        }
161
 
162
        return nf_nat_packet(ct, ctinfo, hooknum, skb);
163
}
164
 
165
static unsigned int
166
nf_nat_in(unsigned int hooknum,
167
          struct sk_buff *skb,
168
          const struct net_device *in,
169
          const struct net_device *out,
170
          int (*okfn)(struct sk_buff *))
171
{
172
        unsigned int ret;
173
        __be32 daddr = ip_hdr(skb)->daddr;
174
 
175
        ret = nf_nat_fn(hooknum, skb, in, out, okfn);
176
        if (ret != NF_DROP && ret != NF_STOLEN &&
177
            daddr != ip_hdr(skb)->daddr) {
178
                dst_release(skb->dst);
179
                skb->dst = NULL;
180
        }
181
        return ret;
182
}
183
 
184
static unsigned int
185
nf_nat_out(unsigned int hooknum,
186
           struct sk_buff *skb,
187
           const struct net_device *in,
188
           const struct net_device *out,
189
           int (*okfn)(struct sk_buff *))
190
{
191
#ifdef CONFIG_XFRM
192
        struct nf_conn *ct;
193
        enum ip_conntrack_info ctinfo;
194
#endif
195
        unsigned int ret;
196
 
197
        /* root is playing with raw sockets. */
198
        if (skb->len < sizeof(struct iphdr) ||
199
            ip_hdrlen(skb) < sizeof(struct iphdr))
200
                return NF_ACCEPT;
201
 
202
        ret = nf_nat_fn(hooknum, skb, in, out, okfn);
203
#ifdef CONFIG_XFRM
204
        if (ret != NF_DROP && ret != NF_STOLEN &&
205
            (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
206
                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
207
 
208
                if (ct->tuplehash[dir].tuple.src.u3.ip !=
209
                    ct->tuplehash[!dir].tuple.dst.u3.ip
210
                    || ct->tuplehash[dir].tuple.src.u.all !=
211
                       ct->tuplehash[!dir].tuple.dst.u.all
212
                    )
213
                        return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP;
214
        }
215
#endif
216
        return ret;
217
}
218
 
219
static unsigned int
220
nf_nat_local_fn(unsigned int hooknum,
221
                struct sk_buff *skb,
222
                const struct net_device *in,
223
                const struct net_device *out,
224
                int (*okfn)(struct sk_buff *))
225
{
226
        struct nf_conn *ct;
227
        enum ip_conntrack_info ctinfo;
228
        unsigned int ret;
229
 
230
        /* root is playing with raw sockets. */
231
        if (skb->len < sizeof(struct iphdr) ||
232
            ip_hdrlen(skb) < sizeof(struct iphdr))
233
                return NF_ACCEPT;
234
 
235
        ret = nf_nat_fn(hooknum, skb, in, out, okfn);
236
        if (ret != NF_DROP && ret != NF_STOLEN &&
237
            (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
238
                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
239
 
240
                if (ct->tuplehash[dir].tuple.dst.u3.ip !=
241
                    ct->tuplehash[!dir].tuple.src.u3.ip) {
242
                        if (ip_route_me_harder(skb, RTN_UNSPEC))
243
                                ret = NF_DROP;
244
                }
245
#ifdef CONFIG_XFRM
246
                else if (ct->tuplehash[dir].tuple.dst.u.all !=
247
                         ct->tuplehash[!dir].tuple.src.u.all)
248
                        if (ip_xfrm_me_harder(skb))
249
                                ret = NF_DROP;
250
#endif
251
        }
252
        return ret;
253
}
254
 
255
static unsigned int
256
nf_nat_adjust(unsigned int hooknum,
257
              struct sk_buff *skb,
258
              const struct net_device *in,
259
              const struct net_device *out,
260
              int (*okfn)(struct sk_buff *))
261
{
262
        struct nf_conn *ct;
263
        enum ip_conntrack_info ctinfo;
264
 
265
        ct = nf_ct_get(skb, &ctinfo);
266
        if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
267
                pr_debug("nf_nat_standalone: adjusting sequence number\n");
268
                if (!nf_nat_seq_adjust(skb, ct, ctinfo))
269
                        return NF_DROP;
270
        }
271
        return NF_ACCEPT;
272
}
273
 
274
/* We must be after connection tracking and before packet filtering. */
275
 
276
static struct nf_hook_ops nf_nat_ops[] = {
277
        /* Before packet filtering, change destination */
278
        {
279
                .hook           = nf_nat_in,
280
                .owner          = THIS_MODULE,
281
                .pf             = PF_INET,
282
                .hooknum        = NF_IP_PRE_ROUTING,
283
                .priority       = NF_IP_PRI_NAT_DST,
284
        },
285
        /* After packet filtering, change source */
286
        {
287
                .hook           = nf_nat_out,
288
                .owner          = THIS_MODULE,
289
                .pf             = PF_INET,
290
                .hooknum        = NF_IP_POST_ROUTING,
291
                .priority       = NF_IP_PRI_NAT_SRC,
292
        },
293
        /* After conntrack, adjust sequence number */
294
        {
295
                .hook           = nf_nat_adjust,
296
                .owner          = THIS_MODULE,
297
                .pf             = PF_INET,
298
                .hooknum        = NF_IP_POST_ROUTING,
299
                .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
300
        },
301
        /* Before packet filtering, change destination */
302
        {
303
                .hook           = nf_nat_local_fn,
304
                .owner          = THIS_MODULE,
305
                .pf             = PF_INET,
306
                .hooknum        = NF_IP_LOCAL_OUT,
307
                .priority       = NF_IP_PRI_NAT_DST,
308
        },
309
        /* After packet filtering, change source */
310
        {
311
                .hook           = nf_nat_fn,
312
                .owner          = THIS_MODULE,
313
                .pf             = PF_INET,
314
                .hooknum        = NF_IP_LOCAL_IN,
315
                .priority       = NF_IP_PRI_NAT_SRC,
316
        },
317
        /* After conntrack, adjust sequence number */
318
        {
319
                .hook           = nf_nat_adjust,
320
                .owner          = THIS_MODULE,
321
                .pf             = PF_INET,
322
                .hooknum        = NF_IP_LOCAL_IN,
323
                .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
324
        },
325
};
326
 
327
static int __init nf_nat_standalone_init(void)
328
{
329
        int ret = 0;
330
 
331
        need_ipv4_conntrack();
332
 
333
#ifdef CONFIG_XFRM
334
        BUG_ON(ip_nat_decode_session != NULL);
335
        ip_nat_decode_session = nat_decode_session;
336
#endif
337
        ret = nf_nat_rule_init();
338
        if (ret < 0) {
339
                printk("nf_nat_init: can't setup rules.\n");
340
                goto cleanup_decode_session;
341
        }
342
        ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
343
        if (ret < 0) {
344
                printk("nf_nat_init: can't register hooks.\n");
345
                goto cleanup_rule_init;
346
        }
347
        return ret;
348
 
349
 cleanup_rule_init:
350
        nf_nat_rule_cleanup();
351
 cleanup_decode_session:
352
#ifdef CONFIG_XFRM
353
        ip_nat_decode_session = NULL;
354
        synchronize_net();
355
#endif
356
        return ret;
357
}
358
 
359
static void __exit nf_nat_standalone_fini(void)
360
{
361
        nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
362
        nf_nat_rule_cleanup();
363
#ifdef CONFIG_XFRM
364
        ip_nat_decode_session = NULL;
365
        synchronize_net();
366
#endif
367
        /* Conntrack caches are unregistered in nf_conntrack_cleanup */
368
}
369
 
370
module_init(nf_nat_standalone_init);
371
module_exit(nf_nat_standalone_fini);
372
 
373
MODULE_LICENSE("GPL");
374
MODULE_ALIAS("ip_nat");

powered by: WebSVN 2.1.0

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