1 // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * 4 * Copyright (c) 2007 Igor Mammedov 5 * Author(s): Igor Mammedov (niallain@gmail.com) 6 * Steve French (sfrench@us.ibm.com) 7 * Wang Lei (wang840925@gmail.com) 8 * David Howells (dhowells@redhat.com) 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 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 */ 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