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

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [net/] [ipv4/] [ip_masq_ftp.c] - Blame information for rev 901

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *              IP_MASQ_FTP ftp masquerading module
3
 *
4
 *
5
 * Version:     @(#)ip_masq_ftp.c 0.01   02/05/96
6
 *
7
 * Author:      Wouter Gadeyne
8
 *
9
 *
10
 * Fixes:
11
 *      Wouter Gadeyne          :       Fixed masquerading support of ftp PORT commands
12
 *      Juan Jose Ciarlante     :       Code moved and adapted from ip_fw.c
13
 *      Keith Owens             :       Add keep alive for ftp control channel
14
 *      Nigel Metheringham      :       Added multiple port support
15
 *
16
 *
17
 *
18
 *      This program is free software; you can redistribute it and/or
19
 *      modify it under the terms of the GNU General Public License
20
 *      as published by the Free Software Foundation; either version
21
 *      2 of the License, or (at your option) any later version.
22
 *
23
 * Multiple Port Support
24
 *      The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
25
 *      with the port numbers being defined at module load time.  The module
26
 *      uses the symbol "ports" to define a list of monitored ports, which can
27
 *      be specified on the insmod command line as
28
 *              ports=x1,x2,x3...
29
 *      where x[n] are integer port numbers.  This option can be put into
30
 *      /etc/conf.modules (or /etc/modules.conf depending on your config)
31
 *      where modload will pick it up should you use modload to load your
32
 *      modules.
33
 *
34
 */
35
 
36
#include <linux/module.h>
37
#include <asm/system.h>
38
#include <linux/types.h>
39
#include <linux/kernel.h>
40
#include <linux/skbuff.h>
41
#include <linux/in.h>
42
#include <linux/ip.h>
43
#include <net/protocol.h>
44
#include <net/tcp.h>
45
#include <net/ip_masq.h>
46
 
47
#ifndef DEBUG_CONFIG_IP_MASQ_FTP
48
#define DEBUG_CONFIG_IP_MASQ_FTP 0
49
#endif
50
 
51
#ifdef MODULE
52
#define STATIC
53
#else
54
#define STATIC  static
55
#endif
56
 
57
/*
58
 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
59
 * First port is set to the default port.
60
 */
61
STATIC int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */
62
struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
63
 
64
static int
65
masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
66
{
67
        MOD_INC_USE_COUNT;
68
        return 0;
69
}
70
 
71
static int
72
masq_ftp_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
73
{
74
        MOD_DEC_USE_COUNT;
75
        return 0;
76
}
77
 
78
int
79
masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
80
{
81
        struct sk_buff *skb;
82
        struct iphdr *iph;
83
        struct tcphdr *th;
84
        char *p, *data, *data_limit;
85
        unsigned char p1,p2,p3,p4,p5,p6;
86
        __u32 from;
87
        __u16 port;
88
        struct ip_masq *n_ms;
89
        char buf[24];           /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
90
        unsigned buf_len;
91
        int diff;
92
 
93
        skb = *skb_p;
94
        iph = skb->h.iph;
95
        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
96
        data = (char *)&th[1];
97
        data_limit = skb->h.raw + skb->len - 18;
98
        if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0))
99
                ms->flags |= IP_MASQ_F_FTP_PASV;
100
 
101
        while (data < data_limit)
102
        {
103
                if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5))
104
                {
105
                        data ++;
106
                        continue;
107
                }
108
                p = data+5;
109
                p1 = simple_strtoul(data+5,&data,10);
110
                if (*data!=',')
111
                        continue;
112
                p2 = simple_strtoul(data+1,&data,10);
113
                if (*data!=',')
114
                        continue;
115
                p3 = simple_strtoul(data+1,&data,10);
116
                if (*data!=',')
117
                        continue;
118
                p4 = simple_strtoul(data+1,&data,10);
119
                if (*data!=',')
120
                        continue;
121
                p5 = simple_strtoul(data+1,&data,10);
122
                if (*data!=',')
123
                        continue;
124
                p6 = simple_strtoul(data+1,&data,10);
125
                if (*data!='\r' && *data!='\n')
126
                        continue;
127
 
128
                from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
129
                port = (p5<<8) | p6;
130
#if DEBUG_CONFIG_IP_MASQ_FTP
131
                printk("PORT %X:%X detected\n",from,port);
132
#endif  
133
                /*
134
                 * Now update or create an masquerade entry for it
135
                 */
