GNUnet debian-0.24.3-29-g453fda2cf
 
Loading...
Searching...
No Matches
gnunet-service-dns.c File Reference

service to intercept and modify DNS queries (and replies) of this system More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_protocols.h"
#include "dns.h"
#include "gnunet_dns_service.h"
#include "gnunet_statistics_service.h"
Include dependency graph for gnunet-service-dns.c:

Go to the source code of this file.

Data Structures

struct  ClientRecord
 Entry we keep for each client. More...
 
struct  RequestRecord
 Entry we keep for each active request. More...
 

Macros

#define DNS_PORT   53
 Port number for DNS.
 
#define LOG(kind, ...)    GNUNET_log_from (kind, "dns", __VA_ARGS__);
 Generic logging shorthand.
 

Enumerations

enum  RequestPhase {
  RP_INIT , RP_REQUEST_MONITOR , RP_QUERY , RP_INTERNET_DNS ,
  RP_MODIFY , RP_RESPONSE_MONITOR , RP_DROP
}
 Phases each request goes through. More...
 

Functions

static void cleanup_rr (struct RequestRecord *rr)
 We're done processing a DNS request, free associated memory.
 
static void cleanup_task (void *cls)
 Task run during shutdown.
 
static void request_done (struct RequestRecord *rr)
 We're done with some request, finish processing.
 
static void send_request_to_client (struct RequestRecord *rr, struct ClientRecord *cr)
 Show the payload of the given request record to the client (and wait for a response).
 
static void process_dns_result (void *cls, const struct GNUNET_TUN_DnsHeader *dns, size_t r)
 Callback called from DNSSTUB resolver when a resolution succeeded.
 
static void next_phase (struct RequestRecord *rr)
 A client has completed its processing for this request.
 
static void * client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
 A client connected, setup our data structures.
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
 A client disconnected, clean up after it.
 
static void handle_client_init (void *cls, const struct GNUNET_DNS_Register *reg)
 We got a new client.
 
static int check_client_response (void *cls, const struct GNUNET_DNS_Response *resp)
 Check a response from a client.
 
static void handle_client_response (void *cls, const struct GNUNET_DNS_Response *resp)
 Handle a response from a client.
 
static int process_helper_messages (void *cls, const struct GNUNET_MessageHeader *message)
 Functions with this signature are called whenever a complete message is received by the tokenizer from the DNS hijack process.
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct GNUNET_SERVICE_Handle *service)
 
 GNUNET_SERVICE_MAIN (GNUNET_OS_project_data_gnunet(), "dns", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_fixed_size(client_init, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, struct GNUNET_DNS_Register, NULL), GNUNET_MQ_hd_var_size(client_response, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, struct GNUNET_DNS_Response, NULL), GNUNET_MQ_handler_end())
 Define "main" method using service macro.
 

Variables

static int global_ret
 Global return value from 'main'.
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 The configuration to use.
 
static struct GNUNET_STATISTICS_Handlestats
 Statistics.
 
static struct GNUNET_HELPER_Handlehijacker
 Handle to DNS hijacker helper process ("gnunet-helper-dns").
 
static char * helper_argv [8]
 Command-line arguments we are giving to the hijacker process.
 
static struct ClientRecordclients_head
 Head of DLL of clients we consult.
 
static struct ClientRecordclients_tail
 Tail of DLL of clients we consult.
 
static struct RequestRecord requests [UINT16_MAX+1]
 Array of all open requests.
 
static uint64_t request_id_gen
 Generator for unique request IDs.
 
static struct GNUNET_DNSSTUB_Contextdnsstub
 Handle to the DNS Stub resolver.
 

Detailed Description

service to intercept and modify DNS queries (and replies) of this system

Author
Christian Grothoff

For "secure" interaction with the legacy DNS system, we permit replies only to arrive within a 5s window (and they must match ports, IPs and request IDs). Furthermore, we let the OS pick a source port, opening up to 128 sockets per address family (IPv4 or IPv6). Those sockets are closed if they are not in use for 5s (which means they will be freshly randomized afterwards). For new requests, we pick a random slot in the array with 128 socket slots (and reuse an existing socket if the slot is still in use). Thus each request will be given one of 128 random source ports, and the 128 random source ports will also change "often" (less often if the system is very busy, each time if we are mostly idle). At the same time, the system will never use more than 256 UDP sockets.

Definition in file gnunet-service-dns.c.

Macro Definition Documentation

◆ DNS_PORT

#define DNS_PORT   53

Port number for DNS.

Definition at line 49 of file gnunet-service-dns.c.

◆ LOG

#define LOG (   kind,
  ... 
)     GNUNET_log_from (kind, "dns", __VA_ARGS__);

Generic logging shorthand.

Definition at line 55 of file gnunet-service-dns.c.

