Module: sip-router Branch: andrei/cancel_reason Commit: 23e0d801e5717586da6c696460f5a30d04467028 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=23e0d801...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Tue Mar 2 17:28:16 2010 +0100
tm: Reason header copy for received CANCELs
When canceling branches due to a received CANCEL, use the Reason headers in the received CANCEL (all the Reason headers from the received CANCEL will be copied in the generated CANCELs, see RFC3326 for more details).
---
modules/tm/t_fwd.c | 11 ++++++++--- modules/tm/t_msgbuilder.c | 37 +++++++++++++++++++++++++++++++++---- modules/tm/t_reply.c | 5 ++++- 3 files changed, 45 insertions(+), 8 deletions(-)
diff --git a/modules/tm/t_fwd.c b/modules/tm/t_fwd.c index 4f7cb02..0e1a00e 100644 --- a/modules/tm/t_fwd.c +++ b/modules/tm/t_fwd.c @@ -951,13 +951,15 @@ error:
-void e2e_cancel( struct sip_msg *cancel_msg, +void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite ) { branch_bm_t cancel_bm; #ifndef E2E_CANCEL_HOP_BY_HOP branch_bm_t tmp_bm; -#endif +#else /* def E2E_CANCEL_HOP_BY_HOP */ + struct cancel_reason reason; +#endif /* E2E_CANCEL_HOP_BY_HOP */ int i; int lowest_error; int ret; @@ -1002,6 +1004,9 @@ void e2e_cancel( struct sip_msg *cancel_msg, * have 0 branches and we check for the branch number in * t_reply_matching() ). */ + init_cancel_reason(&reason); + reason.cause=CANCEL_REAS_RCVD_CANCEL; + reason.u.e2e_cancel=cancel_msg; for (i=0; i<t_invite->nr_of_outgoings; i++) if (cancel_bm & (1<<i)) { /* it's safe to get the reply lock since e2e_cancel is @@ -1011,7 +1016,7 @@ void e2e_cancel( struct sip_msg *cancel_msg, ret=cancel_branch( t_invite, i, - 0, + &reason, cfg_get(tm,tm_cfg, cancel_b_flags) | ((t_invite->uac[i].request.buffer==NULL)? F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */ diff --git a/modules/tm/t_msgbuilder.c b/modules/tm/t_msgbuilder.c index bf49c64..4ccf3d2 100644 --- a/modules/tm/t_msgbuilder.c +++ b/modules/tm/t_msgbuilder.c @@ -104,6 +104,7 @@ char *build_local(struct cell *Trans,unsigned int branch, str via_id; struct hostport hp; int reason_len, code_len; + struct hdr_field *reas1, *reas_last;
/* init */ via_id.s=0; @@ -169,6 +170,7 @@ char *build_local(struct cell *Trans,unsigned int branch, /* Content Length, EoM */ *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN; reason_len = 0; + reas1 = 0; /* compute reason size */ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0)){ @@ -179,7 +181,14 @@ char *build_local(struct cell *Trans,unsigned int branch, CRLF_LEN; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel) { - /* FIXME: TODO */ + /* parse the entire cancel, to get all the Reason headers */ + parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0); + for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; + hdr; hdr=next_sibling_hdr(hdr)) { + /* hdr->len includes CRLF */ + reason_len += hdr->len; + reas_last=hdr; + } } else if (unlikely(reason->cause != -1)) BUG("unhandled reason cause %d\n", reason->cause); } @@ -243,7 +252,12 @@ char *build_local(struct cell *Trans,unsigned int branch, } append_str(p, CRLF, CRLF_LEN); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { - /* FIXME: handle cancel */ + for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { + /* hdr->len includes CRLF */ + append_str(p, hdr->name.s, hdr->len); + if (likely(hdr==reas_last)) + break; + } } } append_str(p, CRLF, CRLF_LEN); /* msg. end */ @@ -274,6 +288,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch, enum _hdr_types_t hf_type; int first_via, to_len; int cancel_buf_len, reason_len, code_len; + struct hdr_field *reas1, *reas_last, *hdr;
invite_buf = Trans->uac[branch].request.buffer; invite_len = Trans->uac[branch].request.buffer_len; @@ -289,6 +304,7 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch, } reason_len = 0; + reas1 = 0; /* compute reason size */ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0)){ @@ -299,7 +315,14 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch, CRLF_LEN; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel) { - /* FIXME: TODO */ + /* parse the entire cancel, to get all the Reason headers */ + parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0); + for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; + hdr; hdr=next_sibling_hdr(hdr)) { + /* hdr->len includes CRLF */ + reason_len += hdr->len; + reas_last=hdr; + } } else if (unlikely(reason->cause != -1)) BUG("unhandled reason cause %d\n", reason->cause); } @@ -424,9 +447,15 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch, } append_str(d, CRLF, CRLF_LEN); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { - /* FIXME: handle cancel */ + for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { + /* hdr->len includes CRLF */ + append_str(d, hdr->name.s, hdr->len); + if (likely(hdr==reas_last)) + break; + } } } + /* final (end-of-headers) CRLF */ append_str(d, CRLF, CRLF_LEN); *len = d - cancel_buf; /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */ diff --git a/modules/tm/t_reply.c b/modules/tm/t_reply.c index a42820e..6ee3fae 100644 --- a/modules/tm/t_reply.c +++ b/modules/tm/t_reply.c @@ -2035,12 +2035,15 @@ int reply_received( struct sip_msg *p_msg ) SEND_BUFFER( &uac->local_cancel ); #endif /* retrs. should be already started so do nothing */ - }else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0, + }else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0, (long)BUSY_BUFFER)==0){ /* try to rebuild it if empty (not set or marked as BUSY). * if BUSY or set just exit, a cancel will be (or was) sent * shortly on this branch */ DBG("tm: reply_received: branch CANCEL created\n"); + /* note that in this case we do not know the reason + (it could be a final reply or a received cancel) + and we don't want to wait for it => no reason */ cancel_branch(t, branch, 0, F_CANCEL_B_FORCE_C); } goto done; /* nothing to do */
El Martes, 2 de Marzo de 2010, Andrei Pelinescu-Onciul escribió:
tm: Reason header copy for received CANCELs
When canceling branches due to a received CANCEL, use the Reason headers in the received CANCEL (all the Reason headers from the received CANCEL will be copied in the generated CANCELs, see RFC3326 for more details).
Hi Andrei, great addition. However there could be a minor security issue:
Perhaps it wouldn't be safe to propagate any Reason header coming in a CANCEL from any sender (imagine you receive a malicius call at 5 o'clock in the night and the hacker added "Reason" header to the CANCEL so you don't find that call in the missed calls list of the phone).
- This local policy could be implemented as follows:
a) Enabling a flag in t_relay() that only makes sense for CANCEL rather than INVITE, so:
if (is_method("CANCEL")) { if ($si == MY_APPLICATION_SERVER_IP) # Allow propagating "Reason" header. t_relay(0x12); else t_relay(); }
or using an explicit flag:
if (is_method("CANCEL")) { if ($si == MY_APPLICATION_SERVER_IP) setflag(FLAG_ALLOW_CANCEL_REASON); t_relay(); }
Opinions? Thanks a lot.
On Mar 02, 2010 at 20:10, I?aki Baz Castillo ibc@aliax.net wrote:
El Martes, 2 de Marzo de 2010, Andrei Pelinescu-Onciul escribi?:
tm: Reason header copy for received CANCELs
When canceling branches due to a received CANCEL, use the Reason headers in the received CANCEL (all the Reason headers from the received CANCEL will be copied in the generated CANCELs, see RFC3326 for more details).
Hi Andrei, great addition. However there could be a minor security issue:
Perhaps it wouldn't be safe to propagate any Reason header coming in a CANCEL from any sender (imagine you receive a malicius call at 5 o'clock in the night and the hacker added "Reason" header to the CANCEL so you don't find that call in the missed calls list of the phone).
- This local policy could be implemented as follows:
a) Enabling a flag in t_relay() that only makes sense for CANCEL rather than INVITE, so:
I've added support for it. It can be turned on/off per transaction by using t_set_no_e2e_cancel_reason(0|1). The default state is controlled by e2e_cancel_reason modparam or runtime config variable (e.g. sercmd cfg.set_now_int tm e2e_cancel_reason 0 # disable).
if (is_method("CANCEL")) { if ($si == MY_APPLICATION_SERVER_IP) # Allow propagating "Reason" header. t_relay(0x12);
^^^^^^^^^^^^^ this would look like this: t_set_no_e2e_cancel_reason(1); t_relay();
else t_relay();
}
Note that you could use t_set_no_e2e_cancel_reason() at any time, before or after creating the transaction. local_cancel_reason can be turned on/off independently, but only globally (I couldn't find any reason for wanting to do it per transaction).
Andrei
El Miércoles, 3 de Marzo de 2010, Andrei Pelinescu-Onciul escribió:
On Mar 02, 2010 at 20:10, I?aki Baz Castillo ibc@aliax.net wrote:
El Martes, 2 de Marzo de 2010, Andrei Pelinescu-Onciul escribi?:
tm: Reason header copy for received CANCELs
When canceling branches due to a received CANCEL, use the Reason headers in the received CANCEL (all the Reason headers from the received CANCEL will be copied in the generated CANCELs, see RFC3326 for more details).
Hi Andrei, great addition. However there could be a minor security issue:
Perhaps it wouldn't be safe to propagate any Reason header coming in a CANCEL from any sender (imagine you receive a malicius call at 5 o'clock in the night and the hacker added "Reason" header to the CANCEL so you don't find that call in the missed calls list of the phone).
- This local policy could be implemented as follows:
a) Enabling a flag in t_relay() that only makes sense for CANCEL rather than INVITE, so:
I've added support for it. It can be turned on/off per transaction by using t_set_no_e2e_cancel_reason(0|1). The default state is controlled by e2e_cancel_reason modparam or runtime config variable (e.g. sercmd cfg.set_now_int tm e2e_cancel_reason 0 # disable).
Great :)
if (is_method("CANCEL")) { if ($si == MY_APPLICATION_SERVER_IP) # Allow propagating "Reason" header. t_relay(0x12);
^^^^^^^^^^^^^ this would look like this: t_set_no_e2e_cancel_reason(1); t_relay();
else t_relay();
}
Note that you could use t_set_no_e2e_cancel_reason() at any time, before or after creating the transaction.
So this can be set during INVITE transaction, right? this is really better than what I suggested.
local_cancel_reason can be turned on/off independently, but only globally (I couldn't find any reason for wanting to do it per transaction).
Neither me as such "Reason" header is trusted (it has been created locally by SR, so it's safe to allow it always).
Thanks a lot.