]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Fix error in the "IPorHost" section of a SIP dialstring.
authorMark Michelson <mmichelson@digium.com>
Tue, 7 Aug 2012 15:49:48 +0000 (15:49 +0000)
committerMark Michelson <mmichelson@digium.com>
Tue, 7 Aug 2012 15:49:48 +0000 (15:49 +0000)
This is based on the review request posted by Walter Doekes
(referenced lower in the commit message)

The main fix here is to treat the IPorHost portion of the dial
string as a temporary outbound proxy. This ensures requests
get sent to the proper location.

Due to the age of the request, some parts were no longer relevant.
For instance, the request moved outbound proxy parsing code into
a single method. This is done in a previous commit, so it was not
necessary to do again.

Also, the review request fixed some errors with regards to request
routing for CANCEL and ACK requests. This has also been fixed in
more recent commits.

(closes issue ASTERISK-19677)
reported by Walter Doekes

Review https://reviewboard.asterisk.org/r/1859
........

Merged revisions 370769 from http://svn.asterisk.org/svn/asterisk/branches/1.8

git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@370844 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
channels/sip/config_parser.c
channels/sip/include/sip.h

index bf54539d4b3760d256d3670a9f56ac2bbbae22b5..e4731ac88347ce74291dd60524ecce3ef6d79f90 100644 (file)
@@ -1539,7 +1539,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
 static const struct ast_sockaddr *sip_real_dst(const struct sip_pvt *p);
 static void build_via(struct sip_pvt *p);
 static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
-static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog, struct ast_sockaddr *remote_address);
+static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog);
 static char *generate_random_string(char *buf, size_t size);
 static void build_callid_pvt(struct sip_pvt *pvt);
 static void change_callid_pvt(struct sip_pvt *pvt, const char *callid);
@@ -1962,7 +1962,7 @@ static int sip_cc_monitor_request_cc(struct ast_cc_monitor *monitor, int *availa
 
        sip_pvt_lock(monitor_instance->subscription_pvt);
        ast_set_flag(&monitor_instance->subscription_pvt->flags[0], SIP_OUTGOING);
-       create_addr(monitor_instance->subscription_pvt, monitor_instance->peername, 0, 1, NULL);
+       create_addr(monitor_instance->subscription_pvt, monitor_instance->peername, 0, 1);
        ast_sip_ouraddrfor(&monitor_instance->subscription_pvt->sa, &monitor_instance->subscription_pvt->ourip, monitor_instance->subscription_pvt);
        monitor_instance->subscription_pvt->subscribed = CALL_COMPLETION;
        monitor_instance->subscription_pvt->expiry = when;
@@ -3137,6 +3137,52 @@ static int proxy_update(struct sip_proxy *proxy)
        return TRUE;
 }
 
