/*
* To enable debugging, replace the line below with #define IP_NF_RTSP_DEBUG 1
*/
-#undef IP_NF_RTSP_DEBUG
+#undef IP_NF_RTSP_DEBUG
#define INFOP(args...) printk(KERN_INFO args)
#ifdef IP_NF_RTSP_DEBUG
#define DEBUGP(args...) printk(KERN_DEBUG "%s:%s ", __FILE__, __FUNCTION__); \
MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
MODULE_PARM(max_outstanding, "i");
MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
-MODULE_PARM(setup_timeout, "i");
-MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
+//MODULE_PARM(setup_timeout, "i");
+//MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
#endif
DECLARE_LOCK(ip_rtsp_lock);
* lot of "no free client map entries" messages.
*/
#define MAX_PORT_MAPS 16
-static u_int16_t g_tr_port = 10000;
+static u_int16_t g_tr_port = 7000;
+
+#define PAUSE_TIMEOUT (5 * HZ)
+#define RTSP_PAUSE_TIMEOUT (6 * HZ)
/*** default port list was here in the masq code: 554, 3030, 4040 ***/
* process the packets appropriately.
*/
struct _rtsp_data_ports {
- u_int32_t client_ip;
- u_int16_t client_tcp_port;
- u_int16_t client_udp_lo;
- u_int16_t client_udp_hi;
- portblock_t pbtype;
- u_int16_t nat_udp_lo;
- u_int16_t nat_udp_hi;
- int in_use;
+ u_int32_t client_ip;
+ u_int16_t client_tcp_port;
+ u_int16_t client_udp_lo;
+ u_int16_t client_udp_hi;
+ portblock_t pbtype;
+ u_int16_t nat_udp_lo;
+ u_int16_t nat_udp_hi;
+ struct timer_list pause_timeout;
+ struct ip_conntrack *ct_lo;
+ struct ip_conntrack *ct_hi;
+ int timeout_active;
+ int in_use;
} rtsp_data_ports[MAX_PORT_MAPS];
+static u_int16_t rtsp_nat_to_client_pmap(u_int16_t nat_port);
+
+static void
+save_ct(struct ip_conntrack *ct)
+{
+ int i = 0;
+ struct ip_conntrack_tuple *tp = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+
+ for (i = 0; i < MAX_PORT_MAPS; i++)
+ {
+ if (!rtsp_data_ports[i].in_use)
+ {
+ continue;
+ }
+ if (rtsp_data_ports[i].nat_udp_lo == ntohs((tp)->dst.u.all))
+ {
+ rtsp_data_ports[i].ct_lo = ct;
+ break;
+ }
+ else if (rtsp_data_ports[i].nat_udp_hi == ntohs((tp)->dst.u.all))
+ {
+ rtsp_data_ports[i].ct_hi = ct;
+ break;
+ }
+ }
+}
+
+static void
+rtsp_pause_timeout(unsigned long data)
+{
+ int index = (int)data;
+ struct _rtsp_data_ports *rtsp_data = &rtsp_data_ports[index];
+ struct ip_conntrack *ct_lo = rtsp_data->ct_lo;
+
+ if (rtsp_data->in_use) {
+ rtsp_data->pause_timeout.expires = jiffies + PAUSE_TIMEOUT;
+ rtsp_data->pause_timeout.function = rtsp_pause_timeout;
+ rtsp_data->pause_timeout.data = data;
+ rtsp_data->timeout_active = 1;
+ ip_ct_refresh(ct_lo, RTSP_PAUSE_TIMEOUT);
+ add_timer(&rtsp_data->pause_timeout);
+ }
+}
+
+static void
+ip_conntrack_rtsp_proc_play(struct ip_conntrack *ct, const struct iphdr *iph)
+{
+ int i = 0;
+ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
+
+ for (i = 0; i < MAX_PORT_MAPS; i++)
+ {
+ if (!rtsp_data_ports[i].in_use)
+ {
+ continue;
+ }
+ DEBUGP("Searching client info IP %u.%u.%u.%u->%hu PORTS (%hu-%hu)\n",
+ NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
+ rtsp_data_ports[i].client_udp_hi);
+ if ((rtsp_data_ports[i].client_ip == iph->saddr) &&
+ (rtsp_data_ports[i].client_tcp_port == tcph->source))
+ {
+ DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
+ NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
+ rtsp_data_ports[i].client_udp_hi);
+ if (rtsp_data_ports[i].timeout_active)
+ {
+ del_timer(&rtsp_data_ports[i].pause_timeout);
+ rtsp_data_ports[i].timeout_active = 0;
+ }
+ }
+ }
+}
+
+static void
+ip_conntrack_rtsp_proc_pause(struct ip_conntrack *ct, const struct iphdr *iph)
+{
+ int i = 0;
+ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
+ struct ip_conntrack_tuple *tp_lo;
+ struct ip_conntrack_tuple *tp_hi;
+ struct ip_conntrack *ct_lo;
+ struct ip_conntrack *ct_hi;
+
+ for (i = 0; i < MAX_PORT_MAPS; i++)
+ {
+ if (!rtsp_data_ports[i].in_use)
+ {
+ continue;
+ }
+ DEBUGP("Searching client info IP %u.%u.%u.%u->%hu PORTS (%hu-%hu)\n",
+ NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
+ rtsp_data_ports[i].client_udp_hi);
+ if ((rtsp_data_ports[i].client_ip == iph->saddr) &&
+ (rtsp_data_ports[i].client_tcp_port == tcph->source))
+ {
+ DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
+ NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
+ rtsp_data_ports[i].client_udp_hi);
+ if (rtsp_data_ports[i].timeout_active != 0 ||
+ rtsp_data_ports[i].ct_lo == NULL)
+ {
+ break;
+ }
+ rtsp_data_ports[i].pause_timeout.expires = jiffies + PAUSE_TIMEOUT;
+ rtsp_data_ports[i].pause_timeout.function = rtsp_pause_timeout;
+ rtsp_data_ports[i].pause_timeout.data = (unsigned long)i;
+ add_timer(&rtsp_data_ports[i].pause_timeout);
+ rtsp_data_ports[i].timeout_active = 1;
+ rtsp_data_ports[i].ct_lo = ct;
+ tp_lo = &ct_lo->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+ tp_hi = &ct_hi->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+ ip_ct_refresh(ct, RTSP_PAUSE_TIMEOUT);
+ }
+ }
+}
+
+static int
+rtp_expect(struct ip_conntrack *ct)
+{
+ u_int16_t nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port;
+ u_int16_t orig_port = 0;
+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ orig_port = rtsp_nat_to_client_pmap(nat_port);
+ if (orig_port)
+ {
+ ct->nat.rtsp_info.orig_port = orig_port;
+ } else {
+ return NF_DROP;
+ }
+ DEBUGP("UDP client port %hu\n", ct->nat.rtsp_info.orig_port);
+ save_ct(ct);
+
+ return NF_ACCEPT;
+}
+
/*
* Maps client ports that are overlapping with other client UDP transport to
* new NAT ports that will be tracked and converted back to client assigned
rtsp_data_ports[i].in_use, NIPQUAD(rtsp_data_ports[i].client_ip),
rtsp_data_ports[i].client_udp_lo, rtsp_data_ports[i].client_udp_hi,
rtsp_data_ports[i].nat_udp_lo, rtsp_data_ports[i].nat_udp_hi);
+ if (ntohl(iph->saddr) == rtsp_data_ports[i].client_ip &&
+ ntohs(tcph->source) == rtsp_data_ports[i].client_tcp_port &&
+ ntohs(prtspexp->loport) == rtsp_data_ports[i].client_udp_lo &&
+ ntohs(prtspexp->hiport) == rtsp_data_ports[i].client_udp_hi)
+ {
+ prtspexp->loport = rtsp_data_ports[i].nat_udp_lo;
+ prtspexp->hiport = rtsp_data_ports[i].nat_udp_hi;
+ return rc = 2;
+ }
continue;
}
- rtsp_data_ports[i].client_ip = ntohl(iph->saddr);
- rtsp_data_ports[i].client_tcp_port = ntohs(tcph->source);
- rtsp_data_ports[i].client_udp_lo = ntohs(prtspexp->loport);
- rtsp_data_ports[i].client_udp_hi = ntohs(prtspexp->hiport);
- rtsp_data_ports[i].pbtype = prtspexp->pbtype;
- rtsp_data_ports[i].in_use = 1;
- DEBUGP("Mapped at index %d ORIGINAL PORTS %hu-%hu\n", i,
- ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
- prtspexp->loport = rtsp_data_ports[i].nat_udp_lo = g_tr_port++;
- prtspexp->hiport = rtsp_data_ports[i].nat_udp_hi = g_tr_port++;
- DEBUGP("NEW PORTS %hu-%hu\n", ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
- return rc = 1;
+ rtsp_data_ports[i].client_ip = ntohl(iph->saddr);
+ rtsp_data_ports[i].client_tcp_port = ntohs(tcph->source);
+ rtsp_data_ports[i].client_udp_lo = ntohs(prtspexp->loport);
+ rtsp_data_ports[i].client_udp_hi = ntohs(prtspexp->hiport);
+ rtsp_data_ports[i].pbtype = prtspexp->pbtype;
+ rtsp_data_ports[i].in_use = 1;
+ init_timer(&rtsp_data_ports[i].pause_timeout);
+ DEBUGP("Mapped at index %d ORIGINAL PORTS %hu-%hu\n", i,
+ ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
+ prtspexp->loport = rtsp_data_ports[i].nat_udp_lo = g_tr_port++;
+ prtspexp->hiport = rtsp_data_ports[i].nat_udp_hi = g_tr_port++;
+ DEBUGP("NEW PORTS %hu-%hu\n", ntohs(prtspexp->loport), ntohs(prtspexp->hiport));
+ return rc = 1;
}
return rc;
}
DEBUGP("Searching at index %d NAT_PORT %hu CLIENT PORTS (%hu-%hu)\n", i,
ntohs(nat_port), rtsp_data_ports[i].client_udp_lo,
rtsp_data_ports[i].client_udp_hi);
- if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_lo) {
+ if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_lo ||
+ ntohs(nat_port) == rtsp_data_ports[i].client_udp_lo) {
tr_port = rtsp_data_ports[i].client_udp_lo;
DEBUGP("Found at index %d NAT_PORT %hu CLIENT PORTS (%hu-%hu) tr_port %hu\n", i,
nat_port, rtsp_data_ports[i].client_udp_lo,
rtsp_data_ports[i].client_udp_hi, tr_port);
- } else if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_hi) {
+ } else if (ntohs(nat_port) == rtsp_data_ports[i].nat_udp_hi ||
+ ntohs(nat_port) == rtsp_data_ports[i].client_udp_hi) {
tr_port = rtsp_data_ports[i].client_udp_hi;
DEBUGP("Found at index %d NAT_PORT %hu CLIENT PORTS %hu-%hu tr_port %hu\n", i,
nat_port, rtsp_data_ports[i].client_udp_lo,
DEBUGP("Found client info SRC IP %u.%u.%u.%u TCP PORT %hu UDP PORTS (%hu-%hu)\n",
NIPQUAD(iph->saddr), tcph->source, rtsp_data_ports[i].client_udp_lo,
rtsp_data_ports[i].client_udp_hi);
+ if (rtsp_data_ports[i].timeout_active)
+ {
+ del_timer(&rtsp_data_ports[i].pause_timeout);
+ rtsp_data_ports[i].timeout_active = 0;
+ }
+ memset(&rtsp_data_ports[i], 0, sizeof(struct _rtsp_data_ports));
rtsp_data_ports[i].in_use = 0;
- break;
+ //break;
}
}
}
const char* pparamend;
uint nextparamoff;
- pparamend = memchr(ptran+off, ',', tranlen-off);
+ pparamend = find_char(ptran+off, ',', tranlen-off);
pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
nextparamoff = pparamend-ptran;
else
{
prtspexp->loport = prtspexp->hiport = port;
+ DEBUGP("DASH or SLASH 0x%x\n", ptran[off]);
if (ptran[off] == '-')
{
off++;
return rc;
}
-static int
-rtp_expect(struct ip_conntrack *ct)
-{
- u_int16_t nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port;
- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- ct->nat.rtsp_info.orig_port = rtsp_nat_to_client_pmap(nat_port);
- DEBUGP("UDP client port %hu\n", ct->nat.rtsp_info.orig_port);
-
- return NF_ACCEPT;
-}
-
/*** conntrack functions ***/
/* outbound packet: client->server */
uint off;
int rc;
uint port = 0;
- int i = 0;
struct ip_conntrack_expect *new_exp = NULL;
+ int ret = 0;
if (!rtsp_parse_message(pdata, datalen, &dataoff,
&hdrsoff, &hdrslen,
break; /* not a valid message */
}
+ if (strncmp(pdata+cmdoff, "PLAY ", 5) == 0)
+ {
+ ip_conntrack_rtsp_proc_play(ct, iph);
+ continue;
+ }
+
+ if (strncmp(pdata+cmdoff, "PAUSE ", 6) == 0)
+ {
+ ip_conntrack_rtsp_proc_pause(ct, iph);
+ continue;
+ }
+
if (strncmp(pdata+cmdoff, "TEARDOWN ", 6) == 0)
{
ip_conntrack_rtsp_proc_teardown(iph); /* TEARDOWN message */
* Translate the original ports to the NAT ports and note them
* down to translate back in the return direction.
*/
- if (!rtsp_client_to_nat_pmap(&exp.help.exp_rtsp_info, iph, ct))
+ if (!(ret = rtsp_client_to_nat_pmap(&exp.help.exp_rtsp_info, iph, ct)))
{
DEBUGP("Dropping the packet. No more space in the mapping table\n");
UNLOCK_BH(&ip_rtsp_lock);
return NF_DROP;
}
- i = 0;
port = exp.help.exp_rtsp_info.loport;
- while (i < 2) {
+ while (port <= exp.help.exp_rtsp_info.hiport) {
/*
* Allocate expectation for tracking this connection
*/
DEBUGP("Adding UDP port %hu,%hu\n", htons(port), ntohs(port));
new_exp->tuple = ct->tuplehash[!dir].tuple;
- new_exp->tuple.dst.u.udp.port = htons(port);
+ if (ret == 2) {
+ new_exp->tuple.dst.u.udp.port = htons(g_tr_port);
+ g_tr_port++;
+ } else
+ new_exp->tuple.dst.u.udp.port = htons(port);
new_exp->tuple.dst.protonum = IPPROTO_UDP;
new_exp->mask.src.ip = 0xffffffff;
new_exp->mask.dst.ip = 0xffffffff;
- //exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
+ //new_exp->mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
new_exp->mask.dst.u.udp.port = 0xffff;
new_exp->expectfn = rtp_expect;
new_exp->mask.dst.protonum = 0xffff;
rc = ip_conntrack_expect_related(new_exp, ct);
if (rc == 0)
{
- DEBUGP("ip_conntrack_expect_related succeeded\n");
+ DEBUGP("ip_conntrack_expect_related succeeded loport\n");
}
else
{
- INFOP("ip_conntrack_expect_related failed\n");
+ DEBUGP("ip_conntrack_expect_related loport failed (%d)\n", rc);
}
port++;
- i++;
}
UNLOCK_BH(&ip_rtsp_lock);
}
DEBUGP("unregistering port %d\n", ports[i]);
ip_conntrack_helper_unregister(&rtsp_helpers[i]);
}
+ for (i = 0; i < MAX_PORT_MAPS; i++)
+ {
+ if (!rtsp_data_ports[i].in_use)
+ {
+ continue;
+ }
+ if (rtsp_data_ports[i].timeout_active == 1) {
+ del_timer(&rtsp_data_ports[i].pause_timeout);
+ }
+ }
}
static int __init