linux-old/net/ipv4/ip_masq_vdolive.c
<<
>>
Prefs
   1/*
   2 *              IP_MASQ_VDOLIVE  - VDO Live masquerading module
   3 *
   4 *
   5 * Version:     @(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
   6 *
   7 * Author:      Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
   8 *              PLAnet Online Ltd
   9 *
  10 * Fixes:       Minor changes for 2.1 by
  11 *              Steven Clarke <Steven.Clarke@ThePlanet.Net>, Planet Online Ltd
  12 *
  13 *      This program is free software; you can redistribute it and/or
  14 *      modify it under the terms of the GNU General Public License
  15 *      as published by the Free Software Foundation; either version
  16 *      2 of the License, or (at your option) any later version.
  17 *
  18 * Thanks:
  19 *      Thank you to VDOnet Corporation for allowing me access to
  20 *      a protocol description without an NDA.  This means that
  21 *      this module can be distributed as source - a great help!
  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 <asm/system.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/ip_masq.h>
  37
  38struct vdolive_priv_data {
  39        /* Ports used */
  40        unsigned short  origport;
  41        unsigned short  masqport;
  42        /* State of decode */
  43        unsigned short  state;
  44};
  45
  46/* 
  47 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
  48 * First port is set to the default port.
  49 */
  50static int ports[MAX_MASQ_APP_PORTS] = {7000}; /* I rely on the trailing items being set to zero */
  51struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
  52
  53/*
  54 *     Debug level
  55 */
  56#ifdef CONFIG_IP_MASQ_DEBUG
  57static int debug=0;
  58MODULE_PARM(debug, "i");
  59#endif
  60
  61MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
  62
  63static int
  64masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
  65{
  66        MOD_INC_USE_COUNT;
  67        if ((ms->app_data = kmalloc(sizeof(struct vdolive_priv_data),
  68                                    GFP_ATOMIC)) == NULL) 
  69                IP_MASQ_DEBUG(1-debug, "VDOlive: No memory for application data\n");
  70        else 
  71        {
  72                struct vdolive_priv_data *priv = 
  73                        (struct vdolive_priv_data *)ms->app_data;
  74                priv->origport = 0;
  75                priv->masqport = 0;
  76                priv->state = 0;
  77        }
  78        return 0;
  79}
  80
  81static int
  82masq_vdolive_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
  83{
  84        MOD_DEC_USE_COUNT;
  85        if (ms->app_data)
  86                kfree_s(ms->app_data, sizeof(struct vdolive_priv_data));
  87        return 0;
  88}
  89
  90int
  91masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
  92{
  93        struct sk_buff *skb;
  94        struct iphdr *iph;
  95        struct tcphdr *th;
  96        char *data, *data_limit;
  97        unsigned int tagval;    /* This should be a 32 bit quantity */
  98        struct ip_masq *n_ms;
  99        struct vdolive_priv_data *priv = 
 100                (struct vdolive_priv_data *)ms->app_data;
 101
 102        /* This doesn't work at all if no priv data was allocated on startup */
 103        if (!priv)
 104                return 0;
 105
 106        /* Everything running correctly already */
 107        if (priv->state == 3)
 108                return 0;
 109
 110        skb = *skb_p;
 111        iph = skb->nh.iph;
 112        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 113        data = (char *)&th[1];
 114
 115        data_limit = skb->h.raw + skb->len;
 116
 117        if (data+8 > data_limit) {
 118                IP_MASQ_DEBUG(1-debug, "VDOlive: packet too short for ID %p %p\n", data, data_limit);
 119                return 0;
 120        }
 121        memcpy(&tagval, data+4, 4);
 122        IP_MASQ_DEBUG(1-debug, "VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
 123
 124        /* Check for leading packet ID */
 125        if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) {
 126                IP_MASQ_DEBUG(1-debug, "VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
 127                return 0;
 128        }
 129                
 130
 131        /* Check packet is long enough for data - ignore if not */
 132        if ((ntohl(tagval) == 6) && (data+36 > data_limit)) {
 133                IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet too short %p %p\n", data, data_limit);
 134                return 0;
 135        } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) {
 136                IP_MASQ_DEBUG(1-debug,"VDOlive: secondary packet too short %p %p\n", data, data_limit);
 137                return 0;
 138        }
 139
 140        /* Adjust data pointers */
 141        /*
 142         * I could check the complete protocol version tag 
 143         * in here however I am just going to look for the
 144         * "VDO Live" tag in the hope that this part will
 145         * remain constant even if the version changes
 146         */
 147        if (ntohl(tagval) == 6) {
 148                data += 24;
 149                IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet found\n");
 150        } else {
 151                data += 8;
 152                IP_MASQ_DEBUG(1-debug, "VDOlive: secondary packet found\n");
 153        }
 154
 155        if (memcmp(data, "VDO Live", 8) != 0) {
 156                IP_MASQ_DEBUG(1-debug,"VDOlive: did not find tag\n");
 157                return 0;
 158        }
 159        /* 
 160         * The port number is the next word after the tag.
 161         * VDOlive encodes all of these values
 162         * in 32 bit words, so in this case I am
 163         * skipping the first 2 bytes of the next
 164         * word to get to the relevant 16 bits
 165         */
 166        data += 10;
 167
 168        /*
 169         * If we have not seen the port already,
 170         * set the masquerading tunnel up
 171         */
 172        if (!priv->origport) {
 173                memcpy(&priv->origport, data, 2);
 174                IP_MASQ_DEBUG(1-debug, "VDOlive: found port %d\n", ntohs(priv->origport));
 175
 176                /* Open up a tunnel */
 177                n_ms = ip_masq_new(IPPROTO_UDP,
 178                                   maddr, 0,
 179                                   ms->saddr, priv->origport,
 180                                   ms->daddr, 0,
 181                                   IP_MASQ_F_NO_DPORT);
 182                                        
 183                if (n_ms==NULL) {
 184                        ip_masq_put(n_ms);
 185                        IP_MASQ_DEBUG(1-debug, "VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport);
 186                        /* Leave state as unset */
 187                        priv->origport = 0;
 188                        return 0;
 189                }
 190                ip_masq_listen(n_ms);
 191
 192                ip_masq_put(ms);
 193                priv->masqport = n_ms->mport;
 194        } else if (memcmp(data, &(priv->origport), 2)) {
 195                IP_MASQ_DEBUG(1-debug, "VDOlive: ports do not match\n");
 196                /* Write the port in anyhow!!! */
 197        }
 198
 199        /*
 200         * Write masq port into packet
 201         */
 202        memcpy(data, &(priv->masqport), 2);
 203        IP_MASQ_DEBUG(1-debug, "VDOlive: rewrote port %d to %d, server %08X\n", ntohs(priv->origport), ntohs(priv->masqport), ms->saddr);
 204
 205        /*
 206         * Set state bit to make which bit has been done
 207         */
 208
 209        priv->state |= (ntohl(tagval) == 6) ? 1 : 2;
 210
 211        return 0;
 212}
 213
 214
 215struct ip_masq_app ip_masq_vdolive = {
 216        NULL,                   /* next */
 217        "VDOlive",              /* name */
 218        0,                      /* type */
 219        0,                      /* n_attach */
 220        masq_vdolive_init_1,    /* ip_masq_init_1 */
 221        masq_vdolive_done_1,    /* ip_masq_done_1 */
 222        masq_vdolive_out,       /* pkt_out */
 223        NULL                    /* pkt_in */
 224};
 225
 226/*
 227 *      ip_masq_vdolive initialization
 228 */
 229
 230__initfunc(int ip_masq_vdolive_init(void))
 231{
 232        int i, j;
 233
 234        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
 235                if (ports[i]) {
 236                        if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
 237                                                            GFP_KERNEL)) == NULL)
 238                                return -ENOMEM;
 239                        memcpy(masq_incarnations[i], &ip_masq_vdolive, sizeof(struct ip_masq_app));
 240                        if ((j = register_ip_masq_app(masq_incarnations[i], 
 241                                                      IPPROTO_TCP, 
 242                                                      ports[i]))) {
 243                                return j;
 244                        }
 245                        IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n", i, ports[i]);
 246                } else {
 247                        /* To be safe, force the incarnation table entry to NULL */
 248                        masq_incarnations[i] = NULL;
 249                }
 250        }
 251        return 0;
 252}
 253
 254/*
 255 *      ip_masq_vdolive fin.
 256 */
 257
 258int ip_masq_vdolive_done(void)
 259{
 260        int i, j, k;
 261
 262        k=0;
 263        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
 264                if (masq_incarnations[i]) {
 265                        if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
 266                                k = j;
 267                        } else {
 268                                kfree(masq_incarnations[i]);
 269                                masq_incarnations[i] = NULL;
 270                                IP_MASQ_DEBUG(1-debug,"VDOlive: unloaded support on port[%d] = %d\n", i, ports[i]);
 271                        }
 272                }
 273        }
 274        return k;
 275}
 276
 277
 278#ifdef MODULE
 279EXPORT_NO_SYMBOLS;
 280
 281int init_module(void)
 282{
 283        if (ip_masq_vdolive_init() != 0)
 284                return -EIO;
 285        return 0;
 286}
 287
 288void cleanup_module(void)
 289{
 290        if (ip_masq_vdolive_done() != 0)
 291                IP_MASQ_DEBUG(1-debug, "ip_masq_vdolive: can't remove module");
 292}
 293
 294#endif /* MODULE */
 295
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.