action.c
145e3fb3
 
4ac74c03
 /*
  * $Id$
7dd0b342
  *
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
f141bc93
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
7dd0b342
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
049f64c2
  *
  * History:
  * ---------
3e8c3475
  *  2003-02-28  scratchpad compatibility abandoned (jiri)
  *  2003-01-29  removed scratchpad (jiri)
  *  2003-03-19  fixed set* len calculation bug & simplified a little the code
b621d616
  *              (should be a little faster now) (andrei)
3e8c3475
  *              replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
  *  2003-04-01  Added support for loose routing in forward (janakj)
  *  2003-04-12  FORCE_RPORT_T added (andrei)
1d9f91d6
  *  2003-04-22  strip_tail added (jiri)
6bfaa042
  *  2003-10-02  added SET_ADV_ADDR_T & SET_ADV_PORT_T (andrei)
59653eb8
  *  2003-10-29  added FORCE_TCP_ALIAS_T (andrei)
6cd48835
  *  2004-11-30  added FORCE_SEND_SOCKET_T (andrei)
01dea124
  *  2005-12-12  return & drop/exit differentiation (andrei)
a0fb4e8b
  *  2005-12-19  select framework (mma)
e6a2b12e
  *  2006-04-12  updated *_send() calls to use a struct dest_info (andrei)
dcb59e67
  *  2006-07-27  dns cache and dns based send address failover support (andrei)
1875e1d7
  *  2006-12-06  on popular request last_retcode set also by module functions
  *              (andrei)
20fded1f
  *  2007-06-14  run_actions & do_action need a ctx or handle now, no more 
  *               static vars (andrei)
a2da0c58
  *  2008-11-18  support for variable parameter module functions (andrei)
ab7f82d2
  *  2008-12-03  use lvalues/rvalues for assignments (andrei)
4ac74c03
  */
 
 
049f64c2
 #include "comp_defs.h"
7dd0b342
 
4ac74c03
 #include "action.h"
 #include "config.h"
 #include "error.h"
 #include "dprint.h"
 #include "proxy.h"
3e429f5c
 #include "forward.h"
 #include "udp_server.h"
 #include "route.h"
3881f12c
 #include "parser/msg_parser.h"
855c2e68
 #include "parser/parse_uri.h"
104316b6
 #include "ut.h"
ab7f82d2
 #include "lvalue.h"
3bf76e49
 #include "sr_module.h"
dda9dab1
 #include "mem/mem.h"
1400b772
 #include "globals.h"
caf80ae6
 #include "dset.h"
0d88ce78
 #include "onsend.h"
2f0f1a30
 #include "resolve.h"
0c5da34b
 #ifdef USE_TCP
 #include "tcp_server.h"
 #endif
ed990c31
 #ifdef USE_SCTP
 #include "sctp_server.h"
 #endif
4ac74c03
 
a46cdb8c
 #include <sys/types.h>
 #include <sys/socket.h>
4ac74c03
 #include <netdb.h>
 #include <stdlib.h>
63fa628f
 #include <netinet/in.h>
 #include <arpa/inet.h>
e22bbdb8
 #include <string.h>
63fa628f
 
01dea124
 
03150098
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
4ac74c03
 
0d88ce78
 struct onsend_info* p_onsend=0; /* onsend route send info */
 
f141bc93
 /* ret= 0! if action -> end of list(e.g DROP),
7268726e
       > 0 to continue processing next actions
    and <0 on error */
20fded1f
 int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
