- still to do action,c
[sip-router] / route.c
diff --git a/route.c b/route.c
index cf75f49..f5a3f8c 100644 (file)
--- a/route.c
+++ b/route.c
@@ -9,20 +9,25 @@
 #include <regex.h>
 #include <netdb.h>
 #include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
 
 #include "route.h"
 #include "cfg_parser.h"
 #include "dprint.h"
 
 /* main routing list */
-struct route_elem* rlist=0;
+struct route_elem* rlist[RT_NO];
 
 
 
-void free_re(struct route_elem* r)
+ void free_re(struct route_elem* r)
 {
        int i;
        if (r){
+               /*
                        regfree(&(r->method));
                        regfree(&(r->uri));
                        
@@ -37,6 +42,7 @@ void free_re(struct route_elem* r)
                                        free(r->host.h_addr_list[i]);
                                free(r->host.h_addr_list);
                        }
+               */
                        free(r);
        }
 }
@@ -82,102 +88,301 @@ void clear_rlist(struct route_elem** rl)
 
 
 
-int add_rule(struct cfg_line* cl, struct route_elem** head)
+/* traverses an expr tree and compiles the REs where necessary) 
+ * returns: 0 for ok, <0 if errors */
+int fix_expr(struct expr* exp)
 {
-       
-       struct route_elem* re;
-       struct hostent * he;
+       regex_t* re;
        int ret;
-       int i,len, len2;
+       
+       if (exp==0){
+               LOG(L_CRIT, "BUG: fix_expr: null pointer\n");
+               return E_BUG;
+       }
+       if (exp->type==EXP_T){
+               switch(exp->op){
+                       case AND_OP:
+                       case OR_OP:
+                                               if ((ret=fix_expr(exp->l.expr))!=0)
+                                                       return ret;
+                                               ret=fix_expr(exp->r.expr);
+                                               break;
+                       case NOT_OP:
+                                               ret=fix_expr(exp->l.expr);
+                                               break;
+                       default:
+                                               LOG(L_CRIT, "BUG: fix_expr: unknown op %d\n",
+                                                               exp->op);
+               }
+       }else if (exp->type==ELEM_T){
+                       if (exp->op==MATCH_OP){
+                               if (exp->subtype==STRING_ST){
+                                       re=(regex_t*)malloc(sizeof(regex_t));
+                                       if (re==0){
+                                               LOG(L_CRIT, "ERROR: fix_expr: memory allocation"
+                                                               " failure\n");
+                                               return E_OUT_OF_MEM;
+                                       }
+                                       if (regcomp(re, (char*) exp->r.param,
+                                                               REG_EXTENDED|REG_NOSUB|REG_ICASE) ){
+                                               LOG(L_CRIT, "ERROR: fix_expr : bad re \"%s\"\n",
+                                                                       (char*) exp->r.param);
+                                               free(re);
+                                               return E_BAD_RE;
+                                       }
+                                       /* replace the string with the re */
+                                       free(exp->r.param);
+                                       exp->r.param=re;
+                                       exp->subtype=RE_ST;
+                               }else if (exp->subtype!=RE_ST){
+                                       LOG(L_CRIT, "BUG: fix_expr : invalid type for match\n");
+                                       return E_BUG;
+                               }
+                       }
+                       ret=0;
+       }
+       return ret;
+}
 
 
-       re=init_re();
-       if (re==0) return E_OUT_OF_MEM;
 
