linux-old/net/ipv4/ip_masq_autofw.c
<<
>>
Prefs
   1/*
   2 *              IP_MASQ_AUTOFW auto forwarding module
   3 *
   4 *
   5 *      $Id: ip_masq_autofw.c,v 1.3 1998/08/29 23:51:10 davem Exp $
   6 *
   7 * Author:      Richard Lynch
   8 *
   9 *      This program is free software; you can redistribute it and/or
  10 *      modify it under the terms of the GNU General Public License
  11 *      as published by the Free Software Foundation; either version
  12 *      2 of the License, or (at your option) any later version.
  13 *
  14 *
  15 * Fixes:
  16 *      Juan Jose Ciarlante     : created this new file from ip_masq.c and ip_fw.c
  17 *      Juan Jose Ciarlante     : modularized 
  18 *      Juan Jose Ciarlante     : use GFP_KERNEL when creating entries
  19 *      Juan Jose Ciarlante     : call del_timer() when freeing entries (!)
  20 *  FIXME:
  21 *      - implement refcnt
  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/slab.h>
  30#include <linux/errno.h>
  31#include <asm/system.h>
  32#include <linux/stat.h>
  33#include <linux/proc_fs.h>
  34#include <linux/if.h>
  35#include <linux/init.h>
  36#include <linux/ip_fw.h>
  37#include <net/ip_masq.h>
  38#include <net/ip_masq_mod.h>
  39#include <linux/ip_masq.h>
  40
  41#define IP_AUTOFW_EXPIRE             15*HZ
  42
  43/* WARNING: bitwise equal to ip_autofw_user  in linux/ip_masq.h */
  44struct ip_autofw {
  45        struct ip_autofw * next;
  46        __u16 type;
  47        __u16 low;
  48        __u16 hidden;
  49        __u16 high;
  50        __u16 visible;
  51        __u16 protocol;
  52        __u32 lastcontact;
  53        __u32 where;
  54        __u16 ctlproto;
  55        __u16 ctlport;
  56        __u16 flags;
  57        struct timer_list timer;
  58};
  59
  60/*
  61 *      Debug level
  62 */
  63#ifdef CONFIG_IP_MASQ_DEBUG
  64static int debug=0;
  65MODULE_PARM(debug, "i");
  66#endif
  67
  68/*
  69 *      Auto-forwarding table
  70 */
  71
  72static struct ip_autofw * ip_autofw_hosts = NULL;
  73static struct ip_masq_mod * mmod_self = NULL;
  74
  75/*
  76 *      Check if a masq entry should be created for a packet
  77 */
  78
  79static __inline__ struct ip_autofw * ip_autofw_check_range (__u32 where, __u16 port, __u16 protocol, int reqact)
  80{
  81        struct ip_autofw *af;
  82        af=ip_autofw_hosts;
  83        port=ntohs(port);
  84        while (af) {
  85                if (af->type==IP_FWD_RANGE && 
  86                     port>=af->low && 
  87                     port<=af->high && 
  88                     protocol==af->protocol && 
  89
  90                     /*
  91                      *         It's ok to create masq entries after 
  92                      *         the timeout if we're in insecure mode 
  93                      */
  94                     (af->flags & IP_AUTOFW_ACTIVE || !reqact || !(af->flags & IP_AUTOFW_SECURE)) &&  
  95                     (!(af->flags & IP_AUTOFW_SECURE) || af->lastcontact==where || !reqact))
  96                        return(af);
  97                af=af->next;
  98        }
  99        return(NULL);
 100}
 101
 102static __inline__ struct ip_autofw * ip_autofw_check_port (__u16 port, __u16 protocol)
 103{
 104        struct ip_autofw *af;
 105        af=ip_autofw_hosts;
 106        port=ntohs(port);
 107        while (af)
 108        {
 109                if (af->type==IP_FWD_PORT && port==af->visible && protocol==af->protocol)
 110                        return(af);
 111                af=af->next;
 112        }
 113        return(NULL);
 114}
 115
 116static __inline__ struct ip_autofw * ip_autofw_check_direct (__u16 port, __u16 protocol)
 117{
 118        struct ip_autofw *af;
 119        af=ip_autofw_hosts;
 120        port=ntohs(port);
 121        while (af)
 122        {
 123                if (af->type==IP_FWD_DIRECT && af->low<=port && af->high>=port)
 124                        return(af);
 125                af=af->next;
 126        }
 127        return(NULL);
 128}
 129
 130static __inline__ void ip_autofw_update_out (__u32 who, __u32 where, __u16 port, __u16 protocol)
 131{
 132        struct ip_autofw *af;
 133        af=ip_autofw_hosts;
 134        port=ntohs(port);
 135        while (af)
 136        {
 137                if (af->type==IP_FWD_RANGE && af->ctlport==port && af->ctlproto==protocol)
 138                {
 139                        if (af->flags & IP_AUTOFW_USETIME)
 140                        {
 141                                mod_timer(&af->timer,
 142                                          jiffies+IP_AUTOFW_EXPIRE);
 143                        }
 144                        af->flags|=IP_AUTOFW_ACTIVE;
 145                        af->lastcontact=where;
 146                        af->where=who;
 147                }
 148                af=af->next;
 149        }
 150}
 151
 152#if 0
 153static __inline__ void ip_autofw_update_in (__u32 where, __u16 port, __u16 protocol)
 154{
 155        struct ip_autofw *af;
 156        af=ip_autofw_check_range(where, port,protocol);
 157        if (af)
 158        {
 159                mod_timer(&af->timer, jiffies+IP_AUTOFW_EXPIRE);
 160        }
 161}
 162#endif
 163
 164
 165static __inline__ void ip_autofw_expire(unsigned long data)
 166{
 167        struct ip_autofw * af;
 168        af=(struct ip_autofw *) data;
 169        af->flags &= ~IP_AUTOFW_ACTIVE;
 170        af->timer.expires=0;
 171        af->lastcontact=0;
 172        if (af->flags & IP_AUTOFW_SECURE)
 173                af->where=0;
 174}
 175
 176
 177
 178static __inline__ int ip_autofw_add(struct ip_autofw_user * af)
 179{
 180        struct ip_autofw * newaf;
 181        newaf = kmalloc( sizeof(struct ip_autofw), GFP_KERNEL );
 182        init_timer(&newaf->timer);
 183        if ( newaf == NULL ) 
 184        {
 185                printk("ip_autofw_add:  malloc said no\n");
 186                return( ENOMEM );
 187        }
 188
 189        MOD_INC_USE_COUNT;
 190
 191        memcpy(newaf, af, sizeof(struct ip_autofw_user));
 192        newaf->timer.data = (unsigned long) newaf;
 193        newaf->timer.function = ip_autofw_expire;
 194        newaf->timer.expires = 0;
 195        newaf->lastcontact=0;
 196        newaf->next=ip_autofw_hosts;
 197        ip_autofw_hosts=newaf;
 198        ip_masq_mod_inc_nent(mmod_self);
 199        return(0);
 200}
 201
 202static __inline__ int ip_autofw_del(struct ip_autofw_user * af)
 203{
 204        struct ip_autofw ** af_p, *curr;
 205
 206        for (af_p=&ip_autofw_hosts, curr=*af_p; (curr=*af_p); af_p = &(*af_p)->next) {
 207                if (af->type     == curr->type &&
 208                    af->low      == curr->low &&
 209                    af->high     == curr->high &&
 210                    af->hidden   == curr->hidden &&
 211                    af->visible  == curr->visible &&
 212                    af->protocol == curr->protocol &&
 213                    af->where    == curr->where &&
 214                    af->ctlproto == curr->ctlproto &&
 215                    af->ctlport  == curr->ctlport)
 216                {
 217                        ip_masq_mod_dec_nent(mmod_self);
 218                        *af_p = curr->next;
 219                        if (af->flags&IP_AUTOFW_ACTIVE)
 220                                del_timer(&curr->timer);
 221                        kfree_s(curr,sizeof(struct ip_autofw));
 222                        MOD_DEC_USE_COUNT;
 223                        return 0;
 224                }
 225                curr=curr->next;
 226        }
 227        return EINVAL;
 228}
 229
 230static __inline__ int ip_autofw_flush(void)
 231{
 232        struct ip_autofw * af;
 233
 234        while (ip_autofw_hosts)
 235        {
 236                af=ip_autofw_hosts;
 237                ip_masq_mod_dec_nent(mmod_self);
 238                ip_autofw_hosts=ip_autofw_hosts->next;
 239                if (af->flags&IP_AUTOFW_ACTIVE)
 240                        del_timer(&af->timer);
 241                kfree_s(af,sizeof(struct ip_autofw));
 242                MOD_DEC_USE_COUNT;
 243        }
 244        return(0);
 245}
 246
 247/*
 248 *      Methods for registered object
 249 */
 250
 251static int autofw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
 252{
 253        struct ip_autofw_user *af = &mctl->u.autofw_user;
 254
 255        switch (mctl->m_cmd) {
 256                case IP_MASQ_CMD_ADD:
 257                case IP_MASQ_CMD_INSERT:
 258                        if (optlen<sizeof(*af))
 259                                return EINVAL;
 260                        return ip_autofw_add(af);
 261                case IP_MASQ_CMD_DEL:
 262                        if (optlen<sizeof(*af))
 263                                return EINVAL;
 264                        return ip_autofw_del(af);
 265                case IP_MASQ_CMD_FLUSH:
 266                        return ip_autofw_flush();
 267
 268        }
 269        return EINVAL;
 270}
 271
 272
 273static int autofw_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
 274{
 275        const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
 276        /* 
 277         *      Update any ipautofw entries ...
 278         */
 279
 280        ip_autofw_update_out(iph->saddr, iph->daddr, portp[1], iph->protocol);
 281        return IP_MASQ_MOD_NOP;
 282}
 283
 284static struct ip_masq * autofw_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 285{
 286        const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
 287        /*
 288         *      If the source port is supposed to match the masq port, then
 289         *      make it so 
 290         */
 291
 292        if (ip_autofw_check_direct(portp[1],iph->protocol)) {
 293                return ip_masq_new(iph->protocol,
 294                                        maddr, portp[0],
 295                                        iph->saddr, portp[0],
 296                                        iph->daddr, portp[1],
 297                                        0);
 298        }
 299        return NULL;
 300}
 301
 302#if 0
 303static int autofw_in_update(const struct sk_buff *skb, const struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
 304{
 305        const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
 306        ip_autofw_update_in(iph->saddr, portp[1], iph->protocol);
 307        return IP_MASQ_MOD_NOP;
 308}
 309#endif
 310
 311static int autofw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
 312{
 313        const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
 314        return (ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0)
 315                || ip_autofw_check_direct(portp[1], iph->protocol)
 316                || ip_autofw_check_port(portp[1], iph->protocol));
 317}
 318
 319static struct ip_masq * autofw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 320{
 321        const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
 322        struct ip_autofw *af;
 323
 324        if ((af=ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0))) {
 325                IP_MASQ_DEBUG(1-debug, "autofw_check_range HIT\n");
 326                return ip_masq_new(iph->protocol,
 327                                        maddr, portp[1],
 328                                        af->where, portp[1],
 329                                        iph->saddr, portp[0],
 330                                        0);
 331        } 
 332        if ((af=ip_autofw_check_port(portp[1], iph->protocol)) ) {
 333                IP_MASQ_DEBUG(1-debug, "autofw_check_port HIT\n");
 334                return ip_masq_new(iph->protocol,
 335                                        maddr, htons(af->visible),
 336                                        af->where, htons(af->hidden),
 337                                        iph->saddr, portp[0],
 338                                        0);
 339        }
 340        return NULL;
 341}
 342
 343#ifdef CONFIG_PROC_FS
 344static int autofw_procinfo(char *buffer, char **start, off_t offset,
 345                              int length, int unused)
 346{
 347        off_t pos=0, begin=0;
 348        struct ip_autofw * af;
 349        int len=0;
 350        
 351        len=sprintf(buffer,"Type Prot Low  High Vis  Hid  Where    Last     CPto CPrt Timer Flags\n"); 
 352        
 353        for(af = ip_autofw_hosts; af ; af = af->next)
 354        {
 355                len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n",
 356                                        af->type,
 357                                        af->protocol,
 358                                        af->low,
 359                                        af->high,
 360                                        af->visible,
 361                                        af->hidden,
 362                                        ntohl(af->where),
 363                                        ntohl(af->lastcontact),
 364                                        af->ctlproto,
 365                                        af->ctlport,
 366                                        (af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies), 
 367                                        af->flags);
 368
 369                pos=begin+len;
 370                if(pos<offset) 
 371                {
 372                        len=0;
 373                        begin=pos;
 374                }
 375                if(pos>offset+length)
 376                        break;
 377        }
 378        *start=buffer+(offset-begin);
 379        len-=(offset-begin);
 380        if(len>length)
 381                len=length;
 382        return len;
 383}
 384
 385static struct proc_dir_entry autofw_proc_entry = {
 386                0, 0, NULL,
 387                S_IFREG | S_IRUGO, 1, 0, 0,
 388                0, &proc_net_inode_operations,
 389                autofw_procinfo
 390};
 391
 392#define proc_ent &autofw_proc_entry
 393#else /* !CONFIG_PROC_FS */
 394
 395#define proc_ent NULL
 396#endif
 397
 398
 399#define autofw_in_update NULL
 400#define autofw_out_rule NULL
 401#define autofw_mod_init NULL
 402#define autofw_mod_done NULL
 403
 404static struct ip_masq_mod autofw_mod = {
 405        NULL,                   /* next */
 406        NULL,                   /* next_reg */
 407        "autofw",               /* name */
 408        ATOMIC_INIT(0),         /* nent */
 409        ATOMIC_INIT(0),         /* refcnt */
 410        proc_ent,
 411        autofw_ctl,
 412        autofw_mod_init,
 413        autofw_mod_done,
 414        autofw_in_rule,
 415        autofw_in_update,
 416        autofw_in_create,
 417        autofw_out_rule,
 418        autofw_out_update,
 419        autofw_out_create,
 420};
 421
 422__initfunc(int ip_autofw_init(void))
 423{
 424        return register_ip_masq_mod ((mmod_self=&autofw_mod));
 425}
 426
 427int ip_autofw_done(void)
 428{
 429        return unregister_ip_masq_mod(&autofw_mod);
 430}
 431
 432#ifdef MODULE
 433EXPORT_NO_SYMBOLS;
 434
 435int init_module(void)
 436{
 437        if (ip_autofw_init() != 0)
 438                return -EIO;
 439        return 0;
 440}
 441
 442void cleanup_module(void)
 443{
 444        if (ip_autofw_done() != 0)
 445                printk(KERN_INFO "ip_autofw_done(): can't remove module");
 446}
 447
 448#endif /* MODULE */
 449
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.