action.c
4ac74c03
 /*
  * $Id$
  */
 
 
 
 #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"
104316b6
 #include "ut.h"
3bf76e49
 #include "sr_module.h"
dda9dab1
 #include "mem/mem.h"
1400b772
 #include "globals.h"
caf80ae6
 #include "dset.h"
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
 
03150098
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
4ac74c03
 
7268726e
 /* ret= 0! if action -> end of list(e.g DROP), 
       > 0 to continue processing next actions
    and <0 on error */
4ac74c03
 int do_action(struct action* a, struct sip_msg* msg)
 {
 	int ret;
f20a56a2
 	int v;
4e2fdd79
 	union sockaddr_union* to;
36ef0329
 	struct socket_info* send_sock;
4ac74c03
 	struct proxy_l* p;
7268726e
 	char* tmp;
 	char *new_uri, *end, *crt;
 	int len;
45072d7a
 	int user;
104316b6
 	int err;
7268726e
 	struct sip_uri uri;
5ada8f8a
 	unsigned short port;
4ac74c03
 
1400b772
 	/* 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;
 
3e429f5c
 	ret=E_BUG;
4ac74c03
 	switch (a->type){
 		case DROP_T:
 				ret=0;
 			break;
 		case FORWARD_T:
5ada8f8a
 			if (a->p1_type==URIHOST_ST){
 				/*parse uri*/
f8d46776
 				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;
 				}
1400b772
 				ret=parse_uri(tmp, len, &uri );
 				if (ret<0) {
5ada8f8a
 					LOG(L_ERR, "ERROR: do_action: forward: bad_uri <%s>,"
 								" dropping packet\n",tmp);
 					break;
 				}
 				switch (a->p2_type){
 					case URIPORT_ST:
f8d46776
 									if (uri.port.s){
104316b6
 									 /*port=strtol(uri.port.s,&end,10);*/
51eadd0c
 										port=str2s((unsigned char*)uri.port.s, 
 													uri.port.len, &err);
104316b6
 										/*if ((end)&&(*end)){*/
 										if (err){
5ada8f8a
 											LOG(L_ERR, "ERROR: do_action: "
4e2fdd79
 												"forward: bad port in "
 												"uri: <%s>\n", uri.port.s);
1400b772
 											ret=E_BAD_URI;
7f858173
 											goto error_fwd_uri;
5ada8f8a
 										}
1b71270a
 									}else port=0;
5ada8f8a
 									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);
7f858173
 							ret=E_UNSPEC;
 							goto error_fwd_uri;
5ada8f8a
 				}
 				/* create a temporary proxy*/
f8d46776
 				p=mk_proxy(uri.host.s, port);
7f858173
 				if (p==0){
 					LOG(L_ERR, "ERROR:  bad host name in uri,"
 							" dropping packet\n");
 					ret=E_BAD_ADDRESS;
 					goto error_fwd_uri;
 				}
5ada8f8a
 				ret=forward_request(msg, p);
 				free_uri(&uri);
 				free_proxy(p); /* frees only p content, not p itself */
 				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);
 				if (ret>=0) ret=1;
 			}else{
3e429f5c
 				LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n",
 						a->p1_type, a->p2_type);
4ac74c03
 				ret=E_BUG;
 			}
 			break;
 		case SEND_T:
3e429f5c
 			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);
4ac74c03
 				ret=E_BUG;
 				break;
 			}
4e2fdd79
 			to=(union sockaddr_union*) malloc(sizeof(union sockaddr_union));
 			if (to==0){
 				LOG(L_ERR, "ERROR: do_action: "
 							"memory allocation failure\n");
 				ret=E_OUT_OF_MEM;
 				break;
 			}
4ac74c03
 			
 			p=(struct proxy_l*)a->p1.data;
 			
 			if (p->ok==0){
 				if (p->host.h_addr_list[p->addr_idx+1])
 					p->addr_idx++;
5ada8f8a
 				else 
 					p->addr_idx=0;
4ac74c03
 				p->ok=1;
 			}
4e2fdd79
 			ret=hostent2su(	to, &p->host, p->addr_idx,
 						(p->port)?htons(p->port):htons(SIP_PORT) );
 			if (ret==0){
 				p->tx++;
 				p->tx_bytes+=msg->len;
36ef0329
 				send_sock=get_send_socket(to);
 				if (send_sock!=0){
 					ret=udp_send(send_sock, msg->orig, msg->len, to,
 									sizeof(union sockaddr_union));
 				}else{
 					ret=-1;
 				}
4e2fdd79
 			}
4ac74c03
 			free(to);
 			if (ret<0){
 				p->errors++;
 				p->ok=0;
 			}else ret=1;
 			
 			break;
 		case LOG_T:
3e429f5c
 			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);
4ac74c03
 			ret=1;
 			break;
3881f12c
 
caf80ae6
 		/* 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;
 
1f377e97
 		/* 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 */
 			
3881f12c
 		/* 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 */
 
4ac74c03
 		case ERROR_T:
3e429f5c
 			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;
 			}
4ac74c03
 			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:
3e429f5c
 			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(%d)\n", a->p1.number);
 				ret=E_CFG;
 				break;
 			}
f20a56a2
 			ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1;
4ac74c03
 			break;
 		case EXEC_T:
3e429f5c
 			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,"
4ac74c03
 						" 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;
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;
 			};
 			ret=1;
 			break;