62{
66 RP_INIT,
67
73
79
84
91
97
101 RP_DROP
102};
103
104
108struct ClientRecord
109{
113 struct ClientRecord *next;
114
118 struct ClientRecord *prev;
119
124
128 struct GNUNET_MQ_Handle *mq;
129
134};
135
136
140struct RequestRecord
141{
147
152 char *payload;
153
159
163 struct sockaddr_storage src_addr;
164
168 struct sockaddr_storage dst_addr;
169
175 uint64_t request_id;
176
180 size_t payload_length;
181
185 unsigned int client_wait_list_length;
186
190 enum RequestPhase phase;
191};
192
193
197static int global_ret;
198
202static const struct GNUNET_CONFIGURATION_Handle *cfg;
203
207static struct GNUNET_STATISTICS_Handle *stats;
208
212static struct GNUNET_HELPER_Handle *hijacker;
213
217static char *helper_argv[8];
218
222static struct ClientRecord *clients_head;
223
227static struct ClientRecord *clients_tail;
228
232static struct RequestRecord requests[UINT16_MAX + 1];
233
237static uint64_t request_id_gen;
238
242static struct GNUNET_DNSSTUB_Context *dnsstub;
243
244
250static void
251cleanup_rr (struct RequestRecord *rr)
252{
253 GNUNET_free (rr->payload);
254 rr->payload = NULL;
255 rr->payload_length = 0;
258 0);
259}
260
261
267static void
268cleanup_task (void *cls GNUNET_UNUSED)
269{
270 if (NULL != hijacker)
271 {
273 hijacker = NULL;
274 }
275 for (unsigned int i = 0; i < 8; i++)
277 for (unsigned int i = 0; i <= UINT16_MAX; i++)
278 cleanup_rr (&requests[i]);
279 if (NULL != stats)
280 {
282 GNUNET_NO);
283 stats = NULL;
284 }
285 if (NULL != dnsstub)
286 {
288 dnsstub = NULL;
289 }
290}
291
292
298static void
299request_done (struct RequestRecord *rr)
300{
301 struct GNUNET_MessageHeader *hdr;
302 size_t reply_len;
303 uint16_t source_port;
304 uint16_t destination_port;
305
308 0);
309 if (RP_RESPONSE_MONITOR != rr->phase)
310 {
311 /* no response, drop */
313 "Got no response for request %llu, dropping\n",
314 (unsigned long long) rr->request_id);
315 cleanup_rr (rr);
316 return;
317 }
318
320 "Transmitting response for request %llu\n",
321 (unsigned long long) rr->request_id);
322 /* send response via hijacker */
323 reply_len = sizeof(struct GNUNET_MessageHeader);
324 reply_len += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
325 switch (rr->src_addr.ss_family)
326 {
327 case AF_INET:
328 reply_len += sizeof(struct GNUNET_TUN_IPv4Header);
329 break;
330
331 case AF_INET6:
332 reply_len += sizeof(struct GNUNET_TUN_IPv6Header);
333 break;
334
335 default:
336 GNUNET_break (0);
337 cleanup_rr (rr);
338 return;
339 }
340 reply_len += sizeof(struct GNUNET_TUN_UdpHeader);
341 reply_len += rr->payload_length;
342 if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
343 {
344 /* response too big, drop */
345 GNUNET_break (0); /* how can this be? */
346 cleanup_rr (rr);
347 return;
348 }
349 {
350 char buf[reply_len] GNUNET_ALIGN;
351 size_t off;
352 struct GNUNET_TUN_IPv4Header ip4;
353 struct GNUNET_TUN_IPv6Header ip6;
354
355 /* first, GNUnet message header */
356 hdr = (struct GNUNET_MessageHeader*) buf;
358 hdr->size = htons ((uint16_t) reply_len);
359 off = sizeof(struct GNUNET_MessageHeader);
360
361 /* first, TUN header */
362 {
364
365 tun.flags = htons (0);
366 if (rr->src_addr.ss_family == AF_INET)
367 tun.proto = htons (ETH_P_IPV4);
368 else
369 tun.proto = htons (ETH_P_IPV6);
370 GNUNET_memcpy (&buf[off],
371 &tun,
372 sizeof(struct GNUNET_TUN_Layer2PacketHeader));
373 off += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
374 }
375
376 /* now IP header */
377 switch (rr->src_addr.ss_family)
378 {
379 case AF_INET:
380 {
381 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
382 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
383
384 source_port = dst->sin_port;
385 destination_port = src->sin_port;
387 IPPROTO_UDP,
388 reply_len - off - sizeof(struct
390 &dst->sin_addr,
391 &src->sin_addr);
392 GNUNET_memcpy (&buf[off],
393 &ip4,
394 sizeof(ip4));
395 off += sizeof(ip4);
396 }
397 break;
398
399 case AF_INET6:
400 {
401 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
402 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
403
404 source_port = dst->sin6_port;
405 destination_port = src->sin6_port;
407 IPPROTO_UDP,
408 reply_len - off - sizeof(struct
410 &dst->sin6_addr,
411 &src->sin6_addr);
412 GNUNET_memcpy (&buf[off],
413 &ip6,
414 sizeof(ip6));
415 off += sizeof(ip6);
416 }
417 break;
418
419 default:
420 GNUNET_assert (0);
421 }
422
423 /* now UDP header */
424 {
426
428 udp.destination_port = destination_port;
429 udp.len = htons (reply_len - off);
430 if (AF_INET == rr->src_addr.ss_family)
432 &udp,
433 rr->payload,
434 rr->payload_length);
435 else
437 &udp,
438 rr->payload,
439 rr->payload_length);
440 GNUNET_memcpy (&buf[off],
441 &udp,
442 sizeof(udp));
443 off += sizeof(udp);
444 }
445
446 /* now DNS payload */
447 {
448 GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
449 off += rr->payload_length;
450 }
451 /* final checks & sending */
452 GNUNET_assert (off == reply_len);
454 hdr,
456 NULL, NULL);
459 "# DNS requests answered via TUN interface"),
460 1, GNUNET_NO);
461 }
462 /* clean up, we're done */
463 cleanup_rr (rr);
464}
465
466
474static void
476 struct ClientRecord *cr)
477{
478 struct GNUNET_MQ_Envelope *env;
479 struct GNUNET_DNS_Request *req;
480
481 if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >=
483 {
484 GNUNET_break (0);
485 cleanup_rr (rr);
486 return;
487 }
489 "Sending information about request %llu to local client\n",
490 (unsigned long long) rr->request_id);
492 rr->payload_length,
494 req->reserved = htonl (0);
495 req->request_id = rr->request_id;
496 GNUNET_memcpy (&req[1],
497 rr->payload,
498 rr->payload_length);
499 GNUNET_MQ_send (cr->mq,
500 env);
501}
502
503
512static void
513process_dns_result (void *cls,
514 const struct GNUNET_TUN_DnsHeader *dns,
515 size_t r);
516
517
524static void
525next_phase (struct RequestRecord *rr)
526{
527 struct ClientRecord *cr;
528 int nz;
529
530 if (rr->phase == RP_DROP)
531 {
532 cleanup_rr (rr);
533 return;
534 }
535 nz = -1;
536 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
537 {
538 if (NULL != rr->client_wait_list[j])
539 {
540 nz = (int) j;
541 break;
542 }
543 }
544 if (-1 != nz)
545 {
547 rr->client_wait_list[nz]);
548 return;
549 }
550 /* done with current phase, advance! */
552 "Request %llu now in phase %d\n",
553 (unsigned long long) rr->request_id,
554 rr->phase);
555 switch (rr->phase)
556 {
557 case RP_INIT:
559 for (cr = clients_head; NULL != cr; cr = cr->next)
560 {
561 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
564 cr);
565 }
566 next_phase (rr);
567 return;
568
570 rr->phase = RP_QUERY;
571 for (cr = clients_head; NULL != cr; cr = cr->next)
572 {
573 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
576 cr);
577 }
578 next_phase (rr);
579 return;
580
581 case RP_QUERY:
582#if 0
583 /* TODO: optionally, use this to forward DNS requests to the
584 * original* DNS server instead of the one we have configured...
585 (but then we need to create a fresh dnsstub for each request
586 * and* manage the timeout) */
587 switch (rr->dst_addr.ss_family)
588 {
589 case AF_INET:
590 salen = sizeof(struct sockaddr_in);
591 sa = (const struct sockaddr *) &rr->dst_addr;
592 break;
593
594 case AF_INET6:
595 salen = sizeof(struct sockaddr_in6);
596 sa = (const struct sockaddr *) &rr->dst_addr;
597 break;
598
599 default:
600 GNUNET_assert (0);
601 }
602#endif
605 rr->payload,
606 rr->payload_length,
608 NULL);
609 if (NULL == rr->rs)
610 {
613 "# DNS exit failed (failed to open socket)"),
614 1,
615 GNUNET_NO);
616 cleanup_rr (rr);
617 return;
618 }
619 return;
620
621 case RP_INTERNET_DNS:
622 rr->phase = RP_MODIFY;
623 for (cr = clients_head; NULL != cr; cr = cr->next)
624 {
625 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
628 cr);
629 }
630 next_phase (rr);
631 return;
632
633 case RP_MODIFY:
635 for (cr = clients_head; NULL != cr; cr = cr->next)
636 {
640 cr);
641 }
642 next_phase (rr);
643 return;
644
646 request_done (rr);
647 break;
648
649 case RP_DROP:
650 cleanup_rr (rr);
651 break;
652
653 default:
654 GNUNET_break (0);
655 cleanup_rr (rr);
656 break;
657 }
658}
659
660
669static void *
670client_connect_cb (void *cls,
671 struct GNUNET_SERVICE_Client *client,
672 struct GNUNET_MQ_Handle *mq)
673{
674 struct ClientRecord *cr = cls;
675
676 cr = GNUNET_new (struct ClientRecord);
677 cr->client = client;
678 cr->mq = mq;
681 cr);
682 return cr;
683}
684
685
693static void
694client_disconnect_cb (void *cls,
696 void *app_ctx)
697{
698 struct ClientRecord *cr = app_ctx;
699 struct RequestRecord *rr;
700
703 cr);
704 for (unsigned int i = 0; i < UINT16_MAX; i++)
705 {
706 rr = &requests[i];
707 if (0 == rr->client_wait_list_length)
708 continue; /* not in use */
709 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
710 {
711 if (rr->client_wait_list[j] == cr)
712 {
713 rr->client_wait_list[j] = NULL;
714 next_phase (rr);
715 }
716 }
717 }
718 GNUNET_free (cr);
719}
720
721
730static void
731process_dns_result (void *cls,
732 const struct GNUNET_TUN_DnsHeader *dns,
733 size_t r)
734{
735 struct RequestRecord *rr;
736
738 "Processing DNS result from stub resolver\n");
739 GNUNET_assert (NULL == cls);
740 if (NULL == dns)
741 return; /* ignore */
742
743 rr = &requests[dns->id];
744 if (rr->phase != RP_INTERNET_DNS)
745 {
746 /* unexpected / bogus reply */
749 "# External DNS response discarded (no matching request)"),
750 1, GNUNET_NO);
752 "Received DNS reply that does not match any pending request. Dropping.\n");
753 return;
754 }
756 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
757 (unsigned long long) rr->request_id);
758 GNUNET_free (rr->payload);
759 rr->payload = GNUNET_malloc (r);
761 dns,
762 r);
763 rr->payload_length = r;
764 next_phase (rr);
765}
766
767
774static void
775handle_client_init (void *cls,
776 const struct GNUNET_DNS_Register *reg)
777{
778 struct ClientRecord *cr = cls;
779
780 cr->flags = ntohl (reg->flags);
782}
783
784
792static int
793check_client_response (void *cls,
794 const struct GNUNET_DNS_Response *resp)
795{
796 return GNUNET_OK; /* any payload is acceptable */
797}
798
799
806static void
807handle_client_response (void *cls,
808 const struct GNUNET_DNS_Response *resp)
809{
810 struct ClientRecord *cr = cls;
811 struct RequestRecord *rr;
812 uint16_t msize;
813 uint16_t off;
814
815 msize = ntohs (resp->header.size);
816 off = (uint16_t) resp->request_id;
817 rr = &requests[off];
819 "Received DNS response with ID %llu from local client!\n",
820 (unsigned long long) resp->request_id);
821 if (rr->request_id != resp->request_id)
822 {
825 "# Client response discarded (no matching request)"),
826 1,
827 GNUNET_NO);
829 return;
830 }
831 for (unsigned int i = 0; i < rr->client_wait_list_length; i++)
832 {
833 if (NULL == rr->client_wait_list[i])
834 continue;
835 if (rr->client_wait_list[i] != cr)
836 continue;
837 rr->client_wait_list[i] = NULL;
838 switch (ntohl (resp->drop_flag))
839 {
840 case 0: /* drop */
841 rr->phase = RP_DROP;
842 break;
843
844 case 1: /* no change */
845 break;
846
847 case 2: /* update */
848 msize -= sizeof(struct GNUNET_DNS_Response);
849 if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) ||
850 (RP_REQUEST_MONITOR == rr->phase) ||
851 (RP_RESPONSE_MONITOR == rr->phase))
852 {
853 GNUNET_break (0);
855 next_phase (rr);
856 return;
857 }
858 GNUNET_free (rr->payload);
860 "Changing DNS reply according to client specifications\n");
861 rr->payload = GNUNET_malloc (msize);
862 rr->payload_length = msize;
863 GNUNET_memcpy (rr->payload, &resp[1], msize);
864 if (rr->phase == RP_QUERY)
865 {
866 /* clear wait list, we're moving to MODIFY phase next */
869 0);
870 }
871 /* if query changed to answer, move past DNS resolution phase... */
872 if ((RP_QUERY == rr->phase) &&
873 (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) &&
874 ( ((struct GNUNET_TUN_DnsFlags*) &(((struct
876 payload)->flags))->
877 query_or_response == 1) )
878 {
882 0);
883 }
884 break;
885 }
886 next_phase (rr);
888 return;
889 }
890 /* odd, client was not on our list for the request, that ought
891 to be an error */
892 GNUNET_break (0);
894}
895
896
904static int
905process_helper_messages (void *cls,
906 const struct GNUNET_MessageHeader *message)
907{
908 uint16_t msize;
909 const struct GNUNET_TUN_Layer2PacketHeader *tun;
910 const struct GNUNET_TUN_IPv4Header *ip4;
911 const struct GNUNET_TUN_IPv6Header *ip6;
912 const struct GNUNET_TUN_UdpHeader *udp;
913 const struct GNUNET_TUN_DnsHeader *dns;
914 struct RequestRecord *rr;
915 struct sockaddr_in *srca4;
916 struct sockaddr_in6 *srca6;
917 struct sockaddr_in *dsta4;
918 struct sockaddr_in6 *dsta6;
919
921 "Intercepted message via DNS hijacker\n");
922 msize = ntohs (message->size);
923 if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct
925 + sizeof(struct GNUNET_TUN_IPv4Header))
926 {
927 /* non-IP packet received on TUN!? */
928 GNUNET_break (0);
929 return GNUNET_OK;
930 }
931 msize -= sizeof(struct GNUNET_MessageHeader);
932 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
933 msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader);
934 switch (ntohs (tun->proto))
935 {
936 case ETH_P_IPV4:
937 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
938 ip6 = NULL; /* make compiler happy */
939 if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) ||
940 (ip4->version != 4) ||
941 (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) ||
942 (ntohs (ip4->total_length) != msize) ||
943 (ip4->protocol != IPPROTO_UDP))
944 {
945 /* non-IP/UDP packet received on TUN (or with options) */
947 _ ("Received malformed IPv4-UDP packet on TUN interface.\n"));
948 return GNUNET_OK;
949 }
950 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
951 msize -= sizeof(struct GNUNET_TUN_IPv4Header);
952 break;
953
954 case ETH_P_IPV6:
955 ip4 = NULL; /* make compiler happy */
956 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
957 if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) ||
958 (ip6->version != 6) ||
959 (ntohs (ip6->payload_length) != msize - sizeof(struct
961 ||
962 (ip6->next_header != IPPROTO_UDP))
963 {
964 /* non-IP/UDP packet received on TUN (or with extensions) */
966 _ ("Received malformed IPv6-UDP packet on TUN interface.\n"));
967 return GNUNET_OK;
968 }
969 udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
970 msize -= sizeof(struct GNUNET_TUN_IPv6Header);
971 break;
972
973 default:
974 /* non-IP packet received on TUN!? */
976 _ (
977 "Got non-IP packet with %u bytes and protocol %u from TUN\n"),
978 (unsigned int) msize,
979 ntohs (tun->proto));
980 return GNUNET_OK;
981 }
982 if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct
984 ||
985 (DNS_PORT != ntohs (udp->destination_port)))
986 {
987 /* non-DNS packet received on TUN, ignore */
989 _ ("DNS interceptor got non-DNS packet (dropped)\n"));
992 "# Non-DNS UDP packet received via TUN interface"),
993 1, GNUNET_NO);
994 return GNUNET_OK;
995 }
996 msize -= sizeof(struct GNUNET_TUN_UdpHeader);
997 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
998 rr = &requests[dns->id];
999
1000 /* clean up from previous request */
1001 GNUNET_free (rr->payload);
1002 rr->payload = NULL;
1005 0);
1006
1007 /* setup new request */
1008 rr->phase = RP_INIT;
1009 switch (ntohs (tun->proto))
1010 {
1011 case ETH_P_IPV4:
1012 {
1013 srca4 = (struct sockaddr_in*) &rr->src_addr;
1014 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1015 memset (srca4, 0, sizeof(struct sockaddr_in));
1016 memset (dsta4, 0, sizeof(struct sockaddr_in));
1017 srca4->sin_family = AF_INET;
1018 dsta4->sin_family = AF_INET;
1019 srca4->sin_addr = ip4->source_address;
1020 dsta4->sin_addr = ip4->destination_address;
1021 srca4->sin_port = udp->source_port;
1022 dsta4->sin_port = udp->destination_port;
1023#if HAVE_SOCKADDR_IN_SIN_LEN
1024 srca4->sin_len = sizeof(struct sockaddr_in);
1025 dsta4->sin_len = sizeof(struct sockaddr_in);
1026#endif
1027 }
1028 break;
1029
1030 case ETH_P_IPV6:
1031 {
1032 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1033 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1034 memset (srca6, 0, sizeof(struct sockaddr_in6));
1035 memset (dsta6, 0, sizeof(struct sockaddr_in6));
1036 srca6->sin6_family = AF_INET6;
1037 dsta6->sin6_family = AF_INET6;
1038 srca6->sin6_addr = ip6->source_address;
1039 dsta6->sin6_addr = ip6->destination_address;
1040 srca6->sin6_port = udp->source_port;
1041 dsta6->sin6_port = udp->destination_port;
1042#if HAVE_SOCKADDR_IN_SIN_LEN
1043 srca6->sin6_len = sizeof(struct sockaddr_in6);
1044 dsta6->sin6_len = sizeof(struct sockaddr_in6);
1045#endif
1046 }
1047 break;
1048
1049 default:
1050 GNUNET_assert (0);
1051 }
1052 rr->payload = GNUNET_malloc (msize);
1053 rr->payload_length = msize;
1054 GNUNET_memcpy (rr->payload, dns, msize);
1055 rr->request_id = dns->id | (request_id_gen << 16);
1058 "Creating new DNS request %llu\n",
1059 (unsigned long long) rr->request_id);
1061 gettext_noop (
1062 "# DNS requests received via TUN interface"),
1063 1, GNUNET_NO);
1064 /* start request processing state machine */
1065 next_phase (rr);
1066 return GNUNET_OK;
1067}
1068
1069
1075static void
1076run (void *cls,
1077 const struct GNUNET_CONFIGURATION_Handle *cfg_,
1079{
1080 char *ifc_name;
1081 char *ipv4addr;
1082 char *ipv4mask;
1083 char *ipv6addr;
1084 char *ipv6prefix;
1085 char *dns_exit;
1086 char *binary;
1087 int nortsetup;
1088
1089 cfg = cfg_;
1092 cls);
1094 /* TODO: support multiple DNS_EXIT servers being configured */
1095 /* TODO: see above TODO on using DNS server from original packet.
1096 Not sure which is best... */
1097 dns_exit = NULL;
1098 if ((GNUNET_OK !=
1100 "dns",
1101 "DNS_EXIT",
1102 &dns_exit)) ||
1103 (GNUNET_OK !=
1105 dns_exit)))
1106 {
1108 "dns",
1109 "DNS_EXIT",
1110 _ ("need a valid IPv4 or IPv6 address\n"));
1111 GNUNET_free (dns_exit);
1112 }
1114 cfg,
1115 "gnunet-helper-dns");
1116
1117 if (GNUNET_YES !=
1119 GNUNET_YES,
1120 NULL)) // TODO: once we have a windows-testcase, add test parameters here
1121 {
1123 _ ("`%s' is not SUID or the path is invalid, "
1124 "will not run DNS interceptor\n"),
1125 binary);
1126 global_ret = 1;
1127 GNUNET_free (binary);
1128 return;
1129 }
1130 GNUNET_free (binary);
1131
1132 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1133 if (GNUNET_SYSERR ==
1135 "dns",
1136 "IFNAME",
1137 &ifc_name))
1138 {
1140 "No entry 'IFNAME' in configuration!\n");
1141 GNUNET_free (binary);
1143 return;
1144 }
1145 helper_argv[1] = ifc_name;
1146 if ((GNUNET_SYSERR ==
1148 "dns",
1149 "IPV6ADDR",
1150 &ipv6addr)))
1151 {
1153 "No entry 'IPV6ADDR' in configuration!\n");
1154 GNUNET_free (binary);
1156 return;
1157 }
1158 helper_argv[2] = ipv6addr;
1159 if (GNUNET_SYSERR ==
1161 "dns",
1162 "IPV6PREFIX",
1163 &ipv6prefix))
1164 {
1166 "No entry 'IPV6PREFIX' in configuration!\n");
1167 GNUNET_free (binary);
1169 return;
1170 }
1172
1173 if (GNUNET_SYSERR ==
1175 "dns",
1176 "IPV4ADDR",
1177 &ipv4addr))
1178 {
1180 "No entry 'IPV4ADDR' in configuration!\n");
1181 GNUNET_free (binary);
1183 return;
1184 }
1185 helper_argv[4] = ipv4addr;
1186 if (GNUNET_SYSERR ==
1187 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1188 &ipv4mask))
1189 {
1191 "No entry 'IPV4MASK' in configuration!\n");
1192 GNUNET_free (binary);
1194 return;
1195 }
1196 helper_argv[5] = ipv4mask;
1197
1198 nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1199 "SKIP_ROUTING_SETUP");
1200 if (GNUNET_YES == nortsetup)
1201 helper_argv[6] = GNUNET_strdup ("1");
1202 else
1203 helper_argv[6] = GNUNET_strdup ("0");
1204
1205 helper_argv[7] = NULL;
1207 GNUNET_NO,
1208 binary,
1211 NULL, NULL);
1212 GNUNET_free (binary);
1213}
1214
1215
1221 "dns",
1223 &run,
1226 NULL,
1227 GNUNET_MQ_hd_fixed_size (client_init,
1229 struct GNUNET_DNS_Register,
1230 NULL),
1231 GNUNET_MQ_hd_var_size (client_response,
1233 struct GNUNET_DNS_Response,
1234 NULL),
1236
1237
1238/* FIXME: this might need a port on systems without 'getresgid' */
1239#if HAVE_GETRESGID
1240void __attribute__((constructor)) GNUNET_DNS_init (void);
1241
1245void __attribute__ ((constructor))
1246GNUNET_DNS_init (void)
1247{
1248 gid_t rgid;
1249 gid_t egid;
1250 gid_t sgid;
1251
1252 if (-1 == getresgid (&rgid,
1253 &egid,
1254 &sgid))
1255 {
1256 fprintf (stderr,
1257 "getresgid failed: %s\n",
1258 strerror (errno));
1259 }
1260 else if (sgid != rgid)
1261 {
1262 if (-1 == setregid (sgid,
1263 sgid))
1264 fprintf (stderr,
1265 "setregid failed: %s\n",
1266 strerror (errno));
1267 }
1268}
1269
1270
1271#endif
1272
1273
1274/* end of gnunet-service-dns.c */
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
#define gettext_noop(String)
Definition gettext.h:74
static unsigned long long ipv6prefix
IPv6 prefix (0..127) from configuration file.
static struct GNUNET_SCHEDULER_Task * cleanup_task
Cleanup task.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static unsigned long long payload
How much data are we currently storing in the database?
static void next_phase(struct RequestRecord *rr)
A client has completed its processing for this request.
static int process_helper_messages(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer fro...
static void handle_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Handle a response from a client.
static int global_ret
Global return value from 'main'.
RequestPhase
Phases each request goes through.
@ RP_REQUEST_MONITOR
Showing the request to all monitor clients.
@ RP_QUERY
Showing the request to PRE-RESOLUTION clients to find an answer.
@ RP_MODIFY
Client (or global DNS request) has resulted in a response.
@ RP_DROP
Some client has told us to drop the request.
@ RP_INTERNET_DNS
Global Internet query is now pending.
@ RP_INIT
Request has just been received.
@ RP_RESPONSE_MONITOR
Showing the request to all monitor clients.
static void process_dns_result(void *cls, const struct GNUNET_TUN_DnsHeader *dns, size_t r)
Callback called from DNSSTUB resolver when a resolution succeeded.
static struct GNUNET_STATISTICS_Handle * stats
Statistics.
static const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration to use.
static struct GNUNET_HELPER_Handle * hijacker
Handle to DNS hijacker helper process ("gnunet-helper-dns").
static struct GNUNET_DNSSTUB_Context * dnsstub
Handle to the DNS Stub resolver.
static void request_done(struct RequestRecord *rr)
We're done with some request, finish processing.
static char * helper_argv[8]
Command-line arguments we are giving to the hijacker process.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
A client connected, setup our data structures.
static struct ClientRecord * clients_head
Head of DLL of clients we consult.
static uint64_t request_id_gen
Generator for unique request IDs.
#define DNS_PORT
Port number for DNS.
static void handle_client_init(void *cls, const struct GNUNET_DNS_Register *reg)
We got a new client.
static int check_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Check a response from a client.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct GNUNET_SERVICE_Handle *service)
static struct RequestRecord requests[UINT16_MAX+1]
Array of all open requests.
#define LOG(kind,...)
Generic logging shorthand.
static void cleanup_rr(struct RequestRecord *rr)
We're done processing a DNS request, free associated memory.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up after it.
static void send_request_to_client(struct RequestRecord *rr, struct ClientRecord *cr)
Show the payload of the given request record to the client (and wait for a response).
static struct ClientRecord * clients_tail
Tail of DLL of clients we consult.
static int udp
Option -u: UDP requested.
Definition gnunet-vpn.c:75
struct GNUNET_PQ_ResultSpec __attribute__
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition dnsstub.c:586
int GNUNET_DNSSTUB_add_dns_ip(struct GNUNET_DNSSTUB_Context *ctx, const char *dns_ip)
Add nameserver for use by the DNSSTUB.
Definition dnsstub.c:613
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition dnsstub.c:705
struct GNUNET_DNSSTUB_RequestSocket * GNUNET_DNSSTUB_resolve(struct GNUNET_DNSSTUB_Context *ctx, const void *request, size_t request_len, GNUNET_DNSSTUB_ResultCallback rc, void *rc_cls)
Perform DNS resolution using our default IP from init.
Definition dnsstub.c:526
GNUNET_DNS_Flags
Flags that specify when to call the client's handler.
@ GNUNET_DNS_FLAG_RESPONSE_MONITOR
Set this flag to see all requests just before they are returned to the network.
@ GNUNET_DNS_FLAG_REQUEST_MONITOR
Set this flag to see all requests first prior to resolution (for monitoring).
@ GNUNET_DNS_FLAG_PRE_RESOLUTION
This client should be called on requests that have not yet been resolved as this client provides a re...
@ GNUNET_DNS_FLAG_POST_RESOLUTION
This client wants to be called on the results of a DNS resolution (either resolved by PRE-RESOLUTION ...
struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send(struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, bool can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls)
Send an message to the helper.
Definition helper.c:615
struct GNUNET_HELPER_Handle * GNUNET_HELPER_start(const struct GNUNET_OS_ProjectData *pd, int with_control_pipe, const char *binary_name, char *const binary_argv[], GNUNET_MessageTokenizerCallback cb, GNUNET_HELPER_ExceptionCallback exp_cb, void *cb_cls)
Starts a helper and begins reading from it.
Definition helper.c:460
void GNUNET_HELPER_stop(struct GNUNET_HELPER_Handle *h, int soft_kill)
Kills the helper, closes the pipe, frees the handle and calls wait() on the helper process.
Definition helper.c:538
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_UNUSED
gcc-ism to document unused arguments
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
char * GNUNET_OS_get_suid_binary_path(const struct GNUNET_OS_ProjectData *pd, const struct GNUNET_CONFIGURATION_Handle *cfg, const char *progname)
Given the name of a helper, service or daemon binary construct the full path to the binary using the ...
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_HELPER
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT
Initial message from client to DNS service for registration.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1339
#define GNUNET_SERVICE_MAIN(pd, service_name, service_options, init_cb, connect_cb, disconnect_cb, cls,...)
Creates the "main" function for a GNUnet service.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition service.c:2462
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2433
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
void GNUNET_TUN_initialize_ipv6_header(struct GNUNET_TUN_IPv6Header *ip, uint8_t protocol, uint16_t payload_length, const struct in6_addr *src, const struct in6_addr *dst)
Initialize an IPv6 header.
Definition tun.c:115
void GNUNET_TUN_calculate_udp4_checksum(const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length)
Calculate IPv4 UDP checksum.
Definition tun.c:193
GNUNET_NETWORK_STRUCT_END void GNUNET_TUN_initialize_ipv4_header(struct GNUNET_TUN_IPv4Header *ip, uint8_t protocol, uint16_t payload_length, const struct in_addr *src, const struct in_addr *dst)
Initialize an IPv4 header.
Definition tun.c:80
#define ETH_P_IPV6
Number for IPv6.
#define ETH_P_IPV4
Number for IPv4.
void GNUNET_TUN_calculate_udp6_checksum(const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length)
Calculate IPv6 UDP checksum.
Definition tun.c:224
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
Entry we keep for each client.
struct ClientRecord * prev
Kept in doubly-linked list.
struct GNUNET_MQ_Handle * mq
Message queue to talk to client.
enum GNUNET_DNS_Flags flags
Flags for the client.
struct GNUNET_SERVICE_Client * client
Handle to the client.
struct ClientRecord * next
Kept in doubly-linked list.
Handle to the stub resolver.
Definition dnsstub.c:125
UDP socket we are using for sending DNS requests to the Internet.
Definition dnsstub.c:46
Message from client to DNS service to register itself.
Definition dns.h:36
uint32_t flags
NBO encoding of enum GNUNET_DNS_Flags for the client.
Definition dns.h:45
Message from DNS service to client: please handle a request.
Definition dns.h:53
uint32_t reserved
Always zero.
Definition dns.h:62
uint64_t request_id
Unique request ID.
Definition dns.h:67
Message from client to DNS service: here is my reply.
Definition dns.h:77
struct GNUNET_MessageHeader header
Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE.
Definition dns.h:81
uint64_t request_id
Unique request ID.
Definition dns.h:91
The handle to a helper process.
Definition helper.c:77
Handle to a message queue.
Definition mq.c:87
Header for all communications.
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Handle for the service.
DNS flags (largely RFC 1035 / RFC 2136).
uint16_t id
Unique identifier for the request/response.
Standard IPv4 header.
uint16_t total_length
Length of the packet, including this header.
uint8_t protocol
L4-protocol, for example, IPPROTO_UDP or IPPROTO_TCP.
struct in_addr source_address
Origin of the packet.
struct in_addr destination_address
Destination of the packet.
Standard IPv6 header.
struct in6_addr source_address
Origin of the packet.
uint8_t next_header
For example, IPPROTO_UDP or IPPROTO_TCP.
struct in6_addr destination_address
Destination of the packet.
uint16_t payload_length
Length of the payload, excluding this header.
Header from Linux TUN interface.
uint16_t proto
Here we get an ETH_P_-number.
uint16_t flags
Some flags (unused).
UDP packet header.
uint16_t destination_port
Destination port (in NBO).
uint16_t source_port
Source port (in NBO).
Entry we keep for each active request.
struct sockaddr_storage src_addr
Source address of the original request (for sending response).
char * payload
Payload of the UDP packet (the UDP payload), can be either query or already the response.
uint64_t request_id
ID of this request, also basis for hashing.
unsigned int client_wait_list_length
Length of the client_wait_list.
struct sockaddr_storage dst_addr
Destination address of the original request (for potential use as exit).
size_t payload_length
Number of bytes in payload.
struct ClientRecord ** client_wait_list
List of clients that still need to see this request (each entry is set to NULL when the client is don...
struct GNUNET_DNSSTUB_RequestSocket * rs
Socket we are using to transmit this request (must match if we receive a response).
enum RequestPhase phase
In which phase this this request?

Enumeration Type Documentation

◆ RequestPhase

Phases each request goes through.

Enumerator
RP_INIT 

Request has just been received.

RP_REQUEST_MONITOR 

Showing the request to all monitor clients.

If client list is empty, will enter QUERY phase.

RP_QUERY 

Showing the request to PRE-RESOLUTION clients to find an answer.

If client list is empty, will trigger global DNS request.

RP_INTERNET_DNS 

Global Internet query is now pending.

RP_MODIFY 

Client (or global DNS request) has resulted in a response.

Forward to all POST-RESOLUTION clients. If client list is empty, will enter RESPONSE_MONITOR phase.

RP_RESPONSE_MONITOR 

Showing the request to all monitor clients.

If client list is empty, give the result to the hijacker (and be done).

RP_DROP 

Some client has told us to drop the request.

Definition at line 62 of file gnunet-service-dns.c.

63{
67 RP_INIT,
68
74
80
85
92
98
102 RP_DROP
103};

Function Documentation

◆ cleanup_rr()

static void cleanup_rr ( struct RequestRecord rr)
static

We're done processing a DNS request, free associated memory.

Parameters
rrrequest to clean up

Definition at line 252 of file gnunet-service-dns.c.

253{
254 GNUNET_free (rr->payload);
255 rr->payload = NULL;
256 rr->payload_length = 0;
259 0);
260}

References RequestRecord::client_wait_list, RequestRecord::client_wait_list_length, GNUNET_array_grow, GNUNET_free, RequestRecord::payload, and RequestRecord::payload_length.

Referenced by cleanup_task(), next_phase(), request_done(), and send_request_to_client().

Here is the caller graph for this function:

◆ cleanup_task()

static void cleanup_task ( void *  cls)
static

Task run during shutdown.

Parameters
clsunused

Definition at line 269 of file gnunet-service-dns.c.

270{
271 if (NULL != hijacker)
272 {
274 hijacker = NULL;
275 }
276 for (unsigned int i = 0; i < 8; i++)
278 for (unsigned int i = 0; i <= UINT16_MAX; i++)
279 cleanup_rr (&requests[i]);
280 if (NULL != stats)
281 {
283 GNUNET_NO);
284 stats = NULL;
285 }
286 if (NULL != dnsstub)
287 {
289 dnsstub = NULL;
290 }
291}

