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