7268726e
 		case SET_HOST_T:
 		case SET_HOSTPORT_T:
 		case SET_USER_T:
 		case SET_USERPASS_T:
 		case SET_PORT_T:
 		case SET_URI_T:
1f377e97
 		case PREFIX_T:
 		case STRIP_T:
45072d7a
 				user=0;
1f377e97
 				if (a->type==STRIP_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){
7268726e
 					LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
 							a->p1_type);
 					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;
 					}
7268726e
 					len=strlen(a->p1.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;
 					}
f8d46776
 					memcpy(msg->new_uri.s, a->p1.string, len);
 					msg->new_uri.s[len]=0;
 					msg->new_uri.len=len;
 					
7268726e
 					ret=1;
 					break;
 				}
f8d46776
 				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){
45072d7a
 					LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
 								" packet\n", tmp);
7268726e
 					ret=E_UNSPEC;
 					break;
 				}
 				
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;
5ada8f8a
 					free_uri(&uri);
7268726e
 					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) {
45072d7a
 					tmp=a->p1.string;
7268726e
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
1f377e97
 					/* whateever 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: "
 							"%d of %s\n", a->p1.number, 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 {
 					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){
 					len=strlen(":"); if(crt+len>end) goto error_uri;
 					memcpy(crt,":",len);crt+=len;
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* host */
45072d7a
 				if (user || tmp){ /* add @ */
 					len=strlen("@"); if(crt+len>end) goto error_uri;
 					memcpy(crt,"@",len);crt+=len;
 				}
 				if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T))
 					tmp=a->p1.string;
 				else
f8d46776
 					tmp=uri.host.s;
7268726e
 				if (tmp){
 					len=strlen(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;
f8d46776
 				else tmp=uri.port.s;
7268726e
 				if (tmp){
 					len=strlen(":"); if(crt+len>end) goto error_uri;
 					memcpy(crt,":",len);crt+=len;
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* params */
f8d46776
 				tmp=uri.params.s;
7268726e
 				if (tmp){
 					len=strlen(";"); if(crt+len>end) goto error_uri;
 					memcpy(crt,";",len);crt+=len;
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* headers */
f8d46776
 				tmp=uri.headers.s;
7268726e
 				if (tmp){
 					len=strlen("?"); if(crt+len>end) goto error_uri;
 					memcpy(crt,"?",len);crt+=len;
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					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;
5ada8f8a
 				free_uri(&uri);
7268726e
 				ret=1;
 				break;
f20a56a2
 		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){
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
 					}
a1041efe
 					
9e973a63
 					ret=1;  /*default is continue */
9598488f
 					if (v>0) {
f20a56a2
 						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;
3bf76e49
 		case MODULE_T:
21f03122
 			if ( ((a->p1_type==CMDF_ST)&&a->p1.data)/*&&
 					((a->p2_type==STRING_ST)&&a->p2.data)*/ ){
34fd2612
 				ret=((cmd_function)(a->p1.data))(msg, (char*)a->p2.data,
 													  (char*)a->p3.data);
3bf76e49
 			}else{
 				LOG(L_CRIT,"BUG: do_action: bad module call\n");
 			}
 			break;
4ac74c03
 		default:
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
 	}
e22bbdb8
 /*skip:*/
4ac74c03
 	return ret;
7268726e
 	
 error_uri:
 	LOG(L_ERR, "ERROR: do_action: set*: uri too long\n");
5ada8f8a
 	free_uri(&uri);
7268726e
 	if (new_uri) free(new_uri);
 	return E_UNSPEC;
7f858173
 error_fwd_uri:
 	free_uri(&uri);
 	return ret;
4ac74c03
 }
 
 
 
f20a56a2
 /* returns: 0, or 1 on success, <0 on error */
 /* (0 if drop or break encountered, 1 if not ) */
4ac74c03
 int run_actions(struct action* a, struct sip_msg* msg)
 {
 	struct action* t;
e22bbdb8
 	int ret=E_UNSPEC;
3e429f5c
 	static int rec_lev=0;
4bd1673d
 	struct sr_module *mod;
3e429f5c
 
 	rec_lev++;
 	if (rec_lev>ROUTE_MAX_REC_LEV){
 		LOG(L_ERR, "WARNING: too many recursive routing table lookups (%d)"
 					" giving up!\n", rec_lev);
 		ret=E_UNSPEC;
 		goto error;
 	}
 		
4ac74c03
 	if (a==0){
ea6721d7
 		LOG(L_ERR, "WARNING: run_actions: null action list (rec_level=%d)\n", 
 			rec_lev);
4ac74c03
 		ret=0;
 	}
 
 	for (t=a; t!=0; t=t->next){
 		ret=do_action(t, msg);
 		if(ret==0) break;
5ada8f8a
 		/* ignore errors */
 		/*else if (ret<0){ ret=-1; goto error; }*/
4ac74c03
 	}
3e429f5c
 	
 	rec_lev--;
4bd1673d
 	/* process module onbreak handlers if present */
 	if (rec_lev==0 && ret==0) 
 		for (mod=modules;mod;mod=mod->next) 
 			if (mod->exports && mod->exports->onbreak_f) {
 				mod->exports->onbreak_f( msg );
 				DBG("DEBUG: %s onbreak handler called\n", mod->exports->name);
 			}
f20a56a2
 	return ret;
3e429f5c
 	
4ac74c03
 
 error:
3e429f5c
 	rec_lev--;
4ac74c03
 	return ret;
 }