Exemplo n.º 1
0
static int trace_send_duplicate(char *buf, int len, struct dest_info *dst2)
{
	struct dest_info dst;
	struct proxy_l * p = NULL;

	if(buf==NULL || len <= 0)
		return -1;

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;

	init_dest_info(&dst);
	/* create a temporary proxy*/
	dst.proto = PROTO_UDP;
	p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
			dst.proto);
	if (p==0)
	{
		LM_ERR("bad host name in uri\n");
		return -1;
	}

	if (!dst2){
		init_dest_info(&dst);
		/* create a temporary proxy*/
		dst.proto = PROTO_UDP;
		p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
				dst.proto);
		if (p==0){
			LM_ERR("bad host name in uri\n");
			return -1;
		}
		hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);

		dst.send_sock=get_send_socket(0, &dst.to, dst.proto);
		if (dst.send_sock==0){
			LM_ERR("can't forward to af %d, proto %d no corresponding"
					" listening socket\n", dst.to.s.sa_family, dst.proto);
			goto error;
		}
	}

	if (msg_send((dst2)?dst2:&dst, buf, len)<0)
	{
		LM_ERR("cannot send duplicate message\n");
		goto error;
	}

	if (p){
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	return 0;
error:
	if (p){
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	return -1;
}
Exemplo n.º 2
0
int forward_sl_request(struct sip_msg *msg,struct proxy_l *proxy,int proto)
{
	union sockaddr_union *to;
	struct socket_info *send_sock;
	int ret;

	to = (union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
	ret = -1;

	hostent2su(to, &proxy->host, proxy->addr_idx,
		(proxy->port)?proxy->port:SIP_PORT);

	do {
		send_sock=get_send_socket(msg, to, proto);
		if (send_sock==0){
			LM_ERR( "cannot forward to af %d, "
				"proto %d no corresponding listening socket\n",
				to->s.sa_family, proto);
			continue;
		}
		LM_DBG("Sending:\n%.*s.\n", (int)msg->len,msg->buf);
		if (msg_send(send_sock, proto, to, 0, msg->buf,msg->len)<0){
			LM_ERR("ERROR:seas:forward_msg: Error sending message !!\n");
			continue;
		}
		ret = 0;
		break;
	}while( get_next_su( proxy, to, 0)==0 );

	pkg_free(to);
	return ret;
}
Exemplo n.º 3
0
int init_rb( struct retr_buf *rb, struct sip_msg *msg)
{
	struct socket_info* send_sock;
	struct via_body* via;
	int proto;

	via=msg->via1;
	if (!reply_to_via) {
		update_sock_struct_from_ip( &rb->dst.to, msg );
		proto=msg->rcv.proto;
	} else {
		/*init retrans buffer*/
		if (update_sock_struct_from_via( &(rb->dst.to), msg, via )==-1) {
			LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst: %.*s\n",
				via->host.len, via->host.s );
			ser_error=E_BAD_VIA;
			return 0;
		}
		proto=via->proto;
	}
	rb->dst.proto=proto;
	rb->dst.proto_reserved1=msg->rcv.proto_reserved1;
	send_sock=get_send_socket(&rb->dst.to, proto);
	if (send_sock==0) {
		LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d "
			"no socket\n", rb->dst.to.s.sa_family, proto);
		ser_error=E_BAD_VIA;
		return 0;
	}
	rb->dst.send_sock=send_sock;
	
    return 1;
}
Exemplo n.º 4
0
/**
 * Pings a contact to keep the NAT pinhole alive.
 * @param c - the r_contact to ping
 * @returns 1 on success, -1 on failure
 */
int nat_send_ping(r_contact *c) {
	struct dest_info dst;
	
	if(c->pinhole == NULL)
		return 1;
	if(c->transport != PROTO_UDP && c->transport != PROTO_NONE)
		return 1;
	init_dest_info(&dst);
	dst.proto = PROTO_UDP;
	
	memset(&(dst.to), 0, sizeof(union sockaddr_union));
	dst.to.s.sa_family=c->pinhole->nat_addr.af;
	switch(dst.to.s.sa_family) {
		case AF_INET6:
			memcpy(&dst.to.sin6.sin6_addr, c->pinhole->nat_addr.u.addr, c->pinhole->nat_addr.len);
			//dst.to.sin6.sin6_len=sizeof(struct sockaddr_in6);
			dst.to.sin6.sin6_port=htons(c->pinhole->nat_port);
			break;
		case AF_INET:
			memcpy(&dst.to.sin.sin_addr, c->pinhole->nat_addr.u.addr, c->pinhole->nat_addr.len);
			//dst.to.sin.sin_len=sizeof(struct sockaddr_in);
			dst.to.sin.sin_port=htons(c->pinhole->nat_port);
			break;
		default:
			LOG(L_CRIT,"CRIT:"M_NAME":nat_send_ping: unknown address family %d\n", dst.to.s.sa_family);
			return -1;
	}
	dst.send_sock=get_send_socket(0, &dst.to, PROTO_UDP);
	if(dst.send_sock == NULL) {
		LOG(L_ERR,"ERR:"M_NAME":nat_send_ping: cannot get sending socket\n");
		return -1;
	}
	udp_send(&dst, (char *)udp_ping, sizeof(udp_ping));
	return 1; 
}
Exemplo n.º 5
0
static int trace_send_duplicate(char *buf, int len)
{
	union sockaddr_union* to;
	struct socket_info* send_sock;
	struct proxy_l * p;
	int proto;
	int ret;

	if(buf==NULL || len <= 0)
		return -1;

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;

	to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
	if (to==0){
		LM_ERR("out of pkg memory\n");
		return -1;
	}

	/* create a temporary proxy*/
	proto = PROTO_UDP;
	p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
			proto, 0);
	if (p==0){
		LM_ERR("bad host name in uri\n");
		pkg_free(to);
		return -1;
	}

	hostent2su(to, &p->host, p->addr_idx,
				(p->port)?p->port:SIP_PORT);

	ret = -1;

	do {
		send_sock=get_send_socket(0, to, proto);
		if (send_sock==0){
			LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n",
					to->s.sa_family,proto);
			continue;
		}

		if (msg_send(send_sock, proto, to, 0, buf, len, NULL)<0){
			LM_ERR("cannot send duplicate message\n");
			continue;
		}
		ret = 0;
		break;
	}while( get_next_su( p, to, 0)==0 );

	free_proxy(p); /* frees only p content, not p itself */
	pkg_free(p);
	pkg_free(to);

	return ret;
}
Exemplo n.º 6
0
int select_next_hop_src_ip(str* res, select_t* s, struct sip_msg* msg) {
	struct socket_info* socket_info;
	union sockaddr_union to;
	char proto;
	struct sip_uri *u, next_hop;
	str *dst_host;

	if (msg->first_line.type!=SIP_REQUEST) 
		return -1;

	if (msg->force_send_socket) {
		*res = msg->force_send_socket->address_str;
		return 0;
	}

	if (msg->dst_uri.len) {
		if (parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop) < 0)
			return -1;
		u = &next_hop;
	}
	else {
		if (parse_sip_msg_uri(msg) < 0)
			return -1;
		u = &msg->parsed_uri;
	}
#ifdef USE_TLS
	if (u->type==SIPS_URI_T)
		proto = PROTO_TLS;
	else
#endif
		proto = u->proto;

#ifdef HONOR_MADDR
	if (u->maddr_val.s && u->maddr_val.len)
		dst_host = &u->maddr_val;
	else
