Exemple #1
0
/**
 * Check if the message is from the AS.
 * Inserts route headers and set the dst_uri
 * @param msg - the message to check
 * @param str1 - the direction of the request orig/term
 * @param str2 - not used
 * @returns #ISC_RETURN_TRUE if session should continue, #ISC_RETURN_FALSE if not, #ISC_RETURN_BREAK on error
 */
int ISC_is_session_continued(struct sip_msg *msg,char *str1,char *str2)
{
	int ret = ISC_RETURN_FALSE;
	isc_mark old_mark;
	struct sip_msg *req;

	req = cscf_get_request_from_reply(msg);
	
	if (!req) {
		LOG(L_ERR,"ERR:"M_NAME":ISC_is_session_continued(): There is no transaction \n");			
		return ISC_RETURN_FALSE;
	}
	
	if (!isc_is_initial_request(req)) {
		LOG(L_ERR,"ERR:"M_NAME":ISC_is_session_continued(): This is no initial request \n");			
		return ISC_RETURN_FALSE;
	}
		
	/* starting or resuming? */
	if (isc_mark_get_from_lump(req,&old_mark)){		
		LOG(L_INFO,"INFO:"M_NAME":ISC_is_session_continued(): Message returned handling [%d] \n",old_mark.handling);
		if (old_mark.handling == IFC_SESSION_CONTINUED) 
			ret = ISC_RETURN_TRUE;
		else 
			ret = ISC_RETURN_FALSE;
	} else {
		LOG(L_ERR,"ERR:"M_NAME":ISC_is_session_continued(): mark not found in lump \n");					
		ret = ISC_RETURN_ERROR;
	}
	return ret;
}
Exemple #2
0
/**
 * enforce a response coming from a UE to contain the same Via headers sent in the corresponding request
 * @param rpl - the SIP reply
 * @param str1 - not used
 * @param str2 - not used
 * @returns true if ok, false if not or error
 */
int P_enforce_via_list(struct sip_msg *rpl,char *str1, char *str2)
{
	static struct hdr_field * h = NULL;
	str hdr;

	cscf_del_all_headers(rpl, HDR_VIA_T);

	struct sip_msg *req = cscf_get_request_from_reply(rpl);
	
	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_via_list: No transactional request found.\n");
		return CSCF_RETURN_FALSE;
	
	}

	h = cscf_get_next_via_hdr(req,0);
	while (h)
	{
		hdr.len = h->body.len + via_hdr_s.len + via_hdr_e.len;
		hdr.s = pkg_malloc(hdr.len);
		if (!hdr.s)
		{
			LOG(L_ERR, "ERR:"M_NAME":P_enforce_via_list: cannot alloc bytes : %d", hdr.len);
		}
		hdr.len=0;
		STR_APPEND(hdr, via_hdr_s);
		STR_APPEND(hdr, h->body);
		STR_APPEND(hdr, via_hdr_e);
		cscf_add_header_first(rpl, &hdr, HDR_VIA_T);
		h = cscf_get_next_via_hdr(req,h);
	}
	
	return CSCF_RETURN_TRUE;
}
Exemple #3
0
/**
 * Checks if a response coming from a UE contains the same Via headers sent in the corresponding request
 * @param rpl - the SIP reply
 * @param str1 - not used
 * @param str2 - not used
 * @returns true if ok, false if not or error
 */
int P_follows_via_list(struct sip_msg *rpl,char *str1, char *str2)
{
	int h_req_pos, h_rpl_pos,indx_rpl, indx_req;
	struct hdr_field *h_req=NULL, *h_out_req, *h_rpl=NULL, *h_out_rpl;
	str via_req={0,0}, via_rpl={0,0};

	struct sip_msg *req = cscf_get_request_from_reply(rpl);	
	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_via_list: No transactional request found.\n");
		return CSCF_RETURN_ERROR;
	}	

	indx_rpl = indx_req = 0;
	//get via headers
	via_rpl = cscf_get_next_via_str(rpl, 0, 0, &h_out_rpl, &h_rpl_pos);
	while (via_rpl.len)
	{
		if (indx_rpl > 0) //first header from reply shouldn't be checked
		{
			if (indx_req == 0)
			{
				via_req = cscf_get_next_via_str(req, 0, 0, &h_out_req, &h_req_pos);
				if (!via_req.len || !cscf_str_via_matching(&via_req, &via_rpl))
				{
					LOG(L_INFO,"DBG:"M_NAME":P_follows_via_list: first via not matching <%.*s>!=<%.*s>\n",
						via_req.len,via_req.s,via_rpl.len,via_rpl.s);
					return CSCF_RETURN_FALSE; 
				}
			}
			else
			{
				if (!via_req.len || (via_req.len!=via_rpl.len) || (strncasecmp(via_req.s, via_rpl.s, via_req.len)))
				{
					LOG(L_INFO,"DBG:"M_NAME":P_follows_via_list: not matching <%.*s>!=<%.*s>\n",
						via_req.len,via_req.s,via_rpl.len,via_rpl.s);
					return CSCF_RETURN_FALSE;
				}
			}
			indx_req++;
			h_req = h_out_req;
			if (!h_req)
			{
				break;
			}
			via_req = cscf_get_next_via_str(req, h_req, h_req_pos , &h_out_req, &h_req_pos);
		}
		indx_rpl++;
		h_rpl = h_out_rpl;
		if (!h_rpl) break;
		via_rpl = cscf_get_next_via_str(rpl, h_rpl, h_rpl_pos , &h_out_rpl, &h_rpl_pos);
	}

	if (h_out_req || h_out_rpl) //remaining headers ...
	{ 
		LOG(L_INFO,"DBG:"M_NAME":P_follows_via_list: header count not matching \n");
		return CSCF_RETURN_FALSE;
	}
	return CSCF_RETURN_TRUE;
}
/**
 * Enforce a response coming from a UE to contain the same Record Route headers sent in the
 * corresponding request.
 * @param msg - the SIP reply
 * @param str1 - not used
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE on success, #CSCF_RETURN_ERROR on error
 */
