root/net/ipv4/ip_masq_app.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. masq_proto_name
  2. register_ip_masq_app
  3. unregister_ip_masq_app
  4. ip_masq_app_get
  5. ip_masq_app_bind_chg
  6. ip_masq_bind_app
  7. ip_masq_unbind_app
  8. masq_fix_seq
  9. masq_fix_ack_seq
  10. masq_seq_update
  11. ip_masq_app_pkt_out
  12. ip_masq_app_pkt_in
  13. ip_masq_app_getinfo
  14. ip_masq_app_init
  15. skb_replace
  16. ip_masq_skb_replace

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

/* [previous][next][first][last][top][bottom][index][help] */