diff options
author | Kinsey Moore <kmoore@digium.com> | 2014-03-10 13:30:51 +0000 |
---|---|---|
committer | Kinsey Moore <kmoore@digium.com> | 2014-03-10 13:30:51 +0000 |
commit | c300f7e5a8634bb0f1824fc146a4c6fffae078ac (patch) | |
tree | d113dd85007d7411df4e526d2f2bd67537255bb4 | |
parent | aa57dcf6341a9a6e91e93cda14258ea3ba48af60 (diff) |
AST-2014-002: chan_sip: Exit early on bad session timers request
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
........
Merged revisions 410329 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410346 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r-- | channels/chan_sip.c | 303 |
1 files changed, 160 insertions, 143 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cda815305..2198ee625 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -24992,6 +24992,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 @@ -25010,19 +25149,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]; @@ -25481,6 +25610,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. */ @@ -25515,6 +25652,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) { @@ -25526,140 +25673,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); } } |