Module Name:    src
Committed By:   mlelstv
Date:           Sat Nov 25 08:06:02 UTC 2023

Modified Files:
        src/sbin/iscsictl: iscsic_parse.c
        src/sbin/iscsid: iscsid_driverif.c

Log Message:
Parse IPv6 targets and handle IPv6 addresses.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sbin/iscsictl/iscsic_parse.c
cvs rdiff -u -r1.8 -r1.9 src/sbin/iscsid/iscsid_driverif.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/iscsictl/iscsic_parse.c
diff -u src/sbin/iscsictl/iscsic_parse.c:1.4 src/sbin/iscsictl/iscsic_parse.c:1.5
--- src/sbin/iscsictl/iscsic_parse.c:1.4	Fri Dec  3 13:27:38 2021
+++ src/sbin/iscsictl/iscsic_parse.c	Sat Nov 25 08:06:02 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsic_parse.c,v 1.4 2021/12/03 13:27:38 andvar Exp $	*/
+/*	$NetBSD: iscsic_parse.c,v 1.5 2023/11/25 08:06:02 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@@ -48,50 +48,62 @@
 STATIC void
 get_address(iscsi_portal_address_t * portal, char *str, char *arg)
 {
-	char *sp, *sp2;
+	char *sp;
 	int val;
 
 	if (!str || !*str)
 		arg_error(arg, "Address is missing");
 
-	/* is there a port? don't check inside square brackets (IPv6 addr) */
-	for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) {
-		if (*sp == '[')
-			val = 1;
-		else if (*sp == ']')
-			val = 0;
-	}
-
-	/* */
-	if (*sp) {
-		for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++);
-		/* if there's a second colon, assume it's an unbracketed IPv6 address */
-		if (!*sp2) {
-			/* truncate source, that's the address */
-			*sp++ = '\0';
-			if (sscanf(sp, "%d", &val) != 1)
-				arg_error(arg, "Bad address format: Expected port number");
-			if (val < 0 || val > 0xffff)
-				arg_error(arg, "Bad address format: Port number out of range");
-			portal->port = (uint16_t) val;
-		}
-		/* is there a group tag? */
-		for (; isdigit((unsigned char)*sp); sp++);
-		if (*sp && *sp != ',')
-			arg_error(arg, "Bad address format: Extra character(s) '%c'", *sp);
-	} else
-		for (sp = str + 1; *sp && *sp != ','; sp++);
-
-	if (*sp) {
+	/* Parse and strip trailing group tag */
+	sp = strrchr(str, ',');
+	if (sp != NULL) {
 		if (sscanf(sp + 1, "%d", &val) != 1)
 			arg_error(arg, "Bad address format: Expected group tag");
 		if (val < 0 || val > 0xffff)
 			arg_error(arg, "Bad address format: Group tag out of range");
 		portal->group_tag = (uint16_t) val;
-		/* truncate source, that's the address */
 		*sp = '\0';
 	}
-	/* only check length, don't verify correct format (too many possibilities) */
+
+	/* Skip over bracketed IPv6 address */
+	sp = strchr(str, ']');
+	if (sp != NULL)
+		sp++;
+	else
+		sp = str;
+
+	/* Parse and strip trailing port number */
+	sp = strchr(sp, ':');
+	if (sp != NULL) {
+		if (strchr(sp + 1, ':') != NULL) {
+			/*
+			 *  If there's a second colon, assume
+			 *  it's an unbracketed IPv6 address
+			 */
+			portal->port = 0;
+		} else {
+			if (sscanf(sp + 1, "%d", &val) != 1)
+				arg_error(arg, "Bad address format: Expected port number");
+			if (val < 0 || val > 0xffff)
+				arg_error(arg, "Bad address format: Port number ut  of range");
+			portal->port = (uint16_t) val;
+			*sp = '\0';
+		}
+	}
+
+	/* Remove brackets */
+	if (*str == '[') {
+		sp = strchr(str, ']');
+		if (sp != NULL && !*(sp+1)) {
+			str = str + 1;
+			*sp = '\0';
+		}
+	}
+
+	/*
+	 * only check length, don't verify correct format
+	 * (too many possibilities)
+	 */
 	if (strlen(str) >= sizeof(portal->address))
 		arg_error(arg, "Bad address format: Address string too long");
 

Index: src/sbin/iscsid/iscsid_driverif.c
diff -u src/sbin/iscsid/iscsid_driverif.c:1.8 src/sbin/iscsid/iscsid_driverif.c:1.9
--- src/sbin/iscsid/iscsid_driverif.c:1.8	Sun May 29 13:35:45 2016
+++ src/sbin/iscsid/iscsid_driverif.c	Sat Nov 25 08:06:02 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsid_driverif.c,v 1.8 2016/05/29 13:35:45 mlelstv Exp $	*/
+/*	$NetBSD: iscsid_driverif.c,v 1.9 2023/11/25 08:06:02 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@@ -98,23 +98,29 @@ set_node_name(iscsid_set_node_name_req_t
 static int
 bind_socket(int sock, uint8_t * addr)
 {
-	struct sockaddr_in serverAddress;
-	struct hostent *host;
+	struct addrinfo hints, *ai, *ai0;
+	int ret = FALSE;
 
 	DEB(8, ("Binding to <%s>", addr));
-	(void) memset(&serverAddress, 0x0, sizeof(serverAddress));
-	host = gethostbyname((char *)addr);
-	if (host == NULL)
-		return FALSE;
-	if (host->h_length > (int)sizeof(serverAddress.sin_addr))
-		return FALSE;
-	serverAddress.sin_family = host->h_addrtype;
-	serverAddress.sin_port = 0;
-	serverAddress.sin_len = host->h_length;
-	memcpy(&serverAddress.sin_addr, host->h_addr_list[0], host->h_length);
+	
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_flags = AI_PASSIVE;
+	if (getaddrinfo((char *)addr, NULL, &hints, &ai0))
+		return ret;
+
+	for (ai = ai0; ai; ai = ai->ai_next) {
+		if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0)
+			continue;
+
+		listen(sock, 5);
+		ret = TRUE;
+		break;
+	}
+	freeaddrinfo(ai0);
 
-	return bind(sock, (struct sockaddr *)(void *)&serverAddress,
-				(socklen_t)sizeof(serverAddress)) >= 0;
+	return ret;
 }
 
 
@@ -183,14 +189,13 @@ make_connection(session_t * sess, iscsid
 	target_t *target;
 	portal_t *portal = NULL;
 	iscsi_portal_address_t *addr;
-	struct sockaddr_in serverAddress;
-	struct hostent *host;
+	struct addrinfo hints, *ai, *ai0;
+	char portnum[6];
 	initiator_t *init;
 
 	DEB(9, ("Make Connection sess=%p, req=%p, res=%p, stid=%p",
 			 sess, req, res, stid));
 	(void) memset(&loginp, 0x0, sizeof(loginp));
-	(void) memset(&serverAddress, 0x0, sizeof(serverAddress));
 
 	/* find the target portal */
 	if (stid != NULL) {
@@ -277,69 +282,72 @@ make_connection(session_t * sess, iscsid
 	/* translate target address */
 	DEB(8, ("Connecting to <%s>, port %d", addr->address, addr->port));
 
-	host = gethostbyname((char *)addr->address);
-	if (host == NULL) {
-		switch (h_errno) {
-		case HOST_NOT_FOUND:
-			res->status = ISCSID_STATUS_HOST_NOT_FOUND;
-			break;
-		case TRY_AGAIN:
-			res->status = ISCSID_STATUS_HOST_TRY_AGAIN;
-			break;
-		default:
-			res->status = ISCSID_STATUS_HOST_ERROR;
-			break;
-		}
-		return NULL;
-	}
-	if (host->h_length > (int)sizeof(serverAddress.sin_addr)) {
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	snprintf(portnum, sizeof(portnum), "%u", addr->port);
+	ret = getaddrinfo((char *)addr->address, portnum, &hints, &ai0);
+	switch (ret) {
+	case 0:
+		break;
+	case EAI_NODATA:
+		res->status = ISCSID_STATUS_HOST_NOT_FOUND;
+		break;
+	case EAI_AGAIN:
+		res->status = ISCSID_STATUS_HOST_TRY_AGAIN;
+		break;
+	default:
 		res->status = ISCSID_STATUS_HOST_ERROR;
-		return NULL;
+		break;
 	}
-	DEB(8, ("Gethostbyname OK, addrtype %d, len %d, addr %x",
-			host->h_addrtype, host->h_length, *((int *) host->h_addr_list[0])));
-	serverAddress.sin_family = host->h_addrtype;
-	serverAddress.sin_port = htons((addr->port)
-		? addr->port : ISCSI_DEFAULT_PORT);
-	serverAddress.sin_len = host->h_length;
-	memcpy(&serverAddress.sin_addr, host->h_addr_list[0], host->h_length);
 
 	/* alloc the connection structure */
 	conn = calloc(1, sizeof(*conn));
 	if (conn == NULL) {
+		freeaddrinfo(ai0);
 		res->status = ISCSID_STATUS_NO_RESOURCES;
 		return NULL;
 	}
-	/* create and connect the socket */
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0) {
-		free(conn);
-		res->status = ISCSID_STATUS_SOCKET_ERROR;
-		return NULL;
-	}
 
-	if (init) {
-		if (!bind_socket(sock, init->address)) {
+	res->status = ISCSID_STATUS_HOST_ERROR;
+	sock = -1;
+	for (ai = ai0; ai; ai = ai->ai_next) {
+		/* create and connect the socket */
+		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (sock < 0) {
+			res->status = ISCSID_STATUS_SOCKET_ERROR;
+			break;
+		}
+
+		if (init) {
+			if (!bind_socket(sock, init->address)) {
+				close(sock);
+				res->status = ISCSID_STATUS_INITIATOR_BIND_ERROR;
+				break;
+			}
+		}
+
+		DEB(8, ("Connecting socket"));
+		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
 			close(sock);
-			free(conn);
-			res->status = ISCSID_STATUS_INITIATOR_BIND_ERROR;
-			return NULL;
+			res->status = ISCSID_STATUS_CONNECT_ERROR;
+			continue;
 		}
+
+		res->status = ISCSID_STATUS_SUCCESS;
+		break;
 	}
+	freeaddrinfo(ai0);
 
-	DEB(8, ("Connecting socket"));
-	if (connect(sock, (struct sockaddr *)(void *)&serverAddress,
-		(socklen_t)sizeof(serverAddress)) < 0) {
-		close(sock);
+	if (sock < 0) {
 		free(conn);
-		res->status = ISCSID_STATUS_CONNECT_ERROR;
 		DEB(1, ("Connecting to socket failed (error %d), returning %d",
 				errno, res->status));
 		return NULL;
 	}
+
 	/* speed up socket processing */
 	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, (socklen_t)sizeof(yes));
-
 	/* setup login parameter structure */
 	loginp.socket = sock;
 	if (target->TargetName[0]) {
@@ -506,11 +514,10 @@ event_recover_connection(uint32_t sid, u
 	portal_t *portal;
 	initiator_t *init;
 	iscsi_portal_address_t *addr;
-	struct sockaddr_in serverAddress;
-	struct hostent *host;
+	struct addrinfo hints, *ai, *ai0;
+	char portnum[6];
 
 	DEB(1, ("Event_Recover_Connection sid=%d, cid=%d", sid, cid));
-	(void) memset(&serverAddress, 0x0, sizeof(serverAddress));
 
 	LOCK_SESSIONS;
 
@@ -543,47 +550,53 @@ event_recover_connection(uint32_t sid, u
 	DEB(1, ("Event_Recover_Connection Connecting to <%s>, port %d",
 			addr->address, addr->port));
 
-	if ((host = gethostbyname((char *)addr->address)) == NULL) {
-		DEB(1, ("GetHostByName failed (error %d)", h_errno));
-		return;
-	}
-	if (host->h_length > (int)sizeof(serverAddress.sin_addr)) {
-		DEB(1, ("Host address length invalid (%d)", host->h_length));
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	snprintf(portnum, sizeof(portnum), "%u", addr->port);
+	ret = getaddrinfo((char *)addr->address, portnum, &hints, &ai0);
+	if (ret) {
+		DEB(1, ("getaddrinfo failed (%s)", gai_strerror(ret)));
 		return;
 	}
 
-	serverAddress.sin_family = host->h_addrtype;
-	serverAddress.sin_port = htons((addr->port)
-		? addr->port : ISCSI_DEFAULT_PORT);
-	serverAddress.sin_len = host->h_length;
-	memcpy(&serverAddress.sin_addr, host->h_addr_list[0], host->h_length);
+	sock = -1;
+	for (ai = ai0; ai; ai = ai->ai_next) {
 
-	/* create and connect the socket */
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0) {
-		DEB(1, ("Creating socket failed (error %d)", errno));
-		return;
-	}
+		/* create and connect the socket */
+		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (sock < 0) {
+			DEB(1, ("Creating socket failed (error %d)", errno));
+			break;
+		}
 
-	DEB(1, ("recover_connection: Socket = %d", sock));
+		DEB(1, ("recover_connection: Socket = %d", sock));
 
-	if (init) {
-		if (!bind_socket(sock, init->address)) {
-			DEB(1, ("Binding to interface failed (error %d)", errno));
+		if (init) {
+			if (!bind_socket(sock, init->address)) {
+				DEB(1, ("Binding to interface failed (error %d)", errno));
+				close(sock);
+				sock = -1;
+				continue;
+			}
+		}
+
+		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
 			close(sock);
-			return;
+			sock = -1;
+			DEB(1, ("Connecting to socket failed (error %d)", errno));
+			continue;
 		}
+
+		break;
 	}
+	freeaddrinfo(ai0);
 
-	if (connect(sock, (struct sockaddr *)(void *)&serverAddress,
-		(socklen_t)sizeof(serverAddress)) < 0) {
-		DEB(1, ("Connecting to socket failed (error %d)", errno));
-		close(sock);
+	if (sock < 0)
 		return;
-	}
+
 	/* speed up socket processing */
 	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, (socklen_t)sizeof(yes));
-
 	conn->loginp.socket = sock;
 	conn->loginp.status = 0;
 	ret = ioctl(driver, ISCSI_RESTORE_CONNECTION, &conn->loginp);
@@ -631,7 +644,6 @@ log_in(iscsid_login_req_t * req, iscsid_
 	UNLOCK_SESSIONS;
 }
 
-
 /*
  * add_connection:
  *    Handle ADD_CONNECTION request: Log secondary connection into given portal.

Reply via email to