/* HINT: Search archives @ http://www.indyramp.com/masq/ before posting! */


I was told to send this here.
  This is a patch (and the modified file for those who don't like patches)
that is applied to:
        linux/net/ipv4/ip_masq_raudio.c
for kernel versions 2.2.10 and up.

  This will make your firewall correctly masquerade Quicktime 4 (and
possibly other RTSP connections) as well as real audio.

Please send me comments and suggestions.



*** ip_masq_raudio.c.orig       Sun Jun 27 22:34:12 1999
--- ip_masq_raudio.c    Sat Aug  7 02:38:25 1999
***************
*** 367,373 ****
                    {
                        state = 5;
                    }
!                   else if(*data == ';')
                    {
                        portend = data - 1;
                        firstport[firstportpos] = 0;
--- 367,373 ----
                    {
                        state = 5;
                    }
!                   else if((*data == ';') || (*data == '\r') || (*data == '\n'))
                    {
                        portend = data - 1;
                        firstport[firstportpos] = 0;
***************
*** 399,405 ****
                    }
                    break;
                case 6:
!                   if(*data == ';')
                    {
                        portend = data - 1;
                        secondport[secondportpos] = 0;
--- 399,405 ----
                    }
                    break;
                case 6:
!                 if ((*data == ';') || (*data == '\r') || (*data == '\n'))
                    {
                        portend = data - 1;
                        secondport[secondportpos] = 0;
***************
*** 429,441 ****
            char* tmpptr;
  
            udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
!           n_ms = ip_masq_new(IPPROTO_UDP,
!                              maddr, 0,
!                              ms->saddr, udp_port,
!                              ms->daddr, 0,
!                              IP_MASQ_F_NO_DPORT);
!           if (n_ms==NULL)
                return 0;
            
            ip_masq_listen(n_ms);
            ip_masq_control_add(n_ms, ms);
--- 429,444 ----
            char* tmpptr;
  
            udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
!           /* port must be even for apple -- is this a leak? */
!           do {
!             n_ms = ip_masq_new(IPPROTO_UDP,
!                                maddr, 0,
!                                ms->saddr, udp_port,
!                                ms->daddr, 0,
!                                IP_MASQ_F_NO_DPORT);
!             if (n_ms==NULL)
                return 0;
+           } while (ntohs(n_ms->mport) & 1);  
            
            ip_masq_listen(n_ms);
            ip_masq_control_add(n_ms, ms);
***************
*** 467,473 ****
                                         portstart, portend - portstart + 1,
                                         newbuf, strlen(newbuf));
            IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
!           diff = strlen(newbuf) - (portend - portstart);
        }
        else
        {
--- 470,476 ----
                                         portstart, portend - portstart + 1,
                                         newbuf, strlen(newbuf));
            IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
!           diff = strlen(newbuf) - (portend - portstart + 1);
        }
        else
        {
***************
*** 476,482 ****
            
        if(priv)
        {
!           priv->seen_start = 1;
            if(n_ms)
                priv->data_conn = n_ms;
            if(n_ms2)
--- 479,487 ----
            
        if(priv)
        {
!         /* priv->seen_start = 1; */
!         /* we have multiple streams to worry about, and redirects */
!         /* so we will be slower, but at least we'll work */
            if(n_ms)
                priv->data_conn = n_ms;
            if(n_ms2)


/*
 *              IP_MASQ_RAUDIO  - Real Audio masquerading module
 *
 *
 * Version:     @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
 *
 * Author:      Nigel Metheringham
 *              Real Time Streaming code by Progressive Networks
 *              [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
 *              [Real Audio information taken from Progressive Networks firewall docs]
 *              [Kudos to Progressive Networks for making the protocol specs available]
 *
 *
 *
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 *
 *
 * Limitations
 *      The IP Masquerading proxies at present do not have access to a processed
 *      data stream.  Hence for a protocol like the Real Audio control protocol,
 *      which depends on knowing where you are in the data stream, you either
 *      to keep a *lot* of state in your proxy, or you cheat and simplify the
 *      problem [needless to say I did the latter].
 *
 *      This proxy only handles data in the first packet.  Everything else is
 *      passed transparently.  This means it should work under all normal
 *      circumstances, but it could be fooled by new data formats or a
 *      malicious application!
 *
 *      At present the "first packet" is defined as a packet starting with
 *      the protocol ID string - "PNA".
 *      When the link is up there appears to be enough control data 
 *      crossing the control link to keep it open even if a long audio
 *      piece is playing.
 *
 *      The Robust UDP support added in RealAudio 3.0 is supported, but due
 *      to servers/clients not making great use of this has not been greatly
 *      tested.  RealVideo (as used in the Real client version 4.0beta1) is
 *      supported but again is not greatly tested (bandwidth requirements
 *      appear to exceed that available at the sites supporting the protocol).
 *
 * Multiple Port Support
 *      The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
 *      with the port numbers being defined at module load time.  The module
 *      uses the symbol "ports" to define a list of monitored ports, which can
 *      be specified on the insmod command line as
 *              ports=x1,x2,x3...
 *      where x[n] are integer port numbers.  This option can be put into
 *      /etc/conf.modules (or /etc/modules.conf depending on your config)
 *      where modload will pick it up should you use modload to load your
 *      modules.
 *
 * Fixes:
 *      Juan Jose Ciarlante     :       Use control_add() for control chan
 *      10/15/97 - Modifications to allow masquerading of RTSP connections as
 *              well as PNA, which can potentially exist on the same port.
 *              Joe Rumsey <[EMAIL PROTECTED]>
 *      
 */

#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/init.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/ip_masq.h>

/*
#ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO
#define DEBUG_CONFIG_IP_MASQ_RAUDIO 0
#endif
*/

#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c))
#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))

struct raudio_priv_data {
        /* Associated data connection - setup but not used at present */
        struct  ip_masq *data_conn;
        /* UDP Error correction connection - setup but not used at present */
        struct  ip_masq *error_conn;
        /* Have we seen and performed setup */
        short   seen_start;
        short   is_rtsp;
};

int
masq_rtsp_out (struct ip_masq_app *mapp, 
                 struct ip_masq *ms, 
                 struct sk_buff **skb_p, 
                 __u32 maddr);

/* 
 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
 * First port is set to the default port.
 */
int ports[MAX_MASQ_APP_PORTS] = {554, 7070, 0}; /* I rely on the trailing items being 
set to zero */
struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];

/*
 *      Debug level
 */
#ifdef CONFIG_IP_MASQ_DEBUG
static int debug=0;
MODULE_PARM(debug, "i");
#endif

MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");


static int
masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
{
        MOD_INC_USE_COUNT;
        if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data),
                                    GFP_ATOMIC)) == NULL) 
                printk(KERN_INFO "RealAudio: No memory for application data\n");
        else 
        {
                struct raudio_priv_data *priv = 
                        (struct raudio_priv_data *)ms->app_data;
                priv->seen_start = 0;
                priv->data_conn = NULL;
                priv->error_conn = NULL;
                priv->is_rtsp = 0;
        }
        return 0;
}

