Ticket #5168: 605-netfilter_rtsp.patch

File 605-netfilter_rtsp.patch, 39.6 KB (added by fabroce <fabricedagorn@…>, 5 years ago)

target/linux/generic/patches-2.6.37/605-netfilter_rtsp.patch

  • new file include/linux/netfilter/nf_conntrack_rtsp.h

    - +  
     1/* 
     2 * RTSP extension for IP connection tracking. 
     3 * (C) 2003 by Tom Marshall <tmarshall at real.com> 
     4 * based on ip_conntrack_irc.h 
     5 * 
     6 *      This program is free software; you can redistribute it and/or 
     7 *      modify it under the terms of the GNU General Public License 
     8 *      as published by the Free Software Foundation; either version 
     9 *      2 of the License, or (at your option) any later version. 
     10 */ 
     11#ifndef _IP_CONNTRACK_RTSP_H 
     12#define _IP_CONNTRACK_RTSP_H 
     13 
     14//#define IP_NF_RTSP_DEBUG 1 
     15#define IP_NF_RTSP_VERSION "0.6.21" 
     16 
     17#ifdef __KERNEL__ 
     18/* port block types */ 
     19typedef enum { 
     20    pb_single,  /* client_port=x */ 
     21    pb_range,   /* client_port=x-y */ 
     22    pb_discon   /* client_port=x/y (rtspbis) */ 
     23} portblock_t; 
     24 
     25/* We record seq number and length of rtsp headers here, all in host order. */ 
     26 
     27/* 
     28 * This structure is per expected connection.  It is a member of struct 
     29 * ip_conntrack_expect.  The TCP SEQ for the conntrack expect is stored 
     30 * there and we are expected to only store the length of the data which 
     31 * needs replaced.  If a packet contains multiple RTSP messages, we create 
     32 * one expected connection per message. 
     33 * 
     34 * We use these variables to mark the entire header block.  This may seem 
     35 * like overkill, but the nature of RTSP requires it.  A header may appear 
     36 * multiple times in a message.  We must treat two Transport headers the 
     37 * same as one Transport header with two entries. 
     38 */ 
     39struct ip_ct_rtsp_expect 
     40{ 
     41    u_int32_t   len;        /* length of header block */ 
     42    portblock_t pbtype;     /* Type of port block that was requested */ 
     43    u_int16_t   loport;     /* Port that was requested, low or first */ 
     44    u_int16_t   hiport;     /* Port that was requested, high or second */ 
     45#if 0 
     46    uint        method;     /* RTSP method */ 
     47    uint        cseq;       /* CSeq from request */ 
     48#endif 
     49}; 
     50 
     51extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, 
     52                                 enum ip_conntrack_info ctinfo, 
     53                                 unsigned int matchoff, unsigned int matchlen, 
     54                                 struct ip_ct_rtsp_expect *prtspexp, 
     55                                 struct nf_conntrack_expect *exp); 
     56 
     57extern void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); 
     58 
     59#define RTSP_PORT   554 
     60 
     61#endif /* __KERNEL__ */ 
     62 
     63#endif /* _IP_CONNTRACK_RTSP_H */ 
  • new file include/linux/netfilter_helpers.h

    - +  
     1/* 
     2 * Helpers for netfiler modules.  This file provides implementations for basic 
     3 * functions such as strncasecmp(), etc. 
     4 * 
     5 * gcc will warn for defined but unused functions, so we only include the 
     6 * functions requested.  The following macros are used: 
     7 *   NF_NEED_STRNCASECMP        nf_strncasecmp() 
     8 *   NF_NEED_STRTOU16           nf_strtou16() 
     9 *   NF_NEED_STRTOU32           nf_strtou32() 
     10 */ 
     11#ifndef _NETFILTER_HELPERS_H 
     12#define _NETFILTER_HELPERS_H 
     13 
     14/* Only include these functions for kernel code. */ 
     15#ifdef __KERNEL__ 
     16 
     17#include <linux/ctype.h> 
     18#define iseol(c) ( (c) == '\r' || (c) == '\n' ) 
     19 
     20/* 
     21 * The standard strncasecmp() 
     22 */ 
     23#ifdef NF_NEED_STRNCASECMP 
     24static int 
     25nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) 
     26{ 
     27    if (s1 == NULL || s2 == NULL) 
     28    { 
     29        if (s1 == NULL && s2 == NULL) 
     30        { 
     31            return 0; 
     32        } 
     33        return (s1 == NULL) ? -1 : 1; 
     34    } 
     35    while (len > 0 && tolower(*s1) == tolower(*s2)) 
     36    { 
     37        len--; 
     38        s1++; 
     39        s2++; 
     40    } 
     41    return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); 
     42} 
     43#endif /* NF_NEED_STRNCASECMP */ 
     44 
     45/* 
     46 * Parse a string containing a 16-bit unsigned integer. 
     47 * Returns the number of chars used, or zero if no number is found. 
     48 */ 
     49#ifdef NF_NEED_STRTOU16 
     50static int 
     51nf_strtou16(const char* pbuf, u_int16_t* pval) 
     52{ 
     53    int n = 0; 
     54 
     55    *pval = 0; 
     56    while (isdigit(pbuf[n])) 
     57    { 
     58        *pval = (*pval * 10) + (pbuf[n] - '0'); 
     59        n++; 
     60    } 
     61 
     62    return n; 
     63} 
     64#endif /* NF_NEED_STRTOU16 */ 
     65 
     66/* 
     67 * Parse a string containing a 32-bit unsigned integer. 
     68 * Returns the number of chars used, or zero if no number is found. 
     69 */ 
     70#ifdef NF_NEED_STRTOU32 
     71static int 
     72nf_strtou32(const char* pbuf, u_int32_t* pval) 
     73{ 
     74    int n = 0; 
     75 
     76    *pval = 0; 
     77    while (pbuf[n] >= '0' && pbuf[n] <= '9') 
     78    { 
     79        *pval = (*pval * 10) + (pbuf[n] - '0'); 
     80        n++; 
     81    } 
     82 
     83    return n; 
     84} 
     85#endif /* NF_NEED_STRTOU32 */ 
     86 
     87/* 
     88 * Given a buffer and length, advance to the next line and mark the current 
     89 * line. 
     90 */ 
     91#ifdef NF_NEED_NEXTLINE 
     92static int 
     93nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) 
     94{ 
     95    uint    off = *poff; 
     96    uint    physlen = 0; 
     97 
     98    if (off >= len) 
     99    { 
     100        return 0; 
     101    } 
     102 
     103    while (p[off] != '\n') 
     104    { 
     105        if (len-off <= 1) 
     106        { 
     107            return 0; 
     108        } 
     109 
     110        physlen++; 
     111        off++; 
     112    } 
     113 
     114    /* if we saw a crlf, physlen needs adjusted */ 
     115    if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') 
     116    { 
     117        physlen--; 
     118    } 
     119 
     120    /* advance past the newline */ 
     121    off++; 
     122 
     123    *plineoff = *poff; 
     124    *plinelen = physlen; 
     125    *poff = off; 
     126 
     127    return 1; 
     128} 
     129#endif /* NF_NEED_NEXTLINE */ 
     130 
     131#endif /* __KERNEL__ */ 
     132 
     133#endif /* _NETFILTER_HELPERS_H */ 
  • new file include/linux/netfilter_mime.h

    - +  
     1/* 
     2 * MIME functions for netfilter modules.  This file provides implementations 
     3 * for basic MIME parsing.  MIME headers are used in many protocols, such as 
     4 * HTTP, RTSP, SIP, etc. 
     5 * 
     6 * gcc will warn for defined but unused functions, so we only include the 
     7 * functions requested.  The following macros are used: 
     8 *   NF_NEED_MIME_NEXTLINE      nf_mime_nextline() 
     9 */ 
     10#ifndef _NETFILTER_MIME_H 
     11#define _NETFILTER_MIME_H 
     12 
     13/* Only include these functions for kernel code. */ 
     14#ifdef __KERNEL__ 
     15 
     16#include <linux/ctype.h> 
     17 
     18/* 
     19 * Given a buffer and length, advance to the next line and mark the current 
     20 * line.  If the current line is empty, *plinelen will be set to zero.  If 
     21 * not, it will be set to the actual line length (including CRLF). 
     22 * 
     23 * 'line' in this context means logical line (includes LWS continuations). 
     24 * Returns 1 on success, 0 on failure. 
     25 */ 
     26#ifdef NF_NEED_MIME_NEXTLINE 
     27static int 
     28nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) 
     29{ 
     30    uint    off = *poff; 
     31    uint    physlen = 0; 
     32    int     is_first_line = 1; 
     33 
     34    if (off >= len) 
     35    { 
     36        return 0; 
     37    } 
     38 
     39    do 
     40    { 
     41        while (p[off] != '\n') 
     42        { 
     43            if (len-off <= 1) 
     44            { 
     45                return 0; 
     46            } 
     47 
     48            physlen++; 
     49            off++; 
     50        } 
     51 
     52        /* if we saw a crlf, physlen needs adjusted */ 
     53        if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') 
     54        { 
     55            physlen--; 
     56        } 
     57 
     58        /* advance past the newline */ 
     59        off++; 
     60 
     61        /* check for an empty line */ 
     62        if (physlen == 0) 
     63        { 
     64            break; 
     65        } 
     66 
     67        /* check for colon on the first physical line */ 
     68        if (is_first_line) 
     69        { 
     70            is_first_line = 0; 
     71            if (memchr(p+(*poff), ':', physlen) == NULL) 
     72            { 
     73                return 0; 
     74            } 
     75        } 
     76    } 
     77    while (p[off] == ' ' || p[off] == '\t'); 
     78 
     79    *plineoff = *poff; 
     80    *plinelen = (physlen == 0) ? 0 : (off - *poff); 
     81    *poff = off; 
     82 
     83    return 1; 
     84} 
     85#endif /* NF_NEED_MIME_NEXTLINE */ 
     86 
     87#endif /* __KERNEL__ */ 
     88 
     89#endif /* _NETFILTER_MIME_H */ 
  • net/ipv4/netfilter/Makefile

    a b obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_am 
    2626obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o 
    2727obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 
    2828obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o 
     29obj-$(CONFIG_NF_NAT_RTSP) += nf_nat_rtsp.o 
    2930obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 
    3031obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o 
    3132obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o 
  • net/netfilter/Kconfig

    a b config NF_CONNTRACK_TFTP 
    259259 
    260260          To compile it as a module, choose M here.  If unsure, say N. 
    261261 
     262config NF_CONNTRACK_RTSP 
     263        tristate "RTSP protocol support" 
     264        depends on NF_CONNTRACK 
     265        help 
     266                Support the RTSP protocol.  This allows UDP transports to be setup 
     267                properly, including RTP and RDT. 
     268 
     269                If you want to compile it as a module, say 'M' here and read 
     270                Documentation/modules.txt.  If unsure, say 'Y'. 
     271 
    262272config NF_CT_NETLINK 
    263273        tristate 'Connection tracking netlink interface' 
    264274        select NETFILTER_NETLINK 
  • net/netfilter/Makefile

    a b obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_co 
    3333obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o 
    3434obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o 
    3535obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o 
     36obj-$(CONFIG_NF_CONNTRACK_RTSP) += nf_conntrack_rtsp.o 
    3637 
    3738# transparent proxy support 
    3839obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o 
  • net/ipv4/netfilter/Kconfig

    a b config NF_NAT_IRC 
    257257        depends on NF_CONNTRACK && NF_NAT 
    258258        default NF_NAT && NF_CONNTRACK_IRC 
    259259 
     260config NF_NAT_RTSP 
     261        tristate 
     262        depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT 
     263        default NF_NAT && NF_CONNTRACK_RTSP 
     264 
    260265config NF_NAT_TFTP 
    261266        tristate 
    262267        depends on NF_CONNTRACK && NF_NAT 
  • new file net/netfilter/nf_conntrack_rtsp.c

    - +  
     1/* 
     2 * RTSP extension for IP connection tracking 
     3 * (C) 2003 by Tom Marshall <tmarshall at real.com> 
     4 * based on ip_conntrack_irc.c 
     5 * 
     6 *      This program is free software; you can redistribute it and/or 
     7 *      modify it under the terms of the GNU General Public License 
     8 *      as published by the Free Software Foundation; either version 
     9 *      2 of the License, or (at your option) any later version. 
     10 * 
     11 * Module load syntax: 
     12 *   insmod nf_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS> 
     13 *                              max_outstanding=n setup_timeout=secs 
     14 * 
     15 * If no ports are specified, the default will be port 554. 
     16 * 
     17 * With max_outstanding you can define the maximum number of not yet 
     18 * answered SETUP requests per RTSP session (default 8). 
     19 * With setup_timeout you can specify how long the system waits for 
     20 * an expected data channel (default 300 seconds). 
     21 * 
     22 * 2005-02-13: Harald Welte <laforge at netfilter.org> 
     23 *      - port to 2.6 
     24 *      - update to recent post-2.6.11 api changes 
     25 * 2006-09-14: Steven Van Acker <deepstar at singularity.be> 
     26 *      - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack 
     27 * 2007-04-18: Michael Guntsche <mike at it-loops.com> 
     28 *                      - Port to new NF API 
     29 */ 
     30 
     31#include <linux/module.h> 
     32#include <linux/netfilter.h> 
     33#include <linux/ip.h> 
     34#include <linux/inet.h> 
     35#include <net/tcp.h> 
     36 
     37#include <net/netfilter/nf_conntrack.h> 
     38#include <net/netfilter/nf_conntrack_expect.h> 
     39#include <net/netfilter/nf_conntrack_helper.h> 
     40#include <linux/netfilter/nf_conntrack_rtsp.h> 
     41 
     42#define NF_NEED_STRNCASECMP 
     43#define NF_NEED_STRTOU16 
     44#define NF_NEED_STRTOU32 
     45#define NF_NEED_NEXTLINE 
     46#include <linux/netfilter_helpers.h> 
     47#define NF_NEED_MIME_NEXTLINE 
     48#include <linux/netfilter_mime.h> 
     49 
     50#include <linux/ctype.h> 
     51#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ 
     52 
     53#define MAX_PORTS 8 
     54static int ports[MAX_PORTS]; 
     55static int num_ports = 0; 
     56static int max_outstanding = 8; 
     57static unsigned int setup_timeout = 300; 
     58 
     59MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>"); 
     60MODULE_DESCRIPTION("RTSP connection tracking module"); 
     61MODULE_LICENSE("GPL"); 
     62module_param_array(ports, int, &num_ports, 0400); 
     63MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); 
     64module_param(max_outstanding, int, 0400); 
     65MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); 
     66module_param(setup_timeout, int, 0400); 
     67MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); 
     68 
     69static char *rtsp_buffer; 
     70static DEFINE_SPINLOCK(rtsp_buffer_lock); 
     71 
     72static struct nf_conntrack_expect_policy rtsp_exp_policy;  
     73 
     74unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, 
     75                                 enum ip_conntrack_info ctinfo, 
     76                                 unsigned int matchoff, unsigned int matchlen,struct ip_ct_rtsp_expect* prtspexp, 
     77                                 struct nf_conntrack_expect *exp); 
     78void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); 
     79 
     80EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook); 
     81 
     82/* 
     83 * Max mappings we will allow for one RTSP connection (for RTP, the number 
     84 * of allocated ports is twice this value).  Note that SMIL burns a lot of 
     85 * ports so keep this reasonably high.  If this is too low, you will see a 
     86 * lot of "no free client map entries" messages. 
     87 */ 
     88#define MAX_PORT_MAPS 16 
     89 
     90/*** default port list was here in the masq code: 554, 3030, 4040 ***/ 
     91 
     92#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } 
     93 
     94/* 
     95 * Parse an RTSP packet. 
     96 * 
     97 * Returns zero if parsing failed. 
     98 * 
     99 * Parameters: 
     100 *  IN      ptcp        tcp data pointer 
     101 *  IN      tcplen      tcp data len 
     102 *  IN/OUT  ptcpoff     points to current tcp offset 
     103 *  OUT     phdrsoff    set to offset of rtsp headers 
     104 *  OUT     phdrslen    set to length of rtsp headers 
     105 *  OUT     pcseqoff    set to offset of CSeq header 
     106 *  OUT     pcseqlen    set to length of CSeq header 
     107 */ 
     108static int 
     109rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, 
     110                   uint* phdrsoff, uint* phdrslen, 
     111                   uint* pcseqoff, uint* pcseqlen, 
     112                   uint* transoff, uint* translen) 
     113{ 
     114        uint    entitylen = 0; 
     115        uint    lineoff; 
     116        uint    linelen; 
     117         
     118        if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) 
     119                return 0; 
     120         
     121        *phdrsoff = *ptcpoff; 
     122        while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) { 
     123                if (linelen == 0) { 
     124                        if (entitylen > 0) 
     125                                *ptcpoff += min(entitylen, tcplen - *ptcpoff); 
     126                        break; 
     127                } 
     128                if (lineoff+linelen > tcplen) { 
     129                        pr_info("!! overrun !!\n"); 
     130                        break; 
     131                } 
     132                 
     133                if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) { 
     134                        *pcseqoff = lineoff; 
     135                        *pcseqlen = linelen; 
     136                }  
     137 
     138                if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) { 
     139                        *transoff = lineoff; 
     140                        *translen = linelen; 
     141                } 
     142                 
     143                if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) { 
     144                        uint off = lineoff+15; 
     145                        SKIP_WSPACE(ptcp+lineoff, linelen, off); 
     146                        nf_strtou32(ptcp+off, &entitylen); 
     147                } 
     148        } 
     149        *phdrslen = (*ptcpoff) - (*phdrsoff); 
     150         
     151        return 1; 
     152} 
     153 
     154/* 
     155 * Find lo/hi client ports (if any) in transport header 
     156 * In: 
     157 *   ptcp, tcplen = packet 
     158 *   tranoff, tranlen = buffer to search 
     159 * 
     160 * Out: 
     161 *   pport_lo, pport_hi = lo/hi ports (host endian) 
     162 * 
     163 * Returns nonzero if any client ports found 
     164 * 
     165 * Note: it is valid (and expected) for the client to request multiple 
     166 * transports, so we need to parse the entire line. 
     167 */ 
     168static int 
     169rtsp_parse_transport(char* ptran, uint tranlen, 
     170                     struct ip_ct_rtsp_expect* prtspexp) 
     171{ 
     172        int     rc = 0; 
     173        uint    off = 0; 
     174         
     175        if (tranlen < 10 || !iseol(ptran[tranlen-1]) || 
     176            nf_strncasecmp(ptran, "Transport:", 10) != 0) { 
     177                pr_info("sanity check failed\n"); 
     178                return 0; 
     179        } 
     180         
     181        pr_debug("tran='%.*s'\n", (int)tranlen, ptran); 
     182        off += 10; 
     183        SKIP_WSPACE(ptran, tranlen, off); 
     184         
     185        /* Transport: tran;field;field=val,tran;field;field=val,... */ 
     186        while (off < tranlen) { 
     187                const char* pparamend; 
     188                uint        nextparamoff; 
     189                 
     190                pparamend = memchr(ptran+off, ',', tranlen-off); 
     191                pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; 
     192                nextparamoff = pparamend-ptran; 
     193                 
     194                while (off < nextparamoff) { 
     195                        const char* pfieldend; 
     196                        uint        nextfieldoff; 
     197                         
     198                        pfieldend = memchr(ptran+off, ';', nextparamoff-off); 
     199                        nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 
     200                    
     201                        if (strncmp(ptran+off, "client_port=", 12) == 0) { 
     202                                u_int16_t   port; 
     203                                uint        numlen; 
     204                     
     205                                off += 12; 
     206                                numlen = nf_strtou16(ptran+off, &port); 
     207                                off += numlen; 
     208                                if (prtspexp->loport != 0 && prtspexp->loport != port) 
     209                                        pr_debug("multiple ports found, port %hu ignored\n", port); 
     210                                else { 
     211                                        pr_debug("lo port found : %hu\n", port); 
     212                                        prtspexp->loport = prtspexp->hiport = port; 
     213                                        if (ptran[off] == '-') { 
     214                                                off++; 
     215                                                numlen = nf_strtou16(ptran+off, &port); 
     216                                                off += numlen; 
     217                                                prtspexp->pbtype = pb_range; 
     218                                                prtspexp->hiport = port; 
     219                                                 
     220                                                // If we have a range, assume rtp: 
     221                                                // loport must be even, hiport must be loport+1 
     222                                                if ((prtspexp->loport & 0x0001) != 0 || 
     223                                                    prtspexp->hiport != prtspexp->loport+1) { 
     224                                                        pr_debug("incorrect range: %hu-%hu, correcting\n", 
     225                                                               prtspexp->loport, prtspexp->hiport); 
     226                                                        prtspexp->loport &= 0xfffe; 
     227                                                        prtspexp->hiport = prtspexp->loport+1; 
     228                                                } 
     229                                        } else if (ptran[off] == '/') { 
     230                                                off++; 
     231                                                numlen = nf_strtou16(ptran+off, &port); 
     232                                                off += numlen; 
     233                                                prtspexp->pbtype = pb_discon; 
     234                                                prtspexp->hiport = port; 
     235                                        } 
     236                                        rc = 1; 
     237                                } 
     238                        } 
     239                         
     240                        /* 
     241                         * Note we don't look for the destination parameter here. 
     242                         * If we are using NAT, the NAT module will handle it.  If not, 
     243                         * and the client is sending packets elsewhere, the expectation 
     244                         * will quietly time out. 
     245                         */ 
     246                         
     247                        off = nextfieldoff; 
     248                } 
     249                 
     250                off = nextparamoff; 
     251        } 
     252         
     253        return rc; 
     254} 
     255 
     256void expected(struct nf_conn *ct, struct nf_conntrack_expect *exp) 
     257{ 
     258                typeof(nf_nat_rtsp_hook_expectfn) nf_nat_rtsp_expectfn; 
     259                nf_nat_rtsp_expectfn = rcu_dereference(nf_nat_rtsp_hook_expectfn); 
     260    if(nf_nat_rtsp_expectfn && ct->master->status & IPS_NAT_MASK) { 
     261        nf_nat_rtsp_expectfn(ct,exp); 
     262    } 
     263} 
     264 
     265/*** conntrack functions ***/ 
     266 
     267/* outbound packet: client->server */ 
     268 
     269static inline int 
     270help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen, 
     271                struct nf_conn *ct, enum ip_conntrack_info ctinfo) 
     272{ 
     273        struct ip_ct_rtsp_expect expinfo; 
     274         
     275        int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */ 
     276        //struct  tcphdr* tcph = (void*)iph + iph->ihl * 4; 
     277        //uint    tcplen = pktlen - iph->ihl * 4; 
     278        char*   pdata = rb_ptr; 
     279        //uint    datalen = tcplen - tcph->doff * 4; 
     280        uint    dataoff = 0; 
     281        int ret = NF_ACCEPT; 
     282         
     283        struct nf_conntrack_expect *exp; 
     284         
     285        __be16 be_loport; 
     286         
     287        typeof(nf_nat_rtsp_hook) nf_nat_rtsp; 
     288 
     289        memset(&expinfo, 0, sizeof(expinfo)); 
     290         
     291        while (dataoff < datalen) { 
     292                uint    cmdoff = dataoff; 
     293                uint    hdrsoff = 0; 
     294                uint    hdrslen = 0; 
     295                uint    cseqoff = 0; 
     296                uint    cseqlen = 0; 
     297                uint    transoff = 0; 
     298                uint    translen = 0; 
     299                uint    off; 
     300                 
     301                if (!rtsp_parse_message(pdata, datalen, &dataoff, 
     302                                        &hdrsoff, &hdrslen, 
     303                                        &cseqoff, &cseqlen, 
     304                                        &transoff, &translen)) 
     305                        break;      /* not a valid message */ 
     306                 
     307                if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) 
     308                        continue;   /* not a SETUP message */ 
     309                pr_debug("found a setup message\n"); 
     310 
     311                off = 0; 
     312                if(translen) { 
     313                        rtsp_parse_transport(pdata+transoff, translen, &expinfo); 
     314                } 
     315 
     316                if (expinfo.loport == 0) { 
     317                        pr_debug("no udp transports found\n"); 
     318                        continue;   /* no udp transports found */ 
     319                } 
     320 
     321                pr_debug("udp transport found, ports=(%d,%hu,%hu)\n", 
     322                       (int)expinfo.pbtype, expinfo.loport, expinfo.hiport); 
     323 
     324                exp = nf_ct_expect_alloc(ct); 
     325                if (!exp) { 
     326                        ret = NF_DROP; 
     327                        goto out; 
     328                } 
     329 
     330                be_loport = htons(expinfo.loport); 
     331 
     332                nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), 
     333                        &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, 
     334                        IPPROTO_UDP, NULL, &be_loport);  
     335 
     336                exp->master = ct; 
     337 
     338                exp->expectfn = expected; 
     339                exp->flags = 0; 
     340 
     341                if (expinfo.pbtype == pb_range) { 
     342                        pr_debug("Changing expectation mask to handle multiple ports\n"); 
     343                        //exp->mask.dst.u.udp.port  = 0xfffe; 
     344                } 
     345 
     346                pr_debug("expect_related %pI4:%u-%pI4:%u\n", 
     347                       &exp->tuple.src.u3.ip, 
     348                       ntohs(exp->tuple.src.u.udp.port), 
     349                       &exp->tuple.dst.u3.ip, 
     350                       ntohs(exp->tuple.dst.u.udp.port)); 
     351 
     352                nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook); 
     353                if (nf_nat_rtsp && ct->status & IPS_NAT_MASK) 
     354                        /* pass the request off to the nat helper */ 
     355                        ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp); 
     356                else if (nf_ct_expect_related(exp) != 0) { 
     357                        pr_info("nf_conntrack_expect_related failed\n"); 
     358                        ret  = NF_DROP; 
     359                } 
     360                nf_ct_expect_put(exp); 
     361                goto out; 
     362        } 
     363out: 
     364 
     365        return ret; 
     366} 
     367 
     368 
     369static inline int 
     370help_in(struct sk_buff *skb, size_t pktlen, 
     371 struct nf_conn* ct, enum ip_conntrack_info ctinfo) 
     372{ 
     373 return NF_ACCEPT; 
     374} 
     375 
     376static int help(struct sk_buff *skb, unsigned int protoff, 
     377                struct nf_conn *ct, enum ip_conntrack_info ctinfo)  
     378{ 
     379        struct tcphdr _tcph, *th; 
     380        unsigned int dataoff, datalen; 
     381        char *rb_ptr; 
     382        int ret = NF_DROP; 
     383 
     384        /* Until there's been traffic both ways, don't look in packets. */ 
     385        if (ctinfo != IP_CT_ESTABLISHED &&  
     386            ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { 
     387                pr_debug("conntrackinfo = %u\n", ctinfo); 
     388                return NF_ACCEPT; 
     389        }  
     390 
     391        /* Not whole TCP header? */ 
     392        th = skb_header_pointer(skb,protoff, sizeof(_tcph), &_tcph); 
     393 
     394        if (!th) 
     395                return NF_ACCEPT; 
     396    
     397        /* No data ? */ 
     398        dataoff = protoff + th->doff*4; 
     399        datalen = skb->len - dataoff; 
     400        if (dataoff >= skb->len) 
     401                return NF_ACCEPT; 
     402 
     403        spin_lock_bh(&rtsp_buffer_lock); 
     404        rb_ptr = skb_header_pointer(skb, dataoff, 
     405                                    skb->len - dataoff, rtsp_buffer); 
     406        BUG_ON(rb_ptr == NULL); 
     407 
     408#if 0 
     409        /* Checksum invalid?  Ignore. */ 
     410        /* FIXME: Source route IP option packets --RR */ 
     411        if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, 
     412                         csum_partial((char*)tcph, tcplen, 0))) 
     413        { 
     414                DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", 
     415                       tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); 
     416                return NF_ACCEPT; 
     417        } 
     418#endif 
     419 
     420        switch (CTINFO2DIR(ctinfo)) { 
     421        case IP_CT_DIR_ORIGINAL: 
     422                ret = help_out(skb, rb_ptr, datalen, ct, ctinfo); 
     423                break; 
     424        case IP_CT_DIR_REPLY: 
     425                pr_debug("IP_CT_DIR_REPLY\n"); 
     426                /* inbound packet: server->client */ 
     427                ret = NF_ACCEPT; 
     428                break; 
     429        } 
     430 
     431        spin_unlock_bh(&rtsp_buffer_lock); 
     432 
     433        return ret; 
     434} 
     435 
     436static struct nf_conntrack_helper rtsp_helpers[MAX_PORTS]; 
     437static char rtsp_names[MAX_PORTS][10]; 
     438 
     439/* This function is intentionally _NOT_ defined as __exit */ 
     440static void 
     441fini(void) 
     442{ 
     443        int i; 
     444        for (i = 0; i < num_ports; i++) { 
     445                pr_debug("unregistering port %d\n", ports[i]); 
     446                nf_conntrack_helper_unregister(&rtsp_helpers[i]); 
     447        } 
     448        kfree(rtsp_buffer); 
     449} 
     450 
     451static int __init 
     452init(void) 
     453{ 
     454        int i, ret; 
     455        struct nf_conntrack_helper *hlpr; 
     456        char *tmpname; 
     457 
     458        printk("nf_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); 
     459 
     460        if (max_outstanding < 1) { 
     461                printk("nf_conntrack_rtsp: max_outstanding must be a positive integer\n"); 
     462                return -EBUSY; 
     463        } 
     464        if (setup_timeout < 0) { 
     465                printk("nf_conntrack_rtsp: setup_timeout must be a positive integer\n"); 
     466                return -EBUSY; 
     467        } 
     468 
     469  rtsp_exp_policy.max_expected = max_outstanding; 
     470  rtsp_exp_policy.timeout = setup_timeout; 
     471         
     472        rtsp_buffer = kmalloc(65536, GFP_KERNEL); 
     473        if (!rtsp_buffer)  
     474                return -ENOMEM; 
     475 
     476        /* If no port given, default to standard rtsp port */ 
     477        if (ports[0] == 0) { 
     478                ports[0] = RTSP_PORT; 
     479        } 
     480 
     481        for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { 
     482                hlpr = &rtsp_helpers[i]; 
     483                memset(hlpr, 0, sizeof(struct nf_conntrack_helper)); 
     484                hlpr->tuple.src.l3num = AF_INET; 
     485                hlpr->tuple.src.u.tcp.port = htons(ports[i]); 
     486                hlpr->tuple.dst.protonum = IPPROTO_TCP; 
     487                //hlpr->mask.src.u.tcp.port = 0xFFFF; 
     488                //hlpr->mask.dst.protonum = 0xFF; 
     489                hlpr->expect_policy = &rtsp_exp_policy; 
     490                hlpr->me = THIS_MODULE; 
     491                hlpr->help = help; 
     492 
     493                tmpname = &rtsp_names[i][0]; 
     494                if (ports[i] == RTSP_PORT) { 
     495                        sprintf(tmpname, "rtsp"); 
     496                } else { 
     497                        sprintf(tmpname, "rtsp-%d", i); 
     498                } 
     499                hlpr->name = tmpname; 
     500 
     501                pr_debug("port #%d: %d\n", i, ports[i]); 
     502 
     503                ret = nf_conntrack_helper_register(hlpr); 
     504 
     505                if (ret) { 
     506                        printk("nf_conntrack_rtsp: ERROR registering port %d\n", ports[i]); 
     507                        fini(); 
     508                        return -EBUSY; 
     509                } 
     510                num_ports++; 
     511        } 
     512        return 0; 
     513} 
     514 
     515module_init(init); 
     516module_exit(fini); 
     517 
     518EXPORT_SYMBOL(nf_nat_rtsp_hook_expectfn); 
     519 
  • new file net/ipv4/netfilter/nf_nat_rtsp.c

    - +  
     1/* 
     2 * RTSP extension for TCP NAT alteration 
     3 * (C) 2003 by Tom Marshall <tmarshall at real.com> 
     4 * based on ip_nat_irc.c 
     5 * 
     6 *      This program is free software; you can redistribute it and/or 
     7 *      modify it under the terms of the GNU General Public License 
     8 *      as published by the Free Software Foundation; either version 
     9 *      2 of the License, or (at your option) any later version. 
     10 * 
     11 * Module load syntax: 
     12 *      insmod nf_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS> 
     13 *                           stunaddr=<address> 
     14 *                           destaction=[auto|strip|none] 
     15 * 
     16 * If no ports are specified, the default will be port 554 only. 
     17 * 
     18 * stunaddr specifies the address used to detect that a client is using STUN. 
     19 * If this address is seen in the destination parameter, it is assumed that 
     20 * the client has already punched a UDP hole in the firewall, so we don't 
     21 * mangle the client_port.  If none is specified, it is autodetected.  It 
     22 * only needs to be set if you have multiple levels of NAT.  It should be 
     23 * set to the external address that the STUN clients detect.  Note that in 
     24 * this case, it will not be possible for clients to use UDP with servers 
     25 * between the NATs. 
     26 * 
     27 * If no destaction is specified, auto is used. 
     28 *   destaction=auto:  strip destination parameter if it is not stunaddr. 
     29 *   destaction=strip: always strip destination parameter (not recommended). 
     30 *   destaction=none:  do not touch destination parameter (not recommended). 
     31 */ 
     32 
     33#include <linux/module.h> 
     34#include <net/tcp.h> 
     35#include <net/netfilter/nf_nat_helper.h> 
     36#include <net/netfilter/nf_nat_rule.h> 
     37#include <linux/netfilter/nf_conntrack_rtsp.h> 
     38#include <net/netfilter/nf_conntrack_expect.h> 
     39 
     40#include <linux/inet.h> 
     41#include <linux/ctype.h> 
     42#define NF_NEED_STRNCASECMP 
     43#define NF_NEED_STRTOU16 
     44#include <linux/netfilter_helpers.h> 
     45#define NF_NEED_MIME_NEXTLINE 
     46#include <linux/netfilter_mime.h> 
     47 
     48#define MAX_PORTS       8 
     49#define DSTACT_AUTO     0 
     50#define DSTACT_STRIP    1 
     51#define DSTACT_NONE     2 
     52 
     53static char*    stunaddr = NULL; 
     54static char*    destaction = NULL; 
     55 
     56static u_int32_t extip = 0; 
     57static int       dstact = 0; 
     58 
     59MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>"); 
     60MODULE_DESCRIPTION("RTSP network address translation module"); 
     61MODULE_LICENSE("GPL"); 
     62module_param(stunaddr, charp, 0644); 
     63MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); 
     64module_param(destaction, charp, 0644); 
     65MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); 
     66 
     67#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } 
     68 
     69/*** helper functions ***/ 
     70 
     71static void 
     72get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) 
     73{ 
     74    struct iphdr*   iph  = ip_hdr(skb); 
     75    struct tcphdr*  tcph = (void *)iph + ip_hdrlen(skb); 
     76 
     77    *pptcpdata = (char*)tcph +  tcph->doff*4; 
     78    *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata; 
     79} 
     80 
     81/*** nat functions ***/ 
     82 
     83/* 
     84 * Mangle the "Transport:" header: 
     85 *   - Replace all occurences of "client_port=<spec>" 
     86 *   - Handle destination parameter 
     87 * 
     88 * In: 
     89 *   ct, ctinfo = conntrack context 
     90 *   skb        = packet 
     91 *   tranoff    = Transport header offset from TCP data 
     92 *   tranlen    = Transport header length (incl. CRLF) 
     93 *   rport_lo   = replacement low  port (host endian) 
     94 *   rport_hi   = replacement high port (host endian) 
     95 * 
     96 * Returns packet size difference. 
     97 * 
     98 * Assumes that a complete transport header is present, ending with CR or LF 
     99 */ 
     100static int 
     101rtsp_mangle_tran(enum ip_conntrack_info ctinfo, 
     102                 struct nf_conntrack_expect* exp, 
     103                                                                 struct ip_ct_rtsp_expect* prtspexp, 
     104                 struct sk_buff* skb, uint tranoff, uint tranlen) 
     105{ 
     106    char*       ptcp; 
     107    uint        tcplen; 
     108    char*       ptran; 
     109    char        rbuf1[16];      /* Replacement buffer (one port) */ 
     110    uint        rbuf1len;       /* Replacement len (one port) */ 
     111    char        rbufa[16];      /* Replacement buffer (all ports) */ 
     112    uint        rbufalen;       /* Replacement len (all ports) */ 
     113    u_int32_t   newip; 
     114    u_int16_t   loport, hiport; 
     115    uint        off = 0; 
     116    uint        diff;           /* Number of bytes we removed */ 
     117 
     118    struct nf_conn *ct = exp->master; 
     119    struct nf_conntrack_tuple *t; 
     120 
     121    char    szextaddr[15+1]; 
     122    uint    extaddrlen; 
     123    int     is_stun; 
     124 
     125    get_skb_tcpdata(skb, &ptcp, &tcplen); 
     126    ptran = ptcp+tranoff; 
     127 
     128    if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || 
     129        tranlen < 10 || !iseol(ptran[tranlen-1]) || 
     130        nf_strncasecmp(ptran, "Transport:", 10) != 0) 
     131    { 
     132        pr_info("sanity check failed\n"); 
     133        return 0; 
     134    } 
     135    off += 10; 
     136    SKIP_WSPACE(ptcp+tranoff, tranlen, off); 
     137 
     138    newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; 
     139    t = &exp->tuple; 
     140    t->dst.u3.ip = newip; 
     141 
     142    extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip) 
     143                       : sprintf(szextaddr, "%pI4", &newip); 
     144    pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); 
     145 
     146    rbuf1len = rbufalen = 0; 
     147    switch (prtspexp->pbtype) 
     148    { 
     149    case pb_single: 
     150        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ 
     151        { 
     152            t->dst.u.udp.port = htons(loport); 
     153            if (nf_ct_expect_related(exp) == 0) 
     154            { 
     155                pr_debug("using port %hu\n", loport); 
     156                break; 
     157            } 
     158        } 
     159        if (loport != 0) 
     160        { 
     161            rbuf1len = sprintf(rbuf1, "%hu", loport); 
     162            rbufalen = sprintf(rbufa, "%hu", loport); 
     163        } 
     164        break; 
     165    case pb_range: 
     166        for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ 
     167        { 
     168            t->dst.u.udp.port = htons(loport); 
     169            if (nf_ct_expect_related(exp) == 0) 
     170            { 
     171                hiport = loport + 1; //~exp->mask.dst.u.udp.port; 
     172                pr_debug("using ports %hu-%hu\n", loport, hiport); 
     173                break; 
     174            } 
     175        } 
     176        if (loport != 0) 
     177        { 
     178            rbuf1len = sprintf(rbuf1, "%hu", loport); 
     179            rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); 
     180        } 
     181        break; 
     182    case pb_discon: 
     183        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ 
     184        { 
     185            t->dst.u.udp.port = htons(loport); 
     186            if (nf_ct_expect_related(exp) == 0) 
     187            { 
     188                pr_debug("using port %hu (1 of 2)\n", loport); 
     189                break; 
     190            } 
     191        } 
     192        for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ 
     193        { 
     194            t->dst.u.udp.port = htons(hiport); 
     195            if (nf_ct_expect_related(exp) == 0) 
     196            { 
     197                pr_debug("using port %hu (2 of 2)\n", hiport); 
     198                break; 
     199            } 
     200        } 
     201        if (loport != 0 && hiport != 0) 
     202        { 
     203            rbuf1len = sprintf(rbuf1, "%hu", loport); 
     204            if (hiport == loport+1) 
     205            { 
     206                rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); 
     207            } 
     208            else 
     209            { 
     210                rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); 
     211            } 
     212        } 
     213        break; 
     214    } 
     215 
     216    if (rbuf1len == 0) 
     217    { 
     218        return 0;   /* cannot get replacement port(s) */ 
     219    } 
     220 
     221    /* Transport: tran;field;field=val,tran;field;field=val,... */ 
     222    while (off < tranlen) 
     223    { 
     224        uint        saveoff; 
     225        const char* pparamend; 
     226        uint        nextparamoff; 
     227 
     228        pparamend = memchr(ptran+off, ',', tranlen-off); 
     229        pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; 
     230        nextparamoff = pparamend-ptcp; 
     231 
     232        /* 
     233         * We pass over each param twice.  On the first pass, we look for a 
     234         * destination= field.  It is handled by the security policy.  If it 
     235         * is present, allowed, and equal to our external address, we assume 
     236         * that STUN is being used and we leave the client_port= field alone. 
     237         */ 
     238        is_stun = 0; 
     239        saveoff = off; 
     240        while (off < nextparamoff) 
     241        { 
     242            const char* pfieldend; 
     243            uint        nextfieldoff; 
     244 
     245            pfieldend = memchr(ptran+off, ';', nextparamoff-off); 
     246            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 
     247 
     248            if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) 
     249            { 
     250                if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) 
     251                { 
     252                    is_stun = 1; 
     253                } 
     254                if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) 
     255                { 
     256                    diff = nextfieldoff-off; 
     257                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 
     258                                                         off, diff, NULL, 0)) 
     259                    { 
     260                        /* mangle failed, all we can do is bail */ 
     261                        nf_ct_unexpect_related(exp); 
     262                        return 0; 
     263                    } 
     264                    get_skb_tcpdata(skb, &ptcp, &tcplen); 
     265                    ptran = ptcp+tranoff; 
     266                    tranlen -= diff; 
     267                    nextparamoff -= diff; 
     268                    nextfieldoff -= diff; 
     269                } 
     270            } 
     271 
     272            off = nextfieldoff; 
     273        } 
     274        if (is_stun) 
     275        { 
     276            continue; 
     277        } 
     278        off = saveoff; 
     279        while (off < nextparamoff) 
     280        { 
     281            const char* pfieldend; 
     282            uint        nextfieldoff; 
     283 
     284            pfieldend = memchr(ptran+off, ';', nextparamoff-off); 
     285            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 
     286 
     287            if (strncmp(ptran+off, "client_port=", 12) == 0) 
     288            { 
     289                u_int16_t   port; 
     290                uint        numlen; 
     291                uint        origoff; 
     292                uint        origlen; 
     293                char*       rbuf    = rbuf1; 
     294                uint        rbuflen = rbuf1len; 
     295 
     296                off += 12; 
     297                origoff = (ptran-ptcp)+off; 
     298                origlen = 0; 
     299                numlen = nf_strtou16(ptran+off, &port); 
     300                off += numlen; 
     301                origlen += numlen; 
     302                if (port != prtspexp->loport) 
     303                { 
     304                    pr_debug("multiple ports found, port %hu ignored\n", port); 
     305                } 
     306                else 
     307                { 
     308                    if (ptran[off] == '-' || ptran[off] == '/') 
     309                    { 
     310                        off++; 
     311                        origlen++; 
     312                        numlen = nf_strtou16(ptran+off, &port); 
     313                        off += numlen; 
     314                        origlen += numlen; 
     315                        rbuf = rbufa; 
     316                        rbuflen = rbufalen; 
     317                    } 
     318 
     319                    /* 
     320                     * note we cannot just memcpy() if the sizes are the same. 
     321                     * the mangle function does skb resizing, checks for a 
     322                     * cloned skb, and updates the checksums. 
     323                     * 
     324                     * parameter 4 below is offset from start of tcp data. 
     325                     */ 
     326                    diff = origlen-rbuflen; 
     327                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 
     328                                              origoff, origlen, rbuf, rbuflen)) 
     329                    { 
     330                        /* mangle failed, all we can do is bail */ 
     331                        nf_ct_unexpect_related(exp); 
     332                        return 0; 
     333                    } 
     334                    get_skb_tcpdata(skb, &ptcp, &tcplen); 
     335                    ptran = ptcp+tranoff; 
     336                    tranlen -= diff; 
     337                    nextparamoff -= diff; 
     338                    nextfieldoff -= diff; 
     339                } 
     340            } 
     341 
     342            off = nextfieldoff; 
     343        } 
     344 
     345        off = nextparamoff; 
     346    } 
     347 
     348    return 1; 
     349} 
     350 
     351static uint 
     352help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 
     353         unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,  
     354         struct nf_conntrack_expect* exp) 
     355{ 
     356    char*   ptcp; 
     357    uint    tcplen; 
     358    uint    hdrsoff; 
     359    uint    hdrslen; 
     360    uint    lineoff; 
     361    uint    linelen; 
     362    uint    off; 
     363 
     364    //struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; 
     365    //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); 
     366 
     367    get_skb_tcpdata(skb, &ptcp, &tcplen); 
     368    hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq); 
     369    hdrslen = matchlen; 
     370    off = hdrsoff; 
     371    pr_debug("NAT rtsp help_out\n"); 
     372 
     373    while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) 
     374    { 
     375        if (linelen == 0) 
     376        { 
     377            break; 
     378        } 
     379        if (off > hdrsoff+hdrslen) 
     380        { 
     381            pr_info("!! overrun !!"); 
     382            break; 
     383        } 
     384        pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); 
     385 
     386        if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) 
     387        { 
     388            uint oldtcplen = tcplen; 
     389            pr_debug("hdr: Transport\n"); 
     390            if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen)) 
     391            { 
     392                pr_debug("hdr: Transport mangle failed"); 
     393                break; 
     394            } 
     395            get_skb_tcpdata(skb, &ptcp, &tcplen); 
     396            hdrslen -= (oldtcplen-tcplen); 
     397            off -= (oldtcplen-tcplen); 
     398            lineoff -= (oldtcplen-tcplen); 
     399            linelen -= (oldtcplen-tcplen); 
     400            pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); 
     401        } 
     402    } 
     403 
     404    return NF_ACCEPT; 
     405} 
     406 
     407static unsigned int 
     408help(struct sk_buff *skb, enum ip_conntrack_info ctinfo,  
     409     unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, 
     410     struct nf_conntrack_expect* exp) 
     411{ 
     412    int dir = CTINFO2DIR(ctinfo); 
     413    int rc = NF_ACCEPT; 
     414 
     415    switch (dir) 
     416    { 
     417    case IP_CT_DIR_ORIGINAL: 
     418        rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp); 
     419        break; 
     420    case IP_CT_DIR_REPLY: 
     421        pr_debug("unmangle ! %u\n", ctinfo); 
     422        /* XXX: unmangle */ 
     423        rc = NF_ACCEPT; 
     424        break; 
     425    } 
     426    //UNLOCK_BH(&ip_rtsp_lock); 
     427 
     428    return rc; 
     429} 
     430 
     431static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp) 
     432{ 
     433    struct nf_nat_multi_range_compat mr; 
     434    u_int32_t newdstip, newsrcip, newip; 
     435 
     436    struct nf_conn *master = ct->master; 
     437 
     438    newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; 
     439    newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; 
     440    //FIXME (how to port that ?) 
     441    //code from 2.4 : newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; 
     442    newip = newdstip; 
     443 
     444    pr_debug("newsrcip=%pI4, newdstip=%pI4, newip=%pI4\n", 
     445           &newsrcip, &newdstip, &newip); 
     446 
     447    mr.rangesize = 1; 
     448    // We don't want to manip the per-protocol, just the IPs.  
     449    mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; 
     450    mr.range[0].min_ip = mr.range[0].max_ip = newip; 
     451 
     452    nf_nat_setup_info(ct, &mr.range[0], IP_NAT_MANIP_DST); 
     453} 
     454 
     455 
     456static void __exit fini(void) 
     457{ 
     458        nf_nat_rtsp_hook = NULL; 
     459        nf_nat_rtsp_hook_expectfn = NULL; 
     460        synchronize_net(); 
     461} 
     462 
     463static int __init init(void) 
     464{ 
     465        printk("nf_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); 
     466 
     467        BUG_ON(nf_nat_rtsp_hook); 
     468        nf_nat_rtsp_hook = help; 
     469        nf_nat_rtsp_hook_expectfn = &expected; 
     470 
     471        if (stunaddr != NULL) 
     472                extip = in_aton(stunaddr); 
     473 
     474        if (destaction != NULL) { 
     475                if (strcmp(destaction, "auto") == 0) 
     476                        dstact = DSTACT_AUTO; 
     477 
     478                if (strcmp(destaction, "strip") == 0) 
     479                        dstact = DSTACT_STRIP; 
     480 
     481                if (strcmp(destaction, "none") == 0) 
     482                        dstact = DSTACT_NONE; 
     483        } 
     484 
     485        return 0; 
     486} 
     487 
     488module_init(init); 
     489module_exit(fini);