From patchwork Mon Feb 12 23:08:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tiago Lam X-Patchwork-Id: 872514 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Z57Clqrx"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zgLzY2fyHz9s7M for ; Tue, 13 Feb 2018 10:12:25 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5295910A2; Mon, 12 Feb 2018 23:09:17 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E18B910A6 for ; Mon, 12 Feb 2018 23:09:14 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wr0-f193.google.com (mail-wr0-f193.google.com [209.85.128.193]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id C6A20405 for ; Mon, 12 Feb 2018 23:09:12 +0000 (UTC) Received: by mail-wr0-f193.google.com with SMTP id t94so16831144wrc.5 for ; Mon, 12 Feb 2018 15:09:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=p0zGnE7n39mj+SniW3qY7WxtmXDn1nOIrOf7L6zbJDs=; b=Z57ClqrxCth7vZ7p+o9ol5g9n7VmXvA+u/Ej0hTMrajR6f9w5DrtWX+fn6JUmAXEpX obRH6Agd0D6wXWj1S0dnlqkjlkAZk+wIYhrrH7GUGSg+y2vlbwCvWOfzaVgp8JffR8Mz j5fBQqh8jFQiw/UExvosOlb1hjRgeM5HJXa0wkqqJ1cI7tahHJu4pdOb6g8So52HerHn CWNZ7S3QWaOkChiBlddZ9B9tdozfREL7WlF3cwRg7ML8JMzenH/J/24Ko2AICp1Qgag1 M/6rjTW9HAGw1apDTSSxcqjOBt2sohPvY5MUONw+h/hbWlHWjrglGITmaEf54hg9y+4Q y5PA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=p0zGnE7n39mj+SniW3qY7WxtmXDn1nOIrOf7L6zbJDs=; b=cLp66rD+SdD4ZzhTUY5QRPEzF/iGXgXoWXy23fAcYONyEXIFUxGsMZTUL0X9y0A/s3 zeQ2UmD5lVT2cuMW17FVWQ1YpQbsn2wJ0CLUE75DqbzoheuCzP+z1zEPiNmIoC70FEoO 25r64NuiDnWIobZL+peE9voRvMYzI1usozN08oDHsJsmvlFkJ2O1DdFGpFKS6CcBfq3Z MMu5SrHTf+c+HC+bz95OV9bhSDhgXXwCoxx4L6o1EmYmvKYpBQ1lwO6T/HHtnxUy+K3K DnUOF8oOtczlvb2nZajuvGC8VeMvFEKEiA+KOIE9d9QqFu43dAERh0XLsNVKioPVqESg 1jFA== X-Gm-Message-State: APf1xPDlk/uat0R0FP2tmFNUPmaF2HMMng5tH09Fo8y+984kZr3fWTW+ V8Mo/nf0zxF21d+obRYhETnLRpk= X-Google-Smtp-Source: AH8x227xHHNPSXPKqTYx8c4HUlrcZfgtB8AQtSkDJBq8vXQB63PufKoodpt4mxuxESZvqjsc8hy/Zw== X-Received: by 10.223.199.194 with SMTP id y2mr9964887wrg.170.1518476950684; Mon, 12 Feb 2018 15:09:10 -0800 (PST) Received: from elche.localdomain (79-66-214-20.dynamic.dsl.as9105.com. [79.66.214.20]) by smtp.googlemail.com with ESMTPSA id z73sm16285673wrb.50.2018.02.12.15.09.09 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 12 Feb 2018 15:09:09 -0800 (PST) From: Tiago Lam To: dev@openvswitch.org Date: Mon, 12 Feb 2018 23:08:29 +0000 Message-Id: <20180212230829.31624-7-tiagolam@gmail.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180212230829.31624-1-tiagolam@gmail.com> References: <20180212230829.31624-1-tiagolam@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [RFC PATCH v2 6/6] Conntrack: Add UDP support for SIP. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The network protocol was already being verified in handle_sip in order to check the transport was indeed TCP. This commit adds support for UDP by checking the network protocol, and in case of UDP, a new function, handle_sip_udp, is called to handle the UDP traffic. This function also takes into account the framing of the SIP message under UDP. An end-to-end test has been added to system-traffic.at to cover the UDP transport. Similar to the TCP case, it also sets up two NS', NS1 and NS2, sets up the expected flows and then verifies that the traffic was handled correctly. More tests have also been added to test-sip.c to validate the correct handling of the UDP framing (if a "Content-Length" header exists then it must be taken into account). Signed-off-by: Tiago Lam --- lib/conntrack-sip.c | 94 +++++++++++++++++++++++++++- lib/conntrack-sip.h | 2 + lib/conntrack.c | 4 ++ tests/system-traffic.at | 71 +++++++++++++++++++++ tests/test-sip.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 328 insertions(+), 3 deletions(-) diff --git a/lib/conntrack-sip.c b/lib/conntrack-sip.c index c4ae8dc50..129ee5e7f 100644 --- a/lib/conntrack-sip.c +++ b/lib/conntrack-sip.c @@ -777,6 +777,95 @@ sip_parse_tcp_msg(char *sip, size_t sip_len) { return out_msg; } +/* Same as 'sip_parse_tcp' function above, but for SIP messages transported + * over UDP. Given a pointer to the beginning of a SIP message that has been + * transmitted over UDP, parses the SIP message. In case the message is not + * well framed or considered invalid, NULL is returned. + * + * 'sip' should point to the beginning of the SIP message. + * 'sip_len' the size of the whole SIP message. + * + * Returns a 'sip_msg' struct, which the caller is responsible for freeing. + * The returned 'sip_msg' has pointers to the parsed message-line, message- + * header, and message-body, as well as appropriate lengths set */ +struct sip_msg * +sip_parse_udp(char *sip, size_t sip_len) { + size_t orig_len = sip_len; + size_t cur_len = orig_len; + + struct sip_strt_ln *strt_ln = sip_parse_strt_ln(sip, sip_len); + if (strt_ln == NULL) { + return NULL; + } + + /* Pointer to the beginning of SIP message-header */ + char *msg_hdr = sip_msg_hdr(sip, &sip_len); + + size_t vlen; + int cont_len; + char *val = sip_get_hdr_val(msg_hdr, sip_len, SIPH_CONT_LEN, &vlen); + if (val == NULL) { + cont_len = 0; + } else { + cont_len = sip_hdr_to_uint(val, vlen); + if (cont_len < 0) { + return NULL; + } + } + + /* Pointer to the beginning of SIP message-body */ + char *msg_bdy = sip_msg_bdy(msg_hdr, &sip_len); + if (msg_bdy == NULL) { + return NULL; + } + + cur_len -= sip_len; + + size_t miss_len; + if (cont_len == 0) { + miss_len = orig_len - cur_len; + } else { + /* If a "Content-Length" header exists "the message body is assumed to + * contain that many bytes" ("18.3 Framing", rfc3261) */ + size_t exp_len = cur_len + cont_len; + if (exp_len > orig_len) { + /* Error: "Content-Length" points to more data than available */ + return NULL; + } else { + /* rfc3261, additional bytes in the transport packet beyond th end + * of the body MUST be discarded */ + miss_len = exp_len - cur_len; + } + } + + /* At most, UDP transports a single SIP message */ + struct sip_msg *out_msg = xmalloc(sizeof(*out_msg)); + out_msg->strt_ln = strt_ln; + out_msg->msg_hdr = msg_hdr; + out_msg->msg_bdy = msg_bdy; + out_msg->bdy_len = miss_len; + + return out_msg; +} + +static void +handle_sip_udp(struct conntrack *ct, struct dp_packet *pkt, + const struct conn *conn, long long now) { + struct udp_header *uh = dp_packet_l4(pkt); + size_t udp_len = ntohs(uh->udp_len) - UDP_HEADER_LEN; + char *udp_hdr = (char *) uh; + + /* Move to beginning of UDP payload, where the SIP payload is */ + char *sip = udp_hdr + UDP_HEADER_LEN; + size_t sip_len = udp_len; + + struct sip_msg *out_msg = sip_parse_udp(sip, sip_len); + + sip_process_msg(ct, pkt, conn, now, out_msg); + + free(out_msg); +} + /* Parses SIP messages over TCP. It relies on the "Content-Length" header to * know the full length of each SIP message. It returns a list of sip_msg * structs, with pointers to each parsed message-line, message-header, and @@ -842,8 +931,6 @@ handle_sip_tcp(struct conntrack *ct, struct dp_packet *pkt, /* XXX Only handles IPv4 for now, must include IPv6 in the future */ /* XXX NAT support hasn't been properly tested yet */ -/* XXX No support for SIP over UDP either (not tested at least), which might - * be required in the future */ void handle_sip(struct conntrack *ct, const struct conn_lookup_ctx *ctx OVS_UNUSED, @@ -861,6 +948,9 @@ handle_sip(struct conntrack *ct, if (conn->key.nw_proto == IPPROTO_TCP) { handle_sip_tcp(ct, pkt, conn, ctx->reply, now); return; + } else if (conn->key.nw_proto == IPPROTO_UDP) { + handle_sip_udp(ct, pkt, conn, now); + return; } else { /* Unrecognised transport for a SIP message */ pkt->md.ct_state |= CS_TRACKED | CS_INVALID; diff --git a/lib/conntrack-sip.h b/lib/conntrack-sip.h index 755ded565..ce284f443 100644 --- a/lib/conntrack-sip.h +++ b/lib/conntrack-sip.h @@ -128,6 +128,8 @@ sip_process_msgs(struct conntrack *ct, struct dp_packet *pkt, struct ovs_list *out_msgs); void free_sip_msg(struct sip_msg *out_msg); +struct sip_msg * +sip_parse_udp(char *sip, size_t sip_len); struct ovs_list * sip_parse_tcp(char *sip, size_t sip_len); void diff --git a/lib/conntrack.c b/lib/conntrack.c index 9387b0165..31ca5b39b 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -493,8 +493,12 @@ get_alg_ctl_type(const struct dp_packet *pkt, ovs_be16 tp_src, ovs_be16 tp_dst, } else if (ip_proto == IPPROTO_TCP && (th->tcp_src == sip_src_port || th->tcp_dst == sip_dst_port)) { return CT_ALG_CTL_SIP; + } else if (ip_proto == IPPROTO_UDP && + (uh->udp_src == sip_src_port || uh->udp_dst == sip_dst_port)) { + return CT_ALG_CTL_SIP; } + return CT_ALG_CTL_NONE; } diff --git a/tests/system-traffic.at b/tests/system-traffic.at index e8dba721a..0445f67f8 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -2941,6 +2941,77 @@ tcp,orig=(src=10.0.2.10,dst=10.0.1.10,sport=,dport=),reply=(sr OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +dnl Setups two namespaces, at_ns0 and at_ns1, connected to a bridge, br0, and +dnl runs sipp in both in the following form: +dnl - at_ns0 loads an UAS scenario and waits for requests; +dnl - at_ns1 loads an UAC scenario, which will connect to at_ns0. +dnl +dnl Aside from RTP (which is over UDP), this tests sends SIP over UDP over +dnl IPv4 and no NAT is performed. +AT_SETUP([conntrack - SIP over UDP over IPv4]) +AT_SKIP_IF([test $HAVE_SIPP = no]) +CHECK_CONNTRACK() +CHECK_CONNTRACK_ALG() + +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.0.1.10/24") +NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 00:00:00:00:01:10]) +ADD_VETH(p1, at_ns1, br0, "10.0.2.10/24") +NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 00:00:00:00:02:10]) +NS_CHECK_EXEC([at_ns0], [ip route add 10.0.2.0/24 via 10.0.1.10 dev p0]) +NS_CHECK_EXEC([at_ns1], [ip route add 10.0.1.0/24 via 10.0.2.10 dev p1]) + +dnl Allow any traffic from at_ns1->at_ns0. +dnl Only allow return traffic from at_ns0->at_ns1 (and arp, icmp). +AT_DATA([flows.txt], [dnl +dnl track all IPv4 traffic +table=0,priority=1,action=drop +table=0,priority=10,arp,action=normal +table=0,priority=10,icmp,action=normal +table=0,priority=100,in_port=2,udp,action=ct(alg=sip,commit),1 +table=0,priority=100,in_port=1,udp,action=ct(table=1) +table=0,priority=50,in_port=1,udp,action=ct(table=2) +table=0,priority=50,in_port=2,udp,action=ct(table=2) +dnl +dnl Table 1 +dnl +dnl Allow new TCPv4 TCP connections. +table=1,in_port=1,udp,ct_state=+trk+est,action=2 +table=1,in_port=1,udp,ct_state=+trk+rel,action=2 +dnl +dnl Table 2 +dnl +dnl Allow RTP (UDP) connections through. +table=2,in_port=2,udp,ct_state=+rel,action=1 +table=2,in_port=1,udp,ct_state=+rel,action=2 +]) + +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +NETNS_DAEMONIZE([at_ns0], [sipp -mi 10.0.1.10 -m 1 -d 20000 -sf $srcdir/sipp/uas_happy_case_scenario.xml], [sipp_uas.pid]) +OVS_WAIT_UNTIL([ip netns exec at_ns0 netstat -l | grep sip]) + +dnl Traffic between at_ns1<->at_ns0 should now start flowing. +NS_CHECK_EXEC([at_ns1], [sipp 10.0.1.10 -rp 1s -m 1 -d 23000 -mi 10.0.2.10 -sf $srcdir/sipp/uac_happy_case_scenario.xml +], [0], [stdout], [stderr]) + +dnl Wait until uas in at_ns0 is done processing all calls. +dnl sipp in at_ns1 (running as uac) is finished with the calls, and sipp in +dnl at_ns0 (running as uas) should be finished as well. If not, then something +dnl is not right and the test should fail. +OVS_WAIT_WHILE([ip netns exec at_ns0 netstat -l | grep sip]) + +dnl Discards CLOSE_WAIT and CLOSING +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.0.1.10)], [0], [dnl +udp,orig=(src=10.0.2.10,dst=10.0.1.10,sport=,dport=),reply=(src=10.0.1.10,dst=10.0.2.10,sport=,dport=),helper=sip +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + AT_BANNER([conntrack - NAT]) AT_SETUP([conntrack - simple SNAT]) diff --git a/tests/test-sip.c b/tests/test-sip.c index 602f52671..78249379e 100644 --- a/tests/test-sip.c +++ b/tests/test-sip.c @@ -78,6 +78,30 @@ static char *sip_invite_missing_cr = "Content-Length: 0\r\n" "\r\n"; +static char *sip_invite_no_cont_length = + "INVITE sip:service@10.0.1.10:5060 SIP/2.0\r\n" + "Via: SIP/2.0/TCP 10.0.2.10:5060;branch=z9hG4bK-26201-1-0\r\n" + "From: sipp ;tag=26201SIPpTag001\r\n" + "To: sut \r\n" + "Call-ID: 1-26201@10.0.2.10\r\n" + "CSeq: 1 INVITE\r\n" + "Contact: sip:sipp@10.0.2.10:5060\r\n" + "Max-Forwards: 70\r\n" + "\r\n"; + +static char *sip_invite_big_cont_length = + "INVITE sip:service@10.0.1.10:5060 SIP/2.0\r\n" + "Via: SIP/2.0/TCP 10.0.2.10:5060;branch=z9hG4bK-26201-1-0\r\n" + "From: sipp ;tag=26201SIPpTag001\r\n" + "To: sut \r\n" + "Call-ID: 1-26201@10.0.2.10\r\n" + "CSeq: 1 INVITE\r\n" + "Contact: sip:sipp@10.0.2.10:5060\r\n" + "Max-Forwards: 70\r\n" + "Content-Type: application/sdp\r\n" + "Content-Length: 500\r\n" + "\r\n"; + static void test_valid_sdp(void) { @@ -165,7 +189,138 @@ compose_dummy_tcp(struct dp_packet *pkt, const struct eth_addr eth_src, return th + TCP_HEADER_LEN; } -/* Test sip_parse_tcp function against multiple cases, including: +static void * +compose_dummy_udp(struct dp_packet *pkt, const struct eth_addr eth_src, + const struct eth_addr eth_dst, ovs_be32 ipv4_src, + ovs_be32 ipv4_dst, ovs_be16 port_src, ovs_be16 port_dst, + int size) +{ + struct udp_header *uh; + + eth_compose(pkt, eth_dst, eth_src, ETH_TYPE_IP, IP_HEADER_LEN); + uh = compose_dummy_ipv4(pkt, IPPROTO_UDP, ipv4_src, ipv4_dst, 0, 1, + UDP_HEADER_LEN, size); + + packet_set_udp_port(pkt, port_src, port_dst); + uh->udp_len = htons(UDP_HEADER_LEN + size); + + return uh + UDP_HEADER_LEN; +} + +/* Test sip_parse_udp function against multiple cases, including: + * - A SIP message with the "Content-Length" header set, checking if it is + * bigger than the transport packet or not; + * - A SIP message without the "Content-Length" set, which means teh whole UDP + * payload should be taken into account. */ + +static void +test_handle_udp_no_content_length(void) +{ + uint32_t stub[128 / 4]; + struct dp_packet packet; + + dp_packet_use_stub(&packet, stub, sizeof stub); + dp_packet_clear(&packet); + + compose_dummy_udp(&packet, DUMMY_ETH_ADDR, DUMMY_ETH_ADDR, + htonl(DUMMY_IP_ADDR),htonl(DUMMY_IP_ADDR), + htons(IPPORT_SIP), htons(IPPORT_SIP), + strlen(sip_invite_no_cont_length) + strlen(valid_sdp)); + /* Compose an SIP message. */ + dp_packet_put(&packet, sip_invite_no_cont_length, + strlen(sip_invite_no_cont_length)); + dp_packet_put(&packet, valid_sdp, strlen(valid_sdp)); + + struct udp_header *uh = dp_packet_l4(&packet); + size_t udp_len = ntohs(uh->udp_len) - UDP_HEADER_LEN; + char *udp_hdr = (char *) uh; + /* Move to beginning of UDP payload, where the SIP payload is */ + char *sip = udp_hdr + UDP_HEADER_LEN; + size_t sip_len = udp_len; + + struct sip_msg *out_msg = sip_parse_udp(sip, sip_len); + + ovs_assert(out_msg != NULL); + + struct sip_strt_ln *strt_ln = out_msg->strt_ln; + sip_len = out_msg->bdy_len; + + ovs_assert(strt_ln != NULL); + ovs_assert(strt_ln->type == REQUEST_LINE); + ovs_assert(strt_ln->reqs_ln->mthd == INVITE); + ovs_assert(sip_len == strlen(valid_sdp)); +} + +static void +test_handle_udp_with_short_content_length(void) +{ + uint32_t stub[128 / 4]; + struct dp_packet packet; + + dp_packet_use_stub(&packet, stub, sizeof stub); + dp_packet_clear(&packet); + + compose_dummy_udp(&packet, DUMMY_ETH_ADDR, DUMMY_ETH_ADDR, + htonl(DUMMY_IP_ADDR),htonl(DUMMY_IP_ADDR), + htons(IPPORT_SIP), htons(IPPORT_SIP), + strlen(sip_invite_with_sdp) + strlen(valid_sdp)); + /* Compose an SIP message. */ + dp_packet_put(&packet, sip_invite_with_sdp, strlen(sip_invite_with_sdp)); + dp_packet_put(&packet, valid_sdp, strlen(valid_sdp)); + /* Add more data available than needed */ + dp_packet_put_zeros(&packet, 100); + + struct udp_header *uh = dp_packet_l4(&packet); + size_t udp_len = ntohs(uh->udp_len) - UDP_HEADER_LEN; + char *udp_hdr = (char *) uh; + /* Move to beginning of UDP payload, where the SIP payload is */ + char *sip = udp_hdr + UDP_HEADER_LEN; + size_t sip_len = udp_len; + + struct sip_msg *out_msg = sip_parse_udp(sip, sip_len); + + ovs_assert(out_msg != NULL); + + struct sip_strt_ln *strt_ln = out_msg->strt_ln; + sip_len = out_msg->bdy_len; + + ovs_assert(strt_ln != NULL); + ovs_assert(strt_ln->type == REQUEST_LINE); + ovs_assert(strt_ln->reqs_ln->mthd == INVITE); + ovs_assert(sip_len == strlen(valid_sdp)); +} + +static void +test_handle_udp_with_big_content_length(void) +{ + uint32_t stub[128 / 4]; + struct dp_packet packet; + + dp_packet_use_stub(&packet, stub, sizeof stub); + dp_packet_clear(&packet); + + compose_dummy_udp(&packet, DUMMY_ETH_ADDR, DUMMY_ETH_ADDR, + htonl(DUMMY_IP_ADDR),htonl(DUMMY_IP_ADDR), + htons(IPPORT_SIP), htons(IPPORT_SIP), + strlen(sip_invite_big_cont_length) + strlen(valid_sdp)); + /* Compose an SIP message. */ + dp_packet_put(&packet, sip_invite_big_cont_length, + strlen(sip_invite_big_cont_length)); + dp_packet_put(&packet, valid_sdp, strlen(valid_sdp)); + + struct udp_header *uh = dp_packet_l4(&packet); + size_t udp_len = ntohs(uh->udp_len) - UDP_HEADER_LEN; + char *udp_hdr = (char *) uh; + /* Move to beginning of UDP payload, where the SIP payload is */ + char *sip = udp_hdr + UDP_HEADER_LEN; + size_t sip_len = udp_len; + + struct sip_msg *out_msg = sip_parse_udp(sip, sip_len); + + ovs_assert(out_msg == NULL); +} + +/* Test handle_sip_tcp function against multiple cases, including: * - A single TCP packet transporting a single SIP message; * - A single TCP packet transporting multiple SIP messages; * - A SIP message being carried across multiple TCP packets, i.e., a first @@ -321,6 +476,9 @@ test_sip_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) run_test(test_handle_single_tcp_single_sip); run_test(test_handle_single_tcp_multiple_sip); run_test(test_handle_single_tcp_incomplete_sip); + run_test(test_handle_udp_no_content_length); + run_test(test_handle_udp_with_short_content_length); + run_test(test_handle_udp_with_big_content_length); printf("executed %d tests\n", num_tests); }