aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2012-09-06 13:06:43 +0300
committerTimo Teräs <timo.teras@iki.fi>2012-09-06 13:06:43 +0300
commit155faf6352fbfcfeffd6d0234979e709b49e7b47 (patch)
treede2edd061534c34d1572a6e9d9b8a6628969e770
parentb4f7e56a38e724e9430ff272fce150f01182a3e3 (diff)
downloadaports-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/APKBUILD4
-rw-r--r--main/asterisk/ASTERISK-13456.patch363
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(&regobjs, 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(&regl, reg);
++ /* Add the new registry entry to the list, but only if it isn't already there */
++ if ((tmp = ASTOBJ_CONTAINER_FIND(&regl, reg->name))) {
++ registry_unref(tmp, "throw away found registry");
++ } else {
++ ast_atomic_fetchadd_int(&regobjs, 1);
++ ASTOBJ_CONTAINER_LINK(&regl, 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(&reg_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(&reg_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;