Переглянути джерело

- tm: t_relay will not stop script execution anymore in case of send error
- 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;
}

Andrei Pelinescu-Onciul 20 роки тому
батько
коміт
0d88ce78c9
13 змінених файлів з 365 додано та 72 видалено
  1. 1 1
      Makefile.defs
  2. 55 22
      NEWS
  3. 15 6
      action.c
  4. 16 0
      cfg.lex
  5. 161 13
      cfg.y
  6. 1 0
      config.h
  7. 18 22
      forward.c
  8. 3 1
      modules/tm/t_funcs.c
  9. 9 0
      modules/tm/t_fwd.c
  10. 78 3
      route.c
  11. 4 3
      route.h
  12. 3 1
      route_struct.h
  13. 1 0
      sr_module.h

+ 1 - 1
Makefile.defs

@@ -61,7 +61,7 @@ MAIN_NAME=ser
 VERSION = 0
 VERSION = 0
 PATCHLEVEL = 10
 PATCHLEVEL = 10
 SUBLEVEL =   99
 SUBLEVEL =   99
-EXTRAVERSION = -dev27-tm-timers
+EXTRAVERSION = -dev28-tm-timers
 
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")

+ 55 - 22
NEWS

@@ -34,8 +34,41 @@ modules:
                          changing the transaction timer from script, even if
                          changing the transaction timer from script, even if
                          the transaction was already created (see tm docs for
                          the transaction was already created (see tm docs for
                          more).
                          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:
 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 
  - timer: - improved performance/precision, new api, see doc/timers.txt 
  - tcp: - improved  performance (io event handling), using OS specific
  - tcp: - improved  performance (io event handling), using OS specific
            optimizations
            optimizations
@@ -368,33 +401,33 @@ actual workload (malloc is a little bit faster now)
 New features
 New features
 =============
 =============
 - RFC3261 support
 - 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
 - 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
 - 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]
       as environment variables to scripts) [exec module]
 - Architectural Improvements
 - 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)
 - 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
 Changes to use of ser scripts
 =============================
 =============================

+ 15 - 6
action.c

@@ -57,6 +57,7 @@
 #include "mem/mem.h"
 #include "mem/mem.h"
 #include "globals.h"
 #include "globals.h"
 #include "dset.h"
 #include "dset.h"
+#include "onsend.h"
 #ifdef USE_TCP
 #ifdef USE_TCP
 #include "tcp_server.h"
 #include "tcp_server.h"
 #endif
 #endif
@@ -74,6 +75,8 @@
 #endif
 #endif
 
 
 
 
