Parse IPv6 targets and handle IPv6 addresses.

pull/20/head
mlelstv 2023-11-25 08:06:02 +00:00
parent bee81b247f
commit 7f1bdbd373
2 changed files with 157 additions and 133 deletions

View File

@ -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");

View File

@ -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 * par)
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;
return bind(sock, (struct sockaddr *)(void *)&serverAddress,
(socklen_t)sizeof(serverAddress)) >= 0;
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 ret;
}
@ -183,14 +189,13 @@ make_connection(session_t * sess, iscsid_login_req_t * req,
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_login_req_t * req,
/* 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);
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);
res->status = ISCSID_STATUS_CONNECT_ERROR;
continue;
}
res->status = ISCSID_STATUS_SUCCESS;
break;
}
freeaddrinfo(ai0);
if (sock < 0) {
free(conn);
res->status = ISCSID_STATUS_SOCKET_ERROR;
return NULL;
}
if (init) {
if (!bind_socket(sock, init->address)) {
close(sock);
free(conn);
res->status = ISCSID_STATUS_INITIATOR_BIND_ERROR;
return NULL;
}
}
DEB(8, ("Connecting socket"));
if (connect(sock, (struct sockaddr *)(void *)&serverAddress,
(socklen_t)sizeof(serverAddress)) < 0) {
close(sock);
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, uint32_t cid)
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, uint32_t cid)
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;
}
DEB(1, ("recover_connection: Socket = %d", sock));
if (init) {
if (!bind_socket(sock, init->address)) {
DEB(1, ("Binding to interface failed (error %d)", errno));
close(sock);
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;
}
}
if (connect(sock, (struct sockaddr *)(void *)&serverAddress,
(socklen_t)sizeof(serverAddress)) < 0) {
DEB(1, ("Connecting to socket failed (error %d)", errno));
close(sock);
return;
DEB(1, ("recover_connection: Socket = %d", sock));
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);
sock = -1;
DEB(1, ("Connecting to socket failed (error %d)", errno));
continue;
}
break;
}
freeaddrinfo(ai0);
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_response_t * res)
UNLOCK_SESSIONS;
}
/*
* add_connection:
* Handle ADD_CONNECTION request: Log secondary connection into given portal.