#endif
		dst_host = &u->host;

	if (sip_hostport2su(&to, dst_host, u->port_no, &proto) < 0)
		return -1;
	socket_info = get_send_socket(msg, &to, proto);
	if (!socket_info)
		return -1;

	*res = socket_info->address_str;
	return 0;
}
Exemplo n.º 7
0
int
natping_contact(str contact, struct dest_info *dst) {
	struct sip_uri curi;
	struct hostent *he;
	str p_method, p_from;

	if (natping_method != NULL) {
		/* XXX: add send_sock handling */
		p_method.s = natping_method;
		p_method.len = strlen(p_method.s);
		p_from.s = "sip:registrar"; /* XXX */
		p_from.len = strlen(p_from.s);
		if (tmb.t_request(&p_method, &contact, &contact, &p_from,
		    NULL, NULL, NULL, NULL, NULL) == -1) {
			LOG(L_ERR, "ERROR: nathelper::natping(): t_request() failed\n");
			return -1;
		}
	} else {
		if (parse_uri(contact.s, contact.len, &curi) < 0) {
			LOG(L_ERR, "ERROR: nathelper::natping: can't parse contact uri\n");
			return -1;
		}
		if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE)
			return -1;
		if (curi.port_no == 0)
			curi.port_no = SIP_PORT;
		he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP);
		if (he == NULL){
			LOG(L_ERR, "ERROR: nathelper::natping: can't resolve host\n");
			return -1;
		}
		hostent2su(&dst->to, he, 0, curi.port_no);
		if (dst->send_sock == NULL) {
			dst->send_sock = force_socket ? force_socket :
			    get_send_socket(0, &dst->to, PROTO_UDP);
		}
		if (dst->send_sock == NULL) {
			LOG(L_ERR, "ERROR: nathelper::natping: can't get sending socket\n");
			return -1;
		}
		dst->proto=PROTO_UDP;
		udp_send(dst, (char *)sbuf, sizeof(sbuf));
	}
	return 1;
}
Exemplo n.º 8
0
int siptrace_net_data_send(void *data)
{
	sr_net_info_t *nd;
	struct dest_info new_dst;
	struct _siptrace_data sto;

	if(data==0)
		return -1;

	nd = (sr_net_info_t*)data;
	if(nd->dst==NULL || nd->data.s==NULL || nd->data.len<=0)
		return -1;

	new_dst=*nd->dst;
	new_dst.send_sock=get_send_socket(0, &nd->dst->to, nd->dst->proto);

	memset(&sto, 0, sizeof(struct _siptrace_data));

	sto.body.s   = nd->data.s;
	sto.body.len = nd->data.len;

	if (unlikely(new_dst.send_sock==0)) {
		LM_WARN("no sending socket found\n");
		strcpy(sto.fromip_buff, "any:255.255.255.255:5060");
	} else {
		strncpy(sto.fromip_buff, new_dst.send_sock->sock_str.s,
			new_dst.send_sock->sock_str.len);
	}
	sto.fromip.s = sto.fromip_buff;
	sto.fromip.len = strlen(sto.fromip_buff);

	siptrace_copy_proto(new_dst.send_sock->proto, sto.toip_buff);
	strcat(sto.toip_buff, suip2a(&new_dst.to, sizeof(new_dst.to)));
	strcat(sto.toip_buff,":");
	strcat(sto.toip_buff, int2str((int)su_getport(&new_dst.to), NULL));
	sto.toip.s = sto.toip_buff;
	sto.toip.len = strlen(sto.toip_buff);

	sto.dir = "out";

	trace_send_hep_duplicate(&sto.body, &sto.fromip, &sto.toip, NULL);
	return 0;
}
Exemplo n.º 9
0
/**
 * @brief Initialize module children
 */
static int child_init(int rank)
{
	if(rank!=PROC_INIT)
		return 0;

	_lc_udp_dst.proto = PROTO_UDP;
	_lc_udp_dst.send_sock=get_send_socket(NULL, &_lc_udp_dst.to, PROTO_UDP);
	if (_lc_udp_dst.send_sock==0) {
		_lc_udp_dst.send_sock = get_out_socket(&_lc_udp_dst.to, PROTO_UDP);
		if (_lc_udp_dst.send_sock==0) {
			LM_ERR("failed to get send socket\n");
			return -1;
		}
	}
	LM_DBG("setting udp-send custom logging function\n");
	km_log_func_set(&_lc_core_log_udp);
	_lc_log_udp = 1;



	return 0;
}
Exemplo n.º 10
0
static inline int update_uac_dst( struct sip_msg *request,
													struct ua_client *uac )
{
	struct socket_info* send_sock;
	char *shbuf;
	unsigned int len;

	send_sock = get_send_socket( request, &uac->request.dst.to ,
			uac->request.dst.proto );
	if (send_sock==0) {
		LM_ERR("failed to fwd to af %d, proto %d "
			" (no corresponding listening socket)\n",
			uac->request.dst.to.s.sa_family, uac->request.dst.proto );
		ser_error=E_NO_SOCKET;
		return -1;
	}

	if (send_sock!=uac->request.dst.send_sock) {
		/* rebuild */
		shbuf = print_uac_request( request, &len, send_sock,
			uac->request.dst.proto);
		if (!shbuf) {
			ser_error=E_OUT_OF_MEM;
			return -1;
		}

		if (uac->request.buffer.s)
			shm_free(uac->request.buffer.s);

		/* things went well, move ahead and install new buffer! */
		uac->request.dst.send_sock = send_sock;
		uac->request.dst.proto_reserved1 = 0;
		uac->request.buffer.s = shbuf;
		uac->request.buffer.len = len;
	}

	return 0;
}
Exemplo n.º 11
0
static void
timer(unsigned int ticks, void *param)
{
	int rval;
	void *buf, *cp;
	str c;
	struct sip_uri curi;
	union sockaddr_union to;
	struct hostent* he;
	struct socket_info* send_sock;

	buf = NULL;
	if (cblen > 0) {
		buf = pkg_malloc(cblen);
		if (buf == NULL) {
			LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n");
			return;
		}
	}
	rval = get_all_ucontacts(buf, cblen);
	if (rval > 0) {
		if (buf != NULL)
			pkg_free(buf);
		cblen = rval * 2;
		buf = pkg_malloc(cblen);
		if (buf == NULL) {
			LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n");
			return;
		}
		rval = get_all_ucontacts(buf, cblen);
		if (rval != 0) {
			pkg_free(buf);
			return;
		}
	}

	if (buf == NULL)
		return;

	cp = buf;
	while (1) {
		memcpy(&(c.len), cp, sizeof(c.len));
		if (c.len == 0)
			break;
		c.s = (char*)cp + sizeof(c.len);
		cp =  (char*)cp + sizeof(c.len) + c.len;
		if (parse_uri(c.s, c.len, &curi) < 0) {
			LOG(L_ERR, "ERROR: nathelper::timer: can't parse contact uri\n");
			continue;
		}
		if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE)
			continue;
		if (curi.port_no == 0)
			curi.port_no = SIP_PORT;
		he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP);
		if (he == NULL){
			LOG(L_ERR, "ERROR: nathelper::timer: can't resolve_hos\n");
			continue;
		}
		hostent2su(&to, he, 0, curi.port_no);
		send_sock = get_send_socket(&to, PROTO_UDP);
		if (send_sock == NULL) {
			LOG(L_ERR, "ERROR: nathelper::timer: can't get sending socket\n");
			continue;
		}
		udp_send(send_sock, (char *)sbuf, sizeof(sbuf), &to);
	}
	pkg_free(buf);
}
Exemplo n.º 12
0
static int trace_send_hep_duplicate(str *body, str *fromproto, str *fromip,
		unsigned short fromport, str *toproto, str *toip, unsigned short toport)
{
	struct proxy_l * p=NULL /* make gcc happy */;
	int ret;
	union sockaddr_union from_su;
	union sockaddr_union to_su;
	unsigned int proto;
	struct socket_info* send_sock;
	union sockaddr_union* to = NULL;

	int heplen;
	char *hepbuf;

	if(body->s==NULL || body->len <= 0)
		return -1;

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;

	/* Convert proto:ip:port to sockaddress union SRC IP */
	if (pipport2su(fromproto, fromip, fromport, &from_su, &proto)==-1 ||
	(pipport2su(toproto, toip, toport, &to_su, &proto)==-1))
		goto error;

	/* check if from and to are in the same family*/
	if(from_su.s.sa_family != to_su.s.sa_family) {
		LM_ERR("ERROR: trace_send_hep_duplicate: interworking detected ?\n");
		goto error;
	}


	/* create a temporary proxy*/
	proto = PROTO_UDP;
	p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,proto, 0);
	if (p==0){
		LM_ERR("bad host name in uri\n");
		return -1;
	}

	to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
	if (to==0){
		LM_ERR("out of pkg memory\n");
		return -1;
	}

	hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);

	if (hep_api.pack_hep(&from_su, to, proto, body->s, body->len,
				&hepbuf, &heplen)) {
		LM_ERR("failed to do hep packing\n");
		return -1;
	}

	ret = -1;

	do {
		send_sock=get_send_socket(0, to, proto);
		if (send_sock==0){
			LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n",
					to->s.sa_family,proto);
			continue;
		}

		if (msg_send(send_sock, PROTO_HEP, to, 0, hepbuf, heplen, NULL)<0){
			LM_ERR("cannot send duplicate message\n");
			continue;
		}
		ret = 0;
		break;
	}while( get_next_su( p, to, 0)==0 );
	free_proxy(p); /* frees only p content, not p itself */
	pkg_free(p);
	pkg_free(to);
	pkg_free(hepbuf);

	return ret;
