aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/dns_resolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/dns_resolve.c')
-rw-r--r--fs/cifs/dns_resolve.c170
1 files changed, 50 insertions, 120 deletions
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 6f8a0e3fb25b..0eb87026cad3 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -4,6 +4,8 @@
4 * Copyright (c) 2007 Igor Mammedov 4 * Copyright (c) 2007 Igor Mammedov
5 * Author(s): Igor Mammedov (niallain@gmail.com) 5 * Author(s): Igor Mammedov (niallain@gmail.com)
6 * Steve French (sfrench@us.ibm.com) 6 * Steve French (sfrench@us.ibm.com)
7 * Wang Lei (wang840925@gmail.com)
8 * David Howells (dhowells@redhat.com)
7 * 9 *
8 * Contains the CIFS DFS upcall routines used for hostname to 10 * Contains the CIFS DFS upcall routines used for hostname to
9 * IP address translation. 11 * IP address translation.
@@ -24,145 +26,73 @@
24 */ 26 */
25 27
26#include <linux/slab.h> 28#include <linux/slab.h>
27#include <keys/user-type.h> 29#include <linux/dns_resolver.h>
28#include "dns_resolve.h" 30#include "dns_resolve.h"
29#include "cifsglob.h" 31#include "cifsglob.h"
30#include "cifsproto.h" 32#include "cifsproto.h"
31#include "cifs_debug.h" 33#include "cifs_debug.h"
32 34
33/* Checks if supplied name is IP address 35/**
34 * returns: 36 * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
35 * 1 - name is IP 37 * @unc: UNC path specifying the server
36 * 0 - name is not IP 38 * @ip_addr: Where to return the IP address.
37 */ 39 *
38static int 40 * The IP address will be returned in string form, and the caller is
39is_ip(char *name) 41 * responsible for freeing it.
40{ 42 *
41 struct sockaddr_storage ss; 43 * Returns length of result on success, -ve on error.
42
43 return cifs_convert_address(name, &ss);
44}
45
46static int
47dns_resolver_instantiate(struct key *key, const void *data,
48 size_t datalen)
49{
50 int rc = 0;
51 char *ip;
52
53 ip = kmalloc(datalen + 1, GFP_KERNEL);
54 if (!ip)
55 return -ENOMEM;
56
57 memcpy(ip, data, datalen);
58 ip[datalen] = '\0';
59
60 /* make sure this looks like an address */
61 if (!is_ip(ip)) {
62 kfree(ip);
63 return -EINVAL;
64 }
65
66 key->type_data.x[0] = datalen;
67 key->payload.data = ip;
68
69 return rc;
70}
71
72static void
73dns_resolver_destroy(struct key *key)
74{
75 kfree(key->payload.data);
76}
77
78struct key_type key_type_dns_resolver = {
79 .name = "dns_resolver",
80 .def_datalen = sizeof(struct in_addr),
81 .describe = user_describe,
82 .instantiate = dns_resolver_instantiate,
83 .destroy = dns_resolver_destroy,
84 .match = user_match,
85};
86
87/* Resolves server name to ip address.
88 * input:
89 * unc - server UNC
90 * output:
91 * *ip_addr - pointer to server ip, caller responcible for freeing it.
92 * return 0 on success
93 */ 44 */
94int 45int
95dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) 46dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
96{ 47{
97 int rc = -EAGAIN; 48 struct sockaddr_storage ss;
98 struct key *rkey = ERR_PTR(-EAGAIN); 49 const char *hostname, *sep;
99 char *name; 50 char *name;
100 char *data = NULL; 51 int len, rc;
101 int len;
102 52
103 if (!ip_addr || !unc) 53 if (!ip_addr || !unc)
104 return -EINVAL; 54 return -EINVAL;
105 55
106 /* search for server name delimiter */
107 len = strlen(unc); 56 len = strlen(unc);
108 if (len < 3) { 57 if (len < 3) {
109 cFYI(1, ("%s: unc is too short: %s", __func__, unc)); 58 cFYI(1, "%s: unc is too short: %s", __func__, unc);
110 return -EINVAL; 59 return -EINVAL;
111 } 60 }
61
62 /* Discount leading slashes for cifs */
112 len -= 2; 63 len -= 2;
113 name = memchr(unc+2, '\\', len); 64 hostname = unc + 2;
114 if (!name) { 65
115 cFYI(1, ("%s: probably server name is whole unc: %s", 66 /* Search for server name delimiter */
116 __func__, unc)); 67 sep = memchr(hostname, '\\', len);
117 } else { 68 if (sep)
118 len = (name - unc) - 2/* leading // */; 69 len = sep - unc;
119 } 70 else
71 cFYI(1, "%s: probably server name is whole unc: %s",
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 cERROR(1, "%s: unable to resolve: %*.*s",
83 __func__, len, len, hostname);
84 else
85 cFYI(1, "%s: resolved: %*.*s to %s",
86 __func__, len, len, hostname, *ip_addr);
87 return rc;
120 88
121 name = kmalloc(len+1, GFP_KERNEL); 89name_is_IP_address:
122 if (!name) { 90 name = kmalloc(len + 1, GFP_KERNEL);
123 rc = -ENOMEM; 91 if (!name)
124 return rc; 92 return -ENOMEM;
125 } 93 memcpy(name, hostname, len);
126 memcpy(name, unc+2, len);
127 name[len] = 0; 94 name[len] = 0;
128 95 cFYI(1, "%s: unc is IP, skipping dns upcall: %s", __func__, name);
129 if (is_ip(name)) { 96 *ip_addr = name;
130 cFYI(1, ("%s: it is IP, skipping dns upcall: %s", 97 return 0;
131 __func__, name));
132 data = name;
133 goto skip_upcall;
134 }
135
136 rkey = request_key(&key_type_dns_resolver, name, "");
137 if (!IS_ERR(rkey)) {
138 len = rkey->type_data.x[0];
139 data = rkey->payload.data;
140 } else {
141 cERROR(1, ("%s: unable to resolve: %s", __func__, name));
142 goto out;
143 }
144
145skip_upcall:
146 if (data) {
147 *ip_addr = kmalloc(len + 1, GFP_KERNEL);
148 if (*ip_addr) {
149 memcpy(*ip_addr, data, len + 1);
150 if (!IS_ERR(rkey))
151 cFYI(1, ("%s: resolved: %s to %s", __func__,
152 name,
153 *ip_addr
154 ));
155 rc = 0;
156 } else {
157 rc = -ENOMEM;
158 }
159 if (!IS_ERR(rkey))
160 key_put(rkey);
161 }
162
163out:
164 kfree(name);
165 return rc;
166} 98}
167
168