static int
masq_raudio_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
{
        MOD_DEC_USE_COUNT;
        if (ms->app_data)
                kfree_s(ms->app_data, sizeof(struct raudio_priv_data));
        return 0;
}

int
masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, 
__u32 maddr)
{
        struct sk_buff *skb;
        struct iphdr *iph;
        struct tcphdr *th;
        char *p, *data, *data_limit;
        struct ip_masq *n_ms;
        unsigned short version, msg_id, msg_len, udp_port;
        struct raudio_priv_data *priv = 
                (struct raudio_priv_data *)ms->app_data;

        /* Everything running correctly already */
        if (priv && priv->seen_start)
                return 0;

        if(priv && priv->is_rtsp)
            return masq_rtsp_out(mapp, ms, skb_p, maddr);

        skb = *skb_p;
        iph = skb->nh.iph;
        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
        data = (char *)&th[1];

        data_limit = skb->h.raw + skb->len;

        if(memcmp(data, "OPTIONS", 7) == 0 ||
           memcmp(data, "DESCRIBE", 8) == 0)
        {
            IP_MASQ_DEBUG(1-debug, "RealAudio: Detected RTSP connection\n");
            /* This is an RTSP client */
            if(priv)
                priv->is_rtsp = 1;
            return masq_rtsp_out(mapp, ms, skb_p, maddr);
        }

        /* Check to see if this is the first packet with protocol ID */
        if (memcmp(data, "PNA", 3)) {
                IP_MASQ_DEBUG(1-debug, "RealAudio: not initial protocol packet - 
ignored\n");
                return(0);
        }
        data += 3;
        memcpy(&version, data, 2);

        IP_MASQ_DEBUG(1-debug, "RealAudio: initial seen - protocol version %d\n",
               ntohs(version));
        if (priv)
                priv->seen_start = 1;

        if (ntohs(version) >= 256)
        {
                printk(KERN_INFO "RealAudio: version (%d) not supported\n",
                       ntohs(version));
                return 0;
        }

        data += 2;
        while (data+4 < data_limit) {
                memcpy(&msg_id, data, 2);
                data += 2;
                memcpy(&msg_len, data, 2);
                data += 2;
                if (ntohs(msg_id) == 0) {
                        /* The zero tag indicates the end of options */
                        IP_MASQ_DEBUG(1-debug, "RealAudio: packet end tag seen\n");
                        return 0;
                }
                IP_MASQ_DEBUG(1-debug, "RealAudio: msg %d - %d byte\n",
                       ntohs(msg_id), ntohs(msg_len));
                if (ntohs(msg_id) == 0) {
                        /* The zero tag indicates the end of options */
                        return 0;
                }
                p = data;
                data += ntohs(msg_len);
                if (data > data_limit)
                {
                        printk(KERN_INFO "RealAudio: Packet too short for data\n");
                        return 0;
                }
        if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
                        /* 
                         * MsgId == 1
                         * Audio UDP data port on client
                         *
                         * MsgId == 7
                         * Robust UDP error correction port number on client
                         *
                         * Since these messages are treated just the same, they
                         * are bundled together here....
                         */
                        memcpy(&udp_port, p, 2);

                        /* 
                         * Sometimes a server sends a message 7 with a zero UDP port
                         * Rather than do anything with this, just ignore it!
                         */
                        if (udp_port == 0)
                                continue;


                        n_ms = ip_masq_new(IPPROTO_UDP,
                                                maddr, 0,
                                                ms->saddr, udp_port,
                                                ms->daddr, 0,
                                                IP_MASQ_F_NO_DPORT);

                        if (n_ms==NULL)
                                return 0;

                        ip_masq_listen(n_ms);
                        ip_masq_control_add(n_ms, ms);

                        memcpy(p, &(n_ms->mport), 2);
                        IP_MASQ_DEBUG(1-debug, "RealAudio: rewrote UDP port %d -> %d 
in msg %d\n",
                               ntohs(udp_port), ntohs(n_ms->mport), ntohs(msg_id));

                        /* Make ref in application data to data connection */
                        if (priv) {
                                if (ntohs(msg_id) == 1)
                                        priv->data_conn = n_ms;
                                else
                                        priv->error_conn = n_ms;
                        }
                        
                        ip_masq_put(n_ms);
                }
        }
        return 0;
}

