static inline void init_synonym_id( struct cell *t )
{
	struct sip_msg *p_msg;
	int size;
	char *c;
	unsigned int myrand;

	if (!syn_branch) {
		p_msg=t->uas.request;
		if (p_msg) {
			/* char value of a proxied transaction is
			   calculated out of header-fields forming
			   transaction key
			*/
			char_msg_val( p_msg, t->md5 );
		} else {
			/* char value for a UAC transaction is created
			   randomly -- UAC is an originating stateful element 
			   which cannot be refreshed, so the value can be
			   anything
			*/
			/* HACK : not long enough */
			myrand=rand();
			c=t->md5;
			size=MD5_LEN;
			memset(c, '0', size );
			int2reverse_hex( &c, &size, myrand );
		}
	}
}
Example #2
0
/* forwards a request to dst
 * parameters:
 *   msg       - sip msg
 *   dst       - destination name, if non-null it will be resolved and
 *               send_info updated with the ip/port. Even if dst is non
 *               null send_info must contain the protocol and if a non
 *               default port or non srv. lookup is desired, the port must
 *               be !=0 
 *   port      - used only if dst!=0 (else the port in send_info->to is used)
 *   send_info - value/result partially filled dest_info structure:
 *                 - send_info->proto and comp are used
 *                 - send_info->to will be filled (dns)
 *                 - send_info->send_flags is filled from the message
 *                 - if the send_socket member is null, a send_socket will be 
 *                   chosen automatically
 * WARNING: don't forget to zero-fill all the  unused members (a non-zero 
 * random id along with proto==PROTO_TCP can have bad consequences, same for
 *   a bogus send_socket value)
 */
int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
							struct dest_info* send_info)
{
	unsigned int len;
	char* buf;
	char md5[MD5_LEN];
	struct socket_info* orig_send_sock; /* initial send_sock */
	int ret;
	struct ip_addr ip; /* debugging only */
	char proto;
#ifdef USE_DNS_FAILOVER
	struct socket_info* prev_send_sock;
	int err;
	struct dns_srv_handle dns_srv_h;
	
	prev_send_sock=0;
	err=0;
#endif
	
	
	buf=0;
	orig_send_sock=send_info->send_sock;
	proto=send_info->proto;
	ret=0;

	if(dst){
#ifdef USE_DNS_FAILOVER
		if (cfg_get(core, core_cfg, use_dns_failover)){
			dns_srv_handle_init(&dns_srv_h);
			err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port,
									&proto, dns_flags);
			if (err!=0){
				LOG(L_ERR, "ERROR: forward_request: resolving \"%.*s\""
						" failed: %s [%d]\n", dst->len, ZSW(dst->s),
						dns_strerror(err), err);
				ret=E_BAD_ADDRESS;
				goto error;
			}
		}else
#endif
		if (sip_hostport2su(&send_info->to, dst, port, &proto)<0){
			LOG(L_ERR, "ERROR: forward_request: bad host name %.*s,"
						" dropping packet\n", dst->len, ZSW(dst->s));
			ret=E_BAD_ADDRESS;
			goto error;
		}
	}/* dst */
	send_info->send_flags=msg->fwd_send_flags;
	/* calculate branch for outbound request;  if syn_branch is turned off,
	   calculate is from transaction key, i.e., as an md5 of From/To/CallID/
	   CSeq exactly the same way as TM does; good for reboot -- than messages
	   belonging to transaction lost due to reboot will still be forwarded
	   with the same branch parameter and will be match-able downstream
	
	   if it is turned on, we don't care about reboot; we simply put a simple
	   value in there; better for performance
	*/
	if (syn_branch ) {
	        memcpy(msg->add_to_branch_s, "z9hG4bKcydzigwkX", 16);
		msg->add_to_branch_len=16;
	} else {
		if (!char_msg_val( msg, md5 )) 	{ /* parses transaction key */
			LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
			ret=E_UNSPEC;
			goto error;
		}
		msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number);
		if (!branch_builder( msg->hash_index, 0, md5, 0 /* 0-th branch */,
					msg->add_to_branch_s, &msg->add_to_branch_len )) {
			LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n");
			ret=E_UNSPEC;
			goto error;
		}
	}
	/* try to send the message until success or all the ips are exhausted
	 *  (if dns lookup is performed && the dns cache used ) */
#ifdef USE_DNS_FAILOVER
	do{
#endif
		if (orig_send_sock==0) /* no forced send_sock => find it **/
			send_info->send_sock=get_send_socket(msg, &send_info->to, proto);
		if (send_info->send_sock==0){
			LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d "
						"no corresponding listening socket\n",
						send_info->to.s.sa_family, proto);
			ret=ser_error=E_NO_SOCKET;
#ifdef USE_DNS_FAILOVER
			/* continue, maybe we find a socket for some other ip */
			continue;
#else
			goto error;
#endif
		}
	