4ac74c03
 {
 	int ret;
f20a56a2
 	int v;
e6a2b12e
 	struct dest_info dst;
7268726e
 	char* tmp;
 	char *new_uri, *end, *crt;
a2da0c58
 	void* f;
7268726e
 	int len;
45072d7a
 	int user;
9de57c42
 	struct sip_uri uri, next_hop;
1bee75ad
 	struct sip_uri *u;
5ada8f8a
 	unsigned short port;
dcb59e67
 	str* dst_host;
4ac74c03
 
1400b772
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
53c7e0f1
 	   functions to return with error (status<0) and not setting it
1400b772
 	   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;
 
3e429f5c
 	ret=E_BUG;
f2f969dd
 	switch ((unsigned char)a->type){
4ac74c03
 		case DROP_T:
f141bc93
 				if (a->val[0].type==RETCODE_ST)
20fded1f
 					ret=h->last_retcode;
01dea124
 				else
f141bc93
 					ret=(int) a->val[0].u.number;
20fded1f
 				h->run_flags|=(unsigned int)a->val[1].u.number;
4ac74c03
 			break;
 		case FORWARD_T:
f2f969dd
 #ifdef USE_TCP
 		case FORWARD_TCP_T:
 #endif
8e807134
 #ifdef USE_TLS
 		case FORWARD_TLS_T:
 #endif
ed990c31
 #ifdef USE_SCTP
 		case FORWARD_SCTP_T:
 #endif
f2f969dd
 		case FORWARD_UDP_T:
2f0f1a30
 			/* init dst */
 			init_dest_info(&dst);
 			if (a->type==FORWARD_UDP_T) dst.proto=PROTO_UDP;
f2f969dd
 #ifdef USE_TCP
2f0f1a30
 			else if (a->type==FORWARD_TCP_T) dst.proto= PROTO_TCP;
f2f969dd
 #endif
e9b02e8e
 #ifdef USE_TLS
2f0f1a30
 			else if (a->type==FORWARD_TLS_T) dst.proto= PROTO_TLS;
e9b02e8e
 #endif
ed990c31
 #ifdef USE_SCTP
 			else if (a->type==FORWARD_SCTP_T) dst.proto=PROTO_SCTP;
 #endif
 			else dst.proto=PROTO_NONE;
f141bc93
 			if (a->val[0].type==URIHOST_ST){
5ada8f8a
 				/*parse uri*/
9de57c42
 
 				if (msg->dst_uri.len) {
7a068ff3
 					ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len,
 									&next_hop);
9de57c42
 					u = &next_hop;
 				} else {
 					ret = parse_sip_msg_uri(msg);
 					u = &msg->parsed_uri;
 				}
 
1400b772
 				if (ret<0) {
855c2e68
 					LOG(L_ERR, "ERROR: do_action: forward: bad_uri "
 								" dropping packet\n");
5ada8f8a
 					break;
 				}
f141bc93
 
 				switch (a->val[1].type){
5ada8f8a
 					case URIPORT_ST:
1baa06b5
 									port=u->port_no;
5ada8f8a
 									break;
 					case NUMBER_ST:
f141bc93
 									port=a->val[1].u.number;
5ada8f8a
 									break;
 					default:
 							LOG(L_CRIT, "BUG: do_action bad forward 2nd"
f141bc93
 										" param type (%d)\n", a->val[1].type);
7f858173
 							ret=E_UNSPEC;
 							goto error_fwd_uri;
5ada8f8a
 				}
2f0f1a30
 				if (dst.proto == PROTO_NONE){ /* only if proto not set get it
87deb93f
 											 from the uri */
 					switch(u->proto){
 						case PROTO_NONE:
dd4ffbb7
 							/*dst.proto=PROTO_UDP; */
 							/* no proto, try to get it from the dns */
87deb93f
 							break;
 						case PROTO_UDP:
f2e456c3
 #ifdef USE_TCP
87deb93f
 						case PROTO_TCP:
f2e456c3
 #endif
e9b02e8e
 #ifdef USE_TLS
87deb93f
 						case PROTO_TLS:
e9b02e8e
 #endif
ed990c31
 #ifdef USE_SCTP
 						case PROTO_SCTP:
 #endif
2f0f1a30
 							dst.proto=u->proto;
87deb93f
 							break;
 						default:
 							LOG(L_ERR,"ERROR: do action: forward: bad uri"
 									" transport %d\n", u->proto);
 							ret=E_BAD_PROTO;
 							goto error_fwd_uri;
 					}
3f601bd0
 #ifdef USE_TLS
2518c900
 					if (u->type==SIPS_URI_T){
87deb93f
 						if (u->proto==PROTO_UDP){
 							LOG(L_ERR, "ERROR: do_action: forward: secure uri"
2518c900
 									" incompatible with transport %d\n",
 									u->proto);
87deb93f
 							ret=E_BAD_PROTO;
 							goto error_fwd_uri;
 						}
2f0f1a30
 						dst.proto=PROTO_TLS;
3f601bd0
 					}
 #endif
87deb93f
 				}
17bae7f1
 
dcb59e67
 #ifdef HONOR_MADDR				
 				if (u->maddr_val.s && u->maddr_val.len)
 					dst_host=&u->maddr_val;
 				else
17bae7f1
 #endif
dcb59e67
 					dst_host=&u->host;
7a068ff3
 #ifdef USE_COMP
 				dst.comp=u->comp;
 #endif
dcb59e67
 				ret=forward_request(msg, dst_host, port, &dst);
 				if (ret>=0){
 					ret=1;
 				}
f141bc93
 			}else if ((a->val[0].type==PROXY_ST) && (a->val[1].type==NUMBER_ST)){
2f0f1a30
 				if (dst.proto==PROTO_NONE)
 					dst.proto=msg->rcv.proto;
 				proxy2su(&dst.to,  (struct proxy_l*)a->val[0].u.data);
dcb59e67
 				ret=forward_request(msg, 0, 0, &dst);
2f0f1a30
 				if (ret>=0){
 					ret=1;
 					proxy_mark((struct proxy_l*)a->val[0].u.data, ret);
 				}else if (ser_error!=E_OK){
 					proxy_mark((struct proxy_l*)a->val[0].u.data, ret);
 				}
5ada8f8a
 			}else{
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n",
f141bc93
 						a->val[0].type, a->val[1].type);
4ac74c03
 				ret=E_BUG;
 			}
 			break;
 		case SEND_T:
