From 84f48fe6a688380e6d711c5fdef9bc36fa10bf93 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Thu, 24 Feb 2022 14:47:28 +0300 Subject: [PATCH] iscsi-scstd: Allow to specify multiple addresses the server should listen on Add the opportunity to globally specify multiple addresses, which iSCSI/iSER portal will listen on. There is a way to specify the addresses for a target, on which portals it will be available, using the allowed_portal parameter. There is also a way to set this globally via the iscsi-scstd --address parameter. The problem is that the last option allows you to specify only one local address. So extend this functionality to specify more then one address. Also increase the maximum number of listening addresses to 32. Signed-off-by: Aleksandr Dyadyushkin --- iscsi-scst/doc/manpages/iscsi-scstd.8 | 4 +- iscsi-scst/usr/iscsi_scstd.c | 189 ++++++++++++++++---------- iscsi-scst/usr/iscsid.h | 3 +- 3 files changed, 122 insertions(+), 74 deletions(-) diff --git a/iscsi-scst/doc/manpages/iscsi-scstd.8 b/iscsi-scst/doc/manpages/iscsi-scstd.8 index 6167a65fe..895db2aea 100644 --- a/iscsi-scst/doc/manpages/iscsi-scstd.8 +++ b/iscsi-scst/doc/manpages/iscsi-scstd.8 @@ -42,8 +42,8 @@ Act as a normal application which uses a console. .BI \-g\ GID ,\ \-\-gid= GID Specify running group id, default is current gid. .TP -.BI \-a\ address ,\ \-\-address= address -Specify on which local address the server should listen, default is any. +.BI \-a\ address\ ... ,\ \-\-address= address\ ... +Specify on which space-separated list of local addresses the server should listen, default is any. .TP .BI \-p\ port ,\ \-\-port= port Specify on which port the server should listen, default is 3260. diff --git a/iscsi-scst/usr/iscsi_scstd.c b/iscsi-scst/usr/iscsi_scstd.c index 80df257c1..58c3705db 100644 --- a/iscsi-scst/usr/iscsi_scstd.c +++ b/iscsi-scst/usr/iscsi_scstd.c @@ -40,7 +40,7 @@ #include "iscsid.h" #include "iscsi_adm.h" -static char *server_address; +static char *server_addresses[ADDR_MAX]; uint16_t server_port = ISCSI_LISTEN_PORT; struct pollfd poll_array[POLL_MAX]; @@ -79,13 +79,13 @@ static void usage(int status) iSCSI target daemon.\n\ -c, --config=[path] Execute in the config file.\n"); printf("\ - -f, --foreground make the program run in the foreground\n\ - -d, --debug debuglevel print debugging information\n\ - -u, --uid=uid run as uid, default is current user\n\ - -g, --gid=gid run as gid, default is current user group\n\ - -a, --address=address listen on specified local address instead of all\n\ - -p, --port=port listen on specified port instead of 3260\n\ - -h, --help display this help and exit\n\ + -f, --foreground make the program run in the foreground\n\ + -d, --debug debuglevel print debugging information\n\ + -u, --uid=uid run as uid, default is current user\n\ + -g, --gid=gid run as gid, default is current user group\n\ + -a, --address=address ... listen on specified space-separated list of local address instead of all\n\ + -p, --port=port listen on specified port instead of 3260\n\ + -h, --help display this help and exit\n\ "); } exit(1); @@ -103,7 +103,7 @@ static void create_listen_socket(struct pollfd *array) { struct addrinfo hints, *res, *res0; char servname[64]; - int i, sock, opt, rc; + int i, k, sock, opt, rc; memset(servname, 0, sizeof(servname)); snprintf(servname, sizeof(servname), "%d", server_port); @@ -112,59 +112,75 @@ static void create_listen_socket(struct pollfd *array) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; - rc = getaddrinfo(server_address, servname, &hints, &res0); - if (rc != 0) { - log_error("Unable to get address info (%s)!", - get_error_str(rc)); - exit(1); - } - i = 0; - for (res = res0; res && i < LISTEN_MAX; res = res->ai_next) { - sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sock < 0) { - log_error("Unable to create server socket (%s) %d %d %d!", - strerror(errno), res->ai_family, - res->ai_socktype, res->ai_protocol); - continue; + for (k = 0; k < ADDR_MAX; k++) { + char *server_address; + + server_address = server_addresses[k]; + if (k > 0 && server_address == NULL) + break; + + if (i == LISTEN_MAX) { + log_error("Cannot handle address %s! Too many were specified.", server_address); + exit(1); } - sock_set_keepalive(sock, 50); - - opt = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) - log_warning("Unable to set SO_REUSEADDR on server socket (%s)!", - strerror(errno)); - opt = 1; - if (res->ai_family == AF_INET6 && - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))) { - log_error("Unable to restrict IPv6 socket (%s)", strerror(errno)); - close(sock); - continue; + rc = getaddrinfo(server_address, servname, &hints, &res0); + if (rc != 0) { + log_error("Unable to get address info [%s] (%s)!", + server_address, get_error_str(rc)); + exit(1); } - if (bind(sock, res->ai_addr, res->ai_addrlen)) { - log_error("Unable to bind server socket (%s)!", strerror(errno)); - close(sock); - continue; + for (res = res0; res && i < LISTEN_MAX; res = res->ai_next) { + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + log_error("Unable to create server socket (%s) %d %d %d!", + strerror(errno), res->ai_family, + res->ai_socktype, res->ai_protocol); + continue; + } + + sock_set_keepalive(sock, 50); + + opt = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) + log_warning("Unable to set SO_REUSEADDR on server socket (%s)!", + strerror(errno)); + opt = 1; + if (res->ai_family == AF_INET6 && + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))) { + log_error("Unable to restrict IPv6 socket (%s)", strerror(errno)); + close(sock); + continue; + } + + if (bind(sock, res->ai_addr, res->ai_addrlen)) { + log_error("Unable to bind server socket (%s)!", strerror(errno)); + close(sock); + continue; + } + + if (listen(sock, INCOMING_MAX)) { + log_error("Unable to listen to server socket (%s)!", strerror(errno)); + close(sock); + continue; + } + + set_non_blocking(sock); + + array[i].fd = sock; + array[i].events = POLLIN; + + i++; } - if (listen(sock, INCOMING_MAX)) { - log_error("Unable to listen to server socket (%s)!", strerror(errno)); - close(sock); - continue; - } + if (res) + log_error("Unable to listen on all available sockets."); - set_non_blocking(sock); - - array[i].fd = sock; - array[i].events = POLLIN; - - i++; + freeaddrinfo(res0); } - freeaddrinfo(res0); - if (i == 0) exit(1); } @@ -226,7 +242,8 @@ static void create_iser_listen_socket(struct pollfd *array) { struct addrinfo hints, *res, *res0; char servname[64]; - int rc, i; + char *server_address; + int rc, i, k; int iser_fd; struct isert_addr_info info; @@ -252,27 +269,42 @@ static void create_iser_listen_socket(struct pollfd *array) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; - rc = getaddrinfo(server_address, servname, &hints, &res0); - if (rc != 0) { - log_error("Unable to get address info (%s)!", - get_error_str(rc)); - exit(1); - } - i = 0; - for (res = res0; res && i < ISERT_MAX_PORTALS; res = res->ai_next) { - memcpy(&info.addr, res->ai_addr, res->ai_addrlen); - info.addr_len = res->ai_addrlen; + for (k = 0; k < ADDR_MAX; k++) { + server_address = server_addresses[k]; - rc = ioctl(iser_fd, SET_LISTEN_ADDR, &info); - if (rc != 0) { - log_error("Unable to set listen address (%s)!", - strerror(errno)); + if (k > 0 && server_address == NULL) + break; + + if (i == ISERT_MAX_PORTALS) { + log_error("iSER: Cannot handle address %s! Too many were specified.", server_address); + exit(1); } - ++i; - } - freeaddrinfo(res0); + rc = getaddrinfo(server_address, servname, &hints, &res0); + if (rc != 0) { + log_error("iSER: Unable to get address info[%s] (%s)!", + server_address, get_error_str(rc)); + exit(1); + } + + for (res = res0; res && i < ISERT_MAX_PORTALS; res = res->ai_next) { + memcpy(&info.addr, res->ai_addr, res->ai_addrlen); + info.addr_len = res->ai_addrlen; + + rc = ioctl(iser_fd, SET_LISTEN_ADDR, &info); + if (rc != 0) { + log_error("iSER: Unable to set listen address (%s)!", + strerror(errno)); + } + ++i; + } + + if (res) + log_error("iSER: Unable to listen on all available sockets."); + + freeaddrinfo(res0); + } } static int iser_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) @@ -868,13 +900,28 @@ int main(int argc, char **argv) case 'g': gid = strtoul(optarg, NULL, 0); break; - case 'a': + case 'a': { + char *server_address, *token; + int i = 0; + server_address = strdup(optarg); if (server_address == NULL) { perror("strdup failed"); exit(-1); } + + token = strtok(server_address, " "); + + while ((i < ADDR_MAX) && token) { + log_debug(0, "Address to listen: %s\n", token); + server_addresses[i] = token; + + i++; + token = strtok(NULL, " "); + } + break; + } case 'p': server_port = (uint16_t)strtoul(optarg, NULL, 0); break; diff --git a/iscsi-scst/usr/iscsid.h b/iscsi-scst/usr/iscsid.h index 278d942df..2143b2bb1 100644 --- a/iscsi-scst/usr/iscsid.h +++ b/iscsi-scst/usr/iscsid.h @@ -224,7 +224,8 @@ struct target { extern int ctrl_fd; extern int conn_blocked; -#define LISTEN_MAX 8 +#define ADDR_MAX 32 +#define LISTEN_MAX 32 #define INCOMING_MAX 256 enum {