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

modules_k/registrar: New outbound_mode parameter

- Controls whether outbound options-tag is required in REGISTER
  requests and whether they are added to responses to REGISTER requests.
- Needed so that an Outbound Edge Proxy can add a Flow-Timer: header
  to 200 OK responses (to REGISTERs) that contain a Requires: header with
  the outbound options-tag.
Peter Dunkley 12 жил өмнө
parent
commit
c486a9358f

+ 7 - 0
modules_k/registrar/reg_mod.c

@@ -119,6 +119,7 @@ int path_use_params = 0;			/*!< if the received- and nat-parameters of last Path
 sruid_t _reg_sruid;
 
 int reg_gruu_enabled = 1;
+int reg_outbound_mode = 0;
 
 /* Populate this AVP if testing for specific registration instance. */
 char *reg_callid_avp_param = 0;
@@ -222,6 +223,7 @@ static param_export_t params[] = {
 	{"xavp_cfg",           STR_PARAM, &reg_xavp_cfg.s     					},
 	{"xavp_rcd",           STR_PARAM, &reg_xavp_rcd.s     					},
 	{"gruu_enabled",       INT_PARAM, &reg_gruu_enabled    					},
+	{"outbound_mode",      INT_PARAM, &reg_outbound_mode					},
 	{0, 0, 0}
 };
 
@@ -373,6 +375,11 @@ static int mod_init(void)
 		sock_flag = -1;
 	}
 
+	if (reg_outbound_mode < 0 || reg_outbound_mode > 2) {
+		LM_ERR("outbound_mode modparam must be 0 (not supported), 1 (supported), or 2 (supported and required)\n");
+		return -1;
+	}
+
 	/* fix the flags */
 	sock_flag = (sock_flag!=-1)?(1<<sock_flag):0;
 	tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<<tcp_persistent_flag):0;

+ 5 - 0
modules_k/registrar/reg_mod.h

@@ -67,6 +67,10 @@
 #define REG_SAVE_REPL_FL    (1<<2)
 #define REG_SAVE_ALL_FL     ((1<<3)-1)
 
+#define REG_OUTBOUND_NONE	0
+#define REG_OUTBOUND_SUPPORTED	1
+#define REG_OUTBOUND_REQUIRE	2
+
 extern int nat_flag;
 extern int tcp_persistent_flag;
 extern int received_avp;
@@ -84,6 +88,7 @@ extern int path_enabled;
 extern int path_mode;
 extern int path_use_params;
 extern int reg_gruu_enabled;
+extern int reg_outbound_mode;
 
 extern str sock_hdr_name;
 extern int sock_flag;

+ 95 - 22
modules_k/registrar/reply.c

@@ -373,6 +373,7 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 #define MSG_200 "OK"
 #define MSG_400 "Bad Request"
 #define MSG_420 "Bad Extension"
+#define MSG_421 "Extension Required"
 #define MSG_500 "Server Internal Error"
 #define MSG_503 "Service Unavailable"
 
@@ -406,6 +407,7 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 #define EI_R_CALLID_LEN  "Callid too long"                          /* R_CALLID_LEN */
 #define EI_R_PARSE_PATH  "Path parse error"                         /* R_PARSE_PATH */
 #define EI_R_PATH_UNSUP  "No support for found Path indicated"      /* R_PATH_UNSUP */
+#define EI_R_OB_UNSUP    "No support for Outbound indicated"        /* R_OB_UNSUP */
 
 str error_info[] = {
 	{EI_R_FINE,       sizeof(EI_R_FINE) - 1},
@@ -437,7 +439,8 @@ str error_info[] = {
 	{EI_R_CONTACT_LEN,sizeof(EI_R_CONTACT_LEN) - 1},
 	{EI_R_CALLID_LEN, sizeof(EI_R_CALLID_LEN) - 1},
 	{EI_R_PARSE_PATH, sizeof(EI_R_PARSE_PATH) - 1},
-	{EI_R_PATH_UNSUP, sizeof(EI_R_PATH_UNSUP) - 1}
+	{EI_R_PATH_UNSUP, sizeof(EI_R_PATH_UNSUP) - 1},
+	{EI_R_OB_UNSUP,   sizeof(EI_R_OB_UNSUP) - 1},
 
 };
 
@@ -471,7 +474,8 @@ int codes[] = {
 	400, /* R_CONTACT_LEN */
 	400, /* R_CALLID_LEN */
 	400, /* R_PARSE_PATH */
-	420  /* R_PATH_UNSUP */
+	420, /* R_PATH_UNSUP */
+	421  /* R_OB_UNSUP */
 
 };
 
@@ -537,6 +541,46 @@ static int add_unsupported(struct sip_msg* _m, str* _p)
  		     LUMP_RPL_HDR | LUMP_RPL_NODUP);
  	return 0;
 }
