summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/res_pjsip.h18
-rw-r--r--res/res_pjsip.exports.in2
-rw-r--r--res/res_pjsip/security_events.c56
-rw-r--r--res/res_pjsip_registrar.c343
4 files changed, 339 insertions, 80 deletions
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 354e8a7a5..9ba2e90c7 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -1478,6 +1478,24 @@ void ast_sip_report_auth_success(struct ast_sip_endpoint *endpoint, pjsip_rx_dat
*/
void ast_sip_report_auth_challenge_sent(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata);
+/*!
+ * \brief Send a security event notification for when a request is not supported
+ *
+ * \param endpoint Pointer to the endpoint in use
+ * \param rdata Received message
+ * \param req_type the type of request
+ */
+void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
+ const char* req_type);
+
+/*!
+ * \brief Send a security event notification for when a memory limit is hit.
+ *
+ * \param endpoint Pointer to the endpoint in use
+ * \param rdata Received message
+ */
+void ast_sip_report_mem_limit(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
+
void ast_sip_initialize_global_headers(void);
void ast_sip_destroy_global_headers(void);
diff --git a/res/res_pjsip.exports.in b/res/res_pjsip.exports.in
index a4b23bc7e..d896ee60d 100644
--- a/res/res_pjsip.exports.in
+++ b/res/res_pjsip.exports.in
@@ -61,6 +61,8 @@
LINKER_SYMBOL_PREFIXast_sip_report_auth_failed_challenge_response;
LINKER_SYMBOL_PREFIXast_sip_report_auth_success;
LINKER_SYMBOL_PREFIXast_sip_report_auth_challenge_sent;
+ LINKER_SYMBOL_PREFIXast_sip_report_req_no_support;
+ LINKER_SYMBOL_PREFIXast_sip_report_mem_limit;
LINKER_SYMBOL_PREFIXast_sip_initialize_global_headers;
LINKER_SYMBOL_PREFIXast_sip_destroy_global_headers;
LINKER_SYMBOL_PREFIXast_sip_add_global_request_header;
diff --git a/res/res_pjsip/security_events.c b/res/res_pjsip/security_events.c
index 7b4913753..6bdb6cb39 100644
--- a/res/res_pjsip/security_events.c
+++ b/res/res_pjsip/security_events.c
@@ -232,3 +232,59 @@ void ast_sip_report_auth_challenge_sent(struct ast_sip_endpoint *endpoint, pjsip
ast_security_event_report(AST_SEC_EVT(&chal_sent));
}
+
+void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
+ const char* req_type)
+{
+ enum ast_transport transport = security_event_get_transport(rdata);
+ char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
+ struct ast_sockaddr local, remote;
+
+ struct ast_security_event_req_no_support req_no_support_event = {
+ .common.event_type = AST_SECURITY_EVENT_REQ_NO_SUPPORT,
+ .common.version = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION,
+ .common.service = "PJSIP",
+ .common.account_id = ast_sorcery_object_get_id(endpoint),
+ .common.local_addr = {
+ .addr = &local,
+ .transport = transport,
+ },
+ .common.remote_addr = {
+ .addr = &remote,
+ .transport = transport,
+ },
+ .common.session_id = call_id,
+ .request_type = req_type
+ };
+
+ security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
+
+ ast_security_event_report(AST_SEC_EVT(&req_no_support_event));
+}
+
+void ast_sip_report_mem_limit(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+{
+ enum ast_transport transport = security_event_get_transport(rdata);
+ char call_id[pj_strlen(&rdata->msg_info.cid->id) + 1];
+ struct ast_sockaddr local, remote;
+
+ struct ast_security_event_mem_limit mem_limit_event = {
+ .common.event_type = AST_SECURITY_EVENT_MEM_LIMIT,
+ .common.version = AST_SECURITY_EVENT_MEM_LIMIT_VERSION,
+ .common.service = "PJSIP",
+ .common.account_id = ast_sorcery_object_get_id(endpoint),
+ .common.local_addr = {
+ .addr = &local,
+ .transport = transport,
+ },
+ .common.remote_addr = {
+ .addr = &remote,
+ .transport = transport,
+ },
+ .common.session_id = call_id
+ };
+
+ security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote);
+
+ ast_security_event_report(AST_SEC_EVT(&mem_limit_event));
+}
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index 0cee19ed7..143f96d79 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -30,6 +30,7 @@
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
#include "asterisk/test.h"
+#include "asterisk/taskprocessor.h"
/*! \brief Internal function which returns the expiration time for a contact */
static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
@@ -188,122 +189,195 @@ static void registrar_add_date_header(pjsip_tx_data *tdata)
ast_sip_add_header(tdata, "Date", date);
}
-static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
+#define SERIALIZER_BUCKETS 59
+
+static struct ao2_container *serializers;
+
+/*! \brief Serializer with associated aor key */
+struct serializer {
+ /* Serializer to distribute tasks to */
+ struct ast_taskprocessor *serializer;
+ /* The name of the aor to associate with the serializer */
+ char aor_name[0];
+};
+
+static void serializer_destroy(void *obj)
{
- struct ast_sip_endpoint *endpoint = ast_pjsip_rdata_get_endpoint(rdata);
- pjsip_sip_uri *uri;
- char user_name[64], domain_name[64];
- char *configured_aors, *aor_name;
- RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
- RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
- int added = 0, updated = 0, deleted = 0;
- pjsip_contact_hdr *contact_hdr = NULL;
- struct registrar_contact_details details = { 0, };
- pjsip_tx_data *tdata;
- pjsip_response_addr addr;
+ struct serializer *ser = obj;
- if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
- return PJ_FALSE;
- }
+ ast_taskprocessor_unreference(ser->serializer);
+}
- if (ast_strlen_zero(endpoint->aors)) {
- /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
- ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
- ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
- return PJ_TRUE;
+static struct serializer *serializer_create(const char *aor_name)
+{
+ size_t size = strlen(aor_name) + 1;
+ struct serializer *ser = ao2_alloc(
+ sizeof(*ser) + size, serializer_destroy);
+
+ if (!ser) {
+ return NULL;
}
- if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
- ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
- ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
- return PJ_TRUE;
+ if (!(ser->serializer = ast_sip_create_serializer())) {
+ ao2_ref(ser, -1);
+ return NULL;
}
- uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
- ast_copy_pj_str(user_name, &uri->user, sizeof(user_name));
- ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name));
+ strcpy(ser->aor_name, aor_name);
+ return ser;
+}
- configured_aors = ast_strdupa(endpoint->aors);
+static struct serializer *serializer_find_or_create(const char *aor_name)
+{
+ struct serializer *ser = ao2_find(serializers, aor_name, OBJ_SEARCH_KEY);
- /* Iterate the configured AORs to see if the user or the user+domain match */
- while ((aor_name = strsep(&configured_aors, ","))) {
- char id[AST_UUID_STR_LEN];
- RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
+ if (ser) {
+ return ser;
+ }
- snprintf(id, sizeof(id), "%s@%s", user_name, domain_name);
- if (!strcmp(aor_name, id)) {
- break;
- }
+ if (!(ser = serializer_create(aor_name))) {
+ return NULL;
+ }
- if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
- snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain);
- if (!strcmp(aor_name, id)) {
- break;
- }
- }
+ ao2_link(serializers, ser);
+ return ser;
+}
- if (!strcmp(aor_name, user_name)) {
- break;
- }
+static int serializer_hash(const void *obj, const int flags)
+{
+ const struct serializer *object;
+ const char *key;
+
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_KEY:
+ key = obj;
+ return ast_str_hash(key);
+ case OBJ_SEARCH_OBJECT:
+ object = obj;
+ return ast_str_hash(object->aor_name);
+ default:
+ /* Hash can only work on something with a full key. */
+ ast_assert(0);
+ return 0;
}
+}
- if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
- /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
- ast_sip_report_failed_acl(endpoint, rdata, "registrar_requested_aor_not_found");
- ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", user_name, ast_sorcery_object_get_id(endpoint));
- return PJ_TRUE;
+static int serializer_cmp(void *obj_left, void *obj_right, int flags)
+{
+ const struct serializer *object_left = obj_left;
+ const struct serializer *object_right = obj_right;
+ const char *right_key = obj_right;
+ int cmp;
+
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_OBJECT:
+ right_key = object_right->aor_name;
+ /* Fall through */
+ case OBJ_SEARCH_KEY:
+ cmp = strcmp(object_left->aor_name, right_key);
+ break;
+ case OBJ_SEARCH_PARTIAL_KEY:
+ /*
+ * We could also use a partial key struct containing a length
+ * so strlen() does not get called for every comparison instead.
+ */
+ cmp = strncmp(object_left->aor_name, right_key, strlen(right_key));
+ break;
+ default:
+ cmp = 0;
+ break;
}
- if (!aor->max_contacts) {
- /* Registration is not permitted for this AOR */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
- ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_registration_permitted");
- ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
- ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint));
- return PJ_TRUE;
+ return cmp ? 0 : CMP_MATCH;
+}
+
+struct rx_task_data {
+ pjsip_rx_data *rdata;
+ struct ast_sip_endpoint *endpoint;
+ struct ast_sip_aor *aor;
+};
+
+static void rx_task_data_destroy(void *obj)
+{
+ struct rx_task_data *task_data = obj;
+
+ pjsip_rx_data_free_cloned(task_data->rdata);
+ ao2_cleanup(task_data->endpoint);
+ ao2_cleanup(task_data->aor);
+}
+
+static struct rx_task_data *rx_task_data_create(pjsip_rx_data *rdata,
+ struct ast_sip_endpoint *endpoint,
+ struct ast_sip_aor *aor)
+{
+ struct rx_task_data *task_data = ao2_alloc(
+ sizeof(*task_data), rx_task_data_destroy);
+
+ if (!task_data) {
+ return NULL;
}
+ pjsip_rx_data_clone(rdata, 0, &task_data->rdata);
+
+ task_data->endpoint = endpoint;
+ ao2_ref(task_data->endpoint, +1);
+
+ task_data->aor = aor;
+ ao2_ref(task_data->aor, +1);
+
+ return task_data;
+}
+
+static int rx_task(void *data)
+{
+ RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+
+ int added = 0, updated = 0, deleted = 0;
+ pjsip_contact_hdr *contact_hdr = NULL;
+ struct registrar_contact_details details = { 0, };
+ pjsip_tx_data *tdata;
+ pjsip_response_addr addr;
+ const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
+
/* Retrieve the current contacts, we'll need to know whether to update or not */
- contacts = ast_sip_location_retrieve_aor_contacts(aor);
+ contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
/* So we don't count static contacts against max_contacts we prune them out from the container */
ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
- if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
+ if (registrar_validate_contacts(task_data->rdata, contacts, task_data->aor, &added, &updated, &deleted)) {
/* The provided Contact headers do not conform to the specification */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
- ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 400, NULL, NULL, NULL);
+ ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_invalid_contacts_provided");
ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
- ast_sorcery_object_get_id(endpoint));
+ ast_sorcery_object_get_id(task_data->endpoint));
return PJ_TRUE;
}
- if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
+ if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) {
/* Enforce the maximum number of contacts */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
- ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL);
+ ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %d\n",
- ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor), aor->max_contacts);
+ ast_sorcery_object_get_id(task_data->endpoint), ast_sorcery_object_get_id(task_data->aor), task_data->aor->max_contacts);
return PJ_TRUE;
}
if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 500, NULL, NULL, NULL);
return PJ_TRUE;
}
/* Iterate each provided Contact header and add, update, or delete */
- while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
+ while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
int expiration;
char contact_uri[PJSIP_MAX_URL_SIZE];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
if (contact_hdr->star) {
/* A star means to unregister everything, so do so for the possible contacts */
- ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, aor_name);
+ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
break;
}
@@ -312,7 +386,7 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
continue;
}
- expiration = registrar_get_expiration(aor, contact_hdr, rdata);
+ expiration = registrar_get_expiration(task_data->aor, contact_hdr, task_data->rdata);
details.uri = pjsip_uri_get_uri(contact_hdr->uri);
pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
@@ -324,7 +398,7 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
continue;
}
- ast_sip_location_add_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
+ ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
contact_uri, aor_name, expiration);
ast_test_suite_event_notify("AOR_CONTACT_ADDED",
@@ -337,8 +411,8 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
} else if (expiration) {
RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup);
updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
- updated->qualify_frequency = aor->qualify_frequency;
- updated->authenticate_qualify = aor->authenticate_qualify;
+ updated->qualify_frequency = task_data->aor->qualify_frequency;
+ updated->authenticate_qualify = task_data->aor->authenticate_qualify;
ast_sip_location_update_contact(updated);
ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
@@ -366,16 +440,16 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
/* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
* do so
*/
- if (aor->remove_existing) {
+ if (task_data->aor->remove_existing) {
ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
}
/* Update the contacts as things will probably have changed */
ao2_cleanup(contacts);
- contacts = ast_sip_location_retrieve_aor_contacts(aor);
+ contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
/* Send a response containing all of the contacts (including static) that are present on this AOR */
- if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 200, NULL, &tdata) != PJ_SUCCESS) {
+ if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), task_data->rdata, 200, NULL, &tdata) != PJ_SUCCESS) {
return PJ_TRUE;
}
@@ -384,7 +458,7 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
ao2_callback(contacts, 0, registrar_add_contact, tdata);
- if (pjsip_get_response_addr(tdata->pool, rdata, &addr) == PJ_SUCCESS) {
+ if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), &addr, tdata, NULL, NULL);
} else {
pjsip_tx_data_dec_ref(tdata);
@@ -393,6 +467,108 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
return PJ_TRUE;
}
+static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
+ struct rx_task_data *task_data;
+
+ RAII_VAR(struct ast_sip_endpoint *, endpoint,
+ ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
+ RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
+ pjsip_sip_uri *uri;
+ char user_name[64], domain_name[64];
+ char *configured_aors, *aor_name;
+
+ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
+ return PJ_FALSE;
+ }
+
+ if (ast_strlen_zero(endpoint->aors)) {
+ /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
+ ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
+ return PJ_TRUE;
+ }
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
+ ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
+ ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
+ return PJ_TRUE;
+ }
+
+ uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
+ ast_copy_pj_str(user_name, &uri->user, sizeof(user_name));
+ ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name));
+
+ configured_aors = ast_strdupa(endpoint->aors);
+
+ /* Iterate the configured AORs to see if the user or the user+domain match */
+ while ((aor_name = strsep(&configured_aors, ","))) {
+ char id[AST_UUID_STR_LEN];
+ RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
+
+ snprintf(id, sizeof(id), "%s@%s", user_name, domain_name);
+ if (!strcmp(aor_name, id)) {
+ break;
+ }
+
+ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
+ snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain);
+ if (!strcmp(aor_name, id)) {
+ break;
+ }
+ }
+
+ if (!strcmp(aor_name, user_name)) {
+ break;
+ }
+ }
+
+ if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
+ /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
+ ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
+ ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", user_name, ast_sorcery_object_get_id(endpoint));
+ return PJ_TRUE;
+ }
+
+ if (!aor->max_contacts) {
+ /* Registration is not permitted for this AOR */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
+ ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
+ ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint));
+ return PJ_TRUE;
+ }
+
+ if (!(ser = serializer_find_or_create(aor_name))) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ ast_sip_report_mem_limit(endpoint, rdata);
+ ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not get serializer\n",
+ ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
+ return PJ_TRUE;
+ }
+
+ if (!(task_data = rx_task_data_create(rdata, endpoint, aor))) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ ast_sip_report_mem_limit(endpoint, rdata);
+ ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not create rx_task_data\n",
+ ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
+ return PJ_TRUE;
+ }
+
+ if (ast_sip_push_task(ser->serializer, rx_task, task_data)) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ ast_sip_report_mem_limit(endpoint, rdata);
+ ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not serialize task\n",
+ ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
+ ao2_ref(task_data, -1);
+ }
+ return PJ_TRUE;
+}
+
static pjsip_module registrar_module = {
.name = { "Registrar", 9 },
.id = -1,
@@ -404,6 +580,11 @@ static int load_module(void)
{
const pj_str_t STR_REGISTER = { "REGISTER", 8 };
+ if (!(serializers = ao2_container_alloc(
+ SERIALIZER_BUCKETS, serializer_hash, serializer_cmp))) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
if (ast_sip_register_service(&registrar_module)) {
return AST_MODULE_LOAD_DECLINE;
}
@@ -419,6 +600,8 @@ static int load_module(void)
static int unload_module(void)
{
ast_sip_unregister_service(&registrar_module);
+
+ ao2_cleanup(serializers);
return 0;
}