mirror of https://github.com/asterisk/asterisk
ASTERISK-30297 Change-Id: Ic700168c80b68879d9cee8bb07afe2712fb17996pull/30/head
parent
e66c5da145
commit
4095a382da
File diff suppressed because it is too large
Load Diff
@ -1,927 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip config parsing functions and unit tests
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "include/sip.h"
|
||||
#include "include/config_parser.h"
|
||||
#include "include/sip_utils.h"
|
||||
|
||||
/*! \brief Parse register=> line in sip.conf
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno)
|
||||
{
|
||||
int portnum = 0;
|
||||
int domainport = 0;
|
||||
enum ast_transport transport = AST_TRANSPORT_UDP;
|
||||
char buf[256] = "";
|
||||
char *userpart = NULL, *hostpart = NULL;
|
||||
/* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] */
|
||||
AST_DECLARE_APP_ARGS(pre1,
|
||||
AST_APP_ARG(peer);
|
||||
AST_APP_ARG(userpart);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(pre2,
|
||||
AST_APP_ARG(transport);
|
||||
AST_APP_ARG(blank);
|
||||
AST_APP_ARG(userpart);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(user1,
|
||||
AST_APP_ARG(userpart);
|
||||
AST_APP_ARG(secret);
|
||||
AST_APP_ARG(authuser);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(user2,
|
||||
AST_APP_ARG(user);
|
||||
AST_APP_ARG(domain);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(user3,
|
||||
AST_APP_ARG(authuser);
|
||||
AST_APP_ARG(domainport);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(host1,
|
||||
AST_APP_ARG(hostpart);
|
||||
AST_APP_ARG(expiry);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(host2,
|
||||
AST_APP_ARG(hostpart);
|
||||
AST_APP_ARG(extension);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(host3,
|
||||
AST_APP_ARG(host);
|
||||
AST_APP_ARG(port);
|
||||
);
|
||||
|
||||
if (!reg) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg->expire = -1;
|
||||
reg->timeout = -1;
|
||||
|
||||
if (!value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_copy_string(buf, value, sizeof(buf));
|
||||
|
||||
/*
|
||||
* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
|
||||
* becomes
|
||||
* userpart => [peer?][transport://]user[@domain][:secret[:authuser]]
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
if ((hostpart = strrchr(buf, '@'))) {
|
||||
*hostpart++ = '\0';
|
||||
userpart = buf;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(userpart) || ast_strlen_zero(hostpart)) {
|
||||
ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre1.userpart => [transport://]user[@domain][:secret[:authuser]]
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(pre1, userpart, '?');
|
||||
if (ast_strlen_zero(pre1.userpart)) {
|
||||
pre1.userpart = pre1.peer;
|
||||
pre1.peer = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* pre2.userpart => user[@domain][:secret[:authuser]]
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(pre2, pre1.userpart, '/');
|
||||
if (ast_strlen_zero(pre2.userpart)) {
|
||||
pre2.userpart = pre2.transport;
|
||||
pre2.transport = NULL;
|
||||
} else {
|
||||
pre2.transport[strlen(pre2.transport) - 1] = '\0'; /* Remove trailing : */
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(pre2.blank)) {
|
||||
ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(user1, pre2.userpart, ':');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host1.hostpart => host[:port][/extension]
|
||||
* host1.expiry => [expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(host1, hostpart, '~');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host2.hostpart => host[:port]
|
||||
* host2.extension => [extension]
|
||||
* host1.expiry => [expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(host2, host1.hostpart, '/');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host3.host => host
|
||||
* host3.port => port
|
||||
* host2.extension => extension
|
||||
* host1.expiry => expiry
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user2.user => user
|
||||
* user2.domain => domain
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host3.host => host
|
||||
* host3.port => port
|
||||
* host2.extension => extension
|
||||
* host1.expiry => expiry
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user2.user => user
|
||||
* user2.domain => domain
|
||||
* user1.secret => secret
|
||||
* user3.authuser => authuser
|
||||
* user3.domainport => domainport
|
||||
* host3.host => host
|
||||
* host3.port => port
|
||||
* host2.extension => extension
|
||||
* host1.expiry => expiry
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(user3, user1.authuser, ':');
|
||||
|
||||
/* Reordering needed due to fields being [(:secret[:username])|(:regdomainport:secret:username)]
|
||||
but parsing being [secret[:username[:regdomainport]]] */
|
||||
if (user3.argc == 2) {
|
||||
char *reorder = user3.domainport;
|
||||
user3.domainport = user1.secret;
|
||||
user1.secret = user3.authuser;
|
||||
user3.authuser = reorder;
|
||||
}
|
||||
|
||||
if (host3.port) {
|
||||
if (!(portnum = port_str2int(host3.port, 0))) {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno);
|
||||
}
|
||||
}
|
||||
if (user3.domainport) {
|
||||
if (!(domainport = port_str2int(user3.domainport, 0))) {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid domain port number on line %d of sip.conf. using default.\n", user3.domainport, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
/* set transport type */
|
||||
if (!pre2.transport) {
|
||||
transport = AST_TRANSPORT_UDP;
|
||||
} else if (!strncasecmp(pre2.transport, "tcp", 3)) {
|
||||
transport = AST_TRANSPORT_TCP;
|
||||
} else if (!strncasecmp(pre2.transport, "tls", 3)) {
|
||||
transport = AST_TRANSPORT_TLS;
|
||||
} else if (!strncasecmp(pre2.transport, "udp", 3)) {
|
||||
transport = AST_TRANSPORT_UDP;
|
||||
} else {
|
||||
transport = AST_TRANSPORT_UDP;
|
||||
ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", pre2.transport, lineno);
|
||||
}
|
||||
|
||||
/* if no portnum specified, set default for transport */
|
||||
if (!portnum) {
|
||||
if (transport == AST_TRANSPORT_TLS) {
|
||||
portnum = STANDARD_TLS_PORT;
|
||||
} else {
|
||||
portnum = STANDARD_SIP_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy into sip_registry object */
|
||||
ast_string_field_set(reg, callback, ast_strip_quoted(S_OR(host2.extension, "s"), "\"", "\""));
|
||||
ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user2.user, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user3.authuser, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, secret, ast_strip_quoted(S_OR(user1.secret, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, peername, ast_strip_quoted(S_OR(pre1.peer, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user2.domain, ""), "\"", "\""));
|
||||
|
||||
reg->transport = transport;
|
||||
reg->portno = portnum;
|
||||
reg->regdomainport = domainport;
|
||||
reg->callid_valid = FALSE;
|
||||
reg->ocseq = INITIAL_CSEQ;
|
||||
reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
AST_TEST_DEFINE(sip_parse_register_line_test)
|
||||
{
|
||||
int res = AST_TEST_PASS;
|
||||
struct sip_registry *reg;
|
||||
int default_expiry = 120;
|
||||
const char *reg1 = "name@domain";
|
||||
const char *reg2 = "name:pass@domain";
|
||||
const char *reg3 = "name@namedomain:pass:authuser@domain";
|
||||
const char *reg4 = "name@namedomain:pass:authuser@domain/extension";
|
||||
const char *reg5 = "tcp://name@namedomain:pass:authuser@domain/extension";
|
||||
const char *reg6 = "tls://name@namedomain:pass:authuser@domain/extension~111";
|
||||
const char *reg7 = "peer?tcp://name@namedomain:pass:authuser@domain:1234/extension~111";
|
||||
const char *reg8 = "peer?name@namedomain:pass:authuser@domain:1234/extension~111";
|
||||
const char *reg9 = "peer?name:pass:authuser:1234/extension~111";
|
||||
const char *reg10 = "@domin:1234";
|
||||
const char *reg12 = "name@namedomain:4321:pass:authuser@domain";
|
||||
const char *reg13 = "name@namedomain:4321::@domain";
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "sip_parse_register_line_test";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "tests sip register line parsing";
|
||||
info->description =
|
||||
"Tests parsing of various register line configurations. "
|
||||
"Verifies output matches expected behavior.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---Test reg 1, simple config --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg1, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "") ||
|
||||
strcmp(reg->secret, "") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 1: simple config failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 2, add secret --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg2, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 2: add secret failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 3, add userdomain and authuser --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg3, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 3: add userdomain and authuser failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 4, add callback extension --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg4, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 4: add callback extension failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 5, add transport --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg5, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_TCP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 5: add transport failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 6, change to tls transport, add expiry --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg6, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_TLS ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != 111 ||
|
||||
reg->expiry != 111 ||
|
||||
reg->configured_expiry != 111 ||
|
||||
reg->portno != STANDARD_TLS_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 6: change to tls transport and add expiry failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 7, change transport to tcp, add custom port, and add peer --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg7, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "peer") ||
|
||||
reg->transport != AST_TRANSPORT_TCP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != 111 ||
|
||||
reg->expiry != 111 ||
|
||||
reg->configured_expiry != 111 ||
|
||||
reg->portno != 1234 ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 7, change transport to tcp, add custom port, and add peer failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 8, remove transport --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg8, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "peer") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != 111 ||
|
||||
reg->expiry != 111 ||
|
||||
reg->configured_expiry != 111 ||
|
||||
reg->portno != 1234 ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 8, remove transport failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 9, missing domain, expected to fail --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) {
|
||||
ast_test_status_update(test,
|
||||
"Test 9, missing domain, expected to fail but did not.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 10, missing user, expected to fail --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) {
|
||||
ast_test_status_update(test,
|
||||
"Test 10, missing user expected to fail but did not\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 11, no registry object, expected to fail--- */
|
||||
if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) {
|
||||
ast_test_status_update(test,
|
||||
"Test 11, no registry object, expected to fail but did not.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* ---Test reg 12, no registry line, expected to fail --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) {
|
||||
|
||||
ast_test_status_update(test,
|
||||
"Test 12, NULL register line expected to fail but did not.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg13, add domain port --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg12, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
reg->regdomainport != 4321 ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 13, add domain port failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg14, domain port without secret --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg13, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "") ||
|
||||
strcmp(reg->secret, "") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
reg->regdomainport != 4321 ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 14, domain port without secret failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
|
||||
return res;
|
||||
|
||||
alloc_fail:
|
||||
ast_test_status_update(test, "Out of memory. \n");
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport)
|
||||
{
|
||||
char *port;
|
||||
|
||||
if (ast_strlen_zero(line)) {
|
||||
*hostname = NULL;
|
||||
return -1;
|
||||
}
|
||||
if ((*hostname = strstr(line, "://"))) {
|
||||
*hostname += 3;
|
||||
|
||||
if (!strncasecmp(line, "tcp", 3)) {
|
||||
*transport = AST_TRANSPORT_TCP;
|
||||
} else if (!strncasecmp(line, "tls", 3)) {
|
||||
*transport = AST_TRANSPORT_TLS;
|
||||
} else if (!strncasecmp(line, "udp", 3)) {
|
||||
*transport = AST_TRANSPORT_UDP;
|
||||
} else if (lineno) {
|
||||
ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", line, lineno);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type in sip config. defaulting to udp.\n", line);
|
||||
}
|
||||
} else {
|
||||
*hostname = line;
|
||||
*transport = AST_TRANSPORT_UDP;
|
||||
}
|
||||
|
||||
if ((line = strrchr(*hostname, '@')))
|
||||
line++;
|
||||
else
|
||||
line = *hostname;
|
||||
|
||||
if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
|
||||
if (lineno) {
|
||||
ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
|
||||
line, lineno);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Cannot parse host '%s' in sip config.\n", line);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (port) {
|
||||
if (!sscanf(port, "%5d", portnum)) {
|
||||
if (lineno) {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid port number in sip config. using default.\n", port);
|
||||
}
|
||||
port = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
if (*transport & AST_TRANSPORT_TLS) {
|
||||
*portnum = STANDARD_TLS_PORT;
|
||||
} else {
|
||||
*portnum = STANDARD_SIP_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
AST_TEST_DEFINE(sip_parse_host_line_test)
|
||||
{
|
||||
int res = AST_TEST_PASS;
|
||||
char *host;
|
||||
int port;
|
||||
enum ast_transport transport;
|
||||
char host1[] = "www.blah.com";
|
||||
char host2[] = "tcp://www.blah.com";
|
||||
char host3[] = "tls://10.10.10.10";
|
||||
char host4[] = "tls://10.10.10.10:1234";
|
||||
char host5[] = "10.10.10.10:1234";
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "sip_parse_host_line_test";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "tests sip.conf host line parsing";
|
||||
info->description =
|
||||
"Tests parsing of various host line configurations. "
|
||||
"Verifies output matches expected behavior.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* test 1, simple host */
|
||||
sip_parse_host(host1, 1, &host, &port, &transport);
|
||||
if (port != STANDARD_SIP_PORT ||
|
||||
ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
|
||||
transport != AST_TRANSPORT_UDP) {
|
||||
ast_test_status_update(test, "Test 1: simple host failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 2, add tcp transport */
|
||||
sip_parse_host(host2, 1, &host, &port, &transport);
|
||||
if (port != STANDARD_SIP_PORT ||
|
||||
ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
|
||||
transport != AST_TRANSPORT_TCP) {
|
||||
ast_test_status_update(test, "Test 2: tcp host failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 3, add tls transport */
|
||||
sip_parse_host(host3, 1, &host, &port, &transport);
|
||||
if (port != STANDARD_TLS_PORT ||
|
||||
ast_strlen_zero(host) || strcmp(host, "10.10.10.10") ||
|
||||
transport != AST_TRANSPORT_TLS) {
|
||||
ast_test_status_update(test, "Test 3: tls host failed. \n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 4, add custom port with tls */
|
||||
sip_parse_host(host4, 1, &host, &port, &transport);
|
||||
if (port != 1234 || ast_strlen_zero(host) ||
|
||||
strcmp(host, "10.10.10.10") ||
|
||||
transport != AST_TRANSPORT_TLS) {
|
||||
ast_test_status_update(test, "Test 4: tls host with custom port failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 5, simple host with custom port */
|
||||
sip_parse_host(host5, 1, &host, &port, &transport);
|
||||
if (port != 1234 || ast_strlen_zero(host) ||
|
||||
strcmp(host, "10.10.10.10") ||
|
||||
transport != AST_TRANSPORT_UDP) {
|
||||
ast_test_status_update(test, "Test 5: simple host with custom port failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 6, expected failure with NULL input */
|
||||
if (!sip_parse_host(NULL, 1, &host, &port, &transport)) {
|
||||
ast_test_status_update(test, "Test 6: expected error on NULL input did not occur.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief Parse the comma-separated nat= option values */
|
||||
void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags)
|
||||
{
|
||||
char *parse, *this;
|
||||
|
||||
if (!(parse = ast_strdupa(value))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since we need to completely override the general settings if we are being called
|
||||
* later for a peer, always set the flags for all options on the mask */
|
||||
ast_set_flag(&mask[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
|
||||
while ((this = strsep(&parse, ","))) {
|
||||
if (ast_false(this)) {
|
||||
ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
break; /* It doesn't make sense to have no + something else */
|
||||
} else if (!strcasecmp(this, "yes")) {
|
||||
ast_log(LOG_WARNING, "nat=yes is deprecated, use nat=force_rport,comedia instead\n");
|
||||
ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
break; /* It doesn't make sense to have yes + something else */
|
||||
} else if (!strcasecmp(this, "force_rport") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
} else if (!strcasecmp(this, "comedia") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
} else if (!strcasecmp(this, "auto_force_rport")) {
|
||||
ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
/* In case someone did something dumb like nat=force_rport,auto_force_rport */
|
||||
ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
} else if (!strcasecmp(this, "auto_comedia")) {
|
||||
ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
/* In case someone did something dumb like nat=comedia,auto_comedia*/
|
||||
ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
#define TEST_FORCE_RPORT 1 << 0
|
||||
#define TEST_COMEDIA 1 << 1
|
||||
#define TEST_AUTO_FORCE_RPORT 1 << 2
|
||||
#define TEST_AUTO_COMEDIA 1 << 3
|
||||
static int match_nat_options(int val, struct ast_flags *flags)
|
||||
{
|
||||
if ((!ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)) != !(val & TEST_FORCE_RPORT)) {
|
||||
return 0;
|
||||
}
|
||||
if (!ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) != !(val & TEST_COMEDIA)) {
|
||||
return 0;
|
||||
}
|
||||
if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT) != !(val & TEST_AUTO_FORCE_RPORT)) {
|
||||
return 0;
|
||||
}
|
||||
if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) != !(val & TEST_AUTO_COMEDIA)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(sip_parse_nat_test)
|
||||
{
|
||||
int i, res = AST_TEST_PASS;
|
||||
struct ast_flags mask[3] = {{0}}, flags[3] = {{0}};
|
||||
struct {
|
||||
const char *str;
|
||||
int i;
|
||||
} options[] = {
|
||||
{ "yes", TEST_FORCE_RPORT | TEST_COMEDIA },
|
||||
{ "no", 0 },
|
||||
{ "force_rport", TEST_FORCE_RPORT },
|
||||
{ "comedia", TEST_COMEDIA },
|
||||
{ "auto_force_rport", TEST_AUTO_FORCE_RPORT },
|
||||
{ "auto_comedia", TEST_AUTO_COMEDIA },
|
||||
{ "force_rport,auto_force_rport", TEST_AUTO_FORCE_RPORT },
|
||||
{ "auto_force_rport,force_rport", TEST_AUTO_FORCE_RPORT },
|
||||
{ "comedia,auto_comedia", TEST_AUTO_COMEDIA },
|
||||
{ "auto_comedia,comedia", TEST_AUTO_COMEDIA },
|
||||
{ "force_rport,comedia", TEST_FORCE_RPORT | TEST_COMEDIA },
|
||||
{ "force_rport,auto_comedia", TEST_FORCE_RPORT | TEST_AUTO_COMEDIA },
|
||||
{ "force_rport,yes,no", TEST_FORCE_RPORT | TEST_COMEDIA },
|
||||
{ "auto_comedia,no,yes", 0 },
|
||||
};
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "sip_parse_nat_test";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "tests sip.conf nat line parsing";
|
||||
info->description =
|
||||
"Tests parsing of various nat line configurations. "
|
||||
"Verifies output matches expected behavior.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(options); i++) {
|
||||
sip_parse_nat_option(options[i].str, mask, flags);
|
||||
if (!match_nat_options(options[i].i, flags)) {
|
||||
ast_test_status_update(test, "Failed nat=%s\n", options[i].str);
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
memset(flags, 0, sizeof(flags));
|
||||
memset(mask, 0, sizeof(mask));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_config_parser_register_tests(void)
|
||||
{
|
||||
AST_TEST_REGISTER(sip_parse_register_line_test);
|
||||
AST_TEST_REGISTER(sip_parse_host_line_test);
|
||||
AST_TEST_REGISTER(sip_parse_nat_test);
|
||||
}
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_config_parser_unregister_tests(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(sip_parse_register_line_test);
|
||||
AST_TEST_UNREGISTER(sip_parse_host_line_test);
|
||||
AST_TEST_UNREGISTER(sip_parse_nat_test);
|
||||
}
|
@ -1,515 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip channel dialplan functions and unit tests
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<info name="CHANNEL" language="en_US" tech="SIP">
|
||||
<enumlist>
|
||||
<enum name="peerip">
|
||||
<para>R/O Get the IP address of the peer.</para>
|
||||
</enum>
|
||||
<enum name="recvip">
|
||||
<para>R/O Get the source IP address of the peer.</para>
|
||||
</enum>
|
||||
<enum name="recvport">
|
||||
<para>R/O Get the source port of the peer.</para>
|
||||
</enum>
|
||||
<enum name="from">
|
||||
<para>R/O Get the URI from the From: header.</para>
|
||||
</enum>
|
||||
<enum name="uri">
|
||||
<para>R/O Get the URI from the Contact: header.</para>
|
||||
</enum>
|
||||
<enum name="ruri">
|
||||
<para>R/O Get the Request-URI from the INVITE header.</para>
|
||||
</enum>
|
||||
<enum name="useragent">
|
||||
<para>R/O Get the useragent.</para>
|
||||
</enum>
|
||||
<enum name="peername">
|
||||
<para>R/O Get the name of the peer.</para>
|
||||
</enum>
|
||||
<enum name="t38passthrough">
|
||||
<para>R/O <literal>1</literal> if T38 is offered or enabled in this channel,
|
||||
otherwise <literal>0</literal></para>
|
||||
</enum>
|
||||
<enum name="rtpqos">
|
||||
<para>R/O Get QOS information about the RTP stream</para>
|
||||
<para> This option takes two additional arguments:</para>
|
||||
<para> Argument 1:</para>
|
||||
<para> <literal>audio</literal> Get data about the audio stream</para>
|
||||
<para> <literal>video</literal> Get data about the video stream</para>
|
||||
<para> <literal>text</literal> Get data about the text stream</para>
|
||||
<para> Argument 2:</para>
|
||||
<para> <literal>local_ssrc</literal> Local SSRC (stream ID)</para>
|
||||
<para> <literal>local_lostpackets</literal> Local lost packets</para>
|
||||
<para> <literal>local_jitter</literal> Local calculated jitter</para>
|
||||
<para> <literal>local_maxjitter</literal> Local calculated jitter (maximum)</para>
|
||||
<para> <literal>local_minjitter</literal> Local calculated jitter (minimum)</para>
|
||||
<para> <literal>local_normdevjitter</literal>Local calculated jitter (normal deviation)</para>
|
||||
<para> <literal>local_stdevjitter</literal> Local calculated jitter (standard deviation)</para>
|
||||
<para> <literal>local_count</literal> Number of received packets</para>
|
||||
<para> <literal>remote_ssrc</literal> Remote SSRC (stream ID)</para>
|
||||
<para> <literal>remote_lostpackets</literal>Remote lost packets</para>
|
||||
<para> <literal>remote_jitter</literal> Remote reported jitter</para>
|
||||
<para> <literal>remote_maxjitter</literal> Remote calculated jitter (maximum)</para>
|
||||
<para> <literal>remote_minjitter</literal> Remote calculated jitter (minimum)</para>
|
||||
<para> <literal>remote_normdevjitter</literal>Remote calculated jitter (normal deviation)</para>
|
||||
<para> <literal>remote_stdevjitter</literal>Remote calculated jitter (standard deviation)</para>
|
||||
<para> <literal>remote_count</literal> Number of transmitted packets</para>
|
||||
<para> <literal>rtt</literal> Round trip time</para>
|
||||
<para> <literal>maxrtt</literal> Round trip time (maximum)</para>
|
||||
<para> <literal>minrtt</literal> Round trip time (minimum)</para>
|
||||
<para> <literal>normdevrtt</literal> Round trip time (normal deviation)</para>
|
||||
<para> <literal>stdevrtt</literal> Round trip time (standard deviation)</para>
|
||||
<para> <literal>all</literal> All statistics (in a form suited to logging,
|
||||
but not for parsing)</para>
|
||||
</enum>
|
||||
<enum name="rtpdest">
|
||||
<para>R/O Get remote RTP destination information.</para>
|
||||
<para> This option takes one additional argument:</para>
|
||||
<para> Argument 1:</para>
|
||||
<para> <literal>audio</literal> Get audio destination</para>
|
||||
<para> <literal>video</literal> Get video destination</para>
|
||||
<para> <literal>text</literal> Get text destination</para>
|
||||
<para> Defaults to <literal>audio</literal> if unspecified.</para>
|
||||
</enum>
|
||||
<enum name="rtpsource">
|
||||
<para>R/O Get source RTP destination information.</para>
|
||||
<para> This option takes one additional argument:</para>
|
||||
<para> Argument 1:</para>
|
||||
<para> <literal>audio</literal> Get audio destination</para>
|
||||
<para> <literal>video</literal> Get video destination</para>
|
||||
<para> <literal>text</literal> Get text destination</para>
|
||||
<para> Defaults to <literal>audio</literal> if unspecified.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/rtp_engine.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/acl.h"
|
||||
|
||||
#include "include/sip.h"
|
||||
#include "include/globals.h"
|
||||
#include "include/dialog.h"
|
||||
#include "include/dialplan_functions.h"
|
||||
#include "include/sip_utils.h"
|
||||
|
||||
|
||||
int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen)
|
||||
{
|
||||
struct sip_pvt *p = ast_channel_tech_pvt(chan);
|
||||
char *parse = ast_strdupa(preparse);
|
||||
int res = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(param);
|
||||
AST_APP_ARG(type);
|
||||
AST_APP_ARG(field);
|
||||
);
|
||||
|
||||
/* Check for zero arguments */
|
||||
if (ast_strlen_zero(parse)) {
|
||||
ast_log(LOG_ERROR, "Cannot call %s without arguments\n", funcname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
/* Sanity check */
|
||||
if (!IS_SIP_TECH(ast_channel_tech(chan))) {
|
||||
ast_log(LOG_ERROR, "Cannot call %s on a non-SIP channel\n", funcname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcasecmp(args.param, "peerip")) {
|
||||
ast_copy_string(buf, ast_sockaddr_isnull(&p->sa) ? "" : ast_sockaddr_stringify_addr(&p->sa), buflen);
|
||||
} else if (!strcasecmp(args.param, "recvip")) {
|
||||
ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_addr(&p->recv), buflen);
|
||||
} else if (!strcasecmp(args.param, "recvport")) {
|
||||
ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_port(&p->recv), buflen);
|
||||
} else if (!strcasecmp(args.param, "from")) {
|
||||
ast_copy_string(buf, p->from, buflen);
|
||||
} else if (!strcasecmp(args.param, "uri")) {
|
||||
ast_copy_string(buf, p->uri, buflen);
|
||||
} else if (!strcasecmp(args.param, "ruri")) {
|
||||
if (p->initreq.data) {
|
||||
char *tmpruri = REQ_OFFSET_TO_STR(&p->initreq, rlpart2);
|
||||
ast_copy_string(buf, tmpruri, buflen);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (!strcasecmp(args.param, "useragent")) {
|
||||
ast_copy_string(buf, p->useragent, buflen);
|
||||
} else if (!strcasecmp(args.param, "peername")) {
|
||||
ast_copy_string(buf, p->peername, buflen);
|
||||
} else if (!strcasecmp(args.param, "t38passthrough")) {
|
||||
ast_copy_string(buf, (p->t38.state == T38_DISABLED) ? "0" : "1", buflen);
|
||||
} else if (!strcasecmp(args.param, "rtpdest")) {
|
||||
struct ast_sockaddr addr;
|
||||
struct ast_rtp_instance *stream;
|
||||
|
||||
if (ast_strlen_zero(args.type))
|
||||
args.type = "audio";
|
||||
|
||||
if (!strcasecmp(args.type, "audio"))
|
||||
stream = p->rtp;
|
||||
else if (!strcasecmp(args.type, "video"))
|
||||
stream = p->vrtp;
|
||||
else if (!strcasecmp(args.type, "text"))
|
||||
stream = p->trtp;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Return 0 to suppress a console warning message */
|
||||
if (!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_rtp_instance_get_remote_address(stream, &addr);
|
||||
snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&addr));
|
||||
} else if (!strcasecmp(args.param, "rtpsource")) {
|
||||
struct ast_sockaddr sa;
|
||||
struct ast_rtp_instance *stream;
|
||||
|
||||
if (ast_strlen_zero(args.type))
|
||||
args.type = "audio";
|
||||
|
||||
if (!strcasecmp(args.type, "audio"))
|
||||
stream = p->rtp;
|
||||
else if (!strcasecmp(args.type, "video"))
|
||||
stream = p->vrtp;
|
||||
else if (!strcasecmp(args.type, "text"))
|
||||
stream = p->trtp;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Return 0 to suppress a console warning message */
|
||||
if (!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_rtp_instance_get_local_address(stream, &sa);
|
||||
|
||||
if (ast_sockaddr_isnull(&sa)) {
|
||||
struct ast_sockaddr dest_sa;
|
||||
ast_rtp_instance_get_remote_address(stream, &dest_sa);
|
||||
ast_ouraddrfor(&dest_sa, &sa);
|
||||
}
|
||||
|
||||
snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&sa));
|
||||
} else if (!strcasecmp(args.param, "rtpqos")) {
|
||||
struct ast_rtp_instance *rtp = NULL;
|
||||
|
||||
if (ast_strlen_zero(args.type)) {
|
||||
args.type = "audio";
|
||||
}
|
||||
|
||||
if (!strcasecmp(args.type, "audio")) {
|
||||
rtp = p->rtp;
|
||||
} else if (!strcasecmp(args.type, "video")) {
|
||||
rtp = p->vrtp;
|
||||
} else if (!strcasecmp(args.type, "text")) {
|
||||
rtp = p->trtp;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.field) || !strcasecmp(args.field, "all")) {
|
||||
char quality_buf[AST_MAX_USER_FIELD];
|
||||
|
||||
if (!ast_rtp_instance_get_quality(rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_copy_string(buf, quality_buf, buflen);
|
||||
return res;
|
||||
} else {
|
||||
struct ast_rtp_instance_stats stats;
|
||||
int i;
|
||||
struct {
|
||||
const char *name;
|
||||
enum { INT, DBL } type;
|
||||
union {
|
||||
unsigned int *i4;
|
||||
double *d8;
|
||||
};
|
||||
} lookup[] = {
|
||||
{ "txcount", INT, { .i4 = &stats.txcount, }, },
|
||||
{ "rxcount", INT, { .i4 = &stats.rxcount, }, },
|
||||
{ "txjitter", DBL, { .d8 = &stats.txjitter, }, },
|
||||
{ "rxjitter", DBL, { .d8 = &stats.rxjitter, }, },
|
||||
{ "remote_maxjitter", DBL, { .d8 = &stats.remote_maxjitter, }, },
|
||||
{ "remote_minjitter", DBL, { .d8 = &stats.remote_minjitter, }, },
|
||||
{ "remote_normdevjitter", DBL, { .d8 = &stats.remote_normdevjitter, }, },
|
||||
{ "remote_stdevjitter", DBL, { .d8 = &stats.remote_stdevjitter, }, },
|
||||
{ "local_maxjitter", DBL, { .d8 = &stats.local_maxjitter, }, },
|
||||
{ "local_minjitter", DBL, { .d8 = &stats.local_minjitter, }, },
|
||||
{ "local_normdevjitter", DBL, { .d8 = &stats.local_normdevjitter, }, },
|
||||
{ "local_stdevjitter", DBL, { .d8 = &stats.local_stdevjitter, }, },
|
||||
{ "txploss", INT, { .i4 = &stats.txploss, }, },
|
||||
{ "rxploss", INT, { .i4 = &stats.rxploss, }, },
|
||||
{ "remote_maxrxploss", DBL, { .d8 = &stats.remote_maxrxploss, }, },
|
||||
{ "remote_minrxploss", DBL, { .d8 = &stats.remote_minrxploss, }, },
|
||||
{ "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
|
||||
{ "remote_stdevrxploss", DBL, { .d8 = &stats.remote_stdevrxploss, }, },
|
||||
{ "local_maxrxploss", DBL, { .d8 = &stats.local_maxrxploss, }, },
|
||||
{ "local_minrxploss", DBL, { .d8 = &stats.local_minrxploss, }, },
|
||||
{ "local_normdevrxploss", DBL, { .d8 = &stats.local_normdevrxploss, }, },
|
||||
{ "local_stdevrxploss", DBL, { .d8 = &stats.local_stdevrxploss, }, },
|
||||
{ "rtt", DBL, { .d8 = &stats.rtt, }, },
|
||||
{ "maxrtt", DBL, { .d8 = &stats.maxrtt, }, },
|
||||
{ "minrtt", DBL, { .d8 = &stats.minrtt, }, },
|
||||
{ "normdevrtt", DBL, { .d8 = &stats.normdevrtt, }, },
|
||||
{ "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
|
||||
{ "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
|
||||
{ "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
|
||||
if (!strcasecmp(args.field, lookup[i].name)) {
|
||||
if (lookup[i].type == INT) {
|
||||
snprintf(buf, buflen, "%u", *lookup[i].i4);
|
||||
} else {
|
||||
snprintf(buf, buflen, "%f", *lookup[i].d8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ast_log(LOG_WARNING, "Unrecognized argument '%s' to %s\n", preparse, funcname);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strcasecmp(args.param, "secure_signaling")) {
|
||||
snprintf(buf, buflen, "%s", p->socket.type == AST_TRANSPORT_TLS ? "1" : "");
|
||||
} else if (!strcasecmp(args.param, "secure_media")) {
|
||||
snprintf(buf, buflen, "%s", p->srtp ? "1" : "");
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
static int test_sip_rtpqos_1_new(struct ast_rtp_instance *instance, struct ast_sched_context *sched, struct ast_sockaddr *addr, void *data)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
ast_rtp_instance_set_data(instance, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sip_rtpqos_1_destroy(struct ast_rtp_instance *instance)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_frame *test_sip_rtpqos_1_read(struct ast_rtp_instance *instance, int rtcp)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
static int test_sip_rtpqos_1_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sip_rtpqos_1_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
|
||||
{
|
||||
struct ast_rtp_instance_stats *s = ast_rtp_instance_get_data(instance);
|
||||
memcpy(stats, s, sizeof(*stats));
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(test_sip_rtpqos_1)
|
||||
{
|
||||
int i, res = AST_TEST_PASS;
|
||||
static struct ast_rtp_engine test_engine = {
|
||||
.name = "test",
|
||||
.new = test_sip_rtpqos_1_new,
|
||||
.destroy = test_sip_rtpqos_1_destroy,
|
||||
.read = test_sip_rtpqos_1_read,
|
||||
.write = test_sip_rtpqos_1_write,
|
||||
.get_stat = test_sip_rtpqos_1_get_stat,
|
||||
};
|
||||
struct ast_sockaddr sa = { {0, } };
|
||||
struct ast_rtp_instance_stats mine = { 0, };
|
||||
struct sip_pvt *p = NULL;
|
||||
struct ast_channel *chan = NULL;
|
||||
struct ast_str *varstr = NULL, *buffer = NULL;
|
||||
struct {
|
||||
const char *name;
|
||||
enum { INT, DBL } type;
|
||||
union {
|
||||
unsigned int *i4;
|
||||
double *d8;
|
||||
};
|
||||
} lookup[] = {
|
||||
{ "txcount", INT, { .i4 = &mine.txcount, }, },
|
||||
{ "rxcount", INT, { .i4 = &mine.rxcount, }, },
|
||||
{ "txjitter", DBL, { .d8 = &mine.txjitter, }, },
|
||||
{ "rxjitter", DBL, { .d8 = &mine.rxjitter, }, },
|
||||
{ "remote_maxjitter", DBL, { .d8 = &mine.remote_maxjitter, }, },
|
||||
{ "remote_minjitter", DBL, { .d8 = &mine.remote_minjitter, }, },
|
||||
{ "remote_normdevjitter", DBL, { .d8 = &mine.remote_normdevjitter, }, },
|
||||
{ "remote_stdevjitter", DBL, { .d8 = &mine.remote_stdevjitter, }, },
|
||||
{ "local_maxjitter", DBL, { .d8 = &mine.local_maxjitter, }, },
|
||||
{ "local_minjitter", DBL, { .d8 = &mine.local_minjitter, }, },
|
||||
{ "local_normdevjitter", DBL, { .d8 = &mine.local_normdevjitter, }, },
|
||||
{ "local_stdevjitter", DBL, { .d8 = &mine.local_stdevjitter, }, },
|
||||
{ "txploss", INT, { .i4 = &mine.txploss, }, },
|
||||
{ "rxploss", INT, { .i4 = &mine.rxploss, }, },
|
||||
{ "remote_maxrxploss", DBL, { .d8 = &mine.remote_maxrxploss, }, },
|
||||
{ "remote_minrxploss", DBL, { .d8 = &mine.remote_minrxploss, }, },
|
||||
{ "remote_normdevrxploss", DBL, { .d8 = &mine.remote_normdevrxploss, }, },
|
||||
{ "remote_stdevrxploss", DBL, { .d8 = &mine.remote_stdevrxploss, }, },
|
||||
{ "local_maxrxploss", DBL, { .d8 = &mine.local_maxrxploss, }, },
|
||||
{ "local_minrxploss", DBL, { .d8 = &mine.local_minrxploss, }, },
|
||||
{ "local_normdevrxploss", DBL, { .d8 = &mine.local_normdevrxploss, }, },
|
||||
{ "local_stdevrxploss", DBL, { .d8 = &mine.local_stdevrxploss, }, },
|
||||
{ "rtt", DBL, { .d8 = &mine.rtt, }, },
|
||||
{ "maxrtt", DBL, { .d8 = &mine.maxrtt, }, },
|
||||
{ "minrtt", DBL, { .d8 = &mine.minrtt, }, },
|
||||
{ "normdevrtt", DBL, { .d8 = &mine.normdevrtt, }, },
|
||||
{ "stdevrtt", DBL, { .d8 = &mine.stdevrtt, }, },
|
||||
{ "local_ssrc", INT, { .i4 = &mine.local_ssrc, }, },
|
||||
{ "remote_ssrc", INT, { .i4 = &mine.remote_ssrc, }, },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "test_sip_rtpqos";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "Test retrieval of SIP RTP QOS stats";
|
||||
info->description =
|
||||
"Verify values in the RTP instance structure can be accessed through the dialplan.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
ast_rtp_engine_register(&test_engine);
|
||||
/* Have to associate this with a SIP pvt and an ast_channel */
|
||||
if (!(p = sip_alloc(0, NULL, 0, SIP_NOTIFY, NULL, 0))) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(p->rtp = ast_rtp_instance_new("test", sched, &bindaddr, &mine))) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
ast_rtp_instance_set_remote_address(p->rtp, &sa);
|
||||
if (!(chan = ast_dummy_channel_alloc())) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
ast_channel_tech_set(chan, &sip_tech);
|
||||
ast_channel_tech_pvt_set(chan, dialog_ref(p, "Give the owner channel a reference to the dialog"));
|
||||
p->owner = chan;
|
||||
|
||||
varstr = ast_str_create(16);
|
||||
buffer = ast_str_create(16);
|
||||
if (!varstr || !buffer) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Populate "mine" with values, then retrieve them with the CHANNEL dialplan function */
|
||||
for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
|
||||
ast_str_set(&varstr, 0, "${CHANNEL(rtpqos,audio,%s)}", lookup[i].name);
|
||||
if (lookup[i].type == INT) {
|
||||
int j;
|
||||
char cmpstr[256];
|
||||
for (j = 1; j < 25; j++) {
|
||||
*lookup[i].i4 = j;
|
||||
ast_str_substitute_variables(&buffer, 0, chan, ast_str_buffer(varstr));
|
||||
snprintf(cmpstr, sizeof(cmpstr), "%d", j);
|
||||
if (strcmp(cmpstr, ast_str_buffer(buffer))) {
|
||||
res = AST_TEST_FAIL;
|
||||
ast_test_status_update(test, "%s != %s != %s\n", ast_str_buffer(varstr), cmpstr, ast_str_buffer(buffer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double j, cmpdbl = 0.0;
|
||||
for (j = 1.0; j < 10.0; j += 0.3) {
|
||||
*lookup[i].d8 = j;
|
||||
ast_str_substitute_variables(&buffer, 0, chan, ast_str_buffer(varstr));
|
||||
if (sscanf(ast_str_buffer(buffer), "%lf", &cmpdbl) != 1 || fabs(j - cmpdbl) > .05) {
|
||||
res = AST_TEST_FAIL;
|
||||
ast_test_status_update(test, "%s != %f != %s\n", ast_str_buffer(varstr), j, ast_str_buffer(buffer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ast_free(varstr);
|
||||
ast_free(buffer);
|
||||
|
||||
/* This unlink and unref will take care of destroying the channel, RTP instance, and SIP pvt */
|
||||
if (p) {
|
||||
dialog_unlink_all(p);
|
||||
dialog_unref(p, "Destroy test object");
|
||||
}
|
||||
if (chan) {
|
||||
ast_channel_unref(chan);
|
||||
}
|
||||
ast_rtp_engine_unregister(&test_engine);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_dialplan_function_register_tests(void)
|
||||
{
|
||||
AST_TEST_REGISTER(test_sip_rtpqos_1);
|
||||
}
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_dialplan_function_unregister_tests(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(test_sip_rtpqos_1);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip.conf parser header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_CONF_PARSE_H
|
||||
#define _SIP_CONF_PARSE_H
|
||||
|
||||
/*!
|
||||
* \brief Parse register=> line in sip.conf
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno);
|
||||
|
||||
/*!
|
||||
* \brief parses a config line for a host with a transport
|
||||
*
|
||||
* An example input would be:
|
||||
* <code>tls://www.google.com:8056</code>
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport);
|
||||
|
||||
/*! \brief Parse the comma-separated nat= option values
|
||||
* \param value The comma-separated value
|
||||
* \param mask An array of ast_flags that will be set by this function
|
||||
* and used as a mask for copying the flags later
|
||||
* \param flags An array of ast_flags that will be set by this function
|
||||
*
|
||||
* \note The nat-related values in both mask and flags are assumed to empty. This function
|
||||
* will treat the first "yes" or "no" value in a list of values as overriding all other values
|
||||
* and will stop parsing. Auto values will override their non-auto counterparts.
|
||||
*/
|
||||
void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags);
|
||||
|
||||
/*!
|
||||
* \brief register config parsing tests
|
||||
*/
|
||||
void sip_config_parser_register_tests(void);
|
||||
|
||||
/*!
|
||||
* \brief unregister config parsing tests
|
||||
*/
|
||||
void sip_config_parser_unregister_tests(void);
|
||||
|
||||
#endif
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip dialog management header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_DIALOG_H
|
||||
#define _SIP_DIALOG_H
|
||||
|
||||
/*! \brief
|
||||
* when we create or delete references, make sure to use these
|
||||
* functions so we keep track of the refcounts.
|
||||
* To simplify the code, we allow a NULL to be passed to dialog_unref().
|
||||
*/
|
||||
#define dialog_ref(dialog, tag) ao2_t_bump(dialog, tag)
|
||||
#define dialog_unref(dialog, tag) ({ ao2_t_cleanup(dialog, tag); (NULL); })
|
||||
|
||||
struct sip_pvt *__sip_alloc(ast_string_field callid, struct ast_sockaddr *sin,
|
||||
int useglobal_nat, const int intended_method, struct sip_request *req, ast_callid logger_callid,
|
||||
const char *file, int line, const char *func);
|
||||
|
||||
#define sip_alloc(callid, addr, useglobal_nat, intended_method, req, logger_callid) \
|
||||
__sip_alloc(callid, addr, useglobal_nat, intended_method, req, logger_callid, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
/*!
|
||||
* \brief Schedule final destruction of SIP dialog.
|
||||
*
|
||||
* \note This cannot be canceled.
|
||||
*
|
||||
* \details
|
||||
* This function is used to keep a dialog around for a period of time in order
|
||||
* to properly respond to any retransmits.
|
||||
*/
|
||||
void sip_scheddestroy_final(struct sip_pvt *p, int ms);
|
||||
|
||||
/*! \brief Schedule destruction of SIP dialog */
|
||||
void sip_scheddestroy(struct sip_pvt *p, int ms);
|
||||
|
||||
/*! \brief Cancel destruction of SIP dialog. */
|
||||
void sip_cancel_destroy(struct sip_pvt *pvt);
|
||||
|
||||
/*!
|
||||
* \brief Unlink a dialog from the dialogs container, as well as any other places
|
||||
* that it may be currently stored.
|
||||
*
|
||||
* \note A reference to the dialog must be held before calling
|
||||
* this function, and this function does not release that
|
||||
* reference.
|
||||
*
|
||||
* \note The dialog must not be locked when called.
|
||||
*/
|
||||
void dialog_unlink_all(struct sip_pvt *dialog);
|
||||
|
||||
/*! \brief Acknowledges receipt of a packet and stops retransmission
|
||||
* called with p locked*/
|
||||
int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod);
|
||||
|
||||
/*! \brief Pretend to ack all packets
|
||||
* called with p locked */
|
||||
void __sip_pretend_ack(struct sip_pvt *p);
|
||||
|
||||
/*! \brief Acks receipt of packet, keep it around (used for provisional responses) */
|
||||
int __sip_semi_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod);
|
||||
|
||||
#endif /* defined(_SIP_DIALOG_H) */
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief SIP dialplan functions header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_DIALPLAN_FUNCTIONS_H
|
||||
#define _SIP_DIALPLAN_FUNCTIONS_H
|
||||
|
||||
/*!
|
||||
* \brief Channel read dialplan function for SIP
|
||||
*/
|
||||
int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
|
||||
|
||||
/*!
|
||||
* \brief register dialplan function tests
|
||||
*/
|
||||
void sip_dialplan_function_register_tests(void);
|
||||
/*!
|
||||
* \brief unregister dialplan function tests
|
||||
*/
|
||||
void sip_dialplan_function_unregister_tests(void);
|
||||
|
||||
#endif /* !defined(_SIP_DIALPLAN_FUNCTIONS_H) */
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip global declaration header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_GLOBALS_H
|
||||
#define _SIP_GLOBALS_H
|
||||
|
||||
extern struct ast_sockaddr bindaddr; /*!< UDP: The address we bind to */
|
||||
extern struct ast_sched_context *sched; /*!< The scheduling context */
|
||||
|
||||
/*! \brief Definition of this channel for PBX channel registration */
|
||||
extern struct ast_channel_tech sip_tech;
|
||||
|
||||
/*! \brief This version of the sip channel tech has no send_digit_begin
|
||||
* callback so that the core knows that the channel does not want
|
||||
* DTMF BEGIN frames.
|
||||
* The struct is initialized just before registering the channel driver,
|
||||
* and is for use with channels using SIP INFO DTMF.
|
||||
*/
|
||||
extern struct ast_channel_tech sip_tech_info;
|
||||
|
||||
#endif /* !defined(SIP_GLOBALS_H) */
|
@ -1,250 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip request response parser header file
|
||||
*/
|
||||
|
||||
#ifndef _SIP_REQRESP_H
|
||||
#define _SIP_REQRESP_H
|
||||
|
||||
/*! \brief uri parameters */
|
||||
struct uriparams {
|
||||
char *transport;
|
||||
char *user;
|
||||
char *method;
|
||||
char *ttl;
|
||||
char *maddr;
|
||||
int lr;
|
||||
};
|
||||
|
||||
struct contact {
|
||||
AST_LIST_ENTRY(contact) list;
|
||||
char *name;
|
||||
char *user;
|
||||
char *pass;
|
||||
char *hostport;
|
||||
struct uriparams params;
|
||||
char *headers;
|
||||
char *expires;
|
||||
char *q;
|
||||
};
|
||||
|
||||
AST_LIST_HEAD_NOLOCK(contactliststruct, contact);
|
||||
|
||||
/*!
|
||||
* \brief parses a URI in its components.
|
||||
*
|
||||
* \note
|
||||
* - Multiple scheme's can be specified ',' delimited. ex: "sip:,sips:"
|
||||
* - If a component is not requested, do not split around it. This means
|
||||
* that if we don't have domain, we cannot split name:pass.
|
||||
* - It is safe to call with ret_name, pass, hostport pointing all to
|
||||
* the same place.
|
||||
* - If no secret parameter is provided, ret_name will return with both
|
||||
* parts, user:secret.
|
||||
* - If the URI contains a port number, hostport will return with both
|
||||
* parts, host:port.
|
||||
* - This function overwrites the URI string.
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on error.
|
||||
*
|
||||
* \verbatim
|
||||
* general form we are expecting is sip:user:password;user-parameters@host:port;uri-parameters?headers
|
||||
* \endverbatim
|
||||
*/
|
||||
int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass,
|
||||
char **hostport, char **transport);
|
||||
|
||||
/*!
|
||||
* \brief parses a URI in to all of its components and any trailing residue
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on error.
|
||||
*
|
||||
*/
|
||||
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
|
||||
char **hostport, struct uriparams *params, char **headers,
|
||||
char **residue);
|
||||
|
||||
/*!
|
||||
* \brief Get caller id name from SIP headers, copy into output buffer
|
||||
*
|
||||
* \return input string pointer placed after display-name field if possible
|
||||
*/
|
||||
const char *get_calleridname(const char *input, char *output, size_t outputsize);
|
||||
|
||||
/*!
|
||||
* \brief Get name and number from sip header
|
||||
*
|
||||
* \note name and number point to malloced memory on return and must be
|
||||
* freed. If name or number is not found, they will be returned as NULL.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int get_name_and_number(const char *hdr, char **name, char **number);
|
||||
|
||||
/*! \brief Pick out text in brackets from character string
|
||||
* \return pointer to terminated stripped string
|
||||
* \param tmp input string that will be modified
|
||||
*
|
||||
* Examples:
|
||||
* \verbatim
|
||||
* "foo" <bar> valid input, returns bar
|
||||
* foo returns the whole string
|
||||
* < "foo ... > returns the string between brackets
|
||||
* < "foo... bogus (missing closing bracket), returns the whole string
|
||||
* \endverbatim
|
||||
*/
|
||||
char *get_in_brackets(char *tmp);
|
||||
|
||||
/*! \brief Get text in brackets on a const without copy
|
||||
*
|
||||
* \param src String to search
|
||||
* \param[out] start Set to first character inside left bracket.
|
||||
* \param[out] length Set to lenght of string inside brackets
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
* \retval 1 no brackets so got all
|
||||
*/
|
||||
int get_in_brackets_const(const char *src,const char **start,int *length);
|
||||
|
||||
/*! \brief Get text in brackets and any trailing residue
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
* \retval 1 no brackets so got all
|
||||
*/
|
||||
int get_in_brackets_full(char *tmp, char **out, char **residue);
|
||||
|
||||
/*! \brief Parse the ABNF structure
|
||||
* name-andor-addr = name-addr / addr-spec
|
||||
* into its components and return any trailing message-header parameters
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int parse_name_andor_addr(char *uri, const char *scheme, char **name,
|
||||
char **user, char **pass, char **domain,
|
||||
struct uriparams *params, char **headers,
|
||||
char **residue);
|
||||
|
||||
/*! \brief Parse all contact header contacts
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
* \retval 1 all contacts (star)
|
||||
*/
|
||||
|
||||
int get_comma(char *parse, char **out);
|
||||
|
||||
int parse_contact_header(char *contactheader, struct contactliststruct *contactlist);
|
||||
|
||||
/*!
|
||||
* \brief register request parsing tests
|
||||
*/
|
||||
void sip_request_parser_register_tests(void);
|
||||
|
||||
/*!
|
||||
* \brief unregister request parsing tests
|
||||
*/
|
||||
void sip_request_parser_unregister_tests(void);
|
||||
|
||||
/*!
|
||||
* \brief Parse supported header in incoming packet
|
||||
*
|
||||
* \details This function parses through the options parameters and
|
||||
* builds a bit field representing all the SIP options in that field. When an
|
||||
* item is found that is not supported, it is copied to the unsupported
|
||||
* out buffer.
|
||||
*
|
||||
* \param options list
|
||||
* \param[in,out] unsupported buffer (optional)
|
||||
* \param[in,out] unsupported_len buffer length
|
||||
*
|
||||
* \note Because this function can be called multiple times, it will append
|
||||
* whatever options are specified in \c options to \c unsupported. Callers
|
||||
* of this function should make sure the unsupported buffer is clear before
|
||||
* calling this function.
|
||||
*/
|
||||
unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len);
|
||||
|
||||
/*!
|
||||
* \brief Compare two URIs as described in RFC 3261 Section 19.1.4
|
||||
*
|
||||
* \param input1 First URI
|
||||
* \param input2 Second URI
|
||||
* \retval 0 URIs match
|
||||
* \retval nonzero URIs do not match or one or both is malformed
|
||||
*/
|
||||
int sip_uri_cmp(const char *input1, const char *input2);
|
||||
|
||||
/*!
|
||||
* \brief initialize request and response parser data
|
||||
*
|
||||
* \retval 0 Success
|
||||
* \retval -1 Failure
|
||||
*/
|
||||
int sip_reqresp_parser_init(void);
|
||||
|
||||
/*!
|
||||
* \brief Free resources used by request and response parser
|
||||
*/
|
||||
void sip_reqresp_parser_exit(void);
|
||||
|
||||
/*!
|
||||
* \brief Parse a Via header
|
||||
*
|
||||
* This function parses the Via header and processes it according to section
|
||||
* 18.2 of RFC 3261 and RFC 3581. Since we don't have a transport layer, we
|
||||
* only care about the maddr and ttl parms. The received and rport params are
|
||||
* not parsed.
|
||||
*
|
||||
* \note This function fails to parse some odd combinations of SWS in parameter
|
||||
* lists.
|
||||
*
|
||||
* \code
|
||||
* VIA syntax. RFC 3261 section 25.1
|
||||
* Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
|
||||
* via-parm = sent-protocol LWS sent-by *( SEMI via-params )
|
||||
* via-params = via-ttl / via-maddr
|
||||
* / via-received / via-branch
|
||||
* / via-extension
|
||||
* via-ttl = "ttl" EQUAL ttl
|
||||
* via-maddr = "maddr" EQUAL host
|
||||
* via-received = "received" EQUAL (IPv4address / IPv6address)
|
||||
* via-branch = "branch" EQUAL token
|
||||
* via-extension = generic-param
|
||||
* sent-protocol = protocol-name SLASH protocol-version
|
||||
* SLASH transport
|
||||
* protocol-name = "SIP" / token
|
||||
* protocol-version = token
|
||||
* transport = "UDP" / "TCP" / "TLS" / "SCTP"
|
||||
* / other-transport
|
||||
* sent-by = host [ COLON port ]
|
||||
* ttl = 1*3DIGIT ; 0 to 255
|
||||
* \endcode
|
||||
*/
|
||||
struct sip_via *parse_via(const char *header);
|
||||
|
||||
/*!
|
||||
* \brief Free parsed Via data.
|
||||
*/
|
||||
void free_via(struct sip_via *v);
|
||||
|
||||
#endif
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip_route header file
|
||||
*/
|
||||
|
||||
#ifndef _SIP_ROUTE_H
|
||||
#define _SIP_ROUTE_H
|
||||
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/strings.h"
|
||||
|
||||
/*!
|
||||
* \brief Opaque storage of a sip route hop
|
||||
*/
|
||||
struct sip_route_hop;
|
||||
|
||||
/*!
|
||||
* \internal \brief Internal enum to remember last calculated
|
||||
*/
|
||||
enum sip_route_type {
|
||||
route_loose = 0, /*!< The first hop contains ;lr or does not exist */
|
||||
route_strict, /*!< The first hop exists and does not contain ;lr */
|
||||
route_invalidated, /*!< strict/loose routing needs to be rechecked */
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Structure to store route information
|
||||
*
|
||||
* \note This must be zero-filled on allocation
|
||||
*/
|
||||
struct sip_route {
|
||||
AST_LIST_HEAD_NOLOCK(, sip_route_hop) list;
|
||||
enum sip_route_type type;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Add a new hop to the route
|
||||
*
|
||||
* \param route Route
|
||||
* \param uri Address of this hop
|
||||
* \param len Length of hop not including null terminator
|
||||
* \param inserthead If true then inserted the new route to the top of the list
|
||||
*
|
||||
* \return Pointer to null terminated copy of URI on success
|
||||
* \retval NULL on error
|
||||
*/
|
||||
const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead);
|
||||
|
||||
/*!
|
||||
* \brief Add routes from header
|
||||
*
|
||||
* \note This procedure is for headers that require use of \<brackets\>.
|
||||
*/
|
||||
void sip_route_process_header(struct sip_route *route, const char *header, int inserthead);
|
||||
|
||||
/*!
|
||||
* \brief copy route-set
|
||||
*/
|
||||
void sip_route_copy(struct sip_route *dst, const struct sip_route *src);
|
||||
|
||||
/*!
|
||||
* \brief Free all routes in the list
|
||||
*/
|
||||
void sip_route_clear(struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Verbose dump of all hops for debugging
|
||||
*/
|
||||
void sip_route_dump(const struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Make the comma separated list of route hops
|
||||
*
|
||||
* \param route Source of route list
|
||||
* \param formatcli Add's space after comma's, print's N/A if list is empty.
|
||||
* \param skip Number of hops to skip
|
||||
*
|
||||
* \return an allocated struct ast_str on success
|
||||
* \retval NULL on failure
|
||||
*/
|
||||
struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
|
||||
/*!
|
||||
* \brief Check if the route is strict
|
||||
*
|
||||
* \note The result is cached in route->type
|
||||
*/
|
||||
int sip_route_is_strict(struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Get the URI of the route's first hop
|
||||
*/
|
||||
const char *sip_route_first_uri(const struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Check if route has no URI's
|
||||
*/
|
||||
#define sip_route_empty(route) AST_LIST_EMPTY(&(route)->list)
|
||||
|
||||
#endif
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2011, Digium, Inc.
|
||||
*
|
||||
* Michael L. Young <elgueromexicano@gmail.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Generate security events in the SIP channel
|
||||
*
|
||||
* \author Michael L. Young <elgueromexicano@gmail.com>
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_SECURITY_EVENTS_H
|
||||
#define _SIP_SECURITY_EVENTS_H
|
||||
|
||||
void sip_report_invalid_peer(const struct sip_pvt *p);
|
||||
void sip_report_failed_acl(const struct sip_pvt *p, const char *aclname);
|
||||
void sip_report_inval_password(const struct sip_pvt *p, const char *responsechallenge, const char *responsehash);
|
||||
void sip_report_auth_success(const struct sip_pvt *p, uint32_t using_password);
|
||||
void sip_report_session_limit(const struct sip_pvt *p);
|
||||
void sip_report_failed_challenge_response(const struct sip_pvt *p, const char *response, const char *expected_response);
|
||||
void sip_report_chal_sent(const struct sip_pvt *p);
|
||||
void sip_report_inval_transport(const struct sip_pvt *p, const char *transport);
|
||||
void sip_digest_parser(char *c, struct digestkeys *keys);
|
||||
int sip_report_security_event(const char *peer, struct ast_sockaddr *addr, const struct sip_pvt *p,
|
||||
const struct sip_request *req, const int res);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip utils header file
|
||||
*/
|
||||
|
||||
#ifndef _SIP_UTILS_H
|
||||
#define _SIP_UTILS_H
|
||||
|
||||
/* wrapper macro to tell whether t points to one of the sip_tech descriptors */
|
||||
#define IS_SIP_TECH(t) ((t) == &sip_tech || (t) == &sip_tech_info)
|
||||
|
||||
/*!
|
||||
* \brief converts ascii port to int representation.
|
||||
*
|
||||
* \arg pt[in] string that contains a port.
|
||||
* \arg standard[in] port to return in case the port string input is NULL
|
||||
* or if there is a parsing error.
|
||||
*
|
||||
* \return An integer port representation.
|
||||
*/
|
||||
unsigned int port_str2int(const char *pt, unsigned int standard);
|
||||
|
||||
/*! \brief Locate closing quote in a string, skipping escaped quotes.
|
||||
* optionally with a limit on the search.
|
||||
* start must be past the first quote.
|
||||
*/
|
||||
const char *find_closing_quote(const char *start, const char *lim);
|
||||
|
||||
|
||||
/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
|
||||
int hangup_sip2cause(int cause);
|
||||
|
||||
/*! \brief Convert Asterisk hangup causes to SIP codes
|
||||
\verbatim
|
||||
Possible values from causes.h
|
||||
AST_CAUSE_NOTDEFINED AST_CAUSE_NORMAL AST_CAUSE_BUSY
|
||||
AST_CAUSE_FAILURE AST_CAUSE_CONGESTION AST_CAUSE_UNALLOCATED
|
||||
|
||||
In addition to these, a lot of PRI codes is defined in causes.h
|
||||
...should we take care of them too ?
|
||||
|
||||
Quote RFC 3398
|
||||
|
||||
ISUP Cause value SIP response
|
||||
---------------- ------------
|
||||
1 unallocated number 404 Not Found
|
||||
2 no route to network 404 Not found
|
||||
3 no route to destination 404 Not found
|
||||
16 normal call clearing --- (*)
|
||||
17 user busy 486 Busy here
|
||||
18 no user responding 408 Request Timeout
|
||||
19 no answer from the user 480 Temporarily unavailable
|
||||
20 subscriber absent 480 Temporarily unavailable
|
||||
21 call rejected 403 Forbidden (+)
|
||||
22 number changed (w/o diagnostic) 410 Gone
|
||||
22 number changed (w/ diagnostic) 301 Moved Permanently
|
||||
23 redirection to new destination 410 Gone
|
||||
26 non-selected user clearing 404 Not Found (=)
|
||||
27 destination out of order 502 Bad Gateway
|
||||
28 address incomplete 484 Address incomplete
|
||||
29 facility rejected 501 Not implemented
|
||||
31 normal unspecified 480 Temporarily unavailable
|
||||
\endverbatim
|
||||
*/
|
||||
const char *hangup_cause2sip(int cause);
|
||||
|
||||
/*! \brief Return a string describing the force_rport value for the given flags */
|
||||
const char *force_rport_string(struct ast_flags *flags);
|
||||
|
||||
/*! \brief Return a string describing the comedia value for the given flags */
|
||||
const char *comedia_string(struct ast_flags *flags);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip_route functions
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
#include "include/route.h"
|
||||
#include "include/reqresp_parser.h"
|
||||
|
||||
/*!
|
||||
* \brief Traverse route hops
|
||||
*/
|
||||
#define sip_route_traverse(route,elem) AST_LIST_TRAVERSE(&(route)->list, elem, list)
|
||||
#define sip_route_first(route) AST_LIST_FIRST(&(route)->list)
|
||||
|
||||
/*!
|
||||
* \brief Structure to save a route hop
|
||||
*/
|
||||
struct sip_route_hop {
|
||||
AST_LIST_ENTRY(sip_route_hop) list;
|
||||
char uri[0];
|
||||
};
|
||||
|
||||
const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
|
||||
if (!uri || len < 1 || uri[0] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Expand len to include null terminator */
|
||||
len++;
|
||||
|
||||
/* ast_calloc is not needed because all fields are initialized in this block */
|
||||
hop = ast_malloc(sizeof(struct sip_route_hop) + len);
|
||||
if (!hop) {
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(hop->uri, uri, len);
|
||||
|
||||
if (inserthead) {
|
||||
AST_LIST_INSERT_HEAD(&route->list, hop, list);
|
||||
route->type = route_invalidated;
|
||||
} else {
|
||||
if (sip_route_empty(route)) {
|
||||
route->type = route_invalidated;
|
||||
}
|
||||
AST_LIST_INSERT_TAIL(&route->list, hop, list);
|
||||
hop->list.next = NULL;
|
||||
}
|
||||
|
||||
return hop->uri;
|
||||
}
|
||||
|
||||
void sip_route_process_header(struct sip_route *route, const char *header, int inserthead)
|
||||
{
|
||||
const char *hop;
|
||||
int len = 0;
|
||||
const char *uri;
|
||||
|
||||
if (!route) {
|
||||
ast_log(LOG_ERROR, "sip_route_process_header requires non-null route");
|
||||
ast_do_crash();
|
||||
return;
|
||||
}
|
||||
|
||||
while (!get_in_brackets_const(header, &uri, &len)) {
|
||||
header = strchr(header, ',');
|
||||
if (header >= uri && header <= (uri + len)) {
|
||||
/* comma inside brackets */
|
||||
const char *next_br = strchr(header, '<');
|
||||
if (next_br && next_br <= (uri + len)) {
|
||||
header++;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((hop = sip_route_add(route, uri, len, inserthead))) {
|
||||
ast_debug(2, "sip_route_process_header: <%s>\n", hop);
|
||||
}
|
||||
header = strchr(uri + len + 1, ',');
|
||||
if (header == NULL) {
|
||||
/* No more field-values, we're done with this header */
|
||||
break;
|
||||
}
|
||||
/* Advance past comma */
|
||||
header++;
|
||||
}
|
||||
}
|
||||
|
||||
void sip_route_copy(struct sip_route *dst, const struct sip_route *src)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
|
||||
/* make sure dst is empty */
|
||||
sip_route_clear(dst);
|
||||
|
||||
sip_route_traverse(src, hop) {
|
||||
const char *uri = sip_route_add(dst, hop->uri, strlen(hop->uri), 0);
|
||||
if (uri) {
|
||||
ast_debug(2, "sip_route_copy: copied hop: <%s>\n", uri);
|
||||
}
|
||||
}
|
||||
|
||||
dst->type = src->type;
|
||||
}
|
||||
|
||||
void sip_route_clear(struct sip_route *route)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
|
||||
while ((hop = AST_LIST_REMOVE_HEAD(&route->list, list))) {
|
||||
ast_free(hop);
|
||||
}
|
||||
|
||||
route->type = route_loose;
|
||||
}
|
||||
|
||||
void sip_route_dump(const struct sip_route *route)
|
||||
{
|
||||
if (sip_route_empty(route)) {
|
||||
ast_verbose("sip_route_dump: no route/path\n");
|
||||
} else {
|
||||
struct sip_route_hop *hop;
|
||||
sip_route_traverse(route, hop) {
|
||||
ast_verbose("sip_route_dump: route/path hop: <%s>\n", hop->uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
const char *comma;
|
||||
struct ast_str *buf;
|
||||
int i = 0 - skip;
|
||||
|
||||
buf = ast_str_create(64);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
comma = formatcli ? ", " : ",";
|
||||
|
||||
sip_route_traverse(route, hop) {
|
||||
if (i >= 0) {
|
||||
ast_str_append(&buf, 0, "%s<%s>", i ? comma : "", hop->uri);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (formatcli && i <= 0) {
|
||||
ast_str_append(&buf, 0, "N/A");
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int sip_route_is_strict(struct sip_route *route)
|
||||
{
|
||||
if (!route) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (route->type == route_invalidated) {
|
||||
struct sip_route_hop *hop = sip_route_first(route);
|
||||
int ret = hop && (strstr(hop->uri, ";lr") == NULL);
|
||||
route->type = ret ? route_strict : route_loose;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (route->type == route_strict) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *sip_route_first_uri(const struct sip_route *route)
|
||||
{
|
||||
struct sip_route_hop *hop = sip_route_first(route);
|
||||
return hop ? hop->uri : NULL;
|
||||
}
|
@ -1,358 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012, Digium, Inc.
|
||||
*
|
||||
* Michael L. Young <elgueromexicano@gmail.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Generate security events in the SIP channel
|
||||
*
|
||||
* \author Michael L. Young <elgueromexicano@gmail.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "include/sip.h"
|
||||
#include "include/security_events.h"
|
||||
|
||||
/*! \brief Determine transport type used to receive request*/
|
||||
|
||||
static enum ast_transport security_event_get_transport(const struct sip_pvt *p)
|
||||
{
|
||||
return p->socket.type;
|
||||
}
|
||||
|
||||
void sip_report_invalid_peer(const struct sip_pvt *p)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_inval_acct_id inval_acct_id = {
|
||||
.common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
|
||||
.common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
|
||||
}
|
||||
|
||||
void sip_report_failed_acl(const struct sip_pvt *p, const char *aclname)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_failed_acl failed_acl_event = {
|
||||
.common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
|
||||
.common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
.acl_name = aclname,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
|
||||
}
|
||||
|
||||
void sip_report_inval_password(const struct sip_pvt *p, const char *response_challenge, const char *response_hash)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_inval_password inval_password = {
|
||||
.common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
|
||||
.common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.challenge = p->nonce,
|
||||
.received_challenge = response_challenge,
|
||||
.received_hash = response_hash,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&inval_password));
|
||||
}
|
||||
|
||||
void sip_report_auth_success(const struct sip_pvt *p, uint32_t using_password)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_successful_auth successful_auth = {
|
||||
.common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
|
||||
.common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
.using_password = using_password,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&successful_auth));
|
||||
}
|
||||
|
||||
void sip_report_session_limit(const struct sip_pvt *p)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_session_limit session_limit = {
|
||||
.common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
|
||||
.common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&session_limit));
|
||||
}
|
||||
|
||||
void sip_report_failed_challenge_response(const struct sip_pvt *p, const char *response, const char *expected_response)
|
||||
{
|
||||
char session_id[32];
|
||||
char account_id[256];
|
||||
|
||||
struct ast_security_event_chal_resp_failed chal_resp_failed = {
|
||||
.common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
|
||||
.common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = account_id,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.challenge = p->nonce,
|
||||
.response = response,
|
||||
.expected_response = expected_response,
|
||||
};
|
||||
|
||||
if (!ast_strlen_zero(p->from)) { /* When dialing, show account making call */
|
||||
ast_copy_string(account_id, p->from, sizeof(account_id));
|
||||
} else {
|
||||
ast_copy_string(account_id, p->exten, sizeof(account_id));
|
||||
}
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
|
||||
}
|
||||
|
||||
void sip_report_chal_sent(const struct sip_pvt *p)
|
||||
{
|
||||
char session_id[32];
|
||||
char account_id[256];
|
||||
|
||||
struct ast_security_event_chal_sent chal_sent = {
|
||||
.common.event_type = AST_SECURITY_EVENT_CHAL_SENT,
|
||||
.common.version = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = account_id,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.challenge = p->nonce,
|
||||
};
|
||||
|
||||
if (!ast_strlen_zero(p->from)) { /* When dialing, show account making call */
|
||||
ast_copy_string(account_id, p->from, sizeof(account_id));
|
||||
} else {
|
||||
ast_copy_string(account_id, p->exten, sizeof(account_id));
|
||||
}
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&chal_sent));
|
||||
}
|
||||
|
||||
void sip_report_inval_transport(const struct sip_pvt *p, const char *transport)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_inval_transport inval_transport = {
|
||||
.common.event_type = AST_SECURITY_EVENT_INVAL_TRANSPORT,
|
||||
.common.version = AST_SECURITY_EVENT_INVAL_TRANSPORT_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.transport = transport,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&inval_transport));
|
||||
}
|
||||
|
||||
int sip_report_security_event(const char *peer, struct ast_sockaddr *addr, const struct sip_pvt *p,
|
||||
const struct sip_request *req, const int res)
|
||||
{
|
||||
|
||||
struct sip_peer *peer_report;
|
||||
enum check_auth_result res_report = res;
|
||||
struct ast_str *buf;
|
||||
char *c;
|
||||
const char *authtoken;
|
||||
char *reqheader, *respheader;
|
||||
int result = 0;
|
||||
char aclname[256];
|
||||
struct digestkeys keys[] = {
|
||||
[K_RESP] = { "response=", "" },
|
||||
[K_URI] = { "uri=", "" },
|
||||
[K_USER] = { "username=", "" },
|
||||
[K_NONCE] = { "nonce=", "" },
|
||||
[K_LAST] = { NULL, NULL}
|
||||
};
|
||||
|
||||
peer_report = sip_find_peer(peer, addr, TRUE, FINDPEERS, FALSE, p->socket.type);
|
||||
|
||||
switch(res_report) {
|
||||
case AUTH_DONT_KNOW:
|
||||
break;
|
||||
case AUTH_SUCCESSFUL:
|
||||
if (peer_report) {
|
||||
if (ast_strlen_zero(peer_report->secret) && ast_strlen_zero(peer_report->md5secret)) {
|
||||
sip_report_auth_success(p, 0);
|
||||
} else {
|
||||
sip_report_auth_success(p, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AUTH_CHALLENGE_SENT:
|
||||
sip_report_chal_sent(p);
|
||||
break;
|
||||
case AUTH_SECRET_FAILED:
|
||||
case AUTH_USERNAME_MISMATCH:
|
||||
sip_auth_headers(WWW_AUTH, &respheader, &reqheader);
|
||||
authtoken = sip_get_header(req, reqheader);
|
||||
buf = ast_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN);
|
||||
ast_str_set(&buf, 0, "%s", authtoken);
|
||||
c = ast_str_buffer(buf);
|
||||
|
||||
sip_digest_parser(c, keys);
|
||||
|
||||
if (res_report == AUTH_SECRET_FAILED) {
|
||||
sip_report_inval_password(p, keys[K_NONCE].s, keys[K_RESP].s);
|
||||
} else {
|
||||
if (peer_report) {
|
||||
sip_report_failed_challenge_response(p, keys[K_USER].s, peer_report->username);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AUTH_NOT_FOUND:
|
||||
/* with sip_cfg.alwaysauthreject on, generates 2 events */
|
||||
sip_report_invalid_peer(p);
|
||||
break;
|
||||
case AUTH_UNKNOWN_DOMAIN:
|
||||
snprintf(aclname, sizeof(aclname), "domain_must_match");
|
||||
sip_report_failed_acl(p, aclname);
|
||||
break;
|
||||
case AUTH_PEER_NOT_DYNAMIC:
|
||||
snprintf(aclname, sizeof(aclname), "peer_not_dynamic");
|
||||
sip_report_failed_acl(p, aclname);
|
||||
break;
|
||||
case AUTH_ACL_FAILED:
|
||||
/* with sip_cfg.alwaysauthreject on, generates 2 events */
|
||||
snprintf(aclname, sizeof(aclname), "device_must_match_acl");
|
||||
sip_report_failed_acl(p, aclname);
|
||||
break;
|
||||
case AUTH_BAD_TRANSPORT:
|
||||
sip_report_inval_transport(p, sip_get_transport(req->socket.type));
|
||||
break;
|
||||
case AUTH_RTP_FAILED:
|
||||
break;
|
||||
case AUTH_SESSION_LIMIT:
|
||||
sip_report_session_limit(p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (peer_report) {
|
||||
sip_unref_peer(peer_report, "sip_report_security_event: sip_unref_peer: from handle_incoming");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2012, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief Utility functions for chan_sip
|
||||
*
|
||||
* \author Terry Wilson <twilson@digium.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "include/sip.h"
|
||||
#include "include/sip_utils.h"
|
||||
|
||||
const char *force_rport_string(struct ast_flags *flags)
|
||||
{
|
||||
if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
return ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT) ? "Auto (Yes)" : "Auto (No)";
|
||||
}
|
||||
return AST_CLI_YESNO(ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT));
|
||||
}
|
||||
|
||||
const char *comedia_string(struct ast_flags *flags)
|
||||
{
|
||||
if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
return ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) ? "Auto (Yes)" : "Auto (No)";
|
||||
}
|
||||
return AST_CLI_YESNO(ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP));
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,57 +0,0 @@
|
||||
; rfc3842
|
||||
; put empty "Content=>" at the end to have CRLF after last body line
|
||||
|
||||
[clear-mwi]
|
||||
Event=>message-summary
|
||||
Content-type=>application/simple-message-summary
|
||||
Content=>Messages-Waiting: no
|
||||
Content=>Message-Account: sip:asterisk@127.0.0.1
|
||||
Content=>Voice-Message: 0/0 (0/0)
|
||||
Content=>
|
||||
|
||||
; Aastra
|
||||
|
||||
[aastra-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
[aastra-xml]
|
||||
Event=>aastra-xml
|
||||
|
||||
; Digium
|
||||
|
||||
[digium-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
; Linksys
|
||||
|
||||
[linksys-cold-restart]
|
||||
Event=>reboot_now
|
||||
|
||||
[linksys-warm-restart]
|
||||
Event=>restart_now
|
||||
|
||||
; Polycom
|
||||
|
||||
[polycom-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
; Sipura
|
||||
|
||||
[sipura-check-cfg]
|
||||
Event=>resync
|
||||
|
||||
[sipura-get-report]
|
||||
Event=>report
|
||||
|
||||
; snom
|
||||
|
||||
[snom-check-cfg]
|
||||
Event=>check-sync\;reboot=false
|
||||
|
||||
[snom-reboot]
|
||||
Event=>check-sync\;reboot=true
|
||||
|
||||
; Cisco
|
||||
|
||||
[cisco-check-cfg]
|
||||
Event=>check-sync
|
@ -1,92 +0,0 @@
|
||||
#!/usr/bin/perl -Tw
|
||||
# Retrieves the sip user/peer entries from the database
|
||||
# Use these commands to create the appropriate tables in MySQL
|
||||
#
|
||||
#CREATE TABLE sip (id INT(11) DEFAULT -1 NOT NULL,keyword VARCHAR(20) NOT NULL,data VARCHAR(50) NOT NULL, flags INT(1) DEFAULT 0 NOT NULL,PRIMARY KEY (id,keyword));
|
||||
#
|
||||
# if flags = 1 then the records are not included in the output file
|
||||
|
||||
use DBI;
|
||||
################### BEGIN OF CONFIGURATION ####################
|
||||
|
||||
# the name of the extensions table
|
||||
$table_name = "sip";
|
||||
# the path to the extensions.conf file
|
||||
# WARNING: this file will be substituted by the output of this program
|
||||
$sip_conf = "/etc/asterisk/sip_additional.conf";
|
||||
# the name of the box the MySQL database is running on
|
||||
$hostname = "localhost";
|
||||
# the name of the database our tables are kept
|
||||
$database = "sip";
|
||||
# username to connect to the database
|
||||
$username = "root";
|
||||
# password to connect to the database
|
||||
$password = "";
|
||||
|
||||
################### END OF CONFIGURATION #######################
|
||||
|
||||
$additional = "";
|
||||
|
||||
open EXTEN, ">$sip_conf" || die "Cannot create/overwrite extensions file: $sip_conf\n";
|
||||
|
||||
$dbh = DBI->connect("dbi:mysql:dbname=$database;host=$hostname", "$username", "$password");
|
||||
$statement = "SELECT keyword,data from $table_name where id=0 and keyword <> 'account' and flags <> 1";
|
||||
my $result = $dbh->selectall_arrayref($statement);
|
||||
unless ($result) {
|
||||
# check for errors after every single database call
|
||||
print "dbh->selectall_arrayref($statement) failed!\n";
|
||||
print "DBI::err=[$DBI::err]\n";
|
||||
print "DBI::errstr=[$DBI::errstr]\n";
|
||||
exit;
|
||||
}
|
||||
my @resultSet = @{$result};
|
||||
if ( $#resultSet > -1 ) {
|
||||
foreach $row (@{ $result }) {
|
||||
my @result = @{ $row };
|
||||
$additional .= $result[0]."=".$result[1]."\n";
|
||||
}
|
||||
}
|
||||
|
||||
$statement = "SELECT data,id from $table_name where keyword='account' and flags <> 1 group by data";
|
||||
|
||||
$result = $dbh->selectall_arrayref($statement);
|
||||
unless ($result) {
|
||||
# check for errors after every single database call
|
||||
print "dbh->selectall_arrayref($statement) failed!\n";
|
||||
print "DBI::err=[$DBI::err]\n";
|
||||
print "DBI::errstr=[$DBI::errstr]\n";
|
||||
}
|
||||
|
||||
@resultSet = @{$result};
|
||||
if ( $#resultSet == -1 ) {
|
||||
print "No sip accounts defined in $table_name\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach my $row ( @{ $result } ) {
|
||||
my $account = @{ $row }[0];
|
||||
my $id = @{ $row }[1];
|
||||
print EXTEN "[$account]\n";
|
||||
$statement = "SELECT keyword,data from $table_name where id=$id and keyword <> 'account' and flags <> 1 order by keyword";
|
||||
my $result = $dbh->selectall_arrayref($statement);
|
||||
unless ($result) {
|
||||
# check for errors after every single database call
|
||||
print "dbh->selectall_arrayref($statement) failed!\n";
|
||||
print "DBI::err=[$DBI::err]\n";
|
||||
print "DBI::errstr=[$DBI::errstr]\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
my @resSet = @{$result};
|
||||
if ( $#resSet == -1 ) {
|
||||
print "no results\n";
|
||||
exit;
|
||||
}
|
||||
foreach my $row ( @{ $result } ) {
|
||||
my @result = @{ $row };
|
||||
print EXTEN "$result[0]=$result[1]\n";
|
||||
}
|
||||
print EXTEN "$additional\n";
|
||||
}
|
||||
|
||||
exit 0;
|
@ -1,67 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# sip_nat_settings: generate NAT settings for sip.conf of an Asterisk system
|
||||
# that is behind a NAT router.
|
||||
#
|
||||
# This is a script to generate sane defaults for externip and localnet
|
||||
# of sip.conf. The output should be included in the [general] section of
|
||||
# sip.conf .
|
||||
#
|
||||
# Multiple network interfaces: If you have multiple network interfaces,
|
||||
# this script will generate a 'localnet' line for each of them that has a
|
||||
# broadcast (ipv4) address, except the loopback interface (lo). You can
|
||||
# later rem-out all of those you don't need.
|
||||
#
|
||||
# Alternatively, provide a network interface as a parameter an a localnet
|
||||
# line will only be generated for its network.
|
||||
#
|
||||
# Copyright (C) 2005 by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# see http://unix.stackexchange.com/q/22615
|
||||
externip=`dig @resolver1.opendns.com -4 myip.opendns.com A +short`
|
||||
|
||||
# optional parameter: network interface to use. By default: none.
|
||||
IFACE="$1"
|
||||
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
Linux)
|
||||
echo "externip = $externip"
|
||||
if [ -x "${IFACE}" ]; then
|
||||
ip --brief -family inet address show scope global up dev $IFACE | awk '{print "localnet = " $3}'
|
||||
else
|
||||
ip --brief -family inet address show scope global up | awk '{print "localnet = " $3}'
|
||||
fi
|
||||
;;
|
||||
OpenBSD|FreeBSD)
|
||||
if [ "${OS}" = "FreeBSD" ]; then
|
||||
VER=`uname -r | cut -d . -f 1`
|
||||
if [ ${VER} -lt 7 ]; then
|
||||
echo "Unsupported OS"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "externip = $externip"
|
||||
ip=`/sbin/ifconfig $IFACE | awk '/\tinet .* broadcast/{print $6}'`
|
||||
x=`/sbin/ifconfig $IFACE | awk '/\tinet .* broadcast/{print $4}'`
|
||||
printf 'localnet = %s/%u.%u.%u.%u\n' $ip $(($x>>24&0xff)) $(($x>>16&0xff)) $(($x>>8&0xff)) $(($x&0xff))
|
||||
;;
|
||||
*)
|
||||
echo >&2 "$0: Unsupported OS $OS"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -0,0 +1,6 @@
|
||||
Subject: chan_sip
|
||||
Master-Only: True
|
||||
|
||||
This module was deprecated in Asterisk 17
|
||||
and is now being removed in accordance with
|
||||
the Asterisk Module Deprecation policy.
|
Loading…
Reference in new issue