diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 08eb71bfe1..bd80394ec1 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1537,7 +1537,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); @@ -1960,7 +1960,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; @@ -3135,6 +3135,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. @@ -3152,6 +3198,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"); @@ -5426,7 +5478,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; @@ -5457,9 +5509,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; @@ -5818,8 +5867,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); @@ -12205,7 +12258,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"); @@ -12518,7 +12571,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; @@ -13003,7 +13056,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" ); @@ -13347,7 +13400,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); @@ -19339,7 +19392,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" ); @@ -20823,6 +20876,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; } @@ -24398,7 +24454,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"); @@ -26937,7 +26993,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); @@ -27045,15 +27100,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(&remote_address_sa, remote_address, 0)) { - 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); } } @@ -27064,7 +27113,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); @@ -27875,39 +27924,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 *tok, *proxyname; - + 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.", v->lineno); + ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf\n", v->lineno); continue; } - - peer->outboundproxy = - ao2_alloc(sizeof(*peer->outboundproxy), NULL); - - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - - sip_parse_host(tok, v->lineno, &proxyname, - &peer->outboundproxy->port, - &peer->outboundproxy->transport); - - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - - if ((tok = strtok(NULL, ","))) { - peer->outboundproxy->force = !strncasecmp(ast_skip_blanks(tok), "force", 5); - } else { - peer->outboundproxy->force = FALSE; - } - - if (ast_strlen_zero(proxyname)) { - ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf.", 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 */ @@ -28854,34 +28881,16 @@ static int reload_config(enum channelreloadreason reason) default_fromdomainport = STANDARD_SIP_PORT; } } else if (!strcasecmp(v->name, "outboundproxy")) { - char *tok, *proxyname; - + 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.", v->lineno); + ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf\n", v->lineno); continue; } - - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - - sip_parse_host(tok, v->lineno, &proxyname, - &sip_cfg.outboundproxy.port, - &sip_cfg.outboundproxy.transport); - - if ((tok = strtok(NULL, ","))) { - sip_cfg.outboundproxy.force = !strncasecmp(ast_skip_blanks(tok), "force", 5); - } else { - sip_cfg.outboundproxy.force = FALSE; - } - - if (ast_strlen_zero(proxyname)) { - ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf.", 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")) { diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 72a7b2c7d0..c26e4960cc 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -643,14 +643,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; @@ -662,14 +665,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; } } diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index b69fa0aaa5..f839cf0b0f 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -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 */