Beispiel #1
0
/* Re-parsing version of build_local() function:
 * it builds a local CANCEL or ACK (for non-200 response) request based on
 * the previous INVITE which was sent out.
 *
 * Can not be used to build other type of requests!
 */
char *build_local_reparse(struct cell *Trans,unsigned int branch,
	unsigned int *len, char *method, int method_len, str *to
#ifdef CANCEL_REASON_SUPPORT
	, struct cancel_reason *reason
#endif /* CANCEL_REASON_SUPPORT */
	)
{
	char	*invite_buf, *invite_buf_end;
	char	*cancel_buf;
	char	*s, *s1, *d;	/* source and destination buffers */
	short	invite_len;
	enum _hdr_types_t	hf_type;
	int	first_via, to_len;
	int cancel_buf_len;
#ifdef CANCEL_REASON_SUPPORT
	int reason_len, code_len;
	struct hdr_field *reas1, *reas_last, *hdr;
#endif /* CANCEL_REASON_SUPPORT */
	int hadded = 0;
	sr_cfgenv_t *cenv = NULL;

	invite_buf = Trans->uac[branch].request.buffer;
	invite_len = Trans->uac[branch].request.buffer_len;

	if (!invite_buf || !invite_len) {
		LM_ERR("INVITE is missing\n");
		goto error;
	}
	if ((*invite_buf != 'I') && (*invite_buf != 'i')) {
		LM_ERR("trying to build with local reparse"
					" for a non-INVITE request?\n");
		goto error;
	}

#ifdef CANCEL_REASON_SUPPORT
	reason_len = 0;
	reas1 = 0;
	reas_last = 0;
	/* compute reason size (if no reason or disabled => reason_len == 0)*/
	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
		if (likely(reason->cause > 0 &&
					cfg_get(tm, tm_cfg, local_cancel_reason))){
			/* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
			reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
				(reason->u.text.s?
					REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
				CRLF_LEN;
		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS &&
					!(Trans->flags & T_NO_E2E_CANCEL_REASON))) {
			reason_len = reason->u.packed_hdrs.len;
		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
					reason->u.e2e_cancel &&
					!(Trans->flags & T_NO_E2E_CANCEL_REASON)) {
			/* parse the entire cancel, to get all the Reason headers */
			if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) {
				LM_WARN("failed to parse headers\n");
			}
			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 < CANCEL_REAS_MIN))
			LM_BUG("unhandled reason cause %d\n", reason->cause);
	}
#endif /* CANCEL_REASON_SUPPORT */

	invite_buf_end = invite_buf + invite_len;
	s = invite_buf;

	/* Allocate memory for the new message.
	The new request will be smaller than the INVITE, so the same size is enough.
	I just extend it with the length of new To HF to be sure.
	Ugly, but we avoid lots of checks and memory allocations this way */
	to_len = to ? to->len : 0;
#ifdef CANCEL_REASON_SUPPORT
	cancel_buf_len = invite_len + to_len + reason_len;
#else
	cancel_buf_len = invite_len + to_len;
