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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* FTP extension for TCP NAT alteration. */
2
#include <linux/module.h>
3
#include <linux/netfilter_ipv4.h>
4
#include <linux/ip.h>
5
#include <linux/tcp.h>
6
#include <net/tcp.h>
7
#include <linux/netfilter_ipv4/ip_nat.h>
8
#include <linux/netfilter_ipv4/ip_nat_helper.h>
9
#include <linux/netfilter_ipv4/ip_nat_rule.h>
10
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
11
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
12
 
13
#if 0
14
#define DEBUGP printk
15
#else
16
#define DEBUGP(format, args...)
17
#endif
18
 
19
#define MAX_PORTS 8
20
static int ports[MAX_PORTS];
21
static int ports_c = 0;
22
 
23
#ifdef MODULE_PARM
24
MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
25
#endif
26
 
27
DECLARE_LOCK_EXTERN(ip_ftp_lock);
28
 
29
/* FIXME: Time out? --RR */
30
 
31
static unsigned int
32
ftp_nat_expected(struct sk_buff **pskb,
33
                 unsigned int hooknum,
34
                 struct ip_conntrack *ct,
35
                 struct ip_nat_info *info)
36
{
37
        struct ip_nat_multi_range mr;
38
        u_int32_t newdstip, newsrcip, newip;
39
        struct ip_ct_ftp_expect *exp_ftp_info;
40
 
41
        struct ip_conntrack *master = master_ct(ct);
42
 
43
        IP_NF_ASSERT(info);
44
        IP_NF_ASSERT(master);
45
 
46
        IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
47
 
48
        DEBUGP("nat_expected: We have a connection!\n");
49
        exp_ftp_info = &ct->master->help.exp_ftp_info;
50
 
51
        LOCK_BH(&ip_ftp_lock);
52
 
53
        if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
54
            || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {
55
                /* PORT command: make connection go to the client. */
56
                newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
57
                newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
58
                DEBUGP("nat_expected: PORT cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
59
                       NIPQUAD(newsrcip), NIPQUAD(newdstip));
60
        } else {
61
                /* PASV command: make the connection go to the server */
62
                newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
63
                newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
64
                DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
65
                       NIPQUAD(newsrcip), NIPQUAD(newdstip));
66
        }
67
        UNLOCK_BH(&ip_ftp_lock);
68
 
69
        if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
70
                newip = newsrcip;
71
        else
72
                newip = newdstip;
73
 
74
        DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
75
 
76
        mr.rangesize = 1;
77
        /* We don't want to manip the per-protocol, just the IPs... */
78
        mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
79
        mr.range[0].min_ip = mr.range[0].max_ip = newip;
80
 
81
        /* ... unless we're doing a MANIP_DST, in which case, make
82
           sure we map to the correct port */
83
        if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
84
                mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
85
                mr.range[0].min = mr.range[0].max
86
                        = ((union ip_conntrack_manip_proto)
87
                                { .tcp = { htons(exp_ftp_info->port) } });
88
        }
89
        return ip_nat_setup_info(ct, &mr, hooknum);
90
}
91
 
92
static int
93
mangle_rfc959_packet(struct sk_buff **pskb,
94
                     u_int32_t newip,
95
                     u_int16_t port,
96
                     unsigned int matchoff,
97
                     unsigned int matchlen,
98
                     struct ip_conntrack *ct,
99
                     enum ip_conntrack_info ctinfo)
100
{
101
        char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
102
 
103
        MUST_BE_LOCKED(&ip_ftp_lock);
104
 
105
        sprintf(buffer, "%u,%u,%u,%u,%u,%u",
106
                NIPQUAD(newip), port>>8, port&0xFF);
107
 
108
        DEBUGP("calling ip_nat_mangle_tcp_packet\n");
109
 
110
        return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
111
                                        matchlen, buffer, strlen(buffer));
112
}
113
 
