- tm: t_relay will not stop script execution anymore in case of send error
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Sun, 11 Dec 2005 22:46:38 +0000 (22:46 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Sun, 11 Dec 2005 22:46:38 +0000 (22:46 +0000)
- added onsend_route: special route executed before forwarding a message, when
 the final destination is known. Only a limited number of commands are allowed
 ( if (expr) {}else{}, drop, flags manipulations, send(), log()).
 Usefull to catch more easily unauthorized attempts to relay/bounce message to
 protected destinations (e.g PSTN gateways)
- new onsend checks: to_{ip,port}, snd_{ip,port,proto,af}. to= to whom the
  message will be sent to. snd=how ser will send it (socket ip/port,proto,af).
- msg:len in onsend_route will containg the "new" message len
- textops: search() onsend_route support (it will use the new, freshly
  constructed message and not the original one)

Example:
onsend_route{
    # allow messages from 10.0.0.0/8 to 1.2.3.4 only if flag 10 was set
    # from the script
    if (to_ip==1.2.3.4 && src_ip==10.0.0.0/8 && !isflagset(10)){
       log("msg dropped\n");
       drop;
    }
   # drop all messages that contain banned_user in from
    if (search("From|f[  ]*:.*banned_user")) drop;
}

13 files changed:
Makefile.defs
NEWS
action.c
cfg.lex
cfg.y
config.h
forward.c
modules/tm/t_funcs.c
modules/tm/t_fwd.c
route.c
route.h
route_struct.h
sr_module.h

index 11840cc..7a1f79c 100644 (file)
@@ -61,7 +61,7 @@ MAIN_NAME=ser
 VERSION = 0
 PATCHLEVEL = 10
 SUBLEVEL =   99
-EXTRAVERSION = -dev27-tm-timers
+EXTRAVERSION = -dev28-tm-timers
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
diff --git a/NEWS b/NEWS
index 6794483..cfcc46b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -34,8 +34,41 @@ modules:
                          changing the transaction timer from script, even if
                          the transaction was already created (see tm docs for
                          more).
+            - t_relay will not stop script execution anymore in case of
+              send error
+ - textops  - search() can be used in the onsend_route where it will search
+              on the "new" message (after applying all script changes, adding
+              Vias a.s.o) and not on the original message
  
 core:
+ - onsend_route added: special route executed before a request is sent.
+                       Only a limited number of commands are allowed (drop, if
+                       + all the checks, msg flag manipulations, send(), log(),
+                       textops::search()). In this route the final destination
+                       of the message is available an can be checked (with
+                       snd_ip, snd_port, to_ip, to_port, snd_proto, snd_af).
+                       This route is executed only when forwarding requests.
+                       It's not executed for replies, retransmissions, or
+                       locally generated messages (e.g. via fifo uac).
+      short example:
+            onsend_route{  if(to_ip==1.2.3.4 && !isflagset(12)){
+                              log(1, "message blocked\n");
+                              drop;
+                           }
+                         }
+ - onsend_route specific checks:
+     - snd_ip, snd_port - behave like src_ip/src_port, but contain the
+       ip/port ser will use to send the message
+     - to_ip, to_port - like above, but contain the ip/port the message will
+       be sent to (not to be confused with dst_ip/dst-port, which are the
+       destination of the original message: ser's ip and port on which the
+       message was received)
+     - snd_proto, snd_af - behave like proto/af but contain the 
+       protocol/address family that ser will use to send the message
+     - msg:len - when used in an onsend_route, msg:len will contain the length
+       of the message on the wire (after all the changes in the script are
+       applied, Vias are added a.s.o) and not the lentgh of the original 
+       message
  - timer: - improved performance/precision, new api, see doc/timers.txt 
  - tcp: - improved  performance (io event handling), using OS specific
            optimizations
@@ -368,33 +401,33 @@ actual workload (malloc is a little bit faster now)
 New features
 =============
 - RFC3261 support
-       - TCP support and cross-transport forwarding [core]
-       - loose routing support [rr module]
+    - TCP support and cross-transport forwarding [core]
+    - loose routing support [rr module]
 - New modules
-       - vm -- voicemail interface [vm]
-       - ENUM support [enum]
-       - presence agent [pa]
-       - dynamic domain management -- allows to manipulate 
-         hosting of multiple domains in run-time [module]
-       - flat-text-file database support [dbtext]
-       - rich access control lists [permissions]
+    - vm -- voicemail interface [vm]
+    - ENUM support [enum]
+    - presence agent [pa]
+    - dynamic domain management -- allows to manipulate 
+      hosting of multiple domains in run-time [module]
+    - flat-text-file database support [dbtext]
+    - rich access control lists [permissions]
 - Feature Improvements
-       - click-to-dial, which is based on improved tm/FIFO 
-         that better supports external applications [tm module]
-       - web accounting -- acc module can report to serweb
-         on placed calls [acc module]
-       - improved exec module (header fields passed now
+    - click-to-dial, which is based on improved tm/FIFO 
+      that better supports external applications [tm module]
+    - web accounting -- acc module can report to serweb
+        on placed calls [acc module]
+    - improved exec module (header fields passed now
       as environment variables to scripts) [exec module]
 - Architectural Improvements
-       - powerpc fast locking support
-       - netbsd support
-       - 64 bits arch. support (e.g. netbsd/sparc64).
+    - powerpc fast locking support
+    - netbsd support
+    - 64 bits arch. support (e.g. netbsd/sparc64).
 - New Experimental Features (not tested at all yet)
-       - nathelper utility for Cisco/ATA NAT traversal [nathelper]
-       - another NAT traversal utility [mangler]
-       - postgress support [postgress]
-       - fcp module [fcp]
-       - pdt module (prefix2domain) [pdt]
+    - nathelper utility for Cisco/ATA NAT traversal [nathelper]
+    - another NAT traversal utility [mangler]
+    - postgress support [postgress]
+    - fcp module [fcp]
+    - pdt module (prefix2domain) [pdt]
 
 Changes to use of ser scripts
 =============================
index b5a4ca3..928e7ff 100644 (file)
--- a/action.c
+++ b/action.c
@@ -57,6 +57,7 @@
 #include "mem/mem.h"
 #include "globals.h"
 #include "dset.h"
+#include "onsend.h"
 #ifdef USE_TCP
 #include "tcp_server.h"
 #endif
@@ -74,6 +75,8 @@
 #endif
 
 
+struct onsend_info* p_onsend=0; /* onsend route send info */
+
 /* ret= 0! if action -> end of list(e.g DROP), 
       > 0 to continue processing next actions
    and <0 on error */
@@ -241,13 +244,20 @@ int do_action(struct action* a, struct sip_msg* msg)
                        ret=hostent2su( to, &p->host, p->addr_idx,
                                                (p->port)?p->port:SIP_PORT );
                        if (ret==0){
+                               if (p_onsend){
+                                       tmp=p_onsend->buf;
+                                       len=p_onsend->len;
+                               }else{
+                                       tmp=msg->buf;
+                                       len=msg->len;
+                               }
                                p->tx++;
-                               p->tx_bytes+=msg->len;
+                               p->tx_bytes+=len;
                                if (a->type==SEND_T){
                                        /*udp*/
                                        send_sock=get_send_socket(msg, to, PROTO_UDP);
                                        if (send_sock!=0){
-                                               ret=udp_send(send_sock, msg->buf, msg->len, to);
+                                               ret=udp_send(send_sock, tmp, len, to);
                                        }else{
                                                ret=-1;
                                        }
@@ -255,7 +265,7 @@ int do_action(struct action* a, struct sip_msg* msg)
 #ifdef USE_TCP
                                        else{
                                        /*tcp*/
-                                       ret=tcp_send(PROTO_TCP, msg->buf, msg->len, to, 0);
+                                       ret=tcp_send(PROTO_TCP, tmp, len, to, 0);
                                }
 #endif
                        }
@@ -743,9 +753,8 @@ int do_action(struct action* a, struct sip_msg* msg)
                                break;
                        }
 
-                            /* If the action is assign then remove the old avp value before adding
-                             * new ones
-                             */
+                       /* If the action is assign then remove the old avp value
+                        * before adding new ones */
                        if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
                        if (add_avp(flags, name, value) < 0) {
                                LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
diff --git a/cfg.lex b/cfg.lex
index 39c2bfc..318cca9 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -56,6 +56,8 @@
  *               tcp_max_connections (andrei)
  *  2005-07-11  added dns_retr_{time,no}, dns_servers_no, dns_use_search_list,
  *              dns_try_ipv6 (andrei)
+ *  2005-12-11  added onsend_route, snd_{ip,port,proto,af},
+ *              to_{ip,port} (andrei)
  */
 
 
@@ -115,6 +117,7 @@ ROUTE       route
 ROUTE_FAILURE failure_route
 ROUTE_ONREPLY onreply_route
 ROUTE_BRANCH branch_route
+ROUTE_SEND onsend_route
 EXEC   exec
 FORCE_RPORT            "force_rport"|"add_rport"
 FORCE_TCP_ALIAS                "force_tcp_alias"|"add_tcp_alias"
@@ -158,6 +161,12 @@ SRCIP      src_ip
 SRCPORT        src_port
 DSTIP  dst_ip
 DSTPORT        dst_port
+SNDIP  snd_ip
+SNDPORT        snd_port
+SNDPROTO       snd_proto|to_proto
+SNDAF          snd_af|to_af
+TOIP   to_ip
+TOPORT to_port
 PROTO  proto
 AF             af
 MYSELF myself
@@ -328,6 +337,7 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{ROUTE_FAILURE}       { count(); yylval.strval=yytext;
                                                                return ROUTE_FAILURE; }
 <INITIAL>{ROUTE_BRANCH} { count(); yylval.strval=yytext; return ROUTE_BRANCH; }
+<INITIAL>{ROUTE_SEND} { count(); yylval.strval=yytext; return ROUTE_SEND; }
 <INITIAL>{EXEC}        { count(); yylval.strval=yytext; return EXEC; }
 <INITIAL>{SET_HOST}    { count(); yylval.strval=yytext; return SET_HOST; }
 <INITIAL>{SET_HOSTPORT}        { count(); yylval.strval=yytext; return SET_HOSTPORT; }
@@ -367,6 +377,12 @@ EAT_ABLE   [\ \t\b\r]
 <INITIAL>{SRCPORT}     { count(); yylval.strval=yytext; return SRCPORT; }
 <INITIAL>{DSTIP}       { count(); yylval.strval=yytext; return DSTIP; }
 <INITIAL>{DSTPORT}     { count(); yylval.strval=yytext; return DSTPORT; }
+<INITIAL>{SNDIP}       { count(); yylval.strval=yytext; return SNDIP; }
+<INITIAL>{SNDPORT}     { count(); yylval.strval=yytext; return SNDPORT; }
+<INITIAL>{SNDPROTO}    { count(); yylval.strval=yytext; return SNDPROTO; }
+<INITIAL>{SNDAF}       { count(); yylval.strval=yytext; return SNDAF; }
+<INITIAL>{TOIP}                { count(); yylval.strval=yytext; return TOIP; }
+<INITIAL>{TOPORT}      { count(); yylval.strval=yytext; return TOPORT; }
 <INITIAL>{PROTO}       { count(); yylval.strval=yytext; return PROTO; }
 <INITIAL>{AF}  { count(); yylval.strval=yytext; return AF; }
 <INITIAL>{MYSELF}      { count(); yylval.strval=yytext; return MYSELF; }
diff --git a/cfg.y b/cfg.y
index 0e56712..6dc1bfc 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -64,6 +64,8 @@
  *             DNS_TRY_IPV6 (andrei)
  * 2005-07-12  default onreply route added (andrei)
  * 2005-11-16  fixed if (cond) cmd; (andrei)
+ * 2005-12-11  added onsend_route support, fcmd (filtered cmd),
+ *             snd_{ip,port,proto,af}, to_{ip,proto} (andrei)
  *
  */
 
  with no built in alloca, like icc*/
 #undef _ALLOCA_H
 
+#define onsend_check(s) \
+       do{\
+               if (rt!=ONSEND_ROUTE) yyerror( s " allowed only in onsend_routes");\
+       }while(0)
 
 extern int yylex();
 static void yyerror(char* s);
@@ -150,6 +156,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token ROUTE_FAILURE
 %token ROUTE_ONREPLY
 %token ROUTE_BRANCH
+%token ROUTE_SEND
 %token EXEC
 %token SET_HOST
 %token SET_HOSTPORT
@@ -183,6 +190,12 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token SRCPORT
 %token DSTIP
 %token DSTPORT
+%token TOIP
+%token TOPORT
+%token SNDIP
+%token SNDPORT
+%token SNDPROTO
+%token SNDAF
 %token PROTO
 %token AF
 %token MYSELF
@@ -310,7 +323,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 
 /*non-terminals */
 %type <expr> exp exp_elem /*, condition*/
-%type <action> action actions cmd if_cmd stm exp_stm assign_action
+%type <action> action actions cmd fcmd if_cmd stm exp_stm assign_action
 %type <ipaddr> ipv4 ipv6 ipv6addr ip
 %type <ipnet> ipnet
 %type <strval> host
@@ -347,6 +360,7 @@ statement:  assign_stm
                | {rt=FAILURE_ROUTE;} failure_route_stm
                | {rt=ONREPLY_ROUTE;} onreply_route_stm
                | {rt=BRANCH_ROUTE;} branch_route_stm
+               | {rt=ONSEND_ROUTE;}   send_route_stm
                | CR    /* null statement*/
        ;
 
@@ -896,6 +910,19 @@ branch_route_stm: ROUTE_BRANCH LBRACE actions RBRACE {
                                                                                }
                | ROUTE_BRANCH error { yyerror("invalid branch_route statement"); }
        ;
+send_route_stm: ROUTE_SEND LBRACE actions RBRACE {
+                                                                       push($3, &onsend_rlist[DEFAULT_RT]);
+                                                                       }
+                       |   ROUTE_SEND LBRACK NUMBER RBRACK LBRACE actions RBRACE {
+                                                                       if (($3<ONSEND_RT_NO)&&($3>=1)){
+                                                                               push($6, &onsend_rlist[$3]);
+                                                                       } else {
+                                                                               yyerror("invalid onsend routing"
+                                                                                               "table number");
+                                                                               YYABORT; }
+                                                               }
+                       | ROUTE_SEND error { yyerror("invalid onsend_route statement"); }
+       ;
 /*
 rules: rules rule { push($2, &$1); $$=$1; }
        | rule {$$=$1; }
@@ -963,7 +990,7 @@ exp_elem:   METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                                                                        " == , != or =~ expected");
                                        }
                | SRCPORT intop NUMBER  { $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); }
-                | SRCPORT intop attr_id { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
+               | SRCPORT intop attr_id { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
                | SRCPORT intop error { $$=0; yyerror("number expected"); }
                | SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
 
@@ -972,6 +999,24 @@ exp_elem:  METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                | DSTPORT intop error { $$=0; yyerror("number expected"); }
                | DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
 
+               | SNDPORT intop NUMBER  {       onsend_check("snd_port");
+                                                                       $$=mk_elem($2, SNDPORT_O, 0, NUMBER_ST,
+                                                                                               (void*)$3 ); }
+               | SNDPORT intop attr_id {       onsend_check("snd_port");
+                                                                       $$=mk_elem($2, SNDPORT_O, 0, AVP_ST,
+                                                                                               (void*)$3 ); }
+               | SNDPORT intop error { $$=0; yyerror("number expected"); }
+               | SNDPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
+
+               | TOPORT intop NUMBER   {       onsend_check("to_port");
+                                                                       $$=mk_elem($2, TOPORT_O, 0, NUMBER_ST,
+                                                                                               (void*)$3 ); }
+               | TOPORT intop attr_id {        onsend_check("to_port");
+                                                                       $$=mk_elem($2, TOPORT_O, 0, AVP_ST,
+                                                                                               (void*)$3 ); }
+               | TOPORT intop error { $$=0; yyerror("number expected"); }
+               | TOPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
+
                | PROTO intop proto     { $$=mk_elem($2, PROTO_O, 0, NUMBER_ST, (void*)$3 ); }
                | PROTO intop attr_id   { $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
                | PROTO intop error { $$=0;
@@ -979,11 +1024,31 @@ exp_elem:        METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                                                        }
                | PROTO error { $$=0; yyerror("equal/!= operator expected"); }
 
+               | SNDPROTO intop proto  {       onsend_check("snd_proto");
+                                                                       $$=mk_elem($2, SNDPROTO_O, 0, NUMBER_ST,
+                                                                               (void*)$3 ); }
+               | SNDPROTO intop attr_id {      onsend_check("snd_proto");
+                                                                       $$=mk_elem($2, SNDPROTO_O, 0, AVP_ST,
+                                                                               (void*)$3 ); }
+               | SNDPROTO intop error { $$=0;
+                                                               yyerror("protocol expected (udp, tcp or tls)");
+                                                       }
+               | SNDPROTO error { $$=0; yyerror("equal/!= operator expected"); }
+
                | AF intop NUMBER       { $$=mk_elem($2, AF_O, 0, NUMBER_ST,(void *) $3 ); }
                | AF intop attr_id      { $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
                | AF intop error { $$=0; yyerror("number expected"); }
                | AF error { $$=0; yyerror("equal/!= operator expected"); }
 
+               | SNDAF intop NUMBER    {       onsend_check("snd_af");
+                                                                       $$=mk_elem($2, SNDAF_O, 0, NUMBER_ST,
+                                                                               (void *) $3 ); }
+               | SNDAF intop attr_id   {       onsend_check("snd_af");
+                                                                       $$=mk_elem($2, SNDAF_O, 0, AVP_ST,
+                                                                               (void *) $3 ); }
+               | SNDAF intop error { $$=0; yyerror("number expected"); }
+               | SNDAF error { $$=0; yyerror("equal/!= operator expected"); }
+
                | MSGLEN intop NUMBER   { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) $3 ); }
                | MSGLEN intop attr_id  { $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
                | MSGLEN intop MAX_LEN  { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); }
@@ -1040,6 +1105,58 @@ exp_elem:        METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                                                                        "expected" ); }
                | DSTIP error { $$=0; 
                                                yyerror("invalid operator, ==, != or =~ expected");}
+               | SNDIP equalop ipnet   { onsend_check("snd_ip");
+                                                                       $$=mk_elem($2, SNDIP_O, 0, NET_ST, $3); }
+               | SNDIP strop STRING    {       onsend_check("snd_ip");
+                                                                       s_tmp.s=$3;
+                                                                       s_tmp.len=strlen($3);
+                                                                       ip_tmp=str2ip(&s_tmp);
+                                                                       if (ip_tmp==0)
+                                                                               ip_tmp=str2ip6(&s_tmp);
+                                                                       if (ip_tmp){
+                                                                               $$=mk_elem(     $2, SNDIP_O, 0, NET_ST,
+                                                                                               mk_net_bitlen(ip_tmp, 
+                                                                                                               ip_tmp->len*8) );
+                                                                       }else{
+                                                                               $$=mk_elem(     $2, SNDIP_O, 0, STRING_ST,
+                                                                                               $3);
+                                                                       }
+                                                               }
+               | SNDIP strop host      {       onsend_check("snd_ip");
+                                                               $$=mk_elem(     $2, SNDIP_O, 0, STRING_ST, $3); }
+               | SNDIP equalop MYSELF  {       onsend_check("snd_ip");
+                                                                       $$=mk_elem(     $2, SNDIP_O, 0, MYSELF_ST, 0);
+                                                               }
+               | SNDIP strop error { $$=0; yyerror( "ip address or hostname"
+                                                "expected" ); }
+               | SNDIP error  { $$=0; 
+                                                yyerror("invalid operator, ==, != or =~ expected");}
+               | TOIP equalop ipnet    { onsend_check("to_ip");
+                                                                       $$=mk_elem($2, TOIP_O, 0, NET_ST, $3); }
+               | TOIP strop STRING     {       onsend_check("to_ip");
+                                                                       s_tmp.s=$3;
+                                                                       s_tmp.len=strlen($3);
+                                                                       ip_tmp=str2ip(&s_tmp);
+                                                                       if (ip_tmp==0)
+                                                                               ip_tmp=str2ip6(&s_tmp);
+                                                                       if (ip_tmp){
+                                                                               $$=mk_elem(     $2, TOIP_O, 0, NET_ST,
+                                                                                               mk_net_bitlen(ip_tmp, 
+                                                                                                               ip_tmp->len*8) );
+                                                                       }else{
+                                                                               $$=mk_elem(     $2, TOIP_O, 0, STRING_ST,
+                                                                                               $3);
+                                                                       }
+                                                               }
+               | TOIP strop host       {       onsend_check("to_ip");
+                                                               $$=mk_elem(     $2, TOIP_O, 0, STRING_ST, $3); }
+               | TOIP equalop MYSELF  {        onsend_check("to_ip");
+                                                                       $$=mk_elem(     $2, TOIP_O, 0, MYSELF_ST, 0);
+                                                               }
+               | TOIP strop error { $$=0; yyerror( "ip address or hostname"
+                                                "expected" ); }
+               | TOIP error  { $$=0; 
+                                                yyerror("invalid operator, ==, != or =~ expected");}
 
                | MYSELF equalop uri_type       { $$=mk_elem(   $2, $3, 0, MYSELF_ST,
                                                                                                       0);
@@ -1047,8 +1164,14 @@ exp_elem:        METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                | MYSELF equalop SRCIP  { $$=mk_elem(   $2, SRCIP_O, 0, MYSELF_ST,
                                                                                                0);
                                                                }
-                | MYSELF equalop DSTIP  { $$=mk_elem(  $2, DSTIP_O, 0, MYSELF_ST,
-                                                       0);
+               | MYSELF equalop DSTIP  { $$=mk_elem(   $2, DSTIP_O, 0, MYSELF_ST,
+                                                                                               0);
+                                                               }
+               | MYSELF equalop SNDIP  {       onsend_check("snd_ip");
+                                                                       $$=mk_elem(     $2, SNDIP_O, 0, MYSELF_ST, 0);
+                                                               }
+               | MYSELF equalop TOIP  {        onsend_check("to_ip");
+                                                                       $$=mk_elem(     $2, TOIP_O, 0, MYSELF_ST, 0);
                                                                }
                | MYSELF equalop error {        $$=0; 
                                                                        yyerror(" URI, SRCIP or DSTIP expected"); }
@@ -1058,11 +1181,11 @@ exp_elem:       METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                | exp_stm                       { $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
                | NUMBER                {$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); }
 
-               | attr_id               {$$=mk_elem( NO_OP, AVP_ST, (void*)$1, 0, 0); }
-               | attr_id strop STRING  {$$=mk_elem( $2, AVP_ST, (void*)$1, STRING_ST, $3); }
-               | attr_id intop NUMBER  {$$=mk_elem( $2, AVP_ST, (void*)$1, NUMBER_ST, (void*)$3); }
-               | attr_id binop NUMBER  {$$=mk_elem( $2, AVP_ST, (void*)$1, NUMBER_ST, (void*)$3); }
-                | attr_id strop attr_id {$$=mk_elem( $2, AVP_ST, (void*)$1, AVP_ST, (void*)$3); }
+               | attr_id               {$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
+               | attr_id strop STRING  {$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
+               | attr_id intop NUMBER  {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
+               | attr_id binop NUMBER  {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
+               | attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
 ;
 
 
@@ -1106,8 +1229,33 @@ host:    ID                              { $$=$1; }
        | host DOT error { $$=0; pkg_free($1); yyerror("invalid hostname"); }
        ;
 
+/* filtered cmd */
+fcmd:  cmd     { /* check if allowed */
+                               if (rt==ONSEND_ROUTE){
+                                       switch($1->type){
+                                               case DROP_T:
+                                               case SEND_T:
+                                               case SEND_TCP_T:
+                                               case LOG_T:
+                                               case SETFLAG_T:
+                                               case RESETFLAG_T:
+                                               case ISFLAGSET_T:
+                                               case IF_T:
+                                               case MODULE_T:
+                                                       $$=$1;
+                                                       break;
+                                               default:
+                                                       $$=0;
+                                                       yyerror("command not allowed in onsend_route\n");
+                                       }
+                               }else{
+                                       $$=$1;
+                               }
+                       }
+       ;
+
 
-exp_stm:       cmd                                             { $$=$1; }
+exp_stm:       fcmd                                            { $$=$1; }
                |       if_cmd                                  { $$=$1; }
                 |       assign_action { $$ = $1; }
                |       LBRACE actions RBRACE   { $$=$2; }
@@ -1122,11 +1270,11 @@ actions:        actions action  {$$=append_action($1, $2); }
                | actions error { $$=0; yyerror("bad command"); }
        ;
 
-action:                cmd SEMICOLON {$$=$1;}
+action:                fcmd SEMICOLON {$$=$1;}
                | if_cmd {$$=$1;}
                | assign_action SEMICOLON {$$=$1;}
                | SEMICOLON /* null action */ {$$=0;}
-               | cmd error { $$=0; yyerror("bad command: missing ';'?"); }
+               | fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
        ;
 
 if_cmd:                IF exp stm                              { $$=mk_action3( IF_T,
@@ -1197,7 +1345,7 @@ assign_op : ADDEQ { $$ = ADD_T; }
 
 assign_action:   attr_id assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); }
                | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
-               | attr_id assign_op cmd     { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
+               | attr_id assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
                | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
                | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
 ;
index da5ee64..0bac5fe 100644 (file)
--- a/config.h
+++ b/config.h
@@ -61,6 +61,7 @@
 #define FAILURE_RT_NO RT_NO /* on_failure routing tables number */
 #define ONREPLY_RT_NO RT_NO /* on_reply routing tables number */
 #define BRANCH_RT_NO RT_NO /* branch_route routing tables number */
+#define ONSEND_RT_NO 1  /* onsend_route routing tables number */
 #define DEFAULT_RT 0 /* default routing table */
 
 #define MAX_REC_LEV 100 /* maximum number of recursive calls */
index 38e786d..4ba8d7d 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -46,6 +46,8 @@
  *  2003-10-24  converted to the new socket_info lists (andrei)
  *  2004-10-10  modified check_self to use grep_sock_info (andrei)
  *  2004-11-08  added force_send_socket support in get_send_socket (andrei)
+ *  2005-12-11  onsend_router support; forward_request to no longer
+ *              pkg_malloc'ed (andrei)
  */
 
 
@@ -75,6 +77,7 @@
 #include "resolve.h"
 #include "name_alias.h"
 #include "socket_info.h"
+#include "onsend.h"
 
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
@@ -261,23 +264,14 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p, int proto)
 {
        unsigned int len;
        char* buf;
-       union sockaddr_union* to;
+       union sockaddr_union to;
        struct socket_info* send_sock;
        char md5[MD5_LEN];
        int id; /* used as branch for tcp! */
        
-       to=0;
        buf=0;
        id=0;
        
-       to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
-       if (to==0){
-               ser_error=E_OUT_OF_MEM;
-               LOG(L_ERR, "ERROR: forward_request: out of memory\n");
-               goto error;
-       }
-       
-       
        /* if error try next ip address if possible */
        if (p->ok==0){
                if (p->host.h_addr_list[p->addr_idx+1])
@@ -286,18 +280,18 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p, int proto)
                p->ok=1;
        }
        
-       hostent2su(to, &p->host, p->addr_idx, 
+       hostent2su(&to, &p->host, p->addr_idx, 
                                (p->port)?p->port:SIP_PORT);
        p->tx++;
        p->tx_bytes+=len;
        
 
-       send_sock=get_send_socket(msg, to, proto);
+       send_sock=get_send_socket(msg, &to, proto);
        if (send_sock==0){
                LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d "
-                               "no corresponding listening socket\n", to->s.sa_family, proto);
+                               "no corresponding listening socket\n", to.s.sa_family, proto);
                ser_error=E_NO_SOCKET;
-               goto error1;
+               goto error;
        }
 
        /* calculate branch for outbound request;  if syn_branch is turned off,
@@ -315,43 +309,45 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p, int proto)
        } else {
                if (!char_msg_val( msg, md5 ))  { /* parses transaction key */
                        LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
-                       goto error1;
+                       goto error;
                }
                msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number);
                if (!branch_builder( msg->hash_index, 0, md5, id /* 0-th branch */,
                                        msg->add_to_branch_s, &msg->add_to_branch_len )) {
                        LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n");
-                       goto error1;
+                       goto error;
                }
        }
 
        buf = build_req_buf_from_sip_req( msg, &len, send_sock,  proto);
        if (!buf){
                LOG(L_ERR, "ERROR: forward_request: building failed\n");
-               goto error1;
+               goto error;
        }
         /* send it! */
        DBG("Sending:\n%.*s.\n", (int)len, buf);
        DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, proto );
        
