- changed sip_msg (new rcv member containing all the ips, ports, protocol)
[sip-router] / route.c
diff --git a/route.c b/route.c
index b54f30a..04235ae 100644 (file)
--- a/route.c
+++ b/route.c
@@ -3,7 +3,31 @@
  *
  * SIP routing engine
  *
+ *
+ * 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:
+ *    info@iptel.org
+ *
+ * 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 <stdlib.h>
 #include <sys/types.h>
 #include <netdb.h>
 
 #include "route.h"
+#include "forward.h"
 #include "dprint.h"
 #include "proxy.h"
+#include "action.h"
+#include "sr_module.h"
+#include "ip_addr.h"
+#include "resolve.h"
+#include "parser/parse_uri.h"
 
-/* main routing list */
-struct route_elem* rlist[RT_NO];
-
-
-
- void free_re(struct route_elem* r)
-{
-       /*int i;*/
-       if (r){
-               /*
-                       regfree(&(r->method));
-                       regfree(&(r->uri));
-                       
-                       if (r->host.h_name)      free(r->host.h_name);
-                       if (r->host.h_aliases){
-                               for (i=0; r->host.h_aliases[i]; i++)
-                                       free(r->host.h_aliases[i]);
-                               free(r->host.h_aliases);
-                       }
-                       if (r->host.h_addr_list){
-                               for (i=0; r->host.h_addr_list[i]; i++)
-                                       free(r->host.h_addr_list[i]);
-                               free(r->host.h_addr_list);
-                       }
-               */
-                       free(r);
-       }
-}
-
-
-
-struct route_elem* init_re()
-{
-       struct route_elem* r;
-       r=(struct route_elem *) malloc(sizeof(struct route_elem));
-       if (r==0) return 0;
-       memset((void*)r, 0, sizeof (struct route_elem));
-       return r;
-}
-
-
-/* adds re list to head; re must be null terminated (last re->next=0))*/
-void push(struct route_elem* re, struct route_elem** head)
-{
-       struct route_elem *t;
-       if (*head==0){
-               *head=re;
-               return;
-       }
-       for (t=*head; t->next;t=t->next);
-       t->next=re;
-}
-
+#ifdef DEBUG_DMALLOC
+#include <dmalloc.h>
+#endif
 
+/* main routing script table  */
+struct action* rlist[RT_NO];
+/* reply routing table */
+struct action* reply_rlist[REPLY_RT_NO];
 
-void clear_rlist(struct route_elem** rl)
-{
-       struct route_elem *t, *u;
-
-       if (*rl==0) return;
-       u=0;
-       for (t=*rl; t; u=t, t=t->next){
-               if (u) free_re(u);
-       }
-       *rl=0;
-}
 
+static int fix_actions(struct action* a); /*fwd declaration*/
 
 
 /* traverses an expr tree and compiles the REs where necessary) 
@@ -95,6 +69,7 @@ static int fix_expr(struct expr* exp)
        regex_t* re;
        int ret;
        
+       ret=E_BUG;
        if (exp==0){
                LOG(L_CRIT, "BUG: fix_expr: null pointer\n");
                return E_BUG;
@@ -139,6 +114,13 @@ static int fix_expr(struct expr* exp)
                                        return E_BUG;
                                }
                        }
+                       if (exp->l.operand==ACTION_O){
+                               ret=fix_actions((struct action*)exp->r.param);
+                               if (ret!=0){
+                                       LOG(L_CRIT, "ERROR: fix_expr : fix_actions error\n");
+                                       return ret;
+                               }
+                       }
                        ret=0;
        }
        return ret;
@@ -147,21 +129,30 @@ static int fix_expr(struct expr* exp)
 
 
 /* adds the proxies in the proxy list & resolves the hostnames */
