From 31f17abe449c2a9b43ef4e820792fb52d4b27d7a Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 19 May 2016 15:56:26 -0400 Subject: [PATCH] res_pjsip: add "via_addr", "via_port", "call_id" to contact As res_pjsip_nat rewrites contact's address, only the last Via header can contain the source address of registered endpoint. Also Call-Id header may contain the source address of registered endpoint. Added "via_addr", "via_port", "call_id" to contact. Added new fields ViaAddress, CallID to AMI event ContactStatus. ASTERISK-26011 Change-Id: I36bcc0bf422b3e0623680152d80486aeafe4c576 --- CHANGES | 6 ++++ ...184_res_pjsip_add_contact_via_addr_and_.py | 25 +++++++++++++++ include/asterisk/res_pjsip.h | 8 +++++ main/stasis_endpoints.c | 6 ++++ res/res_pjsip.c | 28 ++++++++++++++++ res/res_pjsip/location.c | 17 ++++++++++ res/res_pjsip/pjsip_options.c | 10 ++++++ res/res_pjsip_registrar.c | 32 +++++++++++++++++-- 8 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py diff --git a/CHANGES b/CHANGES index 281cff393c..7b129e03ad 100644 --- a/CHANGES +++ b/CHANGES @@ -328,6 +328,12 @@ res_fax res_pjsip ------------------ + * Added "via_addr", "via_port", "call_id" to contacts. + As res_pjsip_nat rewrites contact's address, only the last Via header + can contain the source address of registered endpoint. + Also Call-Id header may contain the source address of registered endpoint. + Added new fields ViaAddress,CallID to AMI event ContactStatus + * Endpoint IP Access Controls Added new configuration Endpoint options: "acl" - list of IP ACL section names in acl.conf diff --git a/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py b/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py new file mode 100644 index 0000000000..893d9d82e7 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py @@ -0,0 +1,25 @@ +"""res_pjsip: add contact via_addr and callid + +Revision ID: a845e4d8ade8 +Revises: bca7113d796f +Create Date: 2016-05-19 15:51:33.410852 + +""" + +# revision identifiers, used by Alembic. +revision = 'a845e4d8ade8' +down_revision = 'bca7113d796f' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_contacts', sa.Column('via_addr', sa.String(40))) + op.add_column('ps_contacts', sa.Column('via_port', sa.Integer)) + op.add_column('ps_contacts', sa.Column('call_id', sa.String(255))) + +def downgrade(): + op.drop_column('ps_contacts', 'via_addr') + op.drop_column('ps_contacts', 'via_port') + op.drop_column('ps_contacts', 'call_id') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index cf8c719d5b..50d02d9808 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -250,6 +250,12 @@ struct ast_sip_contact { struct ast_sip_endpoint *endpoint; /*! Asterisk Server name */ AST_STRING_FIELD_EXTENDED(reg_server); + /*! IP-address of the Via header in REGISTER request */ + AST_STRING_FIELD_EXTENDED(via_addr); + /* Port of the Via header in REGISTER request */ + int via_port; + /*! Content of the Call-ID header in REGISTER request */ + AST_STRING_FIELD_EXTENDED(call_id); }; #define CONTACT_STATUS "contact_status" @@ -1093,6 +1099,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na */ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint); /*! @@ -1114,6 +1121,7 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, */ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint); /*! diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 14d3d0ca1e..2d114210b7 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -104,6 +104,12 @@ ASTERISK_REGISTER_FILE() Absolute time that this contact is no longer valid after + + IP address:port of the last Via header in REGISTER request + + + Content of the Call-ID header in REGISTER request + diff --git a/res/res_pjsip.c b/res/res_pjsip.c index bebe941b51..8fc3c530e1 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1175,6 +1175,28 @@ Asterisk Server name on which SIP endpoint registered. + + IP-address of the last Via header from registration. + + The last Via header should contain the address of UA which sent the request. + The IP-address of the last Via header is automatically stored based on data present + in incoming SIP REGISTER requests and is not intended to be configured manually. + + + + IP-port of the last Via header from registration. + + The IP-port of the last Via header is automatically stored based on data present + in incoming SIP REGISTER requests and is not intended to be configured manually. + + + + Call-ID header from registration. + + The Call-ID header is automatically stored based on data present + in incoming SIP REGISTER requests and is not intended to be configured manually. + + The configuration for a location of an endpoint @@ -1967,6 +1989,12 @@ Absolute time that this contact is no longer valid after + + IP address:port of the last Via header in REGISTER request + + + Content of the Call-ID header in REGISTER request + diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index fd6db6edc1..43e6ea40f4 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -121,6 +121,8 @@ static void *contact_alloc(const char *name) } ast_string_field_init_extended(contact, reg_server); + ast_string_field_init_extended(contact, via_addr); + ast_string_field_init_extended(contact, call_id); /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { @@ -303,6 +305,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { char name[MAX_OBJECT_FIELD * 2 + 3]; @@ -337,6 +340,15 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME); } + if (!ast_strlen_zero(via_addr)) { + ast_string_field_set(contact, via_addr, via_addr); + } + contact->via_port = via_port; + + if (!ast_strlen_zero(call_id)) { + ast_string_field_set(contact, call_id, call_id); + } + contact->endpoint = ao2_bump(endpoint); return ast_sorcery_create(ast_sip_get_sorcery(), contact); @@ -344,6 +356,7 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { int res; @@ -356,6 +369,7 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, ao2_wrlock(lock); res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent, + via_addr, via_port, call_id, endpoint); ao2_unlock(lock); ast_named_lock_put(lock); @@ -1120,6 +1134,9 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); + ast_sorcery_object_field_register(sorcery, "contact", "via_addr", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, via_addr)); + ast_sorcery_object_field_register(sorcery, "contact", "via_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact, via_port)); + ast_sorcery_object_field_register(sorcery, "contact", "call_id", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, call_id)); ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration)); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 62640fe4e6..1114336bd0 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1156,6 +1156,16 @@ static int format_contact_status(void *obj, void *arg, int flags) ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent); ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec); + if (!ast_strlen_zero(contact->via_addr)) { + ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr); + if (contact->via_port) { + ast_str_append(&buf, 0, ":%d", contact->via_port); + } + ast_str_append(&buf, 0, "\r\n"); + } + if (!ast_strlen_zero(contact->call_id)) { + ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id); + } ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status)); if (status->status == UNKNOWN) { ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index cbc33ab80f..0e14ab7868 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -447,6 +447,13 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co char *user_agent = NULL; pjsip_user_agent_hdr *user_agent_hdr; pjsip_expires_hdr *expires_hdr; + pjsip_via_hdr *via_hdr; + pjsip_via_hdr *via_hdr_last; + char *via_addr = NULL; + int via_port = 0; + pjsip_cid_hdr *call_id_hdr; + char *call_id = NULL; + size_t alloc_size; /* 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); @@ -484,11 +491,32 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co user_agent_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &USER_AGENT, NULL); if (user_agent_hdr) { - size_t alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; + alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; user_agent = ast_alloca(alloc_size); ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size); } + /* Find the first Via header */ + via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_VIA, NULL); + if (via_hdr) { + /* Find the last Via header */ + while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, + PJSIP_H_VIA, via_hdr->next)) != NULL) { + via_hdr_last = via_hdr; + } + alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1; + via_addr = ast_alloca(alloc_size); + ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size); + via_port=via_hdr_last->sent_by.port; + } + + call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); + if (call_id_hdr) { + alloc_size = pj_strlen(&call_id_hdr->id) + 1; + call_id = ast_alloca(alloc_size); + ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size); + } + /* Iterate each provided Contact header and add, update, or delete */ while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { int expiration; @@ -520,7 +548,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co if (ast_sip_location_add_contact_nolock(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, - user_agent, task_data->endpoint)) { + user_agent, via_addr, via_port, call_id, task_data->endpoint)) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", contact_uri, aor_name); continue;