/* * $Id$ */ #include "action.h" #include "config.h" #include "error.h" #include "dprint.h" #include "proxy.h" #include "forward.h" #include "udp_server.h" #include "route.h" #include "msg_parser.h" #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #ifdef DEBUG_DMALLOC #include <dmalloc.h> #endif /* 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; struct sockaddr_in* to; struct proxy_l* p; struct route_elem* re; char* tmp; char *new_uri, *end, *crt; int len; int user; struct sip_uri uri; ret=E_BUG; switch (a->type){ case DROP_T: ret=0; break; case FORWARD_T: if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){ LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } ret=forward_request(msg, (struct proxy_l*)a->p1.data); if (ret>=0) ret=1; break; case SEND_T: to=(struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); if (to==0){ LOG(L_ERR, "ERROR: do_action: " "memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } 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; } 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++; p->ok=1; } to->sin_addr.s_addr=*((long*)p->host.h_addr_list[p->addr_idx]); p->tx++; p->tx_bytes+=msg->len; ret=udp_send(msg->orig, msg->len, (struct sockaddr*)to, sizeof(struct sockaddr_in)); 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; 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(%d)\n", a->p1.number); ret=E_CFG; break; } re=route_match(msg, &rlist[a->p1.number]); if (re==0){ LOG(L_INFO, "WARNING: do_action: route(%d): no new route" " found\n", a->p1.number); ret=1; break; } ret=((ret=run_actions(re->actions, 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 SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: user=0; 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){ LOG(L_ERR, "ERROR: do_action: memory allocation" " failure\n"); 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){ LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping" " packet\n", tmp); ret=E_UNSPEC; break; } new_uri=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 */ if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) tmp=a->p1.string; else tmp=uri.user; if (tmp){ len=strlen(tmp); 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; /* 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 */ 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; 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; ret=1; break; default: LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type); } return ret; error_uri: LOG(L_ERR, "ERROR: do_action: set*: uri too long\n"); if (new_uri) free(new_uri); return E_UNSPEC; } /* returns: 0 on success, -1 on error */ int run_actions(struct action* a, struct sip_msg* msg) { struct action* t; int ret; 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; } 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; else if (ret<0){ ret=-1; goto error; } } rec_lev--; return 0; error: rec_lev--; return ret; }