Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iscsi-target: ST response on IN6ADDR_ANY socket

Odd little issue, found that if you create an IPv6 portal bound to the
IN6ADDR_ANY wildcard address it will accept IPv4 connections (as long as
bindv6only isn't set globally) but respond to SendTargets requests with
an IPv4-mapped IPv6 address.

Example over loopback:

In targetcli create a wildcard IPv6 portal
/iscsi/iqn.../portals/> create ::
Which should create a portal [::]:3260

Initiate SendTargets discovery to the portal using an IPv4 address
# iscsiadm -m discovery -t st -p 127.0.0.1
The response formats TargetAddress as [::ffff:127.0.0.1]:3260,1

This still works and uses v4 on the network between two v6 sockets, but
only if the initiator supports IPv6 with v4-mapped addresses.

This change detects v4-mapped address on v6 sockets for the wildcard
case, and instead formats the TargetAddress response as an IPv4 address.

In order to not further complicate iscsit_build_sendtargets_response,
I've actually simplified it by moving the bracket wrapping of IPv6
address into iscsit_accept_np where local_ip and login_ip strings are
set. That also simplifies iscsi_stat_tgt_attr_show_attr_fail_intr_addr.

Side effect of the string format change is that
lio_target_nacl_show_info will now print login_ip bracket wrapped for
IPv6 connections, as will a few debug prints.

Signed-off-by: Chris Leech <cleech@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>

authored by

Chris Leech and committed by
Nicholas Bellinger
dfecf611 de04a8aa

+16 -16
+3 -5
drivers/target/iscsi/iscsi_target.c
··· 3444 3444 bool inaddr_any = iscsit_check_inaddr_any(np); 3445 3445 3446 3446 len = sprintf(buf, "TargetAddress=" 3447 - "%s%s%s:%hu,%hu", 3448 - (np->np_sockaddr.ss_family == AF_INET6) ? 3449 - "[" : "", (inaddr_any == false) ? 3447 + "%s:%hu,%hu", 3448 + (inaddr_any == false) ? 3450 3449 np->np_ip : conn->local_ip, 3451 - (np->np_sockaddr.ss_family == AF_INET6) ? 3452 - "]" : "", (inaddr_any == false) ? 3450 + (inaddr_any == false) ? 3453 3451 np->np_port : conn->local_port, 3454 3452 tpg->tpgt); 3455 3453 len += 1;
+12 -4
drivers/target/iscsi/iscsi_target_login.c
··· 1007 1007 rc = conn->sock->ops->getname(conn->sock, 1008 1008 (struct sockaddr *)&sock_in6, &err, 1); 1009 1009 if (!rc) { 1010 - snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", 1011 - &sock_in6.sin6_addr.in6_u); 1010 + if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) 1011 + snprintf(conn->login_ip, sizeof(conn->login_ip), "[%pI6c]", 1012 + &sock_in6.sin6_addr.in6_u); 1013 + else 1014 + snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI4", 1015 + &sock_in6.sin6_addr.s6_addr32[3]); 1012 1016 conn->login_port = ntohs(sock_in6.sin6_port); 1013 1017 } 1014 1018 1015 1019 rc = conn->sock->ops->getname(conn->sock, 1016 1020 (struct sockaddr *)&sock_in6, &err, 0); 1017 1021 if (!rc) { 1018 - snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", 1019 - &sock_in6.sin6_addr.in6_u); 1022 + if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) 1023 + snprintf(conn->local_ip, sizeof(conn->local_ip), "[%pI6c]", 1024 + &sock_in6.sin6_addr.in6_u); 1025 + else 1026 + snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI4", 1027 + &sock_in6.sin6_addr.s6_addr32[3]); 1020 1028 conn->local_port = ntohs(sock_in6.sin6_port); 1021 1029 } 1022 1030 } else {
+1 -7
drivers/target/iscsi/iscsi_target_stat.c
··· 432 432 int ret; 433 433 434 434 spin_lock(&lstat->lock); 435 - if (lstat->last_intr_fail_ip_family == AF_INET6) { 436 - ret = snprintf(page, PAGE_SIZE, "[%s]\n", 437 - lstat->last_intr_fail_ip_addr); 438 - } else { 439 - ret = snprintf(page, PAGE_SIZE, "%s\n", 440 - lstat->last_intr_fail_ip_addr); 441 - } 435 + ret = snprintf(page, PAGE_SIZE, "%s\n", lstat->last_intr_fail_ip_addr); 442 436 spin_unlock(&lstat->lock); 443 437 444 438 return ret;