mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-09 09:17:34 +00:00
add sofia_dig [xml] api func
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16745 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
4d3dac5b52
commit
ffe784f110
@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
|
|||||||
SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
|
SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
|
||||||
|
|
||||||
mod_LTLIBRARIES = mod_sofia.la
|
mod_LTLIBRARIES = mod_sofia.la
|
||||||
mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c mod_sofia.h
|
mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c sip-dig.c mod_sofia.h
|
||||||
mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I.
|
mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I.
|
||||||
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
|
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
|
||||||
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http
|
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http
|
||||||
|
@ -3935,6 +3935,7 @@ static switch_status_t list_profile_gateway(const char *line, const char *cursor
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
||||||
{
|
{
|
||||||
switch_chat_interface_t *chat_interface;
|
switch_chat_interface_t *chat_interface;
|
||||||
@ -4084,6 +4085,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
|||||||
|
|
||||||
|
|
||||||
SWITCH_ADD_API(api_interface, "sofia_contact", "Sofia Contacts", sofia_contact_function, "[profile/]<user>@<domain>");
|
SWITCH_ADD_API(api_interface, "sofia_contact", "Sofia Contacts", sofia_contact_function, "[profile/]<user>@<domain>");
|
||||||
|
SWITCH_ADD_API(api_interface, "sofia_dig", "SIP DIG", sip_dig_function, "<url>");
|
||||||
SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
|
SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
|
||||||
|
|
||||||
/* indicate that the module should continue to be loaded */
|
/* indicate that the module should continue to be loaded */
|
||||||
|
@ -973,3 +973,4 @@ void sofia_glue_tech_untrack(sofia_profile_t *profile, switch_core_session_t *se
|
|||||||
void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *session);
|
void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *session);
|
||||||
int sofia_glue_recover(switch_bool_t flush);
|
int sofia_glue_recover(switch_bool_t flush);
|
||||||
void sofia_profile_destroy(sofia_profile_t *profile);
|
void sofia_profile_destroy(sofia_profile_t *profile);
|
||||||
|
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);
|
||||||
|
896
src/mod/endpoints/mod_sofia/sip-dig.c
Normal file
896
src/mod/endpoints/mod_sofia/sip-dig.c
Normal file
@ -0,0 +1,896 @@
|
|||||||
|
/*
|
||||||
|
* 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 "switch.h"
|
||||||
|
#include "../../config.h"
|
||||||
|
|
||||||
|
#include "sofia-sip/su.h"
|
||||||
|
|
||||||
|
#include "sofia-resolv/sres.h"
|
||||||
|
#include "sofia-resolv/sres_record.h"
|
||||||
|
|
||||||
|
#include "sofia-sip/url.h"
|
||||||
|
#include "sofia-sip/su_alloc.h"
|
||||||
|
#include "sofia-sip/su_string.h"
|
||||||
|
#include "sofia-sip/hostdomain.h"
|
||||||
|
|
||||||
|
char const name[] = "sip-dig";
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
void _usage(int exitcode, switch_stream_handle_t *stream)
|
||||||
|
{
|
||||||
|
stream->write_function(stream, "%s", "usage: sofia_dig [OPTIONS] [@dnsserver] uri\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
{
|
||||||
|
int exitcode = 0;
|
||||||
|
int o_sctp = 1, o_tls_sctp = 1, o_verbatim = 1;
|
||||||
|
int family = 0, multiple = 0;
|
||||||
|
char const *dnsserver = NULL;
|
||||||
|
char const *string;
|
||||||
|
url_t *uri = NULL;
|
||||||
|
|
||||||
|
char const *host;
|
||||||
|
char const *port;
|
||||||
|
char *transport = NULL, tport[32];
|
||||||
|
int argc;
|
||||||
|
char *argv_[25] = { 0 };
|
||||||
|
char *mycmd = NULL;
|
||||||
|
char **argv;
|
||||||
|
struct dig dig[1] = {{ NULL }};
|
||||||
|
su_home_t *home = NULL;
|
||||||
|
int xml = 0;
|
||||||
|
|
||||||
|
home = su_home_new(sizeof(*home));
|
||||||
|
|
||||||
|
argv = argv_;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
|
{usage(1);}
|
||||||
|
}
|
||||||
|
|
||||||
|
mycmd = strdup(cmd);
|
||||||
|
|
||||||
|
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv_) / sizeof(argv_[0])) - 1);
|
||||||
|
argv = argv_;
|
||||||
|
|
||||||
|
if (!strcasecmp(argv[1], "xml")) {
|
||||||
|
switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "xml", "true");
|
||||||
|
argv++;
|
||||||
|
xml++;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[0] = "sofia_dig";
|
||||||
|
|
||||||
|
|
||||||
|
//if (su_init() != 0)
|
||||||
|
//return -1;
|
||||||
|
|
||||||
|
while (argv[1] && argv[1][0] == '-') {
|
||||||
|
if (strcmp(argv[1], "-v") == 0)
|
||||||
|
o_verbatim++;
|
||||||
|
else if (strcmp(argv[1], "-6") == 0)
|
||||||
|
dig->ip6 = ++family;
|
||||||
|
else if (strcmp(argv[1], "-4") == 0)
|
||||||
|
dig->ip4 = ++family;
|
||||||
|
else if (strncmp(argv[1], "-p", 2) == 0) {
|
||||||
|
char const *proto;
|
||||||
|
|
||||||
|
if (argv[1][2] == '=')
|
||||||
|
proto = argv[1] + 3;
|
||||||
|
else if (argv[1][2])
|
||||||
|
proto = argv[1] + 2;
|
||||||
|
else
|
||||||
|
proto = argv++[2];
|
||||||
|
|
||||||
|
if (proto == NULL)
|
||||||
|
{usage(2);}
|
||||||
|
|
||||||
|
if (prepare_transport(dig, proto) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[1], "--udp") == 0)
|
||||||
|
prepare_transport(dig, "udp");
|
||||||
|
else if (strcmp(argv[1], "--tcp") == 0)
|
||||||
|
prepare_transport(dig, "tcp");
|
||||||
|
else if (strcmp(argv[1], "--tls") == 0)
|
||||||
|
prepare_transport(dig, "tls");
|
||||||
|
else if (strcmp(argv[1], "--sctp") == 0)
|
||||||
|
prepare_transport(dig, "sctp");
|
||||||
|
else if (strcmp(argv[1], "--tls-sctp") == 0)
|
||||||
|
prepare_transport(dig, "tls-sctp");
|
||||||
|
else if (strcmp(argv[1], "--tls-udp") == 0)
|
||||||
|
prepare_transport(dig, "tls-udp");
|
||||||
|
else if (strcmp(argv[1], "--no-sctp") == 0)
|
||||||
|
o_sctp = 0, o_tls_sctp = 0;
|
||||||
|
else if (strcmp(argv[1], "--help") == 0)
|
||||||
|
{usage(0);}
|
||||||
|
else if (strcmp(argv[1], "-h") == 0)
|
||||||
|
{usage(0);}
|
||||||
|
else if (strcmp(argv[1], "-?") == 0)
|
||||||
|
{usage(0);}
|
||||||
|
else if (strcmp(argv++[1], "-") == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{usage(2);}
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (xml) {
|
||||||
|
stream->write_function(stream, "%s", "<routes>\n");
|
||||||
|
} else {
|
||||||
|
stream->write_function(stream, "%10s\t%10s\t%10s\t%10s\t%10s\n", "Preference", "Weight", "Transport", "Port", "Address");
|
||||||
|
stream->write_function(stream, "================================================================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!family)
|
||||||
|
dig->ip4 = 1, dig->ip6 = 2;
|
||||||
|
|
||||||
|
if (argv[1] && argv[1][0] == '@')
|
||||||
|
dnsserver = argv++[1] + 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!argv[1])
|
||||||
|
{usage(2);}
|
||||||
|
|
||||||
|
|
||||||
|
multiple = argv[1] && argv[2];
|
||||||
|
|
||||||
|
if (!count_transports(dig, NULL, NULL)) {
|
||||||
|
prepare_transport(dig, "udp");
|
||||||
|
prepare_transport(dig, "tcp");
|
||||||
|
if (o_sctp)
|
||||||
|
prepare_transport(dig, "sctp");
|
||||||
|
prepare_transport(dig, "tls");
|
||||||
|
if (o_tls_sctp)
|
||||||
|
prepare_transport(dig, "tls-sctp");
|
||||||
|
}
|
||||||
|
|
||||||
|
dig->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
|
||||||
|
if (!dig->sres)
|
||||||
|
{usage(1);}
|
||||||
|
|
||||||
|
for (; (string = argv[1]); argv++) {
|
||||||
|
if (multiple)
|
||||||
|
stream->write_function(stream, "%s", string);
|
||||||
|
|
||||||
|
uri = url_hdup(home, (void *)string);
|
||||||
|
|
||||||
|
if (uri && uri->url_type == url_unknown)
|
||||||
|
url_sanitize(uri);
|
||||||
|
|
||||||
|
if (uri && uri->url_type == url_any)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!uri || (uri->url_type != url_sip && uri->url_type != url_sips)) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: invalid uri\n", string);
|
||||||
|
exitcode = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
port = url_port(uri);
|
||||||
|
if (port && !port[0]) port = NULL;
|
||||||
|
if (url_param(uri->url_params, "transport=", tport, sizeof tport) > 0)
|
||||||
|
transport = tport;
|
||||||
|
|
||||||
|
host = uri->url_host;
|
||||||
|
|
||||||
|
if (host_is_ip_address(host)) {
|
||||||
|
if (transport) {
|
||||||
|
print_result(host, port, transport, 1.0, 1, stream);
|
||||||
|
}
|
||||||
|
else if (uri->url_type == url_sips) {
|
||||||
|
print_result(host, port, "tls", 1.0, 1, stream);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print_result(host, port, "udp", 1.0, 1, stream);
|
||||||
|
print_result(host, port, "tcp", 1.0, 2, stream);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!host_is_domain(host)) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: invalid host\n", string);
|
||||||
|
exitcode = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dig->sips = uri->url_type == url_sips;
|
||||||
|
dig->preference = 1;
|
||||||
|
|
||||||
|
if (!port && !transport && dig_naptr(dig, host, 1.0, stream))
|
||||||
|
continue /* resolved naptr */;
|
||||||
|
else if (!port && dig_all_srvs(dig, transport, host, 1.0, stream))
|
||||||
|
continue /* resolved srv */;
|
||||||
|
else if (dig_addr(dig, transport, host, port, 1.0, stream))
|
||||||
|
continue /* resolved a/aaaa */;
|
||||||
|
|
||||||
|
stream->write_function(stream, "-ERR: %s: not found\n", string);
|
||||||
|
exitcode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xml) {
|
||||||
|
stream->write_function(stream, "%s", "</routes>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fail:
|
||||||
|
su_home_unref(home);
|
||||||
|
sres_resolver_unref(dig->sres);
|
||||||
|
switch_safe_free(mycmd);
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int transport_is_secure(char const *tportname)
|
||||||
|
{
|
||||||
|
return su_casenmatch(tportname, "tls", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
int prepare_transport(struct dig *dig, char const *tport)
|
||||||
|
{
|
||||||
|
struct transport *tports = dig->tports;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < N_TPORT; j++) {
|
||||||
|
if (!tports[j].name)
|
||||||
|
break;
|
||||||
|
if (su_casematch(tports[j].name, tport))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == N_TPORT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strchr(tport, '/')) {
|
||||||
|
char *service = strchr(tport, '/');
|
||||||
|
char *srv = strchr(service + 1, '/');
|
||||||
|
|
||||||
|
if (!srv || srv[strlen(srv) - 1] != '.') {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: invalid transport specifier \"%s\"\n"
|
||||||
|
|
||||||
|
"\tspecifier should have name/service/srv-id\n"
|
||||||
|
"\twhere name is protocol name (e.g, \"tls-udp\")\n"
|
||||||
|
"\t service specifies service as per RFC 2915 (e.g., \"SIPS+D2U\")\n"
|
||||||
|
"\t srv-id is prefix for SRV lookup (e.g., \"_sips._udp.\")\n%s",
|
||||||
|
name,
|
||||||
|
tport,
|
||||||
|
srv ? "\t and it should end with a dot \".\"\n" : "");
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*service++ = '\0', *srv++ = '\0';
|
||||||
|
|
||||||
|
tports[j].name = tport,
|
||||||
|
tports[j].service = service;
|
||||||
|
tports[j].srv = srv;
|
||||||
|
}
|
||||||
|
else if (su_casematch(tport, "udp")) {
|
||||||
|
tports[j].name = "udp";
|
||||||
|
tports[j].service = "SIP+D2U";
|
||||||
|
tports[j].srv = "_sip._udp.";
|
||||||
|
}
|
||||||
|
else if (su_casematch(tport, "tcp")) {
|
||||||
|
tports[j].name = "tcp";
|
||||||
|
tports[j].service = "SIP+D2T";
|
||||||
|
tports[j].srv = "_sip._tcp.";
|
||||||
|
}
|
||||||
|
else if (su_casematch(tport, "tls")) {
|
||||||
|
tports[j].name = "tls";
|
||||||
|
tports[j].service = "SIPS+D2T";
|
||||||
|
tports[j].srv = "_sips._tcp.";
|
||||||
|
}
|
||||||
|
else if (su_casematch(tport, "sctp")) {
|
||||||
|
tports[j].name = "sctp";
|
||||||
|
tports[j].service = "SIP+D2S";
|
||||||
|
tports[j].srv = "_sip._sctp.";
|
||||||
|
}
|
||||||
|
else if (su_casematch(tport, "tls-sctp")) {
|
||||||
|
tports[j].name = "tls-sctp";
|
||||||
|
tports[j].service = "SIPS+D2S";
|
||||||
|
tports[j].srv = "_sips._sctp.";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: unknown transport \"%s\"\n", name, tport);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
|
||||||
|
tports[j].service = tports[j].srv = tports[j].name = NULL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
count_transports(struct dig *dig,
|
||||||
|
char const *tport,
|
||||||
|
char const *tport2)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, tcount = 0;
|
||||||
|
struct transport const *tports = dig->tports;
|
||||||
|
|
||||||
|
for (i = 0; tports[i].name; i++) {
|
||||||
|
if (dig->sips && !transport_is_secure(tports[i].name))
|
||||||
|
continue;
|
||||||
|
if (!tport || su_casematch(tport, tports[i].name))
|
||||||
|
tcount++;
|
||||||
|
else if (tport2 && su_casematch(tport2, tports[i].name))
|
||||||
|
tcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct transport const *
|
||||||
|
transport_by_service(struct transport const *tports, char const *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; tports[i].name; i++) {
|
||||||
|
if (su_casematch(tports[i].service, s))
|
||||||
|
return tports + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dig_naptr(struct dig *dig,
|
||||||
|
char const *host,
|
||||||
|
double weight,
|
||||||
|
switch_stream_handle_t *stream)
|
||||||
|
{
|
||||||
|
sres_record_t **answers = NULL;
|
||||||
|
struct transport const *tp;
|
||||||
|
int i, error;
|
||||||
|
int order = 0, count = 0, nacount = 0, scount = 0;
|
||||||
|
|
||||||
|
error = sres_blocking_query(dig->sres, sres_type_naptr, host, 0, &answers);
|
||||||
|
if (error < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Sort by priority */
|
||||||
|
sres_sort_answers(dig->sres, answers);
|
||||||
|
|
||||||
|
/* Count number of matching naptrs */
|
||||||
|
for (i = 0; answers[i]; i++) {
|
||||||
|
sres_naptr_record_t const *na = answers[i]->sr_naptr;
|
||||||
|
|
||||||
|
if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dig->print)
|
||||||
|
stream->write_function(stream, "%s\n\t%d IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s\n",
|
||||||
|
na->na_record->r_name, na->na_record->r_ttl,
|
||||||
|
na->na_order, na->na_prefer,
|
||||||
|
na->na_flags, na->na_services,
|
||||||
|
na->na_regexp, na->na_replace);
|
||||||
|
|
||||||
|
if (!su_casematch(na->na_flags, "s") && !su_casematch(na->na_flags, "a"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nacount && order != na->na_order)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dig->sips && !su_casenmatch(na->na_services, "SIPS+", 5))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!transport_by_service(dig->tports, na->na_services))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
order = na->na_order, nacount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nacount == 0) {
|
||||||
|
sres_free_answers(dig->sres, answers);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; answers[i]; i++) {
|
||||||
|
sres_naptr_record_t const *na = answers[i]->sr_naptr;
|
||||||
|
|
||||||
|
if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
|
||||||
|
continue;
|
||||||
|
if (order != na->na_order)
|
||||||
|
continue;
|
||||||
|
if (!su_casematch(na->na_flags, "s") && !su_casematch(na->na_flags, "a"))
|
||||||
|
continue;
|
||||||
|
if (dig->sips && !su_casenmatch(na->na_services, "SIPS+", 5))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tp = transport_by_service(dig->tports, na->na_services);
|
||||||
|
if (!tp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (su_casematch(na->na_flags, "s")) {
|
||||||
|
scount = dig_srv(dig, tp->name, na->na_replace, weight / nacount, stream);
|
||||||
|
}
|
||||||
|
else if (su_casematch(na->na_flags, "a")) {
|
||||||
|
scount = dig_addr(dig, tp->name, na->na_replace, NULL, weight / nacount, stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
scount = 0;
|
||||||
|
|
||||||
|
count += scount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dig_all_srvs(struct dig *dig,
|
||||||
|
char const *tport,
|
||||||
|
char const *host,
|
||||||
|
double weight,
|
||||||
|
switch_stream_handle_t *stream)
|
||||||
|
{
|
||||||
|
int i, j, n;
|
||||||
|
int tcount, count = 0, scount;
|
||||||
|
char *domain;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char const *proto; sres_record_t **answers;
|
||||||
|
} srvs[N_TPORT + 1] = {{ NULL }};
|
||||||
|
|
||||||
|
tcount = count_transports(dig, tport, NULL);
|
||||||
|
if (!tcount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0, n = 0; dig->tports[i].name; i++) {
|
||||||
|
if (tport && !su_casematch(dig->tports[i].name, tport))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dig->sips && !transport_is_secure(dig->tports[i].name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
domain = su_strcat(NULL, dig->tports[i].srv, host);
|
||||||
|
|
||||||
|
if (domain) {
|
||||||
|
if (sres_blocking_query(dig->sres, sres_type_srv, domain, 0,
|
||||||
|
&srvs[n].answers) >= 0) {
|
||||||
|
srvs[n++].proto = dig->tports[i].name;
|
||||||
|
}
|
||||||
|
free(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
unsigned priority = 0, pweight = 0, m = 0;
|
||||||
|
sres_record_t **answers = srvs[i].answers;
|
||||||
|
char const *tport = srvs[i].proto;
|
||||||
|
|
||||||
|
for (j = 0; answers[j]; j++) {
|
||||||
|
sres_srv_record_t const *srv = answers[j]->sr_srv;
|
||||||
|
|
||||||
|
if (srv->srv_record->r_type != sres_type_srv)
|
||||||
|
continue;
|
||||||
|
if (srv->srv_record->r_status != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (srv->srv_priority != priority && pweight != 0) {
|
||||||
|
scount = dig_srv_at(dig, tport, answers, weight / n, pweight,
|
||||||
|
priority, stream);
|
||||||
|
if (scount) dig->preference++;
|
||||||
|
count += scount;
|
||||||
|
pweight = 0, m = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
priority = srv->srv_priority, pweight += srv->srv_weight, m++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m) {
|
||||||
|
scount = dig_srv_at(dig, tport, answers, weight / n, pweight, priority, stream);
|
||||||
|
if (scount)
|
||||||
|
dig->preference++;
|
||||||
|
count += scount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dig_srv(struct dig *dig,
|
||||||
|
char const *tport,
|
||||||
|
char const *domain,
|
||||||
|
double weight,
|
||||||
|
switch_stream_handle_t *stream)
|
||||||
|
{
|
||||||
|
sres_record_t **answers = NULL;
|
||||||
|
int j, n, error;
|
||||||
|
int count = 0, scount = 0;
|
||||||
|
|
||||||
|
uint32_t priority, pweight;
|
||||||
|
|
||||||
|
assert(tport && domain);
|
||||||
|
|
||||||
|
error = sres_blocking_query(dig->sres, sres_type_srv, domain, 0, &answers);
|
||||||
|
if (error < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Sort by priority */
|
||||||
|
sres_sort_answers(dig->sres, answers);
|
||||||
|
|
||||||
|
priority = 0; pweight = 0; n = 0;
|
||||||
|
|
||||||
|
for (j = 0; answers[j]; j++) {
|
||||||
|
sres_srv_record_t const *srv = answers[j]->sr_srv;
|
||||||
|
|
||||||
|
if (srv->srv_record->r_type != sres_type_srv)
|
||||||
|
continue;
|
||||||
|
if (srv->srv_record->r_status != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (srv->srv_priority != priority && pweight != 0) {
|
||||||
|
scount = dig_srv_at(dig, tport, answers, weight, pweight,
|
||||||
|
priority, stream);
|
||||||
|
if (scount) dig->preference++;
|
||||||
|
count += scount;
|
||||||
|
pweight = 0, n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
priority = srv->srv_priority, pweight += srv->srv_weight, n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
scount = dig_srv_at(dig, tport, answers, weight, pweight, priority, stream);
|
||||||
|
if (scount) dig->preference++;
|
||||||
|
count += scount;
|
||||||
|
}
|
||||||
|
|
||||||
|
sres_free_answers(dig->sres, answers);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 count = 0;
|
||||||
|
int i;
|
||||||
|
char port[8];
|
||||||
|
|
||||||
|
if (pweight == 0)
|
||||||
|
pweight = 1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dig_addr(struct dig *dig,
|
||||||
|
char const *tport,
|
||||||
|
char const *host,
|
||||||
|
char const *port,
|
||||||
|
double weight,
|
||||||
|
switch_stream_handle_t *stream)
|
||||||
|
{
|
||||||
|
int error, i;
|
||||||
|
char const *tport2 = NULL;
|
||||||
|
sres_record_t **answers1 = NULL, **answers2 = NULL;
|
||||||
|
unsigned count1 = 0, count2 = 0, tcount = 0;
|
||||||
|
int type1 = 0, type2 = 0, family1 = 0, family2 = 0;
|
||||||
|
|
||||||
|
if (dig->ip6 > dig->ip4) {
|
||||||
|
type1 = sres_type_aaaa, family1 = AF_INET6;
|
||||||
|
if (dig->ip4)
|
||||||
|
type2 = sres_type_a, family2 = AF_INET;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
type1 = sres_type_a, family1 = AF_INET;
|
||||||
|
if (dig->ip6)
|
||||||
|
type2 = sres_type_aaaa, family2 = AF_INET6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tport == NULL) {
|
||||||
|
if (dig->sips)
|
||||||
|
tport = "tls";
|
||||||
|
else
|
||||||
|
tport = "udp", tport2 = "tcp";
|
||||||
|
}
|
||||||
|
|
||||||
|
tcount = count_transports(dig, tport, tport2);
|
||||||
|
if (!tcount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (type1) {
|
||||||
|
error = sres_blocking_query(dig->sres, type1, host, 0, &answers1);
|
||||||
|
if (error >= 0)
|
||||||
|
for (i = 0; answers1[i]; i++) {
|
||||||
|
sres_common_t *r = answers1[i]->sr_record;
|
||||||
|
count1 += r->r_type == type1 && r->r_status == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type2) {
|
||||||
|
error = sres_blocking_query(dig->sres, type2, host, 0, &answers2);
|
||||||
|
if (error >= 0)
|
||||||
|
for (i = 0; answers2[i]; i++) {
|
||||||
|
sres_common_t *r = answers2[i]->sr_record;
|
||||||
|
count2 += r->r_type == type2 && r->r_status == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count1 + count2) {
|
||||||
|
double w = weight / (count1 + count2) / tcount;
|
||||||
|
|
||||||
|
if (count1)
|
||||||
|
print_addr_results(dig->tports, tport, tport2,
|
||||||
|
answers1, type1, family1, port,
|
||||||
|
w, dig->preference, stream);
|
||||||
|
if (count2)
|
||||||
|
print_addr_results(dig->tports, tport, tport2,
|
||||||
|
answers2, type2, family2, port,
|
||||||
|
w, dig->preference, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
sres_free_answers(dig->sres, answers1);
|
||||||
|
sres_free_answers(dig->sres, answers2);
|
||||||
|
|
||||||
|
return count1 + count2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
char addr[64];
|
||||||
|
|
||||||
|
for (i = 0; answers[i]; i++) {
|
||||||
|
if (answers[i]->sr_record->r_type != type)
|
||||||
|
continue;
|
||||||
|
if (answers[i]->sr_record->r_status != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
su_inet_ntop(af, &answers[i]->sr_a->a_addr, addr, sizeof addr);
|
||||||
|
|
||||||
|
for (j = 0; tports[j].name; j++) {
|
||||||
|
if (su_casematch(tport, tports[j].name))
|
||||||
|
print_result(addr, port, tport, weight, preference, stream);
|
||||||
|
if (su_casematch(tport2, tports[j].name))
|
||||||
|
print_result(addr, port, tport2, weight, preference, stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_result(char const *addr,
|
||||||
|
char const *port,
|
||||||
|
char const *tport,
|
||||||
|
double weight,
|
||||||
|
unsigned preference,
|
||||||
|
switch_stream_handle_t *stream)
|
||||||
|
{
|
||||||
|
int xml = switch_true(switch_event_get_header(stream->param_event, "xml"));
|
||||||
|
|
||||||
|
if (!port || !port[0])
|
||||||
|
port = transport_is_secure(tport) ? "5061" : "5060";
|
||||||
|
|
||||||
|
if (xml) {
|
||||||
|
stream->write_function(stream,
|
||||||
|
" <route>\n"
|
||||||
|
" <preference>%u</preference>\n"
|
||||||
|
" <weight>%.3f</weight>\n"
|
||||||
|
" <transport>%s</transport>\n"
|
||||||
|
" <port>%s</port>\n"
|
||||||
|
" <address>%s</address>\n"
|
||||||
|
" </route>\n",
|
||||||
|
preference, weight, tport, port, addr);
|
||||||
|
} else {
|
||||||
|
stream->write_function(stream, "%10u\t%10.3f\t%10s\t%10s\t%10s\n", preference, weight, tport, port, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user