|
@@ -9,20 +9,25 @@
|
|
#include <regex.h>
|
|
#include <regex.h>
|
|
#include <netdb.h>
|
|
#include <netdb.h>
|
|
#include <string.h>
|
|
#include <string.h>
|
|
|
|
+#include <sys/socket.h>
|
|
|
|
+#include <netinet/in.h>
|
|
|
|
+#include <arpa/inet.h>
|
|
|
|
+#include <netdb.h>
|
|
|
|
|
|
#include "route.h"
|
|
#include "route.h"
|
|
#include "cfg_parser.h"
|
|
#include "cfg_parser.h"
|
|
#include "dprint.h"
|
|
#include "dprint.h"
|
|
|
|
|
|
/* main routing list */
|
|
/* 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;
|
|
int i;
|
|
if (r){
|
|
if (r){
|
|
|
|
+ /*
|
|
regfree(&(r->method));
|
|
regfree(&(r->method));
|
|
regfree(&(r->uri));
|
|
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[i]);
|
|
free(r->host.h_addr_list);
|
|
free(r->host.h_addr_list);
|
|
}
|
|
}
|
|
|
|
+ */
|
|
free(r);
|
|
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 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;
|
|
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;
|
|
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);
|
|
push(re,head);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
error:
|
|
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;
|
|
struct route_elem* t;
|
|
if (*rl==0){
|
|
if (*rl==0){
|
|
@@ -185,13 +390,7 @@ struct route_elem* route_match(char* method, char* uri, struct route_elem** rl)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
for (t=*rl; t; t=t->next){
|
|
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 :( */
|
|
/* no match :( */
|
|
return 0;
|
|
return 0;
|
|
@@ -206,26 +405,17 @@ void print_rl()
|
|
int i,j;
|
|
int i,j;
|
|
|
|
|
|
if (rlist==0){
|
|
if (rlist==0){
|
|
- LOG(L_INFO, "the routing table is empty\n");
|
|
|
|
|
|
+ printf("the routing table is empty\n");
|
|
return;
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|