+
+#define REQUIRE "Require: "
+#define REQUIRE_LEN (sizeof(REQUIRE) - 1)
+
+static int add_require(struct sip_msg* _m, str* _p)
+{
+	char* buf;
+
+ 	buf = (char*)pkg_malloc(REQUIRE_LEN + _p->len + CRLF_LEN);
+ 	if (!buf) {
+ 		LM_ERR("no pkg memory left\n");
+ 		return -1;
+ 	}
+ 	memcpy(buf, REQUIRE, REQUIRE_LEN);
+ 	memcpy(buf + REQUIRE_LEN, _p->s, _p->len);
+ 	memcpy(buf + REQUIRE_LEN + _p->len, CRLF, CRLF_LEN);
+ 	add_lump_rpl(_m, buf, REQUIRE_LEN + _p->len + CRLF_LEN,
+ 		     LUMP_RPL_HDR | LUMP_RPL_NODUP);
+ 	return 0;
+}
+
+#define SUPPORTED "Supported: "
+#define SUPPORTED_LEN (sizeof(SUPPORTED) - 1)
+
+static int add_supported(struct sip_msg* _m, str* _p)
+{
+	char* buf;
+
+ 	buf = (char*)pkg_malloc(SUPPORTED_LEN + _p->len + CRLF_LEN);
+ 	if (!buf) {
+ 		LM_ERR("no pkg memory left\n");
+ 		return -1;
+ 	}
+ 	memcpy(buf, SUPPORTED, SUPPORTED_LEN);
+ 	memcpy(buf + SUPPORTED_LEN, _p->s, _p->len);
+ 	memcpy(buf + SUPPORTED_LEN + _p->len, CRLF, CRLF_LEN);
+ 	add_lump_rpl(_m, buf, SUPPORTED_LEN + _p->len + CRLF_LEN,
+ 		     LUMP_RPL_HDR | LUMP_RPL_NODUP);
+ 	return 0;
+}
  
 /*! \brief
  * Send a reply
@@ -544,6 +588,7 @@ static int add_unsupported(struct sip_msg* _m, str* _p)
 int reg_send_reply(struct sip_msg* _m)
 {
 	str unsup = str_init(SUPPORTED_PATH_STR);
+	str outbound_str = str_init(SUPPORTED_OUTBOUND_STR);
 	long code;
 	str msg = str_init(MSG_200); /* makes gcc shut up */
 	char* buf;
@@ -552,34 +597,62 @@ int reg_send_reply(struct sip_msg* _m)
 		add_lump_rpl( _m, contact.buf, contact.data_len, LUMP_RPL_HDR|LUMP_RPL_NODUP|LUMP_RPL_NOFREE);
 		contact.data_len = 0;
 	}
