From 775352ee6c2a5bcd4f0e3df51aee5d1b0abf4cbe Mon Sep 17 00:00:00 2001 From: Flole998 Date: Wed, 13 Dec 2023 14:28:15 +0000 Subject: [PATCH] res_pjsip_outbound_registration.c: Add User-Agent header override This introduces a setting for outbound registrations to override the global User-Agent header setting. Resolves: #515 UserNote: PJSIP outbound registrations now support a per-registration User-Agent header --- ...c12d8e9014_add_user_agent_header_to_ps_.py | 22 +++++++++++++ res/res_pjsip_outbound_registration.c | 31 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/24c12d8e9014_add_user_agent_header_to_ps_.py diff --git a/contrib/ast-db-manage/config/versions/24c12d8e9014_add_user_agent_header_to_ps_.py b/contrib/ast-db-manage/config/versions/24c12d8e9014_add_user_agent_header_to_ps_.py new file mode 100644 index 0000000000..f3a0d77c4f --- /dev/null +++ b/contrib/ast-db-manage/config/versions/24c12d8e9014_add_user_agent_header_to_ps_.py @@ -0,0 +1,22 @@ +"""add user-agent-header to ps_registrations + +Revision ID: 24c12d8e9014 +Revises: 37a5332640e2 +Create Date: 2024-01-05 14:14:47.510917 + +""" + +# revision identifiers, used by Alembic. +revision = '24c12d8e9014' +down_revision = '37a5332640e2' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_registrations', sa.Column('user_agent', sa.String(255))) + + +def downgrade(): + op.drop_column('ps_registrations', 'user_agent') diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index a1cd19373e..dc14cfc51d 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -209,6 +209,9 @@ Enables advertising SIP Outbound support (RFC5626) for outbound REGISTER requests. + + Overrides the User-Agent header that should be used for outbound REGISTER requests. + @@ -341,6 +344,8 @@ struct sip_outbound_registration { AST_STRING_FIELD(outbound_proxy); /*! \brief Endpoint to use for related incoming calls */ AST_STRING_FIELD(endpoint); + /*! \brief User-Agent to use when sending the REGISTER */ + AST_STRING_FIELD(user_agent); ); /*! \brief Requested expiration time */ unsigned int expiration; @@ -433,6 +438,8 @@ struct sip_outbound_registration_client_state { char *registration_name; /*! \brief Expected time of registration lapse/expiration */ unsigned int registration_expires; + /*! \brief The value for the User-Agent header sent in requests */ + char *user_agent; }; /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */ @@ -743,6 +750,27 @@ static pj_status_t registration_client_send(struct sip_outbound_registration_cli /* Add Security-Verify or Security-Client headers */ add_security_headers(client_state, tdata); + /* + * Replace the User-Agent header if a different one should be used + */ + if (!ast_strlen_zero(client_state->user_agent)) { + static const pj_str_t user_agent_str = { "User-Agent", 10 }; + pjsip_generic_string_hdr *default_user_agent_hdr; + pjsip_generic_string_hdr *user_agent_hdr; + pj_str_t user_agent_val; + default_user_agent_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &user_agent_str, NULL); + user_agent_val = pj_str(client_state->user_agent); + user_agent_hdr = pjsip_generic_string_hdr_create(tdata->pool, &user_agent_str, &user_agent_val); + if (!user_agent_hdr) { + ast_log(LOG_ERROR, "Could not add custom User-Agent to outbound registration %s, sending REGISTER request with non-custom header\n", client_state->registration_name); + } else { + if (default_user_agent_hdr) { + pj_list_erase(default_user_agent_hdr); + } + pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)user_agent_hdr); + } + } + /* * Set the transport in case transports were reloaded. * When pjproject removes the extraneous error messages produced, @@ -1520,6 +1548,7 @@ static void sip_outbound_registration_client_state_destroy(void *obj) ast_taskprocessor_unreference(client_state->serializer); ast_free(client_state->transport_name); ast_free(client_state->registration_name); + ast_free(client_state->user_agent); if (client_state->last_tdata) { pjsip_tx_data_dec_ref(client_state->last_tdata); } @@ -1548,6 +1577,7 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a state->client_state->transport_name = ast_strdup(registration->transport); state->client_state->registration_name = ast_strdup(ast_sorcery_object_get_id(registration)); + state->client_state->user_agent = ast_strdup(registration->user_agent); ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0); ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, @@ -2805,6 +2835,7 @@ static int load_module(void) ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "security_mechanisms", "", security_mechanisms_handler, security_mechanism_to_str, NULL, 0, 0); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint)); + ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, user_agent)); /* * Register sorcery observers.