162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *   Copyright (c) 2007 Igor Mammedov
562306a36Sopenharmony_ci *   Author(s): Igor Mammedov (niallain@gmail.com)
662306a36Sopenharmony_ci *              Steve French (sfrench@us.ibm.com)
762306a36Sopenharmony_ci *              Wang Lei (wang840925@gmail.com)
862306a36Sopenharmony_ci *		David Howells (dhowells@redhat.com)
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *   Contains the CIFS DFS upcall routines used for hostname to
1162306a36Sopenharmony_ci *   IP address translation.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/inet.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/dns_resolver.h>
1862306a36Sopenharmony_ci#include "dns_resolve.h"
1962306a36Sopenharmony_ci#include "cifsglob.h"
2062306a36Sopenharmony_ci#include "cifsproto.h"
2162306a36Sopenharmony_ci#include "cifs_debug.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/**
2462306a36Sopenharmony_ci * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
2562306a36Sopenharmony_ci * @unc: UNC path specifying the server (with '/' as delimiter)
2662306a36Sopenharmony_ci * @ip_addr: Where to return the IP address.
2762306a36Sopenharmony_ci * @expiry: Where to return the expiry time for the dns record.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Returns zero success, -ve on error.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ciint
3262306a36Sopenharmony_cidns_resolve_server_name_to_ip(const char *unc, struct sockaddr *ip_addr, time64_t *expiry)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	const char *hostname, *sep;
3562306a36Sopenharmony_ci	char *ip;
3662306a36Sopenharmony_ci	int len, rc;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (!ip_addr || !unc)
3962306a36Sopenharmony_ci		return -EINVAL;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	len = strlen(unc);
4262306a36Sopenharmony_ci	if (len < 3) {
4362306a36Sopenharmony_ci		cifs_dbg(FYI, "%s: unc is too short: %s\n", __func__, unc);
4462306a36Sopenharmony_ci		return -EINVAL;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* Discount leading slashes for cifs */
4862306a36Sopenharmony_ci	len -= 2;
4962306a36Sopenharmony_ci	hostname = unc + 2;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* Search for server name delimiter */
5262306a36Sopenharmony_ci	sep = memchr(hostname, '/', len);
5362306a36Sopenharmony_ci	if (sep)
5462306a36Sopenharmony_ci		len = sep - hostname;
5562306a36Sopenharmony_ci	else
5662306a36Sopenharmony_ci		cifs_dbg(FYI, "%s: probably server name is whole unc: %s\n",
5762306a36Sopenharmony_ci			 __func__, unc);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* Try to interpret hostname as an IPv4 or IPv6 address */
6062306a36Sopenharmony_ci	rc = cifs_convert_address(ip_addr, hostname, len);
6162306a36Sopenharmony_ci	if (rc > 0) {
6262306a36Sopenharmony_ci		cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %*.*s\n", __func__, len, len,
6362306a36Sopenharmony_ci			 hostname);
6462306a36Sopenharmony_ci		return 0;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* Perform the upcall */
6862306a36Sopenharmony_ci	rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len,
6962306a36Sopenharmony_ci		       NULL, &ip, expiry, false);
7062306a36Sopenharmony_ci	if (rc < 0) {
7162306a36Sopenharmony_ci		cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
7262306a36Sopenharmony_ci			 __func__, len, len, hostname);
7362306a36Sopenharmony_ci	} else {
7462306a36Sopenharmony_ci		cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n",
7562306a36Sopenharmony_ci			 __func__, len, len, hostname, ip,
7662306a36Sopenharmony_ci			 expiry ? (*expiry) : 0);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		rc = cifs_convert_address(ip_addr, ip, strlen(ip));
7962306a36Sopenharmony_ci		kfree(ip);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		if (!rc) {
8262306a36Sopenharmony_ci			cifs_dbg(FYI, "%s: unable to determine ip address\n", __func__);
8362306a36Sopenharmony_ci			rc = -EHOSTUNREACH;
8462306a36Sopenharmony_ci		} else
8562306a36Sopenharmony_ci			rc = 0;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	return rc;
8862306a36Sopenharmony_ci}
89