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