Mesh calls me with a NULL peer to terminate the list of peers
[oweals/gnunet.git] / src / vpn / gnunet-service-dns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 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 vpn/gnunet-service-dns.c
23  * @author Philipp Toelke
24  */
25 #include "platform.h"
26 #include "gnunet_getopt_lib.h"
27 #include "gnunet_service_lib.h"
28 #include "gnunet_network_lib.h"
29 #include "gnunet_os_lib.h"
30 #include "gnunet-service-dns-p.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_applications.h"
33 #include "gnunet-vpn-packet.h"
34 #include "gnunet_container_lib.h"
35 #include "gnunet-dns-parser.h"
36 #include "gnunet_dht_service.h"
37 #include "gnunet_block_lib.h"
38 #include "block_dns.h"
39 #include "gnunet_crypto_lib.h"
40 #include "gnunet_mesh_service.h"
41 #include "gnunet_signatures.h"
42
43 struct GNUNET_MESH_Handle *mesh_handle;
44
45 /**
46  * The UDP-Socket through which DNS-Resolves will be sent if they are not to be
47  * sent through gnunet. The port of this socket will not be hijacked.
48  */
49 static struct GNUNET_NETWORK_Handle *dnsout;
50
51 /**
52  * The port bound to the socket dnsout
53  */
54 static unsigned short dnsoutport;
55
56 /**
57  * A handle to the DHT-Service
58  */
59 static struct GNUNET_DHT_Handle *dht;
60
61 /**
62  * The configuration to use
63  */
64 static const struct GNUNET_CONFIGURATION_Handle *cfg;
65
66 /**
67  * A list of DNS-Responses that have to be sent to the requesting client
68  */
69 static struct answer_packet_list *head;
70
71 /**
72  * The tail of the list of DNS-responses
73  */
74 static struct answer_packet_list *tail;
75
76 /**
77  * A structure containing a mapping from network-byte-ordered DNS-id (16 bit) to
78  * some information needed to handle this query
79  *
80  * It currently allocates at least
81  * (1 + machine-width + machine-width + 32 + 32 + 16 + machine-width + 8) * 65536 bit
82  * = 17 MiB on 64 bit.
83  * = 11 MiB on 32 bit.
84  */
85 static struct {
86     unsigned valid:1;
87     struct GNUNET_SERVER_Client* client;
88     struct GNUNET_MESH_Tunnel *tunnel;
89     uint32_t local_ip;
90     uint32_t remote_ip;
91     uint16_t local_port;
92     char* name;
93     uint8_t namelen;
94 } query_states[UINT16_MAX];
95
96 /**
97  * A struct used to give more than one value as
98  * closure to receive_dht
99  */
100 struct receive_dht_cls {
101     uint16_t id;
102     struct GNUNET_DHT_GetHandle* handle;
103 };
104
105 /**
106  * Hijack all outgoing DNS-Traffic but for traffic leaving "our" port.
107  */
108 static void
109 hijack (void *cls __attribute__((unused)), const struct GNUNET_SCHEDULER_TaskContext *tc)
110 {
111   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
112     return;
113
114   char port_s[6];
115   char *virt_dns;
116   struct GNUNET_OS_Process *proc;
117
118   if (GNUNET_SYSERR ==
119       GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS",
120                                              &virt_dns))
121     {
122       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
123                   "No entry 'VIRTDNS' in configuration!\n");
124       exit (1);
125     }
126
127   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacking, port is %d\n", dnsoutport);
128   snprintf (port_s, 6, "%d", dnsoutport);
129   if (NULL != (proc = GNUNET_OS_start_process (NULL,
130                                                NULL,
131                                                "gnunet-helper-hijack-dns",
132                                                "gnunet-hijack-dns",
133                                                port_s, virt_dns, NULL)))
134     GNUNET_OS_process_close (proc);
135   GNUNET_free (virt_dns);
136 }
137
138 /**
139  * Delete the hijacking-routes
140  */
141 static void
142 unhijack (unsigned short port)
143 {
144   char port_s[6];
145   char *virt_dns;
146   struct GNUNET_OS_Process *proc;
147
148   if (GNUNET_SYSERR ==
149       GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS",
150                                              &virt_dns))
151     {
152       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
153                   "No entry 'VIRTDNS' in configuration!\n");
154       exit (1);
155     }
156
157   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unHijacking, port is %d\n", port);
158   snprintf (port_s, 6, "%d", port);
159   if (NULL != (proc = GNUNET_OS_start_process (NULL,
160                                                NULL,
161                                                "gnunet-helper-hijack-dns",
162                                                "gnunet-hijack-dns",
163                                                "-d", port_s, virt_dns, NULL)))
164     GNUNET_OS_process_close (proc);
165   GNUNET_free (virt_dns);
166 }
167
168 /**
169  * Send the DNS-Response to the client. Gets called via the notify_transmit_ready-
170  * system.
171  */
172 static size_t
173 send_answer(void* cls, size_t size, void* buf) {
174     struct answer_packet_list* query = head;
175     size_t len = ntohs(query->pkt.hdr.size);
176
177     GNUNET_assert(len <= size);
178
179     memcpy(buf, &query->pkt.hdr, len);
180
181     GNUNET_CONTAINER_DLL_remove (head, tail, query);
182
183     GNUNET_free(query);
184
185     /* When more data is to be sent, reschedule */
186     if (head != NULL)
187       GNUNET_SERVER_notify_transmit_ready(cls,
188                                           ntohs(head->pkt.hdr.size),
189                                           GNUNET_TIME_UNIT_FOREVER_REL,
190                                           &send_answer,
191                                           cls);
192
193     return len;
194 }
195
196 struct tunnel_cls {
197     struct GNUNET_MESH_Tunnel *tunnel GNUNET_PACKED;
198     struct GNUNET_MessageHeader hdr;
199     struct dns_pkt dns;
200 };
201
202 struct tunnel_cls *remote_pending[UINT16_MAX];
203
204 static size_t
205 mesh_send_response (void *cls, size_t size, void *buf)
206 {
207   GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
208   struct GNUNET_MessageHeader *hdr = buf;
209   uint32_t *sz = cls;
210   struct dns_pkt *dns = (struct dns_pkt *) (sz + 1);
211   hdr->type = htons (GNUNET_MESSAGE_TYPE_REMOTE_ANSWER_DNS);
212   hdr->size = htons (*sz + sizeof (struct GNUNET_MessageHeader));
213
214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
215               "Sending response, size=%d, sz=%d, sz+hdr=%d\n", size, *sz,
216               *sz + sizeof (struct GNUNET_MessageHeader));
217
218   GNUNET_assert (size >= (*sz + sizeof (struct GNUNET_MessageHeader)));
219
220   memcpy (hdr + 1, dns, *sz);
221   GNUNET_free (cls);
222   return ntohs (hdr->size);
223 }
224
225 static size_t
226 mesh_send (void *cls, size_t size, void *buf)
227 {
228   struct tunnel_cls *cls_ = (struct tunnel_cls *) cls;
229
230   GNUNET_assert(cls_->hdr.size <= size);
231
232   size = cls_->hdr.size;
233   cls_->hdr.size = htons(cls_->hdr.size);
234
235   memcpy(buf, &cls_->hdr, size);
236   return size;
237 }
238
239
240 void mesh_connect (void* cls, const struct GNUNET_PeerIdentity* peer, const struct GNUNET_TRANSPORT_ATS_Information *atsi __attribute__((unused))) {
241   if (NULL == peer) return;
242   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %x\n", *((unsigned long*)peer));
243   struct tunnel_cls *cls_ = (struct tunnel_cls*)cls;
244
245   GNUNET_MESH_notify_transmit_ready(cls_->tunnel,
246                                     GNUNET_YES,
247                                     42,
248                                     GNUNET_TIME_UNIT_MINUTES,
249                                     NULL,
250                                     cls_->hdr.size,
251                                     mesh_send,
252                                     cls);
253 }
254
255
256 static void
257 send_mesh_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
258 {
259   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
260     return;
261
262   struct tunnel_cls *cls_ = (struct tunnel_cls*)cls;
263
264   cls_->tunnel = GNUNET_MESH_peer_request_connect_by_type(mesh_handle,
265                                            GNUNET_TIME_UNIT_HOURS,
266                                            GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
267                                            mesh_connect,
268                                            NULL,
269                                            cls_);
270
271   remote_pending[cls_->dns.s.id] = cls_;
272 }
273
274 static int
275 receive_mesh_query (void *cls __attribute__((unused)),
276                     struct GNUNET_MESH_Tunnel *tunnel,
277                     void **ctx __attribute__((unused)),
278                     const struct GNUNET_PeerIdentity *sender __attribute__((unused)),
279                     const struct GNUNET_MessageHeader *message,
280                     const struct GNUNET_TRANSPORT_ATS_Information *atsi __attribute__((unused)))
281 {
282   struct dns_pkt *dns = (struct dns_pkt*)(message + 1);
283
284   struct sockaddr_in dest;
285   memset(&dest, 0, sizeof dest);
286   dest.sin_port = htons(53);
287   /* TODO: read from config */
288   inet_pton(AF_INET, "8.8.8.8", &dest.sin_addr);
289
290   query_states[dns->s.id].tunnel = tunnel;
291   query_states[dns->s.id].valid = GNUNET_YES;
292
293   GNUNET_NETWORK_socket_sendto(dnsout,
294                                dns,
295                                ntohs(message->size) - sizeof(struct GNUNET_MessageHeader),
296                                (struct sockaddr*) &dest,
297                                sizeof dest);
298
299   return GNUNET_SYSERR;
300 }
301
302 static int
303 receive_mesh_answer (void *cls __attribute__((unused)),
304                      struct GNUNET_MESH_Tunnel *tunnel,
305                      void **ctx __attribute__((unused)),
306                      const struct GNUNET_PeerIdentity *sender __attribute__((unused)),
307                      const struct GNUNET_MessageHeader *message,
308                      const struct GNUNET_TRANSPORT_ATS_Information *atsi __attribute__((unused)))
309 {
310   /* TODo: size check */
311   struct dns_pkt *dns = (struct dns_pkt *) (message + 1);
312
313   /* They sent us a packet we were not waiting for */
314   if (remote_pending[dns->s.id] == NULL
315       || remote_pending[dns->s.id]->tunnel != tunnel)
316     return GNUNET_SYSERR;
317   if (query_states[dns->s.id].valid != GNUNET_YES)
318     return GNUNET_SYSERR;
319   query_states[dns->s.id].valid = GNUNET_NO;
320
321   size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[dns->s.id].namelen + sizeof (struct dns_query_line) + 2    /* To hold the pointer (as defined in RFC1035) to the name */
322     + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */
323
324   struct answer_packet_list *answer =
325     GNUNET_malloc (len + 2 * sizeof (struct answer_packet_list *));
326   memset (answer, 0, len + 2 * sizeof (struct answer_packet_list *));
327
328   answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
329   answer->pkt.hdr.size = htons (len);
330   answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE;
331
332   struct dns_pkt_parsed* pdns = parse_dns_packet(dns);
333
334   if (ntohs(pdns->s.ancount) < 1)
335     {
336       free_parsed_dns_packet(pdns);
337       return GNUNET_OK;
338     }
339
340   answer->pkt.addrsize = pdns->answers[0]->data_len;
341   memcpy(answer->pkt.addr, pdns->answers[0]->data, ntohs(pdns->answers[0]->data_len));
342
343   answer->pkt.from = query_states[dns->s.id].remote_ip;
344
345   answer->pkt.to = query_states[dns->s.id].local_ip;
346   answer->pkt.dst_port = query_states[dns->s.id].local_port;
347
348   struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data;
349
350   dpkt->s.id = dns->s.id;
351   dpkt->s.aa = 1;
352   dpkt->s.qr = 1;
353   dpkt->s.ra = 1;
354   dpkt->s.qdcount = htons (1);
355   dpkt->s.ancount = htons (1);
356
357   memcpy (dpkt->data, query_states[dns->s.id].name,
358           query_states[dns->s.id].namelen);
359   GNUNET_free (query_states[dns->s.id].name);
360
361   struct dns_query_line *dque =
362     (struct dns_query_line *) (dpkt->data +
363                                (query_states[dns->s.id].namelen));
364   dque->type = htons (28);      /* AAAA */
365   dque->class = htons (1);      /* IN */
366
367   char *anname =
368     (char *) (dpkt->data + (query_states[dns->s.id].namelen) +
369               sizeof (struct dns_query_line));
370   memcpy (anname, "\xc0\x0c", 2);
371
372   struct dns_record_line *drec_data =
373     (struct dns_record_line *) (dpkt->data +
374                                 (query_states[dns->s.id].namelen) +
375                                 sizeof (struct dns_query_line) + 2);
376   drec_data->type = htons (28); /* AAAA */
377   drec_data->class = htons (1); /* IN */
378
379   drec_data->ttl = pdns->answers[0]->ttl;
380   drec_data->data_len = htons (16);
381
382   /* Calculate at which offset in the packet the IPv6-Address belongs, it is
383    * filled in by the daemon-vpn */
384   answer->pkt.addroffset =
385     htons ((unsigned short) ((unsigned long) (&drec_data->data) -
386                              (unsigned long) (&answer->pkt)));
387
388   GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer);
389
390   GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client,
391                                        len,
392                                        GNUNET_TIME_UNIT_FOREVER_REL,
393                                        &send_answer,
394                                        query_states[dns->s.id].client);
395
396   free_parsed_dns_packet(pdns);
397   return GNUNET_OK;
398 }
399
400
401 static void
402 send_rev_query(void * cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
403     if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
404       return;
405
406     struct dns_pkt_parsed* pdns = (struct dns_pkt_parsed*) cls;
407
408     unsigned short id = pdns->s.id;
409
410     free_parsed_dns_packet(pdns);
411
412     if (query_states[id].valid != GNUNET_YES) return;
413     query_states[id].valid = GNUNET_NO;
414
415     GNUNET_assert(query_states[id].namelen == 74);
416
417     size_t len = sizeof(struct answer_packet) - 1 \
418                  + sizeof(struct dns_static) \
419                  + 74 /* this is the length of a reverse ipv6-lookup */ \
420                  + sizeof(struct dns_query_line) \
421                  + 2 /* To hold the pointer (as defined in RFC1035) to the name */ \
422                  + sizeof(struct dns_record_line) - 1 \
423                  - 2 /* We do not know the lenght of the answer yet*/;
424
425     struct answer_packet_list* answer = GNUNET_malloc(len + 2*sizeof(struct answer_packet_list*));
426     memset(answer, 0, len + 2*sizeof(struct answer_packet_list*));
427
428     answer->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
429     answer->pkt.hdr.size = htons(len);
430     answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REV;
431
432     answer->pkt.from = query_states[id].remote_ip;
433
434     answer->pkt.to = query_states[id].local_ip;
435     answer->pkt.dst_port = query_states[id].local_port;
436
437     struct dns_pkt *dpkt = (struct dns_pkt*)answer->pkt.data;
438
439     dpkt->s.id = id;
440     dpkt->s.aa = 1;
441     dpkt->s.qr = 1;
442     dpkt->s.ra = 1;
443     dpkt->s.qdcount = htons(1);
444     dpkt->s.ancount = htons(1);
445
446     memcpy(dpkt->data, query_states[id].name, query_states[id].namelen);
447     GNUNET_free(query_states[id].name);
448
449     struct dns_query_line* dque = (struct dns_query_line*)(dpkt->data+(query_states[id].namelen));
450     dque->type = htons(12); /* PTR */
451     dque->class = htons(1); /* IN */
452
453     char* anname = (char*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line));
454     memcpy(anname, "\xc0\x0c", 2);
455
456     struct dns_record_line *drec_data = (struct dns_record_line*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line)+2);
457     drec_data->type = htons(12); /* AAAA */
458     drec_data->class = htons(1); /* IN */
459     /* FIXME: read the TTL from block:
460      * GNUNET_TIME_absolute_get_remaining(rec->expiration_time)
461      *
462      * But how to get the seconds out of this?
463      */
464     drec_data->ttl = htonl(3600);
465
466     /* Calculate at which offset in the packet the length of the name and the
467      * name, it is filled in by the daemon-vpn */
468     answer->pkt.addroffset = htons((unsigned short)((unsigned long)(&drec_data->data_len)-(unsigned long)(&answer->pkt)));
469
470     GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, answer);
471
472     GNUNET_SERVER_notify_transmit_ready(query_states[id].client,
473                                         len,
474                                         GNUNET_TIME_UNIT_FOREVER_REL,
475                                         &send_answer,
476                                         query_states[id].client);
477 }
478
479 /**
480  * Receive a block from the dht.
481  */
482 static void
483 receive_dht(void *cls,
484             struct GNUNET_TIME_Absolute exp __attribute__((unused)),
485             const GNUNET_HashCode *key __attribute__((unused)),
486             const struct GNUNET_PeerIdentity *const *get_path __attribute__((unused)),
487             const struct GNUNET_PeerIdentity *const *put_path __attribute__((unused)),
488             enum GNUNET_BLOCK_Type type,
489             size_t size,
490             const void *data) {
491
492     unsigned short id = ((struct receive_dht_cls*)cls)->id;
493     struct GNUNET_DHT_GetHandle* handle = ((struct receive_dht_cls*)cls)->handle;
494     GNUNET_free(cls);
495
496     GNUNET_assert(type == GNUNET_BLOCK_TYPE_DNS);
497
498     /* If no query with this id is pending, ignore the block */
499     if (query_states[id].valid != GNUNET_YES) return;
500     query_states[id].valid = GNUNET_NO;
501
502     const struct GNUNET_DNS_Record* rec = data;
503     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
504                "Got block of size %d, peer: %08x, desc: %08x\n",
505                size,
506                *((unsigned int*)&rec->peer),
507                *((unsigned int*)&rec->service_descriptor));
508
509     size_t len = sizeof(struct answer_packet) - 1 \
510                  + sizeof(struct dns_static) \
511                  + query_states[id].namelen \
512                  + sizeof(struct dns_query_line) \
513                  + 2 /* To hold the pointer (as defined in RFC1035) to the name */ \
514                  + sizeof(struct dns_record_line) - 1 \
515                  + 16; /* To hold the IPv6-Address */
516
517     struct answer_packet_list* answer = GNUNET_malloc(len + 2*sizeof(struct answer_packet_list*));
518     memset(answer, 0, len + 2*sizeof(struct answer_packet_list*));
519
520     answer->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
521     answer->pkt.hdr.size = htons(len);
522     answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_SERVICE;
523
524     GNUNET_CRYPTO_hash(&rec->peer,
525                        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
526                        &answer->pkt.service_descr.peer);
527
528     memcpy(&answer->pkt.service_descr.service_descriptor,
529            &rec->service_descriptor,
530            sizeof(GNUNET_HashCode));
531     memcpy(&answer->pkt.service_descr.service_type,
532            &rec->service_type,
533            sizeof(answer->pkt.service_descr.service_type));
534     memcpy(&answer->pkt.service_descr.ports, &rec->ports, sizeof(answer->pkt.service_descr.ports));
535
536     answer->pkt.from = query_states[id].remote_ip;
537
538     answer->pkt.to = query_states[id].local_ip;
539     answer->pkt.dst_port = query_states[id].local_port;
540
541     struct dns_pkt *dpkt = (struct dns_pkt*)answer->pkt.data;
542
543     dpkt->s.id = id;
544     dpkt->s.aa = 1;
545     dpkt->s.qr = 1;
546     dpkt->s.ra = 1;
547     dpkt->s.qdcount = htons(1);
548     dpkt->s.ancount = htons(1);
549
550     memcpy(dpkt->data, query_states[id].name, query_states[id].namelen);
551     GNUNET_free(query_states[id].name);
552
553     struct dns_query_line* dque = (struct dns_query_line*)(dpkt->data+(query_states[id].namelen));
554     dque->type = htons(28); /* AAAA */
555     dque->class = htons(1); /* IN */
556
557     char* anname = (char*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line));
558     memcpy(anname, "\xc0\x0c", 2);
559
560     struct dns_record_line *drec_data = (struct dns_record_line*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line)+2);
561     drec_data->type = htons(28); /* AAAA */
562     drec_data->class = htons(1); /* IN */
563
564     /* FIXME: read the TTL from block:
565      * GNUNET_TIME_absolute_get_remaining(rec->expiration_time)
566      *
567      * But how to get the seconds out of this?
568      */
569     drec_data->ttl = htonl(3600);
570     drec_data->data_len = htons(16);
571
572     /* Calculate at which offset in the packet the IPv6-Address belongs, it is
573      * filled in by the daemon-vpn */
574     answer->pkt.addroffset = htons((unsigned short)((unsigned long)(&drec_data->data)-(unsigned long)(&answer->pkt)));
575
576     GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, answer);
577
578     GNUNET_SERVER_notify_transmit_ready(query_states[id].client,
579                                         len,
580                                         GNUNET_TIME_UNIT_FOREVER_REL,
581                                         &send_answer,
582                                         query_states[id].client);
583
584     GNUNET_DHT_get_stop(handle);
585 }
586
587 /**
588  * This receives a GNUNET_MESSAGE_TYPE_REHIJACK and rehijacks the DNS
589  */
590 static void
591 rehijack(void *cls __attribute__((unused)),
592          struct GNUNET_SERVER_Client *client,
593          const struct GNUNET_MessageHeader *message __attribute__((unused))) {
594     unhijack(dnsoutport);
595     GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS, hijack, NULL);
596
597     GNUNET_SERVER_receive_done(client, GNUNET_OK);
598 }
599
600 /**
601  * This receives the dns-payload from the daemon-vpn and sends it on over the udp-socket
602  */
603 static void
604 receive_query(void *cls __attribute__((unused)),
605               struct GNUNET_SERVER_Client *client,
606               const struct GNUNET_MessageHeader *message) {
607     struct query_packet* pkt = (struct query_packet*)message;
608     struct dns_pkt* dns = (struct dns_pkt*)pkt->data;
609     struct dns_pkt_parsed* pdns = parse_dns_packet(dns);
610
611     query_states[dns->s.id].valid = GNUNET_YES;
612     query_states[dns->s.id].client = client;
613     query_states[dns->s.id].local_ip = pkt->orig_from;
614     query_states[dns->s.id].local_port = pkt->src_port;
615     query_states[dns->s.id].remote_ip = pkt->orig_to;
616     query_states[dns->s.id].namelen = strlen((char*)dns->data) + 1;
617     query_states[dns->s.id].name = GNUNET_malloc(query_states[dns->s.id].namelen);
618     memcpy(query_states[dns->s.id].name, dns->data, query_states[dns->s.id].namelen);
619
620     /* The query is for a .gnunet-address */
621     if (pdns->queries[0]->namelen > 9 &&
622         0 == strncmp(pdns->queries[0]->name+(pdns->queries[0]->namelen - 9), ".gnunet.", 9))
623       {
624         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Query for .gnunet!\n");
625         GNUNET_HashCode key;
626         GNUNET_CRYPTO_hash(pdns->queries[0]->name, pdns->queries[0]->namelen, &key);
627
628         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
629                    "Getting with key %08x, len is %d\n",
630                    *((unsigned int*)&key),
631                    pdns->queries[0]->namelen);
632
633         struct receive_dht_cls* cls = GNUNET_malloc(sizeof(struct receive_dht_cls));
634         cls->id = dns->s.id;
635
636         cls->handle = GNUNET_DHT_get_start(dht,
637                                            GNUNET_TIME_UNIT_MINUTES,
638                                            GNUNET_BLOCK_TYPE_DNS,
639                                            &key,
640                                            DEFAULT_GET_REPLICATION,
641                                            GNUNET_DHT_RO_NONE,
642                                            NULL,
643                                            0,
644                                            NULL,
645                                            0,
646                                            receive_dht,
647                                            cls);
648
649         goto outfree;
650       }
651
652     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Query for '%s'; namelen=%d\n", pdns->queries[0]->name, pdns->queries[0]->namelen);
653
654     /* This is a PTR-Query. Check if it is for "our" network */
655     if (htons(pdns->queries[0]->qtype) == 12 &&
656         74 == pdns->queries[0]->namelen)
657       {
658         char* ipv6addr;
659         char ipv6[16];
660         char ipv6rev[74] = "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.ip6.arpa.";
661         unsigned int i;
662         unsigned long long ipv6prefix;
663         unsigned int comparelen;
664
665         GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "vpn", "IPV6ADDR", &ipv6addr));
666         inet_pton (AF_INET6, ipv6addr, ipv6);
667         GNUNET_free(ipv6addr);
668
669         GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "vpn", "IPV6PREFIX", &ipv6prefix));
670         GNUNET_assert(ipv6prefix < 127);
671         ipv6prefix = (ipv6prefix + 7)/8;
672
673         for (i = ipv6prefix; i < 16; i++)
674           ipv6[i] = 0;
675
676         for (i = 0; i < 16; i++)
677           {
678             unsigned char c1 = ipv6[i] >> 4;
679             unsigned char c2 = ipv6[i] & 0xf;
680
681             if (c1 <= 9)
682               ipv6rev[62-(4*i)] = c1 + '0';
683             else
684               ipv6rev[62-(4*i)] = c1 + 87; /* 87 is the difference between 'a' and 10 */
685
686             if (c2 <= 9)
687               ipv6rev[62-((4*i)+2)] = c2 + '0';
688             else
689               ipv6rev[62-((4*i)+2)] = c2 + 87;
690           }
691         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "My network is %s'.\n", ipv6rev);
692         comparelen = 10 + 4*ipv6prefix;
693         if(0 == strncmp(pdns->queries[0]->name+(pdns->queries[0]->namelen - comparelen),
694                         ipv6rev + (74 - comparelen),
695                         comparelen))
696           {
697             GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Reverse-Query for .gnunet!\n");
698
699             GNUNET_SCHEDULER_add_now(send_rev_query, pdns);
700
701             goto out;
702           }
703       }
704
705     char* virt_dns;
706     unsigned int virt_dns_bytes;
707     if (GNUNET_SYSERR ==
708         GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS",
709                                                &virt_dns))
710       {
711         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
712                     "No entry 'VIRTDNS' in configuration!\n");
713         exit (1);
714       }
715
716     if (1 != inet_pton (AF_INET, virt_dns, &virt_dns_bytes))
717       {
718         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
719                     "Error parsing 'VIRTDNS': %s; %m!\n", virt_dns);
720         exit(1);
721       }
722
723     GNUNET_free(virt_dns);
724
725     if (virt_dns_bytes == pkt->orig_to)
726       {
727         /* This is a packet that was sent directly to the virtual dns-server
728          *
729          * This means we have to send this query over gnunet
730          */
731
732         size_t size = sizeof(struct GNUNET_MESH_Tunnel*) + sizeof(struct GNUNET_MessageHeader) + (ntohs(message->size) - sizeof(struct query_packet) + 1);
733         struct tunnel_cls *cls_ =  GNUNET_malloc(size);
734         cls_->hdr.size = size - sizeof(struct GNUNET_MESH_Tunnel*);
735
736         cls_->hdr.type = ntohs(GNUNET_MESSAGE_TYPE_REMOTE_QUERY_DNS);
737         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size);
738
739         memcpy(&cls_->dns, dns, cls_->hdr.size - sizeof(struct GNUNET_MessageHeader));
740         GNUNET_SCHEDULER_add_now(send_mesh_query, cls_);
741
742         goto out;
743       }
744
745
746     /* The query should be sent to the network */
747
748     struct sockaddr_in dest;
749     memset(&dest, 0, sizeof dest);
750     dest.sin_port = htons(53);
751     dest.sin_addr.s_addr = pkt->orig_to;
752
753     GNUNET_NETWORK_socket_sendto(dnsout,
754                                  dns,
755                                  ntohs(pkt->hdr.size) - sizeof(struct query_packet) + 1,
756                                  (struct sockaddr*) &dest,
757                                  sizeof dest);
758
759 outfree:
760     free_parsed_dns_packet(pdns);
761     pdns = NULL;
762 out:
763     GNUNET_SERVER_receive_done(client, GNUNET_OK);
764 }
765
766 static void read_response (void *cls,
767                            const struct GNUNET_SCHEDULER_TaskContext *tc);
768
769 static void
770 open_port ()
771 {
772   struct sockaddr_in addr;
773
774   dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
775   if (dnsout == NULL)
776     return;
777   memset (&addr, 0, sizeof (struct sockaddr_in));
778
779   int err = GNUNET_NETWORK_socket_bind (dnsout,
780                                         (struct sockaddr *) &addr,
781                                         sizeof (struct sockaddr_in));
782
783   if (err != GNUNET_YES)
784     {
785       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
786                   "Could not bind a port, exiting\n");
787       return;
788     }
789
790   /* Read the port we bound to */
791   socklen_t addrlen = sizeof (struct sockaddr_in);
792   err = getsockname (GNUNET_NETWORK_get_fd (dnsout),
793                      (struct sockaddr *) &addr, &addrlen);
794
795   dnsoutport = htons (addr.sin_port);
796
797   GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout,
798                                  &read_response, NULL);
799 }
800
801 /**
802  * Read a response-packet of the UDP-Socket
803  */
804 static void
805 read_response (void *cls __attribute__((unused)), const struct GNUNET_SCHEDULER_TaskContext *tc)
806 {
807   struct sockaddr_in addr;
808   socklen_t addrlen = sizeof (addr);
809   int r;
810   int len;
811
812   if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
813     return;
814
815   memset (&addr, 0, sizeof addr);
816
817 #ifndef MINGW
818   if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
819     {
820       unhijack (dnsoutport);
821       open_port ();
822       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, hijack, NULL);
823       return;
824     }
825 #else
826   /* port the code above? */
827   len = 65536;
828 #endif
829   {
830     unsigned char buf[len];
831     struct dns_pkt *dns = (struct dns_pkt *) buf;
832
833     r = GNUNET_NETWORK_socket_recvfrom (dnsout,
834                                         buf,
835                                         sizeof (buf),
836                                         (struct sockaddr *) &addr, &addrlen);
837
838     if (r < 0)
839       {
840         unhijack (dnsoutport);
841         open_port ();
842         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, hijack, NULL);
843         return;
844       }
845
846     if (query_states[dns->s.id].valid == GNUNET_YES)
847       {
848         if (query_states[dns->s.id].tunnel != NULL)
849           {
850             uint32_t *c = GNUNET_malloc(4 + r);
851             *c = r;
852             memcpy(c+1, dns, r);
853             GNUNET_MESH_notify_transmit_ready (query_states[dns->s.id].tunnel,
854                                                GNUNET_YES,
855                                                32,
856                                                GNUNET_TIME_UNIT_MINUTES,
857                                                NULL, r + sizeof(struct GNUNET_MessageHeader), mesh_send_response, c);
858           }
859         else
860           {
861             query_states[dns->s.id].valid = GNUNET_NO;
862
863             size_t len = sizeof (struct answer_packet) + r - 1; /* 1 for the unsigned char data[1]; */
864             struct answer_packet_list *answer =
865               GNUNET_malloc (len + 2 * sizeof (struct answer_packet_list *));
866             answer->pkt.hdr.type =
867               htons (GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
868             answer->pkt.hdr.size = htons (len);
869             answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP;
870             answer->pkt.from = addr.sin_addr.s_addr;
871             answer->pkt.to = query_states[dns->s.id].local_ip;
872             answer->pkt.dst_port = query_states[dns->s.id].local_port;
873             memcpy (answer->pkt.data, buf, r);
874
875             GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer);
876
877             GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].
878                                                  client, len,
879                                                  GNUNET_TIME_UNIT_FOREVER_REL,
880                                                  &send_answer,
881                                                  query_states[dns->s.id].
882                                                  client);
883           }
884       }
885   }
886   GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
887                                  dnsout, &read_response, NULL);
888 }
889
890
891 /**
892  * Task run during shutdown.
893  *
894  * @param cls unused
895  * @param tc unused
896  */
897 static void
898 cleanup_task (void *cls __attribute__((unused)),
899               const struct GNUNET_SCHEDULER_TaskContext *tc)
900 {
901   GNUNET_assert(0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
902
903   unhijack(dnsoutport);
904   GNUNET_DHT_disconnect(dht);
905 }
906
907 /**
908  * @brief Create a port-map from udp and tcp redirects
909  *
910  * @param udp_redirects
911  * @param tcp_redirects
912  *
913  * @return 
914  */
915 uint64_t
916 get_port_from_redirects (const char *udp_redirects, const char *tcp_redirects)
917 {
918   uint64_t ret = 0;
919   char* cpy, *hostname, *redirect;
920   int local_port, count = 0;
921
922   if (NULL != udp_redirects)
923     {
924       cpy = GNUNET_strdup (udp_redirects);
925       for (redirect = strtok (cpy, " "); redirect != NULL; redirect = strtok (NULL, " "))
926         {
927           if (NULL == (hostname = strstr (redirect, ":")))
928             {
929               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Warning: option %s is not formatted correctly!\n", redirect);
930               continue;
931             }
932           hostname[0] = '\0';
933           local_port = atoi (redirect);
934           if (!((local_port > 0) && (local_port < 65536)))
935             GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Warning: %s is not a correct port.", redirect);
936
937           ret |= (0xFFFF & htons(local_port));
938           ret <<= 16;
939           count ++;
940
941           if(count > 4)
942             {
943               ret = 0;
944               goto out;
945             }
946         }
947       GNUNET_free(cpy);
948       cpy = NULL;
949     }
950
951   if (NULL != tcp_redirects)
952     {
953       cpy = GNUNET_strdup (tcp_redirects);
954       for (redirect = strtok (cpy, " "); redirect != NULL; redirect = strtok (NULL, " "))
955         {
956           if (NULL == (hostname = strstr (redirect, ":")))
957             {
958               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Warning: option %s is not formatted correctly!\n", redirect);
959               continue;
960             }
961           hostname[0] = '\0';
962           local_port = atoi (redirect);
963           if (!((local_port > 0) && (local_port < 65536)))
964             GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Warning: %s is not a correct port.", redirect);
965
966           ret |= (0xFFFF & htons(local_port));
967           ret <<= 16;
968           count ++;
969
970           if(count > 4)
971             {
972               ret = 0;
973               goto out;
974             }
975         }
976       GNUNET_free(cpy);
977       cpy = NULL;
978     }
979
980 out:
981   if (NULL != cpy)
982     GNUNET_free(cpy);
983   return ret;
984 }
985
986 void
987 publish_name (const char *name, uint64_t ports, uint32_t service_type,
988               struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key)
989 {
990   size_t size = sizeof (struct GNUNET_DNS_Record);
991   struct GNUNET_DNS_Record data;
992   memset (&data, 0, size);
993
994   data.purpose.size =
995     htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
996   data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD;
997
998   GNUNET_CRYPTO_hash (name, strlen (name) + 1, &data.service_descriptor);
999   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n",
1000               *((unsigned long long *) &data.service_descriptor));
1001
1002   data.service_type = service_type;
1003   data.ports = ports;
1004
1005   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &data.peer);
1006
1007   data.expiration_time =
1008     GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_HOURS, 2));
1009
1010   /* Sign the block */
1011   if (GNUNET_OK != GNUNET_CRYPTO_rsa_sign (my_private_key,
1012                                            &data.purpose, &data.signature))
1013     {
1014       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n");
1015       return;
1016     }
1017
1018   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1019               "Putting with key %08x, size = %d\n",
1020               *((unsigned int *) &data.service_descriptor), size);
1021
1022   GNUNET_DHT_put (dht,
1023                   &data.service_descriptor,
1024                   DEFAULT_PUT_REPLICATION,
1025                   GNUNET_DHT_RO_NONE,
1026                   GNUNET_BLOCK_TYPE_DNS,
1027                   size,
1028                   (char *) &data,
1029                   GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS),
1030                   GNUNET_TIME_UNIT_MINUTES, NULL, NULL);
1031 }
1032
1033 /**
1034  * @brief Publishes the record defined by the section section
1035  *
1036  * @param cls closure
1037  * @param section the current section
1038  */
1039 void
1040 publish_iterate (void *cls __attribute__((unused)), const char *section)
1041 {
1042   if ((strlen(section) < 8) || (0 != strcmp (".gnunet.", section + (strlen(section) - 8))))
1043     return;
1044
1045   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Parsing dns-name %s\n", section);
1046
1047   char *udp_redirects, *tcp_redirects, *alternative_names, *alternative_name,
1048     *keyfile;
1049
1050   GNUNET_CONFIGURATION_get_value_string (cfg, section,
1051                                          "UDP_REDIRECTS", &udp_redirects);
1052   GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS",
1053                                          &tcp_redirects);
1054
1055   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD",
1056                                                             "HOSTKEY",
1057                                                             &keyfile))
1058     {
1059       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not read keyfile-value\n");
1060       if (keyfile != NULL)
1061         GNUNET_free (keyfile);
1062       return;
1063     }
1064
1065   struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key =
1066     GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1067   GNUNET_free (keyfile);
1068   GNUNET_assert (my_private_key != NULL);
1069
1070   uint64_t ports = get_port_from_redirects (udp_redirects, tcp_redirects);
1071   uint32_t service_type = 0;
1072
1073   if (NULL != udp_redirects)
1074     service_type = GNUNET_DNS_SERVICE_TYPE_UDP;
1075
1076   if (NULL != tcp_redirects)
1077     service_type |= GNUNET_DNS_SERVICE_TYPE_TCP;
1078
1079   service_type = htonl (service_type);
1080
1081
1082   publish_name (section, ports, service_type, my_private_key);
1083
1084   GNUNET_CONFIGURATION_get_value_string (cfg, section,
1085                                          "ALTERNATIVE_NAMES",
1086                                          &alternative_names);
1087   for (alternative_name = strtok (alternative_names, " ");
1088        alternative_name != NULL; alternative_name = strtok (NULL, " "))
1089     {
1090       char *altname =
1091         alloca (strlen (alternative_name) + strlen (section) + 1 + 1);
1092       strcpy (altname, alternative_name);
1093       strcpy (altname + strlen (alternative_name) + 1, section);
1094       altname[strlen (alternative_name)] = '.';
1095
1096       publish_name (altname, ports, service_type, my_private_key);
1097     }
1098
1099   GNUNET_free_non_null(alternative_names);
1100   GNUNET_CRYPTO_rsa_key_free (my_private_key);
1101   GNUNET_free_non_null (udp_redirects);
1102   GNUNET_free_non_null (tcp_redirects);
1103 }
1104
1105 /**
1106  * Publish a DNS-record in the DHT.
1107  */
1108 static void
1109 publish_names (void *cls __attribute__((unused)),
1110                const struct GNUNET_SCHEDULER_TaskContext *tc) {
1111     if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1112       return;
1113
1114     GNUNET_CONFIGURATION_iterate_sections(cfg, publish_iterate, NULL);
1115
1116     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_HOURS,
1117                                   publish_names,
1118                                   NULL);
1119 }
1120
1121 /**
1122  * @param cls closure
1123  * @param server the initialized server
1124  * @param cfg_ configuration to use
1125  */
1126 static void
1127 run (void *cls,
1128      struct GNUNET_SERVER_Handle *server,
1129      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1130 {
1131   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1132     /* callback, cls, type, size */
1133     {&receive_query, NULL, GNUNET_MESSAGE_TYPE_LOCAL_QUERY_DNS, 0},
1134     {&rehijack, NULL, GNUNET_MESSAGE_TYPE_REHIJACK,
1135      sizeof (struct GNUNET_MessageHeader)},
1136     {NULL, NULL, 0, 0}
1137   };
1138
1139   static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1140     {receive_mesh_query, GNUNET_MESSAGE_TYPE_REMOTE_QUERY_DNS, 0},
1141     {receive_mesh_answer, GNUNET_MESSAGE_TYPE_REMOTE_ANSWER_DNS, 0},
1142     {NULL, 0, 0}
1143   };
1144
1145   static GNUNET_MESH_ApplicationType *apptypes;
1146
1147   if (GNUNET_YES ==
1148       GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1149     apptypes = (GNUNET_MESH_ApplicationType[])
1150     {
1151     GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1152     GNUNET_APPLICATION_TYPE_END};
1153   else
1154   apptypes = (GNUNET_MESH_ApplicationType[])
1155   {
1156   GNUNET_APPLICATION_TYPE_END};
1157
1158   mesh_handle =
1159     GNUNET_MESH_connect (cfg_, NULL, NULL, mesh_handlers, apptypes);
1160
1161   cfg = cfg_;
1162
1163   unsigned int i;
1164   for (i = 0; i < 65536; i++)
1165     {
1166       query_states[i].valid = GNUNET_NO;
1167     }
1168
1169   dht = GNUNET_DHT_connect (cfg, 1024);
1170
1171   open_port ();
1172
1173   GNUNET_SCHEDULER_add_now (publish_names, NULL);
1174
1175   GNUNET_SERVER_add_handlers (server, handlers);
1176   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1177                                 &cleanup_task, cls);
1178 }
1179
1180 /**
1181  * The main function for the dns service.
1182  *
1183  * @param argc number of arguments from the command line
1184  * @param argv command line arguments
1185  * @return 0 ok, 1 on error
1186  */
1187 int
1188 main (int argc, char *const *argv)
1189 {
1190   return (GNUNET_OK ==
1191           GNUNET_SERVICE_run (argc,
1192                               argv,
1193                               "dns",
1194                               GNUNET_SERVICE_OPTION_NONE,
1195                               &run, NULL)) ? 0 : 1;
1196 }