#endif /* CANCEL_REASON_SUPPORT */
	cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len);
	if (!cancel_buf)
	{
		LM_ERR("cannot allocate shared memory\n");
		goto error;
	}
	d = cancel_buf;

	/* method name + space */
	append_str(d, method, method_len);
	*d = ' ';
	d++;
	/* skip "INVITE " and copy the rest of the line including CRLF */
	s += 7;
	s1 = s;
	s = eat_line(s, invite_buf_end - s);
	append_str(d, s1, s - s1);

	cenv = sr_cfgenv_get();

	/* check every header field name,
	we must exclude and modify some of the headers */
	first_via = 1;
	while (s < invite_buf_end) {
		s1 = s;
		if ((*s == '\n') || (*s == '\r')) {
			/* end of SIP msg */
			hf_type = HDR_EOH_T;
		} else {
			/* parse HF name */
			s = lw_get_hf_name(s, invite_buf_end,
						&hf_type);
		}

		switch(hf_type) {
			case HDR_CSEQ_T:
				/* find the method name and replace it */
				while ((s < invite_buf_end)
					&& ((*s == ':') || (*s == ' ') || (*s == '\t') ||
						((*s >= '0') && (*s <= '9')))
					) s++;
				append_str(d, s1, s - s1);
				append_str(d, method, method_len);
				append_str(d, CRLF, CRLF_LEN);
				s = lw_next_line(s, invite_buf_end);
				break;

			case HDR_VIA_T:
				s = lw_next_line(s, invite_buf_end);
				if (first_via) {
					/* copy hf */
					append_str(d, s1, s - s1);
					first_via = 0;
				} /* else skip this line, we need olny the first via */
				break;

			case HDR_TO_T:
				if (to_len == 0) {
					/* there is no To tag required, just copy paste
					 * the header */
					s = lw_next_line(s, invite_buf_end);
					append_str(d, s1, s - s1);
				} else {
					/* use the given To HF instead of the original one */
					append_str(d, to->s, to->len);
					/* move the pointer to the next line */
					s = lw_next_line(s, invite_buf_end);
				}
				break;

			case HDR_FROM_T:
			case HDR_CALLID_T:
			case HDR_ROUTE_T:
			case HDR_MAXFORWARDS_T:
				/* copy hf */
				s = lw_next_line(s, invite_buf_end);
				append_str(d, s1, s - s1);
				break;

			case HDR_REQUIRE_T:
			case HDR_PROXYREQUIRE_T:
				/* skip this line */
				s = lw_next_line(s, invite_buf_end);
				break;

			case HDR_CONTENTLENGTH_T:
				/* copy hf name with 0 value */
				append_str(d, s1, s - s1);
				append_str(d, ": 0" CRLF, 3 + CRLF_LEN);
				/* move the pointer to the next line */
				s = lw_next_line(s, invite_buf_end);
				break;

			case HDR_EOH_T:
				/* end of SIP message found */
#ifdef CANCEL_REASON_SUPPORT
				/* add reason if needed */
				if (reason_len) {
					/* if reason_len !=0, no need for any reason enabled
					 * checks */
					if (likely(reason->cause > 0)) {
						append_str(d, REASON_PREFIX, REASON_PREFIX_LEN);
						code_len=ushort2sbuf(reason->cause, d,
										cancel_buf_len-(int)(d-cancel_buf));
						if (unlikely(code_len==0))
							LM_BUG("not enough space to write reason code");
						d+=code_len;
						if (reason->u.text.s){
							append_str(d, REASON_TEXT, REASON_TEXT_LEN);
							*d='"'; d++;
							append_str(d, reason->u.text.s,
											reason->u.text.len);
							*d='"'; d++;
						}
						append_str(d, CRLF, CRLF_LEN);
					} else if (likely(reason->cause ==
										CANCEL_REAS_PACKED_HDRS)) {
							append_str(d, reason->u.packed_hdrs.s,
											reason->u.packed_hdrs.len);
					} else if (reason->cause == CANCEL_REAS_RCVD_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;
						}
					}
				}
#endif /* CANCEL_REASON_SUPPORT */
				/* 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); */
				return cancel_buf;

			default:
				s = lw_next_line(s, invite_buf_end);
				hadded = 0;

				/* uac auth headers */
				if(Trans->uas.request &&
						(Trans->uas.request->msg_flags & FL_UAC_AUTH)) {
					if(s1 + cenv->uac_cseq_auth.len + 2 < invite_buf_end) {
						if(s1[cenv->uac_cseq_auth.len]==':'
								&& strncmp(s1, cenv->uac_cseq_auth.s,
									cenv->uac_cseq_auth.len)==0) {
							hadded = 1;
							append_str(d, s1, s - s1);
						} else if(s1[cenv->uac_cseq_refresh.len]==':'
								&& strncmp(s1, cenv->uac_cseq_refresh.s,
									cenv->uac_cseq_refresh.len)==0) {
							hadded = 1;
							append_str(d, s1, s - s1);
						}
					}
				}

				if(likely(hadded==0)) {
					if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len
							&& (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end)
							&& (strncasecmp(s1,
									cfg_get(tm, tm_cfg, ac_extra_hdrs).s,
									cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)) {
						append_str(d, s1, s - s1);
					}
				}
				break;
		}
	}

	/* HDR_EOH_T was not found in the buffer, the message is corrupt */
	LM_ERR("HDR_EOH_T was not found\n");

	shm_free(cancel_buf);
