18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  fs/cifs/dns_resolve.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Copyright (c) 2007 Igor Mammedov
58c2ecf20Sopenharmony_ci *   Author(s): Igor Mammedov (niallain@gmail.com)
68c2ecf20Sopenharmony_ci *              Steve French (sfrench@us.ibm.com)
78c2ecf20Sopenharmony_ci *              Wang Lei (wang840925@gmail.com)
88c2ecf20Sopenharmony_ci *		David Howells (dhowells@redhat.com)
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *   Contains the CIFS DFS upcall routines used for hostname to
118c2ecf20Sopenharmony_ci *   IP address translation.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
148c2ecf20Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as published
158c2ecf20Sopenharmony_ci *   by the Free Software Foundation; either version 2.1 of the License, or
168c2ecf20Sopenharmony_ci *   (at your option) any later version.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *   This library is distributed in the hope that it will be useful,
198c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
208c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
218c2ecf20Sopenharmony_ci *   the GNU Lesser General Public License for more details.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public License
248c2ecf20Sopenharmony_ci *   along with this library; if not, write to the Free Software
258c2ecf20Sopenharmony_ci *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include <linux/dns_resolver.h>
308c2ecf20Sopenharmony_ci#include "dns_resolve.h"
318c2ecf20Sopenharmony_ci#include "cifsglob.h"
328c2ecf20Sopenharmony_ci#include "cifsproto.h"
338c2ecf20Sopenharmony_ci#include "cifs_debug.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/**
368c2ecf20Sopenharmony_ci * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
378c2ecf20Sopenharmony_ci * @unc: UNC path specifying the server (with '/' as delimiter)
388c2ecf20Sopenharmony_ci * @ip_addr: Where to return the IP address.
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * The IP address will be returned in string form, and the caller is
418c2ecf20Sopenharmony_ci * responsible for freeing it.
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci * Returns length of result on success, -ve on error.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ciint
468c2ecf20Sopenharmony_cidns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct sockaddr_storage ss;
498c2ecf20Sopenharmony_ci	const char *hostname, *sep;
508c2ecf20Sopenharmony_ci	char *name;
518c2ecf20Sopenharmony_ci	int len, rc;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (!ip_addr || !unc)
548c2ecf20Sopenharmony_ci		return -EINVAL;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	len = strlen(unc);
578c2ecf20Sopenharmony_ci	if (len < 3) {
588c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: unc is too short: %s\n", __func__, unc);
598c2ecf20Sopenharmony_ci		return -EINVAL;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Discount leading slashes for cifs */
638c2ecf20Sopenharmony_ci	len -= 2;
648c2ecf20Sopenharmony_ci	hostname = unc + 2;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/* Search for server name delimiter */
678c2ecf20Sopenharmony_ci	sep = memchr(hostname, '/', len);
688c2ecf20Sopenharmony_ci	if (sep)
698c2ecf20Sopenharmony_ci		len = sep - hostname;
708c2ecf20Sopenharmony_ci	else
718c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: probably server name is whole unc: %s\n",
728c2ecf20Sopenharmony_ci			 __func__, unc);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* Try to interpret hostname as an IPv4 or IPv6 address */
758c2ecf20Sopenharmony_ci	rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
768c2ecf20Sopenharmony_ci	if (rc > 0)
778c2ecf20Sopenharmony_ci		goto name_is_IP_address;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* Perform the upcall */
808c2ecf20Sopenharmony_ci	rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len,
818c2ecf20Sopenharmony_ci		       NULL, ip_addr, NULL, false);
828c2ecf20Sopenharmony_ci	if (rc < 0)
838c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
848c2ecf20Sopenharmony_ci			 __func__, len, len, hostname);
858c2ecf20Sopenharmony_ci	else
868c2ecf20Sopenharmony_ci		cifs_dbg(FYI, "%s: resolved: %*.*s to %s\n",
878c2ecf20Sopenharmony_ci			 __func__, len, len, hostname, *ip_addr);
888c2ecf20Sopenharmony_ci	return rc;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciname_is_IP_address:
918c2ecf20Sopenharmony_ci	name = kmalloc(len + 1, GFP_KERNEL);
928c2ecf20Sopenharmony_ci	if (!name)
938c2ecf20Sopenharmony_ci		return -ENOMEM;
948c2ecf20Sopenharmony_ci	memcpy(name, hostname, len);
958c2ecf20Sopenharmony_ci	name[len] = 0;
968c2ecf20Sopenharmony_ci	cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %s\n",
978c2ecf20Sopenharmony_ci		 __func__, name);
988c2ecf20Sopenharmony_ci	*ip_addr = name;
998c2ecf20Sopenharmony_ci	return 0;
1008c2ecf20Sopenharmony_ci}
101