References cleanup_rr(), dnsstub, GNUNET_DNSSTUB_stop(), GNUNET_free, GNUNET_HELPER_stop(), GNUNET_NO, GNUNET_STATISTICS_destroy(), helper_argv, hijacker, requests, and stats.

Here is the call graph for this function:

◆ request_done()

static void request_done ( struct RequestRecord rr)
static

We're done with some request, finish processing.

Parameters
rrrequest send to the network or just clean up.

Definition at line 300 of file gnunet-service-dns.c.

301{
302 struct GNUNET_MessageHeader *hdr;
303 size_t reply_len;
304 uint16_t source_port;
305 uint16_t destination_port;
306
309 0);
310 if (RP_RESPONSE_MONITOR != rr->phase)
311 {
312 /* no response, drop */
314 "Got no response for request %llu, dropping\n",
315 (unsigned long long) rr->request_id);
316 cleanup_rr (rr);
317 return;
318 }
319
321 "Transmitting response for request %llu\n",
322 (unsigned long long) rr->request_id);
323 /* send response via hijacker */
324 reply_len = sizeof(struct GNUNET_MessageHeader);
325 reply_len += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
326 switch (rr->src_addr.ss_family)
327 {
328 case AF_INET:
329 reply_len += sizeof(struct GNUNET_TUN_IPv4Header);
330 break;
331
332 case AF_INET6:
333 reply_len += sizeof(struct GNUNET_TUN_IPv6Header);
334 break;
335
336 default:
337 GNUNET_break (0);
338 cleanup_rr (rr);
339 return;
340 }
341 reply_len += sizeof(struct GNUNET_TUN_UdpHeader);
342 reply_len += rr->payload_length;
343 if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
344 {
345 /* response too big, drop */
346 GNUNET_break (0); /* how can this be? */
347 cleanup_rr (rr);
348 return;
349 }
350 {
351 char buf[reply_len] GNUNET_ALIGN;
352 size_t off;
353 struct GNUNET_TUN_IPv4Header ip4;
354 struct GNUNET_TUN_IPv6Header ip6;
355
356 /* first, GNUnet message header */
357 hdr = (struct GNUNET_MessageHeader*) buf;
359 hdr->size = htons ((uint16_t) reply_len);
360 off = sizeof(struct GNUNET_MessageHeader);
361
362 /* first, TUN header */
363 {
365
366 tun.flags = htons (0);
367 if (rr->src_addr.ss_family == AF_INET)
368 tun.proto = htons (ETH_P_IPV4);
369 else
370 tun.proto = htons (ETH_P_IPV6);
371 GNUNET_memcpy (&buf[off],
372 &tun,
373 sizeof(struct GNUNET_TUN_Layer2PacketHeader));
374 off += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
375 }
376
377 /* now IP header */
378 switch (rr->src_addr.ss_family)
379 {
380 case AF_INET:
381 {
382 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
383 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
384
385 source_port = dst->sin_port;
386 destination_port = src->sin_port;
388 IPPROTO_UDP,
389 reply_len - off - sizeof(struct
391 &dst->sin_addr,
392 &src->sin_addr);
393 GNUNET_memcpy (&buf[off],
394 &ip4,
395 sizeof(ip4));
396 off += sizeof(ip4);
397 }
398 break;
399
400 case AF_INET6:
401 {
402 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
403 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
404
405 source_port = dst->sin6_port;
406 destination_port = src->sin6_port;
408 IPPROTO_UDP,
409 reply_len - off - sizeof(struct
411 &dst->sin6_addr,
412 &src->sin6_addr);
413 GNUNET_memcpy (&buf[off],
414 &ip6,
415 sizeof(ip6));
416 off += sizeof(ip6);
417 }
418 break;
419
420 default:
421 GNUNET_assert (0);
422 }
423
424 /* now UDP header */
425 {
427
429 udp.destination_port = destination_port;
430 udp.len = htons (reply_len - off);
431 if (AF_INET == rr->src_addr.ss_family)
433 &udp,
434 rr->payload,
435 rr->payload_length);
436 else
438 &udp,
439 rr->payload,
440 rr->payload_length);
441 GNUNET_memcpy (&buf[off],
442 &udp,
443 sizeof(udp));
444 off += sizeof(udp);
445 }
446
447 /* now DNS payload */
448 {
449 GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
450 off += rr->payload_length;
451 }
452 /* final checks & sending */
453 GNUNET_assert (off == reply_len);
455 hdr,
457 NULL, NULL);
460 "# DNS requests answered via TUN interface"),
461 1, GNUNET_NO);
462 }
463 /* clean up, we're done */
464 cleanup_rr (rr);
465}

