[Asterisk-code-review] pbx_dundi: added IPv4/IPv6 dual bind support to DUNDi (...asterisk[master])

George Joseph asteriskteam at digium.com
Mon Jun 10 07:37:33 CDT 2019


George Joseph has submitted this change and it was merged. ( https://gerrit.asterisk.org/c/asterisk/+/11437 )

Change subject: pbx_dundi: added IPv4/IPv6 dual bind support to DUNDi
......................................................................

pbx_dundi: added IPv4/IPv6 dual bind support to DUNDi

ASTERISK-28234
Reported-by: Kirsty Tyerman

Change-Id: I5d6e6b52dbe51415046bb3953fd16f5b421bc2e1
---
M configs/samples/dundi.conf.sample
A doc/CHANGES-staging/pbx_dundi_ipv6.txt
M pbx/pbx_dundi.c
3 files changed, 114 insertions(+), 26 deletions(-)

Approvals:
  George Joseph: Looks good to me, approved; Approved for Submit



diff --git a/configs/samples/dundi.conf.sample b/configs/samples/dundi.conf.sample
index b97d3b2..3c67164 100644
--- a/configs/samples/dundi.conf.sample
+++ b/configs/samples/dundi.conf.sample
@@ -21,8 +21,10 @@
 ;phone=+12565551212
 ;
 ;
-; Specify bind address and port number.  Default is
-; 4520
+; Specify bind address. IPv6 addresses are accepted. Default is 0.0.0.0
+; You can specify 'bindaddr2' to bind to another address however
+; 'bindaddr and 'bindaddr2' need to be different IP protocols.
+; Specify port number. Default is 4520.
 ;
 ;bindaddr=0.0.0.0
 ;port=4520
diff --git a/doc/CHANGES-staging/pbx_dundi_ipv6.txt b/doc/CHANGES-staging/pbx_dundi_ipv6.txt
new file mode 100644
index 0000000..c15ae44
--- /dev/null
+++ b/doc/CHANGES-staging/pbx_dundi_ipv6.txt
@@ -0,0 +1,3 @@
+Subject: pbx_dundi
+
+The DUNDi PBX module now supports IPv4/IPv6 dual binding.
diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c
index ec150f3..6cc7711 100644
--- a/pbx/pbx_dundi.c
+++ b/pbx/pbx_dundi.c
@@ -183,7 +183,8 @@
 
 static struct io_context *io;
 static struct ast_sched_context *sched;
-static int netsocket = -1;
+static int netsocket = -1; /* Socket for bindaddr if only one bindaddr. Otherwise the IPv4 socket when bindaddr2 given. */
+static int netsocket2 = -1; /* IPv6 socket when bindaddr2 given. */
 static pthread_t netthreadid = AST_PTHREADT_NULL;
 static pthread_t precachethreadid = AST_PTHREADT_NULL;
 static pthread_t clearcachethreadid = AST_PTHREADT_NULL;
@@ -2079,14 +2080,14 @@
 	return 0;
 }
 
