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         len=sprintf(buffer,"prot port    n_attach\n");
 441         for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
 442                 for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
 443                         len += sprintf(buffer+len, "%s  %-7u %-7d\n",
 444                                        masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
 445                                        IP_MASQ_APP_PORT(mapp->type), mapp->n_attach);
 446                         pos=begin+len;
 447                         if(pos<offset) {
 448                                 len=0;
 449                                 begin=pos;
 450                         }
 451                         if(pos>offset+length)
 452                                 break;
 453                 }
 454         *start=buffer+(offset-begin);
 455         len-=(offset-begin);
 456         if(len>length)
 457                 len=length;     
 458         return len;
 459 }
 460 
 461 
 462 /*
 463  *      Initialization routine
 464  */
 465 
 466 int ip_masq_app_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 467 {
 468         
 469         register_symtab (&ip_masq_app_syms);
 470         
 471         proc_net_register(&(struct proc_dir_entry) {
 472                 PROC_NET_IP_MASQ_APP, 11, "ip_masq_app",
 473                 S_IFREG | S_IRUGO, 1, 0, 0,
 474                 0, &proc_net_inode_operations,
 475                 ip_masq_app_getinfo
 476         });
 477         
 478         return 0;
 479 }
 480 
 481 /*
 482  *      Replace a segment (of skb->data) with a new one.
 483  *      FIXME: Should re-use same skb if space available, this could
 484  *             be done if n_len < o_len, unless some extra space
 485  *             were already allocated at driver level :P .
 486  */
 487 
 488 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] */
 489 {
 490         int maxsize, diff, o_offset;
 491         struct sk_buff *n_skb;
 492 
 493         maxsize = skb->truesize - sizeof(struct sk_buff);
 494 
 495         diff = n_len - o_len;
 496         o_offset = o_buf - (char*) skb->data;
 497 
 498         if (maxsize <= n_len) {
 499             if (diff != 0) {
 500                 memcpy(skb->data + o_offset + n_len,o_buf + o_len,
 501                        skb->len - (o_offset + o_len));
 502             }
 503 
 504             memcpy(skb->data + o_offset, n_buf, n_len);
 505 
 506             n_skb    = skb;
 507             skb->len = n_len;
 508             skb->end = skb->head+n_len;
 509         } else {
 510                 /*
 511                  *      Sizes differ, make a copy
 512                  */
 513         
 514                 n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
 515                 if (n_skb == NULL) {
 516                         printk("skb_replace(): no room left (from %p)\n",
 517                                __builtin_return_address(0));
 518                         return skb;
 519 
 520                 }
 521                 n_skb->free = skb->free;
 522                 skb_reserve(n_skb, MAX_HEADER);
 523                 skb_put(n_skb, skb->len + diff);
 524                 n_skb->h.raw = n_skb->data + (skb->h.raw - skb->data);
 525                 
 526                 /*
 527                  * Copy pkt in new buffer
 528                  */
 529                 
 530                 memcpy(n_skb->data, skb->data, o_offset);
 531                 memcpy(n_skb->data + o_offset, n_buf, n_len);
 532                 memcpy(n_skb->data + o_offset + n_len, o_buf + o_len,
 533                        skb->len - (o_offset + o_len) );
 534                 
 535                 /*
 536                  * Problem, how to replace the new skb with old one,
 537                  * preferably inplace
 538                  */
 539                 
 540                 kfree_skb(skb, FREE_WRITE);
 541         }
 542         return n_skb;
 543 }
 544 
 545 /*
 546  *      calls skb_replace() and update ip header if new skb was allocated
 547  */
 548 
 549 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] */
 550 {
 551         int diff;
 552         struct sk_buff *n_skb;
 553         unsigned skb_len;
 554 
 555         diff = n_len - o_len;
 556         n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len);
 557         skb_len = skb->len;
 558                 
 559         if (diff)
 560         {
 561                 struct iphdr *iph;
 562 #if DEBUG_CONFIG_IP_MASQ_APP
 563                 printk("masq_skb_replace(): pkt resized for %d bytes (len=%ld)\n", diff, skb->len);
 564 #endif
 565                 /*
 566                  *      update ip header
 567                  */
 568                 iph = n_skb->h.iph;
 569                 iph->check = 0;
 570                 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 571                 iph->tot_len = htons(skb_len + diff);
 572         }
 573         return n_skb;
 574 }

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