/*
 * masq_rtsp_out
 *
 * 
 */
int
masq_rtsp_out (struct ip_masq_app *mapp, 
                 struct ip_masq *ms, 
                 struct sk_buff **skb_p, 
                 __u32 maddr)
{
        struct sk_buff *skb;
        struct iphdr *iph;
        struct tcphdr *th;
        char *data, *data_limit;
        struct ip_masq *n_ms, *n_ms2;
        unsigned short udp_port;
        struct raudio_priv_data *priv = 
                (struct raudio_priv_data *)ms->app_data;
        const char* srch = "transport:";
        const char* srchpos = srch;
        const char* srchend = srch + strlen(srch);
        int state = 0;
        char firstport[6];
        int firstportpos = 0;
        char secondport[6];
        int secondportpos = 0;
        char *portstart = NULL, *portend = NULL;
        int diff;

        /* Everything running correctly already */
        if (priv && priv->seen_start)
                return 0;

        skb = *skb_p;
        iph = skb->nh.iph;
        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
        data = (char *)&th[1];

        data_limit = skb->h.raw + skb->len;

        firstport[0] = 0;
        secondport[0] = 0;

        while(data < data_limit && state >= 0)
        {
            switch(state)
            {
                case 0:
                case 1:
                    if(TOLOWER(*data) == *srchpos)
                    {
                        srchpos++;
                        if(srchpos == srchend)
                        {
                            IP_MASQ_DEBUG(1-debug, "Found string %s in message\n",
                                   srch);
                            state++;
                            if(state == 1)
                            {
                                srch = "client_port";
                                srchpos = srch;
                                srchend = srch + strlen(srch);
                            }
                        }
                    }
                    else
                    {
                        srchpos = srch;
                    }
                    break;
                case 2:
                    if(*data == '=')
                        state = 3;
                    break;
                case 3:
                    if(ISDIGIT(*data))
                    {
                        portstart = data;
                        firstportpos = 0;
                        firstport[firstportpos++] = *data;
                        state = 4;
                    }
                    break;
                case 4:
                    if(*data == '-')
                    {
                        state = 5;
                    }
                    else if((*data == ';') || (*data == '\r') || (*data == '\n'))
                    {
                        portend = data - 1;
                        firstport[firstportpos] = 0;
                        state = -1;
                    }
                    else if(ISDIGIT(*data))
                    {
                        firstport[firstportpos++] = *data;
                    }
                    else if(*data != ' ' && *data != '\t')
                    {
                        /* This is a badly formed RTSP message, let's bail out */
                        IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
                        return 0;
                    }
                    break;
                case 5:
                    if(ISDIGIT(*data))
                    {
                        secondportpos = 0;
                        secondport[secondportpos++] = *data;
                        state = 6;
                    }
                    else if(*data == ';')
                    {
                        portend = data - 1;
                        secondport[secondportpos] = 0;
                        state = -1;
                    }
                    break;
                case 6:
                  if ((*data == ';') || (*data == '\r') || (*data == '\n'))
                    {
                        portend = data - 1;
                        secondport[secondportpos] = 0;
                        state = -1;
                    }
                    else if(ISDIGIT(*data))
                    {
                        secondport[secondportpos++] = *data;
                    }
                    else if(*data != ' ' && *data != '\t')
                    {
                        /* This is a badly formed RTSP message, let's bail out */
                        IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
                        return 0;
                    }
                    break;
            }
            data++;
        }

        if(state >= 0)
            return 0;

        if(firstportpos > 0)
        {
            char newbuf[12]; /* xxxxx-xxxxx\0 */
            char* tmpptr;

            udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
            /* port must be even for apple -- is this a leak? */
            do {
              n_ms = ip_masq_new(IPPROTO_UDP,
                                 maddr, 0,
                                 ms->saddr, udp_port,
                                 ms->daddr, 0,
                                 IP_MASQ_F_NO_DPORT);
              if (n_ms==NULL)
                return 0;
            } while (ntohs(n_ms->mport) & 1);  
            
            ip_masq_listen(n_ms);
            ip_masq_control_add(n_ms, ms);

            if(secondportpos > 0)
            {
                udp_port = htons(simple_strtoul(secondport, &tmpptr, 10));
                n_ms2 = ip_masq_new(IPPROTO_UDP,
                                    maddr, 0,
                                    ms->saddr, udp_port,
                                    ms->daddr, 0,
                                    IP_MASQ_F_NO_DPORT);
                if (n_ms2==NULL) {
                  ip_masq_put(n_ms);
                  return 0;
                }

                ip_masq_listen(n_ms2);
                ip_masq_control_add(n_ms2, ms);
                sprintf(newbuf, "%d-%d", ntohs(n_ms->mport), 
                        ntohs(n_ms2->mport));
            }
            else
            {
                sprintf(newbuf, "%d", ntohs(n_ms->mport));
                n_ms2 = NULL;
            }
            *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
                                         portstart, portend - portstart + 1,
                                         newbuf, strlen(newbuf));
            IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
            diff = strlen(newbuf) - (portend - portstart + 1);
        }
        else
        {
            return 0;
        }
            
        if(priv)
        {
          /* priv->seen_start = 1; */
          /* we have multiple streams to worry about, and redirects */
          /* so we will be slower, but at least we'll work */
            if(n_ms)
                priv->data_conn = n_ms;
            if(n_ms2)
                priv->error_conn = n_ms2;
        }
        /*
         *      Release tunnels
         */

        if (n_ms)
                ip_masq_put(n_ms);

        if (n_ms2)
                ip_masq_put(n_ms2);

        return diff;
}