int P_enforce_record_routes(struct sip_msg *msg,char *str1, char *str2)
{
	str hdr = {0,0};
	str rr_req = {0,0};
	struct sip_msg *req = cscf_get_request_from_reply(msg);

	LOG(L_INFO,"INF:"M_NAME":P_enforce_record_routes(): Enforcing RR in %d reply with the request ones\n",
			msg->first_line.u.reply.statuscode);

	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): No transactional request found.\n");
		return CSCF_RETURN_ERROR;
	}
	
	if(!cscf_del_all_headers(msg, HDR_RECORDROUTE_T)){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): error while deleting headers\n");
		return CSCF_RETURN_ERROR;
	}
	
	rr_req = cscf_get_record_routes(req);
	if(rr_req.len){
		hdr.len = pcscf_record_route_mt.len + s_record_route_s.len + rr_req.len+s_record_route_e.len;
		if(!(hdr.s = pkg_malloc(hdr.len))){
		    LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): Unable to allocate memory for hdr\n");
		    goto out_of_memory;
		}
		hdr.len = 0;
		STR_APPEND(hdr,pcscf_record_route_mt);
		STR_APPEND(hdr,s_record_route_s);
		STR_APPEND(hdr,rr_req);
		STR_APPEND(hdr,s_record_route_e);		
	}else{		
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): Unable to get record routes - the RR should not be empty...\n");
		// still, let it continue, maybe it was empty on purpose
		//return CSCF_RETURN_ERROR;
		STR_PKG_DUP(hdr,pcscf_record_route_mt,"pkg");
	}
	
	if(!cscf_add_header_first(msg,&hdr,HDR_RECORDROUTE_T)){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_record_routes(): Unable to add header\n");
		if (hdr.s) pkg_free(hdr.s);
		return CSCF_RETURN_FALSE;
	}

	return CSCF_RETURN_TRUE;
	