error:
	if(p)
	{
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	if(to) pkg_free(to);
	return -1;
}
Exemplo n.º 13
0
/*! \brief removes first via & sends msg to the second */
int forward_reply(struct sip_msg* msg)
{
	char* new_buf;
	union sockaddr_union* to;
	unsigned int new_len;
	struct sr_module *mod;
	int proto;
	int id; /* used only by tcp*/
	struct socket_info *send_sock;
#ifdef USE_TCP
	char* s;
	int len;
#endif
	
	to=0;
	id=0;
	new_buf=0;
	/*check if first via host = us */
	if (check_via){
		if (check_self(&msg->via1->host,
					msg->via1->port?msg->via1->port:SIP_PORT,
					msg->via1->proto)!=1){
			LM_ERR("host in first via!=me : %.*s:%d\n", 
				msg->via1->host.len, msg->via1->host.s,	msg->via1->port);
			/* send error msg back? */
			goto error;
		}
	}
	/* quick hack, slower for multiple modules*/
	for (mod=modules;mod;mod=mod->next){
		if ((mod->exports) && (mod->exports->response_f)){
			LM_DBG("found module %s, passing reply to it\n",
					mod->exports->name);
			if (mod->exports->response_f(msg)==0) goto skip;
		}
	}

	/* if stateless fwd was disabled, we cannot have stateless replies here*/
	if (sl_fwd_disabled)
		goto skip;

	/* we have to forward the reply stateless, so we need second via -bogdan*/
	if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 
		|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
	{
		/* no second via => error */
		LM_ERR("no 2nd via found in reply\n");
		goto error;
	}

	to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
	if (to==0){
		LM_ERR("out of pkg memory\n");
		goto error;
	}

	new_buf = build_res_buf_from_sip_res( msg, &new_len);
	if (!new_buf){
		LM_ERR("failed to build rpl from req failed\n");
		goto error;
	}

	proto=msg->via2->proto;
	if (update_sock_struct_from_via( to, msg, msg->via2 )==-1) goto error;

#ifdef USE_TCP
	if (proto==PROTO_TCP
#ifdef USE_TLS
			|| proto==PROTO_TLS
#endif
			){
		/* find id in i param if it exists */
		if (msg->via1->i&&msg->via1->i->value.s){
			s=msg->via1->i->value.s;
			len=msg->via1->i->value.len;
			id=reverse_hex2int(s, len);
		}
	}
#endif

	send_sock = get_send_socket(msg, to, proto);

	if (msg_send(send_sock, proto, to, id, new_buf, new_len)<0) {
		update_stat( drp_rpls, 1);
		goto error0;
	}
	update_stat( fwd_rpls, 1);
	/*
	 * If no port is specified in the second via, then this
	 * message output a wrong port number - zero. Despite that
	 * the correct port is choosen in update_sock_struct_from_via,
	 * as its visible with su_getport(to); .
	 */
	LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, 
		msg->via2->host.s, (unsigned short) msg->via2->port);

	pkg_free(new_buf);
	pkg_free(to);
skip:
	return 0;
error:
	update_stat( err_rpls, 1);