References cleanup_rr(), RequestRecord::client_wait_list, RequestRecord::client_wait_list_length, GNUNET_TUN_UdpHeader::destination_port, RequestRecord::dst_addr, ETH_P_IPV4, ETH_P_IPV6, GNUNET_TUN_Layer2PacketHeader::flags, gettext_noop, GNUNET_ALIGN, GNUNET_array_grow, GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_HELPER_send(), GNUNET_MAX_MESSAGE_SIZE, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_DNS_HELPER, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TUN_calculate_udp4_checksum(), GNUNET_TUN_calculate_udp6_checksum(), GNUNET_TUN_initialize_ipv4_header(), GNUNET_TUN_initialize_ipv6_header(), GNUNET_YES, hijacker, LOG, RequestRecord::payload, RequestRecord::payload_length, RequestRecord::phase, GNUNET_TUN_Layer2PacketHeader::proto, RequestRecord::request_id, RP_RESPONSE_MONITOR, GNUNET_TUN_UdpHeader::source_port, RequestRecord::src_addr, stats, GNUNET_MessageHeader::type, and udp.

Referenced by next_phase().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_request_to_client()

static void send_request_to_client ( struct RequestRecord rr,
struct ClientRecord cr 
)
static

Show the payload of the given request record to the client (and wait for a response).