error:
	LM_ERR("cannot build %.*s request\n", method_len, method);
	return NULL;

}
Beispiel #2
0
int dlg_cseq_msg_sent(sr_event_param_t *evp)
{
	sip_msg_t msg;
	str *obuf;
	unsigned int direction;
	dlg_cell_t *dlg = NULL;
	str nval = STR_NULL;
	char tbuf[BUF_SIZE];
	int tbuf_len = 0;
	struct via_body *via;
	hdr_field_t *hfk = NULL;
	sr_cfgenv_t *cenv = NULL;

	obuf = (str*)evp->data;
	memset(&msg, 0, sizeof(sip_msg_t));
	msg.buf = obuf->s;
	msg.len = obuf->len;
	cenv = sr_cfgenv_get();

	if(dlg_cseq_prepare_new_msg(&msg)!=0) {
		goto done;
	}

	if(msg.first_line.type==SIP_REPLY) {
		/* nothing to do for outgoing replies */
		goto done;
	}

	LM_DBG("traking cseq updates\n");
	via = (struct via_body*)msg.h_via1->parsed;

	if(via->branch==NULL || via->branch->value.len<=0) {
		LM_DBG("no branch parameter in top via\n");
		goto done;
	}

	direction = DLG_DIR_NONE;
	dlg = dlg_lookup_msg_dialog(&msg, &direction);

	if(dlg == NULL) {
		LM_DBG("no dialog for this request\n");
		goto done;
	}

	/* supported only for downstrem direction */
	if(direction != DLG_DIR_DOWNSTREAM) {
		LM_DBG("request not going downstream (%u)\n", direction);
		goto done;
	}

	if(parse_headers(&msg, HDR_EOH_F, 0)==-1) {
		LM_ERR("failed to parse all headers\n");
	}

	/* check if transaction is marked for a new increment */
	hfk = sr_hdr_get_z(&msg, cenv->uac_cseq_auth.s);
	if(hfk!=NULL) {
		LM_DBG("new cseq inc requested\n");
		nval = hfk->body;
		trim(&nval);
	} else {
		LM_DBG("new cseq inc not requested\n");
	}

	if(nval.len<=0) {
		hfk = sr_hdr_get_z(&msg, cenv->uac_cseq_refresh.s);
		if(hfk!=NULL) {
			LM_DBG("cseq refresh requested\n");
			nval = hfk->body;
			trim(&nval);
		} else {
			LM_DBG("cseq refresh not requested\n");
		}
	}
	if(nval.len<=0) {
		LM_DBG("cseq refresh requested, but no new value found\n");
		goto done;
	}

	if(msg.len + 3 + 2*nval.len>=BUF_SIZE) {
		LM_ERR("new messages is too big\n");
		goto done;
	}
	LM_DBG("updating cseq to: %.*s\n", nval.len, nval.s);

	/* new cseq value */
	dlg->iflags |= DLG_IFLAG_CSEQ_DIFF;

	if(via->branch->value.s<get_cseq(&msg)->number.s) {
		/* Via is before CSeq */
		/* copy first part till after via branch */
		tbuf_len = via->branch->value.s + via->branch->value.len - msg.buf;
		memcpy(tbuf, msg.buf, tbuf_len);
		/* complete via branch */
		tbuf[tbuf_len++] = '.';
		tbuf[tbuf_len++] = 'c';
		tbuf[tbuf_len++] = 's';
		memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len);
		tbuf_len += get_cseq(&msg)->number.len;
		/* copy till beginning of cseq number */
		memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
				get_cseq(&msg)->number.s - via->branch->value.s
				- via->branch->value.len);
		tbuf_len += get_cseq(&msg)->number.s - via->branch->value.s
					- via->branch->value.len;
		/* add new value */
		memcpy(tbuf+tbuf_len, nval.s, nval.len);
		tbuf_len += nval.len;
		if(hfk && hfk->name.s > get_cseq(&msg)->number.s) {
			/* copy from after cseq number to the beginning of hfk */
			memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
					hfk->name.s - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len);
			tbuf_len += hfk->name.s - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len;
			/* copy from after hfk to the end of sip message */
			memcpy(tbuf+tbuf_len,  hfk->name.s + hfk->len,
					msg.buf + msg.len - hfk->name.s - hfk->len);
			tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len;
		} else {
			/* copy from after cseq number to the end of sip message */
			memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
					msg.buf + msg.len - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len);
			tbuf_len += msg.buf+msg.len - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len;
		}
	} else {
		/* CSeq is before Via */
		/* copy till beginning of cseq number */
		tbuf_len = get_cseq(&msg)->number.s - msg.buf;
		memcpy(tbuf, msg.buf, tbuf_len);
		/* add new value */
		memcpy(tbuf+tbuf_len, nval.s, nval.len);
		tbuf_len += nval.len;
		/* copy from after cseq number to the after via branch */
		memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
				via->branch->value.s + via->branch->value.len
				- get_cseq(&msg)->number.s - get_cseq(&msg)->number.len);
		tbuf_len += via->branch->value.s + via->branch->value.len
				- get_cseq(&msg)->number.s - get_cseq(&msg)->number.len;
		/* complete via branch */
		tbuf[tbuf_len++] = '.';
		tbuf[tbuf_len++] = 'c';
		tbuf[tbuf_len++] = 's';
		memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len);
		tbuf_len += get_cseq(&msg)->number.len;
		if(hfk && hfk->name.s > get_cseq(&msg)->number.s) {
			/* copy from after via to the beginning of hfk */
			memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
					hfk->name.s - via->branch->value.s
					- via->branch->value.len);
			tbuf_len += hfk->name.s - via->branch->value.s
					- via->branch->value.len;
			/* copy from after hfk to the end of sip message */
			memcpy(tbuf+tbuf_len,  hfk->name.s + hfk->len,
					msg.buf + msg.len - hfk->name.s - hfk->len);
			tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len;
		} else {
			/* copy from after via to the end of sip message */
			memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
					msg.buf + msg.len - via->branch->value.s
					- via->branch->value.len);
			tbuf_len += msg.buf+msg.len - via->branch->value.s
					- via->branch->value.len;
		}
	}
	/* replace old msg content */
	obuf->s = pkg_malloc((tbuf_len+1)*sizeof(char));
	if(obuf->s==NULL) {
		LM_ERR("not enough memory for new message\n");
		goto done;
	}
	memcpy(obuf->s, tbuf, tbuf_len);
	obuf->s[tbuf_len] = 0;
	obuf->len = tbuf_len;

