From dfecf611a1bb46dfe19fc5329a23ef12c1f0591d Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Mon, 12 Aug 2013 11:26:28 -0700 Subject: 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 Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 8 +++----- drivers/target/iscsi/iscsi_target_login.c | 16 ++++++++++++---- drivers/target/iscsi/iscsi_target_stat.c | 8 +------- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index f73da43cdf9e..c4aeac314b2e 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3444,12 +3444,10 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) bool inaddr_any = iscsit_check_inaddr_any(np); len = sprintf(buf, "TargetAddress=" - "%s%s%s:%hu,%hu", - (np->np_sockaddr.ss_family == AF_INET6) ? - "[" : "", (inaddr_any == false) ? + "%s:%hu,%hu", + (inaddr_any == false) ? np->np_ip : conn->local_ip, - (np->np_sockaddr.ss_family == AF_INET6) ? - "]" : "", (inaddr_any == false) ? + (inaddr_any == false) ? np->np_port : conn->local_port, tpg->tpgt); len += 1; diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 76cf1cd62e29..0e85238bdf48 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -1007,16 +1007,24 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in6, &err, 1); if (!rc) { - snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", - &sock_in6.sin6_addr.in6_u); + if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) + snprintf(conn->login_ip, sizeof(conn->login_ip), "[%pI6c]", + &sock_in6.sin6_addr.in6_u); + else + snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI4", + &sock_in6.sin6_addr.s6_addr32[3]); conn->login_port = ntohs(sock_in6.sin6_port); } rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in6, &err, 0); if (!rc) { - snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", - &sock_in6.sin6_addr.in6_u); + if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) + snprintf(conn->local_ip, sizeof(conn->local_ip), "[%pI6c]", + &sock_in6.sin6_addr.in6_u); + else + snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI4", + &sock_in6.sin6_addr.s6_addr32[3]); conn->local_port = ntohs(sock_in6.sin6_port); } } else { diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index 464b4206a51e..899bdb423ff3 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -432,13 +432,7 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( int ret; spin_lock(&lstat->lock); - if (lstat->last_intr_fail_ip_family == AF_INET6) { - ret = snprintf(page, PAGE_SIZE, "[%s]\n", - lstat->last_intr_fail_ip_addr); - } else { - ret = snprintf(page, PAGE_SIZE, "%s\n", - lstat->last_intr_fail_ip_addr); - } + ret = snprintf(page, PAGE_SIZE, "%s\n", lstat->last_intr_fail_ip_addr); spin_unlock(&lstat->lock); return ret; -- cgit v1.2.3