]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[mod_sofia] fix md5 digest infoleak
authorDragos Oancea <dragos@signalwire.com>
Thu, 13 May 2021 13:49:09 +0000 (13:49 +0000)
committerAndrey Volk <andywolk@gmail.com>
Fri, 13 Aug 2021 15:17:17 +0000 (18:17 +0300)
[mod_sofia] refactor IP checks with sip-dig

[mod_sofia] add sipp-based unit-tests (use spawn_instead_of_system)

17 files changed:
src/mod/endpoints/mod_sofia/Makefile.am
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sip-dig.c
src/mod/endpoints/mod_sofia/sip-dig.h [new file with mode: 0644]
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_reg.c
src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/sipp-based-tests.c [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-ipv6.xml [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-tcp.xml [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak.xml [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/test_run_sipp.sh [new file with mode: 0755]
src/mod/endpoints/mod_sofia/test/voicemail/vm-goodbye.wav [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/voicemail/vm-not_available.wav [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/voicemail/vm-person.wav [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/voicemail/vm-record_message.wav [new file with mode: 0644]
src/mod/endpoints/mod_sofia/test/voicemail/vm-too-small.wav [new file with mode: 0644]

index 69343c455a9c320a5058d3b9a7c3b7be672e13df..461db1e6e5f1da5187a57d369f8fd9cb8c2aaa6d 100644 (file)
@@ -3,7 +3,7 @@ include $(top_srcdir)/build/modmake.rulesam
 MODNAME=mod_sofia
 
 noinst_LTLIBRARIES = libsofiamod.la
-libsofiamod_la_SOURCES   =  mod_sofia.c sofia.c sofia_json_api.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_media.c sip-dig.c rtp.c mod_sofia.h
+libsofiamod_la_SOURCES   =  mod_sofia.c sofia.c sofia_json_api.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_media.c sip-dig.c rtp.c mod_sofia.h sip-dig.h
 libsofiamod_la_LDFLAGS   = -static
 libsofiamod_la_CFLAGS  = $(AM_CFLAGS) -I. $(SOFIA_SIP_CFLAGS) $(STIRSHAKEN_CFLAGS)
 if HAVE_STIRSHAKEN
@@ -15,7 +15,7 @@ mod_sofia_la_SOURCES =
 mod_sofia_la_LIBADD = $(switch_builddir)/libfreeswitch.la libsofiamod.la
 mod_sofia_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(SOFIA_SIP_LIBS) $(STIRSHAKEN_LIBS)
 
-noinst_PROGRAMS = test/test_sofia_funcs test/test_nuafail
+noinst_PROGRAMS = test/test_sofia_funcs test/test_nuafail test/sipp-based-tests
 
 test_test_sofia_funcs_SOURCES = test/test_sofia_funcs.c
 test_test_sofia_funcs_CFLAGS = $(AM_CFLAGS) $(SOFIA_SIP_CFLAGS) $(STIRSHAKEN_CFLAGS) -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\"
@@ -33,11 +33,17 @@ endif
 test_test_nuafail_LDFLAGS = $(AM_LDFLAGS) -avoid-version -no-undefined $(freeswitch_LDFLAGS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS) $(STIRSHAKEN_LIBS)
 test_test_nuafail_LDADD = libsofiamod.la $(SOFIA_SIP_LIBS)
 
-TESTS = test/test_sofia_funcs.sh test/test_nuafail
+test_sipp_based_tests_SOURCES = test/sipp-based-tests.c
+test_sipp_based_tests_CFLAGS = $(AM_CFLAGS) $(SOFIA_SIP_CFLAGS) -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\"
+test_sipp_based_tests_LDFLAGS = $(AM_LDFLAGS) -avoid-version -no-undefined $(freeswitch_LDFLAGS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS)
+test_sipp_based_tests_LDADD = libsofiamod.la $(SOFIA_SIP_LIBS)
+
+TESTS = test/test_sofia_funcs.sh test/test_nuafail test/test_run_sipp.sh
 
 if ISMAC
 mod_sofia_la_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
 test_test_sofia_funcs_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
 test_test_nuafail_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
+test_sipp_based_tests_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
 endif
 
index 02128bf2fd7294b2370d3f08d8c868f502df0741..63697dbbda78db54f82216d5a411c0e017c2be04 100644 (file)
@@ -91,6 +91,7 @@ typedef struct private_object private_object_t;
 #define MY_EVENT_REINVITE "sofia::reinvite"
 #define MY_EVENT_GATEWAY_ADD "sofia::gateway_add"
 #define MY_EVENT_GATEWAY_DEL "sofia::gateway_delete"
+#define MY_EVENT_GATEWAY_INVALID_DIGEST_REQ "sofia::gateway_invalid_digest_req"
 #define MY_EVENT_RECOVERY "sofia::recovery_recv"
 #define MY_EVENT_RECOVERY_SEND "sofia::recovery_send"
 #define MY_EVENT_RECOVERY_RECOVERED "sofia::recovery_recovered"
@@ -570,6 +571,7 @@ struct sofia_gateway {
        sofia_cid_type_t cid_type;
        char register_network_ip[80];
        int register_network_port;
+       char *gw_auth_acl;
 };
 
 typedef enum {
index 2d74eb66f686b2e9daa738095cf74ed06ed46479..e89f5aef440126f1124d6a5a3cafb3cf17ec258a 100644 (file)
 #include "sofia-sip/su_alloc.h"
 #include "sofia-sip/su_string.h"
 #include "sofia-sip/hostdomain.h"
+#include "sip-dig.h"
+#include "mod_sofia.h"
 
 char const name[] = "sip-dig";
 
@@ -151,59 +153,51 @@ char const name[] = "sip-dig";
 #include <string.h>
 #include <stdio.h>
 
-enum { N_TPORT = 16 };
-
-struct transport { char const *name, *service, *srv; };
-
-struct dig {
-       sres_resolver_t *sres;
-
-       unsigned preference, ip4, ip6, sips, print;
-
-       struct transport tports[N_TPORT + 1];
-};
-
-int dig_naptr(struct dig *dig, char const *host, double weight, switch_stream_handle_t *stream);
-
-int dig_all_srvs(struct dig *dig, char const *tport, char const *host,
-                                double weight, switch_stream_handle_t *stream);
+void _usage(int exitcode, switch_stream_handle_t *stream)
+{
+       stream->write_function(stream, "%s", "usage: sofia_dig [OPTIONS] [@dnsserver] uri\n");
+}
 
-int dig_srv(struct dig *dig, char const *tport, char const *host,
-                       double weight, switch_stream_handle_t *stream);
+#define usage(_x) _usage(_x, stream); goto fail
 
-int dig_srv_at(struct dig *dig,
-                          char const *tport, sres_record_t **answers,
-                          double weight, int pweight,
-                          int priority, switch_stream_handle_t *stream);
+switch_bool_t verify_ip(sres_record_t **answers, const char *ip, switch_bool_t ipv6) 
+{
+       char addr[64];
+       int i;
 
-int dig_addr(struct dig *dig,
-                        char const *tport, char const *host, char const *port,
-                        double weight, switch_stream_handle_t *stream);
+       if (!answers) {
+               return SWITCH_FALSE;
+       }
 
-void print_addr_results(struct transport const *tports,
-                                               char const *tport, char const *tport2,
-                                               sres_record_t **answers, int type, int af,
-                                               char const *port,
-                                               double weight, int preference, switch_stream_handle_t *stream);
+       if (!*answers) {
+               return SWITCH_FALSE;
+       }
 
-void print_result(char const *addr, char const *port, char const *tport,
-                                 double weight,
-                                 unsigned preference,
-                                 switch_stream_handle_t *stream);
+       for (i = 0; answers[i]; i++) {
+               if (ipv6) {
+                       if (answers[i]->sr_record->r_type != sres_type_aaaa)
+                               continue;
+               } else {
+                       if (answers[i]->sr_record->r_type != sres_type_a)
+                               continue;
+               }
+               if (answers[i]->sr_record->r_status != 0)
+                       continue;
 
-int prepare_transport(struct dig *dig, char const *tport);
+               if (ipv6) {
+                       su_inet_ntop(AF_INET6, &answers[i]->sr_aaaa->aaaa_addr, addr, sizeof addr);
+               } else {
+                       su_inet_ntop(AF_INET, &answers[i]->sr_a->a_addr, addr, sizeof addr);
+               }
 
-int count_transports(struct dig *dig,
-                                        char const *tp1,
-                                        char const *tp2);
+               if (ip && !strcmp(addr, ip)) {
+                       return SWITCH_TRUE;
+               }
+       }
 
-void _usage(int exitcode, switch_stream_handle_t *stream)
-{
-       stream->write_function(stream, "%s", "usage: sofia_dig [OPTIONS] [@dnsserver] uri\n");
+       return SWITCH_FALSE;
 }
 
-#define usage(_x) _usage(_x, stream); goto fail
-
 switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream)
 
 {
@@ -608,6 +602,27 @@ int dig_naptr(struct dig *dig,
        return count;
 }
 
+switch_bool_t dig_all_srvs_simple(struct dig *dig,
+                                                               char const *host, char const *ip, switch_bool_t ipv6)
+{
+       sres_record_t **answers;
+       char *domain = su_strcat(NULL, dig->tports[0].srv, host);
+       switch_bool_t ret;
+       int error = -1;
+
+       if (domain) {
+               error = sres_blocking_query(dig->sres, sres_type_srv, domain, 0, &answers);
+               free(domain);
+       }
+
+       if (error >= 0) {
+               ret = dig_srv_at_simple_verify(dig, dig->tports[0].name, answers, ip, ipv6);
+               if (ret) return SWITCH_TRUE;
+       }
+
+       return SWITCH_FALSE;
+}
+
 int dig_all_srvs(struct dig *dig,
                                 char const *tport,
                                 char const *host,
@@ -735,6 +750,36 @@ int dig_srv(struct dig *dig,
        return count;
 }
 
+switch_bool_t dig_srv_at_simple_verify(struct dig *dig,
+                       char const *tport,
+                       sres_record_t **answers, const char *ip, switch_bool_t ipv6)
+{
+       int i;
+       sres_record_t **retanswers = { 0 };
+
+       if (!answers) {
+               return SWITCH_FALSE;
+       }
+
+       for (i = 0; answers[i]; i++) {
+               sres_srv_record_t const *srv = answers[i]->sr_srv;
+               if (srv->srv_record->r_type != sres_type_srv)
+                       continue;
+               if (srv->srv_record->r_status != 0)
+                       continue;
+               retanswers = dig_addr_simple(dig, srv->srv_target, ipv6?sres_type_aaaa:sres_type_a);
+               if (verify_ip(retanswers, ip, ipv6)) {
+                       sres_free_answers(dig->sres, retanswers);
+                       return SWITCH_TRUE;
+               }
+       }
+
+       if (retanswers && *retanswers) {
+               sres_free_answers(dig->sres, retanswers);
+       }
+       return SWITCH_FALSE;
+}
+
 int dig_srv_at(struct dig *dig,
                           char const *tport,
                           sres_record_t **answers,
@@ -758,7 +803,6 @@ int dig_srv_at(struct dig *dig,
                if (srv->srv_priority != priority)
                        continue;
                snprintf(port, sizeof port, "%u", srv->srv_port);
-
                count += dig_addr(dig, tport, srv->srv_target, port,
                                                  weight * srv->srv_weight / pweight, stream);
        }
@@ -766,6 +810,17 @@ int dig_srv_at(struct dig *dig,
        return count;
 }
 
+sres_record_t ** dig_addr_simple(struct dig *dig,
+                                                               char const *host,
+                                                               uint16_t type) 
+{
+       sres_record_t **answers = NULL;
+
+       sres_blocking_query(dig->sres, type, host, 0, &answers);
+
+       return answers;
+}
+
 int dig_addr(struct dig *dig,
                         char const *tport,
                         char const *host,
diff --git a/src/mod/endpoints/mod_sofia/sip-dig.h b/src/mod/endpoints/mod_sofia/sip-dig.h
new file mode 100644 (file)
index 0000000..10dd76a
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * This is an example program for @b sresolv library in synchronous mode.
+ *
+ * @author Pekka Pessi <Pekka.Pessi@nokia.com>
+ *
+ * @date Original Created: Tue Jul 16 18:50:14 2002 ppessi
+ */
+
+/**@page sip-dig Resolve SIP URIs.
+ *
+ * @section sip_dig_synopsis Synopsis
+ * <tt>sip-dig [OPTIONS] uri...</tt>
+ *
+ * @section sip_dig_description Description
+ * The @em sip-dig utility resolves SIP URIs as described in @RFC3263. It
+ * queries NAPTR, SRV and A/AAAA records and prints out the resulting
+ * transport addresses.
+ *
+ * The default transports are: UDP, TCP, SCTP, TLS and TLS-SCTP. The SIPS
+ * URIs are resolved using only TLS transports, TLS and TLS-SCTP. If not
+ * otherwise indicated by NAPTR or SRV records, the sip-dig uses UDP and TCP
+ * as transports for SIP and TLS for SIPS URIs.
+ *
+ * The results are printed intended, with a preference followed by weight,
+ * then protocol name, port number and IP address in numeric format.
+ *
+ * @section sip_dig_options Command Line Options
+ * The @e sip-dig utility accepts following command line options:
+ * <dl>
+ * <dt>-p <em>protoname</em></dt>
+ * <dd>Use named transport protocol. The <em>protoname</em> can be either
+ * well-known, e.g., "udp", or it can specify NAPTR service and SRV
+ * identifier, e.g., "tls-udp/SIPS+D2U/_sips._udp.".
+ * </dd>
+ * <dt>--udp</dt>
+ * <dd>Use UDP transport protocol.
+ * </dd>
+ * <dt>--tcp</dt>
+ * <dd>Use TCP transport protocol.
+ * </dd>
+ * <dt>--tls</dt>
+ * <dd>Use TLS over TCP transport protocol.
+ * </dd>
+ * <dt>--sctp</dt>
+ * <dd>Use SCTP transport protocol.
+ * </dd>
+ * <dt>--tls-sctp</dt>
+ * <dd>Use TLS over SCTP transport protocol.
+ * </dd>
+ * <dt>--no-sctp</dt>
+ * <dd>Ignore SCTP or TLS-SCTP records in the list of default transports.
+ * This option has no effect if transport protocols has been explicitly
+ * listed.
+ * </dd>
+ * <dt>-4</dt>
+ * <dd>Query IP4 addresses (A records)
+ * </dd>
+ * <dt>-6</dt>
+ * <dd>Query IP6 addresses (AAAA records).
+ * </dd>
+ * <dt>-v</dt>
+ * <dd>Be verbatim.
+ * </dd>
+ * <dt></dt>
+ * <dd>
+ * </dd>
+ * </dl>
+ *
+ * @section sip_dig_return Return Codes
+ * <table>
+ * <tr><td>0<td>when successful (a 2XX-series response is received)
+ * <tr><td>1<td>when unsuccessful (a 3XX..6XX-series response is received)
+ * <tr><td>2<td>initialization failure
+ * </table>
+ *
+ * @section sip_dig_examples Examples
+ *
+ * Resolve sip:openlaboratory.net, prefer TLS over TCP, TCP over UDP:
+ * @code
+ * $ sip-dig --tls --tcp --udp sip:openlaboratory.net
+ *     1 0.333 tls 5061 212.213.221.127
+ *     2 0.333 tcp 5060 212.213.221.127
+ *     3 0.333 udp 5060 212.213.221.127
+ * @endcode
+ *
+ * Resolve sips:example.net with TLS over SCTP (TLS-SCTP) and TLS:
+ * @code
+ * $ sip-dig -p tls-sctp --tls sips:example.net
+ *     1 0.500 tls-udp 5061 172.21.55.26
+ *     2 0.500 tls 5061 172.21.55.26
+ * @endcode
+ *
+ * @section sip_dig_environment Environment
+ * #SRESOLV_DEBUG, SRESOLV_CONF
+ *
+ * @section sip_dig_bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel@lists.sourceforge.net>.
+ *
+ * @section sip_dig_author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section sip_dig_copyright Copyright
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_record.h"
+
+enum { N_TPORT = 16 };
+
+struct transport { char const *name, *service, *srv; };
+
+struct dig {
+       sres_resolver_t *sres;
+
+       unsigned preference, ip4, ip6, sips, print;
+
+       struct transport tports[N_TPORT + 1];
+};
+
+int dig_naptr(struct dig *dig, char const *host, double weight, switch_stream_handle_t *stream);
+
+int dig_all_srvs(struct dig *dig, char const *tport, char const *host,
+                                double weight, switch_stream_handle_t *stream);
+
+int dig_srv(struct dig *dig, char const *tport, char const *host,
+                       double weight, switch_stream_handle_t *stream);
+
+int dig_srv_at(struct dig *dig,
+                          char const *tport, sres_record_t **answers,
+                          double weight, int pweight,
+                          int priority, switch_stream_handle_t *stream);
+
+int dig_addr(struct dig *dig,
+                        char const *tport, char const *host, char const *port,
+                        double weight, switch_stream_handle_t *stream);
+
+void print_addr_results(struct transport const *tports,
+                                               char const *tport, char const *tport2,
+                                               sres_record_t **answers, int type, int af,
+                                               char const *port,
+                                               double weight, int preference, switch_stream_handle_t *stream);
+
+void print_result(char const *addr, char const *port, char const *tport,
+                                 double weight,
+                                 unsigned preference,
+                                 switch_stream_handle_t *stream);
+
+int prepare_transport(struct dig *dig, char const *tport);
+
+int count_transports(struct dig *dig,
+                                        char const *tp1,
+                                        char const *tp2);
+
+switch_bool_t dig_srv_at_simple_verify(struct dig *dig,
+                       char const *tport,
+                       sres_record_t **answers, const char *ip, switch_bool_t ipv6);
+
+switch_bool_t dig_all_srvs_simple(struct dig *dig,
+                                                               char const *host, const char *ip, switch_bool_t ipv6); 
+
+sres_record_t ** dig_addr_simple(struct dig *dig,
+                                                               char const *host,
+                                                               uint16_t type); 
+
+switch_bool_t sofia_sip_resolve_compare(const char *domainname, const char *ip);
+
+switch_bool_t verify_ip(sres_record_t **answers, const char *ip, switch_bool_t ipv6);
+
index 3474df96bd47d9090d9f01dccb34a92ffc197892..54d0dbdfe8dc05885b3e375e5dc0dae0e4fd5238 100644 (file)
@@ -3973,6 +3973,10 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag,
                                        }
 
                                        gateway->register_transport = transport;
+                               } else if (!strcmp(var, "gw-auth-acl")) {
+                                       if (!zstr(val)) {
+                                               gateway->gw_auth_acl = switch_core_strdup(gateway->pool, val);
+                                       }
                                }
                        }
 
index 6263e05170d6895a436ea8e90b383db482c390c0..03cb0fb6d04cfa40c046634bf98e12fba1e5670a 100644 (file)
@@ -38,6 +38,8 @@
  *
  */
 #include "mod_sofia.h"
+#include "sofia-sip/hostdomain.h"
+#include "sip-dig.h"
 
 static void sofia_reg_new_handle(sofia_gateway_t *gateway_ptr, int attach)
 {
@@ -2432,6 +2434,126 @@ void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_h
 
 }
 
+switch_bool_t sip_resolve_prepare_transport(struct dig *dig, sofia_transport_t tport)
+{
+       struct transport *tports = dig->tports;
+
+       if (tport == SOFIA_TRANSPORT_UDP) {
+               tports[0].name = "udp";
+               tports[0].service = "SIP+D2U";
+               tports[0].srv = "_sip._udp.";
+       }
+       else if (tport == SOFIA_TRANSPORT_TCP) {
+               tports[0].name = "tcp";
+               tports[0].service = "SIP+D2T";
+               tports[0].srv = "_sip._tcp.";
+       }
+       else if (tport == SOFIA_TRANSPORT_TCP_TLS) {
+               tports[0].name = "tls";
+               tports[0].service = "SIPS+D2T";
+               tports[0].srv = "_sips._tcp.";
+       }
+       else if (tport == SOFIA_TRANSPORT_SCTP) {
+               tports[0].name = "sctp";
+               tports[0].service = "SIP+D2S";
+               tports[0].srv = "_sip._sctp.";
+       } else {
+               return SWITCH_FALSE;
+       }
+       return SWITCH_TRUE;
+}
+
+/* resolve domain name (SRV + A + AAAA) and compare result with passed IP address */
+switch_bool_t sip_resolve_compare(const char *domainname, const char *ip, sofia_transport_t transport)
+{
+       url_t *uri = NULL;
+       char const *host;
+       char const *port;
+       struct dig dig[1] = {{ NULL }};
+       su_home_t *home = NULL;
+       sres_record_t **answers = NULL;
+       switch_bool_t ret = SWITCH_FALSE, ipv6 = SWITCH_FALSE;
+       
+       if (!host_is_domain(domainname)) {
+               return ret;
+       }
+
+       if (!sip_resolve_prepare_transport(dig, transport)) {
+               return ret;
+       }
+
+       home = su_home_new(sizeof(*home));
+
+       dig->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
+
+       uri = url_hdup(home, (void *)domainname);
+
+       if (uri && uri->url_type == url_unknown)
+               url_sanitize(uri);
+
+       if (uri && uri->url_type == url_any) {
+               goto out;
+       }
+
+       if (!uri || (uri->url_type != url_sip && uri->url_type != url_sips)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid uri\n");
+               goto out;
+       }
+
+       port = url_port(uri);
+       if (port && !port[0]) port = NULL;
+
+       host = uri->url_host;
+
+       if (strchr(ip, ':')) {
+               ipv6 = SWITCH_TRUE;
+       }
+       ret = dig_all_srvs_simple(dig, domainname, ip, ipv6);
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "verify 1\n");
+
+       if (!ret) {
+               answers = dig_addr_simple(dig, host, ipv6?sres_type_aaaa:sres_type_a);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "verify 2\n");
+               ret = verify_ip(answers, ip, ipv6);
+       }
+
+out:
+       su_home_unref(home);
+       sres_resolver_unref(dig->sres);
+
+       return ret;
+}
+
+static switch_bool_t is_legitimate_gateway(sofia_dispatch_event_t *de, sofia_gateway_t *gateway) 
+{
+       char remote_ip[80] = { 0 };
+       switch_bool_t ret = SWITCH_FALSE;
+
+       sofia_glue_get_addr(de->data->e_msg, remote_ip, sizeof(remote_ip), NULL);
+
+       if (gateway->gw_auth_acl) {
+               ret = switch_check_network_list_ip(remote_ip, gateway->gw_auth_acl);
+               if (!ret) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Challange from [%s] denied by gw-auth-acl.\n", remote_ip);
+               }
+               return ret;
+       } else {
+               char *register_host = sofia_glue_get_register_host(gateway->register_proxy);
+               const char *host = sofia_glue_strip_proto(register_host);
+
+               if (host_is_ip_address(host)) {
+                       if (host && !strcmp(host, remote_ip)) {
+                               ret = SWITCH_TRUE;
+                       }
+                       switch_safe_free(register_host);
+                       return ret;
+               } else {
+                       ret = sip_resolve_compare(host, remote_ip, gateway->register_transport);
+                       switch_safe_free(register_host); 
+                       return ret;
+               }
+       }
+}
 
 void sofia_reg_handle_sip_r_register(int status,
                                                                         char const *phrase,
@@ -2463,6 +2585,7 @@ void sofia_reg_handle_sip_r_register(int status,
                        sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &gateway->register_network_port);
                        if (!zstr_buf(network_ip)) {
                                snprintf(gateway->register_network_ip, sizeof(gateway->register_network_ip), (msg_addrinfo(de->data->e_msg))->ai_addr->sa_family == AF_INET6 ? "[%s]" : "%s", network_ip);
+
                        }
                }
 
@@ -2684,11 +2807,22 @@ void sofia_reg_handle_sip_r_challenge(int status,
 
        if (sip_auth_username && sip_auth_password) {
                switch_snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, sip_auth_username, sip_auth_password);
-       } else if (gateway) {
+       } else if (gateway && is_legitimate_gateway(de, gateway)) {
                switch_snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->auth_username, gateway->register_password);
        } else {
+               if (gateway) {
+                       switch_event_t *s_event;
+                       if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_GATEWAY_INVALID_DIGEST_REQ) == SWITCH_STATUS_SUCCESS) {
+                               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Gateway", gateway->name);
+                               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", gateway->profile->name);
+                               switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "realm", realm);
+                               switch_event_fire(&s_event);
+                       }
+               }
+
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
-                                                 "Cannot locate any authentication credentials to complete an authentication request for realm '%s'\n", realm);
+                                                         "Cannot locate any authentication credentials to complete an authentication request for realm '%s'\n", realm);
+
                goto cancel;
        }
 
diff --git a/src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml b/src/mod/endpoints/mod_sofia/test/conf-sipp/freeswitch.xml
new file mode 100644 (file)
index 0000000..088a7a5
--- /dev/null
@@ -0,0 +1,1458 @@
+<?xml version="1.0"?>
+<document type="freeswitch/xml">
+  <section name="configuration" description="Various Configuration">
+
+    <configuration name="modules.conf" description="Modules">
+      <modules>
+        <load module="mod_console"/>
+        <load module="mod_sofia"/>
+        <load module="mod_loopback"/>
+        <load module="mod_dptools"/>
+        <load module="mod_dialplan_xml"/>
+        <load module="mod_commands"/>
+        <load module="mod_test"/> 
+        <load module="mod_tone_stream"/>
+        <load module="mod_voicemail"/>
+        <load module="mod_sndfile"/>
+        <load module="mod_say_en" />
+      </modules>
+    </configuration>
+
+<configuration name="voicemail.conf" description="Voicemail">
+  <settings>
+  </settings>
+  <profiles>
+    <profile name="default">
+      <param name="file-extension" value="wav"/>
+      <param name="terminator-key" value="#"/>
+      <param name="max-login-attempts" value="3"/>
+      <param name="digit-timeout" value="10000"/>
+      <param name="min-record-len" value="3"/>
+      <param name="max-record-len" value="300"/>
+      <param name="max-retries" value="3"/>
+      <param name="tone-spec" value="%(1000, 0, 640)"/>
+      <param name="callback-dialplan" value="XML"/>
+      <param name="callback-context" value="default"/>
+      <param name="play-new-messages-key" value="1"/>
+      <param name="play-saved-messages-key" value="2"/>
+      <!-- play-new-messages-lifo and play-saved-messages-lifo default is false, playing oldest messages first
+          <param name="play-new-messages-lifo" value="false"/>
+          <param name="play-saved-messages-lifo" value="false"/>
+      -->
+      <param name="login-keys" value="0"/>
+      <param name="main-menu-key" value="0"/>
+      <param name="config-menu-key" value="5"/>
+      <param name="record-greeting-key" value="1"/>
+      <param name="choose-greeting-key" value="2"/>
+      <param name="change-pass-key" value="6"/>
+      <param name="record-name-key" value="3"/>
+      <param name="record-file-key" value="3"/>
+      <param name="listen-file-key" value="1"/>
+      <param name="save-file-key" value="2"/>
+      <param name="delete-file-key" value="7"/>
+      <param name="undelete-file-key" value="8"/>
+      <param name="email-key" value="4"/>
+      <param name="pause-key" value="0"/>
+      <param name="restart-key" value="1"/>
+      <param name="ff-key" value="6"/>
+      <param name="rew-key" value="4"/>
+      <param name="skip-greet-key" value="#"/>
+      <param name="previous-message-key" value="1"/>
+      <param name="next-message-key" value="3"/>
+      <param name="skip-info-key" value="*"/>
+      <param name="repeat-message-key" value="0"/>
+      <param name="record-silence-threshold" value="200"/>
+      <param name="record-silence-hits" value="2"/>
+      <param name="web-template-file" value="web-vm.tpl"/>
+      <param name="db-password-override" value="false"/>
+      <param name="allow-empty-password-auth" value="true"/>
+      <!-- if you need to change the sample rate of the recorded files e.g. gmail voicemail player -->
+      <!--<param name="record-sample-rate" value="11025"/>-->
+      <!-- the next two both must be set for this to be enabled
+           the extension is in the format of <dest> [<dialplan>] [<context>]
+       -->
+      <param name="operator-extension" value="operator XML default"/>
+      <param name="operator-key" value="9"/>
+      <param name="vmain-extension" value="vmain XML default"/>
+      <param name="vmain-key" value="*"/>
+      <!-- playback created files as soon as they were recorded by default -->
+      <!--<param name="auto-playback-recordings" value="true"/>-->
+      <email>
+       <param name="template-file" value="voicemail.tpl"/>
+       <param name="notify-template-file" value="notify-voicemail.tpl"/>
+       <!-- this is the format voicemail_time will have -->
+        <param name="date-fmt" value="%A, %B %d %Y, %I %M %p"/>
+        <param name="email-from" value="${voicemail_account}@${voicemail_domain}"/>
+      </email>
+      <!--<param name="storage-dir" value="$${storage_dir}"/>-->
+      <!--<param name="odbc-dsn" value="dsn:user:pass"/>-->
+      <!--<param name="record-comment" value="Your Comment"/>-->
+      <!--<param name="record-title" value="Your Title"/>-->
+      <!--<param name="record-copyright" value="Your Copyright"/>-->
+    </profile>
+  </profiles>
+</configuration> 
+
+<configuration name="voicemail_ivr.conf" description="Voicemail IVR">
+<profiles>
+       <profile name="default">
+               <settings>
+                       <param name="IVR-Maximum-Attempts" value="3" />
+                       <param name="IVR-Entry-Timeout" value="3000" />
+                       <param name="Record-Format" value="wav" />
+                       <!--<param name="Record-Sample-Rate" value="8000" />-->
+                       <param name="Record-Silence-Hits" value="4" />
+                       <param name="Record-Silence-Threshold" value="200" />
+                       <param name="Record-Maximum-Length" value="30" />
+                       <!--<param name="Record-Minimum-Length" value="3" />-->
+                       <param name="Exit-Purge" value="true" />
+                       <param name="Password-Mask" value="XXX." />
+                       <param name="User-Mask" value="X." />
+
+               </settings>
+               <apis>
+                       <api name="auth_login" value="vm_fsdb_auth_login" />
+                       <api name="msg_list" value="vm_fsdb_msg_list" />
+                       <api name="msg_count" value="vm_fsdb_msg_count" />
+                       <api name="msg_delete" value="vm_fsdb_msg_delete" />
+                       <api name="msg_undelete" value="vm_fsdb_msg_undelete" />
+                       <api name="msg_save" value="vm_fsdb_msg_save" />
+                       <api name="msg_purge" value="vm_fsdb_msg_purge" />
+                       <api name="msg_get" value="vm_fsdb_msg_get" />
+                       <api name="msg_forward" value="vm_fsdb_msg_forward" />
+                       <api name="pref_greeting_set" value="vm_fsdb_pref_greeting_set" />
+                       <api name="pref_greeting_get" value="vm_fsdb_pref_greeting_get" />
+                       <api name="pref_recname_set" value="vm_fsdb_pref_recname_set" />
+                       <api name="pref_password_set" value="vm_fsdb_pref_password_set" />
+               </apis>
+               <menus>
+                       <menu name="std_authenticate">
+                       <phrases>
+                               <phrase name="fail_auth" value="fail_auth@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                       </keys>
+                       </menu>
+
+                       <menu name="std_authenticate_ask_user">
+                       <phrases>
+                               <phrase name="instructions" value="enter_id@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_authenticate_ask_password">
+                       <phrases>
+                               <phrase name="instructions" value="enter_pass@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_main_menu">
+                       <settings>
+                               <param name="Action-On-New-Message" value="new_msg:std_navigator" />
+                       </settings>
+                       <phrases>
+                               <phrase name="msg_count" value="message_count@voicemail_ivr" />
+                               <phrase name="say_date" value="say_date_event@voicemail_ivr" />
+                               <phrase name="say_msg_number" value="say_message_number@voicemail_ivr" />
+                               <phrase name="menu_options" value="menu@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="new_msg:std_navigator" variable="VM-Key-Play-New-Messages" />
+                               <key dtmf="2" action="saved_msg:std_navigator" variable="VM-Key-Play-Saved-Messages" />
+                               <key dtmf="5" action="menu:std_preference" variable="VM-Key-Config-Menu"/>
+                               <key dtmf="#" action="return" variable="VM-Key-Terminator" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_navigator">
+                       <settings>
+                               <!--<param name="Nav-Action-On-Delete" value="next_msg" />-->
+                       </settings>
+                       <phrases>
+                               <phrase name="msg_count" value="message_count@voicemail_ivr" />
+                               <phrase name="say_date" value="say_date_event@voicemail_ivr" />
+                               <phrase name="say_msg_number" value="say_message_number@voicemail_ivr" />
+                               <phrase name="menu_options" value="listen_file_check@voicemail_ivr" />
+                               <phrase name="ack" value="ack@voicemail_ivr" />
+                               <phrase name="play_message" value="play_message@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="skip_intro" variable="VM-Key-Main-Listen-File" />
+                               <key dtmf="6" action="next_msg" variable="VM-Key-Main-Next-Msg" />
+                               <key dtmf="4" action="prev_msg" />
+                               <key dtmf="7" action="delete_msg" variable="VM-Key-Main-Delete-File" /> <!-- Same key for undelete if it already deleted -->
+                               <key dtmf="8" action="menu:std_forward" variable="VM-Key-Main-Forward" />
+                               <key dtmf="2" action="save_msg" variable="VM-Key-Main-Save-File" />
+                               <key dtmf="5" action="callback" variable="VM-Key-Main-Callback" />
+                               <key dtmf="#" action="return" /> <!-- TODO Might Conflict with future fast-forward -->
+                       </keys>
+                       </menu>
+
+                       <menu name="std_preference">
+                       <phrases>
+                               <phrase name="menu_options" value="config_menu@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="menu:std_record_greeting_with_slot" variable="VM-Key-Record-Greeting" />
+                               <key dtmf="2" action="menu:std_select_greeting_slot" variable="VM-Key-Choose-Greeting" />
+                               <key dtmf="3" action="menu:std_record_name" variable="VM-Key-Record-Name" />
+                               <key dtmf="6" action="menu:std_set_password" variable="VM-Key-Change-Password" />
+                               <key dtmf="0" action="return" variable="VM-Key-Main-Menu" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_record_greeting">
+                       <phrases>
+                               <phrase name="instructions" value="record_greeting@voicemail_ivr" />
+                               <phrase name="play_recording" value="play_recording@voicemail_ivr" />
+                               <phrase name="menu_options" value="record_file_check@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
+                               <key dtmf="2" action="save" variable="VM-Key-Save-File" />
+                               <key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
+                               <key dtmf="#" action="skip_instruction" />
+                       </keys>
+                       </menu>
+
+
+                       <menu name="std_record_name">
+                       <phrases>
+                               <phrase name="instructions" value="record_name@voicemail_ivr" />
+                               <phrase name="play_recording" value="play_recording@voicemail_ivr" />
+                               <phrase name="menu_options" value="record_file_check@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
+                               <key dtmf="2" action="save" variable="VM-Key-Save-File" />
+                               <key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
+                               <key dtmf="#" action="skip_instruction" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_record_message">
+                       <phrases>
+                               <phrase name="instructions" value="record_message@voicemail_ivr" />
+                               <phrase name="play_recording" value="play_recording@voicemail_ivr" />
+                               <phrase name="menu_options" value="record_file_check@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
+                               <key dtmf="2" action="save" variable="VM-Key-Save-File" />
+                               <key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
+                               <key dtmf="#" action="skip_instruction" />
+                       </keys>
+                       </menu>                 
+
+                       <menu name="std_forward_ask_prepend">
+                       <phrases>
+                               <phrase name="menu_options" value="forward_ask_prepend@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="1" action="prepend" variable="VM-Key-Prepend" />
+                               <key dtmf="8" action="forward" variable="VM-Key-Forward" />
+                               <key dtmf="#" action="return" variable="VM-Key-Return" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_forward_ask_extension">
+                       <phrases>
+                               <phrase name="instructions" value="forward_ask_extension@voicemail_ivr" />
+                               <phrase name="ack" value="ack@voicemail_ivr" />
+                               <phrase name="invalid_extension" value="invalid_extension@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
+                       </keys>
+                       </menu>
+
+                       <menu name="std_select_greeting_slot">
+                       <phrases>
+                               <phrase name="instructions" value="choose_greeting@voicemail_ivr" />
+                               <phrase name="invalid_slot" value="choose_greeting_fail@voicemail_ivr" />
+                               <phrase name="selected_slot" value="greeting_selected@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                       </keys>
+                       </menu>
+
+                       <menu name="std_record_greeting_with_slot">
+                       <phrases>
+                               <phrase name="instructions" value="choose_greeting@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                       </keys>
+                       </menu>
+
+                       <menu name="std_set_password">
+                       <phrases>
+                               <phrase name="instructions" value="enter_pass@voicemail_ivr" />
+                       </phrases>
+                       <keys>
+                               <key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
+                       </keys>
+                       </menu>
+               </menus>
+       </profile>
+</profiles>
+</configuration>
+
+
+    <configuration name="console.conf" description="Console Logger">
+      <mappings>
+        <map name="all" value="console,debug,info,notice,warning,err,crit,alert"/>
+      </mappings>
+      <settings>
+        <param name="colorize" value="true"/>
+        <param name="uuid" value="true"/>
+        <param name="loglevel" value="debug"/>
+      </settings>
+    </configuration>
+    <configuration name="sofia.conf" description="SofiaSIP">
+        <profiles>
+    <profile name="external">
+        <gateways>
+           <gateway name="freeswitch.org">
+                <param name="username" value="not-used"/>
+                <param name="password" value="not-used"/>
+                <param name="proxy" value="127.0.0.1:5080"/>
+                <param name="register" value="false"/>
+                <param name="retry-seconds" value="30"/>
+                <param name="dtmf-type" value="rfc2833"/>
+                <variables>   
+                 <variable name="rtp_secure_media"  value="false"  direction="outbound"/>  
+                </variables>
+            </gateway>
+        </gateways>
+
+      <domains>
+        <domain name="all" alias="false" parse="true"/>
+      </domains>
+
+      <settings>
+        <param name="debug" value="1"/>
+        <param name="shutdown-on-fail" value="true"/>
+        <param name="p-asserted-id-parse" value="verbatim"/>
+        <param name="username" value="FS"/>
+        <param name="user-agent-string" value="Unit Test"/>
+        <param name="sip-trace" value="yes"/>
+        <param name="sip-capture" value="no"/>
+        <param name="rfc2833-pt" value="101"/>
+        <param name="sip-port" value="5080"/>
+        <param name="dialplan" value="XML"/>
+        <param name="context" value="default"/>
+        <param name="dtmf-duration" value="2000"/>
+        <param name="inbound-codec-prefs" value="PCMU"/>
+        <param name="outbound-codec-prefs" value="PCMU"/>
+        <param name="rtp-timer-name" value="soft"/>
+        <param name="local-network-acl" value="localnet.auto"/>
+        <param name="manage-presence" value="false"/>
+        <param name="inbound-codec-negotiation" value="generous"/>
+        <param name="nonce-ttl" value="60"/>
+        <param name="inbound-late-negotiation" value="true"/>
+        <param name="inbound-zrtp-passthru" value="false"/>
+        <param name="rtp-ip" value="$${local_ip_v4}"/>
+        <param name="sip-ip" value="$${local_ip_v4}"/>
+        <param name="ext-rtp-ip" value="$${local_ip_v4}"/>
+        <param name="ext-sip-ip" value="$${local_ip_v4}"/>
+        <param name="rtp-timeout-sec" value="300"/>
+        <param name="rtp-hold-timeout-sec" value="1800"/>
+        <param name="session-timeout" value="600"/>
+        <param name="minimum-session-expires" value="90"/>
+               <param name="tls" value="false"/>
+      </settings>
+  </profile>
+
+    <profile name="internal">
+        <gateways>
+    </gateways>
+
+      <domains>
+        <domain name="all" alias="false" parse="true"/>
+      </domains>
+
+      <settings>
+        <param name="debug" value="1"/>
+        <param name="shutdown-on-fail" value="true"/>
+        <param name="p-asserted-id-parse" value="verbatim"/>
+        <param name="username" value="FS"/>
+        <param name="user-agent-string" value="Unit Test"/>
+        <param name="sip-trace" value="yes"/>
+        <param name="sip-capture" value="no"/>
+        <param name="rfc2833-pt" value="101"/>
+        <param name="sip-port" value="5060"/>
+        <param name="dialplan" value="XML"/>
+        <param name="context" value="default"/>
+        <param name="dtmf-duration" value="2000"/>
+        <param name="inbound-codec-prefs" value="PCMU"/>
+        <param name="outbound-codec-prefs" value="PCMU"/>
+        <param name="rtp-timer-name" value="soft"/>
+        <param name="local-network-acl" value="localnet.auto"/>
+        <param name="manage-presence" value="false"/>
+        <param name="inbound-codec-negotiation" value="generous"/>
+        <param name="nonce-ttl" value="60"/>
+        <param name="inbound-late-negotiation" value="true"/>
+        <param name="inbound-zrtp-passthru" value="false"/>
+        <param name="rtp-ip" value="$${local_ip_v4}"/>
+        <param name="sip-ip" value="$${local_ip_v4}"/>
+        <param name="ext-rtp-ip" value="$${local_ip_v4}"/>
+        <param name="ext-sip-ip" value="$${local_ip_v4}"/>
+        <param name="rtp-timeout-sec" value="300"/>
+        <param name="rtp-hold-timeout-sec" value="1800"/>
+        <param name="session-timeout" value="600"/>
+        <param name="minimum-session-expires" value="90"/>
+        <param name="tls" value="false"/>
+      </settings>
+  </profile>
+
+<profile name="external-ipv6">
+  <!-- http://wiki.freeswitch.org/wiki/Sofia_Configuration_Files -->
+  <!-- This profile is only for outbound registrations to providers -->
+  <gateways>
+           <gateway name="freeswitch.org">
+                <param name="username" value="not-used"/>
+                <param name="password" value="not-used"/>
+                <param name="proxy" value="[::1]:5080"/>
+                <param name="register" value="false"/>
+                <param name="retry-seconds" value="30"/>
+                <param name="dtmf-type" value="rfc2833"/>
+                <variables>   
+                 <variable name="rtp_secure_media"  value="false"  direction="outbound"/>  
+                </variables>
+          </gateway>
+
+  </gateways>
+
+  <aliases>
+    <!--
+        <alias name="outbound"/>
+        <alias name="nat"/>
+    -->
+  </aliases>
+
+  <domains>
+    <!--<domain name="all" alias="false" parse="true"/>-->
+  </domains>
+
+  <settings>
+    <param name="debug" value="1"/>
+    <!-- If you want FreeSWITCH to shutdown if this profile fails to load, uncomment the next line. -->
+    <!-- <param name="shutdown-on-fail" value="true"/> -->
+    <param name="sip-trace" value="no"/>
+    <param name="sip-capture" value="no"/>
+    <param name="rfc2833-pt" value="101"/>
+    <!-- RFC 5626 : Send reg-id and sip.instance -->
+    <!--<param name="enable-rfc-5626" value="true"/> -->
+    <param name="sip-port" value="6060"/>
+    <param name="dialplan" value="XML"/>
+    <param name="context" value="default"/>
+    <param name="dtmf-duration" value="2000"/>
+    <param name="inbound-codec-prefs" value="PCMU"/>
+    <param name="outbound-codec-prefs" value="PCMU"/>    
+    <param name="hold-music" value="$${hold_music}"/>
+    <param name="rtp-timer-name" value="soft"/>
+    <!--<param name="enable-100rel" value="true"/>-->
+    <!--<param name="disable-srv503" value="true"/>-->
+    <!-- This could be set to "passive" -->
+    <param name="local-network-acl" value="localnet.auto"/>
+    <param name="manage-presence" value="false"/>
+
+    <!-- used to share presence info across sofia profiles
+         manage-presence needs to be set to passive on this profile
+         if you want it to behave as if it were the internal profile
+         for presence.
+    -->
+    <!-- Name of the db to use for this profile -->
+    <!--<param name="dbname" value="share_presence"/>-->
+    <!--<param name="presence-hosts" value="$${domain}"/>-->
+    <!--<param name="force-register-domain" value="$${domain}"/>-->
+    <!--all inbound reg will stored in the db using this domain -->
+    <!--<param name="force-register-db-domain" value="$${domain}"/>-->
+    <!-- ************************************************* -->
+
+    <!--<param name="aggressive-nat-detection" value="true"/>-->
+    <param name="inbound-codec-negotiation" value="generous"/>
+    <param name="nonce-ttl" value="60"/>
+    <param name="auth-calls" value="false"/>
+    <param name="inbound-late-negotiation" value="true"/>
+    <param name="inbound-zrtp-passthru" value="true"/> <!-- (also enables late negotiation) -->
+    <!--
+        DO NOT USE HOSTNAMES, ONLY IP ADDRESSES IN THESE SETTINGS!
+    -->
+       <!-- <param name="rtp-ip" value="$${local_ip_v6}"/>
+       <param name="sip-ip" value="$${local_ip_v6}"/> -->
+       
+       <param name="rtp-ip" value="0000:0000:0000:0000:0000:0000:0000:0001"/>
+       <param name="sip-ip" value="0000:0000:0000:0000:0000:0000:0000:0001"/>
+       <!-- Shouldn't set these on IPv6 -->
+    <!--<param name="ext-rtp-ip" value="auto-nat"/>-->
+    <!--<param name="ext-sip-ip" value="auto-nat"/>-->
+    <param name="rtp-timeout-sec" value="300"/>
+    <param name="rtp-hold-timeout-sec" value="1800"/>
+    <!--<param name="enable-3pcc" value="true"/>-->
+
+    <!-- TLS: disabled by default, set to "true" to enable -->
+    <param name="tls" value="$${external_ssl_enable}"/>
+    <!-- Set to true to not bind on the normal sip-port but only on the TLS port -->
+    <param name="tls-only" value="false"/>
+    <!-- additional bind parameters for TLS -->
+    <param name="tls-bind-params" value="transport=tls"/>
+    <!-- Port to listen on for TLS requests. (5081 will be used if unspecified) -->
+    <param name="tls-sip-port" value="$${external_tls_port}"/>
+    <!-- Location of the agent.pem and cafile.pem ssl certificates (needed for TLS server) -->
+    <!--<param name="tls-cert-dir" value=""/>-->
+    <!-- Optionally set the passphrase password used by openSSL to encrypt/decrypt TLS private key files -->
+    <param name="tls-passphrase" value=""/>
+    <!-- Verify the date on TLS certificates -->
+    <param name="tls-verify-date" value="true"/>
+    <!-- TLS verify policy, when registering/inviting gateways with other servers (outbound) or handling inbound registration/invite requests how should we verify their certificate -->
+    <!-- set to 'in' to only verify incoming connections, 'out' to only verify outgoing connections, 'all' to verify all connections, also 'subjects_in', 'subjects_out' and 'subjects_all' for subject validation. Multiple policies can be split with a '|' pipe -->
+    <param name="tls-verify-policy" value="none"/>
+    <!-- Certificate max verify depth to use for validating peer TLS certificates when the verify policy is not none -->
+    <param name="tls-verify-depth" value="2"/>
+    <!-- If the tls-verify-policy is set to subjects_all or subjects_in this sets which subjects are allowed, multiple subjects can be split with a '|' pipe -->
+    <param name="tls-verify-in-subjects" value=""/>
+    <!-- TLS version ("sslv23" (default), "tlsv1"). NOTE: Phones may not work with TLSv1 -->
+    <param name="tls-version" value="$${sip_tls_version}"/>
+  </settings>
+</profile>
+  </profiles>
+   </configuration>
+
+   <configuration name="switch.conf" description="Switch">
+     <param name="rtp-start-port" value="20000"/>
+     <param name="rtp-end-port" value="30000"/>
+     <param name="threaded-system-exec" value="false"/>
+   </configuration>
+
+   
+     <configuration name="timezones.conf" description="Timezones">
+        <timezones>
+        <zone name="GMT" value="GMT0" />
+        </timezones>
+     </configuration>
+
+ </section>
+
+
+  <section name="dialplan" description="Regex/XML Dialplan">
+    <context name="default">
+
+    <extension name="unit_test_sipp-uac-digest-leak">
+        <condition field="destination_number" expression="^\+15553334444$">
+            <action application="info"/>
+                       <action application="answer" />
+                       <!-- <action application="system" data="sipp $${local_ip_v4}:5080 -nr -p 5062 -m 1 -s 1001 -recv_timeout 10000 -timeout 10s -sf sipp-scenarios/uac_digest_leak.xml -bg > /dev/null 2>&1" /> -->
+                       <action application="playback" data="silence_stream://-1"/>
+               </condition>
+    </extension>
+
+
+       <extension name="sipp">
+               <condition>
+                  <action application="info"/>
+                  <action application="answer" />
+                  <action application="voicemail" data="default $${domain} 1001"/>
+       </condition>
+    </extension>
+
+       </context>
+
+  </section>
+
+       <section name="directory" description="User Directory">
+       <domain name="$${local_ip_v4}">
+       <users>
+               <user id="1001">
+                       <params>
+                               <param name="password" value="$${default_password}"/>
+                               <param name="vm-password" value="1001"/>
+                       </params>
+                       <variables>
+                               <variable name="toll_allow" value="domestic,international,local"/>
+                               <variable name="accountcode" value="1001"/>
+                               <variable name="user_context" value="default"/>
+                               <variable name="effective_caller_id_name" value="Extension 1001"/>
+                               <variable name="effective_caller_id_number" value="1001"/>
+                               <variable name="outbound_caller_id_name" value="$${outbound_caller_name}"/>
+                               <variable name="outbound_caller_id_number" value="$${outbound_caller_id}"/>
+                               <variable name="callgroup" value="techsupport"/>
+                       </variables>
+               </user>
+       </users>
+       </domain>
+
+       <domain name="$${local_ip_v6}">
+       <users>
+               <user id="1001">
+                       <params>
+                               <param name="password" value="$${default_password}"/>
+                               <param name="vm-password" value="1001"/>
+                       </params>
+                       <variables>
+                               <variable name="toll_allow" value="domestic,international,local"/>
+                               <variable name="accountcode" value="1001"/>
+                               <variable name="user_context" value="default"/>
+                               <variable name="effective_caller_id_name" value="Extension 1001"/>
+                               <variable name="effective_caller_id_number" value="1001"/>
+                               <variable name="outbound_caller_id_name" value="$${outbound_caller_name}"/>
+                               <variable name="outbound_caller_id_number" value="$${outbound_caller_id}"/>
+                               <variable name="callgroup" value="techsupport"/>
+                       </variables>
+               </user>
+       </users>
+       </domain>
+       </section>
+
+       <section name="languages" description="Language Management">
+               <language name="en" say-module="en" sound-prefix="$${sound_prefix}" tts-engine="cepstral" tts-voice="callie">
+                       <phrases>
+                               <macros>
+  <macro name="voicemail_enter_id">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-enter_id.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_enter_pass">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-enter_pass.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_fail_auth">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-fail_auth.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_change_pass_success">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-password_has_been_changed.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_change_pass_fail">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-password_not_valid.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_hello">
+    <input pattern="(.*)">
+      <match>
+        <!--<action function="play-file" data="voicemail/vm-hello.wav"/> -->
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_goodbye">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-goodbye.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_abort">
+    <input pattern="(.*)">
+      <match>
+        <action function="play-file" data="voicemail/vm-abort.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_message_count">
+    <input pattern="^(1):(.*)$" break_on_match="true">
+      <match>
+        <action function="play-file" data="voicemail/vm-you_have.wav"/>
+        <action function="say" data="$1" method="pronounced" type="items"/>
+        <action function="play-file" data="voicemail/vm-$2.wav"/>
+        <action function="play-file" data="voicemail/vm-message.wav"/>
+      </match>
+    </input>
+    <input pattern="^(\d+):(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-you_have.wav"/>
+        <action function="say" data="$1" method="pronounced" type="items"/>
+        <action function="play-file" data="voicemail/vm-$2.wav"/>
+        <action function="play-file" data="voicemail/vm-messages.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_menu">
+    <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+      <match>
+        <!-- To listen to new messages -->
+        <action function="play-file" data="voicemail/vm-listen_new.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- To listen to saved messages -->
+        <action function="play-file" data="voicemail/vm-listen_saved.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- For advanced options -->
+        <action function="play-file" data="voicemail/vm-advanced.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- To exit -->
+        <action function="play-file" data="voicemail/vm-to_exit.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$4" method="pronounced" type="name_phonetic"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_config_menu">
+    <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+      <match>
+        <!-- To record a greeting -->
+        <action function="play-file" data="voicemail/vm-to_record_greeting.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- To choose greeting -->
+        <action function="play-file" data="voicemail/vm-choose_greeting.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- To record your name -->
+        <action function="play-file" data="voicemail/vm-record_name2.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- To change password -->
+        <action function="play-file" data="voicemail/vm-change_password.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$4" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(100)"/>
+
+        <!-- To return to main menu -->
+        <action function="play-file" data="voicemail/vm-main_menu.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$5" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_record_name">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-record_name1.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_record_file_check">
+    <input pattern="^([0-9#*]):([0-9#*]):([0-9#*])$">
+      <match>
+        <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-save_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-rerecord.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_record_urgent_check">
+    <input pattern="^([0-9#*]):([0-9#*])$">
+      <match>
+        <action function="play-file" data="voicemail/vm-mark-urgent.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-continue.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_forward_prepend">
+    <input pattern="^([0-9#*]):([0-9#*])$">
+      <match>
+        <action function="play-file" data="voicemail/vm-forward_add_intro.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-send_message_now.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_forward_message_enter_extension">
+    <input pattern="^([0-9#*])$">
+      <match>
+        <action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
+        <action function="play-file" data="voicemail/vm-followed_by.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_invalid_extension">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_listen_file_check">
+    <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-save_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-delete_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-forward_to_email.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$4" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-return_call.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$5" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-to_forward.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$6" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+    <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+      <match>
+        <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-save_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-delete_recording.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-return_call.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$5" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-to_forward.wav"/>
+        <action function="play-file" data="voicemail/vm-press.wav"/>
+        <action function="say" data="$6" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_choose_greeting">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_choose_greeting_fail">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_record_greeting">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-record_greeting.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_record_message">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-record_message.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_greeting_selected">
+    <input pattern="^(\d+)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-greeting.wav"/>
+        <action function="say" data="$1" method="pronounced" type="items"/>
+        <action function="play-file" data="voicemail/vm-selected.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_play_greeting">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-person.wav"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="play-file" data="voicemail/vm-not_available.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_say_number">
+    <input pattern="^(\d+)$">
+      <match>
+        <action function="say" data="$1" method="pronounced" type="items"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_say_message_number">
+    <input pattern="^([a-z]+):(\d+)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-$1.wav"/>
+        <action function="play-file" data="voicemail/vm-message_number.wav"/>
+        <action function="say" data="$2" method="pronounced" type="items"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_say_phone_number">
+    <input pattern="^000|^$|^[Aa]non|^[Pp]rivate" break_on_match="true">
+      <match>
+        <action function="play-file" data="voicemail/vm-message_from.wav"/>
+        <action function="execute" data="sleep(100)"/>
+        <action function="play-file" data="ivr/ivr-anonymous_caller.wav"/>
+        <action function="execute" data="sleep(500)"/>
+      </match>
+    </input>
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-message_from.wav"/>
+        <action function="execute" data="sleep(100)"/>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        <action function="execute" data="sleep(500)"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_say_name">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+  <!-- Note: Update this to marked-urgent,emailed and saved once new sound files are recorded -->
+  <macro name="voicemail_ack">
+    <input pattern="^(too-small)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-too-small.wav"/>
+      </match>
+    </input>
+    <input pattern="^(deleted)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-message.wav"/>
+        <action function="play-file" data="voicemail/vm-$1.wav"/>
+      </match>
+    </input>
+    <input pattern="^(saved)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-message.wav"/>
+        <action function="play-file" data="voicemail/vm-$1.wav"/>
+      </match>
+    </input>
+    <input pattern="^(emailed)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-message.wav"/>
+        <action function="play-file" data="voicemail/vm-$1.wav"/>
+      </match>
+    </input>
+    <input pattern="^(marked-urgent)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-message.wav"/>
+        <action function="play-file" data="voicemail/vm-$1.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_say_date">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="say" data="$1" method="pronounced" type="short_date_time"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="voicemail_disk_quota_exceeded">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="voicemail/vm-mailbox_full.wav"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="valet_announce_ext">
+    <input pattern="^([^\:]+):(.*)$">
+      <match>
+        <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="valet_lot_full">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="tone_stream://%(275,10,600);%(275,100,300)"/>
+      </match>
+    </input>
+  </macro>
+
+  <macro name="valet_lot_empty">
+    <input pattern="^(.*)$">
+      <match>
+        <action function="play-file" data="tone_stream://%(275,10,600);%(275,100,300)"/>
+      </match>
+    </input>
+  </macro>
+                               </macros>
+
+  <macros name="voicemail_ivr">
+    <macro name="press_key">
+      <input pattern="^(.*):(.*)$">
+        <match>
+          <action function="play-file" data="$2"/>
+          <action function="play-file" data="voicemail/vm-press.wav"/>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="plural_msg">
+      <input pattern="^[1]:(.*):(.*)$" break_on_match="true">
+        <match>
+          <action function="play-file" data="$1"/>
+        </match>
+      </input>
+      <input pattern="^.*:(.*):(.*)$" break_on_match="true">
+        <match>
+          <action function="play-file" data="$2"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="enter_id">
+      <input pattern="(.+)">
+        <match>
+          <action function="play-file" data="voicemail/vm-enter_id.wav"/>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        </match>
+        <nomatch>
+          <action function="play-file" data="voicemail/vm-enter_id.wav"/>
+          <action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
+        </nomatch>
+      </input>
+    </macro>
+
+    <macro name="enter_pass">
+      <input pattern="(.+)">
+        <match>
+          <action function="play-file" data="voicemail/vm-enter_pass.wav"/>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        </match>
+        <nomatch>
+          <action function="play-file" data="voicemail/vm-enter_pass.wav"/>
+          <action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
+        </nomatch>
+
+      </input>
+    </macro>
+
+    <macro name="fail_auth">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-fail_auth.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="hello">
+      <input>
+        <match>
+          <!--<action function="play-file" data="voicemail/vm-hello.wav"/> -->
+        </match>
+      </input>
+    </macro>
+
+    <macro name="goodbye">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-goodbye.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="abort">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-abort.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="message_count">
+      <input field="${VM-Total-New-Urgent-Messages}" pattern="^(0)$">
+        <nomatch>
+          <action function="play-file" data="voicemail/vm-you_have.wav"/>
+          <action function="say" data="${VM-Total-New-Urgent-Messages}" method="pronounced" type="items"/>
+          <action function="play-file" data="voicemail/vm-urgent-new.wav"/>
+          <action function="phrase" phrase="plural_msg@voicemail_ivr" data="${VM-Total-New-Urgent-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
+        </nomatch>
+      </input>
+      <input field="${VM-Total-New-Messages}" pattern="^(\d+)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-you_have.wav"/>
+          <action function="say" data="${VM-Total-New-Messages}" method="pronounced" type="items"/>
+          <action function="play-file" data="voicemail/vm-new.wav"/>
+          <action function="phrase" phrase="plural_msg@voicemail_ivr" data="${VM-Total-New-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
+        </match>
+      </input>
+      <input field="${VM-Total-Saved-Messages}" pattern="^(0)$">
+        <nomatch>
+          <action function="play-file" data="currency/and.wav"/>
+          <action function="say" data="${VM-Total-Saved-Messages}" method="pronounced" type="items"/>
+          <action function="play-file" data="voicemail/vm-saved.wav"/>
+          <action function="phrase" phrase="plural_msg@voicemail_ivr" data="${VM-Total-Saved-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
+        </nomatch>
+      </input>
+    </macro>
+
+    <macro name="menu">
+      <input field="${VM-Total-New-Messages}" pattern="^(0)$">
+        <nomatch>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Play-New-Messages}:voicemail/vm-listen_new.wav"/>
+       </nomatch>
+      </input>
+      <input field="${VM-Total-Saved-Messages}" pattern="^(0)$">
+       <nomatch>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Play-Saved-Messages}:voicemail/vm-listen_saved.wav"/>
+       </nomatch>
+      </input>
+      <input>
+       <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Config-Menu}:voicemail/vm-advanced.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Terminator}:voicemail/vm-to_exit.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="config_menu">
+      <input>
+        <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Record-Greeting}:voicemail/vm-to_record_greeting.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Choose-Greeting}:voicemail/vm-choose_greeting.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Record-Name}:voicemail/vm-record_name2.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Change-Password}:voicemail/vm-change_password.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Menu}:voicemail/vm-main_menu.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="record_name">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-record_name1.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="forward_ask_prepend">
+      <input>
+        <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="forward_ask_extension">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
+          <!--<action function="phrase" phrase="play-file" data="voicemail/vm-followed_by.wav"/>-->
+          <!--<action function="say" data="${VM-Key-Terminate}" method="pronounced" type="name_spelled"/>-->
+        </match>
+      </input>
+    </macro>
+
+    <macro name="record_file_check">
+      <input>
+        <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Save-File}:voicemail/vm-save_recording.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Record-File}:voicemail/vm-rerecord.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="record_urgent_check">
+      <input>
+        <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Urgent}:voicemail/vm-mark-urgent.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Terminator}:voicemail/vm-continue.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="forward_prepend">
+      <input>
+        <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="forward_message_enter_extension">
+      <input pattern="^([0-9#*])$">
+        <match>
+          <action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
+          <action function="play-file" data="voicemail/vm-followed_by.wav"/>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="invalid_extension">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="listen_file_check">
+      <input>
+        <match>
+          <!--<action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Next-Msg}:voicemail/vm-for_next_msg.wav"/>--> <!-- Not existant in callie recordings -->
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Save-File}:voicemail/vm-save_recording.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Delete-File}:voicemail/vm-delete_recording.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
+        </match>
+      </input>
+      <input field="${VM-Message-Email}" pattern="^$">
+        <nomatch>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Email}:voicemail/vm-forward_to_email.wav"/>
+        </nomatch>
+      </input>
+      <input>
+        <match>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Callback}:voicemail/vm-return_call.wav"/>
+          <action function="phrase" phrase="press_key@voicemail_ivr" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="choose_greeting">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="choose_greeting_fail">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="record_greeting">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-record_greeting.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="record_message">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-record_message.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="greeting_selected">
+      <input pattern="^(\d+)$">
+        <match>
+         <action function="play-file" data="${VM-Preference-Greeting-File-Path}"/>
+          <action function="play-file" data="voicemail/vm-greeting.wav"/>
+          <action function="say" data="$1" method="pronounced" type="items"/>
+          <action function="play-file" data="voicemail/vm-selected.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="play_greeting">
+      <input pattern="^(.*)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-person.wav"/>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+          <action function="play-file" data="voicemail/vm-not_available.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="say_number">
+      <input pattern="^(\d+)$">
+        <match>
+          <action function="say" data="$1" method="pronounced" type="items"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="say_message_number">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-${VM-Message-Type}.wav"/>
+          <action function="play-file" data="voicemail/vm-message_number.wav"/>
+          <action function="say" data="${VM-Message-Number}" method="pronounced" type="items"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="say_phone_number">
+      <input pattern="^(.*)$">
+        <match>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="say_name">
+      <input pattern="^(.*)$">
+        <match>
+          <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+        </match>
+      </input>
+    </macro>
+    <!-- Note: Update this to marked-urgent,emailed and saved once new sound files are recorded -->
+    <macro name="ack">
+      <input pattern="^(too-small)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-too-small.wav"/>
+        </match>
+      </input>
+      <input pattern="^(undeleted)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-message.wav"/>
+          <action function="play-file" data="voicemail/vm-$1.wav"/>
+        </match>
+      </input>
+      <input pattern="^(deleted)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-message.wav"/>
+          <action function="play-file" data="voicemail/vm-$1.wav"/>
+        </match>
+      </input>
+      <input pattern="^(saved)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-message.wav"/>
+          <action function="play-file" data="voicemail/vm-$1.wav"/>
+        </match>
+      </input>
+      <input pattern="^(emailed)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-message.wav"/>
+          <action function="play-file" data="voicemail/vm-$1.wav"/>
+        </match>
+      </input>
+      <input pattern="^(marked-urgent)$">
+        <match>
+          <action function="play-file" data="voicemail/vm-message.wav"/>
+          <action function="play-file" data="voicemail/vm-$1.wav"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="say_date">
+      <input pattern="^(.*)$">
+        <match>
+          <action function="say" data="$1" method="pronounced" type="short_date_time"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="say_date_event">
+      <input>
+        <match>
+          <action function="say" data="${VM-Message-Received-Epoch}" method="pronounced" type="short_date_time"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="play_message">
+      <input>
+        <match>
+          <action function="play-file" data="${VM-Message-File-Path}"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="play_recording">
+      <input>
+        <match>
+          <action function="play-file" data="${VM-Record-File-Path}"/>
+        </match>
+      </input>
+    </macro>
+
+    <macro name="disk_quota_exceeded">
+      <input>
+        <match>
+          <action function="play-file" data="voicemail/vm-mailbox_full.wav"/>
+        </match>
+      </input>
+    </macro>
+  </macros>
+
+
+                       </phrases>
+               </language>
+       </section>
+</document>
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c b/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c
new file mode 100644 (file)
index 0000000..382dbc2
--- /dev/null
@@ -0,0 +1,295 @@
+
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2021, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dragos Oancea <dragos@signalwire.com>
+ *
+ *
+ * sipp-based-tests.c - Test FreeSwitch using sipp (https://github.com/SIPp/sipp)
+ *
+ */
+
+#include <switch.h>
+#include <test/switch_test.h>
+#include <stdlib.h>
+
+int test_success = 0;
+int test_sofia_debug = 1;
+
+static switch_bool_t has_ipv6() 
+{
+       switch_stream_handle_t stream = { 0 };
+       SWITCH_STANDARD_STREAM(stream);
+       switch_api_execute("sofia", "status profile external-ipv6", NULL, &stream);
+
+       if (strstr((char *)stream.data, "Invalid Profile")) {
+
+               switch_safe_free(stream.data);
+
+               return SWITCH_FALSE;
+       }
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "STATUS PROFILE: %s\n", (char *) stream.data);
+       
+       switch_safe_free(stream.data);
+
+       return SWITCH_TRUE;
+}
+
+static int start_sipp_uac(const char *ip, int remote_port,const char *scenario_uac, const char *extra)
+{
+       char *cmd = switch_mprintf("sipp %s:%d -nr -p 5062 -m 1 -s 1001 -recv_timeout 10000 -timeout 10s -sf %s -bg %s", ip, remote_port, scenario_uac, extra);
+       int sys_ret = switch_system(cmd, SWITCH_TRUE);
+
+       printf("%s\n", cmd);
+       switch_safe_free(cmd);
+       switch_sleep(1000 * 1000);
+       return sys_ret;
+} 
+
+static void kill_sipp(void)
+{
+       switch_system("pkill -x sipp", SWITCH_TRUE);
+       switch_sleep(1000 * 1000);
+}
+
+static void event_handler(switch_event_t *event) 
+{
+       const char *new_ev = switch_event_get_header(event, "Event-Subclass");
+       char *str;
+       
+       if (new_ev && !strcmp(new_ev, "sofia::gateway_invalid_digest_req")) { 
+               test_success = 1;
+       }
+
+       /*print the event*/
+       switch_event_serialize_json(event, &str);
+       if (str) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", str);
+               switch_safe_free(str);
+       }
+}
+
+FST_CORE_EX_BEGIN("./conf-sipp", SCF_VG | SCF_USE_SQL)
+{
+       FST_MODULE_BEGIN(mod_sofia, uac-uas)
+       {
+               FST_SETUP_BEGIN()
+               {
+                       switch_stream_handle_t stream = { 0 };
+                       SWITCH_STANDARD_STREAM(stream);
+                       switch_api_execute("sofia", "global siptrace on", NULL, &stream);
+                       if (test_sofia_debug) {
+                               switch_api_execute("sofia", "loglevel all 9", NULL, &stream);
+                               switch_api_execute("sofia", "tracelevel debug", NULL, &stream);
+                       }
+                       switch_safe_free(stream.data);
+
+                       switch_core_set_variable("spawn_instead_of_system", "true");
+
+                       fst_requires_module("mod_sndfile");
+                       fst_requires_module("mod_voicemail");
+                       fst_requires_module("mod_sofia");
+                       fst_requires_module("mod_loopback");
+                       fst_requires_module("mod_console");
+                       fst_requires_module("mod_dptools");
+                       fst_requires_module("mod_dialplan_xml");
+                       fst_requires_module("mod_commands");
+                       fst_requires_module("mod_say_en");
+                       fst_requires_module("mod_tone_stream");
+
+               }
+               FST_SETUP_END()
+
+               FST_TEARDOWN_BEGIN()
+               {
+               }
+               FST_TEARDOWN_END()
+
+               FST_TEST_BEGIN(uac_digest_leak_udp)
+               {
+                       switch_core_session_t *session; 
+                       switch_call_cause_t cause;
+                       switch_status_t status;
+                       switch_channel_t *channel;
+                       const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+                       int sipp_ret;
+
+                       switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler, NULL);
+
+                       status = switch_ivr_originate(NULL, &session, &cause, "loopback/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+                       sipp_ret = start_sipp_uac(local_ip_v4, 5080, "sipp-scenarios/uac_digest_leak.xml", "");
+                       if (sipp_ret < 0 || sipp_ret == 127) {
+                               fst_requires(0); /* sipp not found */
+                       }
+
+                       fst_check(status == SWITCH_STATUS_SUCCESS);
+                       if (!session) {
+                               fst_requires(session);
+                       }
+
+                       channel = switch_core_session_get_channel(session);
+                       fst_xcheck(switch_channel_get_state(channel) < CS_HANGUP, "Expect call not to be hung up");
+
+                       while (1) {
+                               int ret;
+                               switch_sleep(1000 * 1000);
+                               ret = switch_system("pidof sipp", SWITCH_TRUE);
+                               if (!ret) {
+                                       break;
+                               }
+                       }
+
+                       switch_sleep(5000 * 1000);
+
+                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+
+                       switch_core_session_rwunlock(session);
+                       switch_sleep(1000 * 1000);
+
+                       switch_event_unbind_callback(event_handler);
+                       /* sipp should timeout, attempt kill, just in case.*/
+                       kill_sipp();
+                       fst_check(test_success);
+                       test_success = 0;
+               }
+               FST_TEST_END()
+
+               FST_TEST_BEGIN(uac_digest_leak_tcp)
+               {
+                       switch_core_session_t *session; 
+                       switch_call_cause_t cause;
+                       switch_status_t status;
+                       switch_channel_t *channel;
+                       const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+                       int sipp_ret;
+
+                       switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler, NULL);
+
+                       status = switch_ivr_originate(NULL, &session, &cause, "loopback/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+                       sipp_ret = start_sipp_uac(local_ip_v4, 5080, "sipp-scenarios/uac_digest_leak-tcp.xml", "-t t1");
+                       if (sipp_ret < 0 || sipp_ret == 127) {
+                               fst_requires(0); /* sipp not found */
+                       }
+
+                       fst_check(status == SWITCH_STATUS_SUCCESS);
+                       if (!session) {
+                               fst_requires(session);
+                       }
+
+                       channel = switch_core_session_get_channel(session);
+                       fst_xcheck(switch_channel_get_state(channel) < CS_HANGUP, "Expect call not to be hung up");
+
+                       while (1) {
+                               int ret;
+                               switch_sleep(1000 * 1000);
+                               ret = switch_system("pidof sipp", SWITCH_TRUE);
+                               if (!ret) {
+                                       break;
+                               }
+                       }
+
+                       switch_sleep(5000 * 1000);
+
+                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+
+                       switch_core_session_rwunlock(session);
+                       switch_sleep(1000 * 1000);
+
+                       switch_event_unbind_callback(event_handler);
+                       /* sipp should timeout, attempt kill, just in case.*/
+                       kill_sipp();
+                       fst_check(test_success);
+                       test_success = 0;
+               }
+               FST_TEST_END()
+
+               FST_TEST_BEGIN(uac_digest_leak_udp_ipv6)
+               {
+                       switch_core_session_t *session; 
+                       switch_call_cause_t cause;
+                       switch_status_t status;
+                       switch_channel_t *channel;
+                       const char *local_ip_v6 = switch_core_get_variable("local_ip_v6");
+                       int sipp_ret;
+                       char *ipv6 = NULL;
+
+                       if (!has_ipv6()) {
+                               goto skiptest;
+                       }
+                       switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler, NULL);
+
+                       if (!strchr(local_ip_v6,'[')) {
+                               ipv6 = switch_mprintf("[%s]", local_ip_v6);
+                       }
+                       status = switch_ivr_originate(NULL, &session, &cause, "loopback/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+
+                       if (!ipv6) {
+                               sipp_ret = start_sipp_uac(local_ip_v6, 6060, "sipp-scenarios/uac_digest_leak-ipv6.xml", "-i [::1]");
+                       } else {
+                               sipp_ret = start_sipp_uac(ipv6, 6060, "sipp-scenarios/uac_digest_leak-ipv6.xml", "-i [::1] -mi [::1]");
+                       }
+
+                       if (sipp_ret < 0 || sipp_ret == 127) {
+                               fst_requires(0); /* sipp not found */
+                       }
+
+                       fst_check(status == SWITCH_STATUS_SUCCESS);
+                       if (!session) {
+                               fst_requires(session);
+                       }
+
+                       channel = switch_core_session_get_channel(session);
+                       fst_xcheck(switch_channel_get_state(channel) < CS_HANGUP, "Expect call not to be hung up");
+
+                       while (1) {
+                               int ret;
+                               switch_sleep(1000 * 1000);
+                               ret = switch_system("pidof sipp", SWITCH_TRUE);
+                               if (!ret) {
+                                       break;
+                               }
+                       }
+
+                       switch_sleep(5000 * 1000);
+
+                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+
+                       switch_core_session_rwunlock(session);
+                       switch_sleep(1000 * 1000);
+
+                       switch_event_unbind_callback(event_handler);
+                       /* sipp should timeout, attempt kill, just in case.*/
+                       kill_sipp();
+                       switch_safe_free(ipv6);
+                       fst_check(test_success);
+skiptest:
+                       test_success = 0;
+               }
+               FST_TEST_END()
+
+       }
+       FST_MODULE_END()
+}
+FST_CORE_END()
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-ipv6.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-ipv6.xml
new file mode 100644 (file)
index 0000000..6ddbe06
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>\r
+<!DOCTYPE scenario SYSTEM "sipp.dtd">\r
+\r
+<!-- SIP digest leak test scenario -->\r
+<!-- Note: realm at WWW-Authenticate may have to be changed if phone realm configuration is not empty -->\r
+<!-- (empty realm at phone configuration = auth against any realm) -->\r
+<!-- http://tomeko.net -->\r
+\r
+<scenario name="SIP digest leak test">\r
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->\r
+  <!-- generated by sipp. To do so, use [call_id] keyword.                -->\r
+\r
+<!-- FS: ipv4 in sdp is intentional -->\r
+  <send retrans="500">\r
+    <![CDATA[\r
+\r
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\r
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\r
+      From: sipp <sip:1001@[local_ip]:[local_port]>;tag=[call_number]\r
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>\r
+      Call-ID: [call_id]\r
+      CSeq: 1 INVITE\r
+      Contact: sip:1001@[local_ip]:[local_port]\r
+      Max-Forwards: 70\r
+      Subject: Performance Test\r
+      Content-Type: application/sdp\r
+      Content-Length: [len]\r
+\r
+      v=0\r
+      o=user1 53655765 2353687637 IN IP[local_ip_type] 0000:0000:0000:0000:0000:0000:0000:0001\r
+      s=-\r
+      c=IN IP6 0000:0000:0000:0000:0000:0000:0000:0001\r
+      t=0 0\r
+      m=audio [media_port] RTP/AVP 0\r
+      a=rtpmap:0 PCMU/8000\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <recv response="100"\r
+        optional="true">\r
+  </recv>\r
+\r
+  <recv response="183" optional="true">\r
+  </recv>\r
+\r
+  <recv response="180" optional="true">\r
+  </recv>\r
+\r
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->\r
+  <!-- are saved and used for following messages sent. Useful to test   -->\r
+  <!-- against stateful SIP proxies/B2BUAs.                             -->\r
+  <recv response="200" rtd="true">\r
+  </recv>\r
+\r
+  <!-- Packet lost can be simulated in any send/recv message by         -->\r
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->\r
+  <send>\r
+    <![CDATA[\r
+\r
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\r
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\r
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\r
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\r
+      Call-ID: [call_id]\r
+      CSeq: 1 ACK\r
+      Contact: sip:1001@[local_ip]:[local_port]\r
+      Max-Forwards: 70\r
+      Subject: Performance Test\r
+      Content-Length: 0\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <!-- At this moment second party is hanging up call (no audio there) -->\r
+  <recv request="BYE"></recv>\r
+\r
+\r
+  <!-- Test with SIP hardware phone: must use WWW-Authenticate instead of Proxy-Authenticate.\r
+       You could also try with SIP/2.0 401 Unauthorized. -->\r
+\r
+  <send>\r
+    <![CDATA[\r
+\r
+      SIP/2.0 407 Proxy Authentication Required\r
+      [last_Via:]\r
+      [last_From:]\r
+      [last_To:]\r
+      [last_Call-ID:]\r
+      [last_CSeq:]\r
+      Proxy-Authenticate: Digest algorithm=MD5, realm="freeswitch.org", nonce="69d327e5"\r
+      Content-Length: 0\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <recv request="BYE"></recv>\r
+\r
+\r
+</scenario>\r
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-tcp.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-tcp.xml
new file mode 100644 (file)
index 0000000..7276fa1
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>\r
+<!DOCTYPE scenario SYSTEM "sipp.dtd">\r
+\r
+<!-- SIP digest leak test scenario -->\r
+<!-- Note: realm at WWW-Authenticate may have to be changed if phone realm configuration is not empty -->\r
+<!-- (empty realm at phone configuration = auth against any realm) -->\r
+<!-- http://tomeko.net -->\r
+\r
+<scenario name="SIP digest leak test">\r
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->\r
+  <!-- generated by sipp. To do so, use [call_id] keyword.                -->\r
+  <send retrans="500">\r
+    <![CDATA[\r
+\r
+      INVITE sip:[service]@[remote_ip]:[remote_port];transport=tcp SIP/2.0\r
+      Via: SIP/2.0/[transport] 127.0.0.1:[local_port];branch=[branch];transport=tcp\r
+      From: sipp <sip:1001@127.0.0.1:[local_port];transport=tcp>;tag=[call_number]\r
+      To: sut <sip:[service]@[remote_ip]:[remote_port];transport=tcp>\r
+      Call-ID: [call_id]\r
+      CSeq: 1 INVITE\r
+      Contact: <sip:1001@127.0.0.1:[local_port];transport=tcp>\r
+      Max-Forwards: 70\r
+      Subject: Performance Test\r
+      Content-Type: application/sdp\r
+      Content-Length: [len]\r
+\r
+      v=0\r
+      o=user1 53655765 2353687637 IN IP[local_ip_type] 127.0.0.1\r
+      s=-\r
+      c=IN IP[media_ip_type] 127.0.0.1\r
+      t=0 0\r
+      m=audio [media_port] RTP/AVP 0\r
+      a=rtpmap:0 PCMU/8000\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <recv response="100"\r
+        optional="true">\r
+  </recv>\r
+\r
+  <recv response="183" optional="true">\r
+  </recv>\r
+\r
+  <recv response="180" optional="true">\r
+  </recv>\r
+\r
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->\r
+  <!-- are saved and used for following messages sent. Useful to test   -->\r
+  <!-- against stateful SIP proxies/B2BUAs.                             -->\r
+  <recv response="200" rtd="true">\r
+  </recv>\r
+\r
+  <!-- Packet lost can be simulated in any send/recv message by         -->\r
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->\r
+  <send>\r
+    <![CDATA[\r
+\r
+      ACK sip:[service]@[remote_ip]:[remote_port];transport=tcp SIP/2.0\r
+      Via: SIP/2.0/[transport] 127.0.0.1:[local_port];branch=[branch];transport=tcp\r
+      From: sipp <sip:sipp@127.0.0.1:[local_port]>;tag=[call_number]\r
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\r
+      Call-ID: [call_id]\r
+      CSeq: 1 ACK\r
+      Contact: <sip:1001@127.0.0.1:[local_port];transport=tcp>\r
+      Max-Forwards: 70\r
+      Subject: Performance Test\r
+      Content-Length: 0\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <!-- At this moment second party is hanging up call (no audio there) -->\r
+\r
+ <recv request="BYE"></recv> \r
+   \r
+  <!--  <pause milliseconds="1000"/> -->\r
+  <!-- Test with SIP hardware phone: must use WWW-Authenticate instead of Proxy-Authenticate.\r
+       You could also try with SIP/2.0 401 Unauthorized. -->\r
+\r
+  <send>\r
+    <![CDATA[\r
+\r
+      SIP/2.0 407 Proxy Authentication Required\r
+      [last_Via:]\r
+      [last_From:]\r
+      [last_To:]\r
+      [last_Call-ID:]\r
+      [last_CSeq:]\r
+      Proxy-Authenticate: Digest algorithm=MD5, realm="freeswitch.org", nonce="69d327e5"\r
+      Content-Length: 0\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <recv request="BYE"></recv>\r
+\r
+\r
+</scenario>\r
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak.xml
new file mode 100644 (file)
index 0000000..7c1e9eb
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>\r
+<!DOCTYPE scenario SYSTEM "sipp.dtd">\r
+\r
+<!-- SIP digest leak test scenario -->\r
+<!-- Note: realm at WWW-Authenticate may have to be changed if phone realm configuration is not empty -->\r
+<!-- (empty realm at phone configuration = auth against any realm) -->\r
+<!-- http://tomeko.net -->\r
+\r
+<scenario name="SIP digest leak test">\r
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->\r
+  <!-- generated by sipp. To do so, use [call_id] keyword.                -->\r
+  <send retrans="500">\r
+    <![CDATA[\r
+\r
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\r
+      Via: SIP/2.0/[transport] 127.0.0.1:[local_port];branch=[branch]\r
+      From: sipp <sip:1001@127.0.0.1:[local_port]>;tag=[call_number]\r
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>\r
+      Call-ID: [call_id]\r
+      CSeq: 1 INVITE\r
+      Contact: sip:1001@127.0.0.1:[local_port]\r
+      Max-Forwards: 70\r
+      Subject: Performance Test\r
+      Content-Type: application/sdp\r
+      Content-Length: [len]\r
+\r
+      v=0\r
+      o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\r
+      s=-\r
+      c=IN IP[media_ip_type] [media_ip]\r
+      t=0 0\r
+      m=audio [media_port] RTP/AVP 0\r
+      a=rtpmap:0 PCMU/8000\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <recv response="100"\r
+        optional="true">\r
+  </recv>\r
+\r
+  <recv response="183" optional="true">\r
+  </recv>\r
+\r
+  <recv response="180" optional="true">\r
+  </recv>\r
+\r
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->\r
+  <!-- are saved and used for following messages sent. Useful to test   -->\r
+  <!-- against stateful SIP proxies/B2BUAs.                             -->\r
+  <recv response="200" rtd="true">\r
+  </recv>\r
+\r
+  <!-- Packet lost can be simulated in any send/recv message by         -->\r
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->\r
+  <send>\r
+    <![CDATA[\r
+\r
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\r
+      Via: SIP/2.0/[transport] 127.0.0.1:[local_port];branch=[branch]\r
+      From: sipp <sip:sipp@127.0.0.1:[local_port]>;tag=[call_number]\r
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\r
+      Call-ID: [call_id]\r
+      CSeq: 1 ACK\r
+      Contact: sip:1001@127.0.0.1:[local_port]\r
+      Max-Forwards: 70\r
+      Subject: Performance Test\r
+      Content-Length: 0\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <!-- At this moment second party is hanging up call (no audio there) -->\r
+  <recv request="BYE"></recv>\r
+\r
+\r
+  <!-- Test with SIP hardware phone: must use WWW-Authenticate instead of Proxy-Authenticate.\r
+       You could also try with SIP/2.0 401 Unauthorized. -->\r
+\r
+  <send>\r
+    <![CDATA[\r
+\r
+      SIP/2.0 407 Proxy Authentication Required\r
+      [last_Via:]\r
+      [last_From:]\r
+      [last_To:]\r
+      [last_Call-ID:]\r
+      [last_CSeq:]\r
+      Proxy-Authenticate: Digest algorithm=MD5, realm="freeswitch.org", nonce="69d327e5"\r
+      Content-Length: 0\r
+\r
+    ]]>\r
+  </send>\r
+\r
+  <recv request="BYE"></recv>\r
+\r
+\r
+</scenario>\r
diff --git a/src/mod/endpoints/mod_sofia/test/test_run_sipp.sh b/src/mod/endpoints/mod_sofia/test/test_run_sipp.sh
new file mode 100755 (executable)
index 0000000..fbe01c1
--- /dev/null
@@ -0,0 +1,3 @@
+#/bin/sh
+./sipp-based-tests
+
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-goodbye.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-goodbye.wav
new file mode 100644 (file)
index 0000000..b656226
Binary files /dev/null and b/src/mod/endpoints/mod_sofia/test/voicemail/vm-goodbye.wav differ
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-not_available.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-not_available.wav
new file mode 100644 (file)
index 0000000..fc53583
Binary files /dev/null and b/src/mod/endpoints/mod_sofia/test/voicemail/vm-not_available.wav differ
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-person.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-person.wav
new file mode 100644 (file)
index 0000000..9d008b1
Binary files /dev/null and b/src/mod/endpoints/mod_sofia/test/voicemail/vm-person.wav differ
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-record_message.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-record_message.wav
new file mode 100644 (file)
index 0000000..b591ec5
Binary files /dev/null and b/src/mod/endpoints/mod_sofia/test/voicemail/vm-record_message.wav differ
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-too-small.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-too-small.wav
new file mode 100644 (file)
index 0000000..35ca061
Binary files /dev/null and b/src/mod/endpoints/mod_sofia/test/voicemail/vm-too-small.wav differ