-static int socket_read(int *id, int fd, short events, void *cbdata)
+static int socket_read(int *id, int fd, short events, void *sock)
 {
 	struct ast_sockaddr sin;
 	int res;
 	struct dundi_hdr *h;
 	char buf[MAX_PACKET_SIZE];
 
-	res = ast_recvfrom(netsocket, buf, sizeof(buf), 0, &sin);
+	res = ast_recvfrom(*((int *)sock), buf, sizeof(buf), 0, &sin);
 	if (res < 0) {
 		if (errno != ECONNREFUSED)
 			ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
@@ -2196,7 +2197,11 @@
 	   from the network, and queue them for delivery to the channels */
 	int res;
 	/* Establish I/O callback for socket read */
-	int *socket_read_id = ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
+	int *socket_read_id = ast_io_add(io, netsocket, socket_read, AST_IO_IN, &netsocket);
+	int *socket_read_id2 = NULL;
+	if (netsocket2 >= 0) {
+		socket_read_id2 = ast_io_add(io, netsocket2, socket_read, AST_IO_IN, &netsocket2);
+	}
 
 	while (!dundi_shutdown) {
 		res = ast_sched_wait(sched);
@@ -2213,6 +2218,10 @@
 
 	ast_io_remove(io, socket_read_id);
 
+	if (socket_read_id2) {
+		ast_io_remove(io, socket_read_id2);
+	}
+
 	return NULL;
 }
 
@@ -3162,7 +3171,17 @@
 	int res;
 	if (dundidebug)
 		dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
-	res = ast_sendto(netsocket, pack->data, pack->datalen, 0, &pack->parent->addr);
+
+	if (netsocket2 < 0) {
+		res = ast_sendto(netsocket, pack->data, pack->datalen, 0, &pack->parent->addr);
+	} else {
+		if (ast_sockaddr_is_ipv4(&pack->parent->addr)) {
+			res = ast_sendto(netsocket, pack->data, pack->datalen, 0, &pack->parent->addr);
+		} else {
+			res = ast_sendto(netsocket2, pack->data, pack->datalen, 0, &pack->parent->addr);
+		}
+	}
+
 	if (res < 0) {
 		ast_log(LOG_WARNING, "Failed to transmit to '%s': %s\n",
 			ast_sockaddr_stringify(&pack->parent->addr), strerror(errno));
@@ -4916,7 +4935,7 @@
 	get_ipaddress(ipaddr, sizeof(ipaddr), hn, family);
 }
 
-static int set_config(char *config_file, struct ast_sockaddr *sin, int reload)
+static int set_config(char *config_file, struct ast_sockaddr *sin, int reload, struct ast_sockaddr *sin2)
 {
 	struct ast_config *cfg;
 	struct ast_variable *v;
@@ -4927,7 +4946,8 @@
 	int port = 0;
 	int globalpcmodel = 0;
 	dundi_eid testeid;
-	char bind_addr[80];
+	char bind_addr[80]={0,};
+	char bind_addr2[80]={0,};
 
 	if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
 		ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
@@ -4957,6 +4977,12 @@
 					ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
 				}
 			}
+		} else if (!strcasecmp(v->name, "bindaddr2")) {
+			if (get_ipaddress(bind_addr2, sizeof(bind_addr2), v->value, AF_UNSPEC) == 0) {
+				if (!ast_sockaddr_parse(sin2, bind_addr2, 0)) {
+					ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
+				}
+			}
 		} else if (!strcasecmp(v->name, "authdebug")) {
 			authdebug = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "ttl")) {
@@ -5031,6 +5057,10 @@
 
 	set_host_ipaddr(sin);
 
+	if (!ast_sockaddr_isnull(sin2)) {
+		ast_sockaddr_set_port(sin2, port);
+	}
+
 	AST_LIST_UNLOCK(&peers);
 
 	mark_mappings();
@@ -5093,6 +5123,14 @@
 		clearcachethreadid = AST_PTHREADT_NULL;
  	}
 
+	if (netsocket >= 0) {
+		close(netsocket);
+	}
+
+	if (netsocket2 >= 0) {
+		close(netsocket2);
+	}
+
 	mark_mappings();
 	prune_mappings();
 	mark_peers();
@@ -5118,10 +5156,12 @@
 static int reload(void)
 {
 	struct ast_sockaddr sin;
+	struct ast_sockaddr sin2;
 
 	ast_sockaddr_setnull(&sin);
+	ast_sockaddr_setnull(&sin2);
 
-	if (set_config("dundi.conf", &sin, 1))
+	if (set_config("dundi.conf", &sin, 1, &sin2))
 		return AST_MODULE_LOAD_FAILURE;
 
 	return AST_MODULE_LOAD_SUCCESS;
@@ -5130,6 +5170,7 @@
 static int load_module(void)
 {
 	struct ast_sockaddr sin;
+	struct ast_sockaddr sin2;
 
 	dundi_set_output(dundi_debug_output);
 	dundi_set_error(dundi_error_output);
@@ -5143,29 +5184,69 @@
 	}
 
 	ast_sockaddr_setnull(&sin);
+	ast_sockaddr_setnull(&sin2);
 
-	if (set_config("dundi.conf", &sin, 0)) {
+	if (set_config("dundi.conf", &sin, 0, &sin2)) {
 		goto declined;
 	}
 
-	if (ast_sockaddr_is_ipv6(&sin)) {
-		netsocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
-	} else {
+	if (!ast_sockaddr_isnull(&sin2)) {
+		if ((ast_sockaddr_is_ipv4(&sin) == ast_sockaddr_is_ipv4(&sin2)) || (ast_sockaddr_is_ipv6(&sin) == ast_sockaddr_is_ipv6(&sin2))) {
+			ast_log(LOG_ERROR, "bindaddr & bindaddr2 should be different IP protocols.\n");
+			goto declined;
+		}
+
+		/*bind netsocket to ipv4, netsocket2 to ipv6 */
+
 		netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+		netsocket2 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
+		if (netsocket < 0 || netsocket2 < 0) {
+			ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
+			goto declined;
+		}
+		if (ast_sockaddr_is_ipv4(&sin)) {
+			if (ast_bind(netsocket, &sin)) {
+				ast_log(LOG_ERROR, "Unable to bind to %s : %s\n",
+				ast_sockaddr_stringify(&sin), strerror(errno));
+				goto declined;
+			}
+			if (ast_bind(netsocket2, &sin2)) {
+				ast_log(LOG_ERROR, "Unable to bind to %s : %s\n",
+				ast_sockaddr_stringify(&sin2), strerror(errno));
+				goto declined;
+			}
+		} else {
+			if (ast_bind(netsocket, &sin2)) {
+				ast_log(LOG_ERROR, "Unable to bind to %s : %s\n",
+				ast_sockaddr_stringify(&sin2), strerror(errno));
+				goto declined;
+			}
+			if (ast_bind(netsocket2, &sin)) {
+				ast_log(LOG_ERROR, "Unable to bind to %s : %s\n",
+					ast_sockaddr_stringify(&sin), strerror(errno));
+				goto declined;
+			}
+		}
+		ast_set_qos(netsocket, tos, 0, "DUNDi");
+		ast_set_qos(netsocket2, tos, 0, "DUNDi");
+	} else {
+		if (ast_sockaddr_is_ipv6(&sin)) {
+			netsocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
+		} else {
+			netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+		}
+		if (netsocket < 0) {
+			ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
+			goto declined;
+		}
+		if (ast_bind(netsocket, &sin))  {
+			ast_log(LOG_ERROR, "Unable to bind to %s : %s\n",
+				ast_sockaddr_stringify(&sin), strerror(errno));
+			goto declined;
+		}
+		ast_set_qos(netsocket, tos, 0, "DUNDi");
 	}
 
-	if (netsocket < 0) {
-		ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
-		goto declined;
-	}
-	if (ast_bind(netsocket, &sin))  {
-		ast_log(LOG_ERROR, "Unable to bind to %s : %s\n",
-			ast_sockaddr_stringify(&sin), strerror(errno));
-		goto declined;
-	}
-
-	ast_set_qos(netsocket, tos, 0, "DUNDi");
-
 	if (start_network_thread()) {
 		ast_log(LOG_ERROR, "Unable to start network thread\n");
 		goto declined;
@@ -5179,6 +5260,8 @@
 	ast_custom_function_register(&dundi_result_function);
 
 	ast_verb(2, "DUNDi Ready and Listening on %s\n", ast_sockaddr_stringify(&sin));
+	if (!ast_sockaddr_isnull(&sin2))
+		ast_verb(2, "DUNDi Ready and Listening on %s\n", ast_sockaddr_stringify(&sin2));
 
 	return AST_MODULE_LOAD_SUCCESS;
 

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/11437
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I5d6e6b52dbe51415046bb3953fd16f5b421bc2e1
Gerrit-Change-Number: 11437
Gerrit-PatchSet: 2
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Benjamin Keith Ford <bford at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kirsty Tyerman <kirsty.tyerman at boeing.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190610/ef9803b8/attachment-0001.html>


More information about the asterisk-code-review mailing list