diff options
Diffstat (limited to 'src/dns/gnunet-service-dns.c')
-rw-r--r-- | src/dns/gnunet-service-dns.c | 1275 |
1 files changed, 0 insertions, 1275 deletions
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c deleted file mode 100644 index 4840c0c95..000000000 --- a/src/dns/gnunet-service-dns.c +++ /dev/null | |||
@@ -1,1275 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dns/gnunet-service-dns.c | ||
23 | * @brief service to intercept and modify DNS queries (and replies) of this system | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * For "secure" interaction with the legacy DNS system, we permit | ||
27 | * replies only to arrive within a 5s window (and they must match | ||
28 | * ports, IPs and request IDs). Furthermore, we let the OS pick a | ||
29 | * source port, opening up to 128 sockets per address family (IPv4 or | ||
30 | * IPv6). Those sockets are closed if they are not in use for 5s | ||
31 | * (which means they will be freshly randomized afterwards). For new | ||
32 | * requests, we pick a random slot in the array with 128 socket slots | ||
33 | * (and re-use an existing socket if the slot is still in use). Thus | ||
34 | * each request will be given one of 128 random source ports, and the | ||
35 | * 128 random source ports will also change "often" (less often if the | ||
36 | * system is very busy, each time if we are mostly idle). At the same | ||
37 | * time, the system will never use more than 256 UDP sockets. | ||
38 | */ | ||
39 | #include "platform.h" | ||
40 | #include "gnunet_util_lib.h" | ||
41 | #include "gnunet_applications.h" | ||
42 | #include "gnunet_constants.h" | ||
43 | #include "gnunet_protocols.h" | ||
44 | #include "gnunet_signatures.h" | ||
45 | #include "dns.h" | ||
46 | #include "gnunet_dns_service.h" | ||
47 | #include "gnunet_dnsparser_lib.h" | ||
48 | #include "gnunet_dnsstub_lib.h" | ||
49 | #include "gnunet_statistics_service.h" | ||
50 | #include "gnunet_tun_lib.h" | ||
51 | |||
52 | /** | ||
53 | * Port number for DNS | ||
54 | */ | ||
55 | #define DNS_PORT 53 | ||
56 | |||
57 | |||
58 | /** | ||
59 | * Generic logging shorthand | ||
60 | */ | ||
61 | #define LOG(kind, ...) \ | ||
62 | GNUNET_log_from (kind, "dns", __VA_ARGS__); | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Phases each request goes through. | ||
67 | */ | ||
68 | enum RequestPhase | ||
69 | { | ||
70 | /** | ||
71 | * Request has just been received. | ||
72 | */ | ||
73 | RP_INIT, | ||
74 | |||
75 | /** | ||
76 | * Showing the request to all monitor clients. If | ||
77 | * client list is empty, will enter QUERY phase. | ||
78 | */ | ||
79 | RP_REQUEST_MONITOR, | ||
80 | |||
81 | /** | ||
82 | * Showing the request to PRE-RESOLUTION clients to find an answer. | ||
83 | * If client list is empty, will trigger global DNS request. | ||
84 | */ | ||
85 | RP_QUERY, | ||
86 | |||
87 | /** | ||
88 | * Global Internet query is now pending. | ||
89 | */ | ||
90 | RP_INTERNET_DNS, | ||
91 | |||
92 | /** | ||
93 | * Client (or global DNS request) has resulted in a response. | ||
94 | * Forward to all POST-RESOLUTION clients. If client list is empty, | ||
95 | * will enter RESPONSE_MONITOR phase. | ||
96 | */ | ||
97 | RP_MODIFY, | ||
98 | |||
99 | /** | ||
100 | * Showing the request to all monitor clients. If | ||
101 | * client list is empty, give the result to the hijacker (and be done). | ||
102 | */ | ||
103 | RP_RESPONSE_MONITOR, | ||
104 | |||
105 | /** | ||
106 | * Some client has told us to drop the request. | ||
107 | */ | ||
108 | RP_DROP | ||
109 | }; | ||
110 | |||
111 | |||
112 | /** | ||
113 | * Entry we keep for each client. | ||
114 | */ | ||
115 | struct ClientRecord | ||
116 | { | ||
117 | /** | ||
118 | * Kept in doubly-linked list. | ||
119 | */ | ||
120 | struct ClientRecord *next; | ||
121 | |||
122 | /** | ||
123 | * Kept in doubly-linked list. | ||
124 | */ | ||
125 | struct ClientRecord *prev; | ||
126 | |||
127 | /** | ||
128 | * Handle to the client. | ||
129 | */ | ||
130 | struct GNUNET_SERVICE_Client *client; | ||
131 | |||
132 | /** | ||
133 | * Message queue to talk to @a client. | ||
134 | */ | ||
135 | struct GNUNET_MQ_Handle *mq; | ||
136 | |||
137 | /** | ||
138 | * Flags for the client. | ||
139 | */ | ||
140 | enum GNUNET_DNS_Flags flags; | ||
141 | }; | ||
142 | |||
143 | |||
144 | /** | ||
145 | * Entry we keep for each active request. | ||
146 | */ | ||
147 | struct RequestRecord | ||
148 | { | ||
149 | /** | ||
150 | * List of clients that still need to see this request (each entry | ||
151 | * is set to NULL when the client is done). | ||
152 | */ | ||
153 | struct ClientRecord **client_wait_list; | ||
154 | |||
155 | /** | ||
156 | * Payload of the UDP packet (the UDP payload), can be either query | ||
157 | * or already the response. | ||
158 | */ | ||
159 | char *payload; | ||
160 | |||
161 | /** | ||
162 | * Socket we are using to transmit this request (must match if we receive | ||
163 | * a response). | ||
164 | */ | ||
165 | struct GNUNET_DNSSTUB_RequestSocket *rs; | ||
166 | |||
167 | /** | ||
168 | * Source address of the original request (for sending response). | ||
169 | */ | ||
170 | struct sockaddr_storage src_addr; | ||
171 | |||
172 | /** | ||
173 | * Destination address of the original request (for potential use as exit). | ||
174 | */ | ||
175 | struct sockaddr_storage dst_addr; | ||
176 | |||
177 | /** | ||
178 | * ID of this request, also basis for hashing. Lowest 16 bit will | ||
179 | * be our message ID when doing a global DNS request and our index | ||
180 | * into the 'requests' array. | ||
181 | */ | ||
182 | uint64_t request_id; | ||
183 | |||
184 | /** | ||
185 | * Number of bytes in payload. | ||
186 | */ | ||
187 | size_t payload_length; | ||
188 | |||
189 | /** | ||
190 | * Length of the @e client_wait_list. | ||
191 | */ | ||
192 | unsigned int client_wait_list_length; | ||
193 | |||
194 | /** | ||
195 | * In which phase this this request? | ||
196 | */ | ||
197 | enum RequestPhase phase; | ||
198 | }; | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Global return value from 'main'. | ||
203 | */ | ||
204 | static int global_ret; | ||
205 | |||
206 | /** | ||
207 | * The configuration to use | ||
208 | */ | ||
209 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
210 | |||
211 | /** | ||
212 | * Statistics. | ||
213 | */ | ||
214 | static struct GNUNET_STATISTICS_Handle *stats; | ||
215 | |||
216 | /** | ||
217 | * Handle to DNS hijacker helper process ("gnunet-helper-dns"). | ||
218 | */ | ||
219 | static struct GNUNET_HELPER_Handle *hijacker; | ||
220 | |||
221 | /** | ||
222 | * Command-line arguments we are giving to the hijacker process. | ||
223 | */ | ||
224 | static char *helper_argv[8]; | ||
225 | |||
226 | /** | ||
227 | * Head of DLL of clients we consult. | ||
228 | */ | ||
229 | static struct ClientRecord *clients_head; | ||
230 | |||
231 | /** | ||
232 | * Tail of DLL of clients we consult. | ||
233 | */ | ||
234 | static struct ClientRecord *clients_tail; | ||
235 | |||
236 | /** | ||
237 | * Array of all open requests. | ||
238 | */ | ||
239 | static struct RequestRecord requests[UINT16_MAX + 1]; | ||
240 | |||
241 | /** | ||
242 | * Generator for unique request IDs. | ||
243 | */ | ||
244 | static uint64_t request_id_gen; | ||
245 | |||
246 | /** | ||
247 | * Handle to the DNS Stub resolver. | ||
248 | */ | ||
249 | static struct GNUNET_DNSSTUB_Context *dnsstub; | ||
250 | |||
251 | |||
252 | /** | ||
253 | * We're done processing a DNS request, free associated memory. | ||
254 | * | ||
255 | * @param rr request to clean up | ||
256 | */ | ||
257 | static void | ||
258 | cleanup_rr (struct RequestRecord *rr) | ||
259 | { | ||
260 | GNUNET_free (rr->payload); | ||
261 | rr->payload = NULL; | ||
262 | rr->payload_length = 0; | ||
263 | GNUNET_array_grow (rr->client_wait_list, | ||
264 | rr->client_wait_list_length, | ||
265 | 0); | ||
266 | } | ||
267 | |||
268 | |||
269 | /** | ||
270 | * Task run during shutdown. | ||
271 | * | ||
272 | * @param cls unused | ||
273 | */ | ||
274 | static void | ||
275 | cleanup_task (void *cls GNUNET_UNUSED) | ||
276 | { | ||
277 | if (NULL != hijacker) | ||
278 | { | ||
279 | GNUNET_HELPER_stop (hijacker, GNUNET_NO); | ||
280 | hijacker = NULL; | ||
281 | } | ||
282 | for (unsigned int i = 0; i < 8; i++) | ||
283 | GNUNET_free (helper_argv[i]); | ||
284 | for (unsigned int i = 0; i <= UINT16_MAX; i++) | ||
285 | cleanup_rr (&requests[i]); | ||
286 | if (NULL != stats) | ||
287 | { | ||
288 | GNUNET_STATISTICS_destroy (stats, | ||
289 | GNUNET_NO); | ||
290 | stats = NULL; | ||
291 | } | ||
292 | if (NULL != dnsstub) | ||
293 | { | ||
294 | GNUNET_DNSSTUB_stop (dnsstub); | ||
295 | dnsstub = NULL; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | |||
300 | /** | ||
301 | * We're done with some request, finish processing. | ||
302 | * | ||
303 | * @param rr request send to the network or just clean up. | ||
304 | */ | ||
305 | static void | ||
306 | request_done (struct RequestRecord *rr) | ||
307 | { | ||
308 | struct GNUNET_MessageHeader *hdr; | ||
309 | size_t reply_len; | ||
310 | uint16_t source_port; | ||
311 | uint16_t destination_port; | ||
312 | |||
313 | GNUNET_array_grow (rr->client_wait_list, | ||
314 | rr->client_wait_list_length, | ||
315 | 0); | ||
316 | if (RP_RESPONSE_MONITOR != rr->phase) | ||
317 | { | ||
318 | /* no response, drop */ | ||
319 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
320 | "Got no response for request %llu, dropping\n", | ||
321 | (unsigned long long) rr->request_id); | ||
322 | cleanup_rr (rr); | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
327 | "Transmitting response for request %llu\n", | ||
328 | (unsigned long long) rr->request_id); | ||
329 | /* send response via hijacker */ | ||
330 | reply_len = sizeof(struct GNUNET_MessageHeader); | ||
331 | reply_len += sizeof(struct GNUNET_TUN_Layer2PacketHeader); | ||
332 | switch (rr->src_addr.ss_family) | ||
333 | { | ||
334 | case AF_INET: | ||
335 | reply_len += sizeof(struct GNUNET_TUN_IPv4Header); | ||
336 | break; | ||
337 | |||
338 | case AF_INET6: | ||
339 | reply_len += sizeof(struct GNUNET_TUN_IPv6Header); | ||
340 | break; | ||
341 | |||
342 | default: | ||
343 | GNUNET_break (0); | ||
344 | cleanup_rr (rr); | ||
345 | return; | ||
346 | } | ||
347 | reply_len += sizeof(struct GNUNET_TUN_UdpHeader); | ||
348 | reply_len += rr->payload_length; | ||
349 | if (reply_len >= GNUNET_MAX_MESSAGE_SIZE) | ||
350 | { | ||
351 | /* response too big, drop */ | ||
352 | GNUNET_break (0); /* how can this be? */ | ||
353 | cleanup_rr (rr); | ||
354 | return; | ||
355 | } | ||
356 | { | ||
357 | char buf[reply_len] GNUNET_ALIGN; | ||
358 | size_t off; | ||
359 | struct GNUNET_TUN_IPv4Header ip4; | ||
360 | struct GNUNET_TUN_IPv6Header ip6; | ||
361 | |||
362 | /* first, GNUnet message header */ | ||
363 | hdr = (struct GNUNET_MessageHeader*) buf; | ||
364 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); | ||
365 | hdr->size = htons ((uint16_t) reply_len); | ||
366 | off = sizeof(struct GNUNET_MessageHeader); | ||
367 | |||
368 | /* first, TUN header */ | ||
369 | { | ||
370 | struct GNUNET_TUN_Layer2PacketHeader tun; | ||
371 | |||
372 | tun.flags = htons (0); | ||
373 | if (rr->src_addr.ss_family == AF_INET) | ||
374 | tun.proto = htons (ETH_P_IPV4); | ||
375 | else | ||
376 | tun.proto = htons (ETH_P_IPV6); | ||
377 | GNUNET_memcpy (&buf[off], | ||
378 | &tun, | ||
379 | sizeof(struct GNUNET_TUN_Layer2PacketHeader)); | ||
380 | off += sizeof(struct GNUNET_TUN_Layer2PacketHeader); | ||
381 | } | ||
382 | |||
383 | /* now IP header */ | ||
384 | switch (rr->src_addr.ss_family) | ||
385 | { | ||
386 | case AF_INET: | ||
387 | { | ||
388 | struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; | ||
389 | struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; | ||
390 | |||
391 | source_port = dst->sin_port; | ||
392 | destination_port = src->sin_port; | ||
393 | GNUNET_TUN_initialize_ipv4_header (&ip4, | ||
394 | IPPROTO_UDP, | ||
395 | reply_len - off - sizeof(struct | ||
396 | GNUNET_TUN_IPv4Header), | ||
397 | &dst->sin_addr, | ||
398 | &src->sin_addr); | ||
399 | GNUNET_memcpy (&buf[off], | ||
400 | &ip4, | ||
401 | sizeof(ip4)); | ||
402 | off += sizeof(ip4); | ||
403 | } | ||
404 | break; | ||
405 | |||
406 | case AF_INET6: | ||
407 | { | ||
408 | struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; | ||
409 | struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; | ||
410 | |||
411 | source_port = dst->sin6_port; | ||
412 | destination_port = src->sin6_port; | ||
413 | GNUNET_TUN_initialize_ipv6_header (&ip6, | ||
414 | IPPROTO_UDP, | ||
415 | reply_len - off - sizeof(struct | ||
416 | GNUNET_TUN_IPv6Header), | ||
417 | &dst->sin6_addr, | ||
418 | &src->sin6_addr); | ||
419 | GNUNET_memcpy (&buf[off], | ||
420 | &ip6, | ||
421 | sizeof(ip6)); | ||
422 | off += sizeof(ip6); | ||
423 | } | ||
424 | break; | ||
425 | |||
426 | default: | ||
427 | GNUNET_assert (0); | ||
428 | } | ||
429 | |||
430 | /* now UDP header */ | ||
431 | { | ||
432 | struct GNUNET_TUN_UdpHeader udp; | ||
433 | |||
434 | udp.source_port = source_port; | ||
435 | udp.destination_port = destination_port; | ||
436 | udp.len = htons (reply_len - off); | ||
437 | if (AF_INET == rr->src_addr.ss_family) | ||
438 | GNUNET_TUN_calculate_udp4_checksum (&ip4, | ||
439 | &udp, | ||
440 | rr->payload, | ||
441 | rr->payload_length); | ||
442 | else | ||
443 | GNUNET_TUN_calculate_udp6_checksum (&ip6, | ||
444 | &udp, | ||
445 | rr->payload, | ||
446 | rr->payload_length); | ||
447 | GNUNET_memcpy (&buf[off], | ||
448 | &udp, | ||
449 | sizeof(udp)); | ||
450 | off += sizeof(udp); | ||
451 | } | ||
452 | |||
453 | /* now DNS payload */ | ||
454 | { | ||
455 | GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length); | ||
456 | off += rr->payload_length; | ||
457 | } | ||
458 | /* final checks & sending */ | ||
459 | GNUNET_assert (off == reply_len); | ||
460 | (void) GNUNET_HELPER_send (hijacker, | ||
461 | hdr, | ||
462 | GNUNET_YES, | ||
463 | NULL, NULL); | ||
464 | GNUNET_STATISTICS_update (stats, | ||
465 | gettext_noop ( | ||
466 | "# DNS requests answered via TUN interface"), | ||
467 | 1, GNUNET_NO); | ||
468 | } | ||
469 | /* clean up, we're done */ | ||
470 | cleanup_rr (rr); | ||
471 | } | ||
472 | |||
473 | |||
474 | /** | ||
475 | * Show the payload of the given request record to the client | ||
476 | * (and wait for a response). | ||
477 | * | ||
478 | * @param rr request to send to client | ||
479 | * @param cr client to send the response to | ||
480 | */ | ||
481 | static void | ||
482 | send_request_to_client (struct RequestRecord *rr, | ||
483 | struct ClientRecord *cr) | ||
484 | { | ||
485 | struct GNUNET_MQ_Envelope *env; | ||
486 | struct GNUNET_DNS_Request *req; | ||
487 | |||
488 | if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >= | ||
489 | GNUNET_MAX_MESSAGE_SIZE) | ||
490 | { | ||
491 | GNUNET_break (0); | ||
492 | cleanup_rr (rr); | ||
493 | return; | ||
494 | } | ||
495 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
496 | "Sending information about request %llu to local client\n", | ||
497 | (unsigned long long) rr->request_id); | ||
498 | env = GNUNET_MQ_msg_extra (req, | ||
499 | rr->payload_length, | ||
500 | GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); | ||
501 | req->reserved = htonl (0); | ||
502 | req->request_id = rr->request_id; | ||
503 | GNUNET_memcpy (&req[1], | ||
504 | rr->payload, | ||
505 | rr->payload_length); | ||
506 | GNUNET_MQ_send (cr->mq, | ||
507 | env); | ||
508 | } | ||
509 | |||
510 | |||
511 | /** | ||
512 | * Callback called from DNSSTUB resolver when a resolution | ||
513 | * succeeded. | ||
514 | * | ||
515 | * @param cls NULL | ||
516 | * @param dns the response itself | ||
517 | * @param r number of bytes in dns | ||
518 | */ | ||
519 | static void | ||
520 | process_dns_result (void *cls, | ||
521 | const struct GNUNET_TUN_DnsHeader *dns, | ||
522 | size_t r); | ||
523 | |||
524 | |||
525 | /** | ||
526 | * A client has completed its processing for this | ||
527 | * request. Move on. | ||
528 | * | ||
529 | * @param rr request to process further | ||
530 | */ | ||
531 | static void | ||
532 | next_phase (struct RequestRecord *rr) | ||
533 | { | ||
534 | struct ClientRecord *cr; | ||
535 | int nz; | ||
536 | |||
537 | if (rr->phase == RP_DROP) | ||
538 | { | ||
539 | cleanup_rr (rr); | ||
540 | return; | ||
541 | } | ||
542 | nz = -1; | ||
543 | for (unsigned int j = 0; j < rr->client_wait_list_length; j++) | ||
544 | { | ||
545 | if (NULL != rr->client_wait_list[j]) | ||
546 | { | ||
547 | nz = (int) j; | ||
548 | break; | ||
549 | } | ||
550 | } | ||
551 | if (-1 != nz) | ||
552 | { | ||
553 | send_request_to_client (rr, | ||
554 | rr->client_wait_list[nz]); | ||
555 | return; | ||
556 | } | ||
557 | /* done with current phase, advance! */ | ||
558 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
559 | "Request %llu now in phase %d\n", | ||
560 | (unsigned long long) rr->request_id, | ||
561 | rr->phase); | ||
562 | switch (rr->phase) | ||
563 | { | ||
564 | case RP_INIT: | ||
565 | rr->phase = RP_REQUEST_MONITOR; | ||
566 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
567 | { | ||
568 | if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) | ||
569 | GNUNET_array_append (rr->client_wait_list, | ||
570 | rr->client_wait_list_length, | ||
571 | cr); | ||
572 | } | ||
573 | next_phase (rr); | ||
574 | return; | ||
575 | |||
576 | case RP_REQUEST_MONITOR: | ||
577 | rr->phase = RP_QUERY; | ||
578 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
579 | { | ||
580 | if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) | ||
581 | GNUNET_array_append (rr->client_wait_list, | ||
582 | rr->client_wait_list_length, | ||
583 | cr); | ||
584 | } | ||
585 | next_phase (rr); | ||
586 | return; | ||
587 | |||
588 | case RP_QUERY: | ||
589 | #if 0 | ||
590 | /* TODO: optionally, use this to forward DNS requests to the | ||
591 | * original* DNS server instead of the one we have configured... | ||
592 | (but then we need to create a fresh dnsstub for each request | ||
593 | * and* manage the timeout) */ | ||
594 | switch (rr->dst_addr.ss_family) | ||
595 | { | ||
596 | case AF_INET: | ||
597 | salen = sizeof(struct sockaddr_in); | ||
598 | sa = (const struct sockaddr *) &rr->dst_addr; | ||
599 | break; | ||
600 | |||
601 | case AF_INET6: | ||
602 | salen = sizeof(struct sockaddr_in6); | ||
603 | sa = (const struct sockaddr *) &rr->dst_addr; | ||
604 | break; | ||
605 | |||
606 | default: | ||
607 | GNUNET_assert (0); | ||
608 | } | ||
609 | #endif | ||
610 | rr->phase = RP_INTERNET_DNS; | ||
611 | rr->rs = GNUNET_DNSSTUB_resolve (dnsstub, | ||
612 | rr->payload, | ||
613 | rr->payload_length, | ||
614 | &process_dns_result, | ||
615 | NULL); | ||
616 | if (NULL == rr->rs) | ||
617 | { | ||
618 | GNUNET_STATISTICS_update (stats, | ||
619 | gettext_noop ( | ||
620 | "# DNS exit failed (failed to open socket)"), | ||
621 | 1, | ||
622 | GNUNET_NO); | ||
623 | cleanup_rr (rr); | ||
624 | return; | ||
625 | } | ||
626 | return; | ||
627 | |||
628 | case RP_INTERNET_DNS: | ||
629 | rr->phase = RP_MODIFY; | ||
630 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
631 | { | ||
632 | if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) | ||
633 | GNUNET_array_append (rr->client_wait_list, | ||
634 | rr->client_wait_list_length, | ||
635 | cr); | ||
636 | } | ||
637 | next_phase (rr); | ||
638 | return; | ||
639 | |||
640 | case RP_MODIFY: | ||
641 | rr->phase = RP_RESPONSE_MONITOR; | ||
642 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
643 | { | ||
644 | if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) | ||
645 | GNUNET_array_append (rr->client_wait_list, | ||
646 | rr->client_wait_list_length, | ||
647 | cr); | ||
648 | } | ||
649 | next_phase (rr); | ||
650 | return; | ||
651 | |||
652 | case RP_RESPONSE_MONITOR: | ||
653 | request_done (rr); | ||
654 | break; | ||
655 | |||
656 | case RP_DROP: | ||
657 | cleanup_rr (rr); | ||
658 | break; | ||
659 | |||
660 | default: | ||
661 | GNUNET_break (0); | ||
662 | cleanup_rr (rr); | ||
663 | break; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | |||
668 | /** | ||
669 | * A client connected, setup our data structures. | ||
670 | * | ||
671 | * @param cls unused | ||
672 | * @param client handle of client that connected | ||
673 | * @param mq message queue to talk to @a client | ||
674 | * @return our `struct ClientRecord` | ||
675 | */ | ||
676 | static void * | ||
677 | client_connect_cb (void *cls, | ||
678 | struct GNUNET_SERVICE_Client *client, | ||
679 | struct GNUNET_MQ_Handle *mq) | ||
680 | { | ||
681 | struct ClientRecord *cr = cls; | ||
682 | |||
683 | cr = GNUNET_new (struct ClientRecord); | ||
684 | cr->client = client; | ||
685 | cr->mq = mq; | ||
686 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
687 | clients_tail, | ||
688 | cr); | ||
689 | return cr; | ||
690 | } | ||
691 | |||
692 | |||
693 | /** | ||
694 | * A client disconnected, clean up after it. | ||
695 | * | ||
696 | * @param cls unused | ||
697 | * @param client handle of client that disconnected | ||
698 | * @param app_ctx our `struct ClientRecord` | ||
699 | */ | ||
700 | static void | ||
701 | client_disconnect_cb (void *cls, | ||
702 | struct GNUNET_SERVICE_Client *client, | ||
703 | void *app_ctx) | ||
704 | { | ||
705 | struct ClientRecord *cr = app_ctx; | ||
706 | struct RequestRecord *rr; | ||
707 | |||
708 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
709 | clients_tail, | ||
710 | cr); | ||
711 | for (unsigned int i = 0; i < UINT16_MAX; i++) | ||
712 | { | ||
713 | rr = &requests[i]; | ||
714 | if (0 == rr->client_wait_list_length) | ||
715 | continue; /* not in use */ | ||
716 | for (unsigned int j = 0; j < rr->client_wait_list_length; j++) | ||
717 | { | ||
718 | if (rr->client_wait_list[j] == cr) | ||
719 | { | ||
720 | rr->client_wait_list[j] = NULL; | ||
721 | next_phase (rr); | ||
722 | } | ||
723 | } | ||
724 | } | ||
725 | GNUNET_free (cr); | ||
726 | } | ||
727 | |||
728 | |||
729 | /** | ||
730 | * Callback called from DNSSTUB resolver when a resolution | ||
731 | * succeeded. | ||
732 | * | ||
733 | * @param cls NULL | ||
734 | * @param dns the response itself | ||
735 | * @param r number of bytes in dns | ||
736 | */ | ||
737 | static void | ||
738 | process_dns_result (void *cls, | ||
739 | const struct GNUNET_TUN_DnsHeader *dns, | ||
740 | size_t r) | ||
741 | { | ||
742 | struct RequestRecord *rr; | ||
743 | |||
744 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
745 | "Processing DNS result from stub resolver\n"); | ||
746 | GNUNET_assert (NULL == cls); | ||
747 | if (NULL == dns) | ||
748 | return; /* ignore */ | ||
749 | |||
750 | rr = &requests[dns->id]; | ||
751 | if (rr->phase != RP_INTERNET_DNS) | ||
752 | { | ||
753 | /* unexpected / bogus reply */ | ||
754 | GNUNET_STATISTICS_update (stats, | ||
755 | gettext_noop ( | ||
756 | "# External DNS response discarded (no matching request)"), | ||
757 | 1, GNUNET_NO); | ||
758 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
759 | "Received DNS reply that does not match any pending request. Dropping.\n"); | ||
760 | return; | ||
761 | } | ||
762 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
763 | "Got a response from the stub resolver for DNS request %llu intercepted locally!\n", | ||
764 | (unsigned long long) rr->request_id); | ||
765 | GNUNET_free (rr->payload); | ||
766 | rr->payload = GNUNET_malloc (r); | ||
767 | GNUNET_memcpy (rr->payload, | ||
768 | dns, | ||
769 | r); | ||
770 | rr->payload_length = r; | ||
771 | next_phase (rr); | ||
772 | } | ||
773 | |||
774 | |||
775 | /** | ||
776 | * We got a new client. Make sure all new DNS requests pass by its desk. | ||
777 | * | ||
778 | * @param cls the client | ||
779 | * @param reg the init message | ||
780 | */ | ||
781 | static void | ||
782 | handle_client_init (void *cls, | ||
783 | const struct GNUNET_DNS_Register *reg) | ||
784 | { | ||
785 | struct ClientRecord *cr = cls; | ||
786 | |||
787 | cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); | ||
788 | GNUNET_SERVICE_client_continue (cr->client); | ||
789 | } | ||
790 | |||
791 | |||
792 | /** | ||
793 | * Check a response from a client. | ||
794 | * | ||
795 | * @param cls the client | ||
796 | * @param resp the response | ||
797 | * @return #GNUNET_OK (always fine) | ||
798 | */ | ||
799 | static int | ||
800 | check_client_response (void *cls, | ||
801 | const struct GNUNET_DNS_Response *resp) | ||
802 | { | ||
803 | return GNUNET_OK; /* any payload is acceptable */ | ||
804 | } | ||
805 | |||
806 | |||
807 | /** | ||
808 | * Handle a response from a client. | ||
809 | * | ||
810 | * @param cls the client | ||
811 | * @param resp the response | ||
812 | */ | ||
813 | static void | ||
814 | handle_client_response (void *cls, | ||
815 | const struct GNUNET_DNS_Response *resp) | ||
816 | { | ||
817 | struct ClientRecord *cr = cls; | ||
818 | struct RequestRecord *rr; | ||
819 | uint16_t msize; | ||
820 | uint16_t off; | ||
821 | |||
822 | msize = ntohs (resp->header.size); | ||
823 | off = (uint16_t) resp->request_id; | ||
824 | rr = &requests[off]; | ||
825 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
826 | "Received DNS response with ID %llu from local client!\n", | ||
827 | (unsigned long long) resp->request_id); | ||
828 | if (rr->request_id != resp->request_id) | ||
829 | { | ||
830 | GNUNET_STATISTICS_update (stats, | ||
831 | gettext_noop ( | ||
832 | "# Client response discarded (no matching request)"), | ||
833 | 1, | ||
834 | GNUNET_NO); | ||
835 | GNUNET_SERVICE_client_continue (cr->client); | ||
836 | return; | ||
837 | } | ||
838 | for (unsigned int i = 0; i < rr->client_wait_list_length; i++) | ||
839 | { | ||
840 | if (NULL == rr->client_wait_list[i]) | ||
841 | continue; | ||
842 | if (rr->client_wait_list[i] != cr) | ||
843 | continue; | ||
844 | rr->client_wait_list[i] = NULL; | ||
845 | switch (ntohl (resp->drop_flag)) | ||
846 | { | ||
847 | case 0: /* drop */ | ||
848 | rr->phase = RP_DROP; | ||
849 | break; | ||
850 | |||
851 | case 1: /* no change */ | ||
852 | break; | ||
853 | |||
854 | case 2: /* update */ | ||
855 | msize -= sizeof(struct GNUNET_DNS_Response); | ||
856 | if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) || | ||
857 | (RP_REQUEST_MONITOR == rr->phase) || | ||
858 | (RP_RESPONSE_MONITOR == rr->phase)) | ||
859 | { | ||
860 | GNUNET_break (0); | ||
861 | GNUNET_SERVICE_client_drop (cr->client); | ||
862 | next_phase (rr); | ||
863 | return; | ||
864 | } | ||
865 | GNUNET_free (rr->payload); | ||
866 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
867 | "Changing DNS reply according to client specifications\n"); | ||
868 | rr->payload = GNUNET_malloc (msize); | ||
869 | rr->payload_length = msize; | ||
870 | GNUNET_memcpy (rr->payload, &resp[1], msize); | ||
871 | if (rr->phase == RP_QUERY) | ||
872 | { | ||
873 | /* clear wait list, we're moving to MODIFY phase next */ | ||
874 | GNUNET_array_grow (rr->client_wait_list, | ||
875 | rr->client_wait_list_length, | ||
876 | 0); | ||
877 | } | ||
878 | /* if query changed to answer, move past DNS resolution phase... */ | ||
879 | if ((RP_QUERY == rr->phase) && | ||
880 | (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) && | ||
881 | ( ((struct GNUNET_TUN_DnsFlags*) &(((struct | ||
882 | GNUNET_TUN_DnsHeader*) rr-> | ||
883 | payload)->flags))-> | ||
884 | query_or_response == 1) ) | ||
885 | { | ||
886 | rr->phase = RP_INTERNET_DNS; | ||
887 | GNUNET_array_grow (rr->client_wait_list, | ||
888 | rr->client_wait_list_length, | ||
889 | 0); | ||
890 | } | ||
891 | break; | ||
892 | } | ||
893 | next_phase (rr); | ||
894 | GNUNET_SERVICE_client_continue (cr->client); | ||
895 | return; | ||
896 | } | ||
897 | /* odd, client was not on our list for the request, that ought | ||
898 | to be an error */ | ||
899 | GNUNET_break (0); | ||
900 | GNUNET_SERVICE_client_drop (cr->client); | ||
901 | } | ||
902 | |||
903 | |||
904 | /** | ||
905 | * Functions with this signature are called whenever a complete | ||
906 | * message is received by the tokenizer from the DNS hijack process. | ||
907 | * | ||
908 | * @param cls closure | ||
909 | * @param message the actual message, a DNS request we should handle | ||
910 | */ | ||
911 | static int | ||
912 | process_helper_messages (void *cls, | ||
913 | const struct GNUNET_MessageHeader *message) | ||
914 | { | ||
915 | uint16_t msize; | ||
916 | const struct GNUNET_TUN_Layer2PacketHeader *tun; | ||
917 | const struct GNUNET_TUN_IPv4Header *ip4; | ||
918 | const struct GNUNET_TUN_IPv6Header *ip6; | ||
919 | const struct GNUNET_TUN_UdpHeader *udp; | ||
920 | const struct GNUNET_TUN_DnsHeader *dns; | ||
921 | struct RequestRecord *rr; | ||
922 | struct sockaddr_in *srca4; | ||
923 | struct sockaddr_in6 *srca6; | ||
924 | struct sockaddr_in *dsta4; | ||
925 | struct sockaddr_in6 *dsta6; | ||
926 | |||
927 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
928 | "Intercepted message via DNS hijacker\n"); | ||
929 | msize = ntohs (message->size); | ||
930 | if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct | ||
931 | GNUNET_TUN_Layer2PacketHeader) | ||
932 | + sizeof(struct GNUNET_TUN_IPv4Header)) | ||
933 | { | ||
934 | /* non-IP packet received on TUN!? */ | ||
935 | GNUNET_break (0); | ||
936 | return GNUNET_OK; | ||
937 | } | ||
938 | msize -= sizeof(struct GNUNET_MessageHeader); | ||
939 | tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; | ||
940 | msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader); | ||
941 | switch (ntohs (tun->proto)) | ||
942 | { | ||
943 | case ETH_P_IPV4: | ||
944 | ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1]; | ||
945 | ip6 = NULL; /* make compiler happy */ | ||
946 | if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) || | ||
947 | (ip4->version != 4) || | ||
948 | (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) || | ||
949 | (ntohs (ip4->total_length) != msize) || | ||
950 | (ip4->protocol != IPPROTO_UDP)) | ||
951 | { | ||
952 | /* non-IP/UDP packet received on TUN (or with options) */ | ||
953 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
954 | _ ("Received malformed IPv4-UDP packet on TUN interface.\n")); | ||
955 | return GNUNET_OK; | ||
956 | } | ||
957 | udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1]; | ||
958 | msize -= sizeof(struct GNUNET_TUN_IPv4Header); | ||
959 | break; | ||
960 | |||
961 | case ETH_P_IPV6: | ||
962 | ip4 = NULL; /* make compiler happy */ | ||
963 | ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1]; | ||
964 | if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) || | ||
965 | (ip6->version != 6) || | ||
966 | (ntohs (ip6->payload_length) != msize - sizeof(struct | ||
967 | GNUNET_TUN_IPv6Header)) | ||
968 | || | ||
969 | (ip6->next_header != IPPROTO_UDP)) | ||
970 | { | ||
971 | /* non-IP/UDP packet received on TUN (or with extensions) */ | ||
972 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
973 | _ ("Received malformed IPv6-UDP packet on TUN interface.\n")); | ||
974 | return GNUNET_OK; | ||
975 | } | ||
976 | udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1]; | ||
977 | msize -= sizeof(struct GNUNET_TUN_IPv6Header); | ||
978 | break; | ||
979 | |||
980 | default: | ||
981 | /* non-IP packet received on TUN!? */ | ||
982 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
983 | _ ( | ||
984 | "Got non-IP packet with %u bytes and protocol %u from TUN\n"), | ||
985 | (unsigned int) msize, | ||
986 | ntohs (tun->proto)); | ||
987 | return GNUNET_OK; | ||
988 | } | ||
989 | if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct | ||
990 | GNUNET_TUN_DnsHeader)) | ||
991 | || | ||
992 | (DNS_PORT != ntohs (udp->destination_port))) | ||
993 | { | ||
994 | /* non-DNS packet received on TUN, ignore */ | ||
995 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
996 | _ ("DNS interceptor got non-DNS packet (dropped)\n")); | ||
997 | GNUNET_STATISTICS_update (stats, | ||
998 | gettext_noop ( | ||
999 | "# Non-DNS UDP packet received via TUN interface"), | ||
1000 | 1, GNUNET_NO); | ||
1001 | return GNUNET_OK; | ||
1002 | } | ||
1003 | msize -= sizeof(struct GNUNET_TUN_UdpHeader); | ||
1004 | dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1]; | ||
1005 | rr = &requests[dns->id]; | ||
1006 | |||
1007 | /* clean up from previous request */ | ||
1008 | GNUNET_free (rr->payload); | ||
1009 | rr->payload = NULL; | ||
1010 | GNUNET_array_grow (rr->client_wait_list, | ||
1011 | rr->client_wait_list_length, | ||
1012 | 0); | ||
1013 | |||
1014 | /* setup new request */ | ||
1015 | rr->phase = RP_INIT; | ||
1016 | switch (ntohs (tun->proto)) | ||
1017 | { | ||
1018 | case ETH_P_IPV4: | ||
1019 | { | ||
1020 | srca4 = (struct sockaddr_in*) &rr->src_addr; | ||
1021 | dsta4 = (struct sockaddr_in*) &rr->dst_addr; | ||
1022 | memset (srca4, 0, sizeof(struct sockaddr_in)); | ||
1023 | memset (dsta4, 0, sizeof(struct sockaddr_in)); | ||
1024 | srca4->sin_family = AF_INET; | ||
1025 | dsta4->sin_family = AF_INET; | ||
1026 | srca4->sin_addr = ip4->source_address; | ||
1027 | dsta4->sin_addr = ip4->destination_address; | ||
1028 | srca4->sin_port = udp->source_port; | ||
1029 | dsta4->sin_port = udp->destination_port; | ||
1030 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1031 | srca4->sin_len = sizeof(struct sockaddr_in); | ||
1032 | dsta4->sin_len = sizeof(struct sockaddr_in); | ||
1033 | #endif | ||
1034 | } | ||
1035 | break; | ||
1036 | |||
1037 | case ETH_P_IPV6: | ||
1038 | { | ||
1039 | srca6 = (struct sockaddr_in6*) &rr->src_addr; | ||
1040 | dsta6 = (struct sockaddr_in6*) &rr->dst_addr; | ||
1041 | memset (srca6, 0, sizeof(struct sockaddr_in6)); | ||
1042 | memset (dsta6, 0, sizeof(struct sockaddr_in6)); | ||
1043 | srca6->sin6_family = AF_INET6; | ||
1044 | dsta6->sin6_family = AF_INET6; | ||
1045 | srca6->sin6_addr = ip6->source_address; | ||
1046 | dsta6->sin6_addr = ip6->destination_address; | ||
1047 | srca6->sin6_port = udp->source_port; | ||
1048 | dsta6->sin6_port = udp->destination_port; | ||
1049 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1050 | srca6->sin6_len = sizeof(struct sockaddr_in6); | ||
1051 | dsta6->sin6_len = sizeof(struct sockaddr_in6); | ||
1052 | #endif | ||
1053 | } | ||
1054 | break; | ||
1055 | |||
1056 | default: | ||
1057 | GNUNET_assert (0); | ||
1058 | } | ||
1059 | rr->payload = GNUNET_malloc (msize); | ||
1060 | rr->payload_length = msize; | ||
1061 | GNUNET_memcpy (rr->payload, dns, msize); | ||
1062 | rr->request_id = dns->id | (request_id_gen << 16); | ||
1063 | request_id_gen++; | ||
1064 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1065 | "Creating new DNS request %llu\n", | ||
1066 | (unsigned long long) rr->request_id); | ||
1067 | GNUNET_STATISTICS_update (stats, | ||
1068 | gettext_noop ( | ||
1069 | "# DNS requests received via TUN interface"), | ||
1070 | 1, GNUNET_NO); | ||
1071 | /* start request processing state machine */ | ||
1072 | next_phase (rr); | ||
1073 | return GNUNET_OK; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /** | ||
1078 | * @param cls closure | ||
1079 | * @param cfg_ configuration to use | ||
1080 | * @param service the initialized service | ||
1081 | */ | ||
1082 | static void | ||
1083 | run (void *cls, | ||
1084 | const struct GNUNET_CONFIGURATION_Handle *cfg_, | ||
1085 | struct GNUNET_SERVICE_Handle *service) | ||
1086 | { | ||
1087 | char *ifc_name; | ||
1088 | char *ipv4addr; | ||
1089 | char *ipv4mask; | ||
1090 | char *ipv6addr; | ||
1091 | char *ipv6prefix; | ||
1092 | char *dns_exit; | ||
1093 | char *binary; | ||
1094 | int nortsetup; | ||
1095 | |||
1096 | cfg = cfg_; | ||
1097 | stats = GNUNET_STATISTICS_create ("dns", cfg); | ||
1098 | GNUNET_SCHEDULER_add_shutdown (&cleanup_task, | ||
1099 | cls); | ||
1100 | dnsstub = GNUNET_DNSSTUB_start (128); | ||
1101 | /* TODO: support multiple DNS_EXIT servers being configured */ | ||
1102 | /* TODO: see above TODO on using DNS server from original packet. | ||
1103 | Not sure which is best... */ | ||
1104 | dns_exit = NULL; | ||
1105 | if ((GNUNET_OK != | ||
1106 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1107 | "dns", | ||
1108 | "DNS_EXIT", | ||
1109 | &dns_exit)) || | ||
1110 | (GNUNET_OK != | ||
1111 | GNUNET_DNSSTUB_add_dns_ip (dnsstub, | ||
1112 | dns_exit))) | ||
1113 | { | ||
1114 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, | ||
1115 | "dns", | ||
1116 | "DNS_EXIT", | ||
1117 | _ ("need a valid IPv4 or IPv6 address\n")); | ||
1118 | GNUNET_free (dns_exit); | ||
1119 | } | ||
1120 | binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-dns"); | ||
1121 | |||
1122 | if (GNUNET_YES != | ||
1123 | GNUNET_OS_check_helper_binary (binary, | ||
1124 | GNUNET_YES, | ||
1125 | NULL)) // TODO: once we have a windows-testcase, add test parameters here | ||
1126 | { | ||
1127 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1128 | _ ("`%s' is not SUID or the path is invalid, " | ||
1129 | "will not run DNS interceptor\n"), | ||
1130 | binary); | ||
1131 | global_ret = 1; | ||
1132 | GNUNET_free (binary); | ||
1133 | return; | ||
1134 | } | ||
1135 | GNUNET_free (binary); | ||
1136 | |||
1137 | helper_argv[0] = GNUNET_strdup ("gnunet-dns"); | ||
1138 | if (GNUNET_SYSERR == | ||
1139 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1140 | "dns", | ||
1141 | "IFNAME", | ||
1142 | &ifc_name)) | ||
1143 | { | ||
1144 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1145 | "No entry 'IFNAME' in configuration!\n"); | ||
1146 | GNUNET_free (binary); | ||
1147 | GNUNET_SCHEDULER_shutdown (); | ||
1148 | return; | ||
1149 | } | ||
1150 | helper_argv[1] = ifc_name; | ||
1151 | if ((GNUNET_SYSERR == | ||
1152 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1153 | "dns", | ||
1154 | "IPV6ADDR", | ||
1155 | &ipv6addr))) | ||
1156 | { | ||
1157 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1158 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1159 | GNUNET_free (binary); | ||
1160 | GNUNET_SCHEDULER_shutdown (); | ||
1161 | return; | ||
1162 | } | ||
1163 | helper_argv[2] = ipv6addr; | ||
1164 | if (GNUNET_SYSERR == | ||
1165 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1166 | "dns", | ||
1167 | "IPV6PREFIX", | ||
1168 | &ipv6prefix)) | ||
1169 | { | ||
1170 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1171 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1172 | GNUNET_free (binary); | ||
1173 | GNUNET_SCHEDULER_shutdown (); | ||
1174 | return; | ||
1175 | } | ||
1176 | helper_argv[3] = ipv6prefix; | ||
1177 | |||
1178 | if (GNUNET_SYSERR == | ||
1179 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1180 | "dns", | ||
1181 | "IPV4ADDR", | ||
1182 | &ipv4addr)) | ||
1183 | { | ||
1184 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1185 | "No entry 'IPV4ADDR' in configuration!\n"); | ||
1186 | GNUNET_free (binary); | ||
1187 | GNUNET_SCHEDULER_shutdown (); | ||
1188 | return; | ||
1189 | } | ||
1190 | helper_argv[4] = ipv4addr; | ||
1191 | if (GNUNET_SYSERR == | ||
1192 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", | ||
1193 | &ipv4mask)) | ||
1194 | { | ||
1195 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1196 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1197 | GNUNET_free (binary); | ||
1198 | GNUNET_SCHEDULER_shutdown (); | ||
1199 | return; | ||
1200 | } | ||
1201 | helper_argv[5] = ipv4mask; | ||
1202 | |||
1203 | nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns", | ||
1204 | "SKIP_ROUTING_SETUP"); | ||
1205 | if (GNUNET_YES == nortsetup) | ||
1206 | helper_argv[6] = GNUNET_strdup ("1"); | ||
1207 | else | ||
1208 | helper_argv[6] = GNUNET_strdup ("0"); | ||
1209 | |||
1210 | helper_argv[7] = NULL; | ||
1211 | hijacker = GNUNET_HELPER_start (GNUNET_NO, | ||
1212 | binary, | ||
1213 | helper_argv, | ||
1214 | &process_helper_messages, | ||
1215 | NULL, NULL); | ||
1216 | GNUNET_free (binary); | ||
1217 | } | ||
1218 | |||
1219 | |||
1220 | /** | ||
1221 | * Define "main" method using service macro. | ||
1222 | */ | ||
1223 | GNUNET_SERVICE_MAIN | ||
1224 | ("dns", | ||
1225 | GNUNET_SERVICE_OPTION_NONE, | ||
1226 | &run, | ||
1227 | &client_connect_cb, | ||
1228 | &client_disconnect_cb, | ||
1229 | NULL, | ||
1230 | GNUNET_MQ_hd_fixed_size (client_init, | ||
1231 | GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, | ||
1232 | struct GNUNET_DNS_Register, | ||
1233 | NULL), | ||
1234 | GNUNET_MQ_hd_var_size (client_response, | ||
1235 | GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, | ||
1236 | struct GNUNET_DNS_Response, | ||
1237 | NULL), | ||
1238 | GNUNET_MQ_handler_end ()); | ||
1239 | |||
1240 | |||
1241 | /* FIXME: this might need a port on systems without 'getresgid' */ | ||
1242 | #if HAVE_GETRESGID | ||
1243 | /** | ||
1244 | * Enable use of SGID capabilities on POSIX | ||
1245 | */ | ||
1246 | void __attribute__ ((constructor)) | ||
1247 | GNUNET_DNS_init () | ||
1248 | { | ||
1249 | gid_t rgid; | ||
1250 | gid_t egid; | ||
1251 | gid_t sgid; | ||
1252 | |||
1253 | if (-1 == getresgid (&rgid, | ||
1254 | &egid, | ||
1255 | &sgid)) | ||
1256 | { | ||
1257 | fprintf (stderr, | ||
1258 | "getresgid failed: %s\n", | ||
1259 | strerror (errno)); | ||
1260 | } | ||
1261 | else if (sgid != rgid) | ||
1262 | { | ||
1263 | if (-1 == setregid (sgid, | ||
1264 | sgid)) | ||
1265 | fprintf (stderr, | ||
1266 | "setregid failed: %s\n", | ||
1267 | strerror (errno)); | ||
1268 | } | ||
1269 | } | ||
1270 | |||
1271 | |||
1272 | #endif | ||
1273 | |||
1274 | |||
1275 | /* end of gnunet-service-dns.c */ | ||