+struct onsend_info* p_onsend=0; /* onsend route send info */
+
 /* ret= 0! if action -> end of list(e.g DROP), 
 /* ret= 0! if action -> end of list(e.g DROP), 
       > 0 to continue processing next actions
       > 0 to continue processing next actions
    and <0 on error */
    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,
 			ret=hostent2su(	to, &p->host, p->addr_idx,
 						(p->port)?p->port:SIP_PORT );
 						(p->port)?p->port:SIP_PORT );
 			if (ret==0){
 			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++;
-				p->tx_bytes+=msg->len;
+				p->tx_bytes+=len;
 				if (a->type==SEND_T){
 				if (a->type==SEND_T){
 					/*udp*/
 					/*udp*/
 					send_sock=get_send_socket(msg, to, PROTO_UDP);
 					send_sock=get_send_socket(msg, to, PROTO_UDP);
 					if (send_sock!=0){
 					if (send_sock!=0){
-						ret=udp_send(send_sock, msg->buf, msg->len, to);
+						ret=udp_send(send_sock, tmp, len, to);
 					}else{
 					}else{
 						ret=-1;
 						ret=-1;
 					}
 					}
@@ -255,7 +265,7 @@ int do_action(struct action* a, struct sip_msg* msg)
 #ifdef USE_TCP
 #ifdef USE_TCP
 					else{
 					else{
 					/*tcp*/
 					/*tcp*/
-					ret=tcp_send(PROTO_TCP, msg->buf, msg->len, to, 0);
+					ret=tcp_send(PROTO_TCP, tmp, len, to, 0);
 				}
 				}
 #endif
 #endif
 			}
 			}
@@ -743,9 +753,8 @@ int do_action(struct action* a, struct sip_msg* msg)
 				break;
 				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 ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
 			if (add_avp(flags, name, value) < 0) {
 			if (add_avp(flags, name, value) < 0) {
 				LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
 				LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");

+ 16 - 0
cfg.lex

@@ -56,6 +56,8 @@
  *               tcp_max_connections (andrei)
  *               tcp_max_connections (andrei)
  *  2005-07-11  added dns_retr_{time,no}, dns_servers_no, dns_use_search_list,
  *  2005-07-11  added dns_retr_{time,no}, dns_servers_no, dns_use_search_list,
  *              dns_try_ipv6 (andrei)
  *              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_FAILURE failure_route
 ROUTE_ONREPLY onreply_route
 ROUTE_ONREPLY onreply_route
 ROUTE_BRANCH branch_route
 ROUTE_BRANCH branch_route
+ROUTE_SEND onsend_route
 EXEC	exec
 EXEC	exec
 FORCE_RPORT		"force_rport"|"add_rport"
 FORCE_RPORT		"force_rport"|"add_rport"
 FORCE_TCP_ALIAS		"force_tcp_alias"|"add_tcp_alias"
 FORCE_TCP_ALIAS		"force_tcp_alias"|"add_tcp_alias"
@@ -158,6 +161,12 @@ SRCIP	src_ip
 SRCPORT	src_port
 SRCPORT	src_port
 DSTIP	dst_ip
 DSTIP	dst_ip
 DSTPORT	dst_port
 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
 PROTO	proto
 AF		af
 AF		af
 MYSELF	myself
 MYSELF	myself
@@ -328,6 +337,7 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{ROUTE_FAILURE}	{ count(); yylval.strval=yytext;
 <INITIAL>{ROUTE_FAILURE}	{ count(); yylval.strval=yytext;
 								return ROUTE_FAILURE; }
 								return ROUTE_FAILURE; }
 <INITIAL>{ROUTE_BRANCH} { count(); yylval.strval=yytext; return ROUTE_BRANCH; }
 <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>{EXEC}	{ count(); yylval.strval=yytext; return EXEC; }
 <INITIAL>{SET_HOST}	{ count(); yylval.strval=yytext; return SET_HOST; }
 <INITIAL>{SET_HOST}	{ count(); yylval.strval=yytext; return SET_HOST; }
 <INITIAL>{SET_HOSTPORT}	{ count(); yylval.strval=yytext; return SET_HOSTPORT; }
 <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>{SRCPORT}	{ count(); yylval.strval=yytext; return SRCPORT; }
 <INITIAL>{DSTIP}	{ count(); yylval.strval=yytext; return DSTIP; }
 <INITIAL>{DSTIP}	{ count(); yylval.strval=yytext; return DSTIP; }
 <INITIAL>{DSTPORT}	{ count(); yylval.strval=yytext; return DSTPORT; }
 <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>{PROTO}	{ count(); yylval.strval=yytext; return PROTO; }
 <INITIAL>{AF}	{ count(); yylval.strval=yytext; return AF; }
 <INITIAL>{AF}	{ count(); yylval.strval=yytext; return AF; }
 <INITIAL>{MYSELF}	{ count(); yylval.strval=yytext; return MYSELF; }
 <INITIAL>{MYSELF}	{ count(); yylval.strval=yytext; return MYSELF; }

+ 161 - 13
cfg.y

@@ -64,6 +64,8 @@
  *             DNS_TRY_IPV6 (andrei)
  *             DNS_TRY_IPV6 (andrei)
  * 2005-07-12  default onreply route added (andrei)
  * 2005-07-12  default onreply route added (andrei)
  * 2005-11-16  fixed if (cond) cmd; (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)
  *
  *
  */
  */
 
 
@@ -103,6 +105,10 @@
  with no built in alloca, like icc*/
  with no built in alloca, like icc*/
 #undef _ALLOCA_H
 #undef _ALLOCA_H
 
 
+#define onsend_check(s) \
+	do{\
+		if (rt!=ONSEND_ROUTE) yyerror( s " allowed only in onsend_routes");\
+	}while(0)
 
 
 extern int yylex();
 extern int yylex();
 static void yyerror(char* s);
 static void yyerror(char* s);
@@ -150,6 +156,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token ROUTE_FAILURE
 %token ROUTE_FAILURE
 %token ROUTE_ONREPLY
 %token ROUTE_ONREPLY
 %token ROUTE_BRANCH
 %token ROUTE_BRANCH
+%token ROUTE_SEND
 %token EXEC
 %token EXEC
 %token SET_HOST
 %token SET_HOST
 %token SET_HOSTPORT
 %token SET_HOSTPORT
@@ -183,6 +190,12 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token SRCPORT
 %token SRCPORT
 %token DSTIP
 %token DSTIP
 %token DSTPORT
 %token DSTPORT
+%token TOIP
+%token TOPORT
+%token SNDIP
+%token SNDPORT
+%token SNDPROTO
+%token SNDAF
 %token PROTO
 %token PROTO
 %token AF
 %token AF
 %token MYSELF
 %token MYSELF
@@ -310,7 +323,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 
 
 /*non-terminals */
 /*non-terminals */
 %type <expr> exp exp_elem /*, condition*/
 %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 <ipaddr> ipv4 ipv6 ipv6addr ip
 %type <ipnet> ipnet
 %type <ipnet> ipnet
 %type <strval> host
 %type <strval> host
@@ -347,6 +360,7 @@ statement:	assign_stm
 		| {rt=FAILURE_ROUTE;} failure_route_stm
 		| {rt=FAILURE_ROUTE;} failure_route_stm
 		| {rt=ONREPLY_ROUTE;} onreply_route_stm
 		| {rt=ONREPLY_ROUTE;} onreply_route_stm
 		| {rt=BRANCH_ROUTE;} branch_route_stm
 		| {rt=BRANCH_ROUTE;} branch_route_stm
+		| {rt=ONSEND_ROUTE;}   send_route_stm
 		| CR	/* null statement*/
 		| CR	/* null statement*/
 	;
 	;
 
 
@@ -896,6 +910,19 @@ branch_route_stm: ROUTE_BRANCH LBRACE actions RBRACE {
 										}
 										}
 		| ROUTE_BRANCH error { yyerror("invalid branch_route statement"); }
 		| 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; }
 rules:	rules rule { push($2, &$1); $$=$1; }
 	| rule {$$=$1; }
 	| rule {$$=$1; }
@@ -963,7 +990,7 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
 									" == , != or =~ expected");
 									" == , != or =~ expected");
 					}
 					}
 		| SRCPORT intop NUMBER	{ $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); }
 		| 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 intop error { $$=0; yyerror("number expected"); }
 		| SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  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 intop error { $$=0; yyerror("number expected"); }
 		| DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  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 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 attr_id	{ $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
 		| PROTO intop error { $$=0;
 		| 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"); }
 		| 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 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 attr_id	{ $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
 		| AF intop error { $$=0; yyerror("number expected"); }
 		| AF intop error { $$=0; yyerror("number expected"); }
 		| AF error { $$=0; yyerror("equal/!= operator 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 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 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); }
 		| 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" ); }
 						 			"expected" ); }
 		| DSTIP error { $$=0; 
 		| DSTIP error { $$=0; 
 						yyerror("invalid operator, ==, != or =~ expected");}
 						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,
 		| MYSELF equalop uri_type	{ $$=mk_elem(	$2, $3, 0, MYSELF_ST,
 												       0);
 												       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,
 		| MYSELF equalop SRCIP  { $$=mk_elem(	$2, SRCIP_O, 0, MYSELF_ST,
 												0);
 												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; 
 		| MYSELF equalop error {	$$=0; 
 									yyerror(" URI, SRCIP or DSTIP expected"); }
 									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);  }
 		| exp_stm			{ $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
 		| NUMBER		{$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$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"); }
 	| 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; }
 		|	if_cmd					{ $$=$1; }
                 |       assign_action { $$ = $1; }
                 |       assign_action { $$ = $1; }
 		|	LBRACE actions RBRACE	{ $$=$2; }
 		|	LBRACE actions RBRACE	{ $$=$2; }
@@ -1122,11 +1270,11 @@ actions:	actions action	{$$=append_action($1, $2); }
 		| actions error { $$=0; yyerror("bad command"); }
 		| actions error { $$=0; yyerror("bad command"); }
 	;
 	;
 
 
-action:		cmd SEMICOLON {$$=$1;}
+action:		fcmd SEMICOLON {$$=$1;}
 		| if_cmd {$$=$1;}
 		| if_cmd {$$=$1;}
 		| assign_action SEMICOLON {$$=$1;}
 		| assign_action SEMICOLON {$$=$1;}
 		| SEMICOLON /* null action */ {$$=0;}
 		| 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,
 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); }
 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 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 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); }
                | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
 ;
 ;

+ 1 - 0
config.h

@@ -61,6 +61,7 @@
 #define FAILURE_RT_NO RT_NO /* on_failure routing tables number */
 #define FAILURE_RT_NO RT_NO /* on_failure routing tables number */
 #define ONREPLY_RT_NO RT_NO /* on_reply 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 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 DEFAULT_RT 0 /* default routing table */
 
 
 #define MAX_REC_LEV 100 /* maximum number of recursive calls */
 #define MAX_REC_LEV 100 /* maximum number of recursive calls */

+ 18 - 22
forward.c

@@ -46,6 +46,8 @@
  *  2003-10-24  converted to the new socket_info lists (andrei)
  *  2003-10-24  converted to the new socket_info lists (andrei)
  *  2004-10-10  modified check_self to use grep_sock_info (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)
  *  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 "resolve.h"
 #include "name_alias.h"
 #include "name_alias.h"
 #include "socket_info.h"
 #include "socket_info.h"
+#include "onsend.h"
 
 
 #ifdef DEBUG_DMALLOC
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #include <dmalloc.h>
@@ -261,23 +264,14 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p, int proto)
 {
 {
 	unsigned int len;
 	unsigned int len;
 	char* buf;
 	char* buf;
-	union sockaddr_union* to;
+	union sockaddr_union to;
 	struct socket_info* send_sock;
 	struct socket_info* send_sock;
 	char md5[MD5_LEN];
 	char md5[MD5_LEN];
 	int id; /* used as branch for tcp! */
 	int id; /* used as branch for tcp! */
 	
 	
-	to=0;
 	buf=0;
 	buf=0;
 	id=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 error try next ip address if possible */
 	if (p->ok==0){
 	if (p->ok==0){
 		if (p->host.h_addr_list[p->addr_idx+1])
 		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;
 		p->ok=1;
 	}
 	}
 	
 	
-	hostent2su(to, &p->host, p->addr_idx, 
+	hostent2su(&to, &p->host, p->addr_idx, 
 				(p->port)?p->port:SIP_PORT);
 				(p->port)?p->port:SIP_PORT);
 	p->tx++;
 	p->tx++;
 	p->tx_bytes+=len;
 	p->tx_bytes+=len;
 	
 	
 
 
-	send_sock=get_send_socket(msg, to, proto);
+	send_sock=get_send_socket(msg, &to, proto);
 	if (send_sock==0){
 	if (send_sock==0){
 		LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d "
 		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;
 		ser_error=E_NO_SOCKET;
-		goto error1;
+		goto error;
 	}
 	}
 
 
 	/* calculate branch for outbound request;  if syn_branch is turned off,
 	/* 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 {
 	} else {
 		if (!char_msg_val( msg, md5 )) 	{ /* parses transaction key */
 		if (!char_msg_val( msg, md5 )) 	{ /* parses transaction key */
 			LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
 			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);
 		msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number);
 		if (!branch_builder( msg->hash_index, 0, md5, id /* 0-th branch */,
 		if (!branch_builder( msg->hash_index, 0, md5, id /* 0-th branch */,
 					msg->add_to_branch_s, &msg->add_to_branch_len )) {
 					msg->add_to_branch_s, &msg->add_to_branch_len )) {
 			LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n");
 			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);
 	buf = build_req_buf_from_sip_req( msg, &len, send_sock,  proto);
 	if (!buf){
 	if (!buf){
 		LOG(L_ERR, "ERROR: forward_request: building failed\n");
 		LOG(L_ERR, "ERROR: forward_request: building failed\n");
-		goto error1;
+		goto error;
 	}
 	}
 	 /* send it! */
 	 /* send it! */
 	DBG("Sending:\n%.*s.\n", (int)len, buf);
 	DBG("Sending:\n%.*s.\n", (int)len, buf);
 	DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, proto );
 	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;
 		ser_error=E_SEND;
 		p->errors++;
 		p->errors++;
 		p->ok=0;
 		p->ok=0;
 		STATS_TX_DROPS;
 		STATS_TX_DROPS;
-		goto error1;
+		goto error;
 	}
 	}
 	
 	
 	/* sent requests stats */
 	/* sent requests stats */
 	STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
 	STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
 	
 	
 	pkg_free(buf);
 	pkg_free(buf);