out_of_memory:
	return CSCF_RETURN_ERROR;
}
Exemple #5
0
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	p_dialog *d;
	int hash;
	str host;
	int port,transport;
	struct sip_msg *req;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_drop_dialog(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":P_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_p_dialog(d);
		
	d_unlock(hash);
	
	print_p_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
/*
 * delete the user data of the current user if exists(the URI is the R-URI of the current OPTIONS msg)
 * @param msg: current OPTIONS request
 * @param str1: not used
 * @param str2: not used
 */
int LRF_del_user_data(struct sip_msg* msg, char*str1, char*str2){

	str user_uri;
	user_d * d;
	unsigned int hash;
	str service;

	if (msg->first_line.u.request.method.len!=7||
		memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){
		LOG(L_WARN,"WARN:"M_NAME":LRF_del_user_data: The method is not an OPTIONS, trying to replace the message\n");

		msg = cscf_get_request_from_reply(NULL);
		if(! msg || msg->first_line.type!=SIP_REQUEST || msg->first_line.u.request.method.len!=7||
			memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){
					
			LOG(L_ERR,"BUG:"M_NAME":LRF_del_user_data: The new message is not an OPTIONS request either\n");
			return CSCF_RETURN_ERROR;
		}
	}

	service = cscf_get_headers_content(msg , service_hdr_name);
	if(!service.len || !service.s){
		LOG(L_ERR, "ERR:"M_NAME":LRF_del_user_data: could not find the service header in the OPTIONS, or could not be parsed\n");
		return CSCF_RETURN_FALSE;
	}

	str callid = cscf_get_call_id(msg, NULL);
	if(!callid.s || !callid.len){
		LOG(L_ERR, "ERR:"M_NAME":LRF_get_psap: could not find the callid header in the OPTIONS request\n");
		return CSCF_RETURN_FALSE;
	}

	user_uri = msg->first_line.u.request.uri;
	d = get_user_data(user_uri, service, callid);
	if(!d) return CSCF_RETURN_FALSE;

	if(d->loc_subscr)
		del_loc_subscription((loc_subscription*)d->loc_subscr);
	hash = d->hash;
	del_user_data(d);
	lrf_unlock(hash);

	return CSCF_RETURN_TRUE;
}
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int LRF_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	lrf_dialog *d;
	int hash;
	struct sip_msg *req;
	enum lrf_dialog_direction dir;
	str target_uri = {0,0};
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&target_uri)){
		LOG(L_ERR,"ERR:"M_NAME":LRF_is_in_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":LRF_drop_dialog(%s): Call-ID <%.*s>: target <%.*s>\n",
		str1,call_id.len,call_id.s,
		target_uri.len, target_uri.s);
	d = get_lrf_dialog(call_id, &dir);
	if (!d)
		d = get_lrf_dialog(call_id, NULL);
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":LRF_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_lrf_dialog(d);
		
	d_unlock(hash);
	
	print_lrf_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
/* Send a transaction reply
 * could be used after to send replies to the OPTIONS trans
 * @param msg  - (possible)the OPTIONS request from the ECSCF
 * @param str1 - reply code 
 * @param str2 - reply reason
 * @return CSCF_RETURN_TRUE if ok, or CSCF_RETURN_FALSE if error
 */
int LRF_options_empty_repl(struct sip_msg* msg, char*str1, char*str2){

	LOG(L_INFO, "INFO:"M_NAME":LRF_options_empty_repl\n");

	if (msg->first_line.u.request.method.len!=7||
		memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){
		LOG(L_WARN,"WARN:"M_NAME":LRF_options_empty_repl: The method is not an OPTIONS, trying to replace the message\n");

		msg = cscf_get_request_from_reply(NULL);
		if(! msg || msg->first_line.type!=SIP_REQUEST || msg->first_line.u.request.method.len!=7||
			memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){
					
			LOG(L_ERR,"BUG:"M_NAME":LRF_options_empty_repl: The new message is not an OPTIONS request either\n");
			return CSCF_RETURN_ERROR;
		}
	}

	cscf_reply_transactional(msg, 400, str2);
	return CSCF_RETURN_TRUE;
}
Exemple #9
0
//static int check_user_natted(struct sip *msg, struct sip_uri *uri){
int P_SDP_manipulate(struct sip_msg *msg,char *str1,char *str2)
{
	int response = CSCF_RETURN_FALSE ;
	int method;
	struct sip_msg *req=0;

	if (!pcscf_nat_enable || !rtpproxy_enable) return CSCF_RETURN_FALSE;
	
    if( check_content_type(msg) ) 
    {
	    if (msg->first_line.type == SIP_REQUEST) method = msg->first_line.u.request.method_value;
	    else {
	    	req = cscf_get_request_from_reply(msg);
	    	if (req){
	    		method = req->first_line.u.request.method_value;
	    	}else method=METHOD_UNDEF;
	    }
		switch(method)
		{	
		    case METHOD_INVITE:
		    	if (msg->first_line.type == SIP_REQUEST){
			 		/* on INVITE */
					/* check the sdp if it has a 1918 */
					if(1)
					{
					/* get rtp_proxy/nathelper to open ports - get a iovec*/
						response = force_rtp_proxy2_f(msg,"","") ;
						LOG(L_CRIT,"DBG:"M_NAME":P_SDP_manipulate: ... rtp proxy done\n");			    	
				    } else {			
						/* using public ip */
						LOG(L_CRIT,"DBG:"M_NAME":P_SDP_manipulate: ... found public network in SDP.\n");
				    	response = CSCF_RETURN_FALSE ;
				    }
		    	}else{
		    		if (msg->first_line.u.reply.statuscode == 183 ||
				    	(msg->first_line.u.reply.statuscode >= 200 &&
				    	 msg->first_line.u.reply.statuscode < 300)) {
					    if(1)
					    {
						/* sdp_1918(msg) */
						/* str1 & str2 must be something */
						    response = force_rtp_proxy2_f(msg, "", "") ;						
							LOG(L_CRIT,"DBG:"M_NAME":P_SDP_manipulate: ... rtp proxy done\n");			    	
						} else {
							/* public ip found */
							response = CSCF_RETURN_FALSE ;						
						}
						break;
			    	}
		    	}
			    break ;
		    case METHOD_BYE:
		    case METHOD_CANCEL:
				LOG(L_CRIT,"DBG:"M_NAME":P_SDP_manipulate: on BYE/CANCEL...\n");
		    	if (msg->first_line.type == SIP_REQUEST){
    			    /* request/response not acceptable */
				    response = unforce_rtp_proxy_f(msg,-1) ;
		    	}
				break;
	
		    default:
		    	response = CSCF_RETURN_FALSE;
				break; 
		}    
    } else {
		LOG(L_ERR, "ERROR:check_content_type: parse error:"
			"see the content_type block\n");
		response = -1 ;
    }	

return response ;
}
Exemple #10
0
/**
 * Process the 200 response for REGISTER and creates the first Security-Associations.
 * The rest of the SA are not set.
 * could come over that one. 
 * @param rpl - the 200 response
 * @param str1 - not used
 * @param str2 - not used
 * @returns 1 if ok, 0 if not
 */
int P_security_200(struct sip_msg *rpl,char *str1, char *str2)
{
	struct sip_msg *req;
	str sec_hdr;
	r_security_type sec_type;
	float sec_q;
	struct hdr_field *h;
	struct via_body *vb;
	r_contact *c;
	r_ipsec *i;
	int expires;
	unsigned long s_hash;
	char out_rpl[256],out_req[256],inc_rpl[256];

	if (!pcscf_use_ipsec &&!pcscf_use_tls) goto	ret_false;

	req = cscf_get_request_from_reply(rpl);
	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_security_200: No transactional request found.\n");
		goto error;
	}	

	sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q);	
	if (!sec_hdr.len) {	
		LOG(L_DBG,"DBG:"M_NAME":P_security_200: No Security-Verify header found.\n");
		goto error;
	}
	
	/* find the expires (reg or dereg?) */
	expires = cscf_get_max_expires(req);
	
	/* get the IPSec info from the registrar */
	
	vb = cscf_get_first_via(req,&h);	
	LOG(L_DBG,"DBG:"M_NAME":P_security_200: Looking for <%d://%.*s:%d> \n",
		vb->proto,vb->host.len,vb->host.s,vb->port);

	c = get_r_contact(vb->host,vb->port,vb->proto);
		
	r_act_time();
	if (!c){
		LOG(L_ERR,"ERR:"M_NAME":P_security_200: Contact not found\n");		
		goto error;
	}
	
	if (c->security_temp){
		if (c->security && c->security->type == SEC_TLS && 
				(c->security->data.tls && c->security->data.tls->port_tls==req->rcv.src_port&& 
				 c->security->data.tls->session_hash!=0 && c->security->data.tls->session_hash == tls_get_session_hash(req))){
			/* don't replace security when doing an integrity protected REGISTER with
			 *  possible attack-garbage from security_temp */
			P_security_drop(c,c->security_temp);
			free_r_security(c->security_temp);
			c->security_temp = 0;
		}
		else
		{	
			if (c->security) {
				P_security_drop(c,c->security);
				free_r_security(c->security);
			}
			
			c->security = c->security_temp;
			c->security_temp = 0;
		}
	}	
	
	switch(sec_type){
		case SEC_NONE:
			break;
		case SEC_TLS:
			if (c->security && pcscf_use_tls) {
				r_tls *tls;
				int port_tls = req->rcv.src_port;
				s_hash = get_tls_session_hash(req);
				if (!s_hash){
					LOG(L_ERR,"ERR:"M_NAME":P_security_200: Session Hash could not be obtained !\n");
					r_unlock(c->hash);
					goto error;
				}	
				tls = new_r_tls(port_tls, s_hash);
				if (!tls) goto error;
				c->security->data.tls = tls;
			} 		
			r_unlock(c->hash);
			break;
		case SEC_IPSEC:
			if (!r_valid_contact(c)||!c->security||!c->security->data.ipsec ){
				LOG(L_DBG,"DBG:"M_NAME":P_security_200: Contact expired or no IPSec info\n");
				r_unlock(c->hash);
				goto error;
			}
			i = c->security->data.ipsec;
			
			/* P_Out_Rpl */
			sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
				pcscf_ipsec_P_Out_Rpl,
				c->host.len,c->host.s,
				i->port_uc,
				pcscf_ipsec_host,
				pcscf_ipsec_port_s,
				i->spi_uc,
				i->ealg.len,i->ealg.s,
				i->ck.len,i->ck.s,
				i->alg.len,i->alg.s,
				i->ik.len,i->ik.s	);					
	
			/* P_Out_Req */
			sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
				pcscf_ipsec_P_Out_Req,
				c->host.len,c->host.s,
				i->port_us,
				pcscf_ipsec_host,
				pcscf_ipsec_port_c,
				i->spi_us,
				i->ealg.len,i->ealg.s,
				i->ck.len,i->ck.s,
				i->alg.len,i->alg.s,
				i->ik.len,i->ik.s	);								
			/* P_Out_Inc_Rpl */
			sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
				pcscf_ipsec_P_Inc_Rpl,
				c->host.len,c->host.s,
				i->port_us,
				pcscf_ipsec_host,
				pcscf_ipsec_port_c,
				i->spi_pc,
				i->ealg.len,i->ealg.s,
				i->ck.len,i->ck.s,
				i->alg.len,i->alg.s,
				i->ik.len,i->ik.s	);								
				
			if (expires<=0) {
				/* Deregister */
				c->reg_state = DEREGISTERED;
				r_act_time();
				c->expires = time_now + 60;
			}			
			r_unlock(c->hash);
		
			//print_r(L_CRIT);
			
			/* run the IPSec scripts */	
			/* Registration */
			execute_cmd(out_rpl);		
			execute_cmd(out_req);		
			execute_cmd(inc_rpl);
			break;
	}
	
	return CSCF_RETURN_TRUE;
