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 216
 
216 217
 	ret=0;
217 218
 	
219
+	/* special case for CANCEL */
220
+	if ( p_msg->REQ_METHOD==METHOD_CANCEL){
221
+		ret=t_forward_cancel(p_msg, proxy, proto, &t);
222
+		if (t) goto handle_ret;
223
+		goto done;
224
+	}
218 225
 	new_tran = t_newtran( p_msg );
219 226
 	
220 227
 	/* 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 290
 
284 291
 	/* now go ahead and forward ... */
285 292
 	ret=t_forward_nonack(t, p_msg, proxy, proto);
293
+handle_ret:
286 294
 	if (ret<=0) {
287 295
 		DBG( "ERROR:tm:t_relay_to:  t_forward_nonack returned error \n");
288 296
 		/* 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 99
 #endif
99 100
 
100 101
 
102
+int unmatched_cancel=UM_CANCEL_STATEFULL;
101 103
 
102 104
 static int goto_on_branch = 0, branch_route = 0;
103 105
 
... ...
@@ -726,13 +728,13 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
726 728
 	int lock_replies;
727 729
 	str dst_uri;
728 730
 	struct socket_info* si, *backup_si;
731
+	
729 732
 
730 733
 	/* make -Wall happy */
731 734
 	current_uri.s=0;
732 735
 
733 736
 	set_kr(REQ_FWDED);
734
-
735
-	if (p_msg->REQ_METHOD==METHOD_CANCEL) {
737
+	if (p_msg->REQ_METHOD==METHOD_CANCEL) { 
736 738
 		t_invite=t_lookupOriginalT(  p_msg );
737 739
 		if (t_invite!=T_NULL_CELL) {
738 740
 			e2e_cancel( p_msg, t, t_invite );
... ...
@@ -835,6 +837,107 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
835 837
 
836 838
 
837 839
 
840
+/* cancel handling/forwarding function
841
+ * CANCELs with no matching transaction are handled in function of
842
+ * the unmatched_cancel config var: they are either forwarded statefully,
843
+ * statelessly or dropped.
844
+ * function returns:
845
+ *       1 - forward successful
846
+ *       0 - error, but do not reply 
847
+ *      <0 - error during forward
848
+ * it also sets *tran if a transaction was created
849
+ */
850
+int t_forward_cancel(struct sip_msg* p_msg , struct proxy_l * proxy, int proto,
851
+						struct cell** tran)
852
+{
853
+	struct cell* t_invite;
854
+	struct cell* t;
855
+	int ret;
856
+	int new_tran;
857
+	struct dest_info dst;
858
+	str host;
859
+	unsigned short port;
860
+	short comp;
861
+	
862
+	t=0;
863
+	/* handle cancels for which no transaction was created yet */
864
+	if (unmatched_cancel==UM_CANCEL_STATEFULL){
865
+		/* create cancel transaction */
866
+		new_tran=t_newtran(p_msg);
867
+		if (new_tran<=0 && new_tran!=E_SCRIPT){
868
+			if (new_tran==0)
869
+				 /* retransmission => do nothing */
870
+				ret=1;
871
+			else
872
+				/* some error => return it or DROP */
873
+				ret=(ser_error==E_BAD_VIA && reply_to_via) ? 0: new_tran;
874
+			goto end;
875
+		}
876
+		t=get_t();
877
+		ret=t_forward_nonack(t, p_msg, proxy, proto);
878
+		goto end;
879
+	}
880
+	
881
+	t_invite=t_lookupOriginalT(  p_msg );
882
+	if (t_invite!=T_NULL_CELL) {
883
+		/* create cancel transaction */
884
+		new_tran=t_newtran(p_msg);
885
+		if (new_tran<=0 && new_tran!=E_SCRIPT){
886
+			if (new_tran==0)
887
+				 /* retransmission => do nothing */
888
+				ret=1;
889
+			else
890
+				/* some error => return it or DROP */
891
+				ret=(ser_error==E_BAD_VIA && reply_to_via) ? 0: new_tran;
892
+			UNREF(t_invite);
893
+			goto end;
894
+		}
895
+		t=get_t();
896
+		e2e_cancel( p_msg, t, t_invite );
897
+		UNREF(t_invite);
898
+		ret=1;
899
+		goto end;
900
+	}else /* no coresponding INVITE transaction */
901
+	     if (unmatched_cancel==UM_CANCEL_DROP){
902
+				DBG("t_forward_nonack: non matching cancel dropped\n");
903
+				ret=1; /* do nothing -> drop */
904
+				goto end;
905
+		 }else{
906
+			/* UM_CANCEL_STATELESS -> stateless forward */
907
+				DBG( "SER: forwarding CANCEL statelessly \n");
908
+				if (proxy==0) {
909
+					init_dest_info(&dst);
910
+					dst.proto=proto;
911
+					if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host,
912
+								&port, &dst.proto, &comp)!=0){
913
+						ret=E_BAD_ADDRESS;
914
+						goto end;
915
+					}
916
+#ifdef USE_COMP
917
+					dst.comp=comp;
918
+#endif
919
+					/* dst->send_sock not set, but forward_request 
920
+					 * will take care of it */
921
+					ret=forward_request(p_msg, &host, port, &dst);
922
+					goto end;
923
+				} else {
924
+					init_dest_info(&dst);
925
+					dst.proto=get_proto(proto, proxy->proto);
926
+					proxy2su(&dst.to, proxy);
927
+					/* dst->send_sock not set, but forward_request 
928
+					 * will take care of it */
929
+					ret=forward_request( p_msg , 0, 0, &dst) ;
930
+					goto end;
931
+				}
932
+		}
933
+end:
934
+	if (tran)
935
+		*tran=t;
936
+	return ret;
937
+}
938
+
939
+
940
+
838 941
 /* WARNING: doesn't work from failure route (deadlock, uses t_relay_to which
839 942
  *  is failure route unsafe) */
840 943
 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 41
 #include "../../proxy.h"
41 42
 #include "h_table.h"
42 43
 
44
+enum unmatched_cancel_t { UM_CANCEL_STATEFULL=0, UM_CANCEL_STATELESS,
45
+							UM_CANCEL_DROP };
46
+
47
+extern int unmatched_cancel;
48
+
43 49
 typedef int (*tfwd_f)(struct sip_msg* p_msg , struct proxy_l * proxy );
44 50
 typedef int (*taddblind_f)( /*struct cell *t */ );
45 51
 
... ...
@@ -62,6 +68,8 @@ int add_uac_dns_fallback( struct cell *t, struct sip_msg* msg,
62 68
 int add_blind_uac( /* struct cell *t */ );
63 69
 int t_forward_nonack( struct cell *t, struct sip_msg* p_msg,
64 70
 						struct proxy_l * p, int proto);
71
+int t_forward_cancel(struct sip_msg* p_msg , struct proxy_l * proxy,
72
+						int proto, struct cell** tran);
65 73
 int t_forward_ack( struct sip_msg* p_msg );
66 74
 int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
67 75
 					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}