0c5da34b
 		case SEND_TCP_T:
f141bc93
 			if ((a->val[0].type!= PROXY_ST)|(a->val[1].type!=NUMBER_ST)){
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n",
f141bc93
 						a->val[0].type, a->val[1].type);
4ac74c03
 				ret=E_BUG;
 				break;
 			}
2f0f1a30
 			/* init dst */
 			init_dest_info(&dst);
 			ret=proxy2su(&dst.to,  (struct proxy_l*)a->val[0].u.data);
4e2fdd79
 			if (ret==0){
0d88ce78
 				if (p_onsend){
 					tmp=p_onsend->buf;
 					len=p_onsend->len;
 				}else{
 					tmp=msg->buf;
 					len=msg->len;
 				}
0c5da34b
 				if (a->type==SEND_T){
 					/*udp*/
e6a2b12e
 					dst.proto=PROTO_UDP; /* not really needed for udp_send */
 					dst.send_sock=get_send_socket(msg, &dst.to, PROTO_UDP);
 					if (dst.send_sock!=0){
 						ret=udp_send(&dst, tmp, len);
0c5da34b
 					}else{
 						ret=-1;
 					}
 				}
 #ifdef USE_TCP
 					else{
2f0f1a30
 						/*tcp*/
 						dst.proto=PROTO_TCP;
 						dst.id=0;
a288ee34
 						ret=tcp_send(&dst, 0, tmp, len);
36ef0329
 				}
0c5da34b
 #endif
2f0f1a30
 			}else{
 				ret=E_BUG;
 				break;
4e2fdd79
 			}
2f0f1a30
 			proxy_mark((struct proxy_l*)a->val[0].u.data, ret);
 			if (ret>=0) ret=1;
f141bc93
 
4ac74c03
 			break;
 		case LOG_T:
f141bc93
 			if ((a->val[0].type!=NUMBER_ST)|(a->val[1].type!=STRING_ST)){
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad log() types %d, %d\n",
f141bc93
 						a->val[0].type, a->val[1].type);
3e429f5c
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			LOG(a->val[0].u.number, "%s", a->val[1].u.string);
4ac74c03
 			ret=1;
 			break;
3881f12c
 
caf80ae6
 		/* jku -- introduce a new branch */
 		case APPEND_BRANCH_T:
f141bc93
 			if ((a->val[0].type!=STRING_ST)) {
caf80ae6
 				LOG(L_CRIT, "BUG: do_action: bad append_branch_t %d\n",
f141bc93
 					a->val[0].type );
caf80ae6
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			ret=append_branch( msg, a->val[0].u.string,
 					   a->val[0].u.string ? strlen(a->val[0].u.string):0,
 					   0, 0, a->val[1].u.number, 0);
caf80ae6
 			break;
 
1f377e97
 		/* jku begin: is_length_greater_than */
 		case LEN_GT_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
1f377e97
 				LOG(L_CRIT, "BUG: do_action: bad len_gt type %d\n",
f141bc93
 					a->val[0].type );
1f377e97
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			/* DBG("XXX: message length %d, max %d\n",
 				msg->len, a->val[0].u.number ); */
 			ret = msg->len >= a->val[0].u.number ? 1 : -1;
1f377e97
 			break;
 		/* jku end: is_length_greater_than */
f141bc93
 
3881f12c
 		/* jku - begin : flag processing */
 
 		case SETFLAG_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
3881f12c
 				LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n",
f141bc93
 					a->val[0].type );