#ifdef USE_DNS_FAILOVER
		if (prev_send_sock!=send_info->send_sock){
			/* rebuild the message only if the send_sock changed */
			prev_send_sock=send_info->send_sock;
#endif
			if (buf) pkg_free(buf);
			send_info->proto=proto;
			buf = build_req_buf_from_sip_req(msg, &len, send_info, 0);
			if (!buf){
				LOG(L_ERR, "ERROR: forward_request: building failed\n");
				ret=E_OUT_OF_MEM; /* most probable */
				goto error;
			}
#ifdef USE_DNS_FAILOVER
		}
#endif
		 /* send it! */
		DBG("Sending:\n%.*s.\n", (int)len, buf);
		DBG("orig. len=%d, new_len=%d, proto=%d\n",
				msg->len, len, send_info->proto );
	
		if (run_onsend(msg, send_info, buf, len)==0){
			su2ip_addr(&ip, &send_info->to);
			LOG(L_INFO, "forward_request: request to %s:%d(%d) dropped"
					" (onsend_route)\n", ip_addr2a(&ip),
						su_getport(&send_info->to), send_info->proto);
			ser_error=E_OK; /* no error */
			ret=E_ADM_PROHIBITED;
#ifdef USE_DNS_FAILOVER
			continue; /* try another ip */
#else
			goto error; /* error ? */
#endif
		}
#ifdef USE_DST_BLACKLIST
		if (cfg_get(core, core_cfg, use_dst_blacklist)){
			if (dst_is_blacklisted(send_info, msg)){
				su2ip_addr(&ip, &send_info->to);
				LOG(L_DBG, "DEBUG: blacklisted destination:%s:%d (%d)\n",
							ip_addr2a(&ip), su_getport(&send_info->to),
							send_info->proto);
				ret=ser_error=E_SEND;
#ifdef USE_DNS_FAILOVER
				continue; /* try another ip */
#else
				goto error;
#endif
			}
		}
#endif
		if (msg_send(send_info, buf, len)<0){
			ret=ser_error=E_SEND;
#ifdef USE_DST_BLACKLIST
			(void)dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
#endif
#ifdef USE_DNS_FAILOVER
			continue; /* try another ip */
#else
			goto error;
#endif
		}else{
			ret=ser_error=E_OK;
			/* sent requests stats */
			STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
			/* exit succcesfully */
			goto end;
		}
#ifdef USE_DNS_FAILOVER
	}while(dst && cfg_get(core, core_cfg, use_dns_failover) &&
			dns_srv_handle_next(&dns_srv_h, err) && 
			((err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port,
										&proto, dns_flags))==0));
	if ((err!=0) && (err!=-E_DNS_EOR)){
		LOG(L_ERR, "ERROR:  resolving %.*s host name in uri"
							" failed: %s [%d] (dropping packet)\n",
									dst->len, ZSW(dst->s),
									dns_strerror(err), err);
		ret=ser_error=E_BAD_ADDRESS;
		goto error;
	}
#endif
	
error:
	STATS_TX_DROPS;
end:
#ifdef USE_DNS_FAILOVER
	if (dst && cfg_get(core, core_cfg, use_dns_failover)){
				dns_srv_handle_put(&dns_srv_h);
	}
#endif
	if (buf) pkg_free(buf);
	/* received_buf & line_buf will be freed in receive_msg by free_lump_list*/
#if defined STATS_REQ_FWD_OK || defined STATS_REQ_FWD_DROP
	if(ret==0)
		STATS_REQ_FWD_OK();
	else
		STATS_REQ_FWD_DROP();