Parameters
rrrequest to send to client
crclient to send the response to

Definition at line 476 of file gnunet-service-dns.c.

478{
479 struct GNUNET_MQ_Envelope *env;
480 struct GNUNET_DNS_Request *req;
481
482 if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >=
484 {
485 GNUNET_break (0);
486 cleanup_rr (rr);
487 return;
488 }
490 "Sending information about request %llu to local client\n",
491 (unsigned long long) rr->request_id);
493 rr->payload_length,
495 req->reserved = htonl (0);
496 req->request_id = rr->request_id;
497 GNUNET_memcpy (&req[1],
498 rr->payload,
499 rr->payload_length);
500 GNUNET_MQ_send (cr->mq,
501 env);
502}

References cleanup_rr(), env, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_MAX_MESSAGE_SIZE, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), LOG, ClientRecord::mq, RequestRecord::payload, RequestRecord::payload_length, GNUNET_DNS_Request::request_id, RequestRecord::request_id, and GNUNET_DNS_Request::reserved.

Referenced by next_phase().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_dns_result()

static void process_dns_result ( void *  cls,
const struct GNUNET_TUN_DnsHeader dns,
size_t  r 
)
static

Callback called from DNSSTUB resolver when a resolution succeeded.

Parameters
clsNULL
dnsthe response itself
rnumber of bytes in dns