error0:
	if (new_buf) pkg_free(new_buf);
	if (to) pkg_free(to);
	return -1;
}
Exemplo n.º 14
0
int forward_request( struct sip_msg* msg, struct proxy_l * p)
{
	union sockaddr_union to;
	unsigned int len;
	char* buf;
	struct socket_info* send_sock;
	struct socket_info* last_sock;
	str *branch;

	buf=0;

	/* calculate branch for outbound request - if the branch buffer is already
	 * set (maybe by an upper level as TM), used it; otherwise computes 
	 * the branch for stateless fwd. . According to the latest discussions
	 * on the topic, you should reuse the latest statefull branch
	 * --bogdan */
	if ( msg->add_to_branch_len==0 ) {
		branch = get_sl_branch(msg);
		if (branch==0) {
			LM_ERR("unable to compute branch\n");
			goto error;
		}
		msg->add_to_branch_len = branch->len;
		memcpy( msg->add_to_branch_s, branch->s, branch->len);
	}

	msg_callback_process(msg, REQ_PRE_FORWARD, (void *)p);

	hostent2su( &to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
	last_sock = 0;

	if (getb0flags() & tcp_no_new_conn_bflag)
		tcp_no_new_conn = 1;

	do {
		send_sock=get_send_socket( msg, &to, p->proto);
		if (send_sock==0){
			LM_ERR("cannot forward to af %d, proto %d no corresponding"
				"listening socket\n", to.s.sa_family, p->proto);
			ser_error=E_NO_SOCKET;
			continue;
		}

		if ( last_sock!=send_sock ) {

			if (buf)
				pkg_free(buf);

			buf = build_req_buf_from_sip_req(msg, &len, send_sock, p->proto, 0);
			if (!buf){
				LM_ERR("building req buf failed\n");
				tcp_no_new_conn = 0;
				goto error;
			}

			last_sock = send_sock;
		}

		if (check_blacklists( p->proto, &to, buf, len)) {
			LM_DBG("blocked by blacklists\n");
			ser_error=E_IP_BLOCKED;
			continue;
		}

		/* send it! */
		LM_DBG("sending:\n%.*s.\n", (int)len, buf);
		LM_DBG("orig. len=%d, new_len=%d, proto=%d\n",
			msg->len, len, p->proto );

		if (msg_send(send_sock, p->proto, &to, 0, buf, len)<0){
			ser_error=E_SEND;
			continue;
		}

		run_fwd_callbacks( msg, buf, len, send_sock, p->proto, &to);

		ser_error = 0;
		break;

	}while( get_next_su( p, &to, (ser_error==E_IP_BLOCKED)?0:1)==0 );

	tcp_no_new_conn = 0;

	if (ser_error) {
		update_stat( drp_reqs, 1);
		goto error;
	}

	/* sent requests stats */
	update_stat( fwd_reqs, 1);

	pkg_free(buf);
	/* received_buf & line_buf will be freed in receive_msg by free_lump_list*/
	return 0;

error:
	if (buf) pkg_free(buf);
	return -1;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
int corex_send(sip_msg_t *msg, gparam_t *pu, enum sip_protos proto)
{
	str dest = {0};
	int ret = 0;
	struct sip_uri next_hop, *u;
	struct dest_info dst;
	char *p;

	if (pu)
	{
		if (fixup_get_svalue(msg, pu, &dest))
		{
			LM_ERR("cannot get the destination parameter\n");
			return -1;
		}
	}

	init_dest_info(&dst);

	if (dest.len <= 0)
	{
		/*get next hop uri uri*/
		if (msg->dst_uri.len) {
			ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len,
							&next_hop);
			u = &next_hop;
		} else {
			ret = parse_sip_msg_uri(msg);
			u = &msg->parsed_uri;
		}

		if (ret<0) {
			LM_ERR("send() - bad_uri dropping packet\n");
			ret=E_BUG;
			goto error;
		}
	} else {
		u = &next_hop;
		u->port_no = 5060;
		u->host = dest;
		/* detect ipv6 */
		p = memchr(dest.s, ']', dest.len);
		if (p) {
			p++;
			p = memchr(p, ':', dest.s + dest.len - p);
		} else {
			p = memchr(dest.s, ':', dest.len);
		}
		if (p)
		{
			u->host.len = p - dest.s;
			p++;
			u->port_no = str2s(p, dest.len - (p - dest.s), NULL);
		}
	}

	ret = sip_hostport2su(&dst.to, &u->host, u->port_no,
				&dst.proto);
	if(ret!=0) {
		LM_ERR("failed to resolve [%.*s]\n", u->host.len,
			ZSW(u->host.s));
		ret=E_BUG;
		goto error;
	}

	dst.proto = proto;
	if (proto == PROTO_UDP)
	{
		dst.send_sock=get_send_socket(msg, &dst.to, PROTO_UDP);
		if (dst.send_sock!=0){
			ret=udp_send(&dst, msg->buf, msg->len);
		}else{
			ret=-1;
		}
	}
#ifdef USE_TCP
	else{
		/*tcp*/
		dst.id=0;
		ret=tcp_send(&dst, 0, msg->buf, msg->len);
	}
#endif

	if (ret>=0) ret=1;


error:
	return ret;
}
Exemplo n.º 17
0
static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info * dst2)
{
	struct dest_info dst;
	struct socket_info *si;
	struct dest_info* dst_fin = NULL;
	struct proxy_l * p=NULL /* make gcc happy */;
	void* buffer = NULL;
	union sockaddr_union from_su;
	union sockaddr_union to_su;
	unsigned int len, buflen, proto;
	struct hep_hdr hdr;
	struct hep_iphdr hep_ipheader;
	struct hep_timehdr hep_time;
	struct timeval tvb;
	struct timezone tz;

	struct hep_ip6hdr hep_ip6header;

	if(body->s==NULL || body->len <= 0)
		return -1;

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;


	gettimeofday( &tvb, &tz );


	/* message length */
	len = body->len 
		+ sizeof(struct hep_ip6hdr)
		+ sizeof(struct hep_hdr) + sizeof(struct hep_timehdr);;


	/* The packet is too big for us */
	if (unlikely(len>BUF_SIZE)){
		goto error;
	}

	/* Convert proto:ip:port to sockaddress union SRC IP */
	if (pipport2su(from->s, &from_su, &proto)==-1 || (pipport2su(to->s, &to_su, &proto)==-1))
		goto error;

	/* check if from and to are in the same family*/
	if(from_su.s.sa_family != to_su.s.sa_family) {
		LM_ERR("interworking detected ?\n");
		goto error;
	}

	if (!dst2){
		init_dest_info(&dst);
		/* create a temporary proxy*/
		dst.proto = PROTO_UDP;
		p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
				dst.proto);
		if (p==0)
		{
			LM_ERR("bad host name in uri\n");
			goto error;
		}

		hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
		LM_DBG("setting up the socket_info\n");
		dst_fin = &dst;
	} else {
		dst_fin = dst2;
	}

	if (force_send_sock_str.s) {
		LM_DBG("force_send_sock activated, grep for the sock_info\n");
		si = grep_sock_info(&force_send_sock_uri->host,
				(force_send_sock_uri->port_no)?force_send_sock_uri->port_no:SIP_PORT,
				PROTO_UDP);
		if (!si) {
			LM_WARN("cannot grep socket info\n");
		} else {
			LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len, si->name.s, si->address_str.len, si->address_str.s);
			dst_fin->send_sock = si;
		}
	}

	if (dst_fin->send_sock == 0) {
		dst_fin->send_sock=get_send_socket(0, &dst_fin->to, dst_fin->proto);
		if (dst_fin->send_sock == 0) {
			LM_ERR("can't forward to af %d, proto %d no corresponding"
					" listening socket\n", dst_fin->to.s.sa_family, dst_fin->proto);
			goto error;
		}
	}

	/* Version && proto && length */
	hdr.hp_l = sizeof(struct hep_hdr);
	hdr.hp_v = hep_version;
	hdr.hp_p = proto;

	/* AND the last */
	if (from_su.s.sa_family==AF_INET){
		/* prepare the hep headers */

		hdr.hp_f = AF_INET;
		hdr.hp_sport = htons(from_su.sin.sin_port);
		hdr.hp_dport = htons(to_su.sin.sin_port);

		hep_ipheader.hp_src = from_su.sin.sin_addr;
		hep_ipheader.hp_dst = to_su.sin.sin_addr;

		len = sizeof(struct hep_iphdr);
	}
	else if (from_su.s.sa_family==AF_INET6){
		/* prepare the hep6 headers */

		hdr.hp_f = AF_INET6;

		hdr.hp_sport = htons(from_su.sin6.sin6_port);
		hdr.hp_dport = htons(to_su.sin6.sin6_port);

		hep_ip6header.hp6_src = from_su.sin6.sin6_addr;
		hep_ip6header.hp6_dst = to_su.sin6.sin6_addr;

		len = sizeof(struct hep_ip6hdr);
	}
	else {
		LM_ERR("Unsupported protocol family\n");
		goto error;;
	}

	hdr.hp_l +=len;
	if (hep_version == 2){
		len += sizeof(struct hep_timehdr);
	}
	len += sizeof(struct hep_hdr) + body->len;
	buffer = (void *)pkg_malloc(len+1);
	if (buffer==0){
		LM_ERR("out of memory\n");
		goto error;
	}

	/* Copy job */
	memset(buffer, '\0', len+1);

	/* copy hep_hdr */
	memcpy((void*)buffer, &hdr, sizeof(struct hep_hdr));
	buflen = sizeof(struct hep_hdr);

	/* hep_ip_hdr */
	if(from_su.s.sa_family==AF_INET) {
		memcpy((void*)buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
		buflen += sizeof(struct hep_iphdr);
	}
	else {
		memcpy((void*)buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
		buflen += sizeof(struct hep_ip6hdr);
	}

	if(hep_version == 2) {

		hep_time.tv_sec = tvb.tv_sec;
		hep_time.tv_usec = tvb.tv_usec;
		hep_time.captid = hep_capture_id;

		memcpy((void*)buffer+buflen, &hep_time, sizeof(struct hep_timehdr));
		buflen += sizeof(struct hep_timehdr);
	}

	/* PAYLOAD */
	memcpy((void*)(buffer + buflen) , (void*)body->s, body->len);
	buflen +=body->len;

	if (msg_send_buffer(dst_fin, buffer, buflen, 1)<0)
	{
		LM_ERR("cannot send hep duplicate message\n");
		goto error;
	}

	if (p) {
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	pkg_free(buffer);
	return 0;
error:
	if(p)
	{
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	if(buffer) pkg_free(buffer);
	return -1;
}
Exemplo n.º 18
0
static int sip_trace(struct sip_msg *msg, struct dest_info * dst, char *dir)
{
	struct _siptrace_data sto;
	struct onsend_info *snd_inf = NULL;

	if (dst){
		if (dst->send_sock == 0){
			dst->send_sock=get_send_socket(0, &dst->to, dst->proto);
			if (dst->send_sock==0){
				LM_ERR("can't forward to af %d, proto %d no corresponding"
						" listening socket\n", dst->to.s.sa_family, dst->proto);
				return -1;
			}
		}
	}

	if(msg==NULL) {
		LM_DBG("nothing to trace\n");
		return -1;
	}
	memset(&sto, 0, sizeof(struct _siptrace_data));

	if(traced_user_avp.n!=0)
		sto.avp=search_first_avp(traced_user_avp_type, traced_user_avp,
				&sto.avp_value, &sto.state);

	if((sto.avp==NULL) && (trace_on_flag==NULL || *trace_on_flag==0)) {
		LM_DBG("trace off...\n");
		return -1;
	}
	if(sip_trace_prepare(msg)<0)
		return -1;

	sto.callid = msg->callid->body;

	if(msg->first_line.type==SIP_REQUEST) {
		sto.method = msg->first_line.u.request.method;
	} else {
		if(parse_headers(msg, HDR_CSEQ_F, 0) != 0 || msg->cseq==NULL
				|| msg->cseq->parsed==NULL) {
			LM_ERR("cannot parse cseq header\n");
			return -1;
		}
		sto.method = get_cseq(msg)->method;
	}

	if(msg->first_line.type==SIP_REPLY) {
		sto.status = msg->first_line.u.reply.status;
	} else {
		sto.status.s = "";
		sto.status.len = 0;
	}

	snd_inf=get_onsend_info();
	if(snd_inf==NULL) {
		sto.body.s = msg->buf;
		sto.body.len = msg->len;

		siptrace_copy_proto(msg->rcv.proto, sto.fromip_buff);
		strcat(sto.fromip_buff, ip_addr2a(&msg->rcv.src_ip));
		strcat(sto.fromip_buff,":");
		strcat(sto.fromip_buff, int2str(msg->rcv.src_port, NULL));
		sto.fromip.s = sto.fromip_buff;
		sto.fromip.len = strlen(sto.fromip_buff);

		siptrace_copy_proto(msg->rcv.proto, sto.toip_buff);
		strcat(sto.toip_buff, ip_addr2a(&msg->rcv.dst_ip));
		strcat(sto.toip_buff,":");
		strcat(sto.toip_buff, int2str(msg->rcv.dst_port, NULL));
		sto.toip.s = sto.toip_buff;
		sto.toip.len = strlen(sto.toip_buff);

		sto.dir = (dir)?dir:"in";
	} else {
		sto.body.s   = snd_inf->buf;
		sto.body.len = snd_inf->len;

		strncpy(sto.fromip_buff, snd_inf->send_sock->sock_str.s,
				snd_inf->send_sock->sock_str.len);
		sto.fromip.s = sto.fromip_buff;
		sto.fromip.len = strlen(sto.fromip_buff);

		siptrace_copy_proto(snd_inf->send_sock->proto, sto.toip_buff);
		strcat(sto.toip_buff, suip2a(snd_inf->to, sizeof(*snd_inf->to)));
		strcat(sto.toip_buff,":");
		strcat(sto.toip_buff, int2str((int)su_getport(snd_inf->to), NULL));
		sto.toip.s = sto.toip_buff;
		sto.toip.len = strlen(sto.toip_buff);

		sto.dir = "out";
	}

	sto.fromtag = get_from(msg)->tag_value;
	sto.totag = get_to(msg)->tag_value;

#ifdef STATISTICS
	if(msg->first_line.type==SIP_REPLY) {
		sto.stat = siptrace_rpl;
	} else {
		sto.stat = siptrace_req;
	}
#endif
	return sip_trace_store(&sto, dst);
}
Exemplo n.º 19
0
/*
 * Send a request using data from the dialog structure
 */
int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
				transaction_cb cb, void* cbp,release_tmcb_param release_func)
{
	union sockaddr_union to_su, new_to_su;
	struct cell *new_cell;
	struct cell *backup_cell;
	struct retr_buf *request;
	static struct sip_msg *req;
	struct usr_avp **backup;
	char *buf, *buf1;
	int buf_len, buf_len1;
	int ret, flags, sflag_bk;
	int backup_route_type;
	int sip_msg_len;
	unsigned int hi;
	struct socket_info *new_send_sock;
	str h_to, h_from, h_cseq, h_callid;
	struct proxy_l *proxy, *new_proxy;
	unsigned short dst_changed;

	ret=-1;

	/*** added by dcm
	 * - needed by external ua to send a request within a dlg
	 */
	if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
		goto error3;

	if(dialog->obp.s)
		dialog->hooks.next_hop = &dialog->obp;

	LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);

	/* calculate the socket corresponding to next hop */
	proxy = uri2proxy( dialog->hooks.next_hop,
		dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE );
	if (proxy==0)  {
		ret=E_BAD_ADDRESS;
		goto error3;
	}
	/* use the first address */
	hostent2su( &to_su,
		&proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT);

	/* check/discover the send socket */
	if (dialog->send_sock) {
		/* if already set, the protocol of send sock must have the 
		   the same type as the proto required by destination URI */
		if (proxy->proto != dialog->send_sock->proto)
			dialog->send_sock = NULL;
	}
	if (dialog->send_sock==NULL) {
		/* get the send socket */
		dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto);
		if (!dialog->send_sock) {
			LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family);
			ser_error = E_NO_SOCKET;
			goto error2;
		}
	}
	LM_DBG("sending socket is %.*s \n",
		dialog->send_sock->name.len,dialog->send_sock->name.s);


	/* ***** Create TRANSACTION and all related  ***** */
	new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/);
	if (!new_cell) {
		ret=E_OUT_OF_MEM;
		LM_ERR("short of cell shmem\n");
		goto error2;
	}

	/* pass the transaction flags from dialog to transaction */
	new_cell->flags |= dialog->T_flags;

	/* add the callback the transaction for LOCAL_COMPLETED event */
	flags = TMCB_LOCAL_COMPLETED;
	/* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */
	if (pass_provisional_replies || pass_provisional(new_cell))
		flags |= TMCB_LOCAL_RESPONSE_OUT;
	if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){
		ret=E_OUT_OF_MEM;
		LM_ERR("short of tmcb shmem\n");
		goto error2;
	}

	if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0)
		new_cell->flags |= T_IS_INVITE_FLAG;
	new_cell->flags |= T_IS_LOCAL_FLAG;

	request = &new_cell->uac[0].request;
	if (dialog->forced_to_su.s.sa_family == AF_UNSPEC)
		request->dst.to = to_su;
	else
		request->dst.to = dialog->forced_to_su;
	request->dst.send_sock = dialog->send_sock;
	request->dst.proto = dialog->send_sock->proto;
	request->dst.proto_reserved1 = 0;

	hi=dlg2hash(dialog);
	LOCK_HASH(hi);
	insert_into_hash_table_unsafe(new_cell, hi);
	UNLOCK_HASH(hi);

	/* copy AVPs into transaction */
	new_cell->user_avps = dialog->avps;
	dialog->avps = NULL;


	/* ***** Create the message buffer ***** */
	buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len);
	if (!buf) {
		LM_ERR("failed to build message\n");
		ret=E_OUT_OF_MEM;
		goto error1;
	}

	if (local_rlist.a) {
		LM_DBG("building sip_msg from buffer\n");
		req = buf_to_sip_msg(buf, buf_len, dialog);
		if (req==NULL) {
			LM_ERR("failed to build sip_msg from buffer\n");
		} else {
			/* set this transaction as active one */
			backup_cell = get_t();
			set_t( new_cell );
			/* set transaction AVP list */
			backup = set_avp_list( &new_cell->user_avps );
			/* backup script flags */
			sflag_bk = getsflags();
			/* disable parallel forking */
			set_dset_state( 0 /*disable*/);

			/* run the route */
			swap_route_type( backup_route_type, LOCAL_ROUTE);
			run_top_route( local_rlist.a, req);
			set_route_type( backup_route_type );

			/* transfer current message context back to t */
			new_cell->uac[0].br_flags = getb0flags(req);
			/* restore the prevoius active transaction */
			set_t( backup_cell );

			set_dset_state( 1 /*enable*/);
			setsflagsval(sflag_bk);
			set_avp_list( backup );

			/* check for changes - if none, do not regenerate the buffer */
			dst_changed = 1;
			if (req->new_uri.s || req->force_send_socket!=dialog->send_sock ||
			req->dst_uri.len != dialog->hooks.next_hop->len ||
			memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) ||
			(dst_changed=0)==0 || req->add_rm || req->body_lumps){

				new_send_sock = NULL;
				/* do we also need to change the destination? */
				if (dst_changed) {
					/* calculate the socket corresponding to next hop */
					new_proxy = uri2proxy(
						req->dst_uri.s ? &(req->dst_uri) : &req->new_uri,
						PROTO_NONE );
					if (new_proxy==0)
						goto abort_update;
					/* use the first address */
					hostent2su( &new_to_su,
						&new_proxy->host, new_proxy->addr_idx,
						new_proxy->port ? new_proxy->port:SIP_PORT);
					/* get the send socket */
					new_send_sock = get_send_socket( req, &new_to_su,
						new_proxy->proto);
					if (!new_send_sock) {
						free_proxy( new_proxy );
						pkg_free( new_proxy );
						LM_ERR("no socket found for the new destination\n");
						goto abort_update;
					}
				}

				/* if interface change, we need to re-build the via */
				if (new_send_sock && new_send_sock != dialog->send_sock) {
					LM_DBG("Interface change in local route -> "
						"rebuilding via\n");
					if (!del_lump(req,req->h_via1->name.s - req->buf,
					req->h_via1->len,0)) {
						LM_ERR("Failed to remove initial via \n");
						goto abort_update;
					}

					memcpy(req->add_to_branch_s,req->via1->branch->value.s,
						req->via1->branch->value.len);
					req->add_to_branch_len = req->via1->branch->value.len;

					/* update also info about new destination and send sock */
					dialog->send_sock = new_send_sock;
					free_proxy( proxy );
					pkg_free( proxy );
					proxy = new_proxy;
					request->dst.send_sock = new_send_sock;
					request->dst.proto = new_send_sock->proto;
					request->dst.proto_reserved1 = 0;

					/* build the shm buffer now */
					set_init_lump_flags(LUMPFLAG_BRANCH);
					buf1 = build_req_buf_from_sip_req(req,
						(unsigned int*)&buf_len1,
						new_send_sock, new_send_sock->proto,
						MSG_TRANS_SHM_FLAG);
					reset_init_lump_flags();
					del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH);

				} else {

					LM_DBG("Change in local route -> rebuilding buffer\n");
					/* build the shm buffer now */
					buf1 = build_req_buf_from_sip_req(req,
						(unsigned int*)&buf_len1,
						dialog->send_sock, dialog->send_sock->proto,
						MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG);
					/* now as it used, hide the original VIA header */
					del_lump(req,req->h_via1->name.s - req->buf,
						req->h_via1->len, 0);

				}

				if (!buf1) {
					LM_ERR("no more shm mem\n");
					/* keep original buffer */
					goto abort_update;
				}
				/* update shortcuts */
				if(!req->add_rm && !req->new_uri.s) {
					/* headers are not affected, simply tranlate */
					new_cell->from.s = new_cell->from.s - buf + buf1;
					new_cell->to.s = new_cell->to.s - buf + buf1;
					new_cell->callid.s = new_cell->callid.s - buf + buf1;
					new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1;
				} else {
					/* use heavy artilery :D */
					if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to,
					&h_cseq, &h_callid)!=0 ) {
						LM_ERR("failed to update shortcut pointers\n");
						shm_free(buf1);
						goto abort_update;
					}
					new_cell->from = h_from;
					new_cell->to = h_to;
					new_cell->callid = h_callid;
					new_cell->cseq_n = h_cseq;
				}
				/* here we rely on how build_uac_req()
				   builds the first line */
				new_cell->uac[0].uri.s = buf1 +
					req->first_line.u.request.method.len + 1;
				new_cell->uac[0].uri.len = GET_RURI(req)->len;

				/* update also info about new destination and send sock */
				if (new_send_sock)
					request->dst.to = new_to_su;

				shm_free(buf);
				buf = buf1;
				buf_len = buf_len1;
				/* use new buffer */
			} else {
				/* no changes over the message, buffer is already generated,
				   just hide the original VIA for potential further branches */
				del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0);
			}