3881f12c
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			if (!flag_in_range( a->val[0].u.number )) {
3881f12c
 				ret=E_CFG;
 				break;
 			}
f141bc93
 			setflag( msg, a->val[0].u.number );
3881f12c
 			ret=1;
 			break;
 
 		case RESETFLAG_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
3881f12c
 				LOG(L_CRIT, "BUG: do_action: bad resetflag() type %d\n",
f141bc93
 					a->val[0].type );
3881f12c
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			if (!flag_in_range( a->val[0].u.number )) {
3881f12c
 				ret=E_CFG;
 				break;
 			}
f141bc93
 			resetflag( msg, a->val[0].u.number );
3881f12c
 			ret=1;
 			break;
f141bc93
 
3881f12c
 		case ISFLAGSET_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
3881f12c
 				LOG(L_CRIT, "BUG: do_action: bad isflagset() type %d\n",
f141bc93
 					a->val[0].type );
3881f12c
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			if (!flag_in_range( a->val[0].u.number )) {
3881f12c
 				ret=E_CFG;
 				break;
 			}
f141bc93
 			ret=isflagset( msg, a->val[0].u.number );
3881f12c
 			break;
 		/* jku - end : flag processing */
 
85d4627f
 		case AVPFLAG_OPER_T:  {
 			struct search_state st;
 			avp_t* avp;
 			int flag;
 			ret = 0;
 			flag = a->val[1].u.number;
 			if ((a->val[0].u.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL || (a->val[0].u.attr->type & AVP_NAME_RE)!=0) {
 				for (avp=search_first_avp(a->val[0].u.attr->type, a->val[0].u.attr->name, NULL, &st); avp; avp = search_next_avp(&st, NULL)) {
 					switch (a->val[2].u.number) {   /* oper: 0..reset, 1..set, -1..no change */
 						case 0:
 							avp->flags &= ~(avp_flags_t)a->val[1].u.number;
 							break;
 						case 1:
 							avp->flags |= (avp_flags_t)a->val[1].u.number;
 							break;
 						default:;
 					}
 					ret = ret || ((avp->flags & (avp_flags_t)a->val[1].u.number) != 0);
 				}
 			}
 			else {
 				avp = search_avp_by_index(a->val[0].u.attr->type, a->val[0].u.attr->name, NULL, a->val[0].u.attr->index);
 				if (avp) {
 					switch (a->val[2].u.number) {   /* oper: 0..reset, 1..set, -1..no change */
 						case 0:
 							avp->flags &= ~(avp_flags_t)a->val[1].u.number;
 							break;
 						case 1:
 							avp->flags |= (avp_flags_t)a->val[1].u.number;
 							break;
 						default:;
 					}
 					ret = (avp->flags & (avp_flags_t)a->val[1].u.number) != 0;
 				}
 			}
 			if (ret==0)
 				ret = -1;
 			break;
 		}
4ac74c03
 		case ERROR_T:
f141bc93
 			if ((a->val[0].type!=STRING_ST)|(a->val[1].type!=STRING_ST)){
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n",
f141bc93
 						a->val[0].type, a->val[1].type);
3e429f5c
 				ret=E_BUG;
 				break;
 			}
4ac74c03
 			LOG(L_NOTICE, "WARNING: do_action: error(\"%s\", \"%s\") "
f141bc93
 					"not implemented yet\n", a->val[0].u.string, a->val[1].u.string);
4ac74c03
 			ret=1;
 			break;
 		case ROUTE_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST){
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad route() type %d\n",
f141bc93
 						a->val[0].type);
3e429f5c
 				ret=E_BUG;
 				break;
 			}
93349b4e
 			if ((a->val[0].u.number>=main_rt.idx)||(a->val[0].u.number<0)){
3e429f5c
 				LOG(L_ERR, "ERROR: invalid routing table number in"
f141bc93
 							"route(%lu)\n", a->val[0].u.number);
3e429f5c
 				ret=E_CFG;
 				break;
 			}
f141bc93
 			/*ret=((ret=run_actions(rlist[a->val[0].u.number], msg))<0)?ret:1;*/
