Parse IPv6 targets and handle IPv6 addresses.
This commit is contained in:
parent
bee81b247f
commit
7f1bdbd373
|
@ -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");
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue