1/* 2 * fs/cifs/dns_resolve.c 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 * This library is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU Lesser General Public License as published 15 * by the Free Software Foundation; either version 2.1 of the License, or 16 * (at your option) any later version. 17 * 18 * This library is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 21 * the GNU Lesser General Public License for more details. 22 * 23 * You should have received a copy of the GNU Lesser General Public License 24 * along with this library; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 */ 27 28#include <linux/slab.h> 29#include <linux/dns_resolver.h> 30#include "dns_resolve.h" 31#include "cifsglob.h" 32#include "cifsproto.h" 33#include "cifs_debug.h" 34 35/** 36 * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. 37 * @unc: UNC path specifying the server (with '/' as delimiter) 38 * @ip_addr: Where to return the IP address. 39 * 40 * The IP address will be returned in string form, and the caller is 41 * responsible for freeing it. 42 * 43 * Returns length of result on success, -ve on error. 44 */ 45int 46dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) 47{ 48 struct sockaddr_storage ss; 49 const char *hostname, *sep; 50 char *name; 51 int len, rc; 52 53 if (!ip_addr || !unc) 54 return -EINVAL; 55 56 len = strlen(unc); 57 if (len < 3) { 58 cifs_dbg(FYI, "%s: unc is too short: %s\n", __func__, unc); 59 return -EINVAL; 60 } 61 62 /* Discount leading slashes for cifs */ 63 len -= 2; 64 hostname = unc + 2; 65 66 /* Search for server name delimiter */ 67 sep = memchr(hostname, '/', len); 68 if (sep) 69 len = sep - hostname; 70 else 71 cifs_dbg(FYI, "%s: probably server name is whole unc: %s\n", 72 __func__, unc); 73 74 /* Try to interpret hostname as an IPv4 or IPv6 address */ 75 rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len); 76 if (rc > 0) 77 goto name_is_IP_address; 78 79 /* Perform the upcall */ 80 rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL); 81 if (rc < 0) 82 cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n", 83 __func__, len, len, hostname); 84 else 85 cifs_dbg(FYI, "%s: resolved: %*.*s to %s\n", 86 __func__, len, len, hostname, *ip_addr); 87 return rc; 88 89name_is_IP_address: 90 name = kmalloc(len + 1, GFP_KERNEL); 91 if (!name) 92 return -ENOMEM; 93 memcpy(name, hostname, len); 94 name[len] = 0; 95 cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %s\n", 96 __func__, name); 97 *ip_addr = name; 98 return 0; 99} 100