Definition at line 732 of file gnunet-service-dns.c.

735{
736 struct RequestRecord *rr;
737
739 "Processing DNS result from stub resolver\n");
740 GNUNET_assert (NULL == cls);
741 if (NULL == dns)
742 return; /* ignore */
743
744 rr = &requests[dns->id];
745 if (rr->phase != RP_INTERNET_DNS)
746 {
747 /* unexpected / bogus reply */
750 "# External DNS response discarded (no matching request)"),
751 1, GNUNET_NO);
753 "Received DNS reply that does not match any pending request. Dropping.\n");
754 return;
755 }
757 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
758 (unsigned long long) rr->request_id);
759 GNUNET_free (rr->payload);
760 rr->payload = GNUNET_malloc (r);
762 dns,
763 r);
764 rr->payload_length = r;
765 next_phase (rr);
766}

References gettext_noop, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TUN_DnsHeader::id, LOG, next_phase(), RequestRecord::payload, RequestRecord::payload_length, RequestRecord::phase, RequestRecord::request_id, requests, RP_INTERNET_DNS, and stats.

Referenced by next_phase().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_phase()

static void next_phase ( struct RequestRecord rr)
static

A client has completed its processing for this request.

Move on.

Parameters
rrrequest to process further

Definition at line 526 of file gnunet-service-dns.c.

527{
528 struct ClientRecord *cr;
529 int nz;
530
531 if (rr->phase == RP_DROP)
532 {
533 cleanup_rr (rr);
534 return;
535 }
536 nz = -1;
537 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
538 {
539 if (NULL != rr->client_wait_list[j])
540 {
541 nz = (int) j;
542 break;
543 }
544 }
545 if (-1 != nz)
546 {
548 rr->client_wait_list[nz]);
549 return;
550 }
551 /* done with current phase, advance! */
553 "Request %llu now in phase %d\n",
554 (unsigned long long) rr->request_id,
555 rr->phase);
556 switch (rr->phase)
557 {
558 case RP_INIT:
560 for (cr = clients_head; NULL != cr; cr = cr->next)
561 {
562 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
565 cr);
566 }
567 next_phase (rr);
568 return;
569
571 rr->phase = RP_QUERY;
572 for (cr = clients_head; NULL != cr; cr = cr->next)
573 {
574 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
577 cr);
578 }
579 next_phase (rr);
580 return;
581
582 case RP_QUERY:
583#if 0
584 /* TODO: optionally, use this to forward DNS requests to the
585 * original* DNS server instead of the one we have configured...
586 (but then we need to create a fresh dnsstub for each request
587 * and* manage the timeout) */
588 switch (rr->dst_addr.ss_family)
589 {
590 case AF_INET:
591 salen = sizeof(struct sockaddr_in);
592 sa = (const struct sockaddr *) &rr->dst_addr;
593 break;
594
595 case AF_INET6:
596 salen = sizeof(struct sockaddr_in6);
597 sa = (const struct sockaddr *) &rr->dst_addr;
598 break;
599
600 default:
601 GNUNET_assert (0);
602 }
603#endif
606 rr->payload,
607 rr->payload_length,
609 NULL);
610 if (NULL == rr->rs)
611 {
614 "# DNS exit failed (failed to open socket)"),
615 1,
616 GNUNET_NO);
617 cleanup_rr (rr);
618 return;
619 }
620 return;
621
622 case RP_INTERNET_DNS:
623 rr->phase = RP_MODIFY;
624 for (cr = clients_head; NULL != cr; cr = cr->next)
625 {
626 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
629 cr);
630 }
631 next_phase (rr);
632 return;
633
634 case RP_MODIFY:
636 for (cr = clients_head; NULL != cr; cr = cr->next)
637 {
641 cr);
642 }
643 next_phase (rr);
644 return;
645
647 request_done (rr);
648 break;
649
650 case RP_DROP:
651 cleanup_rr (rr);
652 break;
653
654 default:
655 GNUNET_break (0);
656 cleanup_rr (rr);
657 break;
658 }
659}

References cleanup_rr(), RequestRecord::client_wait_list, RequestRecord::client_wait_list_length, clients_head, dnsstub, RequestRecord::dst_addr, ClientRecord::flags, gettext_noop, GNUNET_array_append, GNUNET_assert, GNUNET_break, GNUNET_DNS_FLAG_POST_RESOLUTION, GNUNET_DNS_FLAG_PRE_RESOLUTION, GNUNET_DNS_FLAG_REQUEST_MONITOR, GNUNET_DNS_FLAG_RESPONSE_MONITOR, GNUNET_DNSSTUB_resolve(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_NO, GNUNET_STATISTICS_update(), LOG, ClientRecord::next, next_phase(), RequestRecord::payload, RequestRecord::payload_length, RequestRecord::phase, process_dns_result(), request_done(), RequestRecord::request_id, RP_DROP, RP_INIT, RP_INTERNET_DNS, RP_MODIFY, RP_QUERY, RP_REQUEST_MONITOR, RP_RESPONSE_MONITOR, RequestRecord::rs, send_request_to_client(), and stats.

Referenced by client_disconnect_cb(), handle_client_response(), next_phase(), process_dns_result(), and process_helper_messages().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_connect_cb()

static void * client_connect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
struct GNUNET_MQ_Handle mq 
)
static

A client connected, setup our data structures.

Parameters
clsunused
clienthandle of client that connected
mqmessage queue to talk to client
Returns
our struct ClientRecord

Definition at line 671 of file gnunet-service-dns.c.

674{
675 struct ClientRecord *cr = cls;
676
677 cr = GNUNET_new (struct ClientRecord);
678 cr->client = client;
679 cr->mq = mq;
682 cr);
683 return cr;
684}

References ClientRecord::client, clients_head, clients_tail, GNUNET_CONTAINER_DLL_insert, GNUNET_new, mq, and ClientRecord::mq.

◆ client_disconnect_cb()

static void client_disconnect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
void *  app_ctx 
)
static

A client disconnected, clean up after it.

Parameters
clsunused
clienthandle of client that disconnected
app_ctxour struct ClientRecord

Definition at line 695 of file gnunet-service-dns.c.

698{
699 struct ClientRecord *cr = app_ctx;
700 struct RequestRecord *rr;
701
704 cr);
705 for (unsigned int i = 0; i < UINT16_MAX; i++)
706 {
707 rr = &requests[i];
708 if (0 == rr->client_wait_list_length)
709 continue; /* not in use */
710 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
711 {
712 if (rr->client_wait_list[j] == cr)
713 {
714 rr->client_wait_list[j] = NULL;
715 next_phase (rr);
716 }
717 }
718 }
719 GNUNET_free (cr);
720}

References RequestRecord::client_wait_list, RequestRecord::client_wait_list_length, clients_head, clients_tail, GNUNET_CONTAINER_DLL_remove, GNUNET_free, next_phase(), and requests.

Here is the call graph for this function:

◆ handle_client_init()

static void handle_client_init ( void *  cls,
const struct GNUNET_DNS_Register reg 
)
static

We got a new client.

Make sure all new DNS requests pass by its desk.

