Browse code

- new tm param. unmatched_cancel that selects how a cancel for which no matching invite is found will be treated: forward it in stateful mode and thus remember it (for some time) so that if the invite arrives out of order tm will know it's already canceled (0 - default), forward it in stateless mode (1) or just drop it (2).

Andrei Pelinescu-Onciul authored on 02/05/2007 16:57:07
Showing 5 changed files
... ...
@@ -9,6 +9,22 @@ $Id$
9 9
 modules:
10 10
  - tm        - new onsend callbacks support (require defining TMCB_ONSEND prior
11 11
                to compiling tm)
12
+             - behaviour when receiving a CANCEL which doesn't match any 
13
+               transaction can be selected using the unmatched_cancel param.
14
+             - params: 
15
+                        - unmatched_cancel - selects between forwarding cancels
16
+                           that do not match any transaction statefully (0, 
17
+                           default value), statelessly (1) or dropping them
18
+                           (2). Note that the statefull forwarding has an 
19
+                           additional hidden advantage: tm will be able to
20
+                           recognize INVITEs that arrive after their CANCEL.
21
+                           Note also that this feature could be used to try
22
+                           a memory exhaustion DOS attack against a proxy that
23
+                           authenticates all requests, by continuously flooding
24
+                           the victim with CANCELs to random destinations 
25
+                           (since the CANCEL cannot be authenticated, each
26
+                           received bogus CANCEL will create a new transaction 
27
+                           that will live by default 30s).
12 28
 
13 29
 
14 30
 2.0.0 changes
... ...
@@ -47,6 +47,7 @@
47 47
  *  2006-08-11  updated forward_request usage (andrei)
48 48
  *              t_relay_to releases the transaction if t_forward_non_ack
49 49
  *              fails and t_kill fails or this is a failed replication (andrei)
50
+ *  2007-05-02  t_relay_to() uses now t_forward_cancel for cancels (andrei)
50 51
  */
51 52
 
52 53
 #include <limits.h>
... ...
@@ -215,6 +216,12 @@ int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
215 215
 
216 216
 	ret=0;
217 217
 	
218
+	/* special case for CANCEL */
219
+	if ( p_msg->REQ_METHOD==METHOD_CANCEL){
220
+		ret=t_forward_cancel(p_msg, proxy, proto, &t);
221
+		if (t) goto handle_ret;
222
+		goto done;
223
+	}
218 224
 	new_tran = t_newtran( p_msg );
219 225
 	
220 226
 	/* parsing error, memory alloc, whatever ... if via is bad
... ...
@@ -283,6 +290,7 @@ int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
283 283
 
284 284
 	/* now go ahead and forward ... */
285 285
 	ret=t_forward_nonack(t, p_msg, proxy, proto);