abort_update:
			/* save the SIP message into transaction */
			new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1);
			if (new_cell->uas.request==NULL) {
				/* reset any T triggering */
				new_cell->on_negative = 0;
				new_cell->on_reply = 0;
			} else {
				new_cell->uas.end_request=
					((char*)new_cell->uas.request)+sip_msg_len;
			}
			/* no parallel support in UAC transactions */
			new_cell->on_branch = 0;
			free_sip_msg(req);
		}
	}

	/* for DNS based failover, copy the DNS proxy into transaction */
	if (!disable_dns_failover) {
		new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/);
		if (new_cell->uac[0].proxy==NULL)
			LM_ERR("failed to store DNS info -> no DNS based failover\n");
	}

	new_cell->method.s = buf;
	new_cell->method.len = method->len;

	request->buffer.s = buf;
	request->buffer.len = buf_len;
	new_cell->nr_of_outgoings++;

	if(last_localT) {
		*last_localT = new_cell;
		REF_UNSAFE(new_cell);
	}

	if (SEND_BUFFER(request) == -1) {
		LM_ERR("attempt to send to '%.*s' failed\n",
			dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);
	}

	if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) {
		t_release_transaction(new_cell);
	} else {
		start_retr(request);
	}

	free_proxy( proxy );
	pkg_free( proxy );

	return 1;

