2
0
Эх сурвалжийг харах

modules/ims_qos: new mod param regex_sdp_ip_prefix_to_maintain_in_fd

New parameter that allows IPs in flow-description AVP to be replaced with any
keyword to address issue of UEs that change ports midway through call causing filters
to no longer match traffic.
Richard Good 9 жил өмнө
parent
commit
7c0bab804a

+ 24 - 0
modules/ims_qos/doc/ims_qos_admin.xml

@@ -299,7 +299,31 @@ modparam("ims_qos", "confirmed_qosrelease_headers", "X-Reason: QoS failed\r\n")
         </programlisting>
       </example>
     </section>
+    
+    <section>
+      <title><varname>regex_sdp_ip_prefix_to_maintain_in_fd</varname> (String)</title>
+
+      <para>The flow-description AVP is typically populated using IP:port information
+          present in the SDP.  Certain (buggy) UEs can change ports midway during 
+          calls which causes the flow-description to no longer match the 
+          traffic.  This parameter allows the flow-description AVP to use to the 
+          any keyword instead of certain IP:port combinations in the SDP. The 
+          parameter is a regex that if set replaces all IPs that do not match 
+          the regex with the any keyword in the flow-description AVP</para>
+
+      <para><emphasis> Default value is "", no IPs replaced</emphasis></para>
+
+      <example>
+        <title><varname>regex_sdp_ip_prefix_to_maintain_in_fd</varname> parameter
+        usage</title>
 
+        <programlisting format="linespecific">
+...
+modparam("ims_qos", "regex_sdp_ip_prefix_to_maintain_in_fd", "10.21.0.1")
+...
+        </programlisting>
+      </example>
+    </section>
   </section>
 
   <section>

+ 5 - 0
modules/ims_qos/mod.c

@@ -100,6 +100,10 @@ int cdp_event_latency_loglevel = 0; /*log-level to use to report slow processing
 int audio_default_bandwidth = 64;
 int video_default_bandwidth = 128;
 
+//If set then any IP in SDP that does not match this regex is replaced with any in flow description AVP
+//V useful for UEs that change ports mid way through call therefore breaking flow description filters
+str regex_sdp_ip_prefix_to_maintain_in_fd = {0, 0};
+
 int cdp_event_list_size_threshold = 0; /**Threshold for size of cdp event list after which a warning is logged */
 
 stat_var *aars;
@@ -190,6 +194,7 @@ static param_export_t params[] = {
 		{ "early_qosrelease_reason", PARAM_STR, &early_qosrelease_reason},
 		{ "confirmed_qosrelease_headers", PARAM_STR, &confirmed_qosrelease_headers},
 		{ "terminate_dialog_on_rx_failure", INT_PARAM, &terminate_dialog_on_rx_failure},
+		{ "regex_sdp_ip_prefix_to_maintain_in_fd", PARAM_STR, &regex_sdp_ip_prefix_to_maintain_in_fd},
 		{ 0, 0, 0}
 };
 

+ 86 - 8
modules/ims_qos/rx_avp.c

@@ -56,6 +56,7 @@
 #include "rx_avp.h"
 #include "mod.h"
 #include "../../parser/sdp/sdp_helpr_funcs.h"
+#include <regex.h>
 
 #include "../../lib/ims/ims_getters.h"
 
@@ -63,6 +64,8 @@
 extern struct cdp_binds cdpb;
 extern cdp_avp_bind_t *cdp_avp;
 
+extern str regex_sdp_ip_prefix_to_maintain_in_fd;
+
 /**
  * Create and add an AVP to a Diameter message.
  * @param m - Diameter message to add to 
@@ -629,13 +632,39 @@ static str from_s = {" from ", 6};
 static str to_s = {" to ", 4};
 //removed final %s - this is options which Rx 29.214 says will not be used for flow-description AVP
 static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u";
+static char * permit_out_with_any_as_dst = "permit out %i from %.*s %u to any";
+//static char * permit_out_with_any_as_src = "permit out %i from any to %.*s %u";
 //static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u %s";
 static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u";
+static char * permit_in_with_any_as_src = "permit in %i from any to %.*s %u";
+//static char * permit_in_with_any_as_dst = "permit in %i from %.*s %u to any";
 //static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u %s";
 
 static unsigned int flowdata_buflen = 0;
 static str flowdata_buf = {0, 0};
 
+#define MAX_MATCH 20
+
+/*! \brief Match pattern against string and store result in pmatch */
+int reg_match(char *pattern, char *string, regmatch_t *pmatch)
+{
+		regex_t preg;
+
+		if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
+				return -1;
+		}
+		if (preg.re_nsub > MAX_MATCH) {
+				regfree(&preg);
+				return -2;
+		}
+		if (regexec(&preg, string, MAX_MATCH, pmatch, 0)) {
+				regfree(&preg);
+				return -3;
+		}
+		regfree(&preg);
+		return 0;
+}
+
 AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
 		str *ipA, str *portA,
 		str *ipB, str *portB)
@@ -659,8 +688,40 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
 		int intportA = atoi(portA->s);
 		int intportB = atoi(portB->s);
 
