aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2010-01-23 00:42:09 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2010-01-23 00:42:09 +0000
commitf6b9b9c331d3b1858724188500a7cadf146bfee7 (patch)
tree899f3bf5e19f082893f9d991c9b6bfcee9e28fe6
parenta4c14ea2dbf8bcb7455a28de27ab4eb8deebd1d7 (diff)
Backporting register line parsing from trunk to fix a bad parsing error in 1.6.0.
(closes issue #16491) Reported by: jamicque Patches: 20100114__issue16491.diff.txt uploaded by tilghman (license 14) Tested by: jamicque ........ r213098 | tilghman | 2009-08-19 16:05:17 -0500 (Wed, 19 Aug 2009) | 9 lines Better parsing for the "register" line Allows characters that are otherwise used as delimiters to be used within certain fields (like the secret). (closes issue #15008, closes issue #15672) Reported by: tilghman Patches: 20090818__issue15008.diff.txt uploaded by tilghman (license 14) Tested by: lmadsen, tilghman ........ r213635 | dvossel | 2009-08-21 16:02:50 -0500 (Fri, 21 Aug 2009) | 5 lines fixes sip register parsing when user@domain is used (issue #15008) (issue #15672) ........ r215222 | tilghman | 2009-09-01 16:19:40 -0500 (Tue, 01 Sep 2009) | 3 lines Fix register such that lines with a transport string, but without an authuser, parse correctly. (AST-228) ........ r215801 | tilghman | 2009-09-02 22:43:51 -0500 (Wed, 02 Sep 2009) | 5 lines Default the callback extension to "s". This is a regression. (closes issue #15764) Reported by: elguero Change-type: bugfix ........ r235132 | dvossel | 2009-12-15 12:43:06 -0600 (Tue, 15 Dec 2009) | 14 lines reverse minor sip registration regression A registration regression caused by a code tweak in (issue #14331) and a bug fix in (issue #15539) caused some sip registration config entries to be constructed incorrectly. Origially issue #14331 contained the code tweak as well as a bug fix, but since the issue was reported as a tweak the bug fix portion was moved into issue #15539. Both the tweak and the bug fix contained minor incorrect logic that resulted in some SIP registrations to fail. (issue #14331) (issue #15539) ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@242514 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--channels/chan_sip.c290
-rw-r--r--configs/sip.conf.sample2
2 files changed, 225 insertions, 67 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index a2c071162..3b5118147 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -177,6 +177,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/ast_version.h"
#include "asterisk/event.h"
#include "asterisk/tcptls.h"
+#include "asterisk/strings.h"
#ifndef FALSE
#define FALSE 0
@@ -6520,60 +6521,198 @@ static int sip_register(const char *value, int lineno)
int portnum = 0;
enum sip_transport transport = SIP_TRANSPORT_UDP;
char buf[256] = "";
- char *username = NULL;
- char *port = NULL;
- char *hostname=NULL, *secret=NULL, *authuser=NULL, *tmp=NULL;
- char *callback=NULL, *peername=NULL;
+ 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(userpart);
+ AST_APP_ARG(domain);
+ );
+ 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 (!value)
return -1;
ast_copy_string(buf, value, sizeof(buf));
- /* split [peername?][transport://] */
- tmp = strchr(buf, '?');
- if (tmp) {
- *tmp++ = '\0';
- peername = buf;
- } else {
- tmp = 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;
}
- /* tmp is set at the beginning of [transport://] */
- sip_parse_host(tmp, lineno, &username, &portnum, &transport);
- /* First split around the last '@' then parse the two components. */
- hostname = strrchr(username, '@'); /* allow @ in the first part */
- if (hostname)
- *hostname++ = '\0';
- if (ast_strlen_zero(username) || ast_strlen_zero(hostname)) {
- ast_log(LOG_WARNING, "Format for registration is [transport://]user[@domain][:secret[:authuser]]@host[:port][/extension] at line %d\n", lineno);
+ 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;
}
- /* split user[:secret[:authuser]] */
- secret = strchr(username, ':');
- if (secret) {
- *secret++ = '\0';
- authuser = strchr(secret, ':');
- if (authuser)
- *authuser++ = '\0';
- }
-
- /* split host[:port][/contact] */
- callback = strchr(hostname, '/');
- if (callback)
- *callback++ = '\0';
- if (ast_strlen_zero(callback))
- callback = "s";
- /* Separate host from port when checking for reserved characters
+
+ /*!
+ * pre1.peer => peer
+ * pre1.userpart => [transport://]user[@domain][:secret[:authuser]]
+ * hostpart => host[:port][/extension][~expiry]
*/
- if ((port = strchr(hostname, ':'))) {
- *port = '\0';
+ AST_NONSTANDARD_RAW_ARGS(pre1, userpart, '?');
+ if (ast_strlen_zero(pre1.userpart)) {
+ pre1.userpart = pre1.peer;
+ pre1.peer = NULL;
}
- /* And then re-merge the host and port so they are stored correctly
+
+ /*!
+ * pre1.peer => peer
+ * pre2.transport = transport
+ * pre2.userpart => user[@domain][:secret[:authuser]]
+ * hostpart => host[:port][/extension][~expiry]
*/
- if (port) {
- *port = ':';
+ AST_NONSTANDARD_RAW_ARGS(pre2, 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]
+ */
+ 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.userpart => user
+ * user2.domain => domain (regdomain)
+ * user1.secret => secret
+ * user1.authuser => authuser
+ * host3.host => host
+ * host3.port => port
+ * host2.extension => extension (callback)
+ * host1.expiry => expiry
+ */
+ AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
+
+ /*!
+ * pre1.peer => peer
+ * transport = transport
+ * user2.userpart => user
+ * user2.domain => domain (regdomain)
+ * user1.secret => secret
+ * user1.authuser => authuser
+ * host3.host => host
+ * portnum => port
+ * host2.extension => extension (callback)
+ * host1.expiry => expiry
+ */
+ if (host3.port) {
+ if (sscanf(host3.port, "%5u", &portnum) != 1 || portnum > 65535) {
+ ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno);
+ portnum = -1;
+ }
+ }
+
+ /*!
+ * pre1.peer => peer
+ * transport = transport
+ * user2.userpart => user
+ * user2.domain => domain (regdomain)
+ * user1.secret => secret
+ * user1.authuser => authuser
+ * host3.host => host
+ * portnum => port
+ * host2.extension => extension (callback)
+ * host1.expiry => expiry
+ */
+ if (!pre2.transport) {
+ transport = SIP_TRANSPORT_UDP;
+ } else if (!strncasecmp(pre2.transport, "tcp", 3)) {
+ transport = SIP_TRANSPORT_TCP;
+ } else if (!strncasecmp(pre2.transport, "tls", 3)) {
+ transport = SIP_TRANSPORT_TLS;
+ if (portnum < 0) {
+ portnum = STANDARD_TLS_PORT;
+ }
+ } else if (!strncasecmp(pre2.transport, "udp", 3)) {
+ transport = SIP_TRANSPORT_UDP;
+ } else {
+ 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 (portnum < 0) {
+ portnum = STANDARD_SIP_PORT;
+ }
+
if (!(reg = ast_calloc(1, sizeof(*reg)))) {
ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n");
return -1;
@@ -6585,26 +6724,31 @@ static int sip_register(const char *value, int lineno)
return -1;
}
+ /*!
+ * pre1.peer => peer
+ * transport = transport
+ * user2.userpart => user
+ * user2.domain => domain (regdomain)
+ * user1.secret => secret
+ * user1.authuser => authuser
+ * host3.host => host
+ * portnum => port
+ * host2.extension => extension (callback)
+ * host1.expiry => expiry
+ */
regobjs++;
ASTOBJ_INIT(reg);
- ast_string_field_set(reg, callback, callback);
- if (!ast_strlen_zero(username))
- ast_string_field_set(reg, username, username);
- if (hostname)
- ast_string_field_set(reg, hostname, hostname);
- if (authuser)
- ast_string_field_set(reg, authuser, authuser);
- if (secret)
- ast_string_field_set(reg, secret, secret);
- if (peername) {
- ast_string_field_set(reg, peername, peername);
- }
+ 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.userpart, ""), "\"", "\""));
+ ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\""));
+ ast_string_field_set(reg, domain, ast_strip_quoted(S_OR(user2.domain, S_OR(host3.host, "")), "\"", "\""));
+ ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user1.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, ""), "\"", "\""));
+
reg->transport = transport;
- reg->expire = -1;
- reg->configured_expiry = default_expiry;
- reg->expiry = reg->configured_expiry;
- reg->timeout = -1;
- reg->refresh = default_expiry;
+ reg->timeout = reg->expire = -1;
+ reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry);
reg->portno = portnum;
reg->callid_valid = FALSE;
reg->ocseq = INITIAL_CSEQ;
@@ -10100,6 +10244,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
char addr[80];
struct sip_pvt *p;
char *fromdomain;
+ char *domainport = NULL;
/* exit if we are already in process with this registrar ?*/
if ( r == NULL || ((auth==NULL) && (r->regstate==REG_STATE_REGSENT || r->regstate==REG_STATE_AUTHSENT))) {
@@ -10165,9 +10310,10 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
ast_string_field_set(r, callid, p->callid);
if (r->portno) {
p->sa.sin_port = htons(r->portno);
- p->recv.sin_port = htons(r->portno);
- } else /* Set registry port to the port set from the peer definition/srv or default */
+ p->recv.sin_port = htons(r->portno);
+ } else { /* Set registry port to the port set from the peer definition/srv or default */
r->portno = ntohs(p->sa.sin_port);
+ }
ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Registration is outgoing call */
r->call = p; /* Save pointer to SIP dialog */
p->registry = registry_addref(r); /* Add pointer to registry in packet */
@@ -10235,14 +10381,27 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
else
snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, p->tohost);
}
-
+
/* Fromdomain is what we are registering to, regardless of actual
- host name from SRV */
+ host name from SRV */
if (!ast_strlen_zero(p->fromdomain)) {
- if (r->portno && r->portno != STANDARD_SIP_PORT)
- snprintf(addr, sizeof(addr), "sip:%s:%d", p->fromdomain, r->portno);
- else
- snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain);
+ domainport = strrchr(p->fromdomain, ':');
+ if (domainport) {
+ *domainport++ = '\0'; /* trim off domainport from p->fromdomain */
+ if (ast_strlen_zero(domainport))
+ domainport = NULL;
+ }
+ if (domainport) {
+ if (atoi(domainport) != STANDARD_SIP_PORT)
+ snprintf(addr, sizeof(addr), "sip:%s:%s", p->fromdomain, domainport);
+ else
+ snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain);
+ } else {
+ if (r->portno && r->portno != STANDARD_SIP_PORT)
+ snprintf(addr, sizeof(addr), "sip:%s:%d", p->fromdomain, r->portno);
+ else
+ snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain);
+ }
} else {
if (r->portno && r->portno != STANDARD_SIP_PORT)
snprintf(addr, sizeof(addr), "sip:%s:%d", r->hostname, r->portno);
@@ -10269,7 +10428,6 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
if (!ast_strlen_zero(global_useragent))
add_header(&req, "User-Agent", global_useragent);
-
if (auth) /* Add auth header */
add_header(&req, authheader, auth);
else if (!ast_strlen_zero(r->nonce)) {
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index 2e48c9d0f..f68361424 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -437,7 +437,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;----------------------------------------- OUTBOUND SIP REGISTRATIONS ------------------------
; Asterisk can register as a SIP user agent to a SIP proxy (provider)
; Format for the register statement is:
-; register => [transport://]user[@domain][:secret[:authuser]]@host[:port][/extension]
+; register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
;
;
;