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