20fded1f
 			ret=run_actions(h, main_rt.rlist[a->val[0].u.number], msg);
 			h->last_retcode=ret;
 			h->run_flags&=~RETURN_R_F; /* absorb returns */
4ac74c03
 			break;
 		case EXEC_T:
f141bc93
 			if (a->val[0].type!=STRING_ST){
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad exec() type %d\n",
f141bc93
 						a->val[0].type);
3e429f5c
 				ret=E_BUG;
 				break;
 			}
 			LOG(L_NOTICE, "WARNING: exec(\"%s\") not fully implemented,"
f141bc93
 						" using dumb version...\n", a->val[0].u.string);
 			ret=system(a->val[0].u.string);
4ac74c03
 			if (ret!=0){
 				LOG(L_NOTICE, "WARNING: exec() returned %d\n", ret);
 			}
 			ret=1;
 			break;
caf80ae6
 		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;
a6982b85
 				msg->parsed_uri_ok=0; /* invalidate current parsed uri*/
caf80ae6
 			};
 			ret=1;
 			break;
7268726e
 		case SET_HOST_T:
 		case SET_HOSTPORT_T:
6973e34c
 		case SET_HOSTPORTTRANS_T:
7268726e
 		case SET_USER_T:
 		case SET_USERPASS_T:
 		case SET_PORT_T:
 		case SET_URI_T:
1f377e97
 		case PREFIX_T:
 		case STRIP_T:
1d9f91d6
 		case STRIP_TAIL_T:
45072d7a
 				user=0;
1d9f91d6
 				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
f141bc93
 					if (a->val[0].type!=NUMBER_ST) {
1f377e97
 						LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
f141bc93
 							a->val[0].type);
1f377e97
 						break;
 					}
f141bc93
 				} else if (a->val[0].type!=STRING_ST){
7268726e
 					LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
f141bc93
 							a->val[0].type);
7268726e
 					ret=E_BUG;
 					break;
 				}
 				if (a->type==SET_URI_T){
f8d46776
 					if (msg->new_uri.s) {
b78959d0
 							pkg_free(msg->new_uri.s);
f8d46776
 							msg->new_uri.len=0;
903766ce
 					}
a6982b85
 					msg->parsed_uri_ok=0;
f141bc93
 					len=strlen(a->val[0].u.string);
b78959d0
 					msg->new_uri.s=pkg_malloc(len+1);
f8d46776
 					if (msg->new_uri.s==0){
45072d7a
 						LOG(L_ERR, "ERROR: do_action: memory allocation"
 								" failure\n");
7268726e
 						ret=E_OUT_OF_MEM;
 						break;
 					}
f141bc93
 					memcpy(msg->new_uri.s, a->val[0].u.string, len);
f8d46776
 					msg->new_uri.s[len]=0;
 					msg->new_uri.len=len;
f141bc93
 
7268726e
 					ret=1;
 					break;
 				}
6973e34c
 				if (msg->parsed_uri_ok==0) {
 					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;
 					}
 				} else {
 					uri=msg->parsed_uri;
7268726e
 				}
f141bc93
 
b78959d0
 				new_uri=pkg_malloc(MAX_URI_SIZE);
7268726e
 				if (new_uri==0){
45072d7a
 					LOG(L_ERR, "ERROR: do_action: memory allocation "
 								" failure\n");
7268726e
 					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;
1f377e97
 
7268726e
 				/* user */
1f377e97
 
 				/* prefix (-jiri) */
 				if (a->type==PREFIX_T) {
f141bc93
 					tmp=a->val[0].u.string;
7268726e
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
f141bc93
 					/* whatever we had before, with prefix we have username
b621d616
 					   now */
1f377e97
 					user=1;
 				}
 
 				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) {
f141bc93
 					tmp=a->val[0].u.string;
1f377e97
 					len=strlen(tmp);
 				} else if (a->type==STRIP_T) {
f141bc93
 					if (a->val[0].u.number>uri.user.len) {
b621d616
 						LOG(L_WARN, "Error: too long strip asked; "
b667b278
 									" deleting username: %lu of <%.*s>\n",
f141bc93
 									a->val[0].u.number, uri.user.len, uri.user.s );
1f377e97
 						len=0;
f141bc93
 					} else if (a->val[0].u.number==uri.user.len) {
1f377e97
 						len=0;
 					} else {
f141bc93
 						tmp=uri.user.s + a->val[0].u.number;
 						len=uri.user.len - a->val[0].u.number;
1f377e97
 					}
1d9f91d6
 				} else if (a->type==STRIP_TAIL_T) {
f141bc93
 					if (a->val[0].u.number>uri.user.len) {
1d9f91d6
 						LOG(L_WARN, "WARNING: too long strip_tail asked; "
b667b278
 									" deleting username: %lu of <%.*s>\n",
f141bc93
 									a->val[0].u.number, uri.user.len, uri.user.s );
1d9f91d6
 						len=0;
f141bc93
 					} else if (a->val[0].u.number==uri.user.len) {
1d9f91d6
 						len=0;
 					} else {
 						tmp=uri.user.s;
f141bc93
 						len=uri.user.len - a->val[0].u.number;
1d9f91d6
 					}
1f377e97
 				} else {
 					tmp=uri.user.s;
 					len=uri.user.len;
 				}
 
 				if (len){
 					if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
45072d7a
 					user=1; /* we have an user field so mark it */
7268726e
 				}
