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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [ipv4/] [ip_masq_app.c] - Blame information for rev 1772

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

Line No. Rev Author Line
1 1629 jcastillo
/*
2
 *              IP_MASQ_APP application masquerading module
3
 *
4
 *
5
 * Version:     @(#)ip_masq_app.c  0.04      96/06/17
6
 *
7
 * Author:      Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
8
 *
9
 *
10
 *      This program is free software; you can redistribute it and/or
11
 *      modify it under the terms of the GNU General Public License
12
 *      as published by the Free Software Foundation; either version
13
 *      2 of the License, or (at your option) any later version.
14
 *
15
 * Fixes:
16
 *      JJC                     : Implemented also input pkt hook
17
 *      Miquel van Smoorenburg  : Copy more stuff when resizing skb
18
 *      Harald Hoyer/James R. Leu: Additional ipautofw support
19
 *
20
 *
21
 * FIXME:
22
 *      - ip_masq_skb_replace(): use same skb if space available.
23
 *
24
 */
25
 
26
#include <linux/config.h>
27
#include <linux/module.h>
28
#include <linux/types.h>
29
#include <linux/kernel.h>
30
#include <linux/errno.h>
31
#include <linux/skbuff.h>
32
#include <linux/in.h>
33
#include <linux/ip.h>
34
#include <net/protocol.h>
35
#include <net/tcp.h>
36
#include <net/udp.h>
37
#include <asm/system.h>
38
#include <linux/stat.h>
39
#include <linux/proc_fs.h>
40
#include <net/ip_masq.h>
41
 
42
static const char *strProt[] = {"UDP","TCP"};
43
 
44
static __inline__ const char * masq_proto_name(unsigned proto)
45
{
46
        return strProt[proto==IPPROTO_TCP];
47
}
48
 
49
#define IP_MASQ_APP_TAB_SIZE  16 /* must be power of 2 */
50
 
51
#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
52
#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port )
53
#define IP_MASQ_APP_PORT(type)        ( type & 0xffff )
54
#define IP_MASQ_APP_PROTO(type)       ( (type>>16) & 0x00ff )
55
 
56
 
57
static struct symbol_table ip_masq_app_syms = {
58
#include <linux/symtab_begin.h>
59
        X(register_ip_masq_app),
60
        X(unregister_ip_masq_app),
61
        X(ip_masq_skb_replace),
62
#include <linux/symtab_end.h>
63
};
64
 
65
/*
66
 *      will hold masq app. hashed list heads
67
 */
68
 
69
struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE];
70
 
71
/*
72
 *      ip_masq_app registration routine
73
 *      port: host byte order.
74
 */
75
 
76
int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port)
77
{
78
        unsigned long flags;
79
        unsigned hash;
80
        if (!mapp) {
81
                printk("register_ip_masq_app(): NULL arg\n");
82
                return -EINVAL;
83
        }
84
        mapp->type = IP_MASQ_APP_TYPE(proto, port);
85
        mapp->n_attach = 0;
86
        hash = IP_MASQ_APP_HASH(proto, port);
87
 
88
        save_flags(flags);
89
        cli();
90
        mapp->next = ip_masq_app_base[hash];
91
        ip_masq_app_base[hash] = mapp;
92
        restore_flags(flags);
93
 
94
        return 0;
95
}
96
 
97
/*
98
 *      ip_masq_app unreg. routine.
99
 */
100
 
101
int unregister_ip_masq_app(struct ip_masq_app *mapp)
102
{
103
        struct ip_masq_app **mapp_p;
104
        unsigned hash;
105
        unsigned long flags;
106
        if (!mapp) {
107
                printk("unregister_ip_masq_app(): NULL arg\n");
108
                return -EINVAL;
109
        }
110
        /*
111
         * only allow unregistration if it has no attachments
112
         */
113
        if (mapp->n_attach)  {
114
                printk("unregister_ip_masq_app(): has %d attachments. failed\n",
115
                       mapp->n_attach);
116
                return -EINVAL;
117
        }
118
        hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type));
