Import 2.3.10pre5
[davej-history.git] / net / ipv4 / ip_masq_app.c
blob84e059fafc5f55c78db000f3dcb0a8d6e178600f
1 /*
2 * IP_MASQ_APP application masquerading module
5 * $Id: ip_masq_app.c,v 1.16 1998/08/29 23:51:14 davem Exp $
7 * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
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.
15 * Fixes:
16 * JJC : Implemented also input pkt hook
17 * Miquel van Smoorenburg : Copy more stuff when resizing skb
20 * FIXME:
21 * - ip_masq_skb_replace(): use same skb if space available.
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>
42 #define IP_MASQ_APP_TAB_SIZE 16 /* must be power of 2 */
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 )
50 EXPORT_SYMBOL(register_ip_masq_app);
51 EXPORT_SYMBOL(unregister_ip_masq_app);
52 EXPORT_SYMBOL(ip_masq_skb_replace);
55 * will hold masq app. hashed list heads
58 struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE];
61 * ip_masq_app registration routine
62 * port: host byte order.
65 int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port)
67 unsigned long flags;
68 unsigned hash;
69 if (!mapp) {
70 IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
71 return -EINVAL;
73 mapp->type = IP_MASQ_APP_TYPE(proto, port);
74 mapp->n_attach = 0;
75 hash = IP_MASQ_APP_HASH(proto, port);
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);
83 return 0;
87 * ip_masq_app unreg. routine.
90 int unregister_ip_masq_app(struct ip_masq_app *mapp)
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;
100 * only allow unregistration if it has no attachments
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;
107 hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type));
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;
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;
125 * get ip_masq_app object by its proto and port (net byte order).
128 struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port)
130 struct ip_masq_app *mapp;
131 unsigned hash;
132 unsigned type;
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;
140 return NULL;
144 * ip_masq_app object binding related funcs.
148 * change ip_masq_app object's number of bindings
151 static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
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;
166 mapp->n_attach = n_at;
167 restore_flags(flags);
168 return 0;
172 * Bind ip_masq to its ip_masq_app based on proto and dport ALREADY
173 * set in ip_masq struct. Also calls constructor.
176 struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
178 struct ip_masq_app * mapp;
180 if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
181 return NULL;
183 mapp = ip_masq_app_get(ms->protocol, ms->dport);
185 #if 0000
186 /* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */
187 if (mapp == NULL)
188 mapp = ip_masq_app_get(ms->protocol, ms->sport);
189 /* #endif */
190 #endif
192 if (mapp != NULL) {
194 * don't allow binding if already bound
197 if (ms->app != NULL) {
198 IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
199 return ms->app;
202 ms->app = mapp;
203 if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
204 ip_masq_app_bind_chg(mapp, +1);
206 return mapp;
210 * Unbind ms from type object and call ms destructor (does not kfree()).
213 int ip_masq_unbind_app(struct ip_masq *ms)
215 struct ip_masq_app * mapp;
216 mapp = ms->app;
218 if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
219 return 0;
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);
226 return (mapp != NULL);
230 * Fixes th->seq based on ip_masq_seq info.
233 static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
235 __u32 seq;
237 seq = ntohl(th->seq);
240 * Adjust seq with delta-offset for all packets after
241 * the most recent resized pkt seq and with previous_delta offset
242 * for all packets before most recent resized pkt seq.
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);
259 * Fixes th->ack_seq based on ip_masq_seq info.
262 static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
264 __u32 ack_seq;
266 ack_seq=ntohl(th->ack_seq);
269 * Adjust ack_seq with delta-offset for
270 * the packets AFTER most recent resized pkt has caused a shift
271 * for packets before most recent resized pkt, use previous_delta
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);
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);
288 * Updates ip_masq_seq if pkt has been resized
289 * Assumes already checked proto==IPPROTO_TCP and diff!=0.
292 static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff)
294 /* if (diff == 0) return; */
296 if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq))
298 ms_seq->previous_delta=ms_seq->delta;
299 ms_seq->delta+=diff;
300 ms_seq->init_seq=seq;
301 ms->flags |= mflag;
306 * Output pkt hook. Will call bound ip_masq_app specific function
307 * called by ip_fw_masquerade(), assumes previously checked ms!=NULL
308 * returns (new - old) skb->len diff.
311 int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
313 struct ip_masq_app * mapp;
314 struct iphdr *iph;
315 struct tcphdr *th;
316 int diff;
317 __u32 seq;
320 * check if application masquerading is bound to
321 * this ip_masq.
322 * assumes that once an ip_masq is bound,
323 * it will not be unbound during its life.
326 if ( (mapp = ms->app) == NULL)
327 return 0;
329 iph = (*skb_p)->nh.iph;
330 th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
333 * Remember seq number in case this pkt gets resized
336 seq = ntohl(th->seq);
339 * Fix seq stuff if flagged as so.
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);
350 * Call private output hook function
353 if ( mapp->pkt_out == NULL )
354 return 0;
356 diff = mapp->pkt_out(mapp, ms, skb_p, maddr);
359 * Update ip_masq seq stuff if len has changed.
362 if (diff != 0 && ms->protocol == IPPROTO_TCP)
363 masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff);
365 return diff;
369 * Input pkt hook. Will call bound ip_masq_app specific function
370 * called by ip_fw_demasquerade(), assumes previously checked ms!=NULL.
371 * returns (new - old) skb->len diff.
374 int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
376 struct ip_masq_app * mapp;
377 struct iphdr *iph;
378 struct tcphdr *th;
379 int diff;
380 __u32 seq;
383 * check if application masquerading is bound to
384 * this ip_masq.
385 * assumes that once an ip_masq is bound,
386 * it will not be unbound during its life.
389 if ( (mapp = ms->app) == NULL)
390 return 0;
392 iph = (*skb_p)->nh.iph;
393 th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
396 * Remember seq number in case this pkt gets resized
399 seq = ntohl(th->seq);
402 * Fix seq stuff if flagged as so.
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);
413 * Call private input hook function
416 if ( mapp->pkt_in == NULL )
417 return 0;
419 diff = mapp->pkt_in(mapp, ms, skb_p, maddr);
422 * Update ip_masq seq stuff if len has changed.
425 if (diff != 0 && ms->protocol == IPPROTO_TCP)
426 masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff);
428 return diff;
432 * /proc/ip_masq_app entry function
435 int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
437 off_t pos=0, begin=0;
438 int len=0;
439 struct ip_masq_app * mapp;
440 unsigned idx;
442 if (offset < 40)
443 len=sprintf(buffer,"%-39s\n", "prot port n_attach name");
444 pos = 40;
446 for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
447 for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
449 * If you change the length of this sprintf, then all
450 * the length calculations need fixing too!
451 * Line length = 40 (3 + 2 + 7 + 1 + 7 + 1 + 2 + 17)
453 pos += 40;
454 if (pos < offset)
455 continue;
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);
462 if(len >= length)
463 goto done;
465 done:
466 begin = len - (pos - offset);
467 *start = buffer + begin;
468 len -= begin;
469 if (len > length)
470 len = length;
471 return len;
475 #ifdef CONFIG_PROC_FS
476 static 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
482 #endif
485 * Initialization routine
488 __initfunc(int ip_masq_app_init(void))
490 #ifdef CONFIG_PROC_FS
491 ip_masq_proc_register(&proc_net_ip_masq_app);
492 #endif
493 return 0;
497 * Replace a segment (of skb->data) with a new one.
498 * FIXME: Should re-use same skb if space available, this could
499 * be done if n_len < o_len, unless some extra space
500 * were already allocated at driver level :P .
503 static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
505 int maxsize, diff, o_offset;
506 struct sk_buff *n_skb;
507 int offset;
509 maxsize = skb->truesize;
511 diff = n_len - o_len;
512 o_offset = o_buf - (char*) skb->data;
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));
520 memcpy(skb->data + o_offset, n_buf, n_len);
522 n_skb = skb;
523 skb->len = n_len;
524 skb->end = skb->head+n_len;
525 } else {
527 * Sizes differ, make a copy.
529 * FIXME: move this to core/sbuff.c:skb_grow()
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;
539 skb_reserve(n_skb, MAX_HEADER);
540 skb_put(n_skb, skb->len + diff);
543 * Copy as much data from the old skb as possible. Even
544 * though we're only forwarding packets, we need stuff
545 * like skb->protocol (PPP driver wants it).
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);
558 * Copy pkt in new buffer
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) );
567 * Problem, how to replace the new skb with old one,
568 * preferably inplace
571 kfree_skb(skb);
573 return n_skb;
577 * calls skb_replace() and update ip header if new skb was allocated
580 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)
582 int diff;
583 struct sk_buff *n_skb;
584 unsigned skb_len;
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;
590 if (diff)
592 struct iphdr *iph;
593 IP_MASQ_DEBUG(1, "masq_skb_replace(): pkt resized for %d bytes (len=%d)\n", diff, skb->len);
595 * update ip header
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);
602 return n_skb;