struct ip_masq_app ip_masq_raudio = {
        NULL,                   /* next */
        "RealAudio",            /* name */
        0,                      /* type */
        0,                      /* n_attach */
        masq_raudio_init_1,     /* ip_masq_init_1 */
        masq_raudio_done_1,     /* ip_masq_done_1 */
        masq_raudio_out,        /* pkt_out */
        NULL                    /* pkt_in */
};

/*
 *      ip_masq_raudio initialization
 */

__initfunc(int ip_masq_raudio_init(void))
{
        int i, j;

        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
                if (ports[i]) {
                        if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
                                                            GFP_KERNEL)) == NULL)
                                return -ENOMEM;
                        memcpy(masq_incarnations[i], &ip_masq_raudio, sizeof(struct 
ip_masq_app));
                        if ((j = register_ip_masq_app(masq_incarnations[i], 
                                                      IPPROTO_TCP, 
                                                      ports[i]))) {
                                return j;
                        }
                        IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] 
= %d\n",
                               i, ports[i]);
                } else {
                        /* To be safe, force the incarnation table entry to NULL */
                        masq_incarnations[i] = NULL;
                }
        }
        return 0;
}

/*
 *      ip_masq_raudio fin.
 */

int ip_masq_raudio_done(void)
{
        int i, j, k;

        k=0;
        for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
                if (masq_incarnations[i]) {
                        if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
                                k = j;
                        } else {
                                kfree(masq_incarnations[i]);
                                masq_incarnations[i] = NULL;
                                IP_MASQ_DEBUG(1-debug, "RealAudio: unloaded support on 
port[%d] = %d\n",
                                       i, ports[i]);
                        }
                }
        }
        return k;
}

#ifdef MODULE
EXPORT_NO_SYMBOLS;

int init_module(void)
{
        if (ip_masq_raudio_init() != 0)
                return -EIO;
        return 0;
}

void cleanup_module(void)
{
        if (ip_masq_raudio_done() != 0)
                printk(KERN_INFO "ip_masq_raudio: can't remove module");
}

#endif /* MODULE */



_______________________________________________
Masq maillist  -  [EMAIL PROTECTED]
Admin requests can be handled at http://www.indyramp.com/masq-list/
or email to [EMAIL PROTECTED]

PLEASE read the HOWTO and search the archives before posting.
You can start your search at http://www.indyramp.com/masq/
Please keep general linux/unix/pc/internet questions off the list.

Reply via email to