[ovs-dev,3/3] Conntrack: Support asymmetric RTP port for SIP.

Message ID 20171222195337.28983-4-tiagolam@gmail.com
State Changes Requested
Headers show
Series
  • Initial support for new SIP Alg.
Related show

Commit Message

Tiago Lam Dec. 22, 2017, 7:53 p.m.
Previously, when creating the expecations, SIP Alg would assume the RTP
packets are sent from the same IP address + port which had been
announced in the SDP offer + answer. As specified in rfc4961, this might
not be the case, as the RTP packets might be sent from different IP
addresses and / or port.

This commit adds extra logic, by creating two expectations, one in each
direction, to support the "port case", i.e., the RTP packets are sent
from a different port than the one the host is listenning on.

Signed-off-by: Tiago Lam <tiagolam@gmail.com>
---
 lib/conntrack.c | 76 ++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 51 insertions(+), 25 deletions(-)

Patch

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 65d10dd08..0db3447f2 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -2610,32 +2610,31 @@  expectation_lookup(struct hmap *alg_expectations,
 
 static void
 sip_expectation_create(struct conntrack *ct,
-                       const ovs_be32 offer_addr,
-                       const ovs_be32 answer_addr,
-                       const ovs_be16 offer_port,
+                       const ovs_be32 src_addr,
+                       const ovs_be32 dst_addr,
+                       const ovs_be16 dst_port,
                        const long long now,
                        const struct conn *master_conn)
 {
-    /* Set src address coming from answer SDP 'c' */
-    struct ct_addr src_addr;
-    memset(&src_addr, 0, sizeof src_addr);
-    src_addr.ipv4_aligned = answer_addr;
-    /* Set dst address coming from offer SDP 'c' */
-    struct ct_addr dst_addr;
-    memset(&dst_addr, 0, sizeof dst_addr);
-    dst_addr.ipv4_aligned = offer_addr;
+    /* Set src address (from SDP's 'c') */
+    struct ct_addr ct_src_addr;
+    memset(&ct_src_addr, 0, sizeof ct_src_addr);
+    ct_src_addr.ipv4_aligned = src_addr;
+    /* Set dst address (from SDP's 'c') */
+    struct ct_addr ct_dst_addr;
+    memset(&ct_dst_addr, 0, sizeof ct_dst_addr);
+    ct_dst_addr.ipv4_aligned = dst_addr;
 
     struct alg_exp_node *alg_exp_node =
         xzalloc(sizeof *alg_exp_node);
     alg_exp_node->key.dl_type = master_conn->key.dl_type;
-    /* nw_proto might won't be the same as SIP, since RTP is over UDP - hence
-     * set it to UDP explicitly */
+    /* RTP is over UDP - hence set nw_proto to UDP explicitly */
     alg_exp_node->key.nw_proto = IPPROTO_UDP;
     alg_exp_node->key.zone = master_conn->key.zone;
-    alg_exp_node->key.src.addr = src_addr;
-    alg_exp_node->key.dst.addr = dst_addr;
+    alg_exp_node->key.src.addr = ct_src_addr;
+    alg_exp_node->key.dst.addr = ct_dst_addr;
     alg_exp_node->key.src.port = ALG_WC_SRC_PORT;
-    alg_exp_node->key.dst.port = offer_port;
+    alg_exp_node->key.dst.port = dst_port;
     alg_exp_node->master_mark = master_conn->mark;
     alg_exp_node->master_label = master_conn->label;
     alg_exp_node->master_key = master_conn->key;
@@ -2664,6 +2663,39 @@  sip_expectation_create(struct conntrack *ct,
     ct_rwlock_unlock(&ct->resources_lock);
 }
 
+/* Setups two expectations for the RTP connections, one in each direction.
+ * Example: If an SDP answer announces it is listenning at IP address 10.0.1.
+ * 10:6000 and an the SDP offer at 10.0.2.10:6000, then:
+ * - Sets a UDP expectation going from 10.0.1.10:0 to 10.0.2.10:6000:
+ * - Sets another UDP expectation going from 10.0.2.10:0 to 10.0.1.10:6000;
+ *
+ * Thus, this allows traffic from a different port than the one the host is
+ * listenning to (the one it announced in the SDP).
+ *
+ * XXX According to rfc4961, hosts might send RTP packets from a different IP
+ * address and / or port (i.e. asymmetrically). Since this function supports
+ * the sending of packets from a different port, consider supporting the
+ * sending from a different IP address.
+ */
+static void
+sip_expectations_setup(struct conntrack *ct,
+                       const struct sip_sdp *offer_sdp,
+                       const struct sip_sdp *answer_sdp,
+                       const long long now,
+                       const struct conn *conn) {
+    ovs_be32 offer_addr = htonl(offer_sdp->conn);
+    ovs_be16 offer_port = htons(offer_sdp->port);
+    ovs_be32 answer_addr = htonl(answer_sdp->conn);
+    ovs_be16 answer_port = htons(answer_sdp->port);
+
+    /* Set expectation from SDP answer -> SDP offer */
+    sip_expectation_create(ct, answer_addr, offer_addr, offer_port, now,
+                           conn);
+    /* Set expectation from SDP offer -> SDP answer */
+    sip_expectation_create(ct, offer_addr, answer_addr, answer_port, now,
+                           conn);
+}
+
 static void
 expectation_create(struct conntrack *ct,
                    ovs_be16 dst_port,
@@ -3383,9 +3415,6 @@  handle_sip(struct conntrack *ct,
 
             /* Check if this SIP reply has an SDP. */
             struct sip_sdp *sdp = sip_parse_sdp(msg_bdy, sip_len);
-            ovs_be32 offer_addr;
-            ovs_be32 offer_port;
-            ovs_be32 answer_addr;
             if (sdp == NULL) {
                 if (conn->sip_state->peer[0].sdp != NULL &&
                     conn->sip_state->peer[1].sdp == NULL) {
@@ -3400,12 +3429,9 @@  handle_sip(struct conntrack *ct,
                 /* Received a SIP 200 OK from peer, we are now able to set up
                  * the expectations for the data connections, based on the SDP
                  * offer and answer */
-                offer_addr = htonl(conn->sip_state->peer[0].sdp->conn);
-                offer_port = htons(conn->sip_state->peer[0].sdp->port);
-                answer_addr = htonl(conn->sip_state->peer[1].sdp->conn);
-
-                sip_expectation_create(ct, offer_addr, answer_addr, offer_port,
-                                       now, conn);
+                sip_expectations_setup(ct, conn->sip_state->peer[0].sdp,
+                                       conn->sip_state->peer[1].sdp, now,
+                                       conn);
             }
         }
     }