512dcd98 |
/*
* $Id$
*
* SIP routing engine
*
*/
|
3e429f5c |
#include <stdlib.h>
|
512dcd98 |
#include <sys/types.h>
#include <regex.h>
#include <netdb.h>
#include <string.h>
|
a15c363f |
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
|
512dcd98 |
#include "route.h"
#include "dprint.h"
|
4ac74c03 |
#include "proxy.h"
|
f20a56a2 |
#include "action.h"
|
34fd2612 |
#include "sr_module.h"
|
512dcd98 |
|
03150098 |
#ifdef DEBUG_DMALLOC
#include <dmalloc.h>
#endif
|
f20a56a2 |
/* main routing script table */
struct action* rlist[RT_NO];
|
512dcd98 |
|
f20a56a2 |
static int fix_actions(struct action* a); /*fwd declaration*/
|
512dcd98 |
|
a15c363f |
/* traverses an expr tree and compiles the REs where necessary)
* returns: 0 for ok, <0 if errors */
|
3e429f5c |
static int fix_expr(struct expr* exp)
|
512dcd98 |
{
|
a15c363f |
regex_t* re;
|
512dcd98 |
int ret;
|
a15c363f |
|
f20a56a2 |
ret=E_BUG;
|
a15c363f |
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;
}
}
|
f20a56a2 |
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;
}
}
|
a15c363f |
ret=0;
}
return ret;
}
|
512dcd98 |
|
a15c363f |
/* adds the proxies in the proxy list & resolves the hostnames */
|
f20a56a2 |
/* returns 0 if ok, <0 on error */
|
3e429f5c |
static int fix_actions(struct action* a)
|
a15c363f |
{
struct action *t;
|
4ac74c03 |
struct proxy_l* p;
|
a15c363f |
char *tmp;
|
34fd2612 |
int ret,r;
struct sr_module* mod;
|
a15c363f |
|
f20a56a2 |
if (a==0){
LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
return E_BUG;
}
|
a15c363f |
for(t=a; t!=0; t=t->next){
switch(t->type){
case FORWARD_T:
case SEND_T:
switch(t->p1_type){
case NUMBER_ST:
|
3e429f5c |
case IP_ST: /* for now ip_st==number_st*/
|
a15c363f |
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;
|
5ada8f8a |
case URIHOST_ST:
break;
|
a15c363f |
default:
LOG(L_CRIT, "BUG: fix_actions: invalid type"
|
3e429f5c |
"%d (should be string or number)\n",
t->type);
|
a15c363f |
return E_BUG;
}
break;
|
34fd2612 |
case IF_T:
|
f20a56a2 |
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;
|
34fd2612 |
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){
|
5ada8f8a |
ret=mod->exports->fixup_pointers[r](&t->p2.data,
1);
t->p2_type=MODFIXUP_ST;
|
34fd2612 |
if (ret<0) return ret;
}
if (mod->exports->param_no[r]>1){
|
5ada8f8a |
ret=mod->exports->fixup_pointers[r](&t->p3.data,
2);
t->p3_type=MODFIXUP_ST;
|
34fd2612 |
if (ret<0) return ret;
}
}
}
|
a15c363f |
}
|
512dcd98 |
}
|
a15c363f |
return 0;
}
|
512dcd98 |
|
a15c363f |
/* eval_elem helping function, returns str op param */
|
3e429f5c |
static int comp_str(char* str, void* param, int op, int subtype)
|
a15c363f |
{
int ret;
|
512dcd98 |
|
a15c363f |
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);
|
512dcd98 |
goto error;
}
|
a15c363f |
return ret;
|
512dcd98 |
|
a15c363f |
error:
return -1;
}
/* eval_elem helping function, returns a op param */
|
3e429f5c |
static int comp_ip(unsigned a, void* param, int op, int subtype)
|
a15c363f |
{
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:
|
71b44bf0 |
case RE_ST:
|
a15c363f |
/* 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 */
|
f539ba9c |
he=gethostbyaddr((char*)&a, sizeof(a), AF_INET);
|
a15c363f |
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;
|
512dcd98 |
}
|
a15c363f |
return ret;
error:
return -1;
}
|
512dcd98 |
|
a15c363f |
|
a1041efe |
/* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */
|
3e429f5c |
static int eval_elem(struct expr* e, struct sip_msg* msg)
|
a15c363f |
{
int ret;
|
f20a56a2 |
ret=E_BUG;
|
a15c363f |
if (e->type!=ELEM_T){
LOG(L_CRIT," BUG: eval_elem: invalid type\n");
|
512dcd98 |
goto error;
}
|
a15c363f |
switch(e->l.operand){
case METHOD_O:
|
f8d46776 |
ret=comp_str(msg->first_line.u.request.method.s, e->r.param,
|
a15c363f |
e->op, e->subtype);
break;
case URI_O:
|
f8d46776 |
if(msg->new_uri.s){
ret=comp_str(msg->new_uri.s, e->r.param,
|
03150098 |
e->op, e->subtype);
}else{
|
f8d46776 |
ret=comp_str(msg->first_line.u.request.uri.s, e->r.param,
|
03150098 |
e->op, e->subtype);
}
|
a15c363f |
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;
|
f20a56a2 |
case NUMBER_O:
ret=!(!e->r.intval); /* !! to transform it in {0,1} */
break;
case ACTION_O:
|
a1041efe |
ret=run_actions( (struct action*)e->r.param, msg);
if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
else ret=1;
|
a15c363f |
break;
default:
LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
e->l.operand);
|
512dcd98 |
}
|
a15c363f |
return ret;
error:
return -1;
}
|
a1041efe |
/* ret= 0/1 (true/false) , -1 on error or EXPR_DROP (-127) */
|
f20a56a2 |
int eval_expr(struct expr* e, struct sip_msg* msg)
|
a15c363f |
{
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;
|
512dcd98 |
}
|
a15c363f |
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;
|
512dcd98 |
}
|
a15c363f |
}else{
LOG(L_CRIT, "BUG: eval_expr: unknown type %d\n", e->type);
ret=-1;
|
512dcd98 |
}
|
9a3dc64b |
|
a15c363f |
skip:
rec_lev--;
return ret;
}
|
f20a56a2 |
/* 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;
}
|
a15c363f |
|
512dcd98 |
|
f20a56a2 |
int add_actions(struct action* a, struct action** head)
|
a15c363f |
{
int ret;
|
512dcd98 |
|
f20a56a2 |
LOG(L_DBG, "add_actions: fixing actions...\n");
|
3e429f5c |
if ((ret=fix_actions(a))!=0) goto error;
|
f20a56a2 |
push(a,head);
|
512dcd98 |
return 0;
error:
|
a15c363f |
return ret;
|
512dcd98 |
}
|
f20a56a2 |
/* fixes all action tables */
/* returns 0 if ok , <0 on error */
int fix_rls()
|
512dcd98 |
{
|
f20a56a2 |
int i,ret;
for(i=0;i<RT_NO;i++){
if(rlist[i]){
if ((ret=fix_actions(rlist[i]))!=0){
return ret;
}
}
|
512dcd98 |
}
return 0;
}
/* debug function, prints main routing table */
void print_rl()
{
|
f20a56a2 |
struct action* t;
|
512dcd98 |
int i,j;
|
3e429f5c |
for(j=0; j<RT_NO; j++){
if (rlist[j]==0){
|
7268726e |
if (j==0) DBG("WARNING: the main routing table is empty\n");
|
3e429f5c |
continue;
}
|
7268726e |
DBG("routing table %d:\n",j);
|
3e429f5c |
for (t=rlist[j],i=0; t; i++, t=t->next){
|
f20a56a2 |
print_action(t);
|
3e429f5c |
}
|
f20a56a2 |
DBG("\n");
|
512dcd98 |
}
}
|