114
/* |1|132.235.1.2|6275| */
115
static int
116
mangle_eprt_packet(struct sk_buff **pskb,
117
                   u_int32_t newip,
118
                   u_int16_t port,
119
                   unsigned int matchoff,
120
                   unsigned int matchlen,
121
                   struct ip_conntrack *ct,
122
                   enum ip_conntrack_info ctinfo)
123
{
124
        char buffer[sizeof("|1|255.255.255.255|65535|")];
125
 
126
        MUST_BE_LOCKED(&ip_ftp_lock);
127
 
128
        sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
129
 
130
        DEBUGP("calling ip_nat_mangle_tcp_packet\n");
131
 
132
        return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
133
                                        matchlen, buffer, strlen(buffer));
134
}
135
 
136
/* |1|132.235.1.2|6275| */
137
static int
138
mangle_epsv_packet(struct sk_buff **pskb,
139
                   u_int32_t newip,
140
                   u_int16_t port,
141
                   unsigned int matchoff,
142
                   unsigned int matchlen,
143
                   struct ip_conntrack *ct,
144
                   enum ip_conntrack_info ctinfo)
145
{
146
        char buffer[sizeof("|||65535|")];
147
 
148
        MUST_BE_LOCKED(&ip_ftp_lock);
149
 
150
        sprintf(buffer, "|||%u|", port);
151
 
152
        DEBUGP("calling ip_nat_mangle_tcp_packet\n");
153
 
154
        return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
155
                                        matchlen, buffer, strlen(buffer));
156
}
157
 
158
static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
159
                     unsigned int,
160
                     unsigned int,
161
                     struct ip_conntrack *,
162
                     enum ip_conntrack_info)
163
= { [IP_CT_FTP_PORT] mangle_rfc959_packet,
164
    [IP_CT_FTP_PASV] mangle_rfc959_packet,
165
    [IP_CT_FTP_EPRT] mangle_eprt_packet,
166
    [IP_CT_FTP_EPSV] mangle_epsv_packet
167
};
168
 
169
static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
170
                          struct ip_conntrack *ct,
171
                          struct sk_buff **pskb,
172
                          enum ip_conntrack_info ctinfo,
173
                          struct ip_conntrack_expect *expect)
174
{
175
        u_int32_t newip;
176
        struct iphdr *iph = (*pskb)->nh.iph;
177
        struct tcphdr *tcph = (void *)iph + iph->ihl*4;
178
        u_int16_t port;
179
        struct ip_conntrack_tuple newtuple;
180
 
181
        MUST_BE_LOCKED(&ip_ftp_lock);
182
        DEBUGP("FTP_NAT: seq %u + %u in %u\n",
183
               expect->seq, ct_ftp_info->len,
184
               ntohl(tcph->seq));
185
 
186
        /* Change address inside packet to match way we're mapping
187
           this connection. */
188
        if (ct_ftp_info->ftptype == IP_CT_FTP_PASV
189
            || ct_ftp_info->ftptype == IP_CT_FTP_EPSV) {
190
                /* PASV/EPSV response: must be where client thinks server
191
                   is */
192
                newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
193
                /* Expect something from client->server */
194
                newtuple.src.ip =
195
                        ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
196
                newtuple.dst.ip =
197
                        ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
198
        } else {
199
                /* PORT command: must be where server thinks client is */
200
                newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
201
                /* Expect something from server->client */
202
                newtuple.src.ip =
203
                        ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
204
                newtuple.dst.ip =
205
                        ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
206
        }
207
        newtuple.dst.protonum = IPPROTO_TCP;
208
        newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
209
 
210
        /* Try to get same port: if not, try to change it. */
211
        for (port = ct_ftp_info->port; port != 0; port++) {
212
                newtuple.dst.u.tcp.port = htons(port);
213
 
214
                if (ip_conntrack_change_expect(expect, &newtuple) == 0)
215
                        break;
216
        }
217
        if (port == 0)
218
                return 0;
219
 
220
        if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
221
                                          expect->seq - ntohl(tcph->seq),
222
                                          ct_ftp_info->len, ct, ctinfo))
223
                return 0;
224
 