error1:
	LOCK_HASH(hi);
	remove_from_hash_table_unsafe(new_cell);
	UNLOCK_HASH(hi);
	free_cell(new_cell);
error2:
	free_proxy( proxy );
	pkg_free( proxy );
error3:
	return ret;
}
Exemplo n.º 20
0
/** removes first via & sends msg to the second
 * - mode param controls if modules sip response callbacks are executed */
static int do_forward_reply(struct sip_msg* msg, int mode)
{
	char* new_buf;
	struct dest_info dst;
	unsigned int new_len;
	int r;
	struct ip_addr ip;
#ifdef USE_TCP
	char* s;
	int len;
#endif
	init_dest_info(&dst);
	new_buf=0;
	/*check if first via host = us */
	if (check_via){
		if (check_self(&msg->via1->host,
					msg->via1->port?msg->via1->port:SIP_PORT,
					msg->via1->proto)!=1){
			LM_ERR("host in first via!=me : %.*s:%d\n",
				msg->via1->host.len, msg->via1->host.s, msg->via1->port);
			/* send error msg back? */
			goto error;
		}
	}

	/* check modules response_f functions */
	if(likely(mode==0)) {
		for (r=0; r<mod_response_cbk_no; r++)
			if (mod_response_cbks[r](msg)==0) goto skip;
	}
	/* we have to forward the reply stateless, so we need second via -bogdan*/
	if (parse_headers( msg, HDR_VIA2_F, 0 )==-1
		|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
	{
		/* no second via => error */
		LM_DBG("reply cannot be forwarded - no 2nd via\n");
		goto error;
	}

	new_buf = build_res_buf_from_sip_res( msg, &new_len);
	if (!new_buf){
		LM_ERR("building failed\n");
		goto error;
	}

	dst.proto=msg->via2->proto;
	SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags);
	if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error;
#ifdef USE_COMP
	dst.comp=msg->via2->comp_no;
#endif

#if defined USE_TCP || defined USE_SCTP
	if (
#ifdef USE_TCP
			dst.proto==PROTO_TCP
			|| dst.proto==PROTO_WS
#ifdef USE_TLS
			|| dst.proto==PROTO_TLS
			|| dst.proto==PROTO_WSS
#endif
#ifdef USE_SCTP
			||
#endif /* USE_SCTP */
#endif /* USE_TCP */
#ifdef USE_SCTP
			dst.proto==PROTO_SCTP
#endif /* USE_SCTP */
			){
		/* find id in i param if it exists */
		if (msg->via1->i && msg->via1->i->value.s){
			s=msg->via1->i->value.s;
			len=msg->via1->i->value.len;
			LM_DBG("i=%.*s\n",len, ZSW(s));
			if (reverse_hex2int(s, len, (unsigned int*)&dst.id)<0){
				LM_ERR("bad via i param \"%.*s\"\n", len, ZSW(s));
				dst.id=0;
			}
		}

	}
#endif

	apply_force_send_socket(&dst, msg);

	/* call onsend_route */
	if(dst.send_sock == NULL) {
		dst.send_sock=get_send_socket(msg, &dst.to, dst.proto);
		if (dst.send_sock==0){
			LM_ERR("cannot forward reply\n");
			goto done;
		}
	}
	if (onsend_route_enabled(SIP_REPLY)){
		if (run_onsend(msg, &dst, new_buf, new_len)==0){
			su2ip_addr(&ip, &(dst.to));
			LM_ERR("reply to %s:%d(%d) dropped (onsend_route)\n",
					ip_addr2a(&ip), su_getport(&(dst.to)), dst.proto);
			goto error; /* error ? */
		}
	}

	if (msg_send(&dst, new_buf, new_len)<0)
	{
		STATS_RPL_FWD_DROP();
		goto error;
	}

	done:
#ifdef STATS
	STATS_TX_RESPONSE(  (msg->first_line.u.reply.statuscode/100) );
#endif

	LM_DBG("reply forwarded to %.*s:%d\n",
			msg->via2->host.len, msg->via2->host.s,
			(unsigned short) msg->via2->port);

	STATS_RPL_FWD_OK();
	pkg_free(new_buf);
skip:
	return 0;
error:
	if (new_buf) pkg_free(new_buf);
	return -1;
}
Exemplo n.º 21
0
int corex_send_data(str *puri, str *pdata)
{
	struct dest_info dst;
	sip_uri_t next_hop;
	int ret = 0;
	char proto;

	if(parse_uri(puri->s, puri->len, &next_hop)<0)
	{
		LM_ERR("bad dst sip uri <%.*s>\n", puri->len, puri->s);
		return -1;
	}

	init_dest_info(&dst);
	LM_DBG("sending data to sip uri <%.*s>\n", puri->len, puri->s);
	proto = next_hop.proto;
	if(sip_hostport2su(&dst.to, &next_hop.host, next_hop.port_no,
				&proto)!=0) {
		LM_ERR("failed to resolve [%.*s]\n", next_hop.host.len,
			ZSW(next_hop.host.s));
		return -1;
	}
	dst.proto = proto;
	if(dst.proto==PROTO_NONE) dst.proto = PROTO_UDP;

	if (dst.proto == PROTO_UDP)
	{
		dst.send_sock=get_send_socket(0, &dst.to, PROTO_UDP);
		if (dst.send_sock!=0) {
			ret=udp_send(&dst, pdata->s, pdata->len);
		} else {
			LM_ERR("no socket for dst sip uri <%.*s>\n", puri->len, puri->s);
			ret=-1;
		}
	}
#ifdef USE_TCP
	else if(dst.proto == PROTO_TCP) {
		/*tcp*/
		dst.id=0;
		ret=tcp_send(&dst, 0, pdata->s, pdata->len);
	}
#endif
#ifdef USE_TLS
	else if(dst.proto == PROTO_TLS) {
		/*tls*/
		dst.id=0;
		ret=tcp_send(&dst, 0, pdata->s, pdata->len);
	}
#endif
#ifdef USE_SCTP
	else if(dst.proto == PROTO_SCTP) {
		/*sctp*/
		dst.send_sock=get_send_socket(0, &dst.to, PROTO_SCTP);
		if (dst.send_sock!=0) {
			ret=sctp_core_msg_send(&dst, pdata->s, pdata->len);
		} else {
			LM_ERR("no socket for dst sip uri <%.*s>\n", puri->len, puri->s);
			ret=-1;
		}
	}
#endif
	else {
		LM_ERR("unknown proto [%d] for dst sip uri <%.*s>\n",
				dst.proto, puri->len, puri->s);
		ret=-1;
	}

	if (ret>=0) ret=1;

	return ret;
}
Exemplo n.º 22
0
Arquivo: t_fwd.c Projeto: OPSF/uClinux
/* introduce a new uac to transaction; returns its branch id (>=0)
   or error (<0); it doesn't send a message yet -- a reply to it
   might interfere with the processes of adding multiple branches
*/
int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
             struct proxy_l *proxy, int proto )
{

    int ret;
    short temp_proxy;
    union sockaddr_union to;
    unsigned short branch;
    struct socket_info* send_sock;
    char *shbuf;
    unsigned int len;

    branch=t->nr_of_outgoings;
    if (branch==MAX_BRANCHES) {
        LOG(L_ERR, "ERROR: add_uac: maximum number of branches exceeded\n");
        ret=E_CFG;
        goto error;
    }

    /* check existing buffer -- rewriting should never occur */
    if (t->uac[branch].request.buffer) {
        LOG(L_CRIT, "ERROR: add_uac: buffer rewrite attempt\n");
        ret=ser_error=E_BUG;
        goto error;
    }

    /* check DNS resolution */
    if (proxy) {
        temp_proxy=0;
        proto=get_proto(proto, proxy->proto);
    } else {
        proxy=uri2proxy( next_hop ? next_hop : uri, proto );
        if (proxy==0)  {
            ret=E_BAD_ADDRESS;
            goto error;
        }
        proto=proxy->proto; /* uri2proxy will fix it for us */
        temp_proxy=1;
    }