-	pkg_free(to);
 	/* received_buf & line_buf will be freed in receive_msg by free_lump_list*/
 	/* received_buf & line_buf will be freed in receive_msg by free_lump_list*/
 	return 0;
 	return 0;
 
 
-error1:
-	pkg_free(to);
 error:
 error:
 	if (buf) pkg_free(buf);
 	if (buf) pkg_free(buf);
 	return -1;
 	return -1;

+ 3 - 1
modules/tm/t_funcs.c

@@ -42,6 +42,8 @@
  *  2004-02-13  t->is_invite and t->local replaced with flags (bogdan)
  *  2004-02-13  t->is_invite and t->local replaced with flags (bogdan)
  *  2005-02-16  fr_*_timer acceps full AVP specifications; empty AVP
  *  2005-02-16  fr_*_timer acceps full AVP specifications; empty AVP
  *              desable variable timer feature (bogdan)
  *              desable variable timer feature (bogdan)
+ *  2005-12-11  t_relay doesn't return 0 (stop script) on send error 
+ *              anymore (andrei)
  */
  */
 
 
 #include <limits.h>
 #include <limits.h>
@@ -270,7 +272,7 @@ int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
 			  	script */
 			  	script */
 				DBG("ERROR: generation of a stateful reply "
 				DBG("ERROR: generation of a stateful reply "
 					"on error succeeded\n");
 					"on error succeeded\n");