ret_false:
	return CSCF_RETURN_FALSE;
error:
	return CSCF_RETURN_ERROR;
}
Exemple #11
0
/**
 * Process the 401 response for REGISTER and creates the first Security-Associations.
 * IPSEc: Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER
 * could come over that one. 
 * @param rpl - the 401 response
 * @param str1 - not used
 * @param str2 - not used
 * @returns 1 if ok, 0 if not
 */
int P_security_401(struct sip_msg *rpl,char *str1, char *str2)
{
	struct sip_msg *req;
	struct hdr_field *hdr;	
	str sec_hdr,sec_srv={0,0};
	r_security_type sec_type;
	char cmd[256];
	r_contact *c;
	r_ipsec *ipsec;
	float sec_q=-1;
	str auth;

	if (!pcscf_use_ipsec &&!pcscf_use_tls) goto	ret_false;
	
	req = cscf_get_request_from_reply(rpl);
	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_security_401: No transactional request found.\n");
		goto error;
	}
	auth = cscf_get_authenticate(rpl,&hdr);
	if (!auth.len){
		LOG(L_ERR,"ERR:"M_NAME":P_security_401: No WWW-Authenticate header found.\n");
		goto ret_false; 
	}
	
	sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q);
	if (!sec_hdr.len) {	
		LOG(L_DBG,"DBG:"M_NAME":P_security_401: No Security-Client header found.\n");
		goto ret_false;
	}
	LOG(L_INFO,"DBG:"M_NAME":P_security_401: Security-Client header found : <%.*s>.\n", sec_hdr.len, sec_hdr.s);	


	/* save data into registrar */
	c = save_contact_security(req, auth, sec_hdr, sec_type, sec_q);	
	if (!c) goto error;
	switch(sec_type){
		case SEC_NONE:
			break;
		case SEC_TLS:			
			/* try to add the Security-Server header */		
			sec_srv.len = s_security_server_s.len+sec_hdr.len+s_security_server_e.len;
			sec_srv.s = pkg_malloc(sec_srv.len);
			if (!sec_srv.s){
				LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len);
				goto error;
			}
			sec_srv.len=0;
			STR_APPEND(sec_srv,s_security_server_s);
			STR_APPEND(sec_srv,sec_hdr);
			STR_APPEND(sec_srv,s_security_server_e);

			if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
				LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
				pkg_free(sec_srv.s);
				goto error;
			}
			break;
		case SEC_IPSEC:
			ipsec = c->security_temp->data.ipsec;
			/* try to add the Security-Server header */
			sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n",
				ipsec->r_ealg.len,ipsec->r_ealg.s,
				ipsec->r_alg.len,ipsec->r_alg.s,
				ipsec->spi_pc,ipsec->spi_ps,
				pcscf_ipsec_port_c,pcscf_ipsec_port_s);
			
			sec_srv.len = strlen(cmd);
			sec_srv.s = pkg_malloc(sec_srv.len);
			if (!sec_srv.s){
				LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len);
				goto error;
			}
			memcpy(sec_srv.s,cmd,sec_srv.len);
			if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
				LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
				pkg_free(sec_srv.s);
				goto error;
			}
	
			/* run the IPSec script */	
			/* P_Inc_Req */
			sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
				pcscf_ipsec_P_Inc_Req,
				c->host.len,c->host.s,
				ipsec->port_uc,
				pcscf_ipsec_host,
				pcscf_ipsec_port_s,
				ipsec->spi_ps,
				ipsec->ealg.len,ipsec->ealg.s,
				ipsec->ck.len,ipsec->ck.s,
				ipsec->alg.len,ipsec->alg.s,
				ipsec->ik.len,ipsec->ik.s);

			r_unlock(c->hash);
				
			execute_cmd(cmd);
			break;						
	}
	
	return CSCF_RETURN_TRUE;