119
 
120
        save_flags(flags);
121
        cli();
122
        for (mapp_p = &ip_masq_app_base[hash]; *mapp_p ; mapp_p = &(*mapp_p)->next)
123
                if (mapp == (*mapp_p))  {
124
                        *mapp_p = mapp->next;
125
                        restore_flags(flags);
126
                        return 0;
127
                }
128
 
129
        restore_flags(flags);
130
        printk("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
131
               masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
132
        return -EINVAL;
133
}
134
 
135
/*
136
 *      get ip_masq_app object by its proto and port (net byte order).
137
 */
138
 
139
struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port)
140
{
141
        struct ip_masq_app *mapp;
142
        unsigned hash;
143
        unsigned type;
144
 
145
        port = ntohs(port);
146
        type = IP_MASQ_APP_TYPE(proto,port);
147
        hash = IP_MASQ_APP_HASH(proto,port);
148
        for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) {
149
                if (type == mapp->type) return mapp;
150
        }
151
        return NULL;
152
}
153
 
154
/*
155
 *      ip_masq_app object binding related funcs.
156
 */
157
 
158
/*
159
 *      change ip_masq_app object's number of bindings
160
 */
161
 
162
static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
163
{
164
        unsigned long flags;
165
        int n_at;
166
        if (!mapp) return -1;
167
        save_flags(flags);
168
        cli();
169
        n_at = mapp->n_attach + delta;
170
        if (n_at < 0) {
171
                restore_flags(flags);
172
                printk("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
173
                       masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
174
                       IP_MASQ_APP_PORT(mapp->type));
175
                return -1;
176
        }
177
        mapp->n_attach = n_at;
178
        restore_flags(flags);
179
        return 0;
180
}
181
 
182
/*
183
 *      Bind ip_masq to its ip_masq_app based on proto and dport ALREADY
184
 *      set in ip_masq struct. Also calls constructor.
185
 */
186
 
187
struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
188
{
189
        struct ip_masq_app * mapp;
190
        mapp = ip_masq_app_get(ms->protocol, ms->dport);
191
#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
192
        if (mapp == NULL)
193
                mapp = ip_masq_app_get(ms->protocol, ms->sport);
194
#endif
195
        if (mapp != NULL) {
196
                /*
197
                 *      don't allow binding if already bound
198
                 */
199
 
200
                if (ms->app != NULL) {
201
                        printk("ip_masq_bind_app() called for already bound object.\n");
202
                        return ms->app;
203
                }
204
 
205
                ms->app = mapp;
206
                if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
207
                ip_masq_app_bind_chg(mapp, +1);
208
        }
209
        return mapp;
210
}
211
 
212
/*
213
 *      Unbind ms from type object and call ms destructor (does not kfree()).
214
 */
215
 
216
int ip_masq_unbind_app(struct ip_masq *ms)
217
{
218
        struct ip_masq_app * mapp;
219
        mapp = ms->app;
220
        if (mapp != NULL) {
221
                if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms);
222
                ms->app = NULL;
223
                ip_masq_app_bind_chg(mapp, -1);
224
        }
225
        return (mapp != NULL);
226
}
227
 
228
/*
229
 *      Fixes th->seq based on ip_masq_seq info.
230
 */
231
 
232
static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
233
{
234
        __u32 seq;
235
 
236
        seq = ntohl(th->seq);
237
 
238
        /*
239
         *      Adjust seq with delta-offset for all packets after
240
         *      the most recent resized pkt seq and with previous_delta offset
241
         *      for all packets before most recent resized pkt seq.
242
         */
243
 
244
        if (ms_seq->delta || ms_seq->previous_delta) {
245
                if(after(seq,ms_seq->init_seq) ) {
246
                        th->seq = htonl(seq + ms_seq->delta);
247
#if DEBUG_CONFIG_IP_MASQ_APP
248
                        printk("masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
249
#endif
250
                } else {
251
                        th->seq = htonl(seq + ms_seq->previous_delta);
252
#if DEBUG_CONFIG_IP_MASQ_APP
253
                        printk("masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
254
#endif
255
                }
256
        }
257
 
258
 
259
}
260
 
261
/*
262
 *      Fixes th->ack_seq based on ip_masq_seq info.
263
 */
264
 
265
static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
266
{
267
        __u32 ack_seq;
268
 
269
        ack_seq=ntohl(th->ack_seq);
270
 
271
        /*
272
         * Adjust ack_seq with delta-offset for
273
         * the packets AFTER most recent resized pkt has caused a shift
274
         * for packets before most recent resized pkt, use previous_delta
275
         */
276
 
277
        if (ms_seq->delta || ms_seq->previous_delta) {
278
                if(after(ack_seq,ms_seq->init_seq)) {
279
                        th->ack_seq = htonl(ack_seq-ms_seq->delta);
280
#if DEBUG_CONFIG_IP_MASQ_APP
281
                        printk("masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
282
#endif
283
                } else {
284
                        th->ack_seq = htonl(ack_seq-ms_seq->previous_delta);
285
#if DEBUG_CONFIG_IP_MASQ_APP
286
                        printk("masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
287
#endif
288
                }
289
        }
290
 
291
}
292
 
293
/*
294
 *      Updates ip_masq_seq if pkt has been resized
295
 *      Assumes already checked proto==IPPROTO_TCP and diff!=0.
296
 */
297
 
298
static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff)
299
{
300
        /* if (diff == 0) return; */
301
 
302
        if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq))
303
        {
304
                ms_seq->previous_delta=ms_seq->delta;
305
                ms_seq->delta+=diff;
306
                ms_seq->init_seq=seq;
307
                ms->flags |= mflag;
308
        }
309
}
310
 
311
/*
312
 *      Output pkt hook. Will call bound ip_masq_app specific function
313
 *      called by ip_fw_masquerade(), assumes previously checked ms!=NULL
314
 *      returns (new - old) skb->len diff.
315
 */
316
 
317
int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
318
{
319
        struct ip_masq_app * mapp;
320
        struct iphdr *iph;
321
        struct tcphdr *th;
322
        int diff;
323
        __u32 seq;
324
 
325
        /*
326
         *      check if application masquerading is bound to
327
         *      this ip_masq.
328
         *      assumes that once an ip_masq is bound,
329
         *      it will not be unbound during its life.
330
         */
331
 
332
        if ( (mapp = ms->app) == NULL)
333
                return 0;
334
 
335
        iph = (*skb_p)->h.iph;
336
        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
337
 
338
        /*
339
         *      Remember seq number in case this pkt gets resized
340
         */
341
 
342
        seq = ntohl(th->seq);
343
 
344
        /*
345
         *      Fix seq stuff if flagged as so.
346
         */
347
 
348
        if (ms->protocol == IPPROTO_TCP) {
349
                if (ms->flags & IP_MASQ_F_OUT_SEQ)
350
                        masq_fix_seq(&ms->out_seq, th);
351
                if (ms->flags & IP_MASQ_F_IN_SEQ)
352
                        masq_fix_ack_seq(&ms->in_seq, th);
353
        }
354
 
355
        /*
356
         *      Call private output hook function
357
         */
358
 
359
        if ( mapp->pkt_out == NULL )
360
                return 0;
361
 
362
        diff = mapp->pkt_out(mapp, ms, skb_p, dev);
363
 
364
        /*
365
         *      Update ip_masq seq stuff if len has changed.
366
         */
367
 
368
        if (diff != 0 && ms->protocol == IPPROTO_TCP)
369
                masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff);
370
 
371
        return diff;
372
}
373
 
374
/*
375
 *      Input pkt hook. Will call bound ip_masq_app specific function
376
 *      called by ip_fw_demasquerade(), assumes previously checked ms!=NULL.
377
 *      returns (new - old) skb->len diff.
378
 */
379
 
380
int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
381
{
382
        struct ip_masq_app * mapp;
383
        struct iphdr *iph;
384
        struct tcphdr *th;
385
        int diff;
386
        __u32 seq;
387
 
388
        /*
389
         *      check if application masquerading is bound to
390
         *      this ip_masq.
391
         *      assumes that once an ip_masq is bound,
392
         *      it will not be unbound during its life.
393
         */
394
 
395
        if ( (mapp = ms->app) == NULL)
396
                return 0;
397
 
398
        iph = (*skb_p)->h.iph;
399
        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
400
 
401
        /*
402
         *      Remember seq number in case this pkt gets resized
403
         */
404
 
405
        seq = ntohl(th->seq);
406
 
407
        /*
408
         *      Fix seq stuff if flagged as so.
409
         */
410
 
411
        if (ms->protocol == IPPROTO_TCP) {
412
                if (ms->flags & IP_MASQ_F_IN_SEQ)
413
                        masq_fix_seq(&ms->in_seq, th);
414
                if (ms->flags & IP_MASQ_F_OUT_SEQ)
415
                        masq_fix_ack_seq(&ms->out_seq, th);
416
        }
417
 
418
        /*
419
         *      Call private input hook function
420
         */
421
 
422
        if ( mapp->pkt_in == NULL )
423
                return 0;
424
 
425
        diff = mapp->pkt_in(mapp, ms, skb_p, dev);
426
 
427
        /*
428
         *      Update ip_masq seq stuff if len has changed.
429
         */
430
 
431
        if (diff != 0 && ms->protocol == IPPROTO_TCP)
432
                masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff);
433
 
434
        return diff;
435
}
436
 
437
/*
438
 *      /proc/ip_masq_app entry function
439
 */
440
 
441
int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
442
{
443
        off_t pos=0, begin=0;
444
        int len=0;
445
        struct ip_masq_app * mapp;
446
        unsigned idx;
447
 
448
        if (offset < 40)
449
                len=sprintf(buffer,"%-39s\n", "prot port    n_attach name");
450
        pos = 40;
451
 
452
        for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
453
                for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
454
                        /*
455
                         * If you change the length of this sprintf, then all
456
                         * the length calculations need fixing too!
457
                         * Line length = 40 (3 + 2 + 7 + 1 + 7 + 1 + 2 + 17)
458
                         */
459
                        pos += 40;
460
                        if (pos < offset)
461
                                continue;
462
 
463
                        len += sprintf(buffer+len, "%-3s  %-7u %-7d  %-17s\n",
464
                                       masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
465
                                       IP_MASQ_APP_PORT(mapp->type), mapp->n_attach,
466
                                       mapp->name);
467
 
468
                        if(len >= length)
469
                                goto done;
470
                }
471
done:
472
        begin = len - (pos - offset);
473
        *start = buffer + begin;
474
        len -= begin;
475
        if (len > length)
476
                len = length;
477
        return len;
478
}
479
 
480
 
481
/*
482
 *      Initialization routine
483
 */
484
 
485
#ifdef CONFIG_PROC_FS
486
static struct proc_dir_entry pde1 = {
487
                PROC_NET_IP_MASQ_APP, 11, "ip_masq_app",
488
                S_IFREG | S_IRUGO, 1, 0, 0,
489
                0, &proc_net_inode_operations,
490
                ip_masq_app_getinfo
491
        };
492
#endif
493
 
494
int ip_masq_app_init(void)
495
{
496
 
497
        register_symtab (&ip_masq_app_syms);
498
#ifdef CONFIG_PROC_FS        
499
        proc_net_register(&pde1);
500
#endif        
501
        return 0;
502
}
503
 
504
/*
505
 *      Replace a segment (of skb->data) with a new one.
506
 *      FIXME: Should re-use same skb if space available, this could
507
 *             be done if n_len < o_len, unless some extra space
508
 *             were already allocated at driver level :P .
509
 */
510
 
511
static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
512
{
513
        int maxsize, diff, o_offset;
514
        struct sk_buff *n_skb;
515
        int offset;
516
 
517
        maxsize = skb->truesize - sizeof(struct sk_buff);
518
 
519
        diff = n_len - o_len;
520
        o_offset = o_buf - (char*) skb->data;
521
 
522
        if (maxsize <= n_len) {
523
            if (diff != 0) {
524
                memcpy(skb->data + o_offset + n_len,o_buf + o_len,
525
                       skb->len - (o_offset + o_len));
526
            }
527
 
528
            memcpy(skb->data + o_offset, n_buf, n_len);
529
 
530
            n_skb    = skb;
531
            skb->len = n_len;
532
            skb->end = skb->head+n_len;
533
        } else {
534
                /*
535
                 *      Sizes differ, make a copy.
536
                 *
537
                 *      FIXME: move this to core/sbuff.c:skb_grow()
538
                 */
539
 
540
                n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
541
                if (n_skb == NULL) {
542
                        printk("skb_replace(): no room left (from %p)\n",
543
                               __builtin_return_address(0));
544
                        return skb;
545
 
546
                }
547
                n_skb->free = skb->free;
548
                skb_reserve(n_skb, MAX_HEADER);
549
                skb_put(n_skb, skb->len + diff);
550
 
551
                /*
552
                 *      Copy as much data from the old skb as possible. Even
553
                 *      though we're only forwarding packets, we need stuff
554
                 *      like skb->protocol (PPP driver wants it).
555
                 */
556
                offset = n_skb->data - skb->data;
557
                n_skb->h.raw = skb->h.raw + offset;
558
                n_skb->when = skb->when;
559
                n_skb->dev = skb->dev;
560
                n_skb->mac.raw = skb->mac.raw + offset;
561
                n_skb->ip_hdr = (struct iphdr *)(((char *)skb->ip_hdr)+offset);
562
                n_skb->pkt_type = skb->pkt_type;
563
                n_skb->protocol = skb->protocol;
564
                n_skb->ip_summed = skb->ip_summed;
565
 
566
                /*
567
                 * Copy pkt in new buffer
568
                 */
569
 
570
                memcpy(n_skb->data, skb->data, o_offset);
571
                memcpy(n_skb->data + o_offset, n_buf, n_len);
572
                memcpy(n_skb->data + o_offset + n_len, o_buf + o_len,
573
                       skb->len - (o_offset + o_len) );
574
 
575
                /*
576
                 * Problem, how to replace the new skb with old one,
577
                 * preferably inplace
578
                 */
579
 
580
                kfree_skb(skb, FREE_WRITE);
581
        }
582
        return n_skb;
583
}
584
 
585
/*
586
 *      calls skb_replace() and update ip header if new skb was allocated
587
 */
588
 
589
struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
590
{
591
        int diff;
592
        struct sk_buff *n_skb;
593
        unsigned skb_len;
594
 
595
        diff = n_len - o_len;
596
        n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len);
597
        skb_len = skb->len;
598
 
599
        if (diff)
600
        {
601
                struct iphdr *iph;
602
#if DEBUG_CONFIG_IP_MASQ_APP
603
                printk("masq_skb_replace(): pkt resized for %d bytes (len=%ld)\n", diff, skb->len);
604
#endif
605
                /*
606
                 *      update ip header
607
                 */
608
                iph = n_skb->h.iph;
609
                iph->check = 0;
610
                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
611
                iph->tot_len = htons(skb_len + diff);
612
        }
613
        return n_skb;
614
}

powered by: WebSVN 2.1.0

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