|
|
@ -235,7 +235,7 @@ |
|
|
|
+#endif /* _NETFILTER_MIME_H */
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/extensions/rtsp/nf_conntrack_rtsp.c
|
|
|
|
@@ -0,0 +1,576 @@
|
|
|
|
@@ -0,0 +1,732 @@
|
|
|
|
+/*
|
|
|
|
+ * RTSP extension for IP connection tracking
|
|
|
|
+ * (C) 2003 by Tom Marshall <tmarshall at real.com>
|
|
|
@ -250,7 +250,13 @@ |
|
|
|
+ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
|
|
|
|
+ * - fixed rtcp nat mapping and other port mapping fixes
|
|
|
|
+ * - simple TEARDOWN request handling
|
|
|
|
+ * - codestyle fixes and other less significant bug fixes
|
|
|
|
+ * - codestyle fixes and other less significant bug fixes
|
|
|
|
+ * 2018-04-17: Alin Nastac <alin.nastac at gmail.com>
|
|
|
|
+ * Hans Dedecker <dedeckeh at gmail.com>
|
|
|
|
+ * - use IP address read from SETUP URI in expected connections
|
|
|
|
+ * 2018-04-18: Hans Dedecker <dedeckeh at gmail.com>
|
|
|
|
+ * - update RTP expected connection source IP based on SOURCE
|
|
|
|
+ * in the SETUP reply message
|
|
|
|
+ *
|
|
|
|
+ * based on ip_conntrack_irc.c
|
|
|
|
+ *
|
|
|
@ -399,13 +405,14 @@ |
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Find lo/hi client ports (if any) in transport header
|
|
|
|
+ * Find lo/hi client ports and/or source (if any) in transport header
|
|
|
|
+ * In:
|
|
|
|
+ * ptcp, tcplen = packet
|
|
|
|
+ * tranoff, tranlen = buffer to search
|
|
|
|
+ *
|
|
|
|
+ * Out:
|
|
|
|
+ * pport_lo, pport_hi = lo/hi ports (host endian)
|
|
|
|
+ * srvaddr
|
|
|
|
+ *
|
|
|
|
+ * Returns nonzero if any client ports found
|
|
|
|
+ *
|
|
|
@ -482,6 +489,17 @@ |
|
|
|
+ }
|
|
|
|
+ rc = 1;
|
|
|
|
+ }
|
|
|
|
+ } else if (strncmp(ptran+off, "source=", 7) == 0) {
|
|
|
|
+ uint srcaddrlen;
|
|
|
|
+
|
|
|
|
+ off += 7;
|
|
|
|
+ srcaddrlen = nextfieldoff - off - 1;
|
|
|
|
+
|
|
|
|
+ if (in4_pton(ptran + off, srcaddrlen,
|
|
|
|
+ (u8 *)&prtspexp->srvaddr.in,
|
|
|
|
+ -1, NULL))
|
|
|
|
+ pr_debug("source found : %pI4\n",
|
|
|
|
+ &prtspexp->srvaddr.ip);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
@ -543,6 +561,7 @@ |
|
|
|
+ uint transoff = 0;
|
|
|
|
+ uint translen = 0;
|
|
|
|
+ uint off;
|
|
|
|
+ union nf_inet_addr srvaddr;
|
|
|
|
+
|
|
|
|
+ if (!rtsp_parse_message(pdata, datalen, &dataoff,
|
|
|
|
+ &hdrsoff, &hdrslen,
|
|
|
@ -559,6 +578,32 @@ |
|
|
|
+ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
|
|
|
|
+ continue; /* not a SETUP message */
|
|
|
|
+
|
|
|
|
+ srvaddr = ct->tuplehash[!dir].tuple.src.u3;
|
|
|
|
+
|
|
|
|
+ /* try to get RTP media source from SETUP URI */
|
|
|
|
+ off = cmdoff + 6;
|
|
|
|
+ while (off < datalen) {
|
|
|
|
+ if (strncmp(pdata+off, "://", 3) == 0) {
|
|
|
|
+ off += 3;
|
|
|
|
+ cmdoff = off;
|
|
|
|
+
|
|
|
|
+ while (off < datalen) {
|
|
|
|
+ if (pdata[off] == ':' ||
|
|
|
|
+ pdata[off] == '/' ||
|
|
|
|
+ pdata[off] == ' ') {
|
|
|
|
+ in4_pton(pdata + cmdoff,
|
|
|
|
+ off - cmdoff,
|
|
|
|
+ (u8 *)&srvaddr.in,
|
|
|
|
+ -1, NULL);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ off++;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ off++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pr_debug("found a setup message\n");
|
|
|
|
+
|
|
|
|
+ off = 0;
|
|
|
@ -583,8 +628,7 @@ |
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
|
|
|
|
+ nf_ct_l3num(ct),
|
|
|
|
+ NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */
|
|
|
|
+ nf_ct_l3num(ct), &srvaddr,
|
|
|
|
+ &ct->tuplehash[!dir].tuple.dst.u3,
|
|
|
|
+ IPPROTO_UDP, NULL, &be_loport);
|
|
|
|
+
|
|
|
@ -601,8 +645,7 @@ |
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
|
|
|
|
+ nf_ct_l3num(ct),
|
|
|
|
+ NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */
|
|
|
|
+ nf_ct_l3num(ct), &srvaddr,
|
|
|
|
+ &ct->tuplehash[!dir].tuple.dst.u3,
|
|
|
|
+ IPPROTO_UDP, NULL, &be_hiport);
|
|
|
|
+
|
|
|
@ -659,11 +702,120 @@ |
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline int
|
|
|
|
+help_in(struct sk_buff *skb, size_t pktlen,
|
|
|
|
+ struct nf_conn* ct, enum ip_conntrack_info ctinfo)
|
|
|
|
+{
|
|
|
|
+ return NF_ACCEPT;
|
|
|
|
+}
|
|
|
|
+help_in(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
|
|
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
|
|
|
|
+ struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
|
|
|
+ unsigned int protoff)
|
|
|
|
+#else
|
|
|
|
+ struct nf_conn *ct, enum ip_conntrack_info ctinfo)
|
|
|
|
+#endif
|
|
|
|
+ {
|
|
|
|
+ struct ip_ct_rtsp_expect expinfo;
|
|
|
|
+ union nf_inet_addr srvaddr;
|
|
|
|
+ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */
|
|
|
|
+ int len;
|
|
|
|
+ char* pdata = rb_ptr;
|
|
|
|
+ uint dataoff = 0;
|
|
|
|
+ int ret = NF_ACCEPT;
|
|
|
|
+ u_int8_t family;
|
|
|
|
+ struct nf_conntrack_expect *exp_ct = NULL;
|
|
|
|
+ struct nf_conntrack_tuple t;
|
|
|
|
+ struct net *net = nf_ct_net(ct);
|
|
|
|
+
|
|
|
|
+ memset(&expinfo, 0, sizeof(expinfo));
|
|
|
|
+
|
|
|
|
+ while (dataoff < datalen) {
|
|
|
|
+ uint cmdoff = dataoff;
|
|
|
|
+ uint hdrsoff = 0;
|
|
|
|
+ uint hdrslen = 0;
|
|
|
|
+ uint cseqoff = 0;
|
|
|
|
+ uint cseqlen = 0;
|
|
|
|
+ uint transoff = 0;
|
|
|
|
+ uint translen = 0;
|
|
|
|
+
|
|
|
|
+ if (!rtsp_parse_message(pdata, datalen, &dataoff,
|
|
|
|
+ &hdrsoff, &hdrslen,
|
|
|
|
+ &cseqoff, &cseqlen,
|
|
|
|
+ &transoff, &translen))
|
|
|
|
+ break; /* not a valid message */
|
|
|
|
+
|
|
|
|
+ if (strncmp(pdata+cmdoff, "RTSP/", 5) == 0 && translen) {
|
|
|
|
+ union nf_inet_addr zeroaddr;
|
|
|
|
+
|
|
|
|
+ memset(&zeroaddr, 0, sizeof(zeroaddr));
|
|
|
|
+
|
|
|
|
+ if (!rtsp_parse_transport(pdata+transoff, translen, &expinfo))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ srvaddr = expinfo.srvaddr;
|
|
|
|
+
|
|
|
|
+ if (nf_inet_addr_cmp(&srvaddr, &ct->tuplehash[dir].tuple.src.u3) ||
|
|
|
|
+ nf_inet_addr_cmp(&srvaddr, &zeroaddr))
|
|
|
|
+ continue;
|
|
|
|
+ } else
|
|
|
|
+ continue; /* not valid RTSP reply */
|
|
|
|
+
|
|
|
|
+ if (expinfo.loport == 0) {
|
|
|
|
+ pr_debug("no udp transports found\n");
|
|
|
|
+ continue; /* no udp transports found */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ family = nf_ct_l3num(ct);
|
|
|
|
+ if (family == AF_INET)
|
|
|
|
+ len = 4;
|
|
|
|
+ else
|
|
|
|
+ len = 16;
|
|
|
|
+
|
|
|
|
+ /* replace rtp expect src addr */
|
|
|
|
+ t.src.l3num = family;
|
|
|
|
+ t.dst.protonum = IPPROTO_UDP;
|
|
|
|
+
|
|
|
|
+ memcpy(&t.src.u3, &ct->tuplehash[dir].tuple.src.u3, len);
|
|
|
|
+ if (sizeof(t.src.u3) > len)
|
|
|
|
+ /* address needs to be cleared for nf_ct_tuple_equal */
|
|
|
|
+ memset((void *)&t.src.u3 + len, 0, sizeof(t.src.u3) - len);
|
|
|
|
+
|
|
|
|
+ t.src.u.all = 0;
|
|
|
|
+
|
|
|
|
+ memcpy(&t.dst.u3, &ct->tuplehash[dir].tuple.dst.u3, len);
|
|
|
|
+ if (sizeof(t.dst.u3) > len)
|
|
|
|
+ /* address needs to be cleared for nf_ct_tuple_equal */
|
|
|
|
+ memset((void *)&t.dst.u3 + len, 0, sizeof(t.dst.u3) - len);
|
|
|
|
+
|
|
|
|
+ t.dst.u.all = htons(expinfo.loport);
|
|
|
|
+
|
|
|
|
+ /* get the rtp expect and replace the srcaddr with RTP server addr */
|
|
|
|
+ exp_ct = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t);
|
|
|
|
+ if (exp_ct) {
|
|
|
|
+ memcpy(&exp_ct->tuple.src.u3, &srvaddr, len);
|
|
|
|
+ if (sizeof(exp_ct->tuple.src.u3) > len)
|
|
|
|
+ /* address needs to be cleared for nf_ct_tuple_equal */
|
|
|
|
+ memset((void *)&exp_ct->tuple.src.u3 + len, 0,
|
|
|
|
+ sizeof(exp_ct->tuple.src.u3) - len);
|
|
|
|
+ } else
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ /* replace rtcp expect src addr */
|
|
|
|
+ if (expinfo.pbtype == pb_range) {
|
|
|
|
+ t.dst.u.all = htons(expinfo.hiport);
|
|
|
|
+
|
|
|
|
+ /* get the rtcp expect and replace the srcaddr with RTP server addr */
|
|
|
|
+ exp_ct = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t);
|
|
|
|
+ if (exp_ct) {
|
|
|
|
+ memcpy(&exp_ct->tuple.src.u3, &srvaddr, len);
|
|
|
|
+ if (sizeof(exp_ct->tuple.src.u3) > len)
|
|
|
|
+ /* address needs to be cleared for nf_ct_tuple_equal */
|
|
|
|
+ memset((void *)&exp_ct->tuple.src.u3 + len, 0,
|
|
|
|
+ sizeof(exp_ct->tuple.src.u3) - len);
|
|
|
|
+ } else
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+out:
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+static int help(struct sk_buff *skb, unsigned int protoff,
|
|
|
|
+ struct nf_conn *ct, enum ip_conntrack_info ctinfo)
|
|
|
@ -720,7 +872,11 @@ |
|
|
|
+ case IP_CT_DIR_REPLY:
|
|
|
|
+ pr_debug("IP_CT_DIR_REPLY\n");
|
|
|
|
+ /* inbound packet: server->client */
|
|
|
|
+ ret = NF_ACCEPT;
|
|
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
|
|
|
|
+ ret = help_in(skb, rb_ptr, datalen, ct, ctinfo, protoff);
|
|
|
|
+#else
|
|
|
|
+ ret = help_in(skb, rb_ptr, datalen, ct, ctinfo);
|
|
|
|
+#endif
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
@ -814,7 +970,7 @@ |
|
|
|
+module_exit(fini);
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/extensions/rtsp/nf_conntrack_rtsp.h
|
|
|
|
@@ -0,0 +1,72 @@
|
|
|
|
@@ -0,0 +1,73 @@
|
|
|
|
+/*
|
|
|
|
+ * RTSP extension for IP connection tracking.
|
|
|
|
+ * (C) 2003 by Tom Marshall <tmarshall at real.com>
|
|
|
@ -861,13 +1017,14 @@ |
|
|
|
+ */
|
|
|
|
+struct ip_ct_rtsp_expect
|
|
|
|
+{
|
|
|
|
+ u_int32_t len; /* length of header block */
|
|
|
|
+ portblock_t pbtype; /* Type of port block that was requested */
|
|
|
|
+ u_int16_t loport; /* Port that was requested, low or first */
|
|
|
|
+ u_int16_t hiport; /* Port that was requested, high or second */
|
|
|
|
+ u_int32_t len; /* length of header block */
|
|
|
|
+ portblock_t pbtype; /* Type of port block that was requested */
|
|
|
|
+ u_int16_t loport; /* Port that was requested, low or first */
|
|
|
|
+ u_int16_t hiport; /* Port that was requested, high or second */
|
|
|
|
+ union nf_inet_addr srvaddr; /* src address in SETUP reply */
|
|
|
|
+#if 0
|
|
|
|
+ uint method; /* RTSP method */
|
|
|
|
+ uint cseq; /* CSeq from request */
|
|
|
|
+ uint method; /* RTSP method */
|
|
|
|
+ uint cseq; /* CSeq from request */
|
|
|
|
+#endif
|
|
|
|
+};
|
|
|
|
+
|
|
|
|