+/*! \brief Parse proxy string and return an ao2_alloc'd proxy. If dest is
+ *         non-NULL, no allocation is performed and dest is used instead.
+ *         On error NULL is returned. */
+static struct sip_proxy *proxy_from_config(const char *proxy, int sipconf_lineno, struct sip_proxy *dest)
+{
+       char *mutable_proxy, *sep, *name;
+       int allocated = 0;
+
+       if (!dest) {
+               dest = ao2_alloc(sizeof(struct sip_proxy), NULL);
+               if (!dest) {
+                       ast_log(LOG_WARNING, "Unable to allocate config storage for proxy\n");
+                       return NULL;
+               }
+               allocated = 1;
+       }
+
+       /* Format is: [transport://]name[:port][,force] */
+       mutable_proxy = ast_skip_blanks(ast_strdupa(proxy));
+       sep = strchr(mutable_proxy, ',');
+       if (sep) {
+               *sep++ = '\0';
+               dest->force = !strncasecmp(ast_skip_blanks(sep), "force", 5);
+       } else {
+               dest->force = FALSE;
+       }
+
+       sip_parse_host(mutable_proxy, sipconf_lineno, &name, &dest->port, &dest->transport);
+
+       /* Check that there is a name at all */
+       if (ast_strlen_zero(name)) {
+               if (allocated) {
+                       ao2_ref(dest, -1);
+               } else {
+                       dest->name[0] = '\0';
+               }
+               return NULL;
+       }
+       ast_copy_string(dest->name, name, sizeof(dest->name));
+
+       /* Resolve host immediately */
+       proxy_update(dest);
+
+       return dest;
+}
+
 /*! \brief converts ascii port to int representation. If no
  *  pt buffer is provided or the pt has errors when being converted
  *  to an int value, the port provided as the standard is used.
@@ -3154,6 +3200,12 @@ unsigned int port_str2int(const char *pt, unsigned int standard)
 /*! \brief Get default outbound proxy or global proxy */
 static struct sip_proxy *obproxy_get(struct sip_pvt *dialog, struct sip_peer *peer)
 {
+       if (dialog && dialog->options && dialog->options->outboundproxy) {
+               if (sipdebug) {
+                       ast_debug(1, "BLAH\n");
+               }
+               return dialog->options->outboundproxy;
+       }
        if (peer && peer->outboundproxy) {
                if (sipdebug) {
                        ast_debug(1, "OBPROXY: Applying peer OBproxy to this call\n");
@@ -5427,7 +5479,7 @@ static inline int default_sip_port(enum sip_transport type)
 /*! \brief create address structure from device name
  *      Or, if peer not found, find it in the global DNS
  *      returns TRUE (-1) on failure, FALSE on success */
-static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog, struct ast_sockaddr *remote_address)
+static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog)
 {
        struct sip_peer *peer;
        char *peername, *peername2, *hostn;
@@ -5458,9 +5510,6 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
                        set_socket_transport(&dialog->socket, 0);
                }
                res = create_addr_from_peer(dialog, peer);
-               if (!ast_sockaddr_isnull(remote_address)) {
-                       ast_sockaddr_copy(&dialog->sa, remote_address);
-               }
                dialog->relatedpeer = ref_peer(peer, "create_addr: setting dialog's relatedpeer pointer");
                unref_peer(peer, "create_addr: unref peer from find_peer hashtab lookup");
                return res;
@@ -5819,8 +5868,12 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
        if (dumphistory)
                sip_dump_history(p);
 
-       if (p->options)
+       if (p->options) {
+               if (p->options->outboundproxy) {
+                       ao2_ref(p->options->outboundproxy, -1);
+               }
                ast_free(p->options);
+       }
 
        if (p->notify) {
                ast_variables_destroy(p->notify->headers);
@@ -12274,7 +12327,7 @@ static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_ty
 
        sip_pvt_lock(pvt);
 
-       if (create_addr(pvt, epa_entry->destination, NULL, TRUE, NULL)) {
+       if (create_addr(pvt, epa_entry->destination, NULL, TRUE)) {
                sip_pvt_unlock(pvt);
                dialog_unlink_all(pvt);
                dialog_unref(pvt, "create_addr failed in transmit_publish. Unref dialog");
@@ -12588,7 +12641,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
        }
        
        /* Setup the destination of our subscription */
-       if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0, NULL)) {
+       if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0)) {
                dialog_unlink_all(mwi->call);
                mwi->call = dialog_unref(mwi->call, "unref dialog after unlink_all");
                return 0;
@@ -13095,7 +13148,7 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
                return 0;
        }
 