done:
	if(dlg!=NULL) dlg_release(dlg);
	free_sip_msg(&msg);
	return 0;
}
Beispiel #3
0
int uac_auth(sip_msg_t *msg)
{
	static struct authenticate_body auth;
	struct uac_credential *crd;
	int code, branch;
	struct sip_msg *rpl;
	struct cell *t;
	struct hdr_field *hdr;
	HASHHEX response;
	str *new_hdr;
	sr_cfgenv_t *cenv = NULL;

	/* get transaction */
	t = uac_tmb.t_gett();
	if (t==T_UNDEFINED || t==T_NULL_CELL)
	{
		LM_CRIT("no current transaction found\n");
		goto error;
	}

	/* get the selected branch */
	branch = uac_tmb.t_get_picked_branch();
	if (branch<0) {
		LM_CRIT("no picked branch (%d)\n",branch);
		goto error;
	}

	rpl = t->uac[branch].reply;
	code = t->uac[branch].last_received;
	LM_DBG("picked reply is %p, code %d\n",rpl,code);

	if (rpl==0)
	{
		LM_CRIT("empty reply on picked branch\n");
		goto error;
	}
	if (rpl==FAKED_REPLY)
	{
		LM_ERR("cannot process a FAKED reply\n");
		goto error;
	}

	hdr = get_autenticate_hdr( rpl, code);
	if (hdr==0)
	{
		LM_ERR("failed to extract authenticate hdr\n");
		goto error;
	}

	LM_DBG("header found; body=<%.*s>\n",
		hdr->body.len, hdr->body.s);

	if (parse_authenticate_body( &hdr->body, &auth)<0)
	{
		LM_ERR("failed to parse auth hdr body\n");
		goto error;
	}

	/* can we authenticate this realm? */
	crd = 0;
	/* first look into AVP, if set */
	if ( auth_realm_spec.type!=PVT_NONE )
		crd = get_avp_credential( msg, &auth.realm );
	/* if not found, look into predefined credentials */
	if (crd==0)
		crd = lookup_realm( &auth.realm );
	/* found? */
	if (crd==0)
	{
		LM_DBG("no credential for realm \"%.*s\"\n",
			auth.realm.len, auth.realm.s);
		goto error;
	}

	/* do authentication */
	do_uac_auth( &msg->first_line.u.request.method,
			&t->uac[branch].uri, crd, &auth, response);

	/* build the authorization header */
	new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
		crd, &auth, response);
	if (new_hdr==0)
	{
		LM_ERR("failed to build authorization hdr\n");
		goto error;
	}

	/* so far, so good -> add the header and set the proper RURI */
	if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
	{
		LM_ERR("failed to apply changes\n");
		goto error;
	}

	/* mark request in T with uac auth for increase of cseq via dialog
	 * - this function is executed in failure route, msg_flags will be
	 *   reset afterwards by tm fake env */
	if(t->uas.request) {
		t->uas.request->msg_flags |= FL_UAC_AUTH;
		cenv = sr_cfgenv_get();
		if(cenv->cb_cseq_update != NULL) {
			if(cenv->cb_cseq_update(msg)<0) {
				goto error;
			}
		}
	}

	return 0;
error:
	return -1;
}
Beispiel #4
0
int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
		unsigned int direction)
{
	unsigned int ninc = 0;
	unsigned int vinc = 0;
	str nval;
	str *pval;
	sr_cfgenv_t *cenv = NULL;

	if(dlg_cseq_prepare_msg(msg)!=0) {
		goto error;
	}
	if(msg->first_line.type==SIP_REPLY) {
		/* nothing to do for outgoing replies */
		goto done;
	}

	LM_DBG("initiating cseq refresh\n");

	/* supported only for downstrem direction */
	if(direction != DLG_DIR_DOWNSTREAM) {
		LM_DBG("request not going downstream (%u)\n", direction);
		goto done;
	}

	/* take the increment value from dialog */
	if(!((dlg->iflags&DLG_IFLAG_CSEQ_DIFF)==DLG_IFLAG_CSEQ_DIFF)) {
		LM_DBG("no cseq refresh required\n");
		goto done;
	}

	/* get dialog variable holding cseq diff */
	pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name);
	if(pval==NULL || pval->s==NULL || pval->len<=0) {
		LM_DBG("dialog marked with cseq diff but no variable set yet\n");
		goto done;
	}

	if(str2int(pval, &vinc)<0) {
		LM_ERR("invalid dlg cseq diff var value: %.*s\n",
					pval->len, pval->s);
		goto done;
	}
	if(vinc==0) {
		LM_DBG("nothing to increment\n");
		goto done;
	}

	str2int(&get_cseq(msg)->number, &ninc);
	vinc += ninc;
	nval.s = int2str(vinc, &nval.len);
	trim(&nval);

	LM_DBG("adding cseq refresh header value: %.*s\n", nval.len, nval.s);
	if(parse_headers(msg, HDR_EOH_F, 0)==-1) {
		LM_ERR("failed to parse all headers\n");
	}
	cenv = sr_cfgenv_get();
	sr_hdr_add_zs(msg, cenv->uac_cseq_refresh.s, &nval);

done:
	return 0;

error:
	return -1;
}