Parameters
clsthe client
regthe init message

Definition at line 776 of file gnunet-service-dns.c.

778{
779 struct ClientRecord *cr = cls;
780
781 cr->flags = ntohl (reg->flags);
783}

References ClientRecord::client, GNUNET_DNS_Register::flags, ClientRecord::flags, and GNUNET_SERVICE_client_continue().

Here is the call graph for this function:

◆ check_client_response()

static int check_client_response ( void *  cls,
const struct GNUNET_DNS_Response resp 
)
static

Check a response from a client.

Parameters
clsthe client
respthe response
Returns
GNUNET_OK (always fine)

Definition at line 794 of file gnunet-service-dns.c.

796{
797 return GNUNET_OK; /* any payload is acceptable */
798}

References GNUNET_OK.

◆ handle_client_response()

static void handle_client_response ( void *  cls,
const struct GNUNET_DNS_Response resp 
)
static

Handle a response from a client.

Parameters
clsthe client
respthe response

Definition at line 808 of file gnunet-service-dns.c.

810{
811 struct ClientRecord *cr = cls;
812 struct RequestRecord *rr;
813 uint16_t msize;
814 uint16_t off;
815
816 msize = ntohs (resp->header.size);
817 off = (uint16_t) resp->request_id;
818 rr = &requests[off];
820 "Received DNS response with ID %llu from local client!\n",
821 (unsigned long long) resp->request_id);
822 if (rr->request_id != resp->request_id)
823 {
826 "# Client response discarded (no matching request)"),
827 1,
828 GNUNET_NO);
830 return;
831 }
832 for (unsigned int i = 0; i < rr->client_wait_list_length; i++)
833 {
834 if (NULL == rr->client_wait_list[i])
835 continue;
836 if (rr->client_wait_list[i] != cr)
837 continue;
838 rr->client_wait_list[i] = NULL;
839 switch (ntohl (resp->drop_flag))
840 {
841 case 0: /* drop */
842 rr->phase = RP_DROP;
843 break;
844
845 case 1: /* no change */
846 break;
847
848 case 2: /* update */
849 msize -= sizeof(struct GNUNET_DNS_Response);
850 if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) ||
851 (RP_REQUEST_MONITOR == rr->phase) ||
852 (RP_RESPONSE_MONITOR == rr->phase))
853 {
854 GNUNET_break (0);
855 GNUNET_SERVICE_client_drop (cr->client);
856 next_phase (rr);
857 return;
858 }
859 GNUNET_free (rr->payload);
861 "Changing DNS reply according to client specifications\n");
862 rr->payload = GNUNET_malloc (msize);
863 rr->payload_length = msize;
864 GNUNET_memcpy (rr->payload, &resp[1], msize);
865 if (rr->phase == RP_QUERY)
866 {
867 /* clear wait list, we're moving to MODIFY phase next */
868 GNUNET_array_grow (rr->client_wait_list,
869 rr->client_wait_list_length,
870 0);
871 }
872 /* if query changed to answer, move past DNS resolution phase... */
873 if ((RP_QUERY == rr->phase) &&
874 (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) &&
875 ( ((struct GNUNET_TUN_DnsFlags*) &(((struct
877 payload)->flags))->
878 query_or_response == 1) )
879 {
880 rr->phase = RP_INTERNET_DNS;
881 GNUNET_array_grow (rr->client_wait_list,
882 rr->client_wait_list_length,
883 0);
884 }
885 break;
886 }
887 next_phase (rr);
889 return;
890 }
891 /* odd, client was not on our list for the request, that ought
892 to be an error */
893 GNUNET_break (0);
894 GNUNET_SERVICE_client_drop (cr->client);
895}
uint32_t drop_flag
Zero to drop, 1 for no change (no payload), 2 for update (message has payload).
Definition dns.h:86

References ClientRecord::client, RequestRecord::client_wait_list, RequestRecord::client_wait_list_length, GNUNET_DNS_Response::drop_flag, gettext_noop, GNUNET_array_grow, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_NO, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_STATISTICS_update(), GNUNET_DNS_Response::header, LOG, next_phase(), payload, RequestRecord::payload, RequestRecord::payload_length, RequestRecord::phase, GNUNET_DNS_Response::request_id, RequestRecord::request_id, requests, RP_DROP, RP_INTERNET_DNS, RP_QUERY, RP_REQUEST_MONITOR, RP_RESPONSE_MONITOR, GNUNET_MessageHeader::size, and stats.

Here is the call graph for this function:

◆ process_helper_messages()

static int process_helper_messages ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Functions with this signature are called whenever a complete message is received by the tokenizer from the DNS hijack process.

Parameters
clsclosure
messagethe actual message, a DNS request we should handle

Definition at line 906 of file gnunet-service-dns.c.

908{
909 uint16_t msize;
910 const struct GNUNET_TUN_Layer2PacketHeader *tun;
911 const struct GNUNET_TUN_IPv4Header *ip4;
912 const struct GNUNET_TUN_IPv6Header *ip6;
913 const struct GNUNET_TUN_UdpHeader *udp;
914 const struct GNUNET_TUN_DnsHeader *dns;
915 struct RequestRecord *rr;
916 struct sockaddr_in *srca4;
917 struct sockaddr_in6 *srca6;
918 struct sockaddr_in *dsta4;
919 struct sockaddr_in6 *dsta6;
920
922 "Intercepted message via DNS hijacker\n");
923 msize = ntohs (message->size);
924 if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct
926 + sizeof(struct GNUNET_TUN_IPv4Header))
927 {
928 /* non-IP packet received on TUN!? */
929 GNUNET_break (0);
930 return GNUNET_OK;
931 }
932 msize -= sizeof(struct GNUNET_MessageHeader);
933 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
934 msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader);
935 switch (ntohs (tun->proto))
936 {
937 case ETH_P_IPV4:
938 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
939 ip6 = NULL; /* make compiler happy */
940 if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) ||
941 (ip4->version != 4) ||
942 (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) ||
943 (ntohs (ip4->total_length) != msize) ||
944 (ip4->protocol != IPPROTO_UDP))
945 {
946 /* non-IP/UDP packet received on TUN (or with options) */
948 _ ("Received malformed IPv4-UDP packet on TUN interface.\n"));
949 return GNUNET_OK;
950 }
951 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
952 msize -= sizeof(struct GNUNET_TUN_IPv4Header);
953 break;
954
955 case ETH_P_IPV6:
956 ip4 = NULL; /* make compiler happy */
957 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
958 if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) ||
959 (ip6->version != 6) ||
960 (ntohs (ip6->payload_length) != msize - sizeof(struct
962 ||
963 (ip6->next_header != IPPROTO_UDP))
964 {
965 /* non-IP/UDP packet received on TUN (or with extensions) */
967 _ ("Received malformed IPv6-UDP packet on TUN interface.\n"));
968 return GNUNET_OK;
969 }
970 udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
971 msize -= sizeof(struct GNUNET_TUN_IPv6Header);
972 break;
973
974 default:
975 /* non-IP packet received on TUN!? */
977 _ (
978 "Got non-IP packet with %u bytes and protocol %u from TUN\n"),
979 (unsigned int) msize,
980 ntohs (tun->proto));
981 return GNUNET_OK;
982 }
983 if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct
985 ||
986 (DNS_PORT != ntohs (udp->destination_port)))
987 {
988 /* non-DNS packet received on TUN, ignore */
990 _ ("DNS interceptor got non-DNS packet (dropped)\n"));
993 "# Non-DNS UDP packet received via TUN interface"),
994 1, GNUNET_NO);
995 return GNUNET_OK;
996 }
997 msize -= sizeof(struct GNUNET_TUN_UdpHeader);
998 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
999 rr = &requests[dns->id];
1000
1001 /* clean up from previous request */
1002 GNUNET_free (rr->payload);
1003 rr->payload = NULL;
1006 0);
1007
1008 /* setup new request */
1009 rr->phase = RP_INIT;
1010 switch (ntohs (tun->proto))
1011 {
1012 case ETH_P_IPV4:
1013 {
1014 srca4 = (struct sockaddr_in*) &rr->src_addr;
1015 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1016 memset (srca4, 0, sizeof(struct sockaddr_in));
1017 memset (dsta4, 0, sizeof(struct sockaddr_in));
1018 srca4->sin_family = AF_INET;
1019 dsta4->sin_family = AF_INET;
1020 srca4->sin_addr = ip4->source_address;
1021 dsta4->sin_addr = ip4->destination_address;
1022 srca4->sin_port = udp->source_port;
1023 dsta4->sin_port = udp->destination_port;
1024#if HAVE_SOCKADDR_IN_SIN_LEN
1025 srca4->sin_len = sizeof(struct sockaddr_in);
1026 dsta4->sin_len = sizeof(struct sockaddr_in);
1027#endif
1028 }
1029 break;
1030
1031 case ETH_P_IPV6:
1032 {
1033 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1034 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1035 memset (srca6, 0, sizeof(struct sockaddr_in6));
1036 memset (dsta6, 0, sizeof(struct sockaddr_in6));
1037 srca6->sin6_family = AF_INET6;
1038 dsta6->sin6_family = AF_INET6;
1039 srca6->sin6_addr = ip6->source_address;
1040 dsta6->sin6_addr = ip6->destination_address;
1041 srca6->sin6_port = udp->source_port;
1042 dsta6->sin6_port = udp->destination_port;
1043#if HAVE_SOCKADDR_IN_SIN_LEN
1044 srca6->sin6_len = sizeof(struct sockaddr_in6);
1045 dsta6->sin6_len = sizeof(struct sockaddr_in6);
1046#endif
1047 }
1048 break;
1049
1050 default:
1051 GNUNET_assert (0);
1052 }
1053 rr->payload = GNUNET_malloc (msize);
1054 rr->payload_length = msize;
1055 GNUNET_memcpy (rr->payload, dns, msize);
1056 rr->request_id = dns->id | (request_id_gen << 16);
1059 "Creating new DNS request %llu\n",
1060 (unsigned long long) rr->request_id);
1062 gettext_noop (
1063 "# DNS requests received via TUN interface"),
1064 1, GNUNET_NO);
1065 /* start request processing state machine */
1066 next_phase (rr);
1067 return GNUNET_OK;
1068}

