[ovs-dev] [PATCH 3/3] Conntrack: Support asymmetric RTP port for SIP.
Tiago Lam
tiagolam at gmail.com
Fri Dec 22 19:53:37 UTC 2017
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 at gmail.com>
---
lib/conntrack.c | 76 ++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 51 insertions(+), 25 deletions(-)
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);
}
}
}
--
2.14.3
More information about the dev
mailing list