changeset 1936:4528afefe45d

Fix IPv6 address parsing for dbclient -b Now can correctly handle '-b [ipv6address]:port' Code is shared with dropbear -p, though they handle colon-less arguments differently
author Matt Johnston <matt@ucc.asn.au>
date Fri, 01 Apr 2022 14:13:52 +0800
parents a7ad060707b6
children 334b742fdeb8
files cli-runopts.c common-runopts.c runopts.h svr-runopts.c
diffstat 4 files changed, 84 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/cli-runopts.c	Fri Apr 01 12:17:02 2022 +0800
+++ b/cli-runopts.c	Fri Apr 01 14:13:52 2022 +0800
@@ -419,7 +419,7 @@
 
 	/* And now a few sanity checks and setup */
 
-#if DROPBEAR_CLI_PROXYCMD                                                                                                                                   
+#if DROPBEAR_CLI_PROXYCMD
 	if (cli_opts.proxycmd) {
 		/* To match the common path of m_freeing it */
 		cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
@@ -431,14 +431,10 @@
 	}
 
 	if (bind_arg) {
-		/* split [host][:port] */
-		char *port = strrchr(bind_arg, ':');
-		if (port) {
-			cli_opts.bind_port = m_strdup(port+1);
-			*port = '\0';
-		}
-		if (strlen(bind_arg) > 0) {
-			cli_opts.bind_address = m_strdup(bind_arg);
+		if (split_address_port(bind_arg,
+			&cli_opts.bind_address, &cli_opts.bind_port)
+				== DROPBEAR_FAILURE) {
+			dropbear_exit("Bad -b argument");
 		}
 	}
 
--- a/common-runopts.c	Fri Apr 01 12:17:02 2022 +0800
+++ b/common-runopts.c	Fri Apr 01 14:13:52 2022 +0800
@@ -116,3 +116,58 @@
 	}
 
 }
+
+/* Splits addr:port. Handles IPv6 [2001:0011::4]:port style format.
+   Returns first/second parts as malloced strings, second will
+   be NULL if no separator is found.
+   :port  ->  (NULL, "port")
+   port  ->   (port, NULL)
+   addr:port  (addr, port)
+   addr: ->   (addr, "")
+   Returns DROPBEAR_SUCCESS/DROPBEAR_FAILURE */
+int split_address_port(const char* spec, char **first, char ** second) {
+	char *spec_copy = NULL, *addr = NULL, *colon = NULL;
+	int ret = DROPBEAR_FAILURE;
+
+	*first = NULL;
+	*second = NULL;
+	spec_copy = m_strdup(spec);
+	addr = spec_copy;
+
+	if (*addr == '[') {
+		addr++;
+		colon = strchr(addr, ']');
+		if (!colon) {
+			dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
+			goto out;
+		}
+		*colon = '\0';
+		colon++;
+		if (*colon == '\0') {
+			/* No port part */
+			colon = NULL;
+		} else if (*colon != ':') {
+			dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
+			goto out;
+		}
+	} else {
+		/* search for ':', that separates address and port */
+		colon = strrchr(addr, ':');
+	}
+
+	/* colon points to ':' now, or is NULL */
+	if (colon) {
+		/* Split the address/port */
+		*colon = '\0';
+		colon++;
+		*second = m_strdup(colon);
+	}
+	if (strlen(addr)) {
+		*first = m_strdup(addr);
+	}
+	ret = DROPBEAR_SUCCESS;
+
+out:
+	m_free(spec_copy);
+	return ret;
+}
--- a/runopts.h	Fri Apr 01 12:17:02 2022 +0800
+++ b/runopts.h	Fri Apr 01 14:13:52 2022 +0800
@@ -198,5 +198,6 @@
 
 void print_version(void);
 void parse_recv_window(const char* recv_window_arg);
+int split_address_port(const char* spec, char **first, char ** second);
 
 #endif /* DROPBEAR_RUNOPTS_H_ */
--- a/svr-runopts.c	Fri Apr 01 12:17:02 2022 +0800
+++ b/svr-runopts.c	Fri Apr 01 14:13:52 2022 +0800
@@ -452,56 +452,34 @@
 }
 
 static void addportandaddress(const char* spec) {
-	char *spec_copy = NULL, *myspec = NULL, *port = NULL, *address = NULL;
-
-	if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
+	char *port = NULL, *address = NULL;
 
-		/* We don't free it, it becomes part of the runopt state */
-		spec_copy = m_strdup(spec);
-		myspec = spec_copy;
+	if (svr_opts.portcount >= DROPBEAR_MAX_PORTS) {
+		return;
+	}
+
+	if (split_address_port(spec, &address, &port) == DROPBEAR_FAILURE) {
+		dropbear_exit("Bad -p argument");
+	}
 
-		if (myspec[0] == '[') {
-			myspec++;
-			port = strchr(myspec, ']');
-			if (!port) {
-				/* Unmatched [ -> exit */
-				dropbear_exit("Bad listen address");
-			}
-			port[0] = '\0';
-			port++;
-			if (port[0] != ':') {
-				/* Missing port -> exit */
-				dropbear_exit("Missing port");
-			}
-		} else {
-			/* search for ':', that separates address and port */
-			port = strrchr(myspec, ':');
-		}
+	/* A bare port */
+	if (!port) {
+		port = address;
+		address = NULL;
+	}
 
-		if (!port) {
-			/* no ':' -> the whole string specifies just a port */
-			port = myspec;
-		} else {
-			/* Split the address/port */
-			port[0] = '\0'; 
-			port++;
-			address = myspec;
-		}
+	if (!address) {
+		/* no address given -> fill in the default address */
+		address = m_strdup(DROPBEAR_DEFADDRESS);
+	}
 
-		if (!address) {
-			/* no address given -> fill in the default address */
-			address = DROPBEAR_DEFADDRESS;
-		}
-
-		if (port[0] == '\0') {
-			/* empty port -> exit */
-			dropbear_exit("Bad port");
-		}
-		svr_opts.ports[svr_opts.portcount] = m_strdup(port);
-		svr_opts.addresses[svr_opts.portcount] = m_strdup(address);
-		svr_opts.portcount++;
-		m_free(spec_copy);
+	if (port[0] == '\0') {
+		/* empty port -> exit */
+		dropbear_exit("Bad port");
 	}
+	svr_opts.ports[svr_opts.portcount] = port;
+	svr_opts.addresses[svr_opts.portcount] = address;
+	svr_opts.portcount++;
 }
 
 static void disablekey(int type) {