225
        return 1;
226
}
227
 
228
static unsigned int help(struct ip_conntrack *ct,
229
                         struct ip_conntrack_expect *exp,
230
                         struct ip_nat_info *info,
231
                         enum ip_conntrack_info ctinfo,
232
                         unsigned int hooknum,
233
                         struct sk_buff **pskb)
234
{
235
        struct iphdr *iph = (*pskb)->nh.iph;
236
        struct tcphdr *tcph = (void *)iph + iph->ihl*4;
237
        unsigned int datalen;
238
        int dir;
239
        struct ip_ct_ftp_expect *ct_ftp_info;
240
 
241
        if (!exp)
242
                DEBUGP("ip_nat_ftp: no exp!!");
243
 
244
        ct_ftp_info = &exp->help.exp_ftp_info;
245
 
246
        /* Only mangle things once: original direction in POST_ROUTING
247
           and reply direction on PRE_ROUTING. */
248
        dir = CTINFO2DIR(ctinfo);
249
        if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
250
              || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
251
                DEBUGP("nat_ftp: Not touching dir %s at hook %s\n",
252
                       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
253
                       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
254
                       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
255
                       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
256
                return NF_ACCEPT;
257
        }
258
 
259
        datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
260
        LOCK_BH(&ip_ftp_lock);
261
        /* If it's in the right range... */
262
        if (between(exp->seq + ct_ftp_info->len,
263
                    ntohl(tcph->seq),
264
                    ntohl(tcph->seq) + datalen)) {
265
                if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
266
                        UNLOCK_BH(&ip_ftp_lock);
267
                        return NF_DROP;
268
                }
269
        } else {
270
                /* Half a match?  This means a partial retransmisison.
271
                   It's a cracker being funky. */
272
                if (net_ratelimit()) {
273
                        printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
274
                               exp->seq, ct_ftp_info->len,
275
                               ntohl(tcph->seq),
276
                               ntohl(tcph->seq) + datalen);
277
                }
278
                UNLOCK_BH(&ip_ftp_lock);
279
                return NF_DROP;
280
        }
281
        UNLOCK_BH(&ip_ftp_lock);
282
 
283
        return NF_ACCEPT;
284
}
285
 
286
static struct ip_nat_helper ftp[MAX_PORTS];
287
static char ftp_names[MAX_PORTS][10];
288
 
289
/* Not __exit: called from init() */
290
static void fini(void)
291
{
292
        int i;
293
 
294
        for (i = 0; i < ports_c; i++) {
295
                DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
296
                ip_nat_helper_unregister(&ftp[i]);
297
        }
298
}
299
 
300
static int __init init(void)
301
{
302
        int i, ret = 0;
303
        char *tmpname;
304
 
305
        if (ports[0] == 0)
306
                ports[0] = FTP_PORT;
307
 
308
        for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
309
                ftp[i].tuple.dst.protonum = IPPROTO_TCP;
310
                ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
311
                ftp[i].mask.dst.protonum = 0xFFFF;
312
                ftp[i].mask.src.u.tcp.port = 0xFFFF;
313
                ftp[i].help = help;
314
                ftp[i].me = THIS_MODULE;
315
                ftp[i].flags = 0;
316
                ftp[i].expect = ftp_nat_expected;
317
 
318
                tmpname = &ftp_names[i][0];
319
                if (ports[i] == FTP_PORT)
320
                        sprintf(tmpname, "ftp");
321
                else
322
                        sprintf(tmpname, "ftp-%d", i);
323
                ftp[i].name = tmpname;
324
 
325
                DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
326
                                ports[i]);
327
                ret = ip_nat_helper_register(&ftp[i]);
328
 
329
                if (ret) {
330
                        printk("ip_nat_ftp: error registering "
331
                               "helper for port %d\n", ports[i]);
332
                        fini();
333
                        return ret;
334
                }
335
                ports_c++;
336
        }
337
 
338
        return ret;
339
}
340
 
341
module_init(init);
342
module_exit(fini);
343
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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