Blob Blame History Raw
From: Paulo Alcantara <pc@cjr.nz>
Date: Tue, 4 Oct 2022 18:41:36 -0300
Subject: [PATCH] cifs: set resolved ip in sockaddr
Git-commit: 6d740164d8903e6a0e98c30f80fac6af19ce0a21
References: bsc#1190317
Patch-mainline: v6.2-rc1

[ematsumiya: adjusted cifs_compose_mount_options code in cifs_dfs_ref.c that
 didn't exist in original patch]

All callers from dns_resolve_server_name_to_ip() used to convert the
ip addr string back to sockaddr, so do that inside
dns_resolve_server_name_to_ip() and avoid duplicating code.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
Acked-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 fs/cifs/cifs_dfs_ref.c |   18 +++++++++++++++---
 fs/cifs/connect.c      |   28 ++++++++++++----------------
 fs/cifs/dfs_cache.c    |   17 +++++------------
 fs/cifs/dns_resolve.c  |   48 +++++++++++++++++++++++-------------------------
 fs/cifs/dns_resolve.h  |    4 +++-
 fs/cifs/misc.c         |   36 ++++++++++--------------------------
 6 files changed, 68 insertions(+), 83 deletions(-)

--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -146,7 +146,8 @@ char *cifs_compose_mount_options(const c
 	const char *prepath = NULL;
 	int md_len;
 	char *tkn_e;
-	char *srvIP = NULL;
+	char srvIP[INET6_ADDRSTRLEN] = { 0 };
+	struct sockaddr_storage ss;
 	char sep = ',';
 	int off, noff;
 
@@ -179,13 +180,25 @@ char *cifs_compose_mount_options(const c
 		}
 	}
 
-	rc = dns_resolve_server_name_to_ip(name, &srvIP, NULL);
+	rc = dns_resolve_server_name_to_ip(name, (struct sockaddr *)&ss, NULL);
 	if (rc < 0) {
 		cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
 			 __func__, name, rc);
 		goto compose_mount_options_err;
 	}
 
+	switch (ss.ss_family) {
+	case AF_INET:
+		rc = scnprintf(srvIP, INET_ADDRSTRLEN, "%pI4", &((struct sockaddr_in *)&ss)->sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		rc = scnprintf(srvIP, INET6_ADDRSTRLEN, "%pI6", &((struct sockaddr_in6 *)&ss)->sin6_addr.s6_addr);
+		break;
+	}
+
+	if (rc <= 0)
+		memcpy(srvIP, "N/A", 3);
+
 	/*
 	 * In most cases, we'll be building a shorter string than the original,
 	 * but we do have to assume that the address in the ip= option may be
@@ -251,7 +264,6 @@ char *cifs_compose_mount_options(const c
 	/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
 
 compose_mount_options_out:
-	kfree(srvIP);
 	return mountdata;
 
 compose_mount_options_err:
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -364,7 +364,8 @@ static int reconn_set_ipaddr_from_hostna
 {
 	int rc;
 	int len;
-	char *unc, *ipaddr = NULL;
+	char *unc;
+	struct sockaddr_storage ss;
 	time64_t expiry, now;
 	unsigned long ttl = SMB_DNS_RESOLVE_INTERVAL_DEFAULT;
 
@@ -380,7 +381,11 @@ static int reconn_set_ipaddr_from_hostna
 	}
 	scnprintf(unc, len, "\\\\%s", server->hostname);
 
-	rc = dns_resolve_server_name_to_ip(unc, &ipaddr, &expiry);
+	spin_lock(&server->srv_lock);
+	ss = server->dstaddr;
+	spin_unlock(&server->srv_lock);
+
+	rc = dns_resolve_server_name_to_ip(unc, (struct sockaddr *)&ss, &expiry);
 	kfree(unc);
 
 	if (rc < 0) {
@@ -390,22 +395,13 @@ static int reconn_set_ipaddr_from_hostna
 	}
 
 	spin_lock(&server->srv_lock);
-	rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
-				  strlen(ipaddr));
+	memcpy(&server->dstaddr, &ss, sizeof(server->dstaddr));
 	spin_unlock(&server->srv_lock);
-	kfree(ipaddr);
 
-	/* rc == 1 means success here */
-	if (rc) {
-		now = ktime_get_real_seconds();
-		if (expiry && expiry > now)
-			/*
-			 * To make sure we don't use the cached entry, retry 1s
-			 * after expiry.
-			 */
-			ttl = max_t(unsigned long, expiry - now, SMB_DNS_RESOLVE_INTERVAL_MIN) + 1;
-	}
-	rc = !rc ? -1 : 0;
+	now = ktime_get_real_seconds();
+	if (expiry && expiry > now)
+		/* To make sure we don't use the cached entry, retry 1s */
+		ttl = max_t(unsigned long, expiry - now, SMB_DNS_RESOLVE_INTERVAL_MIN) + 1;
 
 requeue_resolve:
 	cifs_dbg(FYI, "%s: next dns resolution scheduled for %lu seconds in the future\n",
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -1311,8 +1311,7 @@ static bool target_share_equal(struct TC
 	char unc[sizeof("\\\\") + SERVER_NAME_LENGTH] = {0};
 	const char *host;
 	size_t hostlen;
-	char *ip = NULL;
-	struct sockaddr sa;
+	struct sockaddr_storage ss;
 	bool match;
 	int rc;
 
@@ -1327,23 +1326,17 @@ static bool target_share_equal(struct TC
 	extract_unc_hostname(s1, &host, &hostlen);
 	scnprintf(unc, sizeof(unc), "\\\\%.*s", (int)hostlen, host);
 
-	rc = dns_resolve_server_name_to_ip(unc, &ip, NULL);
+	rc = dns_resolve_server_name_to_ip(unc, (struct sockaddr *)&ss, NULL);
 	if (rc < 0) {
 		cifs_dbg(FYI, "%s: could not resolve %.*s. assuming server address matches.\n",
 			 __func__, (int)hostlen, host);
 		return true;
 	}
 
-	if (!cifs_convert_address(&sa, ip, strlen(ip))) {
-		cifs_dbg(VFS, "%s: failed to convert address \'%s\'. skip address matching.\n",
-			 __func__, ip);
-	} else {
-		mutex_lock(&server->srv_mutex);
-		match = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, &sa);
-		mutex_unlock(&server->srv_mutex);
-	}
+	mutex_lock(&server->srv_mutex);
+	match = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, (struct sockaddr *)&ss);
+	mutex_unlock(&server->srv_mutex);
 
-	kfree(ip);
 	return match;
 }
 
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -25,6 +25,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/inet.h>
 #include <linux/slab.h>
 #include <linux/dns_resolver.h>
 #include "dns_resolve.h"
@@ -38,17 +39,13 @@
  * @ip_addr: Where to return the IP address.
  * @expiry: Where to return the expiry time for the dns record.
  *
- * The IP address will be returned in string form, and the caller is
- * responsible for freeing it.
- *
- * Returns length of result on success, -ve on error.
+ * Returns zero success, -ve on error.
  */
 int
-dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry)
+dns_resolve_server_name_to_ip(const char *unc, struct sockaddr *ip_addr, time64_t *expiry)
 {
-	struct sockaddr_storage ss;
 	const char *hostname, *sep;
-	char *name;
+	char *ip;
 	int len, rc;
 
 	if (!ip_addr || !unc)
@@ -73,29 +70,30 @@ dns_resolve_server_name_to_ip(const char
 			 __func__, unc);
 
 	/* Try to interpret hostname as an IPv4 or IPv6 address */
-	rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
-	if (rc > 0)
-		goto name_is_IP_address;
+	rc = cifs_convert_address(ip_addr, hostname, len);
+	if (rc > 0) {
+		cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %*.*s\n", __func__, len, len,
+			 hostname);
+		return 0;
+	}
 
 	/* Perform the upcall */