136
#if DEBUG_CONFIG_IP_MASQ_FTP
137
                printk("protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
138
 
139
#endif  
140
                n_ms = ip_masq_out_get_2(iph->protocol,
141
                                         htonl(from), htons(port),
142
                                         iph->daddr, 0);
143
                if (n_ms) {
144
                        /* existing masquerade, clear timer */
145
                        ip_masq_set_expire(n_ms,0);
146
                }
147
                else {
148
                        n_ms = ip_masq_new(dev, IPPROTO_TCP,
149
                                           htonl(from), htons(port),
150
                                           iph->daddr, 0,
151
                                           IP_MASQ_F_NO_DPORT);
152
 
153
                        if (n_ms==NULL)
154
                                return 0;
155
                        n_ms->control = ms;             /* keepalive from data to the control channel */
156
                        ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */
157
                }
158
 
159
                /*
160
                 * keep for a bit longer than tcp_fin, caller may not reissue
161
                 * PORT before tcp_fin_timeout.
162
                 */
163
                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3);
164
 
165
                /*
166
                 * Replace the old PORT with the new one
167
                 */
168
                from = ntohl(n_ms->maddr);
169
                port = ntohs(n_ms->mport);
170
                sprintf(buf,"%d,%d,%d,%d,%d,%d",
171
                        from>>24&255,from>>16&255,from>>8&255,from&255,
172
                        port>>8&255,port&255);
173
                buf_len = strlen(buf);
174
#if DEBUG_CONFIG_IP_MASQ_FTP
175
                printk("new PORT %X:%X\n",from,port);
176
#endif  
177
 
178
                /*
179
                 * Calculate required delta-offset to keep TCP happy
180
                 */
181
 
182
                diff = buf_len - (data-p);
183
 
184
                /*
185
                 *      No shift.
186
                 */
187
 
188
                if (diff==0)
189
                {
190
                        /*
191
                         * simple case, just replace the old PORT cmd
192
                         */
193
                        memcpy(p,buf,buf_len);
194
                        return 0;
195
                }
196
 
197
                *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
198
                return diff;
199
 
200
        }
201
        return 0;
202
 
203
}
204
 
205
/*
206
 * Look at incoming ftp packets to catch the response to a PASV command.  When
207
 * we see one we build a masquerading entry for the client address, client port
208
 * 0 (unknown at the moment), the server address and the server port.  Mark the
209
 * current masquerade entry as a control channel and point the new entry at the
210
 * control entry.  All this work just for ftp keepalive across masquerading.
211
 *
212
 * The incoming packet should be something like
213
 * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
214
 * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
215
 * ncftp 2.3.0 cheats by skipping the leading number then going 22 bytes into
216
 * the data so we do the same.  If it's good enough for ncftp then it's good
217
 * enough for me.
218
 *
219
 * In this case, the client is the source machine being masqueraded, the server
220
 * is the destination for ftp requests.  It all depends on your point of view ...
221
 */
222
 