    if (proxy->ok==0) {
        if (proxy->host.h_addr_list[proxy->addr_idx+1])
            proxy->addr_idx++;
        else proxy->addr_idx=0;
        proxy->ok=1;
    }

    hostent2su( &to, &proxy->host, proxy->addr_idx,
                proxy->port ? proxy->port:SIP_PORT);

    send_sock=get_send_socket( request, &to , proto);
    if (send_sock==0) {
        LOG(L_ERR, "ERROR: add_uac: can't fwd to af %d, proto %d "
            " (no corresponding listening socket)\n",
            to.s.sa_family, proto );
        ret=ser_error=E_NO_SOCKET;
        goto error01;
    }

    /* now message printing starts ... */
    shbuf=print_uac_request( t, request, branch, uri,
                             &len, send_sock, proto );
    if (!shbuf) {
        ret=ser_error=E_OUT_OF_MEM;
        goto error01;
    }

    /* things went well, move ahead and install new buffer! */
    t->uac[branch].request.dst.to=to;
    t->uac[branch].request.dst.send_sock=send_sock;
    t->uac[branch].request.dst.proto=proto;
    t->uac[branch].request.dst.proto_reserved1=0;
    t->uac[branch].request.buffer=shbuf;
    t->uac[branch].request.buffer_len=len;
    t->uac[branch].uri.s=t->uac[branch].request.buffer+
                         request->first_line.u.request.method.len+1;
    t->uac[branch].uri.len=uri->len;
    t->nr_of_outgoings++;

    /* update stats */
    proxy->tx++;
    proxy->tx_bytes+=len;

    /* done! */
    ret=branch;

error01:
    if (temp_proxy) {
        free_proxy( proxy );
        pkg_free( proxy );
    }
error:
    return ret;
}
Exemplo n.º 23
0
static void apply_force_send_socket(struct dest_info* dst, struct sip_msg* msg)
{
	if (msg->force_send_socket != 0) {
		dst->send_sock = get_send_socket(msg, &dst->to, dst->proto);
	}
}
Exemplo n.º 24
0
/* ret= 0! if action -> end of list(e.g DROP), 
      > 0 to continue processing next actions
   and <0 on error */