-	rc = dns_query(NULL, hostname, len, NULL, ip_addr, expiry);
-	if (rc < 0)
+	rc = dns_query(NULL, hostname, len, NULL, &ip, expiry);
+	if (rc < 0) {
 		cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
 			 __func__, len, len, hostname);
-	else
+	} else {
 		cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n",
-			 __func__, len, len, hostname, *ip_addr,
+			 __func__, len, len, hostname, ip,
 			 expiry ? (*expiry) : 0);
-	return rc;
+		rc = cifs_convert_address(ip_addr, ip, strlen(ip));
+		kfree(ip);
 
-name_is_IP_address:
-	name = kmalloc(len + 1, GFP_KERNEL);
-	if (!name)
-		return -ENOMEM;
-	memcpy(name, hostname, len);
-	name[len] = 0;
-	cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %s\n",
-		 __func__, name);
-	*ip_addr = name;
-	return 0;
+		if (!rc) {
+			cifs_dbg(FYI, "%s: unable to determine ip address\n", __func__);
+			rc = -EHOSTUNREACH;
+		} else
+			rc = 0;
+	}
+	return rc;
 }
--- a/fs/cifs/dns_resolve.h
+++ b/fs/cifs/dns_resolve.h
@@ -23,8 +23,10 @@
 #ifndef _DNS_RESOLVE_H
 #define _DNS_RESOLVE_H
 
+#include <linux/net.h>
+
 #ifdef __KERNEL__
-extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry);
+int dns_resolve_server_name_to_ip(const char *unc, struct sockaddr *ip_addr, time64_t *expiry);
 #endif /* KERNEL */
 
 #endif /* _DNS_RESOLVE_H */
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -1095,44 +1095,28 @@ int match_target_ip(struct TCP_Server_In
 		    bool *result)
 {
 	int rc;
-	char *target, *tip = NULL;
-	struct sockaddr tipaddr;
+	char *target;
+	struct sockaddr_storage ss;
 
 	*result = false;
 
 	target = kzalloc(share_len + 3, GFP_KERNEL);
-	if (!target) {
-		rc = -ENOMEM;
-		goto out;
-	}
+	if (!target)
+		return -ENOMEM;
 
 	scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share);
 
 	cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2);
 
-	rc = dns_resolve_server_name_to_ip(target, &tip, NULL);
-	if (rc < 0)
-		goto out;
-
-	cifs_dbg(FYI, "%s: target ip: %s\n", __func__, tip);
+	rc = dns_resolve_server_name_to_ip(target, (struct sockaddr *)&ss, NULL);
+	kfree(target);
 
-	if (!cifs_convert_address(&tipaddr, tip, strlen(tip))) {
-		cifs_dbg(VFS, "%s: failed to convert target ip address\n",
-			 __func__);
-		rc = -EINVAL;
-		goto out;
-	}
+	if (rc < 0)
+		return rc;
 
-	*result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr,
-				    &tipaddr);
+	*result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, (struct sockaddr *)&ss);
 	cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result);
-	rc = 0;
-
-out:
-	kfree(target);
-	kfree(tip);
-
-	return rc;
+	return 0;
 }
 
 int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)