chan_sip: Allow Asterisk to retry after 403 on register

This adds a global option in chan_sip to allow it to continue
attempting registration if a 403 is received, clearing the cached nonce
and treating it as a non-fatal response. Normally, this would cause
registration attempts to that endpoint to stop.

This also adds a similar per-outbound-registration option to chan_pjsip
which allows the retry interval to be altered for 403 responses to
REGISTER requests.

(closes issue ASTERISK-17138)
Review: https://reviewboard.asterisk.org/r/2874/
Reported by: Rudi
........

Merged revisions 400137 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 400140 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 400141 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400142 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kinsey Moore 2013-09-30 15:57:11 +00:00
parent a1d56da32a
commit b44ce141e5
5 changed files with 45 additions and 4 deletions

View File

@ -854,6 +854,10 @@ chan_sip
* Added 'ignore_requested_pref'. When enabled, this will use the preferred
codecs configured for a peer instead of the requested codec.
* The option "register_retry_403" has been added to chan_sip to work around
servers that are known to erroneously send 403 in response to valid
REGISTER requests and allows Asterisk to continue attepmting to connect.
chan_skinny
------------------
* Added the 'immeddialkey' parameter. If set, when the user presses the

View File

@ -819,6 +819,7 @@ static int global_rtpholdtimeout; /*!< Time out call if no RTP during hold */
static int global_rtpkeepalive; /*!< Send RTP keepalives */
static int global_reg_timeout; /*!< Global time between attempts for outbound registrations */
static int global_regattempts_max; /*!< Registration attempts before giving up */
static int global_reg_retry_403; /*!< Treat 403 responses to registrations as 401 responses */
static int global_shrinkcallerid; /*!< enable or disable shrinking of caller id */
static int global_callcounter; /*!< Enable call counters for all devices. This is currently enabled by setting the peer
* call-limit to INT_MAX. When we remove the call-limit from the code, we can make it
@ -21143,6 +21144,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_cli(a->fd, " Sub. max duration: %d secs\n", max_subexpiry);
ast_cli(a->fd, " Outbound reg. timeout: %d secs\n", global_reg_timeout);
ast_cli(a->fd, " Outbound reg. attempts: %d\n", global_regattempts_max);
ast_cli(a->fd, " Outbound reg. retry 403:%d\n", global_reg_retry_403);
ast_cli(a->fd, " Notify ringing state: %s\n", AST_CLI_YESNO(sip_cfg.notifyringing));
if (sip_cfg.notifyringing) {
ast_cli(a->fd, " Include CID: %s%s\n",
@ -31373,6 +31375,7 @@ static int reload_config(enum channelreloadreason reason)
sip_cfg.compactheaders = DEFAULT_COMPACTHEADERS;
global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
global_regattempts_max = 0;
global_reg_retry_403 = 0;
sip_cfg.pedanticsipchecking = DEFAULT_PEDANTIC;
sip_cfg.autocreatepeer = DEFAULT_AUTOCREATEPEER;
global_autoframing = 0;
@ -31761,6 +31764,8 @@ static int reload_config(enum channelreloadreason reason)
}
} else if (!strcasecmp(v->name, "registerattempts")) {
global_regattempts_max = atoi(v->value);
} else if (!strcasecmp(v->name, "register_retry_403")) {
global_reg_retry_403 = ast_true(v->value);
} else if (!strcasecmp(v->name, "bindaddr") || !strcasecmp(v->name, "udpbindaddr")) {
if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);

View File

@ -147,6 +147,7 @@
;client_uri=sip:1234567890@sip.example.com
;contact_user=1234567890
;retry_interval=60
;forbidden_retry_interval=600
;expiration=3600
;[mytrunk_auth]

View File

@ -787,6 +787,9 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; 0 = continue forever, hammering the other server
; until it accepts the registration
; Default is 0 tries, continue forever
;register_retry_403=yes ; Treat 403 responses to registrations as if they were
; 401 responses and continue retrying according to normal
; retry rules.
;----------------------------------------- OUTBOUND MWI SUBSCRIPTIONS -------------------------
; Asterisk can subscribe to receive the MWI from another SIP server and store it locally for retrieval

View File

@ -85,6 +85,17 @@
<configOption name="retry_interval" default="60">
<synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis>
</configOption>
<configOption name="forbidden_retry_interval" default="0">
<synopsis>Interval used when receiving a 403 Forbidden response.</synopsis>
<description><para>
If a 403 Forbidden is received, chan_pjsip will wait
<replaceable>forbidden_retry_interval</replaceable> seconds before
attempting registration again. If 0 is specified, chan_pjsip will not
retry after receiving a 403 Forbidden response. Setting this to a non-zero
value goes against a "SHOULD NOT" in RFC3261, but can be used to work around
buggy registrars.
</para></description>
</configOption>
<configOption name="server_uri">
<synopsis>SIP URI of the server to register against</synopsis>
<description><para>
@ -159,6 +170,8 @@ struct sip_outbound_registration_client_state {
unsigned int max_retries;
/*! \brief Interval at which retries should occur for temporal responses */
unsigned int retry_interval;
/*! \brief Interval at which retries should occur for permanent responses */
unsigned int forbidden_retry_interval;
/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
unsigned int auth_rejection_permanent;
/*! \brief Serializer for stuff and things */
@ -198,6 +211,8 @@ struct sip_outbound_registration {
unsigned int expiration;
/*! \brief Interval at which retries should occur for temporal responses */
unsigned int retry_interval;
/*! \brief Interval at which retries should occur for permanent responses */
unsigned int forbidden_retry_interval;
/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
unsigned int auth_rejection_permanent;
/*! \brief Maximum number of retries permitted */
@ -412,10 +427,21 @@ static int handle_registration_response(void *data)
response->code, server_uri, client_uri, response->client_state->retry_interval);
}
} else {
/* Finally if there's no hope of registering give up */
response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
response->code, server_uri, client_uri);
if (response->code == 403
&& response->client_state->forbidden_retry_interval
&& response->client_state->retries < response->client_state->max_retries) {
/* A forbidden response retry interval is configured and there are retries remaining */
response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
response->client_state->retries++;
schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%d' seconds\n",
server_uri, client_uri, response->client_state->forbidden_retry_interval);
} else {
/* Finally if there's no hope of registering give up */
response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
response->code, server_uri, client_uri);
}
}
ast_system_publish_registry("PJSIP", client_uri, server_uri, sip_outbound_registration_status_str[response->client_state->status], NULL);
@ -716,6 +742,7 @@ static int sip_outbound_registration_perform(void *data)
}
registration->state->client_state->outbound_auths.num = registration->outbound_auths.num;
registration->state->client_state->retry_interval = registration->retry_interval;
registration->state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
registration->state->client_state->max_retries = registration->max_retries;
registration->state->client_state->retries = 0;
@ -911,6 +938,7 @@ static int load_module(void)
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "forbidden_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, forbidden_retry_interval));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, NULL, 0, 0);