223
int
224
masq_ftp_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
225
{
226
        struct sk_buff *skb;
227
        struct iphdr *iph;
228
        struct tcphdr *th;
229
        char *data, *data_limit;
230
        unsigned char p1,p2,p3,p4,p5,p6;
231
        __u32 to;
232
        __u16 port;
233
        struct ip_masq *n_ms;
234
 
235
        if (! ms->flags & IP_MASQ_F_FTP_PASV)
236
                return 0;        /* quick exit if no outstanding PASV */
237
 
238
        skb = *skb_p;
239
        iph = skb->h.iph;
240
        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
241
        data = (char *)&th[1];
242
        data_limit = skb->h.raw + skb->len;
243
 
244
        while (data < data_limit && *data != ' ')
245
                ++data;
246
        while (data < data_limit && *data == ' ')
247
                ++data;
248
        data += 22;
249
        if (data >= data_limit || *data != '(')
250
                return 0;
251
        p1 = simple_strtoul(data+1, &data, 10);
252
        if (data >= data_limit || *data != ',')
253
                return 0;
254
        p2 = simple_strtoul(data+1, &data, 10);
255
        if (data >= data_limit || *data != ',')
256
                return 0;
257
        p3 = simple_strtoul(data+1, &data, 10);
258
        if (data >= data_limit || *data != ',')
259
                return 0;
260
        p4 = simple_strtoul(data+1, &data, 10);
261
        if (data >= data_limit || *data != ',')
262
                return 0;
263
        p5 = simple_strtoul(data+1, &data, 10);
264
        if (data >= data_limit || *data != ',')
265
                return 0;
266
        p6 = simple_strtoul(data+1, &data, 10);
267
        if (data >= data_limit || *data != ')')
268
                return 0;
269
 
270
        to = (p1<<24) | (p2<<16) | (p3<<8) | p4;
271
        port = (p5<<8) | p6;
272
 
273
        /*
274
         * Now update or create an masquerade entry for it
275
         */
276
#if DEBUG_CONFIG_IP_MASQ_FTP
277
        printk("PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port);
278
#endif  
279
        n_ms = ip_masq_out_get_2(iph->protocol,
280
                                 ms->saddr, 0,
281
                                 htonl(to), htons(port));
282
        if (n_ms) {
283
                /* existing masquerade, clear timer */
284
                ip_masq_set_expire(n_ms,0);
285
        }
286
        else {
287
                n_ms = ip_masq_new(dev, IPPROTO_TCP,
288
                                   ms->saddr, 0,
289
                                   htonl(to), htons(port),
290
                                   IP_MASQ_F_NO_SPORT);
291
 
292
                if (n_ms==NULL)
293
                        return 0;
294
                n_ms->control = ms;             /* keepalive from data to the control channel */
295
                ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */
296
        }
297
 
298
        /*
299
         * keep for a bit longer than tcp_fin, client may not issue open
300
         * to server port before tcp_fin_timeout.
301
         */
302
        ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3);
303
        ms->flags &= ~IP_MASQ_F_FTP_PASV;
304
        return 0;        /* no diff required for incoming packets, thank goodness */
305
}
306
 
307
struct ip_masq_app ip_masq_ftp = {
308
        NULL,                   /* next */
309
        "ftp",                  /* name */
310
        0,                      /* type */
311
        0,                      /* n_attach */
312
        masq_ftp_init_1,        /* ip_masq_init_1 */
313
        masq_ftp_done_1,        /* ip_masq_done_1 */
314
        masq_ftp_out,           /* pkt_out */
315
        masq_ftp_in,            /* pkt_in */
316
};
317
 
318
/*
319
 *      ip_masq_ftp initialization
320
 */
321
 
322
int ip_masq_ftp_init(void)
323
{
324
        int i, j;
325
 
326
        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
327
                if (ports[i]) {
328
                        if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
329
                                                            GFP_KERNEL)) == NULL)
330
                                return -ENOMEM;
331
                        memcpy(masq_incarnations[i], &ip_masq_ftp, sizeof(struct ip_masq_app));
332
                        if ((j = register_ip_masq_app(masq_incarnations[i],
333
                                                      IPPROTO_TCP,
334
                                                      ports[i]))) {
335
                                return j;
336
                        }
337
#if DEBUG_CONFIG_IP_MASQ_FTP
338
                        printk("Ftp: loaded support on port[%d] = %d\n",
339
                               i, ports[i]);
340
#endif
341
                } else {
342
                        /* To be safe, force the incarnation table entry to NULL */
343
                        masq_incarnations[i] = NULL;
344
                }
345
        }
346
        return 0;
347
}
348
 
349
/*
350
 *      ip_masq_ftp fin.
351
 */
352
 
353
int ip_masq_ftp_done(void)
354
{
355
        int i, j, k;
356
 
357
        k=0;
358
        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
359
                if (masq_incarnations[i]) {
360
                        if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
361
                                k = j;
362
                        } else {
363
                                kfree(masq_incarnations[i]);
364
                                masq_incarnations[i] = NULL;
365
#if DEBUG_CONFIG_IP_MASQ_FTP
366
                                printk("Ftp: unloaded support on port[%d] = %d\n",
367
                                       i, ports[i]);
368
#endif
369
                        }
370
                }
371
        }
372
        return k;
373
}
374
 
375
#ifdef MODULE
376
 
377
int init_module(void)
378
{
379
        if (ip_masq_ftp_init() != 0)
380
                return -EIO;
381
        register_symtab(0);
382
        return 0;
383
}
384
 
385
void cleanup_module(void)
386
{
387
        if (ip_masq_ftp_done() != 0)
388
                printk("ip_masq_ftp: can't remove module");
389
}
390
 
391
#endif /* MODULE */

powered by: WebSVN 2.1.0

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