ret_false:
	return CSCF_RETURN_FALSE;
error:
	return CSCF_RETURN_ERROR;
}
Exemple #12
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	p_dialog *d;
	int response;
	int cseq;
	struct hdr_field *h=0;
	struct sip_msg *req=0;
	str host;
	int port,transport;
	int expires;
	str totag;
	time_t t_time=0;
	str ses_exp = {0,0};
	str refresher = {0,0};
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		if (msg->first_line.type==SIP_REQUEST &&
			msg->first_line.u.request.method.len == 3 && 
			strncasecmp(msg->first_line.u.request.method.s,"ACK",3)){
			/* to skip the ACK after a 4xx when the dialog was dropped already*/
			return CSCF_RETURN_TRUE;
		}else{
			LOG(L_CRIT,"ERR:"M_NAME":P_update_dialog: dialog does not exists!\n");
			return CSCF_RETURN_FALSE;
		}	
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
		{
			d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
	
			ses_exp = cscf_get_session_expires_body(msg, &h);
			t_time = cscf_get_session_expires(ses_exp, &refresher);
			if (!t_time){
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
				d->lr_session_expires = 0;
			} else {
				d->expires = d_act_time() + t_time;
				d->lr_session_expires = t_time;
				if (refresher.len)
					STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
			}
		}
		else if (d->method == DLG_METHOD_SUBSCRIBE && 
			msg->first_line.u.request.method.len == 6 && 
			strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
		{
			// Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2
			expires = cscf_get_subscription_state(msg);
			if (expires >= 0)
			{
				d->expires = d_act_time()+expires;
			}
			else
			{
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
			}
		}
		else
		{
			expires = cscf_get_expires_hdr(msg);
			if (expires >= 0) 
			{
				LOG(L_INFO,"DBG:"M_NAME":P_update_dialog(%.*s): Update expiration time to %d via Expire header 2\n",call_id.len,call_id.s,expires);
				d->expires = d_act_time()+expires;
			}
			else
			{
				LOG(L_INFO,"INF:"M_NAME": update_dialog(%.*s): d->expires+=pcscf_dialogs_expiration_time 4\n",call_id.len,call_id.s);
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
			}
			d->lr_session_expires = 0;		
		}
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200 && response>100){
				save_dialog_routes(msg,str1,d);
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
			}else
			if (response>=200 && response<300){
				save_dialog_routes(msg,str1,d);
				d->state = DLG_STATE_CONFIRMED;
				
				update_dialog_on_reply(msg, d);
				
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
				
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					return P_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					expires = cscf_get_expires_hdr(msg);
					if (expires >= 0)
					{
						d->expires = d_act_time()+expires;
					}
					else
					{
						d->expires = d_act_time()+pcscf_dialogs_expiration_time;
					}
					d->lr_session_expires = 0;
					break;
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return P_drop_dialog(msg,str1,str2);
					}
					update_dialog_on_reply(msg, d);
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_drop_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return P_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = d_act_time() + expires;
						}
					}
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;
		}
	}
	
	d_unlock(d->hash);
	
	print_p_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	d_unlock(d->hash);
	return CSCF_RETURN_ERROR;	
}
Exemple #13
0
/**
 * Process the 200 response for REGISTER and creates the first Security-Associations.
 * The rest of the SA are not set.
 * could come over that one. 
 * @param rpl - the 200 response
 * @param str1 - not used
 * @param str2 - not used
 * @returns 1 if ok, 0 if not
 */
int P_IPSec_200(struct sip_msg *rpl,char *str1, char *str2)
{
	struct sip_msg *req;
	struct hdr_field *hdr;	
	str sec_cli;
	struct hdr_field *h;
	struct via_body *vb;
	r_contact *c;
	r_ipsec *i;
	int expires;
	char out_rpl[256],out_req[256],inc_rpl[256];

	req = cscf_get_request_from_reply(rpl);
	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: No transactional request found.\n");
		goto error;
	}	
	/* just to jump out if no IPSec is employed - the info is already saved */
	sec_cli = cscf_get_security_client(req,&hdr);
	if (!sec_cli.len){
		LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: No Security-Client header found.\n");
		goto error; 
	}

	/* find the expires (reg or dereg?) */
	expires = cscf_get_max_expires(req);
	
	/* get the IPSec info from the registrar */
	
	vb = cscf_get_first_via(req,&h);
//	if (!h||!h->parsed){
//		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Error extracting sender's id.\n");
//		goto error;
//	}		
//	vb = (struct via_body*) h->parsed;
	
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Looking for <%d://%.*s:%d> \n",
		vb->proto,vb->host.len,vb->host.s,vb->port);

	c = get_r_contact(vb->host,vb->port,vb->proto);
		
	r_act_time();
	if (!c){
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Contact not found\n");		
		goto error;
	}
	if (!r_valid_contact(c)||!c->ipsec){
		LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Contact expired or no IPSec info\n");
		r_unlock(c->hash);
		goto error;
	}
	
	i = c->ipsec;
		
	/* P_Out_Rpl */
	sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
		pcscf_ipsec_P_Out_Rpl,
		c->host.len,c->host.s,
		i->port_uc,
		pcscf_ipsec_host,
		pcscf_ipsec_port_s,
		i->spi_uc,
		i->ealg.len,i->ealg.s,
		i->ck.len,i->ck.s,
		i->alg.len,i->alg.s,
		i->ik.len,i->ik.s	);					

	/* P_Out_Req */
	sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
		pcscf_ipsec_P_Out_Req,
		c->host.len,c->host.s,
		i->port_us,
		pcscf_ipsec_host,
		pcscf_ipsec_port_c,
		i->spi_us,
		i->ealg.len,i->ealg.s,
		i->ck.len,i->ck.s,
		i->alg.len,i->alg.s,
		i->ik.len,i->ik.s	);								
	/* P_Out_Inc_Rpl */
	sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
		pcscf_ipsec_P_Inc_Rpl,
		c->host.len,c->host.s,
		i->port_us,
		pcscf_ipsec_host,
		pcscf_ipsec_port_c,
		i->spi_pc,
		i->ealg.len,i->ealg.s,
		i->ck.len,i->ck.s,
		i->alg.len,i->alg.s,
		i->ik.len,i->ik.s	);								
		
	if (expires<=0) {
		/* Deregister */
		c->reg_state = DEREGISTERED;
		r_act_time();
		c->expires = time_now + 60;
	}			
	r_unlock(c->hash);

	//print_r(L_CRIT);
	
	/* run the IPSec scripts */	
	/* Registration */
	execute_cmd(out_rpl);		
	execute_cmd(out_req);		
	execute_cmd(inc_rpl);
	return 1;	