#endif /* STATS_REQ_FWD_* */
	return ret;
}
Example #3
0
static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list)
{
	static char tid[MD5_LEN];
	str *uri;
	struct sip_uri parsed_uri, oparsed_uri;
	char *val;
	int val_len;

	/* source ip */
	if (!append_var(EV_SRCIP, ip_addr2a(&msg->rcv.src_ip), 0, list)) {
		LOG(L_ERR, "ERROR: append_var SRCIP failed \n");
		return 0;
	}
	/* request URI */
	uri=msg->new_uri.s && msg->new_uri.len ? 
		&msg->new_uri : &msg->first_line.u.request.uri;
	if (!append_var(EV_RURI, uri->s, uri->len, list )) {
		LOG(L_ERR, "ERROR: append_var URI failed\n");
		return 0;
	}
	/* userpart of request URI */
	if (parse_uri(uri->s, uri->len, &parsed_uri)<0) {
		LOG(L_WARN, "WARNING: append_var: URI not parsed\n");
	} else {
		if (!append_var(EV_USER, parsed_uri.user.s, 
					parsed_uri.user.len, list)) {
			LOG(L_ERR, "ERROR: append_var USER failed\n");
			goto error;
		}
	}
	/* original URI */
	if (!append_var(EV_ORURI, msg->first_line.u.request.uri.s,
				msg->first_line.u.request.uri.len, list)) {
		LOG(L_ERR, "ERROR: append_var O-URI failed\n");
		goto error;
	}
	/* userpart of request URI */
	if (parse_uri(msg->first_line.u.request.uri.s, 
				msg->first_line.u.request.uri.len, 
				&oparsed_uri)<0) {
		LOG(L_WARN, "WARNING: append_var: orig URI not parsed\n");
	} else {
		if (!append_var(EV_OUSER, oparsed_uri.user.s, 
					oparsed_uri.user.len, list)) {
			LOG(L_ERR, "ERROR: append_var OUSER failed\n");
			goto error;
		}
	}
	/* tid, transaction id == via/branch */
	if (!char_msg_val(msg, tid)) {
		LOG(L_WARN, "WARNING: no tid can be determined\n");
		val=0; val_len=0;
	} else {
		val=tid;val_len=MD5_LEN;
	}
	if (!append_var(EV_TID, val,val_len, list)) {
		LOG(L_ERR, "ERROR: append_var TID failed\n");
		goto error;
	}

	/* did, dialogue id == To-tag */
	if (!(msg->to && get_to(msg) ))  {
		LOG(L_ERR, "ERROR: append_var: no to-tag\n");
		val=0; val_len=0;
	} else {
		val=get_to(msg)->tag_value.s;
		val_len=get_to(msg)->tag_value.len;
	}
	if (!append_var(EV_DID, val, val_len, list)) {
		LOG(L_ERR, "ERROR: append_var DID failed\n");
		goto error;
	}
	return 1;
error:
	return 0;
}
Example #4
0
struct cell*  build_cell( struct sip_msg* p_msg )
{
	struct cell* new_cell;
	unsigned int i;
	unsigned int myrand;
	int size;
	char *c;
	struct ua_client *uac;

	/* avoid 'unitialized var use' warning */
	myrand=0;

	/* allocs a new cell */
	new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) );
	if  ( !new_cell ) {
		ser_error=E_OUT_OF_MEM;
		return NULL;
	}

	/* filling with 0 */
	memset( new_cell, 0, sizeof( struct cell ) );

	/* UAS */
#ifdef EXTRA_DEBUG
	new_cell->uas.response.retr_timer.tg=TG_RT;
	new_cell->uas.response.fr_timer.tg=TG_FR;
#endif
	new_cell->uas.response.fr_timer.payload =
	new_cell->uas.response.retr_timer.payload = &(new_cell->uas.response);
	new_cell->uas.response.my_T=new_cell;

	/* bogdan - debug */
	/*fprintf(stderr,"before clone VIA |%.*s|\n",via_len(p_msg->via1),
		via_s(p_msg->via1,p_msg));*/

	/* enter callback, which may potentially want to parse some stuff,
	   before the request is shmem-ized
	*/ 
    if (p_msg) callback_event(TMCB_REQUEST_IN, new_cell, p_msg,
            p_msg->REQ_METHOD );

	if (p_msg) {
		new_cell->uas.request = sip_msg_cloner(p_msg);
		if (!new_cell->uas.request)
			goto error;
	}

	/* new_cell->uas.to_tag = &( get_to(new_cell->uas.request)->tag_value ); */
	new_cell->uas.response.my_T = new_cell;

	/* UAC */
	for(i=0;i<MAX_BRANCHES;i++)
	{
		uac=&new_cell->uac[i];
		uac->request.my_T = new_cell;
		uac->request.branch = i;
#ifdef EXTRA_DEBUG
		uac->request.fr_timer.tg = TG_FR;
		uac->request.retr_timer.tg = TG_RT;
#endif
		uac->request.retr_timer.payload = 
		uac->request.fr_timer.payload = &uac->request;
		uac->local_cancel=uac->request;
	}

	/* global data for transaction */
	if (p_msg) {
		new_cell->hash_index = p_msg->hash_index;
	} else {
		/* note: unsatisfactory if 
		   RAND_MAX < TABLE_ENTRIES
		*/
		myrand = rand();
		new_cell->hash_index = myrand % TABLE_ENTRIES ;
	}
	new_cell->wait_tl.payload = new_cell;
	new_cell->dele_tl.payload = new_cell;
	new_cell->relaied_reply_branch   = -1;
	/* new_cell->T_canceled = T_UNDEFINED; */
#ifdef EXTRA_DEBUG
	new_cell->wait_tl.tg=TG_WT;
	new_cell->dele_tl.tg=TG_DEL;
#endif

	if (!syn_branch) {
		if (p_msg) {
			/* char value of a proxied transaction is
			   calculated out of header-fileds forming
			   transaction key
			*/
			char_msg_val( p_msg, new_cell->md5 );
		} else {
			/* char value for a UAC transaction is created
			   randomly -- UAC is an originating stateful element 
			   which cannot be refreshed, so the value can be
			   anything
			*/
			/* HACK : not long enough */
			c=new_cell->md5;
			size=MD5_LEN;
			memset(c, '0', size );
			int2reverse_hex( &c, &size, myrand );
		}
	}

	init_cell_lock(  new_cell );
	return new_cell;

error:
	shm_free(new_cell);
	return NULL;
}