linux-old/net/ipv4/ip_masq_raudio.c
<<
>>
Prefs
   1/*
   2 *              IP_MASQ_RAUDIO  - Real Audio masquerading module
   3 *
   4 *
   5 * Version:     @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
   6 *
   7 * Author:      Nigel Metheringham
   8 *              Real Time Streaming code by Progressive Networks
   9 *              [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
  10 *              [Real Audio information taken from Progressive Networks firewall docs]
  11 *              [Kudos to Progressive Networks for making the protocol specs available]
  12 *
  13 *
  14 *
  15 *
  16 *      This program is free software; you can redistribute it and/or
  17 *      modify it under the terms of the GNU General Public License
  18 *      as published by the Free Software Foundation; either version
  19 *      2 of the License, or (at your option) any later version.
  20 *
  21 *
  22 * Limitations
  23 *      The IP Masquerading proxies at present do not have access to a processed
  24 *      data stream.  Hence for a protocol like the Real Audio control protocol,
  25 *      which depends on knowing where you are in the data stream, you either
  26 *      to keep a *lot* of state in your proxy, or you cheat and simplify the
  27 *      problem [needless to say I did the latter].
  28 *
  29 *      This proxy only handles data in the first packet.  Everything else is
  30 *      passed transparently.  This means it should work under all normal
  31 *      circumstances, but it could be fooled by new data formats or a
  32 *      malicious application!
  33 *
  34 *      At present the "first packet" is defined as a packet starting with
  35 *      the protocol ID string - "PNA".
  36 *      When the link is up there appears to be enough control data 
  37 *      crossing the control link to keep it open even if a long audio
  38 *      piece is playing.
  39 *
  40 *      The Robust UDP support added in RealAudio 3.0 is supported, but due
  41 *      to servers/clients not making great use of this has not been greatly
  42 *      tested.  RealVideo (as used in the Real client version 4.0beta1) is
  43 *      supported but again is not greatly tested (bandwidth requirements
  44 *      appear to exceed that available at the sites supporting the protocol).
  45 *
  46 * Multiple Port Support
  47 *      The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
  48 *      with the port numbers being defined at module load time.  The module
  49 *      uses the symbol "ports" to define a list of monitored ports, which can
  50 *      be specified on the insmod command line as
  51 *              ports=x1,x2,x3...
  52 *      where x[n] are integer port numbers.  This option can be put into
  53 *      /etc/conf.modules (or /etc/modules.conf depending on your config)
  54 *      where modload will pick it up should you use modload to load your
  55 *      modules.
  56 *
  57 * Fixes:
  58 *      Juan Jose Ciarlante     :       Use control_add() for control chan
  59 *      10/15/97 - Modifications to allow masquerading of RTSP connections as
  60 *              well as PNA, which can potentially exist on the same port.
  61 *              Joe Rumsey <ogre@real.com>
  62 *      
  63 */
  64
  65#include <linux/config.h>
  66#include <linux/module.h>
  67#include <asm/system.h>
  68#include <linux/types.h>
  69#include <linux/ctype.h>
  70#include <linux/kernel.h>
  71#include <linux/skbuff.h>
  72#include <linux/in.h>
  73#include <linux/ip.h>
  74#include <linux/init.h>
  75#include <net/protocol.h>
  76#include <net/tcp.h>
  77#include <net/ip_masq.h>
  78
  79/*
  80#ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO
  81#define DEBUG_CONFIG_IP_MASQ_RAUDIO 0
  82#endif
  83*/
  84
  85#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c))
  86#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
  87
  88struct raudio_priv_data {
  89        /* Associated data connection - setup but not used at present */
  90        struct  ip_masq *data_conn;
  91        /* UDP Error correction connection - setup but not used at present */
  92        struct  ip_masq *error_conn;
  93        /* Have we seen and performed setup */
  94        short   seen_start;
  95        short   is_rtsp;
  96};
  97
  98int
  99masq_rtsp_out (struct ip_masq_app *mapp, 
 100                 struct ip_masq *ms, 
 101                 struct sk_buff **skb_p, 
 102                 __u32 maddr);
 103
 104/* 
 105 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
 106 * First port is set to the default port.
 107 */
 108int ports[MAX_MASQ_APP_PORTS] = {554, 7070, 0}; /* I rely on the trailing items being set to zero */
 109struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 110
 111/*
 112 *      Debug level
 113 */
 114#ifdef CONFIG_IP_MASQ_DEBUG
 115static int debug=0;
 116MODULE_PARM(debug, "i");
 117#endif
 118
 119MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
 120
 121
 122static int
 123masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
 124{
 125        MOD_INC_USE_COUNT;
 126        if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data),
 127                                    GFP_ATOMIC)) == NULL) 
 128                printk(KERN_INFO "RealAudio: No memory for application data\n");
 129        else 
 130        {
 131                struct raudio_priv_data *priv = 
 132                        (struct raudio_priv_data *)ms->app_data;
 133                priv->seen_start = 0;
 134                priv->data_conn = NULL;
 135                priv->error_conn = NULL;
 136                priv->is_rtsp = 0;
 137        }
 138        return 0;
 139}
 140
 141static int
 142masq_raudio_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
 143{
 144        MOD_DEC_USE_COUNT;
 145        if (ms->app_data)
 146                kfree_s(ms->app_data, sizeof(struct raudio_priv_data));
 147        return 0;
 148}
 149
 150int
 151masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
 152{
 153        struct sk_buff *skb;
 154        struct iphdr *iph;
 155        struct tcphdr *th;
 156        char *p, *data, *data_limit;
 157        struct ip_masq *n_ms;
 158        unsigned short version, msg_id, msg_len, udp_port;
 159        struct raudio_priv_data *priv = 
 160                (struct raudio_priv_data *)ms->app_data;
 161
 162        /* Everything running correctly already */
 163        if (priv && priv->seen_start)
 164                return 0;
 165
 166        if(priv && priv->is_rtsp)
 167            return masq_rtsp_out(mapp, ms, skb_p, maddr);
 168
 169        skb = *skb_p;
 170        iph = skb->nh.iph;
 171        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 172        data = (char *)&th[1];
 173
 174        data_limit = skb->h.raw + skb->len;
 175
 176        if(memcmp(data, "OPTIONS", 7) == 0 ||
 177           memcmp(data, "DESCRIBE", 8) == 0)
 178        {
 179            IP_MASQ_DEBUG(1-debug, "RealAudio: Detected RTSP connection\n");
 180            /* This is an RTSP client */
 181            if(priv)
 182                priv->is_rtsp = 1;
 183            return masq_rtsp_out(mapp, ms, skb_p, maddr);
 184        }
 185
 186        /* Check to see if this is the first packet with protocol ID */
 187        if (memcmp(data, "PNA", 3)) {
 188                IP_MASQ_DEBUG(1-debug, "RealAudio: not initial protocol packet - ignored\n");
 189                return(0);
 190        }
 191        data += 3;
 192        memcpy(&version, data, 2);
 193
 194        IP_MASQ_DEBUG(1-debug, "RealAudio: initial seen - protocol version %d\n",
 195               ntohs(version));
 196        if (priv)
 197                priv->seen_start = 1;
 198
 199        if (ntohs(version) >= 256)
 200        {
 201                printk(KERN_INFO "RealAudio: version (%d) not supported\n",
 202                       ntohs(version));
 203                return 0;
 204        }
 205
 206        data += 2;
 207        while (data+4 < data_limit) {
 208                memcpy(&msg_id, data, 2);
 209                data += 2;
 210                memcpy(&msg_len, data, 2);
 211                data += 2;
 212                if (ntohs(msg_id) == 0) {
 213                        /* The zero tag indicates the end of options */
 214                        IP_MASQ_DEBUG(1-debug, "RealAudio: packet end tag seen\n");
 215                        return 0;
 216                }
 217                IP_MASQ_DEBUG(1-debug, "RealAudio: msg %d - %d byte\n",
 218                       ntohs(msg_id), ntohs(msg_len));
 219                if (ntohs(msg_id) == 0) {
 220                        /* The zero tag indicates the end of options */
 221                        return 0;
 222                }
 223                p = data;
 224                data += ntohs(msg_len);
 225                if (data > data_limit)
 226                {
 227                        printk(KERN_INFO "RealAudio: Packet too short for data\n");
 228                        return 0;
 229                }
 230                if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
 231                        /* 
 232                         * MsgId == 1
 233                         * Audio UDP data port on client
 234                         *
 235                         * MsgId == 7
 236                         * Robust UDP error correction port number on client
 237                         *
 238                         * Since these messages are treated just the same, they
 239                         * are bundled together here....
 240                         */
 241                        memcpy(&udp_port, p, 2);
 242
 243                        /* 
 244                         * Sometimes a server sends a message 7 with a zero UDP port
 245                         * Rather than do anything with this, just ignore it!
 246                         */
 247                        if (udp_port == 0)
 248                                continue;
 249
 250
 251                        n_ms = ip_masq_new(IPPROTO_UDP,
 252                                                maddr, 0,
 253                                                ms->saddr, udp_port,
 254                                                ms->daddr, 0,
 255                                                IP_MASQ_F_NO_DPORT);
 256
 257                        if (n_ms==NULL)
 258                                return 0;
 259
 260                        ip_masq_listen(n_ms);
 261                        ip_masq_control_add(n_ms, ms);
 262
 263                        memcpy(p, &(n_ms->mport), 2);
 264                        IP_MASQ_DEBUG(1-debug, "RealAudio: rewrote UDP port %d -> %d in msg %d\n",
 265                               ntohs(udp_port), ntohs(n_ms->mport), ntohs(msg_id));
 266
 267                        /* Make ref in application data to data connection */
 268                        if (priv) {
 269                                if (ntohs(msg_id) == 1)
 270                                        priv->data_conn = n_ms;
 271                                else
 272                                        priv->error_conn = n_ms;
 273                        }
 274                        
 275                        ip_masq_put(n_ms);
 276                }
 277        }
 278        return 0;
 279}
 280
 281/*
 282 * masq_rtsp_out
 283 *
 284 * 
 285 */
 286int
 287masq_rtsp_out (struct ip_masq_app *mapp, 
 288                 struct ip_masq *ms, 
 289                 struct sk_buff **skb_p, 
 290                 __u32 maddr)
 291{
 292        struct sk_buff *skb;
 293        struct iphdr *iph;
 294        struct tcphdr *th;
 295        char *data, *data_limit;
 296        struct ip_masq *n_ms, *n_ms2;
 297        unsigned short udp_port;
 298        struct raudio_priv_data *priv = 
 299                (struct raudio_priv_data *)ms->app_data;
 300        const char* srch = "transport:";
 301        const char* srchpos = srch;
 302        const char* srchend = srch + strlen(srch);
 303        int state = 0;
 304        char firstport[6];
 305        int firstportpos = 0;
 306        char secondport[6];
 307        int secondportpos = 0;
 308        char *portstart = NULL, *portend = NULL;
 309        int diff;
 310
 311        /* Everything running correctly already */
 312        if (priv && priv->seen_start)
 313                return 0;
 314
 315        skb = *skb_p;
 316        iph = skb->nh.iph;
 317        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 318        data = (char *)&th[1];
 319
 320        data_limit = skb->h.raw + skb->len;
 321
 322        firstport[0] = 0;
 323        secondport[0] = 0;
 324
 325        while(data < data_limit && state >= 0)
 326        {
 327            switch(state)
 328            {
 329                case 0:
 330                case 1:
 331                    if(TOLOWER(*data) == *srchpos)
 332                    {
 333                        srchpos++;
 334                        if(srchpos == srchend)
 335                        {
 336                            IP_MASQ_DEBUG(1-debug, "Found string %s in message\n",
 337                                   srch);
 338                            state++;
 339                            if(state == 1)
 340                            {
 341                                srch = "client_port";
 342                                srchpos = srch;
 343                                srchend = srch + strlen(srch);
 344                            }
 345                        }
 346                    }
 347                    else
 348                    {
 349                        srchpos = srch;
 350                    }
 351                    break;
 352                case 2:
 353                    if(*data == '=')
 354                        state = 3;
 355                    break;
 356                case 3:
 357                    if(ISDIGIT(*data))
 358                    {
 359                        portstart = data;
 360                        firstportpos = 0;
 361                        firstport[firstportpos++] = *data;
 362                        state = 4;
 363                    }
 364                    break;
 365                case 4:
 366                    if(*data == '-')
 367                    {
 368                        state = 5;
 369                    }
 370                    else if(*data == ';')
 371                    {
 372                        portend = data - 1;
 373                        firstport[firstportpos] = 0;
 374                        state = -1;
 375                    }
 376                    else if(ISDIGIT(*data))
 377                    {
 378                        firstport[firstportpos++] = *data;
 379                    }
 380                    else if(*data != ' ' && *data != '\t')
 381                    {
 382                        /* This is a badly formed RTSP message, let's bail out */
 383                        IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
 384                        return 0;
 385                    }
 386                    break;
 387                case 5:
 388                    if(ISDIGIT(*data))
 389                    {
 390                        secondportpos = 0;
 391                        secondport[secondportpos++] = *data;
 392                        state = 6;
 393                    }
 394                    else if(*data == ';')
 395                    {
 396                        portend = data - 1;
 397                        secondport[secondportpos] = 0;
 398                        state = -1;
 399                    }
 400                    break;
 401                case 6:
 402                    if(*data == ';')
 403                    {
 404                        portend = data - 1;
 405                        secondport[secondportpos] = 0;
 406                        state = -1;
 407                    }
 408                    else if(ISDIGIT(*data))
 409                    {
 410                        secondport[secondportpos++] = *data;
 411                    }
 412                    else if(*data != ' ' && *data != '\t')
 413                    {
 414                        /* This is a badly formed RTSP message, let's bail out */
 415                        IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
 416                        return 0;
 417                    }
 418                    break;
 419            }
 420            data++;
 421        }
 422
 423        if(state >= 0)
 424            return 0;
 425
 426        if(firstportpos > 0)
 427        {
 428            char newbuf[12]; /* xxxxx-xxxxx\0 */
 429            char* tmpptr;
 430
 431            udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
 432            n_ms = ip_masq_new(IPPROTO_UDP,
 433                               maddr, 0,
 434                               ms->saddr, udp_port,
 435                               ms->daddr, 0,
 436                               IP_MASQ_F_NO_DPORT);
 437            if (n_ms==NULL)
 438                return 0;
 439            
 440            ip_masq_listen(n_ms);
 441            ip_masq_control_add(n_ms, ms);
 442
 443            if(secondportpos > 0)
 444            {
 445                udp_port = htons(simple_strtoul(secondport, &tmpptr, 10));
 446                n_ms2 = ip_masq_new(IPPROTO_UDP,
 447                                maddr, 0,
 448                                ms->saddr, udp_port,
 449                                ms->daddr, 0,
 450                                IP_MASQ_F_NO_DPORT);
 451                if (n_ms2==NULL) {
 452                    ip_masq_put(n_ms);
 453                    return 0;
 454                }
 455
 456                ip_masq_listen(n_ms2);
 457                ip_masq_control_add(n_ms2, ms);
 458                sprintf(newbuf, "%d-%d", ntohs(n_ms->mport), 
 459                        ntohs(n_ms2->mport));
 460            }
 461            else
 462            {
 463                sprintf(newbuf, "%d", ntohs(n_ms->mport));
 464                n_ms2 = NULL;
 465            }
 466            *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
 467                                         portstart, portend - portstart + 1,
 468                                         newbuf, strlen(newbuf));
 469            IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
 470            diff = strlen(newbuf) - (portend - portstart);
 471        }
 472        else
 473        {
 474            return 0;
 475        }
 476            
 477        if(priv)
 478        {
 479            priv->seen_start = 1;
 480            if(n_ms)
 481                priv->data_conn = n_ms;
 482            if(n_ms2)
 483                priv->error_conn = n_ms2;
 484        }
 485        /*
 486         *      Release tunnels
 487         */
 488
 489        if (n_ms)
 490                ip_masq_put(n_ms);
 491
 492        if (n_ms2)
 493                ip_masq_put(n_ms2);
 494
 495        return diff;
 496}
 497
 498struct ip_masq_app ip_masq_raudio = {
 499        NULL,                   /* next */
 500        "RealAudio",            /* name */
 501        0,                      /* type */
 502        0,                      /* n_attach */
 503        masq_raudio_init_1,     /* ip_masq_init_1 */
 504        masq_raudio_done_1,     /* ip_masq_done_1 */
 505        masq_raudio_out,        /* pkt_out */
 506        NULL                    /* pkt_in */
 507};
 508
 509/*
 510 *      ip_masq_raudio initialization
 511 */
 512
 513__initfunc(int ip_masq_raudio_init(void))
 514{
 515        int i, j;
 516
 517        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
 518                if (ports[i]) {
 519                        if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
 520                                                            GFP_KERNEL)) == NULL)
 521                                return -ENOMEM;
 522                        memcpy(masq_incarnations[i], &ip_masq_raudio, sizeof(struct ip_masq_app));
 523                        if ((j = register_ip_masq_app(masq_incarnations[i], 
 524                                                      IPPROTO_TCP, 
 525                                                      ports[i]))) {
 526                                return j;
 527                        }
 528                        IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n",
 529                               i, ports[i]);
 530                } else {
 531                        /* To be safe, force the incarnation table entry to NULL */
 532                        masq_incarnations[i] = NULL;
 533                }
 534        }
 535        return 0;
 536}
 537
 538/*
 539 *      ip_masq_raudio fin.
 540 */
 541
 542int ip_masq_raudio_done(void)
 543{
 544        int i, j, k;
 545
 546        k=0;
 547        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
 548                if (masq_incarnations[i]) {
 549                        if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
 550                                k = j;
 551                        } else {
 552                                kfree(masq_incarnations[i]);
 553                                masq_incarnations[i] = NULL;
 554                                IP_MASQ_DEBUG(1-debug, "RealAudio: unloaded support on port[%d] = %d\n",
 555                                       i, ports[i]);
 556                        }
 557                }
 558        }
 559        return k;
 560}
 561
 562#ifdef MODULE
 563EXPORT_NO_SYMBOLS;
 564
 565int init_module(void)
 566{
 567        if (ip_masq_raudio_init() != 0)
 568                return -EIO;
 569        return 0;
 570}
 571
 572void cleanup_module(void)
 573{
 574        if (ip_masq_raudio_done() != 0)
 575                printk(KERN_INFO "ip_masq_raudio: can't remove module");
 576}
 577
 578#endif /* MODULE */
 579
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.