-       if (regcomp(&(re->method), cl->method, REG_EXTENDED|REG_NOSUB|REG_ICASE)){
-               LOG(L_CRIT, "ERROR: add_rule: bad re \"%s\"\n", cl->method);
-               ret=E_BAD_RE;
-               goto error;
-       }
-       if (regcomp(&(re->uri), cl->uri, REG_EXTENDED|REG_NOSUB|REG_ICASE) ){
-               LOG(L_CRIT, "ERROR: add_rule: bad re \"%s\"\n", cl->uri);
-               ret=E_BAD_RE;
-               goto error;
+/* adds the proxies in the proxy list & resolves the hostnames */
+int fix_actions(struct action* a)
+{
+       struct action *t;
+       struct proxy* p;
+       char *tmp;
+       
+       for(t=a; t!=0; t=t->next){
+               switch(t->type){
+                       case FORWARD_T:
+                       case SEND_T:
+                                       switch(t->p1_type){
+                                               case NUMBER_ST:
+                                                       tmp=strdup(inet_ntoa(
+                                                                               *(struct in_addr*)&t->p1.number));
+                                                       if (tmp==0){
+                                                               LOG(L_CRIT, "ERROR: fix_actions:"
+                                                                               "memory allocation failure\n");
+                                                               return E_OUT_OF_MEM;
+                                                       }
+                                                       t->p1_type=STRING_ST;
+                                                       t->p1.string=tmp;
+                                                       /* no break */
+                                               case STRING_ST:
+                                                       p=add_proxy(t->p1.string, t->p2.number);
+                                                       if (p==0) return E_BAD_ADDRESS;
+                                                       t->p1.data=p;
+                                                       t->p1_type=PROXY_ST;
+                                                       break;
+                                               default:
+                                                       LOG(L_CRIT, "BUG: fix_actions: invalid type"
+                                                                       " (should be string or number)\n");
+                                                       return E_BUG;
+                                       }
+                                       break;
+               }
        }
+       return 0;
+}
+
 
+
+/* eval_elem helping function, returns str op param */
+int comp_str(char* str, void* param, int op, int subtype)
+{
+       int ret;
        
-       he=gethostbyname(cl->address);
-       if (he==0){
-               LOG(L_CRIT, "ERROR: add_rule: cannot resolve \"%s\"\n", cl->address);
-               ret=E_BAD_ADDRESS;
+       ret=-1;
+       if (op==EQUAL_OP){
+               if (subtype!=STRING_ST){
+                       LOG(L_CRIT, "BUG: comp_str: bad type %d, "
+                                       "string expected\n", subtype);
+                       goto error;
+               }
+               ret=(strcasecmp(str, (char*)param)==0);
+       }else if (op==MATCH_OP){
+               if (subtype!=RE_ST){
+                       LOG(L_CRIT, "BUG: comp_str: bad type %d, "
+                                       " RE expected\n", subtype);
+                       goto error;
+               }
+               ret=(regexec((regex_t*)param, str, 0, 0, 0)==0);
+       }else{
+               LOG(L_CRIT, "BUG: comp_str: unknown op %d\n", op);
                goto error;
        }
+       return ret;
        
-       /* start copying the host entry.. */
-       /* copy h_name */
-       len=strlen(he->h_name)+1;
-       re->host.h_name=(char*)malloc(sizeof(char) * len);
-       if (re->host.h_name) strncpy(re->host.h_name, he->h_name, len);
-       else{
-               ret=E_OUT_OF_MEM;
-               goto error;
+error:
+       return -1;
+}
+
+
+
+/* eval_elem helping function, returns a op param */
+int comp_ip(unsigned a, void* param, int op, int subtype)
+{
+       struct hostent* he;
+       char ** h;
+       int ret;
+
+       ret=-1;
+       switch(subtype){
+               case NET_ST:
+                       ret=(a&((struct net*)param)->mask)==((struct net*)param)->ip;
+                       break;
+               case STRING_ST:
+                       /* 1: compare with ip2str*/
+                       ret=comp_str(inet_ntoa(*(struct in_addr*)&a), param, op,
+                                               subtype);
+                       if (ret==1) break;
+                       /* 2: (slow) rev dns the address
+                        * and compare with all the aliases */
+                       he=gethostbyaddr(&a, sizeof(a), AF_INET);
+                       if (he==0){
+                               LOG(L_DBG, "comp_ip: could not rev_resolve %x\n", a);
+                               ret=0;
+                       }else{
+                               /*  compare with primayry host name */
+                               ret=comp_str(he->h_name, param, op, subtype);
+                               /* compare with all the aliases */
+                               for(h=he->h_aliases; (ret!=1) && (*h); h++){
+                                       ret=comp_str(*h, param, op, subtype);
+                               }
+                       }
+                       break;
+               default:
+                       LOG(L_CRIT, "BUG: comp_ip: invalid type for "
+                                               " src_ip or dst_ip (%d)\n", subtype);
+                       ret=-1;
        }
+       return ret;
+       
+error:
+       return -1;
+}
+
 
-       /* copy h_aliases */
-       for (len=0;he->h_aliases[len];len++);
-       re->host.h_aliases=(char**)malloc(sizeof(char*)*(len+1));
-       if (re->host.h_aliases==0){
-               ret=E_OUT_OF_MEM;
+
+/* returns: 0/1 (false/true) or -1 on error */
+int eval_elem(struct expr* e, struct sip_msg* msg)
+{
+
+       int ret;
+       
+       if (e->type!=ELEM_T){
+               LOG(L_CRIT," BUG: eval_elem: invalid type\n");
                goto error;
        }
-       memset((void*)re->host.h_aliases, 0, sizeof(char*) * (len+1) );
-       for (i=0;i<len;i++){
-               len2=strlen(he->h_aliases[i])+1;
-               re->host.h_aliases[i]=(char*)malloc(sizeof(char)*len2);
-               if (re->host.h_aliases==0){
-                       ret=E_OUT_OF_MEM;
-                       goto error;
-               }
-               strncpy(re->host.h_aliases[i], he->h_aliases[i], len2);
+       switch(e->l.operand){
+               case METHOD_O:
+                               ret=comp_str(msg->first_line.u.request.method, e->r.param,
+                                                               e->op, e->subtype);
+                               break;
+               case URI_O:
+                               ret=comp_str(msg->first_line.u.request.uri, e->r.param,
+                                                               e->op, e->subtype);
+                               break;
+               case SRCIP_O:
+                               ret=comp_ip(msg->src_ip, e->r.param, e->op, e->subtype);
+                               break;
+               case DSTIP_O:
+                               ret=comp_ip(msg->dst_ip, e->r.param, e->op, e->subtype);
+                               break;
+               case DEFAULT_O:
+                               ret=1;
+                               break;
+               default:
+                               LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
+                                                       e->l.operand);
        }
-       /* copy h_addr_list */
-       for (len=0;he->h_addr_list[len];len++);
-       re->host.h_addr_list=(char**)malloc(sizeof(char*)*(len+1));
-       if (re->host.h_addr_list==0){
-               ret=E_OUT_OF_MEM;
-               goto error;
+       return ret;
+error:
+       return -1;
+}
+
+
+
+int eval_expr(struct expr* e, struct sip_msg* msg)
+{
+       static int rec_lev=0;
+       int ret;
+       
+       rec_lev++;
+       if (rec_lev>MAX_REC_LEV){
+               LOG(L_CRIT, "ERROR: eval_expr: too many expressions (%d)\n",
+                               rec_lev);
+               ret=-1;
+               goto skip;
        }
-       memset((void*)re->host.h_addr_list, 0, sizeof(char*) * (len+1) );
-       for (i=0;i<len;i++){
-               re->host.h_addr_list[i]=(char*)malloc(sizeof(char)*he->h_length);
-               if (re->host.h_addr_list[i]==0){
-                       ret=E_OUT_OF_MEM;
-                       goto error;
+       
+       if (e->type==ELEM_T){
+               ret=eval_elem(e, msg);
+       }else if (e->type==EXP_T){
+               switch(e->op){
+                       case AND_OP:
+                               ret=eval_expr(e->l.expr, msg);
+                               /* if error or false stop evaluating the rest */
+                               if (ret!=1) break;
+                               ret=eval_expr(e->r.expr, msg); /*ret1 is 1*/
+                               break;
+                       case OR_OP:
+                               ret=eval_expr(e->l.expr, msg);
+                               /* if true or error stop evaluating the rest */
+                               if (ret!=0) break;
+                               ret=eval_expr(e->r.expr, msg); /* ret1 is 0 */
+                               break;
+                       case NOT_OP:
+                               ret=eval_expr(e->l.expr, msg);
+                               if (ret<0) break;
+                               ret= ! ret;
+                               break;
+                       default:
+                               LOG(L_CRIT, "BUG: eval_expr: unknown op %d\n", e->op);
+                               ret=-1;
                }
-               memcpy(re->host.h_addr_list[i], he->h_addr_list[i], he->h_length);
+       }else{
+               LOG(L_CRIT, "BUG: eval_expr: unknown type %d\n", e->type);
+               ret=-1;
        }
 
-       /* copy h_addr_type & length */
-       re->host.h_addrtype=he->h_addrtype;
-       re->host.h_length=he->h_length;
-       /*finished hostent copy */
+skip:
+       rec_lev--;
+       return ret;
+}
+
+
+
 
+int add_rule(struct expr* e, struct action* a, struct route_elem** head)
+{
        
-       re->port=cl->port;
-       re->current_addr_idx=0;
-       re->ok=1;
+       struct route_elem* re;
+       struct hostent * he;
+       int ret;
+       int i,len, len2;
 
+       re=init_re();
+       if (re==0) return E_OUT_OF_MEM;
+       LOG(L_DBG, "add_rule: fixing expr...\n");
+       if ((ret=fix_expr(e))!=0) goto error;
+       LOG(L_DBG, "add_rule: fixing actions...\n");
+       if ((ret=fix_action(a))!=0) goto error;
+       re->condition=e;
+       re->actions=a;
+       
        push(re,head);
        return 0;
        
 error:
-               free_re(re);
-               return ret;
+       free_re(re);
+       return ret;
 }
 
 
 
-struct route_elem* route_match(char* method, char* uri, struct route_elem** rl)
+struct route_elem* route_match(struct sip_msg* msg, struct route_elem** rl)
 {
        struct route_elem* t;
        if (*rl==0){
@@ -185,13 +390,7 @@ struct route_elem* route_match(char* method, char* uri, struct route_elem** rl)
                return 0;
        }
        for (t=*rl; t; t=t->next){
-               if (regexec(&(t->method), method, 0, 0, 0)==0){
-                       /* we have a method mach !!! */
-                       if (regexec(&(t->uri), uri, 0, 0, 0)==0){
-                               /* we have a full match */
-                               return t;
-                       }
-               }
+               if (eval_expr(t->condition, msg)==1) return t;
        }
        /* no match :( */
        return 0;
@@ -206,26 +405,17 @@ void print_rl()
        int i,j;
 
        if (rlist==0){
-               LOG(L_INFO, "the routing table is empty\n");
+               printf("the routing table is empty\n");
                return;
        }
        
-       for (t=rlist,i=0; t; i++, t=t->next){
-               LOG(L_INFO, "%2d.to=%s ; route ok=%d\n", i,
-                               t->host.h_name, t->ok);
-               LOG(L_INFO, "   ips: ");
-               for (j=0; t->host.h_addr_list[j]; j++){
-                       LOG(L_INFO, "%d.%d.%d.%d ", 
-                               (unsigned char) t->host.h_addr_list[j][0],
-                               (unsigned char) t->host.h_addr_list[j][1],
-                           (unsigned char) t->host.h_addr_list[j][2],
-                               (unsigned char) t->host.h_addr_list[j][3]
-                                 );
-               }
-               LOG(L_INFO, "\n");
-               LOG(L_INFO, "   port:%d\n", (unsigned short)t->port);
-               LOG(L_INFO, "   Statistics: tx=%d, errors=%d, tx_bytes=%d, idx=%d\n",
-                               t->tx, t->errors, t->tx_bytes, t->current_addr_idx);
+       for (t=rlist[0],i=0; t; i++, t=t->next){
+               printf("%2d.condition: ");
+               print_expr(t->condition);
+               printf("\n  -> ");
+               print_action(t->actions);
+               printf("\n    Statistics: tx=%d, errors=%d, tx_bytes=%d\n",
+                               t->tx, t->errors, t->tx_bytes);
        }
 
 }