+/* returns 0 if ok, <0 on error */
 static int fix_actions(struct action* a)
 {
        struct action *t;
        struct proxy_l* p;
        char *tmp;
+       int ret,r;
+       struct sr_module* mod;
        
+       if (a==0){
+               LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
+               return E_BUG;
+       }
        for(t=a; t!=0; t=t->next){
                switch(t->type){
                        case FORWARD_T:
+                       case FORWARD_TCP_T:
+                       case FORWARD_UDP_T:
                        case SEND_T:
+                       case SEND_TCP_T:
                                        switch(t->p1_type){
-                                               case NUMBER_ST:
-                                               case IP_ST: /* for now ip_st==number_st*/
-                                                       tmp=strdup(inet_ntoa(
-                                                                               *(struct in_addr*)&t->p1.number));
+                                               case IP_ST: 
+                                                       tmp=strdup(ip_addr2a(
+                                                                               (struct ip_addr*)t->p1.data));
                                                        if (tmp==0){
                                                                LOG(L_CRIT, "ERROR: fix_actions:"
                                                                                "memory allocation failure\n");
@@ -176,6 +167,8 @@ static int fix_actions(struct action* a)
                                                        t->p1.data=p;
                                                        t->p1_type=PROXY_ST;
                                                        break;
+                                               case URIHOST_ST:
+                                                       break;
                                                default:
                                                        LOG(L_CRIT, "BUG: fix_actions: invalid type"
                                                                        "%d (should be string or number)\n",
@@ -183,6 +176,56 @@ static int fix_actions(struct action* a)
                                                        return E_BUG;
                                        }
                                        break;
+                       case IF_T:
+                               if (t->p1_type!=EXPR_ST){
+                                       LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+                                                               "%d for if (should be expr)\n",
+                                                               t->p1_type);
+                                       return E_BUG;
+                               }else if( (t->p2_type!=ACTIONS_ST)&&(t->p2_type!=NOSUBTYPE) ){
+                                       LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+                                                               "%d for if() {...} (should be action)\n",
+                                                               t->p2_type);
+                                       return E_BUG;
+                               }else if( (t->p3_type!=ACTIONS_ST)&&(t->p3_type!=NOSUBTYPE) ){
+                                       LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+                                                               "%d for if() {} else{...}(should be action)\n",
+                                                               t->p3_type);
+                                       return E_BUG;
+                               }
+                               if (t->p1.data){
+                                       if ((ret=fix_expr((struct expr*)t->p1.data))<0)
+                                               return ret;
+                               }
+                               if ( (t->p2_type==ACTIONS_ST)&&(t->p2.data) ){
+                                       if ((ret=fix_actions((struct action*)t->p2.data))<0)
+                                               return ret;
+                               }
+                               if ( (t->p3_type==ACTIONS_ST)&&(t->p3.data) ){
+                                               if ((ret=fix_actions((struct action*)t->p3.data))<0)
+                                               return ret;
+                               }
+                               break;
+                       case MODULE_T:
+                               if ((mod=find_module(t->p1.data, &r))!=0){
+                                       DBG("fixing %s %s\n", mod->path,
+                                                       mod->exports->cmd_names[r]);
+                                       if (mod->exports->fixup_pointers[r]){
+                                               if (mod->exports->param_no[r]>0){
+                                                       ret=mod->exports->fixup_pointers[r](&t->p2.data,
+                                                                                                                               1);
+                                                       t->p2_type=MODFIXUP_ST;
+                                                       if (ret<0) return ret;
+                                               }
+                                               if (mod->exports->param_no[r]>1){
+                                                       ret=mod->exports->fixup_pointers[r](&t->p3.data,
+                                                                                                                               2);
+                                                       t->p3_type=MODFIXUP_ST;
+                                                       if (ret<0) return ret;
+                                               }
+                                       }
+                               }
+                       
                }
        }
        return 0;
@@ -222,32 +265,39 @@ error:
 
 
 
-/* eval_elem helping function, returns a op param */
-static int comp_ip(unsigned a, void* param, int op, int subtype)
+/* eval_elem helping function, returns an op param */
+static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
 {
        struct hostent* he;
        char ** h;
        int ret;
+       str tmp;
 
        ret=-1;
        switch(subtype){
                case NET_ST:
-                       ret=(a&((struct net*)param)->mask)==((struct net*)param)->ip;
+                       ret=matchnet(ip, (struct net*) param);
+                       /*ret=(a&((struct net*)param)->mask)==((struct net*)param)->ip;*/
                        break;
                case STRING_ST:
                case RE_ST:
                        /* 1: compare with ip2str*/
+               /* !!!??? review reminder ( resolve(name) & compare w/ all ips? */
+#if 0
                        ret=comp_str(inet_ntoa(*(struct in_addr*)&a), param, op,
                                                subtype);
                        if (ret==1) break;
+#endif
                        /* 2: (slow) rev dns the address
                         * and compare with all the aliases */
-                       he=gethostbyaddr((char*)&a, sizeof(a), AF_INET);
+                       he=rev_resolvehost(ip);
                        if (he==0){
-                               LOG(L_DBG, "comp_ip: could not rev_resolve %x\n", a);
+                               DBG( "comp_ip: could not rev_resolve ip address: ");
+                               print_ip(ip);
+                               DBG("\n");
                                ret=0;
                        }else{
-                               /*  compare with primayry host name */
+                               /*  compare with primary 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++){
@@ -255,6 +305,11 @@ static int comp_ip(unsigned a, void* param, int op, int subtype)
                                }
                        }
                        break;
+               case MYSELF_ST: /* check if it's one of our addresses*/
+                       tmp.s=ip_addr2a(ip);
+                       tmp.len=strlen(tmp.s);
+                       ret=check_self(&tmp, 0);
+                       break;
                default:
                        LOG(L_CRIT, "BUG: comp_ip: invalid type for "
                                                " src_ip or dst_ip (%d)\n", subtype);
@@ -262,17 +317,16 @@ static int comp_ip(unsigned a, void* param, int op, int subtype)
        }
        return ret;
        
-error:
-       return -1;
 }
 
 
 
-/* returns: 0/1 (false/true) or -1 on error */
+/* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */
 static int eval_elem(struct expr* e, struct sip_msg* msg)
 {
 
        int ret;
+       ret=E_BUG;
        
        if (e->type!=ELEM_T){
                LOG(L_CRIT," BUG: eval_elem: invalid type\n");
@@ -280,21 +334,45 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
        }
        switch(e->l.operand){
                case METHOD_O:
-                               ret=comp_str(msg->first_line.u.request.method, e->r.param,
+                               ret=comp_str(msg->first_line.u.request.method.s, 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);
+                               if(msg->new_uri.s){
+                                       if (e->subtype==MYSELF_ST){
+                                               if (parse_sip_msg_uri(msg)<0) ret=-1;
+                                               else    ret=check_self(&msg->parsed_uri.host,
+                                                                       msg->parsed_uri.port_no?
+                                                                       msg->parsed_uri.port_no:SIP_PORT);
+                                       }else{
+                                               ret=comp_str(msg->new_uri.s, e->r.param,
+                                                                               e->op, e->subtype);
+                                       }
+                               }else{
+                                       if (e->subtype==MYSELF_ST){
+                                               if (parse_sip_msg_uri(msg)<0) ret=-1;
+                                               else    ret=check_self(&msg->parsed_uri.host,
+                                                                       msg->parsed_uri.port_no?
+                                                                       msg->parsed_uri.port_no:SIP_PORT);
+                                       }else{
+                                               ret=comp_str(msg->first_line.u.request.uri.s,
+                                                                                e->r.param, e->op, e->subtype);
+                                       }
+                               }
                                break;
                case SRCIP_O:
-                               ret=comp_ip(msg->src_ip, e->r.param, e->op, e->subtype);
+                               ret=comp_ip(&msg->rcv.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);
+                               ret=comp_ip(&msg->rcv.dst_ip, e->r.param, e->op, e->subtype);
+                               break;
+               case NUMBER_O:
+                               ret=!(!e->r.intval); /* !! to transform it in {0,1} */
                                break;
-               case DEFAULT_O:
-                               ret=1;
+               case ACTION_O:
+                               ret=run_actions( (struct action*)e->r.param, msg);
+                               if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
+                               else ret=1;
                                break;
                default:
                                LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
@@ -307,7 +385,8 @@ error:
 
 
 
-static int eval_expr(struct expr* e, struct sip_msg* msg)
+/* ret= 0/1 (true/false) ,  -1 on error or EXPR_DROP (-127)  */
+int eval_expr(struct expr* e, struct sip_msg* msg)
 {
        static int rec_lev=0;
        int ret;
@@ -356,53 +435,63 @@ skip:
 }
 
 
+/* adds an action list to head; a must be null terminated (last a->next=0))*/
+void push(struct action* a, struct action** head)
+{
+       struct action *t;
+       if (*head==0){
+               *head=a;
+               return;
+       }
+       for (t=*head; t->next;t=t->next);
+       t->next=a;
+}
+
+
 
 
-int add_rule(struct expr* e, struct action* a, struct route_elem** head)
+int add_actions(struct action* a, struct action** head)
 {
-       
-       struct route_elem* re;
        int ret;
 
-       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");
+       LOG(L_DBG, "add_actions: fixing actions...\n");
        if ((ret=fix_actions(a))!=0) goto error;
-       re->condition=e;
-       re->actions=a;
-       
-       push(re,head);
+       push(a,head);
        return 0;
        
 error:
-       free_re(re);
        return ret;
 }
 
 
 
-struct route_elem* route_match(struct sip_msg* msg, struct route_elem** rl)
+/* fixes all action tables */
+/* returns 0 if ok , <0 on error */
+int fix_rls()
 {
-       struct route_elem* t;
-       if (*rl==0){
-               LOG(L_ERR, "WARNING: route_match: empty routing table\n");
-               return 0;
+       int i,ret;
+       for(i=0;i<RT_NO;i++){
+               if(rlist[i]){
+                       if ((ret=fix_actions(rlist[i]))!=0){
+                               return ret;
+                       }
+               }
        }
-       for (t=*rl; t; t=t->next){
-               if (eval_expr(t->condition, msg)==1) return t;
+       for(i=0;i<REPLY_RT_NO;i++){
+               if(reply_rlist[i]){
+                       if ((ret=fix_actions(reply_rlist[i]))!=0){
+                               return ret;
+                       }
+               }
        }
-       /* no match :( */
        return 0;
 }
 
 
-
 /* debug function, prints main routing table */
 void print_rl()
 {
-       struct route_elem* t;
+       struct action* t;
        int i,j;
 
        for(j=0; j<RT_NO; j++){
@@ -412,15 +501,21 @@ void print_rl()
                }
                DBG("routing table %d:\n",j);
                for (t=rlist[j],i=0; t; i++, t=t->next){
-                       DBG("%2d.condition: ",i);
-                       print_expr(t->condition);
-                       DBG("\n  -> ");
-                       print_action(t->actions);
-                       DBG("\n    Statistics: tx=%d, errors=%d, tx_bytes=%d\n",
-                                       t->tx, t->errors, t->tx_bytes);
+                       print_action(t);
                }
+               DBG("\n");
+       }
+       for(j=0; j<REPLY_RT_NO; j++){
+               if (reply_rlist[j]==0){
+                       if (j==0) DBG("WARNING: the main reply routing table is empty\n");
+                       continue;
+               }
+               DBG("routing table %d:\n",j);
+               for (t=reply_rlist[j],i=0; t; i++, t=t->next){
+                       print_action(t);
+               }
+               DBG("\n");
        }
-
 }