aboutsummaryrefslogtreecommitdiff
path: root/src/resolver/resolver_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolver/resolver_api.c')
-rw-r--r--src/resolver/resolver_api.c468
1 files changed, 468 insertions, 0 deletions
diff --git a/src/resolver/resolver_api.c b/src/resolver/resolver_api.c
new file mode 100644
index 000000000..27358996a
--- /dev/null
+++ b/src/resolver/resolver_api.c
@@ -0,0 +1,468 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file resolver/resolver_api.c
23 * @brief resolver for writing a tool
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_getopt_lib.h"
28#include "gnunet_client_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_resolver_service.h"
31#include "gnunet_server_lib.h"
32#include "resolver.h"
33
34
35struct GetAddressContext
36{
37 GNUNET_RESOLVER_AddressCallback callback;
38 void *cls;
39 struct GNUNET_RESOLVER_GetMessage *msg;
40 struct GNUNET_CLIENT_Connection *client;
41 struct GNUNET_TIME_Absolute timeout;
42};
43
44
45
46/**
47 * Convert IP address to string without DNS resolution.
48 */
49static char *
50no_resolve (const struct sockaddr *sa, socklen_t salen)
51{
52 char *ret;
53 char inet4[INET_ADDRSTRLEN];
54 char inet6[INET6_ADDRSTRLEN];
55
56 if (salen < sizeof (struct sockaddr))
57 return NULL;
58 switch (sa->sa_family)
59 {
60 case AF_INET:
61 if (salen != sizeof (struct sockaddr_in))
62 return NULL;
63 inet_ntop (AF_INET,
64 &((struct sockaddr_in *) sa)->sin_addr,
65 inet4, INET_ADDRSTRLEN);
66 ret = GNUNET_strdup (inet4);
67 break;
68 case AF_INET6:
69 if (salen != sizeof (struct sockaddr_in6))
70 return NULL;
71 inet_ntop (AF_INET6,
72 &((struct sockaddr_in6 *) sa)->sin6_addr,
73 inet6, INET6_ADDRSTRLEN);
74 ret = GNUNET_strdup (inet6);
75 break;
76 default:
77 ret = NULL;
78 break;
79 }
80 return ret;
81}
82
83
84static void
85handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
86{
87 struct GetAddressContext *gac = cls;
88 uint16_t size;
89 const struct sockaddr *sa;
90 socklen_t salen;
91
92
93 if (msg == NULL)
94 {
95 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
96 _("Timeout trying to resolve hostname.\n"));
97 gac->callback (gac->cls, NULL, 0);
98 GNUNET_CLIENT_disconnect (gac->client);
99 GNUNET_free (gac);
100 return;
101 }
102 if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
103 {
104 GNUNET_break (0);
105 gac->callback (gac->cls, NULL, 0);
106 GNUNET_CLIENT_disconnect (gac->client);
107 GNUNET_free (gac);
108 return;
109 }
110
111 size = ntohs (msg->size);
112 if (size == sizeof (struct GNUNET_MessageHeader))
113 {
114#if DEBUG_RESOLVER
115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116 _("Received end message resolving hostname.\n"));
117#endif
118 gac->callback (gac->cls, NULL, 0);
119 GNUNET_CLIENT_disconnect (gac->client);
120 GNUNET_free (gac);
121 return;
122 }
123 sa = (const struct sockaddr *) &msg[1];
124 salen = size - sizeof (struct GNUNET_MessageHeader);
125 if (salen < sizeof (struct sockaddr))
126 {
127 GNUNET_break (0);
128 gac->callback (gac->cls, NULL, 0);
129 GNUNET_CLIENT_disconnect (gac->client);
130 GNUNET_free (gac);
131 return;
132 }
133#if DEBUG_RESOLVER
134 {
135 char *ips = no_resolve (sa, salen);
136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), ips);
137 GNUNET_free (ips);
138 }
139#endif
140 gac->callback (gac->cls, sa, salen);
141 GNUNET_CLIENT_receive (gac->client,
142 &handle_address_response,
143 gac,
144 GNUNET_TIME_absolute_get_remaining (gac->timeout));
145}
146
147
148static size_t
149transmit_get_ip (void *cls, size_t size, void *buf)
150{
151 struct GetAddressContext *actx = cls;
152 uint16_t ms;
153
154 if (buf == NULL)
155 {
156 /* timeout / error */
157 GNUNET_free (actx->msg);
158 actx->callback (actx->cls, NULL, 0);
159 GNUNET_CLIENT_disconnect (actx->client);
160 GNUNET_free (actx);
161 return 0;
162 }
163 ms = ntohs (actx->msg->header.size);
164 GNUNET_assert (size >= ms);
165 memcpy (buf, actx->msg, ms);
166 GNUNET_free (actx->msg);
167 actx->msg = NULL;
168 GNUNET_CLIENT_receive (actx->client,
169 &handle_address_response,
170 actx,
171 GNUNET_TIME_absolute_get_remaining (actx->timeout));
172 return ms;
173}
174
175
176
177/**
178 * Convert a string to one or more IP addresses.
179 *
180 * @param sched scheduler to use
181 * @param cfg configuration to use
182 * @param hostname the hostname to resolve
183 * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
184 * @param callback function to call with addresses
185 * @param cls closure for callback
186 * @param timeout how long to try resolving
187 */
188void
189GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
190 struct GNUNET_CONFIGURATION_Handle *cfg,
191 const char *hostname,
192 int domain,
193 struct GNUNET_TIME_Relative timeout,
194 GNUNET_RESOLVER_AddressCallback callback, void *cls)
195{
196 struct GNUNET_CLIENT_Connection *client;
197 struct GNUNET_RESOLVER_GetMessage *msg;
198 struct GetAddressContext *actx;
199 size_t slen;
200
201 slen = strlen (hostname) + 1;
202 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
203 GNUNET_SERVER_MAX_MESSAGE_SIZE)
204 {
205 GNUNET_break (0);
206 callback (cls, NULL, 0);
207 return;
208 }
209 client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
210 if (client == NULL)
211 {
212 callback (cls, NULL, 0);
213 return;
214 }
215 msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
216 msg->header.size =
217 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
218 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
219 msg->direction = htonl (GNUNET_NO);
220 msg->domain = htonl (domain);
221 memcpy (&msg[1], hostname, slen);
222 actx = GNUNET_malloc (sizeof (struct GetAddressContext));
223 actx->callback = callback;
224 actx->cls = cls;
225 actx->client = client;
226 actx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
227 actx->msg = msg;
228
229#if DEBUG_RESOLVER
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 _("Resolver requests DNS resolution of hostname `%s'.\n"),
232 hostname);
233#endif
234 if (NULL ==
235 GNUNET_CLIENT_notify_transmit_ready (client,
236 slen +
237 sizeof (struct
238 GNUNET_RESOLVER_GetMessage),
239 timeout, &transmit_get_ip, actx))
240 {
241 GNUNET_free (msg);
242 GNUNET_free (actx);
243 callback (cls, NULL, 0);
244 GNUNET_CLIENT_disconnect (client);
245 return;
246 }
247}
248
249
250struct GetHostnameContext
251{
252 GNUNET_RESOLVER_HostnameCallback callback;
253 void *cls;
254 struct GNUNET_RESOLVER_GetMessage *msg;
255 struct GNUNET_CLIENT_Connection *client;
256 struct GNUNET_TIME_Absolute timeout;
257};
258
259
260static void
261handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
262{
263 struct GetHostnameContext *ghc = cls;
264 uint16_t size;
265 const char *hostname;
266
267 if (msg == NULL)
268 {
269 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
270 _("Timeout trying to resolve IP address.\n"));
271 ghc->callback (ghc->cls, NULL);
272 GNUNET_CLIENT_disconnect (ghc->client);
273 GNUNET_free (ghc);
274 return;
275 }
276 size = ntohs (msg->size);
277 if (size == sizeof (struct GNUNET_MessageHeader))
278 {
279#if DEBUG_RESOLVER
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 _("Received end message resolving IP address.\n"));
282#endif
283 ghc->callback (ghc->cls, NULL);
284 GNUNET_CLIENT_disconnect (ghc->client);
285 GNUNET_free (ghc);
286 return;
287 }
288 hostname = (const char *) &msg[1];
289 if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
290 {
291 GNUNET_break (0);
292 ghc->callback (ghc->cls, NULL);
293 GNUNET_CLIENT_disconnect (ghc->client);
294 GNUNET_free (ghc);
295 return;
296 }
297#if DEBUG_RESOLVER
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 _("Resolver returns `%s'.\n"), hostname);
300#endif
301 ghc->callback (ghc->cls, hostname);
302 GNUNET_CLIENT_receive (ghc->client,
303 &handle_hostname_response,
304 ghc,
305 GNUNET_TIME_absolute_get_remaining (ghc->timeout));
306}
307
308
309static size_t
310transmit_get_hostname (void *cls, size_t size, void *buf)
311{
312 struct GetHostnameContext *hctx = cls;
313 uint16_t msize;
314
315 if (buf == NULL)
316 {
317 GNUNET_free (hctx->msg);
318 hctx->callback (hctx->cls, NULL);
319 GNUNET_CLIENT_disconnect (hctx->client);
320 GNUNET_free (hctx);
321 return 0;
322 }
323 msize = ntohs (hctx->msg->header.size);
324 GNUNET_assert (size >= msize);
325 memcpy (buf, hctx->msg, msize);
326 GNUNET_free (hctx->msg);
327 hctx->msg = NULL;
328 GNUNET_CLIENT_receive (hctx->client,
329 &handle_hostname_response,
330 hctx,
331 GNUNET_TIME_absolute_get_remaining (hctx->timeout));
332 return msize;
333}
334
335
336
337
338/**
339 * Get an IP address as a string.
340 *
341 * @param sched scheduler to use
342 * @param cfg configuration to use
343 * @param sa host address
344 * @param salen length of host address
345 * @param do_resolve use GNUNET_NO to return numeric hostname
346 * @param timeout how long to try resolving
347 * @param callback function to call with hostnames
348 * @param cls closure for callback
349 */
350void
351GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
352 struct GNUNET_CONFIGURATION_Handle *cfg,
353 const struct sockaddr *sa,
354 socklen_t salen,
355 int do_resolve,
356 struct GNUNET_TIME_Relative timeout,
357 GNUNET_RESOLVER_HostnameCallback callback,
358 void *cls)
359{
360 char *result;
361 struct GNUNET_CLIENT_Connection *client;
362 struct GNUNET_RESOLVER_GetMessage *msg;
363 struct GetHostnameContext *hctx;
364
365 if (GNUNET_NO == do_resolve)
366 {
367 result = no_resolve (sa, salen);
368#if DEBUG_RESOLVER
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 _("Resolver returns `%s'.\n"), result);
371#endif
372 callback (cls, result);
373 if (result != NULL)
374 {
375 GNUNET_free (result);
376 callback (cls, NULL);
377 }
378 return;
379 }
380 if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
381 GNUNET_SERVER_MAX_MESSAGE_SIZE)
382 {
383 GNUNET_break (0);
384 callback (cls, NULL);
385 return;
386 }
387 client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
388 if (client == NULL)
389 {
390 callback (cls, NULL);
391 return;
392 }
393 msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
394 msg->header.size =
395 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
396 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
397 msg->direction = htonl (GNUNET_YES);
398 msg->domain = htonl (sa->sa_family);
399 memcpy (&msg[1], sa, salen);
400#if DEBUG_RESOLVER
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 _("Resolver requests DNS resolution of IP address.\n"));
403#endif
404 hctx = GNUNET_malloc (sizeof (struct GetHostnameContext));
405 hctx->callback = callback;
406 hctx->cls = cls;
407 hctx->client = client;
408 hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
409 hctx->msg = msg;
410 if (NULL ==
411 GNUNET_CLIENT_notify_transmit_ready (client,
412 sizeof (struct
413 GNUNET_RESOLVER_GetMessage)
414 + salen, timeout,
415 &transmit_get_hostname, hctx))
416 {
417 GNUNET_free (msg);
418 callback (cls, NULL);
419 GNUNET_CLIENT_disconnect (client);
420 GNUNET_free (hctx);
421 }
422}
423
424/**
425 * Maximum supported length of hostname
426 */
427#define MAX_HOSTNAME 1024
428
429
430/**
431 * Resolve our hostname to an IP address.
432 *
433 * @param sched scheduler to use
434 * @param cfg configuration to use
435 * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
436 * @param callback function to call with addresses
437 * @param cls closure for callback
438 * @param timeout how long to try resolving
439 */
440void
441GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
442 struct GNUNET_CONFIGURATION_Handle *cfg,
443 int domain,
444 struct GNUNET_TIME_Relative timeout,
445 GNUNET_RESOLVER_AddressCallback callback,
446 void *cls)
447{
448 char hostname[MAX_HOSTNAME];
449
450 if (0 != gethostname (hostname, sizeof (hostname) - 1))
451 {
452 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
453 GNUNET_ERROR_TYPE_BULK, "gethostname");
454 callback (cls, NULL, 0);
455 return;
456 }
457#if DEBUG_RESOLVER
458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459 _("Resolving our hostname `%s'\n"), hostname);
460#endif
461 GNUNET_RESOLVER_ip_get (sched,
462 cfg, hostname, domain, timeout, callback, cls);
463}
464
465
466
467
468/* end of resolver_api.c */