286
+handle_ret:
286 287
 	if (ret<=0) {
287 288
 		DBG( "ERROR:tm:t_relay_to:  t_forward_nonack returned error \n");
288 289
 		/* we don't want to pass upstream any reply regarding replicating
... ...
@@ -64,6 +64,7 @@
64 64
  *  2006-11-20  new_uri is no longer saved/restore across add_uac calls, since
65 65
  *              print_uac_request is now uri safe (andrei)
66 66
  * 2007-03-15  TMCB_ONSEND hooks added (andrei)
67
+ * 2007-05-02  added t_forward_cancel(unmatched_cancel) (andrei)
67 68
  */
68 69
 
69 70
 #include "defs.h"
... ...
@@ -98,6 +99,7 @@
98 98
 #endif
99 99
 
100 100
 
101
+int unmatched_cancel=UM_CANCEL_STATEFULL;
101 102
 
102 103
 static int goto_on_branch = 0, branch_route = 0;
103 104
 
... ...
@@ -726,13 +728,13 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
726 726
 	int lock_replies;
727 727
 	str dst_uri;
728 728
 	struct socket_info* si, *backup_si;
729
+	
729 730
 
730 731
 	/* make -Wall happy */
731 732
 	current_uri.s=0;
732 733
 
733 734
 	set_kr(REQ_FWDED);
734
-
735
-	if (p_msg->REQ_METHOD==METHOD_CANCEL) {
735
+	if (p_msg->REQ_METHOD==METHOD_CANCEL) { 
736 736
 		t_invite=t_lookupOriginalT(  p_msg );
737 737
 		if (t_invite!=T_NULL_CELL) {
738 738
 			e2e_cancel( p_msg, t, t_invite );
... ...
@@ -835,6 +837,107 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
835 835
 
836 836
 
837 837
 
838
+/* cancel handling/forwarding function
839
+ * CANCELs with no matching transaction are handled in function of
840
+ * the unmatched_cancel config var: they are either forwarded statefully,
841
+ * statelessly or dropped.
842
+ * function returns:
843
+ *       1 - forward successful
844
+ *       0 - error, but do not reply 
845
+ *      <0 - error during forward
846
+ * it also sets *tran if a transaction was created
847
+ */
848
+int t_forward_cancel(struct sip_msg* p_msg , struct proxy_l * proxy, int proto,
849
+						struct cell** tran)
850
+{
851
+	struct cell* t_invite;
852
+	struct cell* t;
853
+	int ret;
854
+	int new_tran;
855
+	struct dest_info dst;
856
+	str host;
857
+	unsigned short port;
858
+	short comp;
859
+	
860
+	t=0;
861
+	/* handle cancels for which no transaction was created yet */
862
+	if (unmatched_cancel==UM_CANCEL_STATEFULL){
863
+		/* create cancel transaction */
864
+		new_tran=t_newtran(p_msg);
865
+		if (new_tran<=0 && new_tran!=E_SCRIPT){
866
+			if (new_tran==0)
867
+				 /* retransmission => do nothing */
868
+				ret=1;
869
+			else
870
+				/* some error => return it or DROP */
871
+				ret=(ser_error==E_BAD_VIA && reply_to_via) ? 0: new_tran;
872
+			goto end;
873
+		}
874
+		t=get_t();
875
+		ret=t_forward_nonack(t, p_msg, proxy, proto);
876
+		goto end;
877
+	}
878
+	
879
+	t_invite=t_lookupOriginalT(  p_msg );
880
+	if (t_invite!=T_NULL_CELL) {
881
+		/* create cancel transaction */
882
+		new_tran=t_newtran(p_msg);
883
+		if (new_tran<=0 && new_tran!=E_SCRIPT){
884
+			if (new_tran==0)
885
+				 /* retransmission => do nothing */
886
+				ret=1;
887
+			else
888
+				/* some error => return it or DROP */
889
+				ret=(ser_error==E_BAD_VIA && reply_to_via) ? 0: new_tran;
890
+			UNREF(t_invite);
891
+			goto end;
892
+		}
893
+		t=get_t();
894
+		e2e_cancel( p_msg, t, t_invite );
895
+		UNREF(t_invite);
896
+		ret=1;
897
+		goto end;
898
+	}else /* no coresponding INVITE transaction */
899
+	     if (unmatched_cancel==UM_CANCEL_DROP){
900
+				DBG("t_forward_nonack: non matching cancel dropped\n");
901
+				ret=1; /* do nothing -> drop */
902
+				goto end;
903
+		 }else{
904
+			/* UM_CANCEL_STATELESS -> stateless forward */
905
+				DBG( "SER: forwarding CANCEL statelessly \n");
906
+				if (proxy==0) {
907
+					init_dest_info(&dst);
908
+					dst.proto=proto;
909
+					if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host,
910
+								&port, &dst.proto, &comp)!=0){
911
+						ret=E_BAD_ADDRESS;
912
+						goto end;
913
+					}
914
+#ifdef USE_COMP
915
+					dst.comp=comp;
916
+#endif
917
+					/* dst->send_sock not set, but forward_request 
918
+					 * will take care of it */
919
+					ret=forward_request(p_msg, &host, port, &dst);
920
+					goto end;
921
+				} else {
922
+					init_dest_info(&dst);
923
+					dst.proto=get_proto(proto, proxy->proto);
924
+					proxy2su(&dst.to, proxy);
925
+					/* dst->send_sock not set, but forward_request 
926
+					 * will take care of it */
927
+					ret=forward_request( p_msg , 0, 0, &dst) ;
928
+					goto end;
929
+				}
930
+		}
931
+end:
932
+	if (tran)
933
+		*tran=t;
934
+	return ret;
935
+}
936
+
937
+
938
+
838 939
 /* WARNING: doesn't work from failure route (deadlock, uses t_relay_to which
839 940
  *  is failure route unsafe) */
840 941
 int t_replicate(struct sip_msg *p_msg,  struct proxy_l *proxy, int proto )
... ...
@@ -29,6 +29,7 @@
29 29
  * History:
30 30
  * --------
31 31
  *  2003-02-18  added proto to various function prototypes (andrei)
32
+ *  2007-05-02  added unmatched_cancel & t_forward_cancel (andrei)
32 33
  */
33 34
 
34 35
 
... ...
@@ -40,6 +41,11 @@
40 40
 #include "../../proxy.h"
41 41
 #include "h_table.h"
42 42
 
43
+enum unmatched_cancel_t { UM_CANCEL_STATEFULL=0, UM_CANCEL_STATELESS,
44
+							UM_CANCEL_DROP };
45
+
46
+extern int unmatched_cancel;
47
+
43 48
 typedef int (*tfwd_f)(struct sip_msg* p_msg , struct proxy_l * proxy );
44 49
 typedef int (*taddblind_f)( /*struct cell *t */ );
45 50
 
... ...
@@ -62,6 +68,8 @@ int add_uac_dns_fallback( struct cell *t, struct sip_msg* msg,
62 62
 int add_blind_uac( /* struct cell *t */ );
63 63
 int t_forward_nonack( struct cell *t, struct sip_msg* p_msg,
64 64
 						struct proxy_l * p, int proto);
65
+int t_forward_cancel(struct sip_msg* p_msg , struct proxy_l * proxy,
66
+						int proto, struct cell** tran);
65 67
 int t_forward_ack( struct sip_msg* p_msg );
66 68
 int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
67 69
 					struct proxy_l * proxy, int lock_replies);
... ...
@@ -335,6 +335,7 @@ static param_export_t params[]={
335 335
 													(void*)parse_tw_append   },
336 336
 	{"pass_provisional_replies", PARAM_INT, &pass_provisional_replies        },
337 337
 	{"aggregate_challenges", PARAM_INT, &tm_aggregate_auth                   },
338
+	{"unmatched_cancel",    PARAM_INT, &unmatched_cancel                     },
338 339
 	{"default_code",        PARAM_INT, &default_code                         },
339 340
 	{"default_reason",      PARAM_STR, &default_reason                       },
340 341
 	{0,0,0}