-       if (create_addr(p, channame, NULL, 0, NULL)) {
+       if (create_addr(p, channame, NULL, 0)) {
                /* Maybe they're not registered, etc. */
                dialog_unlink_all(p);
                dialog_unref(p, "unref dialog inside for loop" );
@@ -13439,7 +13492,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
                }
 
                /* Find address to hostname */
-               if (create_addr(p, S_OR(r->peername, r->hostname), &r->us, 0, NULL)) {
+               if (create_addr(p, S_OR(r->peername, r->hostname), &r->us, 0)) {
                        /* we have what we hope is a temporary network error,
                         * probably DNS.  We need to reschedule a registration try */
                        dialog_unlink_all(p);
@@ -19455,7 +19508,7 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
                        return CLI_FAILURE;
                }
 
-               if (create_addr(p, a->argv[i], NULL, 1, NULL)) {
+               if (create_addr(p, a->argv[i], NULL, 1)) {
                        /* Maybe they're not registered, etc. */
                        dialog_unlink_all(p);
                        dialog_unref(p, "unref dialog inside for loop" );
@@ -20951,6 +21004,9 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r
                ast_debug(3, "Got 200 OK on subscription for MWI\n");
                set_pvt_allowed_methods(p, req);
                if (p->options) {
+                       if (p->options->outboundproxy) {
+                               ao2_ref(p->options->outboundproxy, -1);
+                       }
                        ast_free(p->options);
                        p->options = NULL;
                }
@@ -24538,7 +24594,7 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f
        sip_pvt_lock(pvt);
 
        /* Look up the host to contact */
-       if (create_addr(pvt, to_host, NULL, TRUE, NULL)) {
+       if (create_addr(pvt, to_host, NULL, TRUE)) {
                sip_pvt_unlock(pvt);
                dialog_unlink_all(pvt);
                dialog_unref(pvt, "create_addr failed sending a MESSAGE");
@@ -27114,7 +27170,6 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
        char dialstring[256];
        char *remote_address;
        enum sip_transport transport = 0;
-       struct ast_sockaddr remote_address_sa = { {0,} };
        format_t oldformat = format;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(peerorhost);
@@ -27222,15 +27277,9 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
        }
 
        if (!ast_strlen_zero(remote_address)) {
-               if (ast_sockaddr_resolve_first_transport(&remote_address_sa, remote_address, 0, transport)) {
-                       ast_log(LOG_WARNING, "Unable to find IP address for host %s. We will not use this remote IP address\n", remote_address);
-               } else {
-                       if (!ast_sockaddr_port(&remote_address_sa)) {
-                               ast_sockaddr_set_port(&remote_address_sa,
-                                                     transport & SIP_TRANSPORT_TLS ?
-                                                     STANDARD_TLS_PORT :
-                                                     STANDARD_SIP_PORT);
-                       }
+               p->options->outboundproxy = proxy_from_config(remote_address, 0, NULL);
+               if (!p->options->outboundproxy) {
+                       ast_log(LOG_WARNING, "Unable to parse outboundproxy %s. We will not use this remote IP address\n", remote_address);
                }
        }
 
@@ -27241,7 +27290,7 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
                ext = extension (user part of URI)
                dnid = destination of the call (applies to the To: header)
        */
-       if (create_addr(p, host, NULL, 1, &remote_address_sa)) {
+       if (create_addr(p, host, NULL, 1)) {
                *cause = AST_CAUSE_UNREGISTERED;
                ast_debug(3, "Cant create SIP call - target device not registered\n");
                dialog_unlink_all(p);
@@ -28053,49 +28102,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                        } else if (!strcasecmp(v->name, "fromuser")) {
                                ast_string_field_set(peer, fromuser, v->value);
                        } else if (!strcasecmp(v->name, "outboundproxy")) {
-                               char *host, *proxyname, *sep;
-
+                               struct sip_proxy *proxy;
                                if (ast_strlen_zero(v->value)) {
                                        ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf\n", v->lineno);
                                        continue;
                                }
-
-                               if (!peer->outboundproxy) {
-                                       peer->outboundproxy = ao2_alloc(sizeof(*peer->outboundproxy), NULL);
-                                       if (!peer->outboundproxy) {
-                                               ast_log(LOG_WARNING, "Unable to allocate config storage for outboundproxy\n");
-                                               continue;
-                                       }
-                               }
-
-                               host = ast_strdupa(v->value);
-                               if (!host) {
-                                       ast_log(LOG_WARNING, "Unable to allocate stack space for parsing outboundproxy\n");
-                                       continue;
-                               }
-
-                               host = ast_skip_blanks(host);
-                               sep = strchr(host, ',');
-                               if (sep) {
-                                       *sep++ = '\0';
-                                       peer->outboundproxy->force = !strncasecmp(ast_skip_blanks(sep), "force", 5);
-                               } else {
-                                       peer->outboundproxy->force = FALSE;
-                               }
-
-                               sip_parse_host(host, v->lineno, &proxyname,
-                                              &peer->outboundproxy->port,
-                                              &peer->outboundproxy->transport);
-
-                               if (ast_strlen_zero(proxyname)) {
-                                       ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf\n", v->lineno);
-                                       sip_cfg.outboundproxy.name[0] = '\0';
+                               proxy = proxy_from_config(v->value, v->lineno, peer->outboundproxy);
+                               if (!proxy) {
+                                       ast_log(LOG_WARNING, "failure parsing the outbound proxy on line %d of sip.conf.\n", v->lineno);
                                        continue;
                                }
-
-                               ast_copy_string(peer->outboundproxy->name, proxyname, sizeof(peer->outboundproxy->name));
-
-                               proxy_update(peer->outboundproxy);
+                               peer->outboundproxy = proxy;
                        } else if (!strcasecmp(v->name, "host")) {
                                if (!strcasecmp(v->value, "dynamic")) {
                                        /* They'll register with us */
@@ -29048,41 +29065,16 @@ static int reload_config(enum channelreloadreason reason)
                                default_fromdomainport = STANDARD_SIP_PORT;
                        }
                } else if (!strcasecmp(v->name, "outboundproxy")) {
-                       char *host, *proxyname, *sep;
-
+                       struct sip_proxy *proxy;
                        if (ast_strlen_zero(v->value)) {
                                ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf\n", v->lineno);
                                continue;
                        }
-
-                       host = ast_strdupa(v->value);
-                       if (!host) {
-                               ast_log(LOG_WARNING, "Unable to allocate stack space for parsing outboundproxy\n");
-                               continue;
-                       }
-
-                       host = ast_skip_blanks(host);
-                       sep = strchr(host, ',');
-                       if (sep) {
-                               *sep++ = '\0';
-                               sip_cfg.outboundproxy.force = !strncasecmp(ast_skip_blanks(sep), "force", 5);
-                       } else {
-                               sip_cfg.outboundproxy.force = FALSE;
-                       }
-
-                       sip_parse_host(host, v->lineno, &proxyname,
-                                      &sip_cfg.outboundproxy.port,
-                                      &sip_cfg.outboundproxy.transport);
-
-                       if (ast_strlen_zero(proxyname)) {
-                               ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf\n", v->lineno);
-                               sip_cfg.outboundproxy.name[0] = '\0';
+                       proxy = proxy_from_config(v->value, v->lineno, &sip_cfg.outboundproxy);
+                       if (!proxy) {
+                               ast_log(LOG_WARNING, "failure parsing the outbound proxy on line %d of sip.conf.\n", v->lineno);
                                continue;
                        }
-
-                       ast_copy_string(sip_cfg.outboundproxy.name, proxyname, sizeof(sip_cfg.outboundproxy.name));
-
-                       proxy_update(&sip_cfg.outboundproxy);
                } else if (!strcasecmp(v->name, "autocreatepeer")) {
                        sip_cfg.autocreatepeer = ast_true(v->value);
                } else if (!strcasecmp(v->name, "match_auth_username")) {
index a5318a4b7a6be2be3c8b9d29bcdbc571a114ee44..cf41587e72f5353ff56f2546dc85c27a292a3c56 100644 (file)
@@ -652,14 +652,17 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum s
        if ((*hostname = strstr(line, "://"))) {
                *hostname += 3;
 
-               if (!strncasecmp(line, "tcp", 3))
+               if (!strncasecmp(line, "tcp", 3)) {
                        *transport = SIP_TRANSPORT_TCP;
-               else if (!strncasecmp(line, "tls", 3))
+               } else if (!strncasecmp(line, "tls", 3)) {
                        *transport = SIP_TRANSPORT_TLS;
-               else if (!strncasecmp(line, "udp", 3))
+               } else if (!strncasecmp(line, "udp", 3)) {
                        *transport = SIP_TRANSPORT_UDP;
-               else
+               } 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 = SIP_TRANSPORT_UDP;
@@ -671,14 +674,22 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum s
                line = *hostname;
 
        if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
-               ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
-                       line, lineno);
+               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, "%5u", portnum)) {
-                       ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
+                       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;
                }
        }
index e4720f6961daa5d6aa842b1717f385de1409abdf..5165c41357ebd967f9a1af3d185346e5b2026415 100644 (file)
@@ -798,6 +798,7 @@ struct sip_invite_param {
        enum sip_auth_type auth_type;  /*!< Authentication type */
        const char *replaces;       /*!< Replaces header for call transfers */
        int transfer;               /*!< Flag - is this Invite part of a SIP transfer? (invite/replaces) */
+       struct sip_proxy *outboundproxy; /*!< Outbound proxy URI */
 };
 
 /*! \brief Structure to save routing information for a SIP session */