-			
-	if (rerrno == R_FINE && path_enabled && _m->path_vec.s) {
-		if (path_mode != PATH_MODE_OFF) {
-			if (parse_supported(_m)<0 && path_mode == PATH_MODE_STRICT) {
-				rerrno = R_PATH_UNSUP;
-				if (add_unsupported(_m, &unsup) < 0)
-					return -1;
-				if (add_path(_m, &_m->path_vec) < 0)
-					return -1;
-			}
-			else if (get_supported(_m) & F_SUPPORTED_PATH) {
-				if (add_path(_m, &_m->path_vec) < 0)
-					return -1;
-			} else if (path_mode == PATH_MODE_STRICT) {
-				rerrno = R_PATH_UNSUP;
-				if (add_unsupported(_m, &unsup) < 0)
-					return -1;
-				if (add_path(_m, &_m->path_vec) < 0)
-					return -1;
+
+	switch (rerrno) {
+	case R_FINE:
+		if (path_enabled && _m->path_vec.s) {
+			if (path_mode != PATH_MODE_OFF) {
+				if (parse_supported(_m)<0 && path_mode == PATH_MODE_STRICT) {
+					rerrno = R_PATH_UNSUP;
+					if (add_unsupported(_m, &unsup) < 0)
+						return -1;
+					if (add_path(_m, &_m->path_vec) < 0)
+						return -1;
+				}
+				else if (get_supported(_m) & F_SUPPORTED_PATH) {
+					if (add_path(_m, &_m->path_vec) < 0)
+						return -1;
+				} else if (path_mode == PATH_MODE_STRICT) {
+					rerrno = R_PATH_UNSUP;
+					if (add_unsupported(_m, &unsup) < 0)
+						return -1;
+					if (add_path(_m, &_m->path_vec) < 0)
+						return -1;
+				}
 			}
 		}
+
+		switch(reg_outbound_mode)
+		{
+		case REG_OUTBOUND_NONE:
+		default:
+			break;
+		case REG_OUTBOUND_REQUIRE:
+			if (add_require(_m, &outbound_str) < 0)
+				return -1;
+			/* Fall-thru */
+		case REG_OUTBOUND_SUPPORTED:
+			if (add_supported(_m, &outbound_str) < 0)
+				return -1;
+			break;
+		}
+		break;
+	case R_OB_UNSUP:
+		if (add_require(_m, &outbound_str) < 0)
+			return -1;
+		if (add_supported(_m, &outbound_str) < 0)
+			return -1;
+		break;
+	default:
+		break;
 	}
 
 	code = codes[rerrno];
 	switch(code) {
-	case 200: msg.s = MSG_200; msg.len = sizeof(MSG_200)-1; break;
+	case 200: msg.s = MSG_200; msg.len = sizeof(MSG_200)-1;break;
 	case 400: msg.s = MSG_400; msg.len = sizeof(MSG_400)-1;break;
 	case 420: msg.s = MSG_420; msg.len = sizeof(MSG_420)-1;break;
+	case 421: msg.s = MSG_420; msg.len = sizeof(MSG_421)-1;break;
 	case 500: msg.s = MSG_500; msg.len = sizeof(MSG_500)-1;break;
 	case 503: msg.s = MSG_503; msg.len = sizeof(MSG_503)-1;break;
 	}

+ 2 - 1
modules_k/registrar/rerrno.h

@@ -63,7 +63,8 @@ typedef enum rerr {
 	R_CONTACT_LEN,/*!< Contact URI or RECEIVED too long */
 	R_CALLID_LEN, /*!< Callid too long */
 	R_PARSE_PATH, /*!< Error while parsing Path */
-	R_PATH_UNSUP  /*!< Path not supported by UAC */
+	R_PATH_UNSUP, /*!< Path not supported by UAC */
+	R_OB_UNSUP    /*!< Outbound not supported by UAC */
 
 } rerr_t;
 

+ 10 - 0
modules_k/registrar/save.c

@@ -61,6 +61,7 @@
 #include "../../mod_fix.h"
 #include "../../lib/srutils/sruid.h"
 #include "../../lib/kcore/cmpapi.h"
+#include "../../lib/kcore/parse_supported.h"
 #include "../../lib/kcore/statistics.h"
 #ifdef USE_TCP
 #include "../../tcp_server.h"
@@ -840,6 +841,15 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	if (check_contacts(_m, &st) > 0) {
 		goto error;
 	}
+
+	if (parse_supported(_m) == 0) {
+		if (!(((struct supported_body *)_m->supported->parsed)->supported_all
+				& F_SUPPORTED_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) {
+			LM_WARN("Outbound required by server and not supported by UAC\n");
+			rerrno = R_OB_UNSUP;
+			goto error;
+		}
+	}
 	
 	get_act_time();
 	c = get_first_contact(_m);