-       if (msg_send(send_sock, proto, to, 0, buf, len)<0){
+       if (run_onsend(msg, send_sock, proto, &to, buf, len)==0){
+               LOG(L_INFO, "forward_request: request dropped (onsend_route)\n");
+               STATS_TX_DROPS;
+               goto error; /* error ? */
+       }
+       if (msg_send(send_sock, proto, &to, 0, buf, len)<0){
                ser_error=E_SEND;
                p->errors++;
                p->ok=0;
                STATS_TX_DROPS;
-               goto error1;
+               goto error;
        }
        
        /* sent requests stats */
        STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
        
        pkg_free(buf);
-       pkg_free(to);
        /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/
        return 0;
 
-error1:
-       pkg_free(to);
 error:
        if (buf) pkg_free(buf);
        return -1;
index ea044a6..2b61f9a 100644 (file)
@@ -42,6 +42,8 @@
  *  2004-02-13  t->is_invite and t->local replaced with flags (bogdan)
  *  2005-02-16  fr_*_timer acceps full AVP specifications; empty AVP
  *              desable variable timer feature (bogdan)
+ *  2005-12-11  t_relay doesn't return 0 (stop script) on send error 
+ *              anymore (andrei)
  */
 
 #include <limits.h>
@@ -270,7 +272,7 @@ int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
                                script */
                                DBG("ERROR: generation of a stateful reply "
                                        "on error succeeded\n");
-                               ret=0;
+                               /*ret=0; -- we don't want to stop the script */
                        }  else {
                                DBG("ERROR: generation of a stateful reply "
                                        "on error failed\n");
index c444b71..649976f 100644 (file)
@@ -44,6 +44,7 @@
  *  2004-02-13: t->is_invite and t->local replaced with flags (bogdan)
  *  2005-08-04  msg->parsed_uri and parsed_uri_ok are no saved & restored
  *               before & after handling the branches (andrei)
+ *  2005-12-11  onsend_route support added for forwarding (andrei)
  */
 
 #include "defs.h"
@@ -60,6 +61,7 @@
 #include "../../dset.h"
 #include "../../action.h"
 #include "../../data_lump.h"
+#include "../../onsend.h"
 #include "t_funcs.h"
 #include "t_hooks.h"
 #include "t_msgbuilder.h"
@@ -551,6 +553,13 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
        success_branch=0;
        for (i=first_branch; i<t->nr_of_outgoings; i++) {
                if (added_branches & (1<<i)) {
+                       if (run_onsend(p_msg,   t->uac[i].request.dst.send_sock,
+                                                                       t->uac[i].request.dst.proto,
+                                                                       &t->uac[i].request.dst.to,
+                                                                       t->uac[i].request.buffer,
+                                                                       t->uac[i].request.buffer_len)==0)
+                               continue; /* if onsend drop, try next branch */
+                       
                        if (SEND_BUFFER( &t->uac[i].request)==-1) {
                                LOG(L_ERR, "ERROR: t_forward_nonack: sending request failed\n");
                                if (proxy) { proxy->errors++; proxy->ok=0; }
diff --git a/route.c b/route.c
index bd24e1b..7bcac23 100644 (file)
--- a/route.c
+++ b/route.c
@@ -66,6 +66,7 @@
 #include "parser/parse_from.h"
 #include "parser/parse_to.h"
 #include "mem/mem.h"
+#include "onsend.h"
 
 
 /* main routing script table  */
@@ -74,6 +75,7 @@ struct action* rlist[RT_NO];
 struct action* onreply_rlist[ONREPLY_RT_NO];
 struct action* failure_rlist[FAILURE_RT_NO];
 struct action* branch_rlist[BRANCH_RT_NO];
+struct action* onsend_rlist[ONSEND_RT_NO];
 
 static int fix_actions(struct action* a); /*fwd declaration*/
 
@@ -643,6 +645,8 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 {
        struct sip_uri uri;
        int ret;
+       struct onsend_info* snd_inf;
+       struct ip_addr ip;
        ret=E_BUG;
        
        if (e->type!=ELEM_T){
@@ -727,6 +731,25 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
        case DSTIP_O:
                ret=comp_ip(e->op, &msg->rcv.dst_ip, e->r_type, &e->r);
                break;
+       
+       case SNDIP_O:
+               snd_inf=get_onsend_info();
+               if (snd_inf && snd_inf->send_sock){
+                       ret=comp_ip(e->op, &snd_inf->send_sock->address, e->r_type, &e->r);
+               }else{
+                       BUG("eval_elem: snd_ip unknown (not in a onsend_route?)\n");
+               }
+               break;
+       
+       case TOIP_O:
+               snd_inf=get_onsend_info();
+               if (snd_inf && snd_inf->to){
+                       su2ip_addr(&ip, snd_inf->to);
+                       ret=comp_ip(e->op, &ip, e->r_type, &e->r);
+               }else{
+                       BUG("eval_elem: to_ip unknown (not in a onsend_route?)\n");
+               }
+               break;
 
        case NUMBER_O:
                ret=!(!e->r.intval); /* !! to transform it in {0,1} */
@@ -748,22 +771,67 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
                             e->r_type, &e->r);
                break;
                
+       case SNDPORT_O:
+               snd_inf=get_onsend_info();
+               if (snd_inf && snd_inf->send_sock){
+                       ret=comp_num(e->op, (int)snd_inf->send_sock->port_no, 
+                                    e->r_type, &e->r);
+               }else{
+                       BUG("eval_elem: snd_port unknown (not in a onsend_route?)\n");
+               }
+               break;
+               
+       case TOPORT_O:
+               snd_inf=get_onsend_info();
+               if (snd_inf && snd_inf->to){
+                       ret=comp_num(e->op, (int)su_getport(snd_inf->to), 
+                                    e->r_type, &e->r);
+               }else{
+                       BUG("eval_elem: to_port unknown (not in a onsend_route?)\n");
+               }
+               break;
+               
        case PROTO_O:
                ret=comp_num(e->op, msg->rcv.proto, 
                             e->r_type, &e->r);
                break;
                
+       case SNDPROTO_O:
+               snd_inf=get_onsend_info();
+               if (snd_inf && snd_inf->send_sock){
+                       ret=comp_num(e->op, snd_inf->send_sock->proto, 
+                                    e->r_type, &e->r);
+               }else{
+                       BUG("eval_elem: snd_proto unknown (not in a onsend_route?)\n");
+               }
+               break;
+               
        case AF_O:
                ret=comp_num(e->op, (int)msg->rcv.src_ip.af, 
                             e->r_type, &e->r);
                break;
+               
+       case SNDAF_O:
+               snd_inf=get_onsend_info();
+               if (snd_inf && snd_inf->send_sock){
+                       ret=comp_num(e->op, snd_inf->send_sock->address.af,
+                                                       e->r_type, &e->r);
+               }else{
+                       BUG("eval_elem: snd_af unknown (not in a onsend_route?)\n");
+               }
+               break;
 
        case MSGLEN_O:
-               ret=comp_num(e->op, (int)msg->len, 
-                               e->r_type, &e->r);
+               if ((snd_inf=get_onsend_info())!=0){
+                       ret=comp_num(e->op, (int)snd_inf->len, 
+                                       e->r_type, &e->r);
+               }else{
+                       ret=comp_num(e->op, (int)msg->len, 
+                                       e->r_type, &e->r);
+               }
                break;
 
-       case AVP_ST:
+       case AVP_O:
                ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
                break;
                
@@ -891,6 +959,13 @@ int fix_rls()
                        }
                }
        }
+       for(i=0;i<ONSEND_RT_NO;i++){
+               if(onsend_rlist[i]){
+                       if ((ret=fix_actions(onsend_rlist[i]))!=0){
+                               return ret;
+                       }
+               }
+       }
        return 0;
 }
 
diff --git a/route.h b/route.h
index a22f1af..dded8c5 100644 (file)
--- a/route.h
+++ b/route.h
 /* main "script table" */
 extern struct action* rlist[RT_NO];
 /* main reply route table */
-extern struct action* onreply_rlist[RT_NO];
-extern struct action* failure_rlist[RT_NO];
-extern struct action* branch_rlist[RT_NO];
+extern struct action* onreply_rlist[ONREPLY_RT_NO];
+extern struct action* failure_rlist[FAILURE_RT_NO];
+extern struct action* branch_rlist[BRANCH_RT_NO];
+extern struct action* onsend_rlist[ONSEND_RT_NO];
 
 
 void push(struct action* a, struct action** head);
index 455298c..5b52e57 100644 (file)
@@ -33,6 +33,7 @@
  *  2003-10-10  >,<,>=,<=, != and MSGLEN_O added (andrei)
  *  2003-10-28  FORCE_TCP_ALIAS added (andrei)
  *  2004-02-24  added LOAD_AVP_T and AVP_TO_URI_T (bogdan)
+ *  2005-12-11  added SND{IP,PORT,PROTO,AF}_O & TO{IP,PORT}_O (andrei)
  */
 
 
@@ -60,7 +61,8 @@ enum { LOGAND_OP=1, LOGOR_OP, NOT_OP, BINAND_OP, BINOR_OP };
 enum { EQUAL_OP=10, MATCH_OP, GT_OP, LT_OP, GTE_OP, LTE_OP, DIFF_OP, NO_OP };
 enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
           DSTIP_O, DSTPORT_O, PROTO_O, AF_O, MSGLEN_O, DEFAULT_O, ACTION_O,
-          NUMBER_O, AVP_O};
+          NUMBER_O, AVP_O, SNDIP_O, SNDPORT_O, TOIP_O, TOPORT_O, SNDPROTO_O, 
+          SNDAF_O};
 
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
                SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, 
index 3e5e51a..8d92d62 100644 (file)
@@ -70,6 +70,7 @@ typedef int (*param_func_t)( modparam_t type, void* val);
 #define FAILURE_ROUTE 2  /* Function can be used in reply route blocks */
 #define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
 #define BRANCH_ROUTE  8  /* Function can be used in branch_route blocks */
+#define ONSEND_ROUTE   16  /* Function can be used in onsend_route blocks */
 
 /* Macros - used as rank in child_init function */
 #define PROC_MAIN      0  /* Main ser process */