diff options
author | Timo Teräs <timo.teras@iki.fi> | 2012-09-06 13:06:43 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2012-09-06 13:06:43 +0300 |
commit | 155faf6352fbfcfeffd6d0234979e709b49e7b47 (patch) | |
tree | de2edd061534c34d1572a6e9d9b8a6628969e770 | |
parent | b4f7e56a38e724e9430ff272fce150f01182a3e3 (diff) | |
download | aports-155faf6352fbfcfeffd6d0234979e709b49e7b47.tar.bz2 aports-155faf6352fbfcfeffd6d0234979e709b49e7b47.tar.xz |
main/asterisk: cherry-pick bugfix for ASTERISK-13456 from Asterisk 11
An annying bug that can cause incoming SIP calls for a registered
number to be associated with wrong peer entry. This can also have
security implications on some systems.
-rw-r--r-- | main/asterisk/APKBUILD | 4 | ||||
-rw-r--r-- | main/asterisk/ASTERISK-13456.patch | 363 |
2 files changed, 366 insertions, 1 deletions
diff --git a/main/asterisk/APKBUILD b/main/asterisk/APKBUILD index ee0b4c976e..481600c395 100644 --- a/main/asterisk/APKBUILD +++ b/main/asterisk/APKBUILD @@ -2,7 +2,7 @@ # Maintainer: Timo Teras <timo.teras@iki.fi> pkgname=asterisk pkgver=10.7.1 -pkgrel=0 +pkgrel=1 pkgdesc="Asterisk: A Module Open Source PBX System" pkgusers="asterisk" pkggroups="asterisk" @@ -23,6 +23,7 @@ source="http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-$ 100-uclibc-daemon.patch 101-caps-uclibc.patch 900-tryinclude.patch + ASTERISK-13456.patch ASTERISK-18977.patch ASTERISK-18995.patch ASTERISK-19109.patch @@ -185,6 +186,7 @@ md5sums="dcf0a017e2644c459f700d0df334f37d asterisk-10.7.1.tar.gz b00c9d98ce2ad445501248a197c6e436 100-uclibc-daemon.patch 6e1129e30c4fd2c25c86c81685a485a9 101-caps-uclibc.patch b794636266cc573f0dda730fba634567 900-tryinclude.patch +d582e71b6992e4b6bfe6975bbe8f75be ASTERISK-13456.patch 1ddadef41aa7120e168738b6f3ed8917 ASTERISK-18977.patch bc6713f5434e07b79d3afdd155461d72 ASTERISK-18995.patch a22bb1d513d026564cb40ec213b1ae7f ASTERISK-19109.patch diff --git a/main/asterisk/ASTERISK-13456.patch b/main/asterisk/ASTERISK-13456.patch new file mode 100644 index 0000000000..d6e579ba03 --- /dev/null +++ b/main/asterisk/ASTERISK-13456.patch @@ -0,0 +1,363 @@ +Add callbackextension matching & realtime callbackextensions + +This patch is based on the one by David Vossel, developer extrodinaire, at +https://reviewboard.asterisk.org/r/344/. If multiple peers are defined with the +same host/port, but differing callbackextensions, it chooses the peer with the +matching callbackextension. Since callbackextension creates an outbound +registration with the callbackextension as the Contact address, matching an +incoming request by that (in addition to the host/port) makes a lot of sense. + +This patch also adds support for callbackextension to realtime by querying all +peers with callbackextensions on reload and adding registrations for them. + +(closes issue ASTERISK-13456) +Review: https://reviewboard.asterisk.org/r/344/ +Review: https://reviewboard.asterisk.org/r/1717/ + +diff --git a/CHANGES b/CHANGES +index de18858..6a22ae2 100644 +--- a/CHANGES ++++ b/CHANGES +@@ -24,6 +24,12 @@ SIP Changes + The LastMsgsSent value has been re-added with the same functionality as in + previous versions of Asterisk. + ++ * Add support to realtime for the 'callbackextension' option ++ * When multiple peers exist with the same address, but differing ++ callbackextension options, incoming requests that are matched by address ++ will be matched to the peer with the matching callbackextension if it is ++ available. ++ + ------------------------------------------------------------------------------ + --- Functionality changes since Asterisk 10.3.0 ------------------------------ + ------------------------------------------------------------------------------ +diff --git a/channels/chan_sip.c b/channels/chan_sip.c +index 41fb935..ad8da22 100644 +--- a/channels/chan_sip.c ++++ b/channels/chan_sip.c +@@ -1456,13 +1456,14 @@ static void destroy_association(struct sip_peer *peer); + static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno); + static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v); + static void set_socket_transport(struct sip_socket *socket, int transport); ++static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags); + + /* Realtime device support */ + static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms); + static void update_peer(struct sip_peer *p, int expire); + static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config); + static const char *get_name_from_variable(const struct ast_variable *var); +-static struct sip_peer *realtime_peer(const char *peername, struct ast_sockaddr *sin, int devstate_only, int which_objects); ++static struct sip_peer *realtime_peer(const char *peername, struct ast_sockaddr *sin, char *callbackexten, int devstate_only, int which_objects); + static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); + + /*--- Internal UA client handling (outbound registrations) */ +@@ -4891,7 +4892,7 @@ static struct ast_variable *realtime_peer_get_sippeer_helper(const char **name, + /* If varregs is NULL, we don't use sipregs. If we return true, then *name is + * set. Using empty if-bodies instead of goto's while avoiding unnecessary + * indents. */ +-static int realtime_peer_by_addr(const char **name, struct ast_sockaddr *addr, const char *ipaddr, struct ast_variable **var, struct ast_variable **varregs) ++static int realtime_peer_by_addr(const char **name, struct ast_sockaddr *addr, const char *ipaddr, const char *callbackexten, struct ast_variable **var, struct ast_variable **varregs) + { + char portstring[6]; /* up to 5 digits plus null terminator */ + ast_copy_string(portstring, ast_sockaddr_stringify_port(addr), sizeof(portstring)); +@@ -4899,8 +4900,11 @@ static int realtime_peer_by_addr(const char **name, struct ast_sockaddr *addr, c + /* We're not finding this peer by this name anymore. Reset it. */ + *name = NULL; + +- /* First check for fixed IP hosts */ +- if ((*var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL))) { ++ /* First check for fixed IP hosts with matching callbackextensions, if specified */ ++ if (!ast_strlen_zero(callbackexten) && (*var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, "callbackextension", callbackexten, SENTINEL))) { ++ ; ++ /* Check for fixed IP hosts */ ++ } else if ((*var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL))) { + ; + /* Check for registered hosts (in sipregs) */ + } else if (varregs && (*varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, SENTINEL)) && +@@ -4951,6 +4955,38 @@ static int realtime_peer_by_addr(const char **name, struct ast_sockaddr *addr, c + return 1; + } + ++static int register_realtime_peers_with_callbackextens(void) ++{ ++ struct ast_config *cfg; ++ char *cat = NULL; ++ ++ if (!(ast_check_realtime("sippeers"))) { ++ return 0; ++ } ++ ++ /* This is hacky. We want name to be the cat, so it is the first property */ ++ if (!(cfg = ast_load_realtime_multientry("sippeers", "name LIKE", "%", "callbackextension LIKE", "%", SENTINEL))) { ++ return -1; ++ } ++ ++ while ((cat = ast_category_browse(cfg, cat))) { ++ struct sip_peer *peer; ++ struct ast_variable *var = ast_category_root(cfg, cat); ++ ++ if (!(peer = build_peer(cat, var, NULL, TRUE, FALSE))) { ++ continue; ++ } ++ ast_log(LOG_NOTICE, "Created realtime peer '%s' for registration\n", peer->name); ++ ++ peer->is_realtime = 1; ++ sip_unref_peer(peer, "register_realtime_peers: Done registering releasing"); ++ } ++ ++ ast_config_destroy(cfg); ++ ++ return 0; ++} ++ + /*! \brief realtime_peer: Get peer from realtime storage + * Checks the "sippeers" realtime family from extconfig.conf + * Checks the "sipregs" realtime family from extconfig.conf if it's configured. +@@ -4960,7 +4996,7 @@ static int realtime_peer_by_addr(const char **name, struct ast_sockaddr *addr, c + * \note This is never called with both newpeername and addr at the same time. + * If you do, be prepared to get a peer with a different name than newpeername. + */ +-static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockaddr *addr, int devstate_only, int which_objects) ++static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockaddr *addr, char *callbackexten, int devstate_only, int which_objects) + { + struct sip_peer *peer = NULL; + struct ast_variable *var = NULL; +@@ -4976,7 +5012,7 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct ast_sockad + + if (newpeername && realtime_peer_by_name(&newpeername, addr, ipaddr, &var, realtimeregs ? &varregs : NULL)) { + ; +- } else if (addr && realtime_peer_by_addr(&newpeername, addr, ipaddr, &var, realtimeregs ? &varregs : NULL)) { ++ } else if (addr && realtime_peer_by_addr(&newpeername, addr, ipaddr, callbackexten, &var, realtimeregs ? &varregs : NULL)) { + ; + } else { + return NULL; +@@ -5052,20 +5088,7 @@ static int find_by_name(void *obj, void *arg, void *data, int flags) + return CMP_MATCH | CMP_STOP; + } + +-/*! +- * \brief Locate device by name or ip address +- * \param peer, sin, realtime, devstate_only, transport +- * \param which_objects Define which objects should be matched when doing a lookup +- * by name. Valid options are FINDUSERS, FINDPEERS, or FINDALLDEVICES. +- * Note that this option is not used at all when doing a lookup by IP. +- * +- * This is used on find matching device on name or ip/port. +- * If the device was declared as type=peer, we don't match on peer name on incoming INVITEs. +- * +- * \note Avoid using this function in new functions if there is a way to avoid it, +- * since it might cause a database lookup. +- */ +-struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int which_objects, int devstate_only, int transport) ++static struct sip_peer *sip_find_peer_full(const char *peer, struct ast_sockaddr *addr, char *callbackexten, int realtime, int which_objects, int devstate_only, int transport) + { + struct sip_peer *p = NULL; + struct sip_peer tmp_peer; +@@ -5077,10 +5100,10 @@ struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int + ast_sockaddr_copy(&tmp_peer.addr, addr); + tmp_peer.flags[0].flags = 0; + tmp_peer.transports = transport; +- p = ao2_t_find(peers_by_ip, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_ip table"); /* WAS: p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); */ ++ p = ao2_t_callback_data(peers_by_ip, OBJ_POINTER, peer_ipcmp_cb_full, &tmp_peer, callbackexten, "ao2_find in peers_by_ip table"); + if (!p) { + ast_set_flag(&tmp_peer.flags[0], SIP_INSECURE_PORT); +- p = ao2_t_find(peers_by_ip, &tmp_peer, OBJ_POINTER, "ao2_find in peers_by_ip table 2"); /* WAS: p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); */ ++ p = ao2_t_callback_data(peers_by_ip, OBJ_POINTER, peer_ipcmp_cb_full, &tmp_peer, callbackexten, "ao2_find in peers_by_ip table 2"); + if (p) { + return p; + } +@@ -5088,7 +5111,9 @@ struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int + } + + if (!p && (realtime || devstate_only)) { +- p = realtime_peer(peer, addr, devstate_only, which_objects); ++ /* realtime_peer will return a peer with matching callbackexten if possible, otherwise one matching ++ * without the callbackexten */ ++ p = realtime_peer(peer, addr, callbackexten, devstate_only, which_objects); + if (p) { + switch (which_objects) { + case FINDUSERS: +@@ -5112,6 +5137,29 @@ struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int + return p; + } + ++/*! ++ * \brief Locate device by name or ip address ++ * \param peer, sin, realtime, devstate_only, transport ++ * \param which_objects Define which objects should be matched when doing a lookup ++ * by name. Valid options are FINDUSERS, FINDPEERS, or FINDALLDEVICES. ++ * Note that this option is not used at all when doing a lookup by IP. ++ * ++ * This is used on find matching device on name or ip/port. ++ * If the device was declared as type=peer, we don't match on peer name on incoming INVITEs. ++ * ++ * \note Avoid using this function in new functions if there is a way to avoid it, ++ * since it might cause a database lookup. ++ */ ++struct sip_peer *sip_find_peer(const char *peer, struct ast_sockaddr *addr, int realtime, int which_objects, int devstate_only, int transport) ++{ ++ return sip_find_peer_full(peer, addr, NULL, realtime, which_objects, devstate_only, transport); ++} ++ ++static struct sip_peer *sip_find_peer_by_ip_and_exten(struct ast_sockaddr *addr, char *callbackexten, int transport) ++{ ++ return sip_find_peer_full(NULL, addr, callbackexten, TRUE, FINDPEERS, FALSE, transport); ++} ++ + /*! \brief Set nat mode on the various data sockets */ + static void do_setnat(struct sip_pvt *p) + { +@@ -8418,16 +8466,16 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a + /*! \brief create sip_registry object from register=> line in sip.conf and link into reg container */ + static int sip_register(const char *value, int lineno) + { +- struct sip_registry *reg; ++ struct sip_registry *reg, *tmp; + + if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { + ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n"); + return -1; + } + +- ast_atomic_fetchadd_int(®objs, 1); + ASTOBJ_INIT(reg); + ++ ast_copy_string(reg->name, value, sizeof(reg->name)); + if (sip_parse_register_line(reg, default_expiry, value, lineno)) { + registry_unref(reg, "failure to parse, unref the reg pointer"); + return -1; +@@ -8438,8 +8486,13 @@ static int sip_register(const char *value, int lineno) + reg->refresh = reg->expiry = reg->configured_expiry = default_expiry; + } + +- /* Add the new registry entry to the list */ +- ASTOBJ_CONTAINER_LINK(®l, reg); ++ /* Add the new registry entry to the list, but only if it isn't already there */ ++ if ((tmp = ASTOBJ_CONTAINER_FIND(®l, reg->name))) { ++ registry_unref(tmp, "throw away found registry"); ++ } else { ++ ast_atomic_fetchadd_int(®objs, 1); ++ ASTOBJ_CONTAINER_LINK(®l, reg); ++ } + + /* release the reference given by ASTOBJ_INIT. The container has another reference */ + registry_unref(reg, "unref the reg pointer"); +@@ -16433,7 +16486,14 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, + + /* Then find devices based on IP */ + if (!peer) { +- peer = sip_find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type); ++ char *uri_tmp, *callback = NULL, *dummy; ++ uri_tmp = ast_strdupa(uri2); ++ parse_uri(uri_tmp, "sip:,sips:", &callback, &dummy, &dummy, &dummy); ++ if (!ast_strlen_zero(callback) && (peer = sip_find_peer_by_ip_and_exten(&p->recv, callback, p->socket.type))) { ++ ; /* found, fall through */ ++ } else { ++ peer = sip_find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type); ++ } + } + } + +@@ -28283,7 +28343,6 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str + time_t regseconds = 0; + struct ast_flags peerflags[3] = {{(0)}}; + struct ast_flags mask[3] = {{(0)}}; +- char callback[256] = ""; + struct sip_peer tmp_peer; + const char *srvlookup = NULL; + static int deprecation_warning = 1; +@@ -28588,7 +28647,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str + } else if (!strcasecmp(v->name, "regexten")) { + ast_string_field_set(peer, regexten, v->value); + } else if (!strcasecmp(v->name, "callbackextension")) { +- ast_copy_string(callback, v->value, sizeof(callback)); ++ ast_string_field_set(peer, callback, v->value); + } else if (!strcasecmp(v->name, "amaflags")) { + format = ast_cdr_amaflags2int(v->value); + if (format < 0) { +@@ -28960,9 +29019,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str + + ast_free_ha(oldha); + ast_free_ha(olddirectmediaha); +- if (!ast_strlen_zero(callback)) { /* build string from peer info */ ++ if (!ast_strlen_zero(peer->callback)) { /* build string from peer info */ + char *reg_string; +- if (asprintf(®_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, callback) < 0) { ++ if (asprintf(®_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, peer->callback) < 0) { + ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); + } else if (reg_string) { + sip_register(reg_string, 0); /* XXX TODO: count in registry_count */ +@@ -30116,6 +30175,8 @@ static int reload_config(enum channelreloadreason reason) + /* Release configuration from memory */ + ast_config_destroy(cfg); + ++ register_realtime_peers_with_callbackextens(); ++ + /* Load the list of manual NOTIFY types to support */ + if (notify_types) { + ast_config_destroy(notify_types); +@@ -31013,9 +31074,17 @@ static int peer_iphash_cb(const void *obj, const int flags) + * + * \note the peer's addr struct provides to fields combined to make a key: the sin_addr.s_addr and sin_port fields. + */ +-static int peer_ipcmp_cb(void *obj, void *arg, int flags) ++static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags) + { + struct sip_peer *peer = obj, *peer2 = arg; ++ char *callback = data; ++ ++ if (!ast_strlen_zero(callback) && strcasecmp(peer->callback, callback)) { ++ /* We require a callback extension match, but don't have one */ ++ return 0; ++ } ++ ++ /* At this point, we match the callback extension if we need to. Carry on. */ + + if (ast_sockaddr_cmp_addr(&peer->addr, &peer2->addr)) { + /* IP doesn't match */ +@@ -31038,6 +31107,10 @@ static int peer_ipcmp_cb(void *obj, void *arg, int flags) + (CMP_MATCH | CMP_STOP) : 0; + } + ++static int peer_ipcmp_cb(void *obj, void *arg, int flags) ++{ ++ return peer_ipcmp_cb_full(obj, arg, NULL, flags); ++} + + static int threadt_hash_cb(const void *obj, const int flags) + { +diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h +index ab2ed1b..48626aa 100644 +--- a/channels/sip/include/sip.h ++++ b/channels/sip/include/sip.h +@@ -1246,6 +1246,7 @@ struct sip_peer { + AST_STRING_FIELD(mwi_from); /*!< Name to place in From header for outgoing NOTIFY requests */ + AST_STRING_FIELD(engine); /*!< RTP Engine to use */ + AST_STRING_FIELD(unsolicited_mailbox); /*!< Mailbox to store received unsolicited MWI NOTIFY messages information in */ ++ AST_STRING_FIELD(callback); /*!< Callback extension */ + ); + struct sip_socket socket; /*!< Socket used for this peer */ + enum sip_transport default_outbound_transport; /*!< Peer Registration may change the default outbound transport. +@@ -1331,7 +1332,7 @@ struct sip_peer { + * \todo Convert this to astobj2 + */ + struct sip_registry { +- ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1); ++ ASTOBJ_COMPONENTS_FULL(struct sip_registry, 80, 1); + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(callid); /*!< Global Call-ID */ + AST_STRING_FIELD(realm); /*!< Authorization realm */ +diff --git a/contrib/realtime/postgresql/realtime.sql b/contrib/realtime/postgresql/realtime.sql +index f14cd79..7b8dcec 100644 +--- a/contrib/realtime/postgresql/realtime.sql ++++ b/contrib/realtime/postgresql/realtime.sql +@@ -72,7 +72,8 @@ lastms integer DEFAULT 0 NOT NULL, + defaultuser character varying(80), + fullcontact character varying(80), + regserver character varying(30), +-useragent character varying(40) ++useragent character varying(40), ++callbackextension character varying(40) + ); + + drop table voicemail_users; |