fix memleak
[oweals/gnunet.git] / src / dns / gnunet-service-dns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file 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_mesh_service.h"
50 #include "gnunet_statistics_service.h"
51 #include "gnunet_tun_lib.h"
52
53
54 /**
55  * Generic logging shorthand
56  */
57 #define LOG(kind, ...)                          \
58   GNUNET_log_from (kind, "dns", __VA_ARGS__);
59
60
61 /**
62  * Phases each request goes through.
63  */
64 enum RequestPhase
65 {
66   /**
67    * Request has just been received.
68    */
69   RP_INIT,
70
71   /**
72    * Showing the request to all monitor clients.  If
73    * client list is empty, will enter QUERY phase.
74    */
75   RP_REQUEST_MONITOR,
76
77   /**
78    * Showing the request to PRE-RESOLUTION clients to find an answer.
79    * If client list is empty, will trigger global DNS request.
80    */
81   RP_QUERY,
82
83   /**
84    * Global Internet query is now pending.
85    */
86   RP_INTERNET_DNS,
87   
88   /**
89    * Client (or global DNS request) has resulted in a response.
90    * Forward to all POST-RESOLUTION clients.  If client list is empty,
91    * will enter RESPONSE_MONITOR phase.
92    */
93   RP_MODIFY,
94
95   /**
96    * Showing the request to all monitor clients.  If
97    * client list is empty, give the result to the hijacker (and be done).
98    */
99   RP_RESPONSE_MONITOR,
100
101   /**
102    * Some client has told us to drop the request.
103    */
104   RP_DROP
105 };
106
107
108 /**
109  * Entry we keep for each client.
110  */ 
111 struct ClientRecord
112 {
113   /**
114    * Kept in doubly-linked list.
115    */ 
116   struct ClientRecord *next;
117
118   /**
119    * Kept in doubly-linked list.
120    */ 
121   struct ClientRecord *prev;
122
123   /**
124    * Handle to the client.
125    */ 
126   struct GNUNET_SERVER_Client *client;
127
128   /**
129    * Flags for the client.
130    */
131   enum GNUNET_DNS_Flags flags;
132
133 };
134
135
136 /**
137  * Entry we keep for each active request.
138  */ 
139 struct RequestRecord
140 {
141
142   /**
143    * List of clients that still need to see this request (each entry
144    * is set to NULL when the client is done).
145    */
146   struct ClientRecord **client_wait_list;
147
148   /**
149    * Payload of the UDP packet (the UDP payload), can be either query
150    * or already the response.
151    */
152   char *payload;
153
154   /**
155    * Socket we are using to transmit this request (must match if we receive
156    * a response).
157    */
158   struct GNUNET_DNSSTUB_RequestSocket *rs;
159
160   /**
161    * Source address of the original request (for sending response).
162    */
163   struct sockaddr_storage src_addr;
164
165   /**
166    * Destination address of the original request (for potential use as exit).
167    */
168   struct sockaddr_storage dst_addr;
169
170   /**
171    * ID of this request, also basis for hashing.  Lowest 16 bit will
172    * be our message ID when doing a global DNS request and our index
173    * into the 'requests' array.
174    */
175   uint64_t request_id;
176
177   /**
178    * Number of bytes in payload.
179    */ 
180   size_t payload_length;
181
182   /**
183    * Length of the client wait list.
184    */
185   unsigned int client_wait_list_length;
186
187   /**
188    * In which phase this this request?
189    */
190   enum RequestPhase phase;
191
192 };
193
194
195 /**
196  * State we keep for each DNS tunnel that terminates at this node.
197  */
198 struct TunnelState
199 {
200
201   /**
202    * Associated MESH tunnel.
203    */
204   struct GNUNET_MESH_Tunnel *tunnel;
205
206   /**
207    * Active request for sending a reply.
208    */
209   struct GNUNET_MESH_TransmitHandle *th;
210
211   /**
212    * DNS reply ready for transmission.
213    */
214   char *reply;
215
216   /**
217    * Socket we are using to transmit this request (must match if we receive
218    * a response).
219    */
220   struct GNUNET_DNSSTUB_RequestSocket *rs;
221
222   /**
223    * Number of bytes in 'reply'.
224    */
225   size_t reply_length;
226
227   /**
228    * Original DNS request ID as used by the client.
229    */
230   uint16_t original_id;
231
232   /**
233    * DNS request ID that we used for forwarding.
234    */
235   uint16_t my_id;
236 };
237
238
239 /**
240  * Global return value from 'main'.
241  */
242 static int global_ret;
243
244 /**
245  * The configuration to use
246  */
247 static const struct GNUNET_CONFIGURATION_Handle *cfg;
248
249 /**
250  * Statistics.
251  */
252 static struct GNUNET_STATISTICS_Handle *stats;
253
254 /**
255  * Handle to DNS hijacker helper process ("gnunet-helper-dns").
256  */
257 static struct GNUNET_HELPER_Handle *hijacker;
258
259 /**
260  * Command-line arguments we are giving to the hijacker process.
261  */
262 static char *helper_argv[7];
263
264 /**
265  * Head of DLL of clients we consult.
266  */
267 static struct ClientRecord *clients_head;
268
269 /**
270  * Tail of DLL of clients we consult.
271  */
272 static struct ClientRecord *clients_tail;
273
274 /**
275  * Our notification context.
276  */
277 static struct GNUNET_SERVER_NotificationContext *nc;
278
279 /**
280  * Array of all open requests from tunnels.
281  */
282 static struct TunnelState *tunnels[UINT16_MAX + 1];
283
284 /**
285  * Array of all open requests.
286  */
287 static struct RequestRecord requests[UINT16_MAX + 1];
288
289 /**
290  * Generator for unique request IDs.
291  */
292 static uint64_t request_id_gen;
293
294 /**
295  * Handle to the MESH service (for receiving DNS queries), or NULL 
296  * if we are not a DNS exit.
297  */
298 static struct GNUNET_MESH_Handle *mesh;
299
300 /**
301  * Handle to the DNS Stub resolver.
302  */
303 static struct GNUNET_DNSSTUB_Context *dnsstub;
304
305
306 /**
307  * We're done processing a DNS request, free associated memory.
308  *
309  * @param rr request to clean up
310  */
311 static void
312 cleanup_rr (struct RequestRecord *rr)
313 {
314   GNUNET_free_non_null (rr->payload);
315   rr->payload = NULL;
316   rr->payload_length = 0;
317   GNUNET_array_grow (rr->client_wait_list,
318                      rr->client_wait_list_length,
319                      0);
320 }
321
322
323 /**
324  * Task run during shutdown.
325  *
326  * @param cls unused
327  * @param tc unused
328  */
329 static void
330 cleanup_task (void *cls GNUNET_UNUSED,
331               const struct GNUNET_SCHEDULER_TaskContext *tc)
332 {
333   unsigned int i;
334
335   GNUNET_HELPER_stop (hijacker);
336   hijacker = NULL;
337   for (i=0;i<7;i++)
338     GNUNET_free_non_null (helper_argv[i]);
339   for (i=0;i<=UINT16_MAX;i++)
340     cleanup_rr (&requests[i]);
341   GNUNET_SERVER_notification_context_destroy (nc);
342   nc = NULL;
343   if (stats != NULL)
344   {
345     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
346     stats = NULL;
347   }
348   if (NULL != dnsstub)
349   {
350     GNUNET_DNSSTUB_stop (dnsstub);
351     dnsstub = NULL;
352   }
353   if (NULL != mesh)
354   {
355     GNUNET_MESH_disconnect(mesh);
356     mesh = NULL;
357   }
358 }
359
360
361 /**
362  * We're done with some request, finish processing.
363  *
364  * @param rr request send to the network or just clean up.
365  */
366 static void
367 request_done (struct RequestRecord *rr)
368 {
369   struct GNUNET_MessageHeader *hdr;
370   size_t reply_len;
371   uint16_t source_port;
372   uint16_t destination_port;
373
374   GNUNET_array_grow (rr->client_wait_list,
375                      rr->client_wait_list_length,
376                      0); 
377   if (RP_RESPONSE_MONITOR != rr->phase)
378   {
379     /* no response, drop */
380     LOG (GNUNET_ERROR_TYPE_DEBUG,
381          "Got no response for request %llu, dropping\n",
382          (unsigned long long) rr->request_id);
383     cleanup_rr (rr);
384     return;
385   }
386
387   LOG (GNUNET_ERROR_TYPE_DEBUG,
388        "Transmitting response for request %llu\n",
389        (unsigned long long) rr->request_id);  
390   /* send response via hijacker */
391   reply_len = sizeof (struct GNUNET_MessageHeader);
392   reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
393   switch (rr->src_addr.ss_family)
394   {
395   case AF_INET:
396     reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
397     break;
398   case AF_INET6:
399     reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
400     break;
401   default:
402     GNUNET_break (0);
403     cleanup_rr (rr);
404     return;   
405   }
406   reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
407   reply_len += rr->payload_length;
408   if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
409   {
410     /* response too big, drop */
411     GNUNET_break (0); /* how can this be? */
412     cleanup_rr(rr);
413     return;    
414   }
415   {
416     char buf[reply_len] GNUNET_ALIGN;
417     size_t off;
418     struct GNUNET_TUN_IPv4Header ip4;
419     struct GNUNET_TUN_IPv6Header ip6;
420
421     /* first, GNUnet message header */
422     hdr = (struct GNUNET_MessageHeader*) buf;
423     hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
424     hdr->size = htons ((uint16_t) reply_len);
425     off = sizeof (struct GNUNET_MessageHeader);
426
427     /* first, TUN header */
428     {
429       struct GNUNET_TUN_Layer2PacketHeader tun;
430
431       tun.flags = htons (0);
432       if (rr->src_addr.ss_family == AF_INET)
433         tun.proto = htons (ETH_P_IPV4); 
434       else
435         tun.proto = htons (ETH_P_IPV6);
436       memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
437       off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
438     }
439
440     /* now IP header */
441     switch (rr->src_addr.ss_family)
442     {
443     case AF_INET:
444       {
445         struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
446         struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
447         
448         source_port = dst->sin_port;
449         destination_port = src->sin_port;
450         GNUNET_TUN_initialize_ipv4_header (&ip4,
451                                            IPPROTO_UDP,
452                                            reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
453                                            &dst->sin_addr,
454                                            &src->sin_addr);
455         memcpy (&buf[off], &ip4, sizeof (ip4));
456         off += sizeof (ip4);
457       }
458       break;
459     case AF_INET6:
460       {
461         struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
462         struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
463
464         source_port = dst->sin6_port;
465         destination_port = src->sin6_port;
466         GNUNET_TUN_initialize_ipv6_header (&ip6,
467                                            IPPROTO_UDP,
468                                            reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
469                                            &dst->sin6_addr,
470                                            &src->sin6_addr);
471         memcpy (&buf[off], &ip6, sizeof (ip6));
472         off += sizeof (ip6);
473       }
474       break;
475     default:
476       GNUNET_assert (0);
477     }
478
479     /* now UDP header */
480     {
481       struct GNUNET_TUN_UdpHeader udp;
482
483       udp.source_port = source_port;
484       udp.destination_port = destination_port;
485       udp.len = htons (reply_len - off);
486       if (AF_INET == rr->src_addr.ss_family)
487         GNUNET_TUN_calculate_udp4_checksum (&ip4,
488                                             &udp,
489                                             rr->payload,
490                                             rr->payload_length);
491       else
492         GNUNET_TUN_calculate_udp6_checksum (&ip6,
493                                             &udp,
494                                             rr->payload,
495                                             rr->payload_length);
496       memcpy (&buf[off], &udp, sizeof (udp));
497       off += sizeof (udp);
498     }
499
500     /* now DNS payload */
501     {
502       memcpy (&buf[off], rr->payload, rr->payload_length);
503       off += rr->payload_length;
504     }
505     /* final checks & sending */
506     GNUNET_assert (off == reply_len);
507     (void) GNUNET_HELPER_send (hijacker,
508                                hdr,
509                                GNUNET_YES,
510                                NULL, NULL);
511     GNUNET_STATISTICS_update (stats,
512                               gettext_noop ("# DNS requests answered via TUN interface"),
513                               1, GNUNET_NO);
514   }
515   /* clean up, we're done */
516   cleanup_rr (rr);
517 }
518
519
520 /**
521  * Show the payload of the given request record to the client
522  * (and wait for a response).
523  *
524  * @param rr request to send to client
525  * @param client client to send the response to
526  */
527 static void
528 send_request_to_client (struct RequestRecord *rr,
529                         struct GNUNET_SERVER_Client *client)
530 {
531   char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length] GNUNET_ALIGN;
532   struct GNUNET_DNS_Request *req;
533
534   if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
535   {
536     GNUNET_break (0);
537     cleanup_rr (rr);
538     return;
539   }
540   LOG (GNUNET_ERROR_TYPE_DEBUG,
541        "Sending information about request %llu to local client\n",
542        (unsigned long long) rr->request_id);  
543   req = (struct GNUNET_DNS_Request*) buf;
544   req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
545   req->header.size = htons (sizeof (buf));
546   req->reserved = htonl (0);
547   req->request_id = rr->request_id;
548   memcpy (&req[1], rr->payload, rr->payload_length);
549   GNUNET_SERVER_notification_context_unicast (nc, 
550                                               client,
551                                               &req->header,
552                                               GNUNET_NO);
553 }
554
555
556
557 /**
558  * Callback called from DNSSTUB resolver when a resolution
559  * succeeded.
560  *
561  * @param cls NULL
562  * @param rs the socket that received the response
563  * @param dns the response itself
564  * @param r number of bytes in dns
565  */
566 static void
567 process_dns_result (void *cls,
568                     struct GNUNET_DNSSTUB_RequestSocket *rs,
569                     const struct GNUNET_TUN_DnsHeader *dns,
570                     size_t r);
571
572
573 /**
574  * A client has completed its processing for this
575  * request.  Move on.
576  *
577  * @param rr request to process further
578  */
579 static void
580 next_phase (struct RequestRecord *rr)
581 {
582   struct ClientRecord *cr;
583   int nz;
584   unsigned int j;
585   socklen_t salen;
586
587   if (rr->phase == RP_DROP)
588   {
589     cleanup_rr (rr);
590     return;
591   }
592   nz = -1;
593   for (j=0;j<rr->client_wait_list_length;j++)
594   {
595     if (NULL != rr->client_wait_list[j])
596     {
597       nz = (int) j;
598       break;
599     }
600   }  
601   if (-1 != nz) 
602   {
603     send_request_to_client (rr, rr->client_wait_list[nz]->client);
604     return;
605   }
606   /* done with current phase, advance! */
607   LOG (GNUNET_ERROR_TYPE_DEBUG,
608        "Request %llu now in phase %d\n",
609        rr->request_id,
610        rr->phase);  
611   switch (rr->phase)
612   {
613   case RP_INIT:
614     rr->phase = RP_REQUEST_MONITOR;
615     for (cr = clients_head; NULL != cr; cr = cr->next)
616     {
617       if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
618         GNUNET_array_append (rr->client_wait_list,
619                              rr->client_wait_list_length,
620                              cr);
621     }
622     next_phase (rr);
623     return;
624   case RP_REQUEST_MONITOR:
625     rr->phase = RP_QUERY;
626     for (cr = clients_head; NULL != cr; cr = cr->next)
627     {
628       if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
629         GNUNET_array_append (rr->client_wait_list,
630                              rr->client_wait_list_length,
631                              cr);
632     }
633     next_phase (rr);
634     return;
635   case RP_QUERY:
636     switch (rr->dst_addr.ss_family)
637     {
638     case AF_INET:
639       salen = sizeof (struct sockaddr_in);
640       break;
641     case AF_INET6:
642       salen = sizeof (struct sockaddr_in6);
643       break;
644     default:
645       GNUNET_assert (0);
646     }
647
648     rr->phase = RP_INTERNET_DNS;
649     rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
650                                      (struct sockaddr*) &rr->dst_addr,
651                                      salen,
652                                      rr->payload,
653                                      rr->payload_length,
654                                      &process_dns_result,
655                                      NULL);
656     if (NULL == rr->rs)
657     {
658       GNUNET_STATISTICS_update (stats,
659                                 gettext_noop ("# DNS exit failed (failed to open socket)"),
660                                 1, GNUNET_NO);
661       cleanup_rr (rr);
662       return;
663     }
664     return;
665   case RP_INTERNET_DNS:
666     rr->phase = RP_MODIFY;
667     for (cr = clients_head; NULL != cr; cr = cr->next)
668     {
669       if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
670         GNUNET_array_append (rr->client_wait_list,
671                              rr->client_wait_list_length,
672                              cr);
673     }
674     next_phase (rr);
675     return;
676   case RP_MODIFY:
677     rr->phase = RP_RESPONSE_MONITOR;
678     for (cr = clients_head; NULL != cr; cr = cr->next)
679     {
680       if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
681         GNUNET_array_append (rr->client_wait_list,
682                              rr->client_wait_list_length,
683                              cr);
684     }
685     next_phase (rr);
686     return;
687  case RP_RESPONSE_MONITOR:
688     request_done (rr);
689     break;
690   case RP_DROP:
691     cleanup_rr (rr);
692     break;
693   default:
694     GNUNET_break (0);
695     cleanup_rr (rr);
696     break;
697   }
698 }
699
700
701 /**
702  * A client disconnected, clean up after it.
703  *
704  * @param cls unused
705  * @param client handle of client that disconnected
706  */ 
707 static void
708 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
709 {
710   struct ClientRecord *cr;
711   struct RequestRecord *rr;
712   unsigned int i;
713   unsigned int j;
714
715   for (cr = clients_head; NULL != cr; cr = cr->next)
716   {
717     if (cr->client == client)
718     {
719       GNUNET_SERVER_client_drop (client);
720       GNUNET_CONTAINER_DLL_remove (clients_head,
721                                    clients_tail,
722                                    cr);
723       for (i=0;i<UINT16_MAX;i++)
724       {
725         rr = &requests[i];
726         if (0 == rr->client_wait_list_length)
727           continue; /* not in use */
728         for (j=0;j<rr->client_wait_list_length;j++)
729         {
730           if (rr->client_wait_list[j] == cr)
731           {
732             rr->client_wait_list[j] = NULL;
733             next_phase (rr); 
734           }
735         }
736       }
737       GNUNET_free (cr);
738       return;
739     }
740   }
741 }
742
743
744 /**
745  * We got a reply from DNS for a request of a MESH tunnel.  Send it
746  * via the tunnel (after changing the request ID back).
747  *
748  * @param cls the 'struct TunnelState'
749  * @param size number of bytes available in buf
750  * @param buf where to copy the reply
751  * @return number of bytes written to buf
752  */
753 static size_t
754 transmit_reply_to_mesh (void *cls,
755                         size_t size,
756                         void *buf)
757 {
758   struct TunnelState *ts = cls;
759   size_t off;
760   size_t ret;
761   char *cbuf = buf;
762   struct GNUNET_MessageHeader hdr;
763   struct GNUNET_TUN_DnsHeader dns;
764
765   ts->th = NULL;
766   GNUNET_assert (ts->reply != NULL);
767   if (size == 0)
768     return 0;
769   ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length; 
770   GNUNET_assert (ret <= size);
771   hdr.size = htons (ret);
772   hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
773   memcpy (&dns, ts->reply, sizeof (dns));
774   dns.id = ts->original_id;
775   off = 0;
776   memcpy (&cbuf[off], &hdr, sizeof (hdr));
777   off += sizeof (hdr);
778   memcpy (&cbuf[off], &dns, sizeof (dns));
779   off += sizeof (dns);
780   memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns));
781   off += ts->reply_length - sizeof (dns);
782   GNUNET_free (ts->reply);
783   ts->reply = NULL;
784   ts->reply_length = 0;  
785   GNUNET_assert (ret == off);
786   return ret;
787 }
788
789
790
791 /**
792  * Callback called from DNSSTUB resolver when a resolution
793  * succeeded.
794  *
795  * @param cls NULL
796  * @param rs the socket that received the response
797  * @param dns the response itself
798  * @param r number of bytes in dns
799  */
800 static void
801 process_dns_result (void *cls,
802                     struct GNUNET_DNSSTUB_RequestSocket *rs,
803                     const struct GNUNET_TUN_DnsHeader *dns,
804                     size_t r)
805 {
806   struct RequestRecord *rr;
807   struct TunnelState *ts;
808
809   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810               "Processing DNS result from stub resolver\n");
811   GNUNET_assert (NULL == cls);
812   /* Handle case that this is a reply to a request from a MESH DNS tunnel */
813   ts = tunnels[dns->id];
814   if ( (NULL == ts) ||
815        (ts->rs != rs) )
816     ts = NULL; /* DNS responder address missmatch */
817   if (NULL != ts)
818   {
819     LOG (GNUNET_ERROR_TYPE_DEBUG,
820          "Got a response from the stub resolver for DNS request received via MESH!\n");
821     tunnels[dns->id] = NULL;
822     GNUNET_free_non_null (ts->reply);
823     ts->reply = GNUNET_malloc (r);
824     ts->reply_length = r;
825     memcpy (ts->reply, dns, r);
826     if (NULL != ts->th)
827       GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
828     ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
829                                                 GNUNET_NO,
830                                                 GNUNET_TIME_UNIT_FOREVER_REL,
831                                                 NULL,
832                                                 sizeof (struct GNUNET_MessageHeader) + r,
833                                                 &transmit_reply_to_mesh,
834                                                 ts);
835   }
836   /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
837   rr = &requests[dns->id];
838   if ( (rr->phase != RP_INTERNET_DNS) ||
839        (rr->rs != rs) )
840   {
841     if (NULL == ts)
842     {
843       /* unexpected / bogus reply */
844       GNUNET_STATISTICS_update (stats,
845                                 gettext_noop ("# External DNS response discarded (no matching request)"),
846                                 1, GNUNET_NO);
847     }
848     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849                 "Received DNS reply that does not match any pending request.  Dropping.\n"); 
850     return; 
851   }
852   LOG (GNUNET_ERROR_TYPE_DEBUG,
853        "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
854        (unsigned long long) rr->request_id);
855   GNUNET_free_non_null (rr->payload);
856   rr->payload = GNUNET_malloc (r);
857   memcpy (rr->payload, dns, r);
858   rr->payload_length = r;
859   next_phase (rr);
860 }
861
862
863 /**
864  * We got a new client.  Make sure all new DNS requests pass by its desk.
865  *
866  * @param cls unused
867  * @param client the new client
868  * @param message the init message (unused)
869  */
870 static void
871 handle_client_init (void *cls GNUNET_UNUSED, 
872                     struct GNUNET_SERVER_Client *client,
873                     const struct GNUNET_MessageHeader *message)
874 {
875   struct ClientRecord *cr;
876   const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
877
878   cr = GNUNET_malloc (sizeof (struct ClientRecord));
879   cr->client = client;
880   cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);  
881   GNUNET_SERVER_client_keep (client);
882   GNUNET_CONTAINER_DLL_insert (clients_head,
883                                clients_tail,
884                                cr);
885   GNUNET_SERVER_notification_context_add (nc, client);
886   GNUNET_SERVER_receive_done (client, GNUNET_OK);
887 }
888
889
890 /**
891  * We got a response from a client.
892  *
893  * @param cls unused
894  * @param client the client
895  * @param message the response
896  */
897 static void
898 handle_client_response (void *cls GNUNET_UNUSED, 
899                         struct GNUNET_SERVER_Client *client,
900                         const struct GNUNET_MessageHeader *message)
901 {
902   const struct GNUNET_DNS_Response *resp;
903   struct RequestRecord *rr;
904   unsigned int i;
905   uint16_t msize;
906   uint16_t off;
907
908   msize = ntohs (message->size);
909   if (msize < sizeof (struct GNUNET_DNS_Response))
910   {
911     GNUNET_break (0);
912     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
913     return;
914   }
915   resp = (const struct GNUNET_DNS_Response*) message;
916   off = (uint16_t) resp->request_id;
917   rr = &requests[off];
918   LOG (GNUNET_ERROR_TYPE_DEBUG,
919        "Received DNS response with ID %llu from local client!\n",
920        (unsigned long long) resp->request_id);
921   if (rr->request_id != resp->request_id)
922   {
923     GNUNET_STATISTICS_update (stats,
924                               gettext_noop ("# Client response discarded (no matching request)"),
925                               1, GNUNET_NO);
926     GNUNET_SERVER_receive_done (client, GNUNET_OK);
927     return;
928   }
929   for (i=0;i<rr->client_wait_list_length;i++)
930   {
931     if (NULL == rr->client_wait_list[i])
932       continue;
933     if (rr->client_wait_list[i]->client != client)
934       continue;
935     rr->client_wait_list[i] = NULL;
936     switch (ntohl (resp->drop_flag))
937     {
938     case 0: /* drop */
939       rr->phase = RP_DROP;
940       break;
941     case 1: /* no change */
942       break;
943     case 2: /* update */
944       msize -= sizeof (struct GNUNET_DNS_Response);
945       if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
946            (RP_REQUEST_MONITOR == rr->phase) ||
947            (RP_RESPONSE_MONITOR == rr->phase) )
948       {
949         GNUNET_break (0);
950         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
951         next_phase (rr); 
952         return;
953       }
954       GNUNET_free_non_null (rr->payload);
955       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
956                   "Changing DNS reply according to client specifications\n");
957       rr->payload = GNUNET_malloc (msize);
958       rr->payload_length = msize;
959       memcpy (rr->payload, &resp[1], msize);
960       if (rr->phase == RP_QUERY)
961       {
962         /* clear wait list, we're moving to MODIFY phase next */
963         GNUNET_array_grow (rr->client_wait_list,
964                            rr->client_wait_list_length,
965                            0);
966       }
967       /* if query changed to answer, move past DNS resolution phase... */
968       if ( (RP_QUERY == rr->phase) &&
969            (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
970            ((struct GNUNET_DNSPARSER_Flags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
971       {
972         rr->phase = RP_INTERNET_DNS;
973         GNUNET_array_grow (rr->client_wait_list,
974                            rr->client_wait_list_length,
975                            0);
976       }
977       break;
978     }
979     next_phase (rr); 
980     GNUNET_SERVER_receive_done (client, GNUNET_OK);
981     return;      
982   }
983   /* odd, client was not on our list for the request, that ought
984      to be an error */
985   GNUNET_break (0);
986   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
987 }
988
989
990 /**
991  * Functions with this signature are called whenever a complete
992  * message is received by the tokenizer from the DNS hijack process.
993  *
994  * @param cls closure
995  * @param client identification of the client
996  * @param message the actual message, a DNS request we should handle
997  */
998 static int
999 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1000                          const struct GNUNET_MessageHeader *message)
1001 {
1002   uint16_t msize;
1003   const struct GNUNET_TUN_Layer2PacketHeader *tun;
1004   const struct GNUNET_TUN_IPv4Header *ip4;
1005   const struct GNUNET_TUN_IPv6Header *ip6;
1006   const struct GNUNET_TUN_UdpHeader *udp;
1007   const struct GNUNET_TUN_DnsHeader *dns;
1008   struct RequestRecord *rr;
1009   struct sockaddr_in *srca4;
1010   struct sockaddr_in6 *srca6;
1011   struct sockaddr_in *dsta4;
1012   struct sockaddr_in6 *dsta6;
1013
1014   LOG (GNUNET_ERROR_TYPE_DEBUG,
1015        "Intercepted message via DNS hijacker\n");
1016   msize = ntohs (message->size);
1017   if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1018   {
1019     /* non-IP packet received on TUN!? */
1020     GNUNET_break (0);
1021     return GNUNET_OK;
1022   }
1023   msize -= sizeof (struct GNUNET_MessageHeader);
1024   tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1025   msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1026   switch (ntohs (tun->proto))
1027   {
1028   case ETH_P_IPV4:
1029     ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1030     ip6 = NULL; /* make compiler happy */
1031     if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1032          (ip4->version != 4) ||
1033          (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1034          (ntohs(ip4->total_length) != msize) ||
1035          (ip4->protocol != IPPROTO_UDP) )
1036     {
1037       /* non-IP/UDP packet received on TUN (or with options) */
1038       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1039                   _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1040       return GNUNET_OK;
1041     }
1042     udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1043     msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1044     break;
1045   case ETH_P_IPV6:
1046     ip4 = NULL; /* make compiler happy */
1047     ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1048     if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1049          (ip6->version != 6) ||
1050          (ntohs (ip6->payload_length) != msize) ||
1051          (ip6->next_header != IPPROTO_UDP) )
1052     {
1053       /* non-IP/UDP packet received on TUN (or with extensions) */
1054       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1055                   _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1056       return GNUNET_OK;
1057     }
1058     udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1059     msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1060     break;
1061   default:
1062     /* non-IP packet received on TUN!? */
1063     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1064                 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1065                 (unsigned int) msize,
1066                 ntohs (tun->proto));
1067     return GNUNET_OK;
1068   }
1069   if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1070   {    
1071     /* non-DNS packet received on TUN, ignore */
1072     GNUNET_STATISTICS_update (stats,
1073                               gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1074                               1, GNUNET_NO);
1075     return GNUNET_OK;
1076   }
1077   msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1078   dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1079   rr = &requests[dns->id];
1080
1081   /* clean up from previous request */
1082   GNUNET_free_non_null (rr->payload);
1083   rr->payload = NULL;
1084   GNUNET_array_grow (rr->client_wait_list,
1085                      rr->client_wait_list_length,
1086                      0);
1087
1088   /* setup new request */
1089   rr->phase = RP_INIT;
1090   switch (ntohs (tun->proto))
1091   {
1092   case ETH_P_IPV4:
1093     {
1094       srca4 = (struct sockaddr_in*) &rr->src_addr;
1095       dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1096       memset (srca4, 0, sizeof (struct sockaddr_in));
1097       memset (dsta4, 0, sizeof (struct sockaddr_in));
1098       srca4->sin_family = AF_INET;
1099       dsta4->sin_family = AF_INET;
1100       srca4->sin_addr = ip4->source_address;
1101       dsta4->sin_addr = ip4->destination_address;
1102       srca4->sin_port = udp->source_port;
1103       dsta4->sin_port = udp->destination_port;
1104 #if HAVE_SOCKADDR_IN_SIN_LEN
1105       srca4->sin_len = sizeof (struct sockaddr_in);
1106       dsta4->sin_len = sizeof (struct sockaddr_in);
1107 #endif
1108     }
1109     break;
1110   case ETH_P_IPV6:
1111     {
1112       srca6 = (struct sockaddr_in6*) &rr->src_addr;
1113       dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1114       memset (srca6, 0, sizeof (struct sockaddr_in6));
1115       memset (dsta6, 0, sizeof (struct sockaddr_in6));
1116       srca6->sin6_family = AF_INET6;
1117       dsta6->sin6_family = AF_INET6;
1118       srca6->sin6_addr = ip6->source_address;
1119       dsta6->sin6_addr = ip6->destination_address;
1120       srca6->sin6_port = udp->source_port;
1121       dsta6->sin6_port = udp->destination_port;
1122 #if HAVE_SOCKADDR_IN_SIN_LEN
1123       srca6->sin6_len = sizeof (struct sockaddr_in6);
1124       dsta6->sin6_len = sizeof (struct sockaddr_in6);
1125 #endif
1126     }
1127   break;
1128   default:
1129     GNUNET_assert (0);
1130   }
1131   rr->payload = GNUNET_malloc (msize);
1132   rr->payload_length = msize;
1133   memcpy (rr->payload, dns, msize);
1134   rr->request_id = dns->id | (request_id_gen << 16);
1135   request_id_gen++;
1136   LOG (GNUNET_ERROR_TYPE_DEBUG,
1137        "Creating new DNS request %llu\n",
1138        (unsigned long long) rr->request_id);
1139   GNUNET_STATISTICS_update (stats,
1140                             gettext_noop ("# DNS requests received via TUN interface"),
1141                             1, GNUNET_NO);
1142   /* start request processing state machine */
1143   next_phase (rr);
1144   return GNUNET_OK;
1145 }
1146
1147
1148 /**
1149  * Process a request via mesh to perform a DNS query.
1150  *
1151  * @param cls closure, NULL
1152  * @param tunnel connection to the other end
1153  * @param tunnel_ctx pointer to our 'struct TunnelState *'
1154  * @param sender who sent the message
1155  * @param message the actual message
1156  * @param atsi performance data for the connection
1157  * @return GNUNET_OK to keep the connection open,
1158  *         GNUNET_SYSERR to close it (signal serious error)
1159  */
1160 static int
1161 receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1162                      void **tunnel_ctx,
1163                      const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1164                      const struct GNUNET_MessageHeader *message,
1165                      const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1166 {
1167   struct TunnelState *ts = *tunnel_ctx;
1168   const struct GNUNET_TUN_DnsHeader *dns;
1169   size_t mlen = ntohs (message->size);
1170   size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1171   char buf[dlen] GNUNET_ALIGN;
1172   struct GNUNET_TUN_DnsHeader *dout;
1173  
1174   if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1175   {
1176     GNUNET_break_op (0);
1177     return GNUNET_SYSERR;
1178   }
1179   dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
1180   ts->original_id = dns->id;
1181   if (tunnels[ts->my_id] == ts)
1182     tunnels[ts->my_id] = NULL;
1183   ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 
1184                                                    UINT16_MAX + 1);
1185   tunnels[ts->my_id] = ts;
1186   memcpy (buf, dns, dlen);
1187   dout = (struct GNUNET_TUN_DnsHeader *) buf;
1188   dout->id = ts->my_id;
1189   ts->rs = GNUNET_DNSSTUB_resolve2 (dnsstub,
1190                                     buf, dlen,
1191                                     &process_dns_result,
1192                                     NULL);
1193   if (NULL == ts->rs)
1194     return GNUNET_SYSERR;
1195   return GNUNET_OK;
1196 }
1197
1198
1199 /**
1200  * Callback from GNUNET_MESH for new tunnels.
1201  *
1202  * @param cls closure
1203  * @param tunnel new handle to the tunnel
1204  * @param initiator peer that started the tunnel
1205  * @param ats performance information for the tunnel
1206  * @return initial tunnel context for the tunnel
1207  */
1208 static void *
1209 accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1210                    const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1211                    const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1212 {
1213   struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState));
1214
1215   GNUNET_STATISTICS_update (stats,
1216                             gettext_noop ("# Inbound MESH tunnels created"),
1217                             1, GNUNET_NO);
1218   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219               "Received inbound tunnel from `%s'\n",
1220               GNUNET_i2s (initiator));
1221   ts->tunnel = tunnel;
1222   return ts;
1223 }
1224
1225
1226 /**
1227  * Function called by mesh whenever an inbound tunnel is destroyed.
1228  * Should clean up any associated state.
1229  *
1230  * @param cls closure (set from GNUNET_MESH_connect)
1231  * @param tunnel connection to the other end (henceforth invalid)
1232  * @param tunnel_ctx place where local state associated
1233  *                   with the tunnel is stored
1234  */
1235 static void
1236 destroy_dns_tunnel (void *cls GNUNET_UNUSED, 
1237                     const struct GNUNET_MESH_Tunnel *tunnel,
1238                     void *tunnel_ctx)
1239 {
1240   struct TunnelState *ts = tunnel_ctx;
1241
1242   if (tunnels[ts->my_id] == ts)
1243     tunnels[ts->my_id] = NULL;
1244   if (NULL != ts->th)
1245     GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1246   GNUNET_free_non_null (ts->reply);
1247   GNUNET_free (ts);
1248 }
1249
1250
1251 /**
1252  * @param cls closure
1253  * @param server the initialized server
1254  * @param cfg_ configuration to use
1255  */
1256 static void
1257 run (void *cls, struct GNUNET_SERVER_Handle *server,
1258      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1259 {
1260   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1261     /* callback, cls, type, size */
1262     {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, 
1263      sizeof (struct GNUNET_DNS_Register)},
1264     {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1265     {NULL, NULL, 0, 0}
1266   };
1267   char *ifc_name;
1268   char *ipv4addr;
1269   char *ipv4mask;
1270   char *ipv6addr;
1271   char *ipv6prefix;
1272   struct in_addr dns_exit4;
1273   struct in6_addr dns_exit6;
1274   char *dns_exit;
1275
1276   cfg = cfg_;
1277   if (GNUNET_YES !=
1278       GNUNET_OS_check_helper_binary ("gnunet-helper-dns"))
1279   {
1280     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1281                 _("`%s' must be installed SUID, refusing to run\n"),
1282                 "gnunet-helper-dns");
1283     global_ret = 1;
1284     return;
1285   }
1286
1287   stats = GNUNET_STATISTICS_create ("dns", cfg);
1288   nc = GNUNET_SERVER_notification_context_create (server, 1);
1289   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1290                                 cls);
1291   dns_exit = NULL;
1292   if ( (GNUNET_YES ==
1293         GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) &&
1294        ( (GNUNET_OK !=
1295           GNUNET_CONFIGURATION_get_value_string (cfg, "dns", 
1296                                                  "DNS_EXIT",
1297                                                  &dns_exit)) ||
1298          ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1299            (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1300   {
1301     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "dns", "DNS_EXIT",
1302                 _("need a valid IPv4 or IPv6 address\n"));
1303     GNUNET_free_non_null (dns_exit);
1304     dns_exit = NULL;
1305   }
1306   dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1307   helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1308   if (GNUNET_SYSERR ==
1309       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1310   {
1311     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1312                 "No entry 'IFNAME' in configuration!\n");
1313     GNUNET_SCHEDULER_shutdown ();
1314     return;
1315   }
1316   helper_argv[1] = ifc_name;
1317   if ( (GNUNET_SYSERR ==
1318         GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1319                                                &ipv6addr)) )
1320   {
1321     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1322                 "No entry 'IPV6ADDR' in configuration!\n");
1323     GNUNET_SCHEDULER_shutdown ();
1324     return;
1325   }
1326   helper_argv[2] = ipv6addr;
1327   if (GNUNET_SYSERR ==
1328       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1329                                              &ipv6prefix))
1330   {
1331     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1332                 "No entry 'IPV6PREFIX' in configuration!\n");
1333     GNUNET_SCHEDULER_shutdown ();
1334     return;
1335   }
1336   helper_argv[3] = ipv6prefix;
1337
1338   if (GNUNET_SYSERR ==
1339       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1340                                              &ipv4addr))
1341   {
1342     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1343                 "No entry 'IPV4ADDR' in configuration!\n");
1344     GNUNET_SCHEDULER_shutdown ();
1345     return;
1346   }
1347   helper_argv[4] = ipv4addr;
1348   if (GNUNET_SYSERR ==
1349       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1350                                              &ipv4mask))
1351   {
1352     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1353                 "No entry 'IPV4MASK' in configuration!\n");
1354     GNUNET_SCHEDULER_shutdown ();
1355     return;
1356   }
1357   helper_argv[5] = ipv4mask;
1358   helper_argv[6] = NULL;
1359
1360   if (NULL != dns_exit)
1361   {
1362     static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1363       {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0},
1364       {NULL, 0, 0}
1365     };
1366     static GNUNET_MESH_ApplicationType mesh_types[] = {
1367       GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1368       GNUNET_APPLICATION_TYPE_END
1369     };
1370     mesh = GNUNET_MESH_connect (cfg,
1371                                 NULL,
1372                                 &accept_dns_tunnel, 
1373                                 &destroy_dns_tunnel,
1374                                 mesh_handlers,
1375                                 mesh_types);
1376   }
1377   hijacker = GNUNET_HELPER_start (GNUNET_NO,
1378                                   "gnunet-helper-dns",
1379                                   helper_argv,
1380                                   &process_helper_messages,
1381                                   NULL, NULL);
1382   GNUNET_SERVER_add_handlers (server, handlers);
1383   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1384 }
1385
1386
1387 /**
1388  * The main function for the dns service.
1389  *
1390  * @param argc number of arguments from the command line
1391  * @param argv command line arguments
1392  * @return 0 ok, 1 on error
1393  */
1394 int
1395 main (int argc, char *const *argv)
1396 {
1397   /* make use of SGID capabilities on POSIX */
1398   /* FIXME: this might need a port on systems without 'getresgid' */
1399 #if HAVE_GETRESGID
1400   gid_t rgid;
1401   gid_t egid;
1402   gid_t sgid;
1403
1404   if (-1 == getresgid (&rgid, &egid, &sgid))
1405   {
1406     fprintf (stderr,
1407              "getresgid failed: %s\n",
1408              strerror (errno));
1409   }
1410   else if (sgid != rgid)
1411   {    
1412     if (-1 ==  setregid (sgid, sgid))
1413       fprintf (stderr, "setregid failed: %s\n", strerror (errno));
1414   }
1415 #endif
1416   return (GNUNET_OK ==
1417           GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1418                               &run, NULL)) ? global_ret : 1;
1419 }
1420
1421
1422 /* end of gnunet-service-dns.c */