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"
7268726e
 #include "msg_parser.h"
3bf76e49
 #include "sr_module.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>
 
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;
4ac74c03
 	struct sockaddr_in* to;
 	struct proxy_l* p;
7268726e
 	char* tmp;
 	char *new_uri, *end, *crt;
 	int len;
45072d7a
 	int user;
7268726e
 	struct sip_uri uri;
5ada8f8a
 	unsigned short port;
4ac74c03
 
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*/
 				tmp=(msg->new_uri)?msg->new_uri:
 						msg->first_line.u.request.uri;
 				if (parse_uri(tmp, strlen(tmp), &uri)<0){
 					LOG(L_ERR, "ERROR: do_action: forward: bad_uri <%s>,"
 								" dropping packet\n",tmp);
 					ret=E_UNSPEC;
 					break;
 				}
 				switch (a->p2_type){
 					case URIPORT_ST:
 									if (uri.port){
 										port=strtol(uri.port,&end,10);
 										if ((end)&&(*end)){
 											LOG(L_ERR, "ERROR: do_action: "
 													"forward: bad port in "
 													"uri: <%s>\n", uri.port);
 											ret=E_UNSPEC;
 											free_uri(&uri);
 											goto skip;
 										}
 									}else port=SIP_PORT;
 									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);
 							free_uri(&uri);
 							goto skip;
 				}
 				/* create a temporary proxy*/
 				p=mk_proxy(uri.host, port);
 				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:
a46cdb8c
 			to=(struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
4ac74c03
 			if (to==0){
 				LOG(L_ERR, "ERROR: do_action: "
 							"memory allocation failure\n");
 				ret=E_OUT_OF_MEM;
 				break;
 			}
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;
 			}
 			
 			p=(struct proxy_l*)a->p1.data;
 			
 			to->sin_family = AF_INET;
 			to->sin_port=(p->port)?htons(p->port):htons(SIP_PORT);
 			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;
 			}
 			to->sin_addr.s_addr=*((long*)p->host.h_addr_list[p->addr_idx]);
 			p->tx++;
 			p->tx_bytes+=msg->len;
3e429f5c
 			ret=udp_send(msg->orig, msg->len, (struct sockaddr*)to,
 					sizeof(struct sockaddr_in));
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;
 		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;
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:
45072d7a
 				user=0;
7268726e
 				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) free(msg->new_uri);
 					len=strlen(a->p1.string);
 					msg->new_uri=malloc(len+1);
 					if (msg->new_uri==0){
45072d7a
 						LOG(L_ERR, "ERROR: do_action: memory allocation"
 								" failure\n");
7268726e
 						ret=E_OUT_OF_MEM;
 						break;
 					}
 					memcpy(msg->new_uri, a->p1.string, len);
 					msg->new_uri[len]=0;
 					ret=1;
 					break;
 				}
 				if (msg->new_uri) tmp=msg->new_uri;
 				else tmp=msg->first_line.u.request.uri;
 				if (parse_uri(tmp, strlen(tmp), &uri)<0){
45072d7a
 					LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
 								" packet\n", tmp);
7268726e
 					ret=E_UNSPEC;
 					break;
 				}
 				
 				new_uri=malloc(MAX_URI_SIZE);
 				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;
 				/* user */
45072d7a
 				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T))
 					tmp=a->p1.string;
 				else 
 					tmp=uri.user;
7268726e
 				if (tmp){
 					len=strlen(tmp); 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
 				}
 				if (a->type==SET_USERPASS_T) tmp=0;
 				else tmp=uri.passwd;
 				/* 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
 					tmp=uri.host;
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;
 				else tmp=uri.port;
 				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 */
 				tmp=uri.params;
 				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 */
 				tmp=uri.headers;
 				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 */
 				if (msg->new_uri) free(msg->new_uri);
 				msg->new_uri=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){
 						LOG(L_WARN,"WARNING: do_action:"
 									"error in expression\n");
 					}
 					ret=1; /* default is continue */
 					if (v==1){
 						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:
 			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);
 	}
5ada8f8a
 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;
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;
 	int ret;
3e429f5c
 	static int rec_lev=0;
 
 	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){
 		LOG(L_ERR, "WARNING: run_actions: null action list\n");
 		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--;
f20a56a2
 	return ret;
3e429f5c
 	
4ac74c03
 
 error:
3e429f5c
 	rec_lev--;
4ac74c03
 	return ret;
 }