From: Matthew Jordan Date: Fri, 2 Nov 2012 15:27:56 +0000 (+0000) Subject: Multiple revisions 372709,373165,373532,373652,374456 X-Git-Tag: certified/1.8.15-cert1-rc1~3^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=56931e984165c0eb30962d3d3881cf4149f5814a;p=thirdparty%2Fasterisk.git Multiple revisions 372709,373165,373532,373652,374456 ........ r372709 | mjordan | 2012-09-08 20:19:21 -0500 (Sat, 08 Sep 2012) | 38 lines Only re-create an SRTP session when needed; respond with correct crypto policy In r356604, SRTP handling was fixed to accomodate multiple crypto keys in an SDP offer and the ability to re-create an SRTP session when the crypto keys changed. In certain circumstances - most notably when a phone is put on hold after having been bridged for a significant amount of time - the act of re-creating the SRTP session causes problems for certain models of phones. The patch committed in r356604 always re-created the SRTP session regardless of whether or not the cryptographic keys changed. Since this is technically not necessary, this patch modifies the behavior to only re-create the SRTP session if Asterisk detects that the remote key has changed. This allows models of phones that do not handle the SRTP session changing to continue to work, while also providing the behavior needed for those phones that do re-negotiate cryptographic keys. In addition, in Asterisk 1.8 only, it was found that phones that offer AES_CM_128_HMAC_SHA1_32 will end up with no audio if the phone is the initiator of the call. The phone will send an INVITE request specifying that AES_CM_128_HMAC_SHA1_32 be used for the cryptographic policy; Asterisk will set its policy to that value. Unfortunately, when the call is Answered and a 200 OK is sent back to the UA, the policy sent in the response's SDP will be the hard coded value AES_CM_128_HMAC_SHA1_80. This potentially results in Asterisk using the INVITE request's policy of AES_CM_128_HMAC_SHA1_32, while the phone uses Asterisk's response of AES_CM_128_HMAC_SHA1_80. Hilarity ensues as both endpoints think the other is crazy. This patch fixes that by caching the policy from the request and responding with it. Note that this is not a problem in Asterisk 10 and later, as the ability to configure the policy was added in that version. (issue ASTERISK-20194) Reported by: Nicolo Mazzon Tested by: Nicolo Mazzon Review: https://reviewboard.asterisk.org/r/2099 ........ r373165 | file | 2012-09-19 11:02:18 -0500 (Wed, 19 Sep 2012) | 10 lines Fix a regression where direct media was not permitted for calls using SIP INFO DTMF. A change was committed to fix direct media ACL support. This change wrongly assumed that only a single channel technology structure exists for chan_sip. This is in fact false as a second exists for calls using SIP INFO DTMF. The code which performs direct media ACL checking now checks for both the non-INFO DTMF and INFO DTMF channel technology structures. (closes issue ASTERISK-20409) Reported by: michele cicciotti privatewave ........ r373532 | file | 2012-09-24 19:09:46 -0500 (Mon, 24 Sep 2012) | 5 lines Add missing checks that I neglected. The SIP technology and SIP info technology should be considered equal. (closes issue ASTERISK-20409) Reported by: michele cicciotti privatewave ........ r373652 | twilson | 2012-09-25 12:21:19 -0500 (Tue, 25 Sep 2012) | 18 lines Properly handle UAC/UAS roles for SIP session timers The SIP session timer mechanism contains a mandatory 'refresher' parameter (included in the Session-Expires header) which is used in the session timer offer/answer signaling within a SIP Invite dialog. It looks like asterisk is interpreting the uac resp. uas role only as the initial role of client and server (caller is uac, callee is uas). The standard rfc 4028 however assigns the client role to the ((RE)-Invite) requester, the server role to the ((RE)-Invite) responder. This patch has Asterisk track the actual refresher as "us" or "them" as opposed to relying on just the configured "uas" or "uac" properties. (closes issue AST-922) Reported by: Thomas Airmont Review: https://reviewboard.asterisk.org/r/2118/ ........ r374456 | file | 2012-10-04 12:39:18 -0500 (Thu, 04 Oct 2012) | 14 lines Fix a regression from direct media ACLs where the directrtpsetup option no longer works. A check was added for direct media ACLs that immediately forbid remote bridging if there was no bridged channel. This caused directrtpsetup to no longer function as it needs this information before bridging actually occurs. Logic has now been adjusted so if there is no bridged channel a remote bridge will still be attempted. (closes issue ASTERISK-20511) Reported by: kristoff Review: https://reviewboard.asterisk.org/r/2146/ ........ Merged revisions 372709,373165,373532,373652,374456 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@375590 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 40fdcd2018..3b2359bfd5 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -758,7 +758,7 @@ static int global_qualify_gap; /*!< Time between our group of peer poke static int global_qualify_peers; /*!< Number of peers to poke at a given time */ static enum st_mode global_st_mode; /*!< Mode of operation for Session-Timers */ -static enum st_refresher global_st_refresher; /*!< Session-Timer refresher */ +static enum st_refresher_param global_st_refresher; /*!< Session-Timer refresher */ static int global_min_se; /*!< Lowest threshold for session refresh interval */ static int global_max_se; /*!< Highest threshold for session refresh interval */ @@ -1602,8 +1602,8 @@ static int proc_session_timer(const void *vp); static void stop_session_timer(struct sip_pvt *p); static void start_session_timer(struct sip_pvt *p); static void restart_session_timer(struct sip_pvt *p); -static const char *strefresher2str(enum st_refresher r); -static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher *const p_ref); +static const char *strefresherparam2str(enum st_refresher r); +static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher_param *const p_ref); static int parse_minse(const char *p_hdrval, int *const p_interval); static int st_get_se(struct sip_pvt *, int max); static enum st_refresher st_get_refresher(struct sip_pvt *); @@ -10451,7 +10451,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg if (p->method == SIP_INVITE && p->stimer && p->stimer->st_active == TRUE && p->stimer->st_active_peer_ua == TRUE) { char se_hdr[256]; snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval, - strefresher2str(p->stimer->st_ref)); + p->stimer->st_ref == SESSION_TIMER_REFRESHER_US ? "uas" : "uac"); add_header(resp, "Session-Expires", se_hdr); } @@ -10623,7 +10623,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, ui && sipmethod == SIP_INVITE) { char se_hdr[256]; snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval, - strefresher2str(p->stimer->st_ref)); + p->stimer->st_ref == SESSION_TIMER_REFRESHER_US ? "uac" : "uas"); add_header(req, "Session-Expires", se_hdr); snprintf(se_hdr, sizeof(se_hdr), "%d", st_get_se(p, FALSE)); add_header(req, "Min-SE", se_hdr); @@ -16880,23 +16880,34 @@ static enum st_mode str2stmode(const char *s) } /* Session-Timer Refreshers */ +static const struct _map_x_s strefresher_params[] = { + { SESSION_TIMER_REFRESHER_PARAM_UNKNOWN, "unknown" }, + { SESSION_TIMER_REFRESHER_PARAM_UAC, "uac" }, + { SESSION_TIMER_REFRESHER_PARAM_UAS, "uas" }, + { -1, NULL }, +}; + static const struct _map_x_s strefreshers[] = { - { SESSION_TIMER_REFRESHER_AUTO, "auto"}, - { SESSION_TIMER_REFRESHER_UAC, "uac"}, - { SESSION_TIMER_REFRESHER_UAS, "uas"}, - { -1, NULL}, + { SESSION_TIMER_REFRESHER_AUTO, "auto" }, + { SESSION_TIMER_REFRESHER_US, "us" }, + { SESSION_TIMER_REFRESHER_THEM, "them" }, + { -1, NULL }, }; -static const char *strefresher2str(enum st_refresher r) +static const char *strefresherparam2str(enum st_refresher r) { - return map_x_s(strefreshers, r, "Unknown"); + return map_x_s(strefresher_params, r, "Unknown"); } -static enum st_refresher str2strefresher(const char *s) +static enum st_refresher str2strefresherparam(const char *s) { - return map_s_x(strefreshers, s, -1); + return map_s_x(strefresher_params, s, -1); } +static const char *strefresher2str(enum st_refresher r) +{ + return map_x_s(strefreshers, r, "Unknown"); +} static int peer_status(struct sip_peer *peer, char *status, int statuslen) { @@ -18042,7 +18053,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct } ast_cli(fd, " Sess-Timers : %s\n", stmode2str(peer->stimer.st_mode_oper)); - ast_cli(fd, " Sess-Refresh : %s\n", strefresher2str(peer->stimer.st_ref)); + ast_cli(fd, " Sess-Refresh : %s\n", strefresherparam2str(peer->stimer.st_ref)); ast_cli(fd, " Sess-Expires : %d secs\n", peer->stimer.st_max_se); ast_cli(fd, " Min-Sess : %d secs\n", peer->stimer.st_min_se); ast_cli(fd, " RTP Engine : %s\n", peer->engine); @@ -18099,7 +18110,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct astman_append(s, "SIP-T.38EC: %s\r\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT))); astman_append(s, "SIP-T.38MaxDtgrm: %d\r\n", peer->t38_maxdatagram); astman_append(s, "SIP-Sess-Timers: %s\r\n", stmode2str(peer->stimer.st_mode_oper)); - astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresher2str(peer->stimer.st_ref)); + astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresherparam2str(peer->stimer.st_ref)); astman_append(s, "SIP-Sess-Expires: %d\r\n", peer->stimer.st_max_se); astman_append(s, "SIP-Sess-Min: %d\r\n", peer->stimer.st_min_se); astman_append(s, "SIP-RTP-Engine: %s\r\n", peer->engine); @@ -18239,7 +18250,7 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args ast_cli(a->fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), user->cid_name, user->cid_num, "")); ast_cli(a->fd, " ACL : %s\n", AST_CLI_YESNO(user->ha != NULL)); ast_cli(a->fd, " Sess-Timers : %s\n", stmode2str(user->stimer.st_mode_oper)); - ast_cli(a->fd, " Sess-Refresh : %s\n", strefresher2str(user->stimer.st_ref)); + ast_cli(a->fd, " Sess-Refresh : %s\n", strefresherparam2str(user->stimer.st_ref)); ast_cli(a->fd, " Sess-Expires : %d secs\n", user->stimer.st_max_se); ast_cli(a->fd, " Sess-Min-SE : %d secs\n", user->stimer.st_min_se); ast_cli(a->fd, " RTP Engine : %s\n", user->engine); @@ -18682,7 +18693,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " Outb. proxy: %s %s\n", ast_strlen_zero(sip_cfg.outboundproxy.name) ? "" : sip_cfg.outboundproxy.name, sip_cfg.outboundproxy.force ? "(forced)" : ""); ast_cli(a->fd, " Session Timers: %s\n", stmode2str(global_st_mode)); - ast_cli(a->fd, " Session Refresher: %s\n", strefresher2str (global_st_refresher)); + ast_cli(a->fd, " Session Refresher: %s\n", strefresherparam2str(global_st_refresher)); ast_cli(a->fd, " Session Expires: %d secs\n", global_max_se); ast_cli(a->fd, " Session Min-SE: %d secs\n", global_min_se); ast_cli(a->fd, " Timer T1: %d\n", global_t1); @@ -19114,7 +19125,7 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_cli(a->fd, " S-Timer Peer Sts: %s\n", cur->stimer->st_active_peer_ua ? "Active" : "Inactive"); ast_cli(a->fd, " S-Timer Cached Min-SE: %d\n", cur->stimer->st_cached_min_se); ast_cli(a->fd, " S-Timer Cached SE: %d\n", cur->stimer->st_cached_max_se); - ast_cli(a->fd, " S-Timer Cached Ref: %s\n", strefresher2str(cur->stimer->st_cached_ref)); + ast_cli(a->fd, " S-Timer Cached Ref: %s\n", strefresherparam2str(cur->stimer->st_cached_ref)); ast_cli(a->fd, " S-Timer Cached Mode: %s\n", stmode2str(cur->stimer->st_cached_mode)); } } @@ -20754,15 +20765,18 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest p_hdrval = (char*)get_header(req, "Session-Expires"); if (!ast_strlen_zero(p_hdrval)) { /* UAS supports Session-Timers */ - enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; + enum st_refresher_param st_ref_param; int tmp_st_interval = 0; - rtn = parse_session_expires(p_hdrval, &tmp_st_interval, &tmp_st_ref); + rtn = parse_session_expires(p_hdrval, &tmp_st_interval, &st_ref_param); if (rtn != 0) { ast_set_flag(&p->flags[0], SIP_PENDINGBYE); } - if (tmp_st_ref == SESSION_TIMER_REFRESHER_UAC || - tmp_st_ref == SESSION_TIMER_REFRESHER_UAS) { - p->stimer->st_ref = tmp_st_ref; + if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) { + p->stimer->st_ref = SESSION_TIMER_REFRESHER_US; + } else if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAS) { + p->stimer->st_ref = SESSION_TIMER_REFRESHER_THEM; + } else { + ast_log(LOG_WARNING, "Unknown refresher on %s\n", p->callid); } if (tmp_st_interval) { p->stimer->st_interval = tmp_st_interval; @@ -20773,7 +20787,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest } else { /* UAS doesn't support Session-Timers */ if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) { - p->stimer->st_ref = SESSION_TIMER_REFRESHER_UAC; + p->stimer->st_ref = SESSION_TIMER_REFRESHER_US; p->stimer->st_active_peer_ua = FALSE; start_session_timer(p); } @@ -22787,7 +22801,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int 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 st_ref; /* Session-Timer session refresher */ + enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher */ int dlg_min_se = -1; struct { char exten[AST_MAX_EXTENSION]; @@ -22795,7 +22809,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int } pickup = { .exten = "", }; - st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Find out what they support */ if (!p->sipoptions) { @@ -23322,6 +23335,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* Session-Timers */ if ((p->sipoptions & SIP_OPT_TIMER) && !ast_strlen_zero(get_header(req, "Session-Expires"))) { + enum st_refresher_param st_ref_param; + /* 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 and \"Session-Expires\" header.\n"); @@ -23332,7 +23347,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* Parse the Session-Expires header */ p_uac_se_hdr = get_header(req, "Session-Expires"); - rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref); + 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; @@ -23374,8 +23390,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int p->stimer->st_active_peer_ua = TRUE; st_active = TRUE; - if (st_ref == SESSION_TIMER_REFRESHER_AUTO) { - st_ref = st_get_refresher(p); + if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) { + tmp_st_ref = st_get_refresher(p); } if (uac_max_se > 0) { @@ -23416,7 +23432,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int case SESSION_TIMER_MODE_ORIGINATE: st_active = TRUE; st_interval = st_get_se(p, TRUE); - st_ref = SESSION_TIMER_REFRESHER_UAS; + tmp_st_ref = SESSION_TIMER_REFRESHER_US; p->stimer->st_active_peer_ua = FALSE; break; @@ -23428,9 +23444,9 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int 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_active = TRUE; p->stimer->st_interval = st_interval; - p->stimer->st_ref = st_ref; + p->stimer->st_ref = tmp_st_ref; start_session_timer(p); } } else { @@ -23443,7 +23459,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* The UAC may be adjusting the session-timers mid-session */ if (st_interval > 0) { p->stimer->st_interval = st_interval; - p->stimer->st_ref = st_ref; + p->stimer->st_ref = tmp_st_ref; } restart_session_timer(p); @@ -26660,7 +26676,6 @@ static void start_session_timer(struct sip_pvt *p) static int proc_session_timer(const void *vp) { struct sip_pvt *p = (struct sip_pvt *) vp; - int sendreinv = FALSE; int res = 0; if (!p->stimer) { @@ -26678,23 +26693,7 @@ static int proc_session_timer(const void *vp) goto return_unref; } - switch (p->stimer->st_ref) { - case SESSION_TIMER_REFRESHER_UAC: - if (p->outgoing_call == TRUE) { - sendreinv = TRUE; - } - break; - case SESSION_TIMER_REFRESHER_UAS: - if (p->outgoing_call != TRUE) { - sendreinv = TRUE; - } - break; - default: - ast_log(LOG_ERROR, "Unknown session refresher %d\n", p->stimer->st_ref); - goto return_unref; - } - - if (sendreinv == TRUE) { + if (p->stimer->st_ref == SESSION_TIMER_REFRESHER_US) { res = 1; transmit_reinvite_with_sdp(p, FALSE, TRUE); } else { @@ -26761,7 +26760,7 @@ int parse_minse (const char *p_hdrval, int *const p_interval) /*! \brief Session-Timers: Function for parsing Session-Expires header */ -int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher *const p_ref) +int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher_param *const p_ref) { char *p_token; int ref_idx; @@ -26772,7 +26771,7 @@ int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_r return -1; } - *p_ref = SESSION_TIMER_REFRESHER_AUTO; + *p_ref = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN; *p_interval = 0; p_se_hdr = ast_strdupa(p_hdrval); @@ -26797,10 +26796,10 @@ int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_r p_se_hdr = ast_skip_blanks(p_se_hdr); if (!strncasecmp(p_se_hdr, "uac", strlen("uac"))) { - *p_ref = SESSION_TIMER_REFRESHER_UAC; + *p_ref = SESSION_TIMER_REFRESHER_PARAM_UAC; ast_debug(2, "Refresher: UAC\n"); } else if (!strncasecmp(p_se_hdr, "uas", strlen("uas"))) { - *p_ref = SESSION_TIMER_REFRESHER_UAS; + *p_ref = SESSION_TIMER_REFRESHER_PARAM_UAS; ast_debug(2, "Refresher: UAS\n"); } else { ast_log(LOG_WARNING, "Invalid refresher value %s\n", p_se_hdr); @@ -26872,20 +26871,24 @@ int st_get_se(struct sip_pvt *p, int max) /*! \brief Get the entity (UAC or UAS) that's acting as the session-timer refresher + * \note This is only called when processing an INVITE, so in that case Asterisk is + * always currently the UAS. If this is ever used to process responses, the + * function will have to be changed. * \param p pointer to the SIP dialog */ enum st_refresher st_get_refresher(struct sip_pvt *p) { - if (p->stimer->st_cached_ref != SESSION_TIMER_REFRESHER_AUTO) + if (p->stimer->st_cached_ref != SESSION_TIMER_REFRESHER_AUTO) { return p->stimer->st_cached_ref; + } if (p->relatedpeer) { - p->stimer->st_cached_ref = p->relatedpeer->stimer.st_ref; + p->stimer->st_cached_ref = (p->relatedpeer->stimer.st_ref == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US; return p->stimer->st_cached_ref; } - p->stimer->st_cached_ref = global_st_refresher; - return global_st_refresher; + p->stimer->st_cached_ref = (global_st_refresher == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US; + return p->stimer->st_cached_ref; } @@ -28320,7 +28323,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str peer->stimer.st_min_se = global_min_se; } } else if (!strcasecmp(v->name, "session-refresher")) { - int i = (int) str2strefresher(v->value); + int i = (int) str2strefresherparam(v->value); if (i < 0) { ast_log(LOG_WARNING, "Invalid session-refresher '%s' at line %d of %s\n", v->value, v->lineno, config); peer->stimer.st_ref = global_st_refresher; @@ -28816,7 +28819,7 @@ static int reload_config(enum channelreloadreason reason) /* Session-Timers */ global_st_mode = SESSION_TIMER_MODE_ACCEPT; - global_st_refresher = SESSION_TIMER_REFRESHER_UAS; + global_st_refresher = SESSION_TIMER_REFRESHER_PARAM_UAS; global_min_se = DEFAULT_MIN_SE; global_max_se = DEFAULT_MAX_SE; @@ -29311,10 +29314,10 @@ static int reload_config(enum channelreloadreason reason) global_min_se = DEFAULT_MIN_SE; } } else if (!strcasecmp(v->name, "session-refresher")) { - int i = (int) str2strefresher(v->value); + int i = (int) str2strefresherparam(v->value); if (i < 0) { ast_log(LOG_WARNING, "Invalid session-refresher '%s' at line %d of %s\n", v->value, v->lineno, config); - global_st_refresher = SESSION_TIMER_REFRESHER_UAS; + global_st_refresher = SESSION_TIMER_REFRESHER_PARAM_UAS; } else { global_st_refresher = i; } @@ -29733,7 +29736,8 @@ static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan) if (!(opp_chan = ast_bridged_channel(chan))) { return NULL; - } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + } else if (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) || + (!(opp = opp_chan->tech_pvt))) { return NULL; } @@ -29809,21 +29813,22 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc return AST_RTP_GLUE_RESULT_FORBID; } - if (!(opp_chan = ast_bridged_channel(chan))) { - return AST_RTP_GLUE_RESULT_FORBID; - } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + if ((opp_chan = ast_bridged_channel(chan)) && (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) || + (!(opp = opp_chan->tech_pvt)))) { return AST_RTP_GLUE_RESULT_FORBID; } sip_pvt_lock(p); - while (sip_pvt_trylock(opp)) { + while (opp && sip_pvt_trylock(opp)) { sip_pvt_unlock(p); usleep(1); sip_pvt_lock(p); } if (!(p->rtp)) { - sip_pvt_unlock(opp); + if (opp) { + sip_pvt_unlock(opp); + } sip_pvt_unlock(p); return AST_RTP_GLUE_RESULT_FORBID; } @@ -29833,7 +29838,7 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { res = AST_RTP_GLUE_RESULT_REMOTE; - if (!apply_directmedia_ha(p, opp, "audio")) { + if (opp && !apply_directmedia_ha(p, opp, "audio")) { res = AST_RTP_GLUE_RESULT_FORBID; } } else if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) { @@ -29842,7 +29847,9 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc res = AST_RTP_GLUE_RESULT_FORBID; } - sip_pvt_unlock(opp); + if (opp) { + sip_pvt_unlock(opp); + } if (p->srtp) { res = AST_RTP_GLUE_RESULT_FORBID; @@ -29864,21 +29871,22 @@ static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, stru return AST_RTP_GLUE_RESULT_FORBID; } - if (!(opp_chan = ast_bridged_channel(chan))) { - return AST_RTP_GLUE_RESULT_FORBID; - } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + if ((opp_chan = ast_bridged_channel(chan)) && (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) || + (!(opp = opp_chan->tech_pvt)))) { return AST_RTP_GLUE_RESULT_FORBID; } sip_pvt_lock(p); - while (sip_pvt_trylock(opp)) { + while (opp && sip_pvt_trylock(opp)) { sip_pvt_unlock(p); usleep(1); sip_pvt_lock(p); } if (!(p->vrtp)) { - sip_pvt_unlock(opp); + if (opp) { + sip_pvt_unlock(opp); + } sip_pvt_unlock(p); return AST_RTP_GLUE_RESULT_FORBID; } @@ -29888,12 +29896,14 @@ static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, stru if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { res = AST_RTP_GLUE_RESULT_REMOTE; - if (!apply_directmedia_ha(p, opp, "video")) { + if (opp && !apply_directmedia_ha(p, opp, "video")) { res = AST_RTP_GLUE_RESULT_FORBID; } } - sip_pvt_unlock(opp); + if (opp) { + sip_pvt_unlock(opp); + } sip_pvt_unlock(p); return res; @@ -29910,21 +29920,22 @@ static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, stru return AST_RTP_GLUE_RESULT_FORBID; } - if (!(opp_chan = ast_bridged_channel(chan))) { - return AST_RTP_GLUE_RESULT_FORBID; - } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + if ((opp_chan = ast_bridged_channel(chan)) && (((opp_chan->tech != &sip_tech) && (opp_chan->tech != &sip_tech_info)) || + (!(opp = opp_chan->tech_pvt)))) { return AST_RTP_GLUE_RESULT_FORBID; } sip_pvt_lock(p); - while (sip_pvt_trylock(opp)) { + while (opp && sip_pvt_trylock(opp)) { sip_pvt_unlock(p); usleep(1); sip_pvt_lock(p); } if (!(p->trtp)) { - sip_pvt_unlock(opp); + if (opp) { + sip_pvt_unlock(opp); + } sip_pvt_unlock(p); return AST_RTP_GLUE_RESULT_FORBID; } @@ -29934,12 +29945,14 @@ static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, stru if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { res = AST_RTP_GLUE_RESULT_REMOTE; - if (!apply_directmedia_ha(p, opp, "text")) { + if (opp && !apply_directmedia_ha(p, opp, "text")) { res = AST_RTP_GLUE_RESULT_FORBID; } } - sip_pvt_unlock(opp); + if (opp) { + sip_pvt_unlock(opp); + } sip_pvt_unlock(p); return res; diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index c1263f075d..ae5437fafa 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -525,9 +525,15 @@ enum st_mode { /*! \brief The entity playing the refresher role for Session-Timers */ enum st_refresher { - SESSION_TIMER_REFRESHER_AUTO, /*!< Negotiated */ - SESSION_TIMER_REFRESHER_UAC, /*!< Session is refreshed by the UAC */ - SESSION_TIMER_REFRESHER_UAS /*!< Session is refreshed by the UAS */ + SESSION_TIMER_REFRESHER_AUTO, /*!< Negotiated */ + SESSION_TIMER_REFRESHER_US, /*!< Initially prefer session refresh by Asterisk */ + SESSION_TIMER_REFRESHER_THEM, /*!< Initially prefer session refresh by the other side */ +}; + +enum st_refresher_param { + SESSION_TIMER_REFRESHER_PARAM_UNKNOWN, + SESSION_TIMER_REFRESHER_PARAM_UAC, + SESSION_TIMER_REFRESHER_PARAM_UAS, }; /*! \brief Define some implemented SIP transports @@ -901,14 +907,14 @@ struct sip_notify { struct sip_st_dlg { int st_active; /*!< Session-Timers on/off */ int st_interval; /*!< Session-Timers negotiated session refresh interval */ + enum st_refresher st_ref; /*!< Session-Timers cached refresher */ int st_schedid; /*!< Session-Timers ast_sched scheduler id */ - enum st_refresher st_ref; /*!< Session-Timers session refresher */ int st_expirys; /*!< Session-Timers number of expirys */ int st_active_peer_ua; /*!< Session-Timers on/off in peer UA */ int st_cached_min_se; /*!< Session-Timers cached Min-SE */ int st_cached_max_se; /*!< Session-Timers cached Session-Expires */ enum st_mode st_cached_mode; /*!< Session-Timers cached M.O. */ - enum st_refresher st_cached_ref; /*!< Session-Timers cached refresher */ + enum st_refresher st_cached_ref; /*!< Session-Timers session refresher */ unsigned char quit_flag:1; /*!< Stop trying to lock; just quit */ }; @@ -917,10 +923,10 @@ struct sip_st_dlg { * of SIP Session-Timers feature on a per user/peer basis. */ struct sip_st_cfg { - enum st_mode st_mode_oper; /*!< Mode of operation for Session-Timers */ - enum st_refresher st_ref; /*!< Session-Timer refresher */ - int st_min_se; /*!< Lowest threshold for session refresh interval */ - int st_max_se; /*!< Highest threshold for session refresh interval */ + enum st_mode st_mode_oper; /*!< Mode of operation for Session-Timers */ + enum st_refresher_param st_ref; /*!< Session-Timer refresher */ + int st_min_se; /*!< Lowest threshold for session refresh interval */ + int st_max_se; /*!< Highest threshold for session refresh interval */ }; /*! \brief Structure for remembering offered media in an INVITE, to make sure we reply diff --git a/channels/sip/sdp_crypto.c b/channels/sip/sdp_crypto.c index 3a95ce9a6c..ea8ea64162 100644 --- a/channels/sip/sdp_crypto.c +++ b/channels/sip/sdp_crypto.c @@ -49,6 +49,8 @@ struct sdp_crypto { char *a_crypto; unsigned char local_key[SRTP_MASTER_LEN]; char local_key64[SRTP_MASTER_LEN64]; + unsigned char remote_key[SRTP_MASTER_LEN]; + char suite[64]; }; static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound); @@ -257,12 +259,20 @@ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_in return -1; } - if ((key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key))) != SRTP_MASTER_LEN) { - ast_log(LOG_WARNING, "SRTP sdescriptions key %d != %d\n", key_len, SRTP_MASTER_LEN); + ast_log(LOG_WARNING, "SRTP descriptions key %d != %d\n", key_len, SRTP_MASTER_LEN); return -1; } + if (!memcmp(p->remote_key, remote_key, sizeof(p->remote_key))) { + ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); + return 0; + } + + /* Set the accepted policy and remote key */ + ast_copy_string(p->suite, suite, sizeof(p->suite)); + memcpy(p->remote_key, remote_key, sizeof(p->remote_key)); + if (sdp_crypto_activate(p, suite_val, remote_key, rtp) < 0) { return -1; } @@ -280,13 +290,17 @@ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_in int sdp_crypto_offer(struct sdp_crypto *p) { char crypto_buf[128]; - const char *crypto_suite = "AES_CM_128_HMAC_SHA1_80"; /* Crypto offer */ + + if (ast_strlen_zero(p->suite)) { + /* Default crypto offer */ + strcpy(p->suite, "AES_CM_128_HMAC_SHA1_80"); + } if (p->a_crypto) { ast_free(p->a_crypto); } - if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n", crypto_suite, p->local_key64) < 1) { + if (snprintf(crypto_buf, sizeof(crypto_buf), "a=crypto:1 %s inline:%s\r\n", p->suite, p->local_key64) < 1) { return -1; } diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 4a1f76d1c3..3a4a72c690 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -560,11 +560,20 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; * session-expires - Maximum session refresh interval in seconds. Defaults to 1800 secs. ; * session-minse - Minimum session refresh interval in seconds. Defualts to 90 secs. ; * session-refresher - The session refresher (uac|uas). Defaults to 'uas'. +; uac - Default to the caller initially refreshing when possible +; uas - Default to the callee initially refreshing when possible +; +; Note that, due to recommendations in RFC 4028, Asterisk will always honor the other +; endpoint's preference for who will handle refreshes. Asterisk will never override the +; preferences of the other endpoint. Doing so could result in Asterisk and the endpoint +; fighting over who sends the refreshes. This holds true for the initiation of session +; timers and subsequent re-INVITE requests whether Asterisk is the caller or callee, or +; whether Asterisk is currently the refresher or not. ; ;session-timers=originate ;session-expires=600 ;session-minse=90 -;session-refresher=uas +;session-refresher=uac ; ;--------------------------- SIP DEBUGGING --------------------------------------------------- ;sipdebug = yes ; Turn on SIP debugging by default, from