1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  *
4  *   Copyright (c) 2007 Igor Mammedov
5  *   Author(s): Igor Mammedov ([email protected])
6  *              Steve French ([email protected])
7  *              Wang Lei ([email protected])
8  *		David Howells ([email protected])
9  *
10  *   Contains the CIFS DFS upcall routines used for hostname to
11  *   IP address translation.
12  *
13  */
14 
15 #include <linux/inet.h>
16 #include <linux/slab.h>
17 #include <linux/dns_resolver.h>
18 #include "dns_resolve.h"
19 #include "cifsglob.h"
20 #include "cifsproto.h"
21 #include "cifs_debug.h"
22 
resolve_name(const char * name,size_t namelen,struct sockaddr * addr)23 static int resolve_name(const char *name, size_t namelen, struct sockaddr *addr)
24 {
25 	char *ip;
26 	int rc;
27 
28 	rc = dns_query(current->nsproxy->net_ns, NULL, name,
29 		       namelen, NULL, &ip, NULL, false);
30 	if (rc < 0) {
31 		cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
32 			 __func__, (int)namelen, (int)namelen, name);
33 	} else {
34 		cifs_dbg(FYI, "%s: resolved: %*.*s to %s\n",
35 			 __func__, (int)namelen, (int)namelen, name, ip);
36 
37 		rc = cifs_convert_address(addr, ip, strlen(ip));
38 		kfree(ip);
39 		if (!rc) {
40 			cifs_dbg(FYI, "%s: unable to determine ip address\n",
41 				 __func__);
42 			rc = -EHOSTUNREACH;
43 		} else {
44 			rc = 0;
45 		}
46 	}
47 	return rc;
48 }
49 
50 /**
51  * dns_resolve_name - Perform an upcall to resolve hostname to an ip address.
52  * @dom: DNS domain name (or NULL)
53  * @name: Name to look up
54  * @namelen: Length of name
55  * @ip_addr: Where to return the IP address
56  *
57  * Returns zero on success, -ve code otherwise.
58  */
dns_resolve_name(const char * dom,const char * name,size_t namelen,struct sockaddr * ip_addr)59 int dns_resolve_name(const char *dom, const char *name,
60 		     size_t namelen, struct sockaddr *ip_addr)
61 {
62 	size_t len;
63 	char *s;
64 	int rc;
65 
66 	cifs_dbg(FYI, "%s: dom=%s name=%.*s\n", __func__, dom, (int)namelen, name);
67 	if (!ip_addr || !name || !*name || !namelen)
68 		return -EINVAL;
69 
70 	cifs_dbg(FYI, "%s: hostname=%.*s\n", __func__, (int)namelen, name);
71 	/* Try to interpret hostname as an IPv4 or IPv6 address */
72 	rc = cifs_convert_address(ip_addr, name, namelen);
73 	if (rc > 0) {
74 		cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %*.*s\n",
75 			 __func__, (int)namelen, (int)namelen, name);
76 		return 0;
77 	}
78 
79 	/*
80 	 * If @name contains a NetBIOS name and @dom has been specified, then
81 	 * convert @name to an FQDN and try resolving it first.
82 	 */
83 	if (dom && *dom && cifs_netbios_name(name, namelen)) {
84 		len = strnlen(dom, CIFS_MAX_DOMAINNAME_LEN) + namelen + 2;
85 		s = kmalloc(len, GFP_KERNEL);
86 		if (!s)
87 			return -ENOMEM;
88 
89 		scnprintf(s, len, "%.*s.%s", (int)namelen, name, dom);
90 		rc = resolve_name(s, len - 1, ip_addr);
91 		kfree(s);
92 		if (!rc)
93 			return 0;
94 	}
95 	return resolve_name(name, namelen, ip_addr);
96 }
97