]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
AST-2014-002: chan_sip: Exit early on bad session timers request
authorKinsey Moore <kmoore@digium.com>
Mon, 10 Mar 2014 14:04:38 +0000 (14:04 +0000)
committerKinsey Moore <kmoore@digium.com>
Mon, 10 Mar 2014 14:04:38 +0000 (14:04 +0000)
This change allows chan_sip to avoid creation of the channel and
consumption of associated file descriptors altogether if the inbound
request is going to be rejected anyway.

(closes issue ASTERISK-23373)
Reported by: Corey Farrell
Patches:
     chan_sip-earlier-st-1.8.patch uploaded by Corey Farrell (license 5909)
     chan_sip-earlier-st-11.patch uploaded by Corey Farrell (license 5909)
........

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

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

git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/11.6@410359 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index d8af87ab7443c2ad85c6757b526be5dfa67cfc64..3abb506978e217d4c854afcf79acdc4e0ea29b62 100644 (file)
@@ -24930,6 +24930,145 @@ static int handle_request_update(struct sip_pvt *p, struct sip_request *req)
        return 0;
 }
 
+/*
+ * \internal \brief Check Session Timers for an INVITE request
+ *
+ * \retval 0 ok
+ * \retval -1 failure
+ */
+static int handle_request_invite_st(struct sip_pvt *p, struct sip_request *req,
+               const char *required, int reinvite)
+{
+       const char *p_uac_se_hdr;       /* UAC's Session-Expires header string                      */
+       const char *p_uac_min_se;       /* UAC's requested Min-SE interval (char string)            */
+       int uac_max_se = -1;            /* UAC's Session-Expires in integer format                  */
+       int uac_min_se = -1;            /* UAC's Min-SE in integer format                           */
+       int st_active = FALSE;          /* Session-Timer on/off boolean                             */
+       int st_interval = 0;            /* Session-Timer negotiated refresh interval                */
+       enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher     */
+       int dlg_min_se = -1;
+       int dlg_max_se = global_max_se;
+       int rtn;
+
+       /* Session-Timers */
+       if ((p->sipoptions & SIP_OPT_TIMER)) {
+               enum st_refresher_param st_ref_param = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN;
+
+               /* The UAC has requested session-timers for this session. Negotiate
+               the session refresh interval and who will be the refresher */
+               ast_debug(2, "Incoming INVITE with 'timer' option supported\n");
+
+               /* Allocate Session-Timers struct w/in the dialog */
+               if (!p->stimer) {
+                       sip_st_alloc(p);
+               }
+
+               /* Parse the Session-Expires header */
+               p_uac_se_hdr = sip_get_header(req, "Session-Expires");
+               if (!ast_strlen_zero(p_uac_se_hdr)) {
+                       ast_debug(2, "INVITE also has \"Session-Expires\" header.\n");
+                       rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
+                       tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
+                       if (rtn != 0) {
+                               transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
+                               return -1;
+                       }
+               }
+
+               /* Parse the Min-SE header */
+               p_uac_min_se = sip_get_header(req, "Min-SE");
+               if (!ast_strlen_zero(p_uac_min_se)) {
+                       ast_debug(2, "INVITE also has \"Min-SE\" header.\n");
+                       rtn = parse_minse(p_uac_min_se, &uac_min_se);
+                       if (rtn != 0) {
+                               transmit_response_reliable(p, "400 Min-SE Invalid Syntax", req);
+                               return -1;
+                       }
+               }
+
+               dlg_min_se = st_get_se(p, FALSE);
+               switch (st_get_mode(p, 1)) {
+               case SESSION_TIMER_MODE_ACCEPT:
+               case SESSION_TIMER_MODE_ORIGINATE:
+                       if (uac_max_se > 0 && uac_max_se < dlg_min_se) {
+                               transmit_response_with_minse(p, "422 Session Interval Too Small", req, dlg_min_se);
+                               return -1;
+                       }
+
+                       p->stimer->st_active_peer_ua = TRUE;
+                       st_active = TRUE;
+                       if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
+                               tmp_st_ref = st_get_refresher(p);
+                       }
+
+                       dlg_max_se = st_get_se(p, TRUE);
+                       if (uac_max_se > 0) {
+                               if (dlg_max_se >= uac_min_se) {
+                                       st_interval = (uac_max_se < dlg_max_se) ? uac_max_se : dlg_max_se;
+                               } else {
+                                       st_interval = uac_max_se;
+                               }
+                       } else if (uac_min_se > 0) {
+                               st_interval = MAX(dlg_max_se, uac_min_se);
+                       } else {
+                               st_interval = dlg_max_se;
+                       }
+                       break;
+
+               case SESSION_TIMER_MODE_REFUSE:
+                       if (p->reqsipoptions & SIP_OPT_TIMER) {
+                               transmit_response_with_unsupported(p, "420 Option Disabled", req, required);
+                               ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required);
+                               return -1;
+                       }
+                       break;
+
+               default:
+                       ast_log(LOG_ERROR, "Internal Error %d at %s:%d\n", st_get_mode(p, 1), __FILE__, __LINE__);
+                       break;
+               }
+       } else {
+               /* The UAC did not request session-timers.  Asterisk (UAS), will now decide
+               (based on session-timer-mode in sip.conf) whether to run session-timers for
+               this session or not. */
+               switch (st_get_mode(p, 1)) {
+               case SESSION_TIMER_MODE_ORIGINATE:
+                       st_active = TRUE;
+                       st_interval = st_get_se(p, TRUE);
+                       tmp_st_ref = SESSION_TIMER_REFRESHER_US;
+                       p->stimer->st_active_peer_ua = (p->sipoptions & SIP_OPT_TIMER) ? TRUE : FALSE;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       if (reinvite == 0) {
+               /* Session-Timers: Start session refresh timer based on negotiation/config */
+               if (st_active == TRUE) {
+                       p->stimer->st_active = TRUE;
+                       p->stimer->st_interval = st_interval;
+                       p->stimer->st_ref = tmp_st_ref;
+               }
+       } else {
+               if (p->stimer->st_active == TRUE) {
+                       /* Session-Timers:  A re-invite request sent within a dialog will serve as
+                       a refresh request, no matter whether the re-invite was sent for refreshing
+                       the session or modifying it.*/
+                       ast_debug (2, "Restarting session-timers on a refresh - %s\n", p->callid);
+
+                       /* The UAC may be adjusting the session-timers mid-session */
+                       if (st_interval > 0) {
+                               p->stimer->st_interval = st_interval;
+                               p->stimer->st_ref      = tmp_st_ref;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /*!
  * \brief Handle incoming INVITE request
  * \note If the INVITE has a Replaces header, it is part of an
@@ -24949,19 +25088,9 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
        struct ast_channel *c = NULL;           /* New channel */
        struct sip_peer *authpeer = NULL;       /* Matching Peer */
        int reinvite = 0;
-       int rtn;
        struct ast_party_redirecting redirecting;
        struct ast_set_party_redirecting update_redirecting;
 
-       const char *p_uac_se_hdr;       /* UAC's Session-Expires header string                      */
-       const char *p_uac_min_se;       /* UAC's requested Min-SE interval (char string)            */
-       int uac_max_se = -1;            /* UAC's Session-Expires in integer format                  */
-       int uac_min_se = -1;            /* UAC's Min-SE in integer format                           */
-       int st_active = FALSE;          /* Session-Timer on/off boolean                             */
-       int st_interval = 0;            /* Session-Timer negotiated refresh interval                */
-       enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher     */
-       int dlg_min_se = -1;
-       int dlg_max_se = global_max_se;
        struct {
                char exten[AST_MAX_EXTENSION];
                char context[AST_MAX_CONTEXT];
@@ -25449,6 +25578,14 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
                        /* Initialize our tag */
 
                        make_our_tag(p);
+
+                       if (handle_request_invite_st(p, req, required, reinvite)) {
+                               p->invitestate = INV_COMPLETED;
+                               sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+                               res = INV_REQ_ERROR;
+                               goto request_invite_cleanup;
+                       }
+
                        /* First invitation - create the channel.  Allocation
                         * failures are handled below. */
 
@@ -25483,6 +25620,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
                }
                if (!req->ignore)
                        reinvite = 1;
+
+               if (handle_request_invite_st(p, req, required, reinvite)) {
+                       p->invitestate = INV_COMPLETED;
+                       if (!p->lastinvite) {
+                               sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+                       }
+                       res = INV_REQ_ERROR;
+                       goto request_invite_cleanup;
+               }
+
                c = p->owner;
                change_redirecting_information(p, req, &redirecting, &update_redirecting, FALSE); /*Will return immediately if no Diversion header is present */
                if (c) {
@@ -25494,140 +25641,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
        /* Check if OLI/ANI-II is present in From: */
        parse_oli(req, p->owner);
 
-       /* Session-Timers */
-       if ((p->sipoptions & SIP_OPT_TIMER)) {
-               enum st_refresher_param st_ref_param = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN;
-
-               /* The UAC has requested session-timers for this session. Negotiate
-               the session refresh interval and who will be the refresher */
-               ast_debug(2, "Incoming INVITE with 'timer' option supported\n");
-
-               /* Allocate Session-Timers struct w/in the dialog */
-               if (!p->stimer)
-                       sip_st_alloc(p);
-
-               /* Parse the Session-Expires header */
-               p_uac_se_hdr = sip_get_header(req, "Session-Expires");
-               if (!ast_strlen_zero(p_uac_se_hdr)) {
-                       ast_debug(2, "INVITE also has \"Session-Expires\" header.\n");
-                       rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
-                       tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
-                       if (rtn != 0) {
-                               transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
-                               p->invitestate = INV_COMPLETED;
-                               if (!p->lastinvite) {
-                                       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                               }
-                               res = INV_REQ_ERROR;
-                               goto request_invite_cleanup;
-                       }
-               }
-
-               /* Parse the Min-SE header */
-               p_uac_min_se = sip_get_header(req, "Min-SE");
-               if (!ast_strlen_zero(p_uac_min_se)) {
-                       ast_debug(2, "INVITE also has \"Min-SE\" header.\n");
-                       rtn = parse_minse(p_uac_min_se, &uac_min_se);
-                       if (rtn != 0) {
-                               transmit_response_reliable(p, "400 Min-SE Invalid Syntax", req);
-                               p->invitestate = INV_COMPLETED;
-                               if (!p->lastinvite) {
-                                       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                               }
-                               res = INV_REQ_ERROR;
-                               goto request_invite_cleanup;
-                       }
-               }
-
-               dlg_min_se = st_get_se(p, FALSE);
-               switch (st_get_mode(p, 1)) {
-               case SESSION_TIMER_MODE_ACCEPT:
-               case SESSION_TIMER_MODE_ORIGINATE:
-                       if (uac_max_se > 0 && uac_max_se < dlg_min_se) {
-                               transmit_response_with_minse(p, "422 Session Interval Too Small", req, dlg_min_se);
-                               p->invitestate = INV_COMPLETED;
-                               if (!p->lastinvite) {
-                                       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                               }
-                               res = INV_REQ_ERROR;
-                               goto request_invite_cleanup;
-                       }
-
-                       p->stimer->st_active_peer_ua = TRUE;
-                       st_active = TRUE;
-                       if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
-                               tmp_st_ref = st_get_refresher(p);
-                       }
-
-                       dlg_max_se = st_get_se(p, TRUE);
-                       if (uac_max_se > 0) {
-                               if (dlg_max_se >= uac_min_se) {
-                                       st_interval = (uac_max_se < dlg_max_se) ? uac_max_se : dlg_max_se;
-                               } else {
-                                       st_interval = uac_max_se;
-                               }
-                       } else if (uac_min_se > 0) {
-                               st_interval = MAX(dlg_max_se, uac_min_se);
-                       } else {
-                               st_interval = dlg_max_se;
-                       }
-                       break;
-
-               case SESSION_TIMER_MODE_REFUSE:
-                       if (p->reqsipoptions & SIP_OPT_TIMER) {
-                               transmit_response_with_unsupported(p, "420 Option Disabled", req, required);
-                               ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required);
-                               p->invitestate = INV_COMPLETED;
-                               if (!p->lastinvite) {
-                                       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-                               }
-                               res = INV_REQ_ERROR;
-                               goto request_invite_cleanup;
-                       }
-                       break;
-
-               default:
-                       ast_log(LOG_ERROR, "Internal Error %d at %s:%d\n", st_get_mode(p, 1), __FILE__, __LINE__);
-                       break;
-               }
-       } else {
-               /* The UAC did not request session-timers.  Asterisk (UAS), will now decide
-               (based on session-timer-mode in sip.conf) whether to run session-timers for
-               this session or not. */
-               switch (st_get_mode(p, 1)) {
-               case SESSION_TIMER_MODE_ORIGINATE:
-                       st_active = TRUE;
-                       st_interval = st_get_se(p, TRUE);
-                       tmp_st_ref = SESSION_TIMER_REFRESHER_US;
-                       p->stimer->st_active_peer_ua = (p->sipoptions & SIP_OPT_TIMER) ? TRUE : FALSE;
-                       break;
-
-               default:
-                       break;
-               }
-       }
-
-       if (reinvite == 0) {
-               /* Session-Timers: Start session refresh timer based on negotiation/config */
-               if (st_active == TRUE) {
-                       p->stimer->st_active = TRUE;
-                       p->stimer->st_interval = st_interval;
-                       p->stimer->st_ref = tmp_st_ref;
+       if (p->stimer->st_active == TRUE) {
+               if (reinvite == 0) {
                        start_session_timer(p);
-               }
-       } else {
-               if (p->stimer->st_active == TRUE) {
-                       /* Session-Timers:  A re-invite request sent within a dialog will serve as
-                       a refresh request, no matter whether the re-invite was sent for refreshing
-                       the session or modifying it.*/
-                       ast_debug (2, "Restarting session-timers on a refresh - %s\n", p->callid);
-
-                       /* The UAC may be adjusting the session-timers mid-session */
-                       if (st_interval > 0) {
-                               p->stimer->st_interval = st_interval;
-                               p->stimer->st_ref      = tmp_st_ref;
-                       }
-
+               } else {
                        restart_session_timer(p);
                }
        }