git: f61f75771f95 - main - ctld: Cleanups to parse_addr_port

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Mon, 04 Aug 2025 19:46:50 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=f61f75771f95b59fdbc6ebd71b8da9407374ad44

commit f61f75771f95b59fdbc6ebd71b8da9407374ad44
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-08-04 19:38:07 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-08-04 19:38:07 +0000

    ctld: Cleanups to parse_addr_port
    
    - Reimplement the address parsing logic using std::string operations
      instead of C string parsing.
    
    - Return a freebsd::addrinfo_up instance holding the allocated
      struct addrinfo chain.
    
    Sponsored by:   Chelsio Communications
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1794
---
 usr.sbin/ctld/ctld.cc | 73 ++++++++++++++++++++++++---------------------------
 1 file changed, 34 insertions(+), 39 deletions(-)

diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc
index b2cf31fff18f..bf700d5b4051 100644
--- a/usr.sbin/ctld/ctld.cc
+++ b/usr.sbin/ctld/ctld.cc
@@ -506,51 +506,41 @@ portal_group_find(const struct conf *conf, const char *name)
 	return (NULL);
 }
 
-static int
-parse_addr_port(char *arg, const char *def_port, struct addrinfo **ai)
+static freebsd::addrinfo_up
+parse_addr_port(const char *address, const char *def_port)
 {
-	struct addrinfo hints;
-	char *str, *addr, *ch;
-	const char *port;
-	int error, colons = 0;
+	struct addrinfo hints, *ai;
+	int error;
 
-	str = arg = strdup(arg);
-	if (arg[0] == '[') {
+	std::string addr(address);
+	std::string port(def_port);
+	if (addr[0] == '[') {
 		/*
 		 * IPv6 address in square brackets, perhaps with port.
 		 */
-		arg++;
-		addr = strsep(&arg, "]");
-		if (arg == NULL) {
-			free(str);
-			return (1);
-		}
-		if (arg[0] == '\0') {
-			port = def_port;
-		} else if (arg[0] == ':') {
-			port = arg + 1;
-		} else {
-			free(str);
-			return (1);
+		addr.erase(0, 1);
+		size_t pos = addr.find(']');
+		if (pos == 0 || pos == addr.npos)
+			return {};
+		if (pos < addr.length() - 1) {
+			port = addr.substr(pos + 1);
+			if (port[0] != ':' || port.length() < 2)
+				return {};
+			port.erase(0, 1);
 		}
+		addr.resize(pos);
 	} else {
 		/*
 		 * Either IPv6 address without brackets - and without
 		 * a port - or IPv4 address.  Just count the colons.
 		 */
-		for (ch = arg; *ch != '\0'; ch++) {
-			if (*ch == ':')
-				colons++;
-		}
-		if (colons > 1) {
-			addr = arg;
-			port = def_port;
-		} else {
-			addr = strsep(&arg, ":");
-			if (arg == NULL)
-				port = def_port;
-			else
-				port = arg;
+		size_t pos = addr.find(':');
+		if (pos != addr.npos && addr.find(':', pos + 1) == addr.npos) {
+			/* Only a single colon at `pos`. */
+			if (pos == addr.length() - 1)
+				return {};
+			port = addr.substr(pos + 1);
+			addr.resize(pos);
 		}
 	}
 
@@ -558,9 +548,10 @@ parse_addr_port(char *arg, const char *def_port, struct addrinfo **ai)
 	hints.ai_family = PF_UNSPEC;
 	hints.ai_socktype = SOCK_STREAM;
 	hints.ai_flags = AI_PASSIVE;
-	error = getaddrinfo(addr, port, &hints, ai);
-	free(str);
-	return ((error != 0) ? 1 : 0);
+	error = getaddrinfo(addr.c_str(), port.c_str(), &hints, &ai);
+	if (error != 0)
+		return {};
+	return freebsd::addrinfo_up(ai);
 }
 
 bool
@@ -572,7 +563,8 @@ portal_group_add_portal(struct portal_group *pg, const char *value, bool iser)
 	portal->p_listen = checked_strdup(value);
 	portal->p_iser = iser;
 
-	if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) {
+	freebsd::addrinfo_up ai = parse_addr_port(portal->p_listen, "3260");
+	if (!ai) {
 		log_warnx("invalid listen address %s", portal->p_listen);
 		portal_delete(portal);
 		return (false);
@@ -583,6 +575,7 @@ portal_group_add_portal(struct portal_group *pg, const char *value, bool iser)
 	 *	those into multiple portals.
 	 */
 
+	portal->p_ai = ai.release();
 	return (true);
 }
 
@@ -598,7 +591,8 @@ isns_new(struct conf *conf, const char *addr)
 	TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next);
 	isns->i_addr = checked_strdup(addr);
 
-	if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) {
+	freebsd::addrinfo_up ai = parse_addr_port(isns->i_addr, "3205");
+	if (!ai) {
 		log_warnx("invalid iSNS address %s", isns->i_addr);
 		isns_delete(isns);
 		return (false);
@@ -609,6 +603,7 @@ isns_new(struct conf *conf, const char *addr)
 	 *	those into multiple servers.
 	 */
 
+	isns->i_ai = ai.release();
 	return (true);
 }