Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f9bc894 authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

iscsi-target: Fix discovery with INADDR_ANY and IN6ADDR_ANY_INIT



This patch addresses a bug with sendtargets discovery where INADDR_ANY (0.0.0.0)
+ IN6ADDR_ANY_INIT ([0:0:0:0:0:0:0:0]) network portals where incorrectly being
reported back to initiators instead of the address of the connecting interface.
To address this, save local socket ->getname() output during iscsi login setup,
and makes iscsit_build_sendtargets_response() return these TargetAddress keys
when INADDR_ANY or IN6ADDR_ANY_INIT portals are in use.

Reported-by: default avatarDax Kelson <dkelson@gurulabs.com>
Reported-by: default avatarAndy Grover <agrover@redhat.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 4949314c
Loading
Loading
Loading
Loading
+33 −4
Original line number Diff line number Diff line
@@ -3164,6 +3164,30 @@ static int iscsit_send_task_mgt_rsp(
	return 0;
}

static bool iscsit_check_inaddr_any(struct iscsi_np *np)
{
	bool ret = false;

	if (np->np_sockaddr.ss_family == AF_INET6) {
		const struct sockaddr_in6 sin6 = {
			.sin6_addr = IN6ADDR_ANY_INIT };
		struct sockaddr_in6 *sock_in6 =
			 (struct sockaddr_in6 *)&np->np_sockaddr;

		if (!memcmp(sock_in6->sin6_addr.s6_addr,
				sin6.sin6_addr.s6_addr, 16))
			ret = true;
	} else {
		struct sockaddr_in * sock_in =
			(struct sockaddr_in *)&np->np_sockaddr;

		if (sock_in->sin_addr.s_addr == INADDR_ANY)
			ret = true;
	}

	return ret;
}

static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
{
	char *payload = NULL;
@@ -3213,12 +3237,17 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
			spin_lock(&tpg->tpg_np_lock);
			list_for_each_entry(tpg_np, &tpg->tpg_gnp_list,
						tpg_np_list) {
				struct iscsi_np *np = tpg_np->tpg_np;
				bool inaddr_any = iscsit_check_inaddr_any(np);

				len = sprintf(buf, "TargetAddress="
					"%s%s%s:%hu,%hu",
					(tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ?
					"[" : "", tpg_np->tpg_np->np_ip,
					(tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ?
					"]" : "", tpg_np->tpg_np->np_port,
					(np->np_sockaddr.ss_family == AF_INET6) ?
					"[" : "", (inaddr_any == false) ?
						np->np_ip : conn->local_ip,
					(np->np_sockaddr.ss_family == AF_INET6) ?
					"]" : "", (inaddr_any == false) ?
						np->np_port : conn->local_port,
					tpg->tpgt);
				len += 1;

+2 −0
Original line number Diff line number Diff line
@@ -508,6 +508,7 @@ struct iscsi_conn {
	u16			cid;
	/* Remote TCP Port */
	u16			login_port;
	u16			local_port;
	int			net_size;
	u32			auth_id;
#define CONNFLAG_SCTP_STRUCT_FILE			0x01
@@ -527,6 +528,7 @@ struct iscsi_conn {
	unsigned char		bad_hdr[ISCSI_HDR_LEN];
#define IPV6_ADDRESS_SPACE				48
	unsigned char		login_ip[IPV6_ADDRESS_SPACE];
	unsigned char		local_ip[IPV6_ADDRESS_SPACE];
	int			conn_usage_count;
	int			conn_waiting_on_uc;
	atomic_t		check_immediate_queue;
+27 −4
Original line number Diff line number Diff line
@@ -615,8 +615,8 @@ static int iscsi_post_login_handler(
		}

		pr_debug("iSCSI Login successful on CID: %hu from %s to"
			" %s:%hu,%hu\n", conn->cid, conn->login_ip, np->np_ip,
				np->np_port, tpg->tpgt);
			" %s:%hu,%hu\n", conn->cid, conn->login_ip,
			conn->local_ip, conn->local_port, tpg->tpgt);

		list_add_tail(&conn->conn_list, &sess->sess_conn_list);
		atomic_inc(&sess->nconn);
@@ -658,7 +658,8 @@ static int iscsi_post_login_handler(
	sess->session_state = TARG_SESS_STATE_LOGGED_IN;

	pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n",
		conn->cid, conn->login_ip, np->np_ip, np->np_port, tpg->tpgt);
		conn->cid, conn->login_ip, conn->local_ip, conn->local_port,
		tpg->tpgt);

	spin_lock_bh(&sess->conn_lock);
	list_add_tail(&conn->conn_list, &sess->sess_conn_list);
@@ -1020,6 +1021,18 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
		snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
				&sock_in6.sin6_addr.in6_u);
		conn->login_port = ntohs(sock_in6.sin6_port);

		if (conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in6, &err, 0) < 0) {
			pr_err("sock_ops->getname() failed.\n");
			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
					ISCSI_LOGIN_STATUS_TARGET_ERROR);
			goto new_sess_out;
		}
		snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
				&sock_in6.sin6_addr.in6_u);
		conn->local_port = ntohs(sock_in6.sin6_port);

	} else {
		memset(&sock_in, 0, sizeof(struct sockaddr_in));

@@ -1032,6 +1045,16 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
		}
		sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
		conn->login_port = ntohs(sock_in.sin_port);

		if (conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in, &err, 0) < 0) {
			pr_err("sock_ops->getname() failed.\n");
			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
					ISCSI_LOGIN_STATUS_TARGET_ERROR);
			goto new_sess_out;
		}
		sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
		conn->local_port = ntohs(sock_in.sin_port);
	}

	conn->network_transport = np->np_network_transport;
@@ -1039,7 +1062,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
	pr_debug("Received iSCSI login request from %s on %s Network"
			" Portal %s:%hu\n", conn->login_ip,
		(conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
			np->np_ip, np->np_port);
			conn->local_ip, conn->local_port);

	pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
	conn->conn_state	= TARG_CONN_STATE_IN_LOGIN;