summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsip-ua/sip_inv.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip/src/pjsip-ua/sip_inv.c')
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c241
1 files changed, 216 insertions, 25 deletions
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 2d411e8c..7252c7aa 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -115,6 +115,9 @@ static pj_status_t handle_timer_response(pjsip_inv_session *inv,
const pjsip_rx_data *rdata,
pj_bool_t end_sess_on_failure);
+static pj_bool_t inv_check_secure_dlg(pjsip_inv_session *inv,
+ pjsip_event *e);
+
static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
{
&inv_on_state_null,
@@ -992,6 +995,49 @@ PJ_DEF(pj_status_t) pjsip_inv_verify_request3(pjsip_rx_data *rdata,
goto on_return;
}
+ /* Ticket #1735: Check Contact/Record-Route header in a secure dialog. */
+ if (pjsip_cfg()->endpt.disable_secure_dlg_check == PJ_FALSE &&
+ msg && c_hdr && c_hdr->uri)
+ {
+ /* Check Contact header */
+ if (!PJSIP_URI_SCHEME_IS_SIPS(c_hdr->uri))
+ status = PJSIP_ESESSIONINSECURE;
+
+ /* Check top Record-Route header */
+ if (status == PJ_SUCCESS) {
+ pjsip_rr_hdr *r = (pjsip_rr_hdr*)
+ pjsip_msg_find_hdr(msg, PJSIP_H_RECORD_ROUTE,
+ NULL);
+ if (r && !PJSIP_URI_SCHEME_IS_SIPS(&r->name_addr)) {
+ /* Not "sips", check if it is "sip" and has param
+ * "transport=tls".
+ */
+ if (PJSIP_URI_SCHEME_IS_SIP(&r->name_addr)) {
+ pjsip_sip_uri *sip_uri = (pjsip_sip_uri*)
+ pjsip_uri_get_uri(r->name_addr.uri);
+ if (pj_stricmp2(&sip_uri->transport_param, "tls")!=0)
+ status = PJSIP_ESESSIONINSECURE;
+ } else {
+ /* Not "sips" nor "sip", treat it as insecure? */
+ status = PJSIP_ESESSIONINSECURE;
+ }
+ }
+ }
+
+ if (status != PJ_SUCCESS) {
+ pjsip_warning_hdr *w;
+ pj_str_t warn_text = pj_str("SIPS Required");
+ w = pjsip_warning_hdr_create(tmp_pool, 381,
+ pjsip_endpt_name(endpt),
+ &warn_text);
+ if (w) {
+ pj_list_push_back(&res_hdr_list, w);
+ }
+ code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
+ goto on_return;
+ }
+ }
+
/* Check the request body, see if it's something that we support,
* only when the body hasn't been parsed before.
*/
@@ -3224,13 +3270,22 @@ static void inv_handle_bye_response( pjsip_inv_session *inv,
* Respond to incoming UPDATE request.
*/
static void inv_respond_incoming_update(pjsip_inv_session *inv,
- pjsip_rx_data *rdata)
+ pjsip_event *e)
{
pjmedia_sdp_neg_state neg_state;
pj_status_t status;
pjsip_tx_data *tdata = NULL;
+ pjsip_rx_data *rdata;
pjsip_status_code st_code;
+ pj_assert(e->type == PJSIP_EVENT_TSX_STATE &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
+ rdata = e->body.tsx_state.src.rdata;
+
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ return;
+
/* Invoke Session Timers module */
status = pjsip_timer_process_req(inv, rdata, &st_code);
if (status != PJ_SUCCESS) {
@@ -3385,21 +3440,27 @@ static pj_bool_t inv_handle_update_response( pjsip_inv_session *inv,
tsx->status_code/100 == 2)
{
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
- status = handle_timer_response(inv, rdata, PJ_FALSE);
- if (rdata->msg_info.msg->body) {
- /* Only process remote SDP if we have sent local offer */
- if (inv->neg && pjmedia_sdp_neg_get_state(inv->neg) ==
- PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
- {
- status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
- } else {
- PJ_LOG(5,(THIS_FILE, "Ignored message body in %s as no local "
- "offer was sent",
- pjsip_rx_data_get_info(rdata)));
+ /* Check routing URI scheme for secure dialog */
+ if (inv_check_secure_dlg(inv, e)) {
+
+ status = handle_timer_response(inv, rdata, PJ_FALSE);
+
+ if (rdata->msg_info.msg->body) {
+ /* Only process remote SDP if we have sent local offer */
+ if (inv->neg && pjmedia_sdp_neg_get_state(inv->neg) ==
+ PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
+ {
+ status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
+ } else {
+ PJ_LOG(5,(THIS_FILE, "Ignored message body in %s as no "
+ "local offer was sent",
+ pjsip_rx_data_get_info(rdata)));
+ }
}
}
- handled = PJ_TRUE;
+
+ handled = PJ_TRUE;
}
/* Process 502/503 error */
@@ -3516,6 +3577,114 @@ static void inv_respond_incoming_prack(pjsip_inv_session *inv,
}
+/* Ticket #1735: If this is a secure dialog, make sure that any incoming
+ * initial/subsequent INVITE/UPDATE request or the 2xx response to INVITE/
+ * UPDATE specifies secure Contact and Record-Route headers.
+ */
+static pj_bool_t inv_check_secure_dlg(pjsip_inv_session *inv,
+ pjsip_event *e)
+{
+ pjsip_transaction *tsx = e->body.tsx_state.tsx;
+ pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
+
+ if (pjsip_cfg()->endpt.disable_secure_dlg_check == PJ_FALSE &&
+ dlg->secure && e->body.tsx_state.type==PJSIP_EVENT_RX_MSG &&
+ (tsx->role==PJSIP_ROLE_UAC && tsx->status_code/100 == 2 ||
+ tsx->role==PJSIP_ROLE_UAS && tsx->state == PJSIP_TSX_STATE_TRYING) &&
+ (tsx->method.id==PJSIP_INVITE_METHOD ||
+ pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0))
+ {
+ const pjsip_msg *msg = e->body.tsx_state.src.rdata->msg_info.msg;
+ pj_status_t status = PJ_SUCCESS;
+ pjsip_contact_hdr *c;
+
+ /* Check Contact header */
+ c = (pjsip_contact_hdr*)
+ pjsip_msg_find_hdr(msg,PJSIP_H_CONTACT, NULL);
+ if (!(c && c->uri && PJSIP_URI_SCHEME_IS_SIPS(c->uri)))
+ status = PJSIP_ESESSIONINSECURE;
+
+ /* Check top Record-Route header */
+ if (status == PJ_SUCCESS) {
+ pjsip_rr_hdr *r = (pjsip_rr_hdr*)
+ pjsip_msg_find_hdr(msg, PJSIP_H_RECORD_ROUTE,
+ NULL);
+ if (r && !PJSIP_URI_SCHEME_IS_SIPS(&r->name_addr)) {
+ /* Not "sips", check if it is "sip" and has param
+ * "transport=tls".
+ */
+ if (PJSIP_URI_SCHEME_IS_SIP(&r->name_addr)) {
+ pjsip_sip_uri *sip_uri = (pjsip_sip_uri*)
+ pjsip_uri_get_uri(r->name_addr.uri);
+ if (pj_stricmp2(&sip_uri->transport_param, "tls")!=0)
+ status = PJSIP_ESESSIONINSECURE;
+ } else {
+ /* Not "sips" nor "sip", treat it as insecure? */
+ status = PJSIP_ESESSIONINSECURE;
+ }
+ }
+ }
+
+ if (status == PJSIP_ESESSIONINSECURE) {
+ /* Found non-SIPS scheme in Contact/Record-Route header */
+
+ pj_str_t warn_text = pj_str("SIPS Required");
+
+ if (tsx->role == PJSIP_ROLE_UAC) {
+
+ /* If we are UAC, terminate the session */
+ pjsip_tx_data *bye;
+
+ PJ_LOG(4,(inv->obj_name,
+ "Secure dialog requires SIPS scheme in Contact and "
+ "Record-Route headers, ending the session"));
+
+ status = pjsip_inv_end_session(inv, 480, NULL, &bye);
+ if (status == PJ_SUCCESS && bye) {
+ pjsip_warning_hdr *w;
+ w = pjsip_warning_hdr_create(bye->pool, 381,
+ pjsip_endpt_name(dlg->endpt),
+ &warn_text);
+ if (w)
+ pjsip_msg_add_hdr(bye->msg, (pjsip_hdr*)w);
+
+ status = pjsip_inv_send_msg(inv, bye);
+ }
+
+ } else {
+
+ /* If we are UAS, reject the request */
+ pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
+ pjsip_tx_data *tdata;
+
+ PJ_LOG(4,(inv->obj_name,
+ "Secure dialog requires SIPS scheme in Contact and "
+ "Route headers, rejecting the request"));
+
+ status = pjsip_dlg_create_response(inv->dlg, rdata, 480,
+ NULL, &tdata);
+ if (status == PJ_SUCCESS) {
+ pjsip_warning_hdr *w;
+ w = pjsip_warning_hdr_create(tdata->pool, 381,
+ pjsip_endpt_name(dlg->endpt),
+ &warn_text);
+ if (w)
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
+
+ pjsip_dlg_send_response(dlg, tsx, tdata);
+ }
+
+ }
+
+ return PJ_FALSE;
+ }
+ }
+
+ return PJ_TRUE;
+}
+
+
+
/*
* State NULL is before anything is sent/received.
*/
@@ -3865,6 +4034,12 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
*/
pj_assert(0);
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
+
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ break;
+
/* Process session timer response. */
status = handle_timer_response(inv,
e->body.tsx_state.src.rdata,
@@ -3872,8 +4047,6 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
if (status != PJ_SUCCESS)
break;
- inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
-
inv_check_sdp_in_incoming_msg(inv, tsx,
e->body.tsx_state.src.rdata);
@@ -3889,6 +4062,14 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
*/
if (tsx->status_code/100 == 2) {
/* This must be receipt of 2xx response */
+ pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
+
+ /* Set state to CONNECTING */
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
+
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ break;
/* Process session timer response. */
status = handle_timer_response(inv,
@@ -3897,15 +4078,9 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
if (status != PJ_SUCCESS)
break;
- /* Set state to CONNECTING */
- inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
-
inv_check_sdp_in_incoming_msg(inv, tsx,
e->body.tsx_state.src.rdata);
-
/* Send ACK */
- pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
-
inv_send_ack(inv, e);
} else {
@@ -3942,7 +4117,7 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
/*
* Handle a very early UPDATE
*/
- inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
+ inv_respond_incoming_update(inv, e);
}
@@ -4060,6 +4235,10 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
pj_status_t status;
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ break;
+
/* Process session timer response. */
status = handle_timer_response(inv,
e->body.tsx_state.src.rdata,
@@ -4100,6 +4279,10 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
pj_status_t status;
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ break;
+
/* Process session timer response. */
status = handle_timer_response(inv,
e->body.tsx_state.src.rdata,
@@ -4149,7 +4332,7 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
/*
* Handle incoming UPDATE
*/
- inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
+ inv_respond_incoming_update(inv, e);
} else if (tsx->role == PJSIP_ROLE_UAC &&
@@ -4357,7 +4540,7 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
/*
* Handle incoming UPDATE
*/
- inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
+ inv_respond_incoming_update(inv, e);
} else if (tsx->role == PJSIP_ROLE_UAC &&
@@ -4487,6 +4670,10 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
return;
}
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ return;
+
/* Save the invite transaction. */
inv->invite_tsx = tsx;
@@ -4729,6 +4916,10 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
/* Re-INVITE was accepted. */
+ /* Check routing URI scheme for secure dialog */
+ if (!inv_check_secure_dlg(inv, e))
+ return;
+
/* Process session timer response. */
status = handle_timer_response(inv,
e->body.tsx_state.src.rdata,
@@ -4787,7 +4978,7 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
/*
* Handle incoming UPDATE
*/
- inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
+ inv_respond_incoming_update(inv, e);
} else if (tsx->role == PJSIP_ROLE_UAC &&
(tsx->state == PJSIP_TSX_STATE_COMPLETED ||