References _, RequestRecord::client_wait_list, RequestRecord::client_wait_list_length, GNUNET_TUN_IPv4Header::destination_address, GNUNET_TUN_IPv6Header::destination_address, DNS_PORT, RequestRecord::dst_addr, ETH_P_IPV4, ETH_P_IPV6, gettext_noop, GNUNET_array_grow, GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_STATISTICS_update(), GNUNET_TUN_IPv4Header::header_length, GNUNET_TUN_DnsHeader::id, LOG, GNUNET_TUN_IPv6Header::next_header, next_phase(), RequestRecord::payload, GNUNET_TUN_IPv6Header::payload_length, RequestRecord::payload_length, RequestRecord::phase, GNUNET_TUN_Layer2PacketHeader::proto, GNUNET_TUN_IPv4Header::protocol, RequestRecord::request_id, request_id_gen, requests, RP_INIT, GNUNET_MessageHeader::size, GNUNET_TUN_IPv4Header::source_address, GNUNET_TUN_IPv6Header::source_address, RequestRecord::src_addr, stats, GNUNET_TUN_IPv4Header::total_length, udp, GNUNET_TUN_IPv4Header::version, and GNUNET_TUN_IPv6Header::version.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run()

static void run ( void *  cls,
const struct GNUNET_CONFIGURATION_Handle cfg_,
struct GNUNET_SERVICE_Handle service 
)
static
Parameters
clsclosure
cfg_configuration to use
servicethe initialized service

Definition at line 1077 of file gnunet-service-dns.c.

1080{
1081 char *ifc_name;
1082 char *ipv4addr;
1083 char *ipv4mask;
1084 char *ipv6addr;
1085 char *ipv6prefix;
1086 char *dns_exit;
1087 char *binary;
1088 int nortsetup;
1089
1090 cfg = cfg_;
1093 cls);
1095 /* TODO: support multiple DNS_EXIT servers being configured */
1096 /* TODO: see above TODO on using DNS server from original packet.
1097 Not sure which is best... */
1098 dns_exit = NULL;
1099 if ((GNUNET_OK !=
1101 "dns",
1102 "DNS_EXIT",
1103 &dns_exit)) ||
1104 (GNUNET_OK !=
1106 dns_exit)))
1107 {
1109 "dns",
1110 "DNS_EXIT",
1111 _ ("need a valid IPv4 or IPv6 address\n"));
1112 GNUNET_free (dns_exit);
1113 }
1115 cfg,
1116 "gnunet-helper-dns");
1117
1118 if (GNUNET_YES !=
1120 GNUNET_YES,
1121 NULL)) // TODO: once we have a windows-testcase, add test parameters here
1122 {
1124 _ ("`%s' is not SUID or the path is invalid, "
1125 "will not run DNS interceptor\n"),
1126 binary);
1127 global_ret = 1;
1128 GNUNET_free (binary);
1129 return;
1130 }
1131 GNUNET_free (binary);
1132
1133 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1134 if (GNUNET_SYSERR ==
1136 "dns",
1137 "IFNAME",
1138 &ifc_name))
1139 {
1141 "No entry 'IFNAME' in configuration!\n");
1142 GNUNET_free (binary);
1144 return;
1145 }
1146 helper_argv[1] = ifc_name;
1147 if ((GNUNET_SYSERR ==
1149 "dns",
1150 "IPV6ADDR",
1151 &ipv6addr)))
1152 {
1154 "No entry 'IPV6ADDR' in configuration!\n");
1155 GNUNET_free (binary);
1157 return;
1158 }
1159 helper_argv[2] = ipv6addr;
1160 if (GNUNET_SYSERR ==
1162 "dns",
1163 "IPV6PREFIX",
1164 &ipv6prefix))
1165 {
1167 "No entry 'IPV6PREFIX' in configuration!\n");
1168 GNUNET_free (binary);
1170 return;
1171 }
1173
1174 if (GNUNET_SYSERR ==
1176 "dns",
1177 "IPV4ADDR",
1178 &ipv4addr))
1179 {
1181 "No entry 'IPV4ADDR' in configuration!\n");
1182 GNUNET_free (binary);
1184 return;
1185 }
1186 helper_argv[4] = ipv4addr;
1187 if (GNUNET_SYSERR ==
1188 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1189 &ipv4mask))
1190 {
1192 "No entry 'IPV4MASK' in configuration!\n");
1193 GNUNET_free (binary);
1195 return;
1196 }
1197 helper_argv[5] = ipv4mask;
1198
1199 nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1200 "SKIP_ROUTING_SETUP");
1201 if (GNUNET_YES == nortsetup)
1202 helper_argv[6] = GNUNET_strdup ("1");
1203 else
1204 helper_argv[6] = GNUNET_strdup ("0");
1205
1206 helper_argv[7] = NULL;
1208 GNUNET_NO,
1209 binary,
1212 NULL, NULL);
1213 GNUNET_free (binary);
1214}

References _, cfg, cleanup_task, dnsstub, global_ret, GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_DNSSTUB_add_dns_ip(), GNUNET_DNSSTUB_start(), GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_HELPER_start(), GNUNET_log, GNUNET_log_config_invalid(), GNUNET_NO, GNUNET_OK, GNUNET_OS_check_helper_binary(), GNUNET_OS_get_suid_binary_path(), GNUNET_OS_project_data_gnunet(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_SCHEDULER_shutdown(), GNUNET_STATISTICS_create(), GNUNET_strdup, GNUNET_SYSERR, GNUNET_YES, helper_argv, hijacker, ipv6prefix, process_helper_messages(), and stats.

Here is the call graph for this function:

◆ GNUNET_SERVICE_MAIN()

GNUNET_SERVICE_MAIN ( GNUNET_OS_project_data_gnunet()  ,
"dns"  ,
GNUNET_SERVICE_OPTION_NONE  ,
run,
client_connect_cb,
client_disconnect_cb,
NULL  ,
GNUNET_MQ_hd_fixed_size(client_init, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, struct GNUNET_DNS_Register, NULL)  ,
GNUNET_MQ_hd_var_size(client_response, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, struct GNUNET_DNS_Response, NULL)  ,
GNUNET_MQ_handler_end()   
)

Define "main" method using service macro.

Variable Documentation

◆ global_ret

int global_ret
static

Global return value from 'main'.

Definition at line 198 of file gnunet-service-dns.c.

Referenced by run().

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

The configuration to use.

Definition at line 203 of file gnunet-service-dns.c.

Referenced by run().

◆ stats

◆ hijacker

struct GNUNET_HELPER_Handle* hijacker
static

Handle to DNS hijacker helper process ("gnunet-helper-dns").

Definition at line 213 of file gnunet-service-dns.c.

Referenced by cleanup_task(), request_done(), and run().

◆ helper_argv

char* helper_argv[8]
static

Command-line arguments we are giving to the hijacker process.

Definition at line 218 of file gnunet-service-dns.c.

Referenced by cleanup_task(), and run().

◆ clients_head

struct ClientRecord* clients_head
static

Head of DLL of clients we consult.

Definition at line 223 of file gnunet-service-dns.c.

Referenced by client_connect_cb(), client_disconnect_cb(), and next_phase().

◆ clients_tail

struct ClientRecord* clients_tail
static

Tail of DLL of clients we consult.

Definition at line 228 of file gnunet-service-dns.c.

Referenced by client_connect_cb(), and client_disconnect_cb().

◆ requests

struct RequestRecord requests[UINT16_MAX+1]
static

Array of all open requests.

Definition at line 233 of file gnunet-service-dns.c.

Referenced by cleanup_task(), client_disconnect_cb(), handle_client_response(), process_dns_result(), and process_helper_messages().

◆ request_id_gen

uint64_t request_id_gen
static

Generator for unique request IDs.

Definition at line 238 of file gnunet-service-dns.c.

Referenced by process_helper_messages().

◆ dnsstub

struct GNUNET_DNSSTUB_Context* dnsstub
static

Handle to the DNS Stub resolver.

Definition at line 243 of file gnunet-service-dns.c.

Referenced by cleanup_task(), next_phase(), and run().