error:
	return 0;	
}
Exemple #14
0
/**
 * Process the 401 response for REGISTER and creates the first Security-Associations.
 * Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER
 * could come over that one. 
 * @param rpl - the 401 response
 * @param str1 - not used
 * @param str2 - not used
 * @returns 1 if ok, 0 if not
 */
int P_IPSec_401(struct sip_msg *rpl,char *str1, char *str2)
{
	struct sip_msg *req;
	str auth;
	struct hdr_field *hdr;	
	str sec_cli,sec_srv={0,0};
	str ck,ik;
	char ck_c[64],ik_c[64];
	str ck_esp={ck_c,0},ik_esp={ik_c,0};
	str alg,ealg;
	str alg_setkey,ealg_setkey;
	str tmp;
	unsigned int spi_uc,spi_us;
	unsigned int spi_pc,spi_ps;
	int port_uc,port_us;
	char cmd[256];
	str ue;
	

	contact_body_t *contact;
	struct sip_uri uri;
	
	req = cscf_get_request_from_reply(rpl);
	if (!req){
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No transactional request found.\n");
		goto error;
	}
	auth = cscf_get_authenticate(rpl,&hdr);
	if (!auth.len){
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No authorization header found.\n");
		goto error; 
	}
	sec_cli = cscf_get_security_client(req,&hdr);
	if (!sec_cli.len){
		LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: No Security-Client header found.\n");
		goto error; 
	}
	
	/* first we look for CK, IK */
	get_qparam(auth,s_ck,ck);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: CK: <%.*s>\n",
		ck.len,ck.s);
	get_qparam(auth,s_ik,ik);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: IK: <%.*s>\n",
		ik.len,ik.s);
	
	/* then for algorithms */
	get_param(sec_cli,s_ealg,ealg);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Enc Algorithm: <%.*s>\n",
		ealg.len,ealg.s);
	get_param(sec_cli,s_alg,alg);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Int Algorithm: <%.*s>\n",
		alg.len,alg.s);
	/* and for spis */
	get_param(sec_cli,s_spi_c,tmp);
	strtoint(tmp,spi_uc);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-C: %d\n",
		spi_uc);
	get_param(sec_cli,s_spi_s,tmp);
	strtoint(tmp,spi_us);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-S: %d\n",
		spi_us);
	/* and for ports */
	get_param(sec_cli,s_port_c,tmp);
	strtoint(tmp,port_uc);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-C: %d\n",
		port_uc);
	get_param(sec_cli,s_port_s,tmp);
	strtoint(tmp,port_us);
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-S: %d\n",
		port_us);
	
	
	contact = cscf_parse_contacts(req);
	if (!contact) {		
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Message contains no Contact!\n");
		goto error;
	}
	if (contact->contacts){
		ue = contact->contacts->uri;
		if (parse_uri(ue.s,ue.len,&uri)){
			LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error parsing uri <%.*s>\n",ue.len,ue.s);
			goto error;
		}
		ue = uri.host;
		if (uri.port_no==0) port_uc=5060;
	}else
		ue = req->via1->host;
	LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: UE IP: <%.*s> \n",ue.len,ue.s);
	
	spi_pc=get_next_spi();	
	spi_ps=get_next_spi();	

	ck_esp.s[ck_esp.len++]='0';
	ck_esp.s[ck_esp.len++]='x';	
	if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) {
		memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32;
		memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16;
		ealg_setkey = s_des_out;
	}
	else
	if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) {
		memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
		ealg_setkey = s_aes_out;
	}else {
		memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
		ealg_setkey = s_null_out;
		ealg = s_null_out;
	}

	ik_esp.s[ik_esp.len++]='0';
	ik_esp.s[ik_esp.len++]='x';		
	if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) {
		memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
		alg_setkey = s_md5_out;
	}
	else
	if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) {		
		memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
		memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8;
		alg_setkey = s_sha_out;
	}else{
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s);
		goto error;
	}

	/* try to add the Security-Server header */
	sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n",
		ealg.len,ealg.s,
		alg.len,alg.s,
		spi_pc,spi_ps,
		pcscf_ipsec_port_c,pcscf_ipsec_port_s);
		
	sec_srv.len = strlen(cmd);
	sec_srv.s = pkg_malloc(sec_srv.len);
	if (!sec_srv.s){
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error allocating %d pkg bytes \n",sec_srv.len);
		goto error;
	}
	memcpy(sec_srv.s,cmd,sec_srv.len);
	if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
		LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
		pkg_free(sec_srv.s);
		goto error;
	}

	/* run the IPSec script */	
	/* P_Inc_Req */
	sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
		pcscf_ipsec_P_Inc_Req,
		ue.len,ue.s,
		port_uc,
		pcscf_ipsec_host,
		pcscf_ipsec_port_s,
		spi_ps,
		ealg_setkey.len,ealg_setkey.s,
		ck_esp.len,ck_esp.s,
		alg_setkey.len,alg_setkey.s,
		ik_esp.len,ik_esp.s);
	execute_cmd(cmd);
			
	/* save data into registrar */
	save_contact_ipsec(req,rpl,
		spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us,
		ealg_setkey,ck_esp,alg_setkey,ik_esp);
	
	
	return 1;	