-		len = (permit_out.len + from_s.len + to_s.len + ipB->len + ipA->len + 4 +
-				proto_len + portA->len + portB->len + 1/*nul terminator*/) * sizeof(char);
+		int useAnyForIpA = 0;
+		int useAnyForIpB = 0;
+
+		if (regex_sdp_ip_prefix_to_maintain_in_fd.len > 0 && regex_sdp_ip_prefix_to_maintain_in_fd.s) {
+				LM_DBG("regex_sdp_ip_prefix_to_maintain_in_fd is set to: [%.*s] therefore we check if we need to replace non matching IPs with any\n",
+						regex_sdp_ip_prefix_to_maintain_in_fd.len, regex_sdp_ip_prefix_to_maintain_in_fd.s);
+				regmatch_t pmatch[MAX_MATCH];
+				if (reg_match(regex_sdp_ip_prefix_to_maintain_in_fd.s, ipA->s, &(pmatch[0]))) {
+						LM_DBG("ipA [%.*s] does not match so will use any instead of ipA", ipA->len, ipA->s);
+						useAnyForIpA = 1;
+				} else {
+						LM_DBG("ipA [%.*s] matches regex so will not use any", ipA->len, ipA->s);
+						useAnyForIpA = 0;
+				}
+				if (reg_match(regex_sdp_ip_prefix_to_maintain_in_fd.s, ipB->s, &(pmatch[0]))) {
+						LM_DBG("ipB [%.*s] does not match so will use any instead of ipB", ipB->len, ipB->s);
+						useAnyForIpB = 1;
+				} else {
+						LM_DBG("ipB [%.*s] matches regex so will not use any", ipB->len, ipB->s);
+						useAnyForIpB = 0;
+				}
+
+		}
+
+		if (!useAnyForIpA && !useAnyForIpB) {
+				len = (permit_out.len + from_s.len + to_s.len + ipB->len + ipA->len + 4 +
+						proto_len + portA->len + portB->len + 1/*nul terminator*/) * sizeof(char);
+		} else if (useAnyForIpA) {
+				len = (permit_out.len + from_s.len + to_s.len + 3 /*for 'any'*/ + ipB->len + 4 +
+						proto_len + portB->len + 1/*nul terminator*/) * sizeof(char);
+		} else if (useAnyForIpB) {
+				len = (permit_out.len + from_s.len + to_s.len + 3 /*for 'any'*/ + ipA->len + 4 +
+						proto_len + portA->len + 1/*nul terminator*/) * sizeof(char);
+		}
 
 		if (!flowdata_buf.s || flowdata_buflen < len) {
 				if (flowdata_buf.s)
@@ -684,9 +745,18 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
 
 		/*IMS Flow descriptions*/
 		/*first flow is the receive flow*/
-		flowdata_buf.len = snprintf(flowdata_buf.s, len, permit_out_with_ports, proto_int,
-				ipA->len, ipA->s, intportA,
-				ipB->len, ipB->s, intportB);
+		if (!useAnyForIpA && !useAnyForIpB) {
+				flowdata_buf.len = snprintf(flowdata_buf.s, len, permit_out_with_ports, proto_int,
+						ipA->len, ipA->s, intportA,
+						ipB->len, ipB->s, intportB);
+		} else if (useAnyForIpA) {
+				flowdata_buf.len = snprintf(flowdata_buf.s, len, permit_out_with_any_as_dst, proto_int,
+						ipB->len, ipB->s, intportB);
+		} else if (useAnyForIpB) {
+				flowdata_buf.len = snprintf(flowdata_buf.s, len, permit_out_with_any_as_dst, proto_int,
+						ipA->len, ipA->s, intportA);
+		}
+
 
 		flowdata_buf.len = strlen(flowdata_buf.s);
 		flow_description1 = cdpb.AAACreateAVP(AVP_IMS_Flow_Description,
@@ -709,9 +779,17 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
 				flowdata_buflen = len2;
 		}
 
-		flowdata_buf.len = snprintf(flowdata_buf.s, len2, permit_in_with_ports, proto_int,
-				ipB->len, ipB->s, intportB,
-				ipA->len, ipA->s, intportA);
+		if (!useAnyForIpA && !useAnyForIpB) {
+				flowdata_buf.len = snprintf(flowdata_buf.s, len2, permit_in_with_ports, proto_int,
+						ipB->len, ipB->s, intportB,
+						ipA->len, ipA->s, intportA);
+		} else if (useAnyForIpA) {
+				flowdata_buf.len = snprintf(flowdata_buf.s, len2, permit_in_with_any_as_src, proto_int,
+						ipB->len, ipB->s, intportB);
+		} else if (useAnyForIpB) {
+				flowdata_buf.len = snprintf(flowdata_buf.s, len2, permit_in_with_any_as_src, proto_int,
+						ipA->len, ipA->s, intportA);
+		}
 
 		flowdata_buf.len = strlen(flowdata_buf.s);
 		flow_description2 = cdpb.AAACreateAVP(AVP_IMS_Flow_Description,