int do_action(struct action* a, struct sip_msg* msg)
{
	int ret;
	int v;
	union sockaddr_union* to;
	struct socket_info* send_sock;
	struct proxy_l* p;
	char* tmp;
	char *new_uri, *end, *crt;
	int len;
	int user;
	struct sip_uri uri, next_hop;
	struct sip_uri* u;
	unsigned short port;
	int proto;

	/* reset the value of error to E_UNSPEC so avoid unknowledgable
	   functions to return with errror (status<0) and not setting it
	   leaving there previous error; cache the previous value though
	   for functions which want to process it */
	prev_ser_error=ser_error;
	ser_error=E_UNSPEC;

	ret=E_BUG;
	switch ((unsigned char)a->type){
		case DROP_T:
				ret=0;
			break;
		case FORWARD_T:
#ifdef USE_TCP
		case FORWARD_TCP_T:
#endif
#ifdef USE_TLS
		case FORWARD_TLS_T:
#endif
		case FORWARD_UDP_T:

			if (a->type==FORWARD_UDP_T) proto=PROTO_UDP;
#ifdef USE_TCP
			else if (a->type==FORWARD_TCP_T) proto= PROTO_TCP;
#endif
#ifdef USE_TLS
			else if (a->type==FORWARD_TLS_T) proto= PROTO_TLS;
#endif
			else proto=msg->rcv.proto;
			if (a->p1_type==URIHOST_ST){
				/*parse uri*/

				if (msg->dst_uri.len) {
					ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop);
					u = &next_hop;
				} else {
					ret = parse_sip_msg_uri(msg);
					u = &msg->parsed_uri;
				}

				if (ret<0) {
					LOG(L_ERR, "ERROR: do_action: forward: bad_uri "
								" dropping packet\n");
					break;
				}
				
				switch (a->p2_type){
					case URIPORT_ST:
									port=u->port_no;
									break;
					case NUMBER_ST:
									port=a->p2.number;
									break;
					default:
							LOG(L_CRIT, "BUG: do_action bad forward 2nd"
										" param type (%d)\n", a->p2_type);
							ret=E_UNSPEC;
							goto error_fwd_uri;
				}
				switch(u->proto){
					case PROTO_NONE:
						proto=PROTO_UDP;
						break;
					case PROTO_UDP:
#ifdef USE_TCP
					case PROTO_TCP:
#endif
#ifdef USE_TLS
					case PROTO_TLS:
#endif
						proto=u->proto;
						break;
					default:
						LOG(L_ERR,"ERROR: do action: forward: bad uri"
								" transport %d\n", u->proto);
						ret=E_BAD_PROTO;
						goto error_fwd_uri;
				}
#ifdef USE_TLS
				if (u->secure){
					if (u->proto==PROTO_UDP){
						LOG(L_ERR, "ERROR: do_action: forward: secure uri"
								" incompatible with transport %d\n", u->proto);
						ret=E_BAD_PROTO;
						goto error_fwd_uri;
					}
					proto=PROTO_TLS;
				}
#endif
				/* create a temporary proxy*/
				p=mk_proxy(&u->host, port, proto);
				if (p==0){
					LOG(L_ERR, "ERROR:  bad host name in uri,"
							" dropping packet\n");
					ret=E_BAD_ADDRESS;
					goto error_fwd_uri;
				}
				ret=forward_request(msg, p, proto);
				/*free_uri(&uri); -- no longer needed, in sip_msg*/
				free_proxy(p); /* frees only p content, not p itself */
				pkg_free(p);
				if (ret>=0) ret=1;
			}else if ((a->p1_type==PROXY_ST) && (a->p2_type==NUMBER_ST)){
				ret=forward_request(msg,(struct proxy_l*)a->p1.data, proto);
				if (ret>=0) ret=1;
			}else{
				LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
			}
			break;
		case SEND_T:
		case SEND_TCP_T:
			if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){
				LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
				break;
			}
			to=(union sockaddr_union*)
					pkg_malloc(sizeof(union sockaddr_union));
			if (to==0){
				LOG(L_ERR, "ERROR: do_action: "
							"memory allocation failure\n");
				ret=E_OUT_OF_MEM;
				break;
			}
			
			p=(struct proxy_l*)a->p1.data;
			
			if (p->ok==0){
				if (p->host.h_addr_list[p->addr_idx+1])
					p->addr_idx++;
				else 
					p->addr_idx=0;
				p->ok=1;
			}
			ret=hostent2su(	to, &p->host, p->addr_idx,
						(p->port)?p->port:SIP_PORT );
			if (ret==0){
				p->tx++;
				p->tx_bytes+=msg->len;
				if (a->type==SEND_T){
					/*udp*/
					send_sock=get_send_socket(to, PROTO_UDP);
					if (send_sock!=0){
						ret=udp_send(send_sock, msg->buf, msg->len, to);
					}else{
						ret=-1;
					}
				}
#ifdef USE_TCP
					else{
					/*tcp*/
					ret=tcp_send(PROTO_TCP, msg->buf, msg->len, to, 0);
				}
#endif
			}
			pkg_free(to);
			if (ret<0){
				p->errors++;
				p->ok=0;
			}else ret=1;
			
			break;
		case LOG_T:
			if ((a->p1_type!=NUMBER_ST)|(a->p2_type!=STRING_ST)){
				LOG(L_CRIT, "BUG: do_action: bad log() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
				break;
			}
			LOG(a->p1.number, a->p2.string);
			ret=1;
			break;

		/* jku -- introduce a new branch */
		case APPEND_BRANCH_T:
			if ((a->p1_type!=STRING_ST)) {
				LOG(L_CRIT, "BUG: do_action: bad append_branch_t %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			ret=append_branch( msg, a->p1.string, 
				a->p1.string ? strlen(a->p1.string):0 );
			break;

		/* jku begin: is_length_greater_than */
		case LEN_GT_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad len_gt type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			/* DBG("XXX: message length %d, max %d\n", 
				msg->len, a->p1.number ); */
			ret = msg->len >= a->p1.number ? 1 : -1;
			break;
		/* jku end: is_length_greater_than */
			
		/* jku - begin : flag processing */

		case SETFLAG_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			if (!flag_in_range( a->p1.number )) {
				ret=E_CFG;
				break;
			}
			setflag( msg, a->p1.number );
			ret=1;
			break;

		case RESETFLAG_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad resetflag() type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			if (!flag_in_range( a->p1.number )) {
				ret=E_CFG;
				break;
			}
			resetflag( msg, a->p1.number );
			ret=1;
			break;
			
		case ISFLAGSET_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad isflagset() type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			if (!flag_in_range( a->p1.number )) {
				ret=E_CFG;
				break;
			}
			ret=isflagset( msg, a->p1.number );
			break;
		/* jku - end : flag processing */

		case ERROR_T:
			if ((a->p1_type!=STRING_ST)|(a->p2_type!=STRING_ST)){
				LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
				break;
			}
			LOG(L_NOTICE, "WARNING: do_action: error(\"%s\", \"%s\") "
					"not implemented yet\n", a->p1.string, a->p2.string);
			ret=1;
			break;
		case ROUTE_T:
			if (a->p1_type!=NUMBER_ST){
				LOG(L_CRIT, "BUG: do_action: bad route() type %d\n",
						a->p1_type);
				ret=E_BUG;
				break;
			}
			if ((a->p1.number>RT_NO)||(a->p1.number<0)){
				LOG(L_ERR, "ERROR: invalid routing table number in"
							"route(%lu)\n", a->p1.number);
				ret=E_CFG;
				break;
			}
			ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1;
			break;
		case EXEC_T:
			if (a->p1_type!=STRING_ST){
				LOG(L_CRIT, "BUG: do_action: bad exec() type %d\n",
						a->p1_type);
				ret=E_BUG;
				break;
			}
			LOG(L_NOTICE, "WARNING: exec(\"%s\") not fully implemented,"
						" using dumb version...\n", a->p1.string);
			ret=system(a->p1.string);
			if (ret!=0){
				LOG(L_NOTICE, "WARNING: exec() returned %d\n", ret);
			}
			ret=1;
			break;
		case REVERT_URI_T:
			if (msg->new_uri.s) {
				pkg_free(msg->new_uri.s);
				msg->new_uri.len=0;
				msg->new_uri.s=0;
				msg->parsed_uri_ok=0; /* invalidate current parsed uri*/
			};
			ret=1;
			break;
		case SET_HOST_T:
		case SET_HOSTPORT_T:
		case SET_USER_T:
		case SET_USERPASS_T:
		case SET_PORT_T:
		case SET_URI_T:
		case PREFIX_T:
		case STRIP_T:
		case STRIP_TAIL_T:
				user=0;
				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
					if (a->p1_type!=NUMBER_ST) {
						LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
							a->p1_type);
						break;
					}
				} else if (a->p1_type!=STRING_ST){
					LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
							a->p1_type);
					ret=E_BUG;
					break;
				}
				if (a->type==SET_URI_T){
					if (msg->new_uri.s) {
							pkg_free(msg->new_uri.s);
							msg->new_uri.len=0;
					}
					msg->parsed_uri_ok=0;
					len=strlen(a->p1.string);
					msg->new_uri.s=pkg_malloc(len+1);
					if (msg->new_uri.s==0){
						LOG(L_ERR, "ERROR: do_action: memory allocation"
								" failure\n");
						ret=E_OUT_OF_MEM;
						break;
					}
					memcpy(msg->new_uri.s, a->p1.string, len);
					msg->new_uri.s[len]=0;
					msg->new_uri.len=len;
					
					ret=1;
					break;
				}
				if (msg->new_uri.s) {
					tmp=msg->new_uri.s;
					len=msg->new_uri.len;
				}else{
					tmp=msg->first_line.u.request.uri.s;
					len=msg->first_line.u.request.uri.len;
				}
				if (parse_uri(tmp, len, &uri)<0){
					LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
								" packet\n", tmp);
					ret=E_UNSPEC;
					break;
				}
				
				new_uri=pkg_malloc(MAX_URI_SIZE);
				if (new_uri==0){
					LOG(L_ERR, "ERROR: do_action: memory allocation "
								" failure\n");
					ret=E_OUT_OF_MEM;
					break;
				}
				end=new_uri+MAX_URI_SIZE;
				crt=new_uri;
				/* begin copying */
				len=strlen("sip:"); if(crt+len>end) goto error_uri;
				memcpy(crt,"sip:",len);crt+=len;

				/* user */

				/* prefix (-jiri) */
				if (a->type==PREFIX_T) {
					tmp=a->p1.string;
					len=strlen(tmp); if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
					/* whatever we had before, with prefix we have username 
					   now */
					user=1;
				}

				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) {
					tmp=a->p1.string;
					len=strlen(tmp);
				} else if (a->type==STRIP_T) {
					if (a->p1.number>uri.user.len) {
						LOG(L_WARN, "Error: too long strip asked; "
									" deleting username: %lu of <%.*s>\n",
									a->p1.number, uri.user.len, uri.user.s );
						len=0;
					} else if (a->p1.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s + a->p1.number;
						len=uri.user.len - a->p1.number;
					}
				} else if (a->type==STRIP_TAIL_T) {
					if (a->p1.number>uri.user.len) {
						LOG(L_WARN, "WARNING: too long strip_tail asked; "
									" deleting username: %lu of <%.*s>\n",
									a->p1.number, uri.user.len, uri.user.s );
						len=0;
					} else if (a->p1.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s;
						len=uri.user.len - a->p1.number;
					}
				} else {
					tmp=uri.user.s;
					len=uri.user.len;
				}

				if (len){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
					user=1; /* we have an user field so mark it */
				}

				if (a->type==SET_USERPASS_T) tmp=0;
				else tmp=uri.passwd.s;
				/* passwd */
				if (tmp){
					len=uri.passwd.len; if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* host */
				if (user || tmp){ /* add @ */
					if(crt+1>end) goto error_uri;
					*crt='@'; crt++;
				}
				if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) {
					tmp=a->p1.string;
					if (tmp) len = strlen(tmp);
					else len=0;
				} else {
					tmp=uri.host.s;
					len = uri.host.len;
				}
				if (tmp){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* port */
				if (a->type==SET_HOSTPORT_T) tmp=0;
				else if (a->type==SET_PORT_T) {
					tmp=a->p1.string;
					if (tmp) len = strlen(tmp);
					else len = 0;
				} else {
					tmp=uri.port.s;
					len = uri.port.len;
				}
				if (tmp){
					if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* params */
				tmp=uri.params.s;
				if (tmp){
					len=uri.params.len; if(crt+len+1>end) goto error_uri;
					*crt=';'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* headers */
				tmp=uri.headers.s;
				if (tmp){
					len=uri.headers.len; if(crt+len+1>end) goto error_uri;
					*crt='?'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				*crt=0; /* null terminate the thing */
				/* copy it to the msg */
				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
				msg->new_uri.s=new_uri;
				msg->new_uri.len=crt-new_uri;
				msg->parsed_uri_ok=0;
				ret=1;
				break;
		case IF_T:
				/* if null expr => ignore if? */
				if ((a->p1_type==EXPR_ST)&&a->p1.data){
					v=eval_expr((struct expr*)a->p1.data, msg);
					if (v<0){
						if (v==EXPR_DROP){ /* hack to quit on DROP*/
							ret=0;
							break;
						}else{
							LOG(L_WARN,"WARNING: do_action:"
										"error in expression\n");
						}
					}
					
					ret=1;  /*default is continue */
					if (v>0) {
						if ((a->p2_type==ACTIONS_ST)&&a->p2.data){
							ret=run_actions((struct action*)a->p2.data, msg);
						}
					}else if ((a->p3_type==ACTIONS_ST)&&a->p3.data){
							ret=run_actions((struct action*)a->p3.data, msg);
					}
				}
			break;
		case MODULE_T:
			if ( ((a->p1_type==CMDF_ST)&&a->p1.data)/*&&
					((a->p2_type==STRING_ST)&&a->p2.data)*/ ){
				ret=((cmd_function)(a->p1.data))(msg, (char*)a->p2.data,
													  (char*)a->p3.data);
			}else{
				LOG(L_CRIT,"BUG: do_action: bad module call\n");
			}
			break;
		case FORCE_RPORT_T:
			msg->msg_flags|=FL_FORCE_RPORT;
			ret=1; /* continue processing */
			break;
		case SET_ADV_ADDR_T:
			if (a->p1_type!=STR_ST){
				LOG(L_CRIT, "BUG: do_action: bad set_advertised_address() "
						"type %d\n", a->p1_type);
				ret=E_BUG;
				break;
			}
			msg->set_global_address=*((str*)a->p1.data);
			ret=1; /* continue processing */
			break;
		case SET_ADV_PORT_T:
			if (a->p1_type!=STR_ST){
				LOG(L_CRIT, "BUG: do_action: bad set_advertised_port() "
						"type %d\n", a->p1_type);
				ret=E_BUG;
				break;
			}
			msg->set_global_port=*((str*)a->p1.data);
			ret=1; /* continue processing */
			break;
		default:
			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
	}
/*skip:*/
	return ret;
	
error_uri:
	LOG(L_ERR, "ERROR: do_action: set*: uri too long\n");
	if (new_uri) pkg_free(new_uri);
	return E_UNSPEC;
error_fwd_uri:
	/*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/
	return ret;
}