error:
	return 0;	
}
Exemple #15
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int response;
	int cseq;

	struct hdr_field *h=0;
	struct sip_msg *req=0;
	int expires=0;
	str totag;
	time_t t_time;
	str ses_exp = {0,0};
	str refresher = {0,0};

	enum s_dialog_direction dir = get_dialog_direction(str1);
		
//	if (!find_dialog_aor(msg,str1,&aor)){
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		if (!req) req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog_dir(call_id,aor);		
//	}
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
		{
			d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
	
			ses_exp = cscf_get_session_expires_body(msg, &h);
			t_time = cscf_get_session_expires(ses_exp, &refresher);
			if (!t_time)
			{
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
				d->lr_session_expires = 0;
			}
			else
			{
				d->expires = d_act_time() + t_time;
				d->lr_session_expires = t_time;
				if (refresher.len)
					STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
			}
		}
		else if (d->method == DLG_METHOD_SUBSCRIBE &&
			msg->first_line.u.request.method.len == 6 &&
			strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
		{
			// Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2
			expires = cscf_get_subscription_state(msg);
			if (expires >= 0)
				d->expires = d_act_time()+expires;
			else
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
		}
		else
		{
			expires = cscf_get_expires_hdr(msg,0);
			if (expires >= 0)
			        d->expires = d_act_time()+expires;
			else
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
	
			d->lr_session_expires = 0;		
		}
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200){
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
			}else
			if (response>=200 && response<300){
				d->state = DLG_STATE_CONFIRMED;
				update_dialog_on_reply(msg, d);
				
				/*I save the dialogs only here because
				 * i only want to release confirmed dialogs*/
				cscf_get_to_tag(msg,&totag);
				if (d->dialog_s){
					tmb.update_dlg_uas(d->dialog_s,response,&totag);
					tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
				}else{
					LOG(L_ERR,"ERR:S_update_dialog(): dialog_s for dialog was NULL!\n");
				}
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					struct cell * t = tmb.t_gett();
					if(t->nr_of_outgoings < 2)
						return S_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					d->lr_session_expires = 0;
					break;
				
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return S_drop_dialog(msg,str1,str2);
					}
					update_dialog_on_reply(msg, d);
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_dros_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return S_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = d_act_time() + expires;
						}
					}
					else if (req && req->first_line.u.request.method.len==9 &&
						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0){
						expires = cscf_get_expires_hdr(msg,0);
						if (expires >= 0)
							d->expires = d_act_time()+expires;
						else
							d->expires = d_act_time()+scscf_dialogs_expiration_time;
					}					
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;						
		}
	}
	
	d_unlock(d->hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_ERROR;	
}
/**
 * Checks if a response on the MT side includes all the required Record Routes, as present in the request
 * @param msg - the SIP reply to check
 * @param str1 - not used
 * @param str2 - not used
 * @return #CSCF_RETURN_TRUE on match, #CSCF_RETURN_FALSE if not matching 
 */
int P_follows_record_routes(struct sip_msg *msg, char *str1, char *str2)
{
	struct hdr_field *temp_hdr_req = NULL,*temp_hdr_rpl = NULL;
	struct sip_msg * req = NULL; 
	rr_t * rr_req = NULL, *rr_req_i = NULL;
	rr_t * rr_rpl = NULL;
  
	LOG(L_INFO,"INF:"M_NAME":P_follows_record_routes(): Checking if RR in %d reply match the request ones\n",
			msg->first_line.u.reply.statuscode);
	
	// Get the first RR in reply
	temp_hdr_rpl = cscf_get_next_record_route(msg,temp_hdr_rpl);	
	if (!temp_hdr_rpl || !(rr_rpl = (rr_t*)temp_hdr_rpl->parsed)){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): No RR's found in reply.\n");
		goto nok;
	}
	
	// Checking first RR - this is a special case because the saved request does not include it
	if (pcscf_record_route_mt_uri.len != rr_rpl->nameaddr.uri.len || 
		strncmp(pcscf_record_route_mt_uri.s,rr_rpl->nameaddr.uri.s,pcscf_record_route_mt_uri.len)!=0){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): First RR did not match P-CSCF MT = %.*s , Rpl = %.*s \n",
				pcscf_record_route_mt_uri.len,pcscf_record_route_mt_uri.s,rr_rpl->nameaddr.uri.len,rr_rpl->nameaddr.uri.s);
		goto nok;
	}	
	rr_rpl = rr_rpl->next;
	if (!rr_rpl){
		temp_hdr_rpl = cscf_get_next_record_route(msg,temp_hdr_rpl);	
		if (temp_hdr_rpl) 
			rr_rpl = (rr_t*)temp_hdr_rpl->parsed;
	}
	
	// Find the request
	if(!(req = cscf_get_request_from_reply(msg))) {
		LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): No transactional request found.\n");
		goto nok;
	}	
	temp_hdr_req = cscf_get_next_record_route(req,temp_hdr_req);	
	if (temp_hdr_req) {
		rr_req = (rr_t*)temp_hdr_req->parsed;
		rr_req_i = rr_req;
	}
	
	// Cycle through the request/reply headers and compare
	while(rr_rpl && rr_req_i) {
		
		if(rr_req_i->nameaddr.uri.len != rr_rpl->nameaddr.uri.len ||
				strncmp(rr_req_i->nameaddr.uri.s,rr_rpl->nameaddr.uri.s,rr_req_i->nameaddr.uri.len)!=0){
			LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): Mismatch in RR URIs Req = %.*s , Rpl = %.*s \n",
					rr_req_i->nameaddr.uri.len,rr_req_i->nameaddr.uri.s,rr_rpl->nameaddr.uri.len,rr_rpl->nameaddr.uri.s);
			goto nok;
		}
		
		rr_rpl = rr_rpl->next;
		if (!rr_rpl){
			temp_hdr_rpl = cscf_get_next_record_route(msg,temp_hdr_rpl);	
			if (temp_hdr_rpl)
				rr_rpl = (rr_t*)temp_hdr_rpl->parsed;
		}

		rr_req_i = rr_req_i->next;		
		if (!rr_req_i){
			if (rr_req){
				free_rr(&rr_req);
				temp_hdr_req->parsed = NULL;
			}
			temp_hdr_req = cscf_get_next_record_route(req,temp_hdr_req);	
			if (temp_hdr_req) {
				rr_req = (rr_t*)temp_hdr_req->parsed;
				rr_req_i = rr_req;
			}
		}
	}

	if(rr_rpl){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): More RR headers in reply than in request\n");
		goto nok;
	}

	if(rr_req){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_record_routes(): More RR headers in request than in reply\n");
		goto nok;
	}

	if (rr_req){
		free_rr(&rr_req);
		temp_hdr_req->parsed = NULL;
	}
	return CSCF_RETURN_TRUE;
	
