123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- /*
- * $Id$
- *
- * Copyright (C) 2001-2003 Fhg Fokus
- *
- * 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:
- * [email protected]
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #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 "parser/msg_parser.h"
- #include "parser/parse_uri.h"
- #include "ut.h"
- #include "sr_module.h"
- #include "mem/mem.h"
- #include "globals.h"
- #include "dset.h"
- #ifdef USE_TCP
- #include "tcp_server.h"
- #endif
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <string.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;
- 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;
- 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
- 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
- else proto=msg->rcv.proto;
- if (a->p1_type==URIHOST_ST){
- /*parse uri*/
- ret=parse_sip_msg_uri(msg);
- if (ret<0) {
- LOG(L_ERR, "ERROR: do_action: forward: bad_uri "
- " dropping packet\n");
- break;
- }
- u=&msg->parsed_uri;
- 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;
- }
- /* create a temporary proxy*/
- p=mk_proxy(&u->host, port);
- 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 */
- 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*) 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)?htons(p->port):htons(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->orig, msg->len, to);
- }else{
- ret=-1;
- }
- }
- #ifdef USE_TCP
- else{
- /*tcp*/
- ret=tcp_send(msg->orig, msg->len, to, 0);
- }
- #endif
- }
- 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(%d)\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:
- user=0;
- 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){
- 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;
- /* 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.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 {
- 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=strlen(":"); if(crt+len>end) goto error_uri;
- memcpy(crt,":",len);crt+=len;
- len=uri.passwd.len; 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;
- if (tmp) len = strlen(tmp);
- } 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 {
- tmp=uri.port.s;
- len = uri.port.len;
- }
- 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.s;
- if (tmp){
- len=strlen(";"); if(crt+len>end) goto error_uri;
- memcpy(crt,";",len);crt+=len;
- len=uri.params.len; if(crt+len>end) goto error_uri;
- memcpy(crt,tmp,len);crt+=len;
- }
- /* headers */
- tmp=uri.headers.s;
- if (tmp){
- len=strlen("?"); if(crt+len>end) goto error_uri;
- memcpy(crt,"?",len);crt+=len;
- len=uri.headers.len; 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.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;
- 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) free(new_uri);
- return E_UNSPEC;
- error_fwd_uri:
- /*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/
- return ret;
- }
- /* returns: 0, or 1 on success, <0 on error */
- /* (0 if drop or break encountered, 1 if not ) */
- int run_actions(struct action* a, struct sip_msg* msg)
- {
- struct action* t;
- int ret=E_UNSPEC;
- static int rec_lev=0;
- struct sr_module *mod;
- 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 (rec_level=%d)\n",
- rec_lev);
- ret=0;
- }
- for (t=a; t!=0; t=t->next){
- ret=do_action(t, msg);
- if(ret==0) break;
- /* ignore errors */
- /*else if (ret<0){ ret=-1; goto error; }*/
- }
-
- rec_lev--;
- /* 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);
- }
- return ret;
-
- error:
- rec_lev--;
- return ret;
- }
|