-				ret=0;
+				/*ret=0; -- we don't want to stop the script */
 			}  else {
 			}  else {
 				DBG("ERROR: generation of a stateful reply "
 				DBG("ERROR: generation of a stateful reply "
 					"on error failed\n");
 					"on error failed\n");

+ 9 - 0
modules/tm/t_fwd.c

@@ -44,6 +44,7 @@
  *  2004-02-13: t->is_invite and t->local replaced with flags (bogdan)
  *  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
  *  2005-08-04  msg->parsed_uri and parsed_uri_ok are no saved & restored
  *               before & after handling the branches (andrei)
  *               before & after handling the branches (andrei)
+ *  2005-12-11  onsend_route support added for forwarding (andrei)
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -60,6 +61,7 @@
 #include "../../dset.h"
 #include "../../dset.h"
 #include "../../action.h"
 #include "../../action.h"
 #include "../../data_lump.h"
 #include "../../data_lump.h"
+#include "../../onsend.h"
 #include "t_funcs.h"
 #include "t_funcs.h"
 #include "t_hooks.h"
 #include "t_hooks.h"
 #include "t_msgbuilder.h"
 #include "t_msgbuilder.h"
@@ -551,6 +553,13 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	success_branch=0;
 	success_branch=0;
 	for (i=first_branch; i<t->nr_of_outgoings; i++) {
 	for (i=first_branch; i<t->nr_of_outgoings; i++) {
 		if (added_branches & (1<<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) {
 			if (SEND_BUFFER( &t->uac[i].request)==-1) {
 				LOG(L_ERR, "ERROR: t_forward_nonack: sending request failed\n");
 				LOG(L_ERR, "ERROR: t_forward_nonack: sending request failed\n");
 				if (proxy) { proxy->errors++; proxy->ok=0; }
 				if (proxy) { proxy->errors++; proxy->ok=0; }

+ 78 - 3
route.c

@@ -66,6 +66,7 @@
 #include "parser/parse_from.h"
 #include "parser/parse_from.h"
 #include "parser/parse_to.h"
 #include "parser/parse_to.h"
 #include "mem/mem.h"
 #include "mem/mem.h"
+#include "onsend.h"
 
 
 
 
 /* main routing script table  */
 /* main routing script table  */
@@ -74,6 +75,7 @@ struct action* rlist[RT_NO];
 struct action* onreply_rlist[ONREPLY_RT_NO];
 struct action* onreply_rlist[ONREPLY_RT_NO];
 struct action* failure_rlist[FAILURE_RT_NO];
 struct action* failure_rlist[FAILURE_RT_NO];
 struct action* branch_rlist[BRANCH_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*/
 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;
 	struct sip_uri uri;
 	int ret;
 	int ret;
+	struct onsend_info* snd_inf;
+	struct ip_addr ip;
 	ret=E_BUG;
 	ret=E_BUG;
 	
 	
 	if (e->type!=ELEM_T){
 	if (e->type!=ELEM_T){
@@ -727,6 +731,25 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 	case DSTIP_O:
 	case DSTIP_O:
 		ret=comp_ip(e->op, &msg->rcv.dst_ip, e->r_type, &e->r);
 		ret=comp_ip(e->op, &msg->rcv.dst_ip, e->r_type, &e->r);
 		break;
 		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:
 	case NUMBER_O:
 		ret=!(!e->r.intval); /* !! to transform it in {0,1} */
 		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);
 			     e->r_type, &e->r);
 		break;
 		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:
 	case PROTO_O:
 		ret=comp_num(e->op, msg->rcv.proto, 
 		ret=comp_num(e->op, msg->rcv.proto, 
 			     e->r_type, &e->r);
 			     e->r_type, &e->r);
 		break;
 		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:
 	case AF_O:
 		ret=comp_num(e->op, (int)msg->rcv.src_ip.af, 
 		ret=comp_num(e->op, (int)msg->rcv.src_ip.af, 
 			     e->r_type, &e->r);
 			     e->r_type, &e->r);
 		break;
 		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:
 	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;
 		break;
 
 
-	case AVP_ST:
+	case AVP_O:
 		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
 		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
 		break;
 		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;
 	return 0;
 }
 }
 
 

+ 4 - 3
route.h

@@ -44,9 +44,10 @@
 /* main "script table" */
 /* main "script table" */
 extern struct action* rlist[RT_NO];
 extern struct action* rlist[RT_NO];
 /* main reply route table */
 /* 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);
 void push(struct action* a, struct action** head);

+ 3 - 1
route_struct.h

@@ -33,6 +33,7 @@
  *  2003-10-10  >,<,>=,<=, != and MSGLEN_O added (andrei)
  *  2003-10-10  >,<,>=,<=, != and MSGLEN_O added (andrei)
  *  2003-10-28  FORCE_TCP_ALIAS added (andrei)
  *  2003-10-28  FORCE_TCP_ALIAS added (andrei)
  *  2004-02-24  added LOAD_AVP_T and AVP_TO_URI_T (bogdan)
  *  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 { 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,
 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,
 	   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,
 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, 
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, 

+ 1 - 0
sr_module.h

@@ -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 FAILURE_ROUTE 2  /* Function can be used in reply route blocks */
 #define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
 #define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
 #define BRANCH_ROUTE  8  /* Function can be used in branch_route blocks */
 #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 */
 /* Macros - used as rank in child_init function */
 #define PROC_MAIN      0  /* Main ser process */
 #define PROC_MAIN      0  /* Main ser process */