Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1
0002 /*
0003  *
0004  *   Copyright (c) 2007 Igor Mammedov
0005  *   Author(s): Igor Mammedov (niallain@gmail.com)
0006  *              Steve French (sfrench@us.ibm.com)
0007  *              Wang Lei (wang840925@gmail.com)
0008  *      David Howells (dhowells@redhat.com)
0009  *
0010  *   Contains the CIFS DFS upcall routines used for hostname to
0011  *   IP address translation.
0012  *
0013  */
0014 
0015 #include <linux/slab.h>
0016 #include <linux/dns_resolver.h>
0017 #include "dns_resolve.h"
0018 #include "cifsglob.h"
0019 #include "cifsproto.h"
0020 #include "cifs_debug.h"
0021 
0022 /**
0023  * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
0024  * @unc: UNC path specifying the server (with '/' as delimiter)
0025  * @ip_addr: Where to return the IP address.
0026  * @expiry: Where to return the expiry time for the dns record.
0027  *
0028  * The IP address will be returned in string form, and the caller is
0029  * responsible for freeing it.
0030  *
0031  * Returns length of result on success, -ve on error.
0032  */
0033 int
0034 dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry)
0035 {
0036     struct sockaddr_storage ss;
0037     const char *hostname, *sep;
0038     char *name;
0039     int len, rc;
0040 
0041     if (!ip_addr || !unc)
0042         return -EINVAL;
0043 
0044     len = strlen(unc);
0045     if (len < 3) {
0046         cifs_dbg(FYI, "%s: unc is too short: %s\n", __func__, unc);
0047         return -EINVAL;
0048     }
0049 
0050     /* Discount leading slashes for cifs */
0051     len -= 2;
0052     hostname = unc + 2;
0053 
0054     /* Search for server name delimiter */
0055     sep = memchr(hostname, '/', len);
0056     if (sep)
0057         len = sep - hostname;
0058     else
0059         cifs_dbg(FYI, "%s: probably server name is whole unc: %s\n",
0060              __func__, unc);
0061 
0062     /* Try to interpret hostname as an IPv4 or IPv6 address */
0063     rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
0064     if (rc > 0)
0065         goto name_is_IP_address;
0066 
0067     /* Perform the upcall */
0068     rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len,
0069                NULL, ip_addr, expiry, false);
0070     if (rc < 0)
0071         cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
0072              __func__, len, len, hostname);
0073     else
0074         cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n",
0075              __func__, len, len, hostname, *ip_addr,
0076              expiry ? (*expiry) : 0);
0077     return rc;
0078 
0079 name_is_IP_address:
0080     name = kmalloc(len + 1, GFP_KERNEL);
0081     if (!name)
0082         return -ENOMEM;
0083     memcpy(name, hostname, len);
0084     name[len] = 0;
0085     cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %s\n",
0086          __func__, name);
0087     *ip_addr = name;
0088     return 0;
0089 }