Просмотр исходного кода

- 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 лет назад
Родитель
Сommit
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
 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]")

+ 55 - 22
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
 =============================

+ 15 - 6
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");

+ 16 - 0
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; }

+ 161 - 13
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)
  *
  */
 
@@ -103,6 +105,10 @@
  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); }
 ;

+ 1 - 0
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 */

+ 18 - 22
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;

+ 3 - 1
modules/tm/t_funcs.c

@@ -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");

+ 9 - 0
modules/tm/t_fwd.c

@@ -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; }

+ 78 - 3
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;
 }
 

+ 4 - 3
route.h

@@ -44,9 +44,10 @@
 /* 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);

+ 3 - 1
route_struct.h

@@ -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, 

+ 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 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 */