1f377e97
 
7268726e
 				if (a->type==SET_USERPASS_T) tmp=0;
f8d46776
 				else tmp=uri.passwd.s;
7268726e
 				/* passwd */
 				if (tmp){
b621d616
 					len=uri.passwd.len; if(crt+len+1>end) goto error_uri;
 					*crt=':'; crt++;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* host */
45072d7a
 				if (user || tmp){ /* add @ */
b621d616
 					if(crt+1>end) goto error_uri;
 					*crt='@'; crt++;
45072d7a
 				}
6973e34c
 				if ((a->type==SET_HOST_T)
 						|| (a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T)) {
f141bc93
 					tmp=a->val[0].u.string;
a6982b85
 					if (tmp) len = strlen(tmp);
b621d616
 					else len=0;
a6982b85
 				} else {
f8d46776
 					tmp=uri.host.s;
a6982b85
 					len = uri.host.len;
 				}
7268726e
 				if (tmp){
a6982b85
 					if(crt+len>end) goto error_uri;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* port */
6973e34c
 				if ((a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T))
 					tmp=0;
a6982b85
 				else if (a->type==SET_PORT_T) {
f141bc93
 					tmp=a->val[0].u.string;
a6982b85
 					if (tmp) len = strlen(tmp);
b621d616
 					else len = 0;
a6982b85
 				} else {
 					tmp=uri.port.s;
 					len = uri.port.len;
 				}
7268726e
 				if (tmp){
b621d616
 					if(crt+len+1>end) goto error_uri;
 					*crt=':'; crt++;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* params */
6973e34c
 				if ((a->type==SET_HOSTPORTTRANS_T) && uri.transport.s) {
 					/* bypass the transport parameter */
 					if (uri.params.s < uri.transport.s) {
 						/* there are parameters before transport */
 						len = uri.transport.s - uri.params.s - 1;
 							/* ignore the ';' at the end */
 						if (crt+len+1>end) goto error_uri;
 						*crt=';'; crt++;
 						memcpy(crt,uri.params.s,len);crt+=len;
 					}
 					len = (uri.params.s + uri.params.len) -
 						(uri.transport.s + uri.transport.len);
 					if (len > 0) {
 						/* there are parameters after transport */
 						if (crt+len>end) goto error_uri;
 						tmp = uri.transport.s + uri.transport.len;
 						memcpy(crt,tmp,len);crt+=len;
 					}
 				} else {
 					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;
 					}
7268726e
 				}
 				/* headers */
f8d46776
 				tmp=uri.headers.s;
7268726e
 				if (tmp){
b621d616
 					len=uri.headers.len; if(crt+len+1>end) goto error_uri;
 					*crt='?'; crt++;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				*crt=0; /* null terminate the thing */
 				/* copy it to the msg */
b78959d0
 				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
f8d46776
 				msg->new_uri.s=new_uri;
 				msg->new_uri.len=crt-new_uri;
a6982b85
 				msg->parsed_uri_ok=0;
7268726e
 				ret=1;
 				break;
f20a56a2
 		case IF_T:
 				/* if null expr => ignore if? */
f141bc93
 				if ((a->val[0].type==EXPR_ST)&&a->val[0].u.data){
20fded1f
 					v=eval_expr(h, (struct expr*)a->val[0].u.data, msg);
01dea124
 #if 0
f20a56a2
 					if (v<0){
a1041efe
 						if (v==EXPR_DROP){ /* hack to quit on DROP*/
 							ret=0;
 							break;
 						}else{
 							LOG(L_WARN,"WARNING: do_action:"
 										"error in expression\n");
 						}
f20a56a2
 					}
01dea124
 #endif
20fded1f
 					if (h->run_flags & EXIT_R_F){
01dea124
 						ret=0;
 						break;
 					}
20fded1f
 					h->run_flags &= ~RETURN_R_F; /* catch returns in expr */
9e973a63
 					ret=1;  /*default is continue */
9598488f
 					if (v>0) {
f141bc93
 						if ((a->val[1].type==ACTIONS_ST)&&a->val[1].u.data){
20fded1f
 							ret=run_actions(h, 
 										(struct action*)a->val[1].u.data, msg);
f20a56a2
 						}
f141bc93
 					}else if ((a->val[2].type==ACTIONS_ST)&&a->val[2].u.data){
20fded1f
 							ret=run_actions(h, 
 										(struct action*)a->val[2].u.data, msg);
f20a56a2
 					}
 				}
 			break;
3bf76e49
 		case MODULE_T:
2873d384
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
a2da0c58
 					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
 				ret=((cmd_function)f)(msg,
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
 		/* instead of using the parameter number, we use different names
 		 * for calls to functions with 3, 4, 5, 6 or variable number of
 		 * parameters due to performance reasons */
 		case MODULE3_T:
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
 					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
 				ret=((cmd_function3)f)(msg,
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
 		case MODULE4_T:
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
 					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
 				ret=((cmd_function4)f)(msg,
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data,
 										(char*)a->val[5].u.data
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
 		case MODULE5_T:
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
 					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
 				ret=((cmd_function5)f)(msg,
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data,
 										(char*)a->val[5].u.data,
 										(char*)a->val[6].u.data
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
 		case MODULE6_T:
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
 					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
 				ret=((cmd_function6)f)(msg,
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data,
 										(char*)a->val[5].u.data,
 										(char*)a->val[6].u.data,
 										(char*)a->val[7].u.data
 									);
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
 			} else {
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
 		case MODULEX_T:
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
 					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
 				ret=((cmd_function_var)f)(msg,
 											a->val[1].u.number,
 											&a->val[2]
 										);
20fded1f
 				if (ret==0) h->run_flags|=EXIT_R_F;
 				h->last_retcode=ret;
f141bc93
 			} else {
3bf76e49
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
3e8c3475
 		case FORCE_RPORT_T:
 			msg->msg_flags|=FL_FORCE_RPORT;
 			ret=1; /* continue processing */
 			break;
6bfaa042
 		case SET_ADV_ADDR_T:
f141bc93
 			if (a->val[0].type!=STR_ST){
6bfaa042
 				LOG(L_CRIT, "BUG: do_action: bad set_advertised_address() "
f141bc93
 						"type %d\n", a->val[0].type);
6bfaa042
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			msg->set_global_address=*((str*)a->val[0].u.data);
6bfaa042
 			ret=1; /* continue processing */
 			break;
 		case SET_ADV_PORT_T:
f141bc93
 			if (a->val[0].type!=STR_ST){
6bfaa042
 				LOG(L_CRIT, "BUG: do_action: bad set_advertised_port() "
f141bc93
 						"type %d\n", a->val[0].type);
6bfaa042
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			msg->set_global_port=*((str*)a->val[0].u.data);
6bfaa042
 			ret=1; /* continue processing */
 			break;
59653eb8
 #ifdef USE_TCP
 		case FORCE_TCP_ALIAS_T:
 			if ( msg->rcv.proto==PROTO_TCP
 #ifdef USE_TLS
 					|| msg->rcv.proto==PROTO_TLS
 #endif
 			   ){
f141bc93
 
 				if (a->val[0].type==NOSUBTYPE)	port=msg->via1->port;
 				else if (a->val[0].type==NUMBER_ST) port=(int)a->val[0].u.number;
59653eb8
 				else{
 					LOG(L_CRIT, "BUG: do_action: bad force_tcp_alias"
f141bc93
 							" port type %d\n", a->val[0].type);
59653eb8
 					ret=E_BUG;
 					break;
 				}
f141bc93
 
59653eb8
 				if (tcpconn_add_alias(msg->rcv.proto_reserved1, port,
 									msg->rcv.proto)!=0){
 					LOG(L_ERR, " ERROR: receive_msg: tcp alias failed\n");
 					ret=E_UNSPEC;
 					break;
 				}
 			}
 #endif
 			ret=1; /* continue processing */
 			break;
6cd48835
 		case FORCE_SEND_SOCKET_T:
f141bc93
 			if (a->val[0].type!=SOCKETINFO_ST){
6cd48835
 				LOG(L_CRIT, "BUG: do_action: bad force_send_socket argument"
f141bc93
 						" type: %d\n", a->val[0].type);
6cd48835
 				ret=E_BUG;
 				break;
 			}
f141bc93
 			msg->force_send_socket=(struct socket_info*)a->val[0].u.data;
6cd48835
 			ret=1; /* continue processing */
 			break;
74ce7043
 
ab7f82d2
 	 case ADD_T:
 	case ASSIGN_T:
 			v=lval_assign(h, msg, (struct lvalue*)a->val[0].u.data,
 								  (struct rval_expr*)a->val[1].u.data);
 			if (likely(v>=0)) 
74ce7043
 				ret = 1;
ab7f82d2
 			else if (unlikely (v == EXPR_DROP)) /* hack to quit on DROP*/
 				ret=0;
 			else
 				ret=v;
74ce7043
 			break;
 
4ac74c03
 		default:
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
 	}
e22bbdb8
 /*skip:*/
4ac74c03
 	return ret;
f141bc93
 
7268726e
 error_uri:
 	LOG(L_ERR, "ERROR: do_action: set*: uri too long\n");
764df2b2
 	if (new_uri) pkg_free(new_uri);
7268726e
 	return E_UNSPEC;
7f858173
 error_fwd_uri:
855c2e68
 	/*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/
7f858173
 	return ret;
4ac74c03
 }
 
 
 
f20a56a2
 /* returns: 0, or 1 on success, <0 on error */
 /* (0 if drop or break encountered, 1 if not ) */
20fded1f
 int run_actions(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
4ac74c03
 {
 	struct action* t;
f8f678c3
 	int ret;
4bd1673d
 	struct sr_module *mod;
3e429f5c
 
f8f678c3
 	ret=E_UNSPEC;
20fded1f
 	h->rec_lev++;
 	if (h->rec_lev>ROUTE_MAX_REC_LEV){
3e429f5c
 		LOG(L_ERR, "WARNING: too many recursive routing table lookups (%d)"
20fded1f
 					" giving up!\n", h->rec_lev);
3e429f5c
 		ret=E_UNSPEC;
 		goto error;
 	}
20fded1f
 	if (h->rec_lev==1){
 		h->run_flags=0;
 		h->last_retcode=0;
 #ifdef USE_LONGJMP
 		if (setjmp(h->jmp_env)){
 			h->rec_lev=0;
 			ret=h->last_retcode;
01dea124
 			goto end;
 		}
20fded1f
 #endif
01dea124
 	}
f141bc93
 
4ac74c03
 	if (a==0){
45319ed9
 		DBG("DEBUG: run_actions: null action list (rec_level=%d)\n",
20fded1f
 				h->rec_lev);
f9ac51fb
 		ret=1;
4ac74c03
 	}
 
 	for (t=a; t!=0; t=t->next){
20fded1f
 		ret=do_action(h, t, msg);
 		if (h->run_flags & (RETURN_R_F|EXIT_R_F)){
 			if (h->run_flags & EXIT_R_F){
 #ifdef USE_LONGJMP
 				h->last_retcode=ret;
 				longjmp(h->jmp_env, ret);
 #endif
01dea124
 			}
 			break;
 		}
 		/* ignore error returns */
4ac74c03
 	}
f141bc93
 
20fded1f
 	h->rec_lev--;
01dea124
 end:
4bd1673d
 	/* process module onbreak handlers if present */
20fded1f
 	if (h->rec_lev==0 && ret==0)
f141bc93
 		for (mod=modules;mod;mod=mod->next)
2873d384
 			if ((mod->mod_interface_ver==0) && mod->exports && 
 					mod->exports->v0.onbreak_f) {
 				mod->exports->v0.onbreak_f( msg );
 				DBG("DEBUG: %s onbreak handler called\n",
 						mod->exports->c.name);
4bd1673d
 			}
f20a56a2
 	return ret;
f141bc93
 
4ac74c03
 
 error:
20fded1f
 	h->rec_lev--;
4ac74c03
 	return ret;
 }