nok:
	if (rr_req){
		free_rr(&rr_req);
		temp_hdr_req->parsed = NULL;
	}
	return CSCF_RETURN_FALSE;
}
Exemple #17
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int response;
	int cseq;
	struct hdr_field *h=0;
	struct sip_msg *req=0;
	int expires=0;
	str totag;

	enum s_dialog_direction dir = get_dialog_direction(str1);
		
//	if (!find_dialog_aor(msg,str1,&aor)){
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		if (!req) req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog_dir(call_id,aor);		
//	}
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		d->expires = d_act_time()+scscf_dialogs_expiration_time;
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200){
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
			}else
			if (response>=200 && response<300){
				d->state = DLG_STATE_CONFIRMED;
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
				/*I save the dialogs only here because
				 * i only want to release confirmed dialogs*/
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);				
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					return S_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					break;
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return S_drop_dialog(msg,str1,str2);
					}
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_dros_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return S_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = expires;
						}
					}
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;						
		}
	}
	
	d_unlock(d->hash);
	
//	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
/* Send the OPTIONS response to the E-CSCF
 * could be used after a LOCSIP NOTIFY is received
 * @param msg  - the OPTIONS request from the ECSCF
 * @param str1 - not used
 * @param str2 - not used
 * @return CSCF_RETURN_TRUE if ok, or CSCF_RETURN_FALSE if error
 */
int LRF_call_query_resp(struct sip_msg* msg, char*str1, char*str2){

	str user_uri;
	user_d * d= NULL;
	str service;
	struct cell * trans = NULL;
	str resp_body = {0,0};
	str headers = {0,0};
	unsigned int hash_index, label;

	LOG(L_INFO, "INFO:"M_NAME":LRF_call_query_resp\n");

	if (msg->first_line.u.request.method.len!=7||
		memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){
		LOG(L_WARN,"WARN:"M_NAME":LRF_call_query_resp: The method is not an OPTIONS, trying to replace the message\n");

		msg = cscf_get_request_from_reply(NULL);
		if(! msg || msg->first_line.type!=SIP_REQUEST || msg->first_line.u.request.method.len!=7||
			memcmp(msg->first_line.u.request.method.s,"OPTIONS",7)!=0){
					
			LOG(L_ERR,"BUG:"M_NAME":LRF_call_query_resp: The new message is not an OPTIONS request either\n");
			return CSCF_RETURN_ERROR;
		}
	}

	service = cscf_get_headers_content(msg, service_hdr_name);
	if(!service.len || !service.s){
		LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not find the service header in the OPTIONS, or could not be parsed\n");
		return CSCF_RETURN_FALSE;
	}

	str callid = cscf_get_call_id(msg, NULL);
	if(!callid.s || !callid.len){
		LOG(L_ERR, "ERR:"M_NAME":LRF_get_psap: could not find the callid header in the OPTIONS request\n");
		return CSCF_RETURN_FALSE;
	}

	user_uri = msg->first_line.u.request.uri;
	d = get_user_data(user_uri, service, callid);
	if(!d) {
		LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not found user data for uri %.*s and service %.*s\n",
				user_uri.len, user_uri.s, service.len, service.s);
		goto error;
	}

	if(!d->psap_uri.len || !d->psap_uri.s){
		LOG(L_ERR, "ERR: "M_NAME":LRF_call_query_resp: null psap uri\n");
		goto error;
	}

	if(d->loc && d->locsip_loc){
		LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: LRF has location information from the LOCSIP server\n");
		if(get_options_resp_body(&resp_body, d)){
			LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp:could not get the OPTIONS response body\n");
			goto error;
		}
	}
	
	if(get_options_resp_headers(&headers, d)){
		LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp:could not get the OPTIONS response headers\n");
		goto error;
	}
	
	//get crt trans	
	if(cscf_get_transaction(msg, &hash_index, &label)<0){
		LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not get the trans from the message\n");
		goto error;
	}

	if(tmb.t_lookup_ident(&trans, hash_index, label)!=1){
		LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not get the trans from the hash and index\n");
		goto error;
	}
	
	if(tmb.t_reply_with_body(trans, 200, "OK - PSAP found", resp_body.s, headers.s, "lrf" )!= 1){
		LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: could not send the response\n");
		goto error2;
	}

#ifndef TM_DEL_UNREF
	LOG(L_ERR, "ERR:"M_NAME":LRF_call_query_resp: options ref count %i\n", trans->ref_count);
#endif
	

	lrf_unlock(d->hash);
	if(resp_body.s)
		pkg_free(resp_body.s);
	if(headers.s)
		pkg_free(headers.s);

	return CSCF_RETURN_TRUE;

error2:
	//tmb.t_unref_ident(trans->hash_index, trans->label);

error:
	LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n");
	if(d)
		lrf_unlock(d->hash);
	LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n");
	//if(resp_body.s) pkg_free(resp_body.s);
	LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n");
	//if(headers.s)	pkg_free(headers.s);
	LOG(L_DBG, "DBG: "M_NAME":LRF_call_query_resp: error label\n");

	return CSCF_RETURN_FALSE;
}