1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/config.h>
26#include <linux/module.h>
27#include <linux/types.h>
28#include <linux/kernel.h>
29#include <linux/errno.h>
30#include <linux/skbuff.h>
31#include <linux/in.h>
32#include <linux/ip.h>
33#include <linux/init.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#define IP_MASQ_APP_TAB_SIZE 16
43
44#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
45#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port )
46#define IP_MASQ_APP_PORT(type) ( type & 0xffff )
47#define IP_MASQ_APP_PROTO(type) ( (type>>16) & 0x00ff )
48
49
50EXPORT_SYMBOL(register_ip_masq_app);
51EXPORT_SYMBOL(unregister_ip_masq_app);
52EXPORT_SYMBOL(ip_masq_skb_replace);
53
54
55
56
57
58struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE];
59
60
61
62
63
64
65int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port)
66{
67 unsigned long flags;
68 unsigned hash;
69 if (!mapp) {
70 IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
71 return -EINVAL;
72 }
73 mapp->type = IP_MASQ_APP_TYPE(proto, port);
74 mapp->n_attach = 0;
75 hash = IP_MASQ_APP_HASH(proto, port);
76
77 save_flags(flags);
78 cli();
79 mapp->next = ip_masq_app_base[hash];
80 ip_masq_app_base[hash] = mapp;
81 restore_flags(flags);
82
83 return 0;
84}
85
86
87
88
89
90int unregister_ip_masq_app(struct ip_masq_app *mapp)
91{
92 struct ip_masq_app **mapp_p;
93 unsigned hash;
94 unsigned long flags;
95 if (!mapp) {
96 IP_MASQ_ERR("unregister_ip_masq_app(): NULL arg\n");
97 return -EINVAL;
98 }
99
100
101
102 if (mapp->n_attach) {
103 IP_MASQ_ERR("unregister_ip_masq_app(): has %d attachments. failed\n",
104 mapp->n_attach);
105 return -EINVAL;
106 }
107 hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type));
108
109 save_flags(flags);
110 cli();
111 for (mapp_p = &ip_masq_app_base[hash]; *mapp_p ; mapp_p = &(*mapp_p)->next)
112 if (mapp == (*mapp_p)) {
113 *mapp_p = mapp->next;
114 restore_flags(flags);
115 return 0;
116 }
117
118 restore_flags(flags);
119 IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
120 masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
121 return -EINVAL;
122}
123
124
125
126
127
128struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port)
129{
130 struct ip_masq_app *mapp;
131 unsigned hash;
132 unsigned type;
133
134 port = ntohs(port);
135 type = IP_MASQ_APP_TYPE(proto,port);
136 hash = IP_MASQ_APP_HASH(proto,port);
137 for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) {
138 if (type == mapp->type) return mapp;
139 }
140 return NULL;
141}
142
143
144
145
146
147
148
149
150
151static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
152{
153 unsigned long flags;
154 int n_at;
155 if (!mapp) return -1;
156 save_flags(flags);
157 cli();
158 n_at = mapp->n_attach + delta;
159 if (n_at < 0) {
160 restore_flags(flags);
161 IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
162 masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
163 IP_MASQ_APP_PORT(mapp->type));
164 return -1;
165 }
166 mapp->n_attach = n_at;
167 restore_flags(flags);
168 return 0;
169}
170
171
172
173
174
175
176struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
177{
178 struct ip_masq_app * mapp;
179
180 if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
181 return NULL;
182
183 mapp = ip_masq_app_get(ms->protocol, ms->dport);
184
185#if 0000
186
187 if (mapp == NULL)
188 mapp = ip_masq_app_get(ms->protocol, ms->sport);
189
190#endif
191
192 if (mapp != NULL) {
193
194
195
196
197 if (ms->app != NULL) {
198 IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
199 return ms->app;
200 }
201
202 ms->app = mapp;
203 if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
204 ip_masq_app_bind_chg(mapp, +1);
205 }
206 return mapp;
207}
208
209
210
211
212
213int ip_masq_unbind_app(struct ip_masq *ms)
214{
215 struct ip_masq_app * mapp;
216 mapp = ms->app;
217
218 if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
219 return 0;
220
221 if (mapp != NULL) {
222 if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms);
223 ms->app = NULL;
224 ip_masq_app_bind_chg(mapp, -1);
225 }
226 return (mapp != NULL);
227}
228
229
230
231
232
233static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
234{
235 __u32 seq;
236
237 seq = ntohl(th->seq);
238
239
240
241
242
243
244
245 if (ms_seq->delta || ms_seq->previous_delta) {
246 if(after(seq,ms_seq->init_seq) ) {
247 th->seq = htonl(seq + ms_seq->delta);
248 IP_MASQ_DEBUG(1, "masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
249 } else {
250 th->seq = htonl(seq + ms_seq->previous_delta);
251 IP_MASQ_DEBUG(1, "masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
252 }
253 }
254
255
256}
257
258
259
260
261
262static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
263{
264 __u32 ack_seq;
265
266 ack_seq=ntohl(th->ack_seq);
267
268
269
270
271
272
273
274 if (ms_seq->delta || ms_seq->previous_delta) {
275 if(after(ack_seq,ms_seq->init_seq)) {
276 th->ack_seq = htonl(ack_seq-ms_seq->delta);
277 IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
278
279 } else {
280 th->ack_seq = htonl(ack_seq-ms_seq->previous_delta);
281 IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
282 }
283 }
284
285}
286
287
288
289
290
291
292static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff)
293{
294
295
296 if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq))
297 {
298 ms_seq->previous_delta=ms_seq->delta;
299 ms_seq->delta+=diff;
300 ms_seq->init_seq=seq;
301 ms->flags |= mflag;
302 }
303}
304
305
306
307
308
309
310
311int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
312{
313 struct ip_masq_app * mapp;
314 struct iphdr *iph;
315 struct tcphdr *th;
316 int diff;
317 __u32 seq;
318
319
320
321
322
323
324
325
326 if ( (mapp = ms->app) == NULL)
327 return 0;
328
329 iph = (*skb_p)->nh.iph;
330 th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
331
332
333
334
335
336 seq = ntohl(th->seq);
337
338
339
340
341
342 if (ms->protocol == IPPROTO_TCP) {
343 if (ms->flags & IP_MASQ_F_OUT_SEQ)
344 masq_fix_seq(&ms->out_seq, th);
345 if (ms->flags & IP_MASQ_F_IN_SEQ)
346 masq_fix_ack_seq(&ms->in_seq, th);
347 }
348
349
350
351
352
353 if ( mapp->pkt_out == NULL )
354 return 0;
355
356 diff = mapp->pkt_out(mapp, ms, skb_p, maddr);
357
358
359
360
361
362 if (diff != 0 && ms->protocol == IPPROTO_TCP)
363 masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff);
364
365 return diff;
366}
367
368
369
370
371
372
373
374int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
375{
376 struct ip_masq_app * mapp;
377 struct iphdr *iph;
378 struct tcphdr *th;
379 int diff;
380 __u32 seq;
381
382
383
384
385
386
387
388
389 if ( (mapp = ms->app) == NULL)
390 return 0;
391
392 iph = (*skb_p)->nh.iph;
393 th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
394
395
396
397
398
399 seq = ntohl(th->seq);
400
401
402
403
404
405 if (ms->protocol == IPPROTO_TCP) {
406 if (ms->flags & IP_MASQ_F_IN_SEQ)
407 masq_fix_seq(&ms->in_seq, th);
408 if (ms->flags & IP_MASQ_F_OUT_SEQ)
409 masq_fix_ack_seq(&ms->out_seq, th);
410 }
411
412
413
414
415
416 if ( mapp->pkt_in == NULL )
417 return 0;
418
419 diff = mapp->pkt_in(mapp, ms, skb_p, maddr);
420
421
422
423
424
425 if (diff != 0 && ms->protocol == IPPROTO_TCP)
426 masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff);
427
428 return diff;
429}
430
431
432
433
434
435int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
436{
437 off_t pos=0, begin=0;
438 int len=0;
439 struct ip_masq_app * mapp;
440 unsigned idx;
441
442 if (offset < 40)
443 len=sprintf(buffer,"%-39s\n", "prot port n_attach name");
444 pos = 40;
445
446 for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
447 for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
448
449
450
451
452
453 pos += 40;
454 if (pos < offset)
455 continue;
456
457 len += sprintf(buffer+len, "%-3s %-7u %-7d %-17s\n",
458 masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
459 IP_MASQ_APP_PORT(mapp->type), mapp->n_attach,
460 mapp->name);
461
462 if(len >= length)
463 goto done;
464 }
465done:
466 begin = len - (pos - offset);
467 *start = buffer + begin;
468 len -= begin;
469 if (len > length)
470 len = length;
471 return len;
472}
473
474
475#ifdef CONFIG_PROC_FS
476static struct proc_dir_entry proc_net_ip_masq_app = {
477 PROC_NET_IP_MASQ_APP, 3, "app",
478 S_IFREG | S_IRUGO, 1, 0, 0,
479 0, &proc_net_inode_operations,
480 ip_masq_app_getinfo
481};
482#endif
483
484
485
486
487
488__initfunc(int ip_masq_app_init(void))
489{
490#ifdef CONFIG_PROC_FS
491 ip_masq_proc_register(&proc_net_ip_masq_app);
492#endif
493 return 0;
494}
495
496
497
498
499
500
501
502
503static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
504{
505 int maxsize, diff, o_offset;
506 struct sk_buff *n_skb;
507 int offset;
508
509 maxsize = skb->truesize;
510
511 diff = n_len - o_len;
512 o_offset = o_buf - (char*) skb->data;
513
514 if (maxsize <= n_len) {
515 if (diff != 0) {
516 memcpy(skb->data + o_offset + n_len,o_buf + o_len,
517 skb->len - (o_offset + o_len));
518 }
519
520 memcpy(skb->data + o_offset, n_buf, n_len);
521
522 n_skb = skb;
523 skb->len = n_len;
524 skb->end = skb->head+n_len;
525 } else {
526
527
528
529
530
531
532 n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
533 if (n_skb == NULL) {
534 IP_MASQ_ERR("skb_replace(): no room left (from %p)\n",
535 __builtin_return_address(0));
536 return skb;
537
538 }
539 skb_reserve(n_skb, MAX_HEADER);
540 skb_put(n_skb, skb->len + diff);
541
542
543
544
545
546
547 offset = n_skb->data - skb->data;
548 n_skb->nh.raw = skb->nh.raw + offset;
549 n_skb->h.raw = skb->h.raw + offset;
550 n_skb->dev = skb->dev;
551 n_skb->mac.raw = skb->mac.raw + offset;
552 n_skb->pkt_type = skb->pkt_type;
553 n_skb->protocol = skb->protocol;
554 n_skb->ip_summed = skb->ip_summed;
555 n_skb->dst = dst_clone(skb->dst);
556
557
558
559
560
561 memcpy(n_skb->data, skb->data, o_offset);
562 memcpy(n_skb->data + o_offset, n_buf, n_len);
563 memcpy(n_skb->data + o_offset + n_len, o_buf + o_len,
564 skb->len - (o_offset + o_len) );
565
566
567
568
569
570
571 kfree_skb(skb);
572 }
573 return n_skb;
574}
575
576
577
578
579
580struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
581{
582 int diff;
583 struct sk_buff *n_skb;
584 unsigned skb_len;
585
586 diff = n_len - o_len;
587 n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len);
588 skb_len = skb->len;
589
590 if (diff)
591 {
592 struct iphdr *iph;
593 IP_MASQ_DEBUG(1, "masq_skb_replace(): pkt resized for %d bytes (len=%d)\n", diff, skb->len);
594
595
596
597 iph = n_skb->nh.iph;
598 iph->check = 0;
599 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
600 iph->tot_len = htons(skb_len + diff);
601 }
602 return n_skb;
603}
604