fix mem-leaks and other nasty stuff
[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-vpn-packet.h"
33 #include "gnunet-vpn-pretty-print.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_signatures.h"
41
42 /**
43  * The UDP-Socket through which DNS-Resolves will be sent if they are not to be
44  * sent through gnunet. The port of this socket will not be hijacked.
45  */
46 static struct GNUNET_NETWORK_Handle *dnsout;
47
48 /**
49  * The port bound to the socket dnsout
50  */
51 static unsigned short dnsoutport;
52
53 /**
54  * A handle to the DHT-Service
55  */
56 static struct GNUNET_DHT_Handle *dht;
57
58 /**
59  * The configuration to use
60  */
61 static const struct GNUNET_CONFIGURATION_Handle *cfg;
62
63 /**
64  * A list of DNS-Responses that have to be sent to the requesting client
65  */
66 static struct answer_packet_list *head;
67
68 /**
69  * The tail of the list of DNS-responses
70  */
71 static struct answer_packet_list *tail;
72
73 /**
74  * A structure containing a mapping from network-byte-ordered DNS-id to
75  * some information needed to handle this query
76  *
77  * It currently allocates at least
78  * (1 + machine-width + 32 + 32 + 16 + machine-width + 8) * 65536 bit
79  * = 1.7 MiB on 64 bit.
80  * = 1.2 MiB on 32 bit.
81  */
82 static struct {
83     unsigned valid:1;
84     struct GNUNET_SERVER_Client* client;
85     unsigned local_ip:32;
86     unsigned remote_ip:32;
87     unsigned local_port:16;
88     char* name;
89     unsigned namelen:8;
90 } query_states[65536];
91
92 /**
93  * A struct used to give more than one value as
94  * closure to receive_dht
95  */
96 struct receive_dht_cls {
97     unsigned short id;
98     struct GNUNET_DHT_GetHandle* handle;
99 };
100
101 /**
102  * Hijack all outgoing DNS-Traffic but for traffic leaving "our" port.
103  */
104 static void
105 hijack (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
106 {
107   char port_s[6];
108   char *virt_dns;
109   struct GNUNET_OS_Process *proc;
110
111   if (GNUNET_SYSERR ==
112       GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS",
113                                              &virt_dns))
114     {
115       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116                   "No entry 'VIRTDNS' in configuration!\n");
117       exit (1);
118     }
119
120   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacking, port is %d\n", dnsoutport);
121   snprintf (port_s, 6, "%d", dnsoutport);
122   if (NULL != (proc = GNUNET_OS_start_process (NULL,
123                                                NULL,
124                                                "gnunet-helper-hijack-dns",
125                                                "gnunet-hijack-dns",
126                                                port_s, virt_dns, NULL)))
127     GNUNET_OS_process_close (proc);
128   GNUNET_free (virt_dns);
129 }
130
131 /**
132  * Delete the hijacking-routes
133  */
134 static void
135 unhijack (unsigned short port)
136 {
137   char port_s[6];
138   char *virt_dns;
139   struct GNUNET_OS_Process *proc;
140
141   if (GNUNET_SYSERR ==
142       GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS",
143                                              &virt_dns))
144     {
145       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
146                   "No entry 'VIRTDNS' in configuration!\n");
147       exit (1);
148     }
149
150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unHijacking, port is %d\n", port);
151   snprintf (port_s, 6, "%d", port);
152   if (NULL != (proc = GNUNET_OS_start_process (NULL,
153                                                NULL,
154                                                "gnunet-helper-hijack-dns",
155                                                "gnunet-hijack-dns",
156                                                "-d", port_s, virt_dns, NULL)))
157     GNUNET_OS_process_close (proc);
158   GNUNET_free (virt_dns);
159 }
160
161 /**
162  * Send the DNS-Response to the client. Gets called via the notify_transmit_ready-
163  * system.
164  */
165 static size_t
166 send_answer(void* cls, size_t size, void* buf) {
167     struct answer_packet_list* query = head;
168     size_t len = ntohs(query->pkt.hdr.size);
169
170     GNUNET_assert(len <= size);
171
172     memcpy(buf, &query->pkt.hdr, len);
173
174     GNUNET_CONTAINER_DLL_remove (head, tail, query);
175
176     GNUNET_free(query);
177
178     /* When more data is to be sent, reschedule */
179     if (head != NULL)
180       GNUNET_SERVER_notify_transmit_ready(cls,
181                                           ntohs(head->pkt.hdr.size),
182                                           GNUNET_TIME_UNIT_FOREVER_REL,
183                                           &send_answer,
184                                           cls);
185
186     return len;
187 }
188
189 static void
190 send_rev_query(void * cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
191     struct dns_pkt_parsed* pdns = (struct dns_pkt_parsed*) cls;
192
193     unsigned short id = pdns->s.id;
194
195     if (query_states[id].valid != GNUNET_YES) return;
196     query_states[id].valid = GNUNET_NO;
197
198     GNUNET_assert(query_states[id].namelen == 74);
199
200     size_t len = sizeof(struct answer_packet) - 1 \
201                  + sizeof(struct dns_static) \
202                  + 74 /* this is the length of a reverse ipv6-lookup */ \
203                  + sizeof(struct dns_query_line) \
204                  + 2 /* To hold the pointer (as defined in RFC1035) to the name */ \
205                  + sizeof(struct dns_record_line) - 1 \
206                  - 2 /* We do not know the lenght of the answer yet*/ \
207                  - 2 /* No idea why... */ ;
208
209     struct answer_packet_list* answer = GNUNET_malloc(len + 2*sizeof(struct answer_packet_list*));
210     memset(answer, 0, len + 2*sizeof(struct answer_packet_list*));
211
212     answer->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
213     answer->pkt.hdr.size = htons(len);
214     answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REV;
215
216     answer->pkt.from = query_states[id].remote_ip;
217
218     answer->pkt.to = query_states[id].local_ip;
219     answer->pkt.dst_port = query_states[id].local_port;
220
221     struct dns_pkt *dpkt = (struct dns_pkt*)answer->pkt.data;
222
223     dpkt->s.id = id;
224     dpkt->s.aa = 1;
225     dpkt->s.qr = 1;
226     dpkt->s.ra = 1;
227     dpkt->s.qdcount = htons(1);
228     dpkt->s.ancount = htons(1);
229
230     memcpy(dpkt->data, query_states[id].name, query_states[id].namelen);
231     GNUNET_free(query_states[id].name);
232
233     struct dns_query_line* dque = (struct dns_query_line*)(dpkt->data+(query_states[id].namelen));
234     dque->type = htons(12); /* PTR */
235     dque->class = htons(1); /* IN */
236
237     char* anname = (char*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line));
238     memcpy(anname, (char[]){0xc0, 0x0c}, 2);
239
240     struct dns_record_line *drec_data = (struct dns_record_line*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line)+2);
241     drec_data->type = htons(12); /* AAAA */
242     drec_data->class = htons(1); /* IN */
243     drec_data->ttl = htonl(3600); /* FIXME: read from block */
244
245     /* Calculate at which offset in the packet the length of the name and the
246      * name, it is filled in by the daemon-vpn */
247     answer->pkt.addroffset = htons((unsigned short)((unsigned long)(&drec_data->data_len)-(unsigned long)(&answer->pkt)));
248
249     GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, answer);
250
251     GNUNET_SERVER_notify_transmit_ready(query_states[id].client,
252                                         len,
253                                         GNUNET_TIME_UNIT_FOREVER_REL,
254                                         &send_answer,
255                                         query_states[id].client);
256
257     /*
258      * build
259      * complete dns-packet with empty name in the answer
260      * provide offsett of the name
261      */
262 }
263
264 /**
265  * Receive a block from the dht.
266  */
267 static void
268 receive_dht(void *cls,
269             struct GNUNET_TIME_Absolute exp,
270             const GNUNET_HashCode *key,
271             const struct GNUNET_PeerIdentity *const *get_path,
272             const struct GNUNET_PeerIdentity *const *put_path,
273             enum GNUNET_BLOCK_Type type,
274             size_t size,
275             const void *data) {
276
277     unsigned short id = ((struct receive_dht_cls*)cls)->id;
278     struct GNUNET_DHT_GetHandle* handle = ((struct receive_dht_cls*)cls)->handle;
279     GNUNET_free(cls);
280
281     GNUNET_assert(type == GNUNET_BLOCK_TYPE_DNS);
282
283     /* If no query with this id is pending, ignore the block */
284     if (query_states[id].valid != GNUNET_YES) return;
285     query_states[id].valid = GNUNET_NO;
286
287     const struct GNUNET_DNS_Record* rec = data;
288     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
289                "Got block of size %d, peer: %08x, desc: %08x\n",
290                size,
291                *((unsigned int*)&rec->peer),
292                *((unsigned int*)&rec->service_descriptor));
293
294     size_t len = sizeof(struct answer_packet) - 1 \
295                  + sizeof(struct dns_static) \
296                  + query_states[id].namelen \
297                  + sizeof(struct dns_query_line) \
298                  + 2 /* To hold the pointer (as defined in RFC1035) to the name */ \
299                  + sizeof(struct dns_record_line) - 1 \
300                  + 16; /* To hold the IPv6-Address */
301
302     struct answer_packet_list* answer = GNUNET_malloc(len + 2*sizeof(struct answer_packet_list*));
303     memset(answer, 0, len + 2*sizeof(struct answer_packet_list*));
304
305     answer->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
306     answer->pkt.hdr.size = htons(len);
307     answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_SERVICE;
308
309     GNUNET_CRYPTO_hash(&rec->peer,
310                        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
311                        &answer->pkt.service_descr.peer);
312
313     memcpy(&answer->pkt.service_descr.service_descriptor,
314            &rec->service_descriptor,
315            sizeof(GNUNET_HashCode));
316     memcpy(&answer->pkt.service_descr.service_type,
317            &rec->service_type,
318            sizeof(answer->pkt.service_descr.service_type));
319     memcpy(&answer->pkt.service_descr.ports, &rec->ports, sizeof(answer->pkt.service_descr.ports));
320
321     answer->pkt.from = query_states[id].remote_ip;
322
323     answer->pkt.to = query_states[id].local_ip;
324     answer->pkt.dst_port = query_states[id].local_port;
325
326     struct dns_pkt *dpkt = (struct dns_pkt*)answer->pkt.data;
327
328     dpkt->s.id = id;
329     dpkt->s.aa = 1;
330     dpkt->s.qr = 1;
331     dpkt->s.ra = 1;
332     dpkt->s.qdcount = htons(1);
333     dpkt->s.ancount = htons(1);
334
335     memcpy(dpkt->data, query_states[id].name, query_states[id].namelen);
336     GNUNET_free(query_states[id].name);
337
338     struct dns_query_line* dque = (struct dns_query_line*)(dpkt->data+(query_states[id].namelen));
339     dque->type = htons(28); /* AAAA */
340     dque->class = htons(1); /* IN */
341
342     char* anname = (char*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line));
343     memcpy(anname, (char[]){0xc0, 0x0c}, 2);
344
345     struct dns_record_line *drec_data = (struct dns_record_line*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line)+2);
346     drec_data->type = htons(28); /* AAAA */
347     drec_data->class = htons(1); /* IN */
348     drec_data->ttl = htonl(3600); /* FIXME: read from block */
349     drec_data->data_len = htons(16);
350
351     /* Calculate at which offset in the packet the IPv6-Address belongs, it is
352      * filled in by the daemon-vpn */
353     answer->pkt.addroffset = htons((unsigned short)((unsigned long)(&drec_data->data)-(unsigned long)(&answer->pkt)));
354
355     GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, answer);
356
357     GNUNET_SERVER_notify_transmit_ready(query_states[id].client,
358                                         len,
359                                         GNUNET_TIME_UNIT_FOREVER_REL,
360                                         &send_answer,
361                                         query_states[id].client);
362
363     GNUNET_DHT_get_stop(handle);
364 }
365
366 /**
367  * This receives a GNUNET_MESSAGE_TYPE_REHIJACK and rehijacks the DNS
368  */
369 static void
370 rehijack(void *cls,
371          struct GNUNET_SERVER_Client *client,
372          const struct GNUNET_MessageHeader *message) {
373     unhijack(dnsoutport);
374     GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS, hijack, NULL);
375
376     GNUNET_SERVER_receive_done(client, GNUNET_OK);
377 }
378
379 /**
380  * This receives the dns-payload from the daemon-vpn and sends it on over the udp-socket
381  */
382 static void
383 receive_query(void *cls,
384               struct GNUNET_SERVER_Client *client,
385               const struct GNUNET_MessageHeader *message) {
386     struct query_packet* pkt = (struct query_packet*)message;
387     struct dns_pkt* dns = (struct dns_pkt*)pkt->data;
388     struct dns_pkt_parsed* pdns = parse_dns_packet(dns);
389
390     query_states[dns->s.id].valid = GNUNET_YES;
391     query_states[dns->s.id].client = client;
392     query_states[dns->s.id].local_ip = pkt->orig_from;
393     query_states[dns->s.id].local_port = pkt->src_port;
394     query_states[dns->s.id].remote_ip = pkt->orig_to;
395     query_states[dns->s.id].namelen = strlen((char*)dns->data) + 1;
396     query_states[dns->s.id].name = GNUNET_malloc(query_states[dns->s.id].namelen);
397     memcpy(query_states[dns->s.id].name, dns->data, query_states[dns->s.id].namelen);
398
399     /* The query is for a .gnunet-address */
400     if (pdns->queries[0]->namelen > 9 &&
401         0 == strncmp(pdns->queries[0]->name+(pdns->queries[0]->namelen - 9), ".gnunet.", 9))
402       {
403         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Query for .gnunet!\n");
404         GNUNET_HashCode key;
405         GNUNET_CRYPTO_hash(pdns->queries[0]->name, pdns->queries[0]->namelen, &key);
406
407         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
408                    "Getting with key %08x, len is %d\n",
409                    *((unsigned int*)&key),
410                    pdns->queries[0]->namelen);
411
412         struct receive_dht_cls* cls = GNUNET_malloc(sizeof(struct receive_dht_cls));
413         cls->id = dns->s.id;
414
415         cls->handle = GNUNET_DHT_get_start(dht,
416                                            GNUNET_TIME_UNIT_MINUTES,
417                                            GNUNET_BLOCK_TYPE_DNS,
418                                            &key,
419                                            DEFAULT_GET_REPLICATION,
420                                            GNUNET_DHT_RO_NONE,
421                                            NULL,
422                                            0,
423                                            NULL,
424                                            0,
425                                            receive_dht,
426                                            cls);
427
428         goto outfree;
429       }
430
431     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Query for '%s'; namelen=%d\n", pdns->queries[0]->name, pdns->queries[0]->namelen);
432     /* The query is for a PTR of a previosly resolved virtual IP */
433     if (htons(pdns->queries[0]->qtype) == 12 &&
434         74 == pdns->queries[0]->namelen)
435       {
436         char* ipv6addr;
437         char ipv6[16];
438         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.";
439         unsigned int i;
440         unsigned long long ipv6prefix;
441         unsigned int comparelen;
442
443         GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "vpn", "IPV6ADDR", &ipv6addr));
444         inet_pton (AF_INET6, ipv6addr, ipv6);
445         GNUNET_free(ipv6addr);
446
447         GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "vpn", "IPV6PREFIX", &ipv6prefix));
448         GNUNET_assert(ipv6prefix < 127);
449         ipv6prefix = (ipv6prefix + 7)/8;
450
451         for (i = ipv6prefix; i < 16; i++)
452           ipv6[i] = 0;
453
454         for (i = 0; i < 16; i++)
455           {
456             unsigned char c1 = ipv6[i] >> 4;
457             unsigned char c2 = ipv6[i] & 0xf;
458
459             if (c1 <= 9)
460               ipv6rev[62-(4*i)] = c1 + '0';
461             else
462               ipv6rev[62-(4*i)] = c1 + 87; /* 87 is the difference between 'a' and 10 */
463
464             if (c2 <= 9)
465               ipv6rev[62-((4*i)+2)] = c2 + '0';
466             else
467               ipv6rev[62-((4*i)+2)] = c2 + 87;
468           }
469         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "My network is %s'.\n", ipv6rev);
470         comparelen = 10 + 4*ipv6prefix;
471         if(0 == strncmp(pdns->queries[0]->name+(pdns->queries[0]->namelen - comparelen),
472                         ipv6rev + (74 - comparelen),
473                         comparelen))
474           {
475             GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Reverse-Query for .gnunet!\n");
476
477             GNUNET_SCHEDULER_add_now(send_rev_query, pdns);
478
479             goto out;
480           }
481       }
482
483     /* The query should be sent to the network */
484
485     struct sockaddr_in dest;
486     memset(&dest, 0, sizeof dest);
487     dest.sin_port = htons(53);
488     dest.sin_addr.s_addr = pkt->orig_to;
489
490     GNUNET_NETWORK_socket_sendto(dnsout,
491                                  dns,
492                                  ntohs(pkt->hdr.size) - sizeof(struct query_packet) + 1,
493                                  (struct sockaddr*) &dest,
494                                  sizeof dest);
495
496 outfree:
497     free_parsed_dns_packet(pdns);
498     pdns = NULL;
499 out:
500     GNUNET_SERVER_receive_done(client, GNUNET_OK);
501 }
502
503 /**
504  * Read a response-packet of the UDP-Socket
505  */
506 static void
507 read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
508     unsigned char buf[65536];
509     struct dns_pkt* dns = (struct dns_pkt*)buf;
510
511     if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
512       return;
513
514     struct sockaddr_in addr;
515     memset(&addr, 0, sizeof addr);
516     socklen_t addrlen = sizeof addr;
517
518     int r;
519     r = GNUNET_NETWORK_socket_recvfrom(dnsout,
520                                        buf,
521                                        65536,
522                                        (struct sockaddr*)&addr,
523                                        &addrlen);
524
525     /* if (r < 0) FIXME */
526
527     if (query_states[dns->s.id].valid == GNUNET_YES) {
528         query_states[dns->s.id].valid = GNUNET_NO;
529
530         size_t len = sizeof(struct answer_packet) + r - 1; /* 1 for the unsigned char data[1]; */
531         struct answer_packet_list* answer = GNUNET_malloc(len + 2*sizeof(struct answer_packet_list*));
532         answer->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
533         answer->pkt.hdr.size = htons(len);
534         answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP;
535         answer->pkt.from = addr.sin_addr.s_addr;
536         answer->pkt.to = query_states[dns->s.id].local_ip;
537         answer->pkt.dst_port = query_states[dns->s.id].local_port;
538         memcpy(answer->pkt.data, buf, r);
539
540         GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, answer);
541
542         GNUNET_SERVER_notify_transmit_ready(query_states[dns->s.id].client,
543                                             len,
544                                             GNUNET_TIME_UNIT_FOREVER_REL,
545                                             &send_answer,
546                                             query_states[dns->s.id].client);
547     }
548
549     GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL,
550                                   dnsout,
551                                   &read_response,
552                                   NULL);
553 }
554
555
556 /**
557  * Task run during shutdown.
558  *
559  * @param cls unused
560  * @param tc unused
561  */
562 static void
563 cleanup_task (void *cls,
564               const struct GNUNET_SCHEDULER_TaskContext *tc)
565 {
566   unhijack(dnsoutport);
567   GNUNET_DHT_disconnect(dht);
568 }
569
570 /**
571  * Publish a DNS-record in the DHT. This is up to now just for testing.
572  */
573 static void
574 publish_name (void *cls,
575               const struct GNUNET_SCHEDULER_TaskContext *tc) {
576     if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
577       return;
578
579     char* name = "philipptoelke.gnunet.";
580     size_t size = sizeof(struct GNUNET_DNS_Record);
581     struct GNUNET_DNS_Record data;
582     memset(&data, 0, size);
583
584     data.purpose.size = htonl(size - sizeof(struct GNUNET_CRYPTO_RsaSignature));
585     data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD;
586
587     GNUNET_CRYPTO_hash(name, strlen(name)+1, &data.service_descriptor);
588     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n", *((unsigned long long*)&data.service_descriptor));
589
590     data.service_type = htonl(GNUNET_DNS_SERVICE_TYPE_UDP);
591     data.ports = htons(69);
592
593     char* keyfile;
594     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename(cfg, "GNUNETD",
595                                                              "HOSTKEY", &keyfile))
596       {
597         GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "could not read keyfile-value\n");
598         if (keyfile != NULL) GNUNET_free(keyfile);
599         return;
600       }
601
602     struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file(keyfile);
603     GNUNET_free(keyfile);
604     GNUNET_assert(my_private_key != NULL);
605
606     GNUNET_CRYPTO_rsa_key_get_public(my_private_key, &data.peer);
607
608     data.expiration_time = GNUNET_TIME_relative_to_absolute(GNUNET_TIME_UNIT_HOURS);
609
610   /* Sign the block */
611     if (GNUNET_OK != GNUNET_CRYPTO_rsa_sign(my_private_key,
612                                             &data.purpose,
613                                             &data.signature))
614       {
615         GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n");
616         return;
617       }
618     GNUNET_CRYPTO_rsa_key_free(my_private_key);
619
620     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
621                "Putting with key %08x, size = %d\n",
622                *((unsigned int*)&data.service_descriptor),
623                size);
624
625     GNUNET_DHT_put(dht,
626                    &data.service_descriptor,
627                    DEFAULT_PUT_REPLICATION,
628                    GNUNET_DHT_RO_NONE,
629                    GNUNET_BLOCK_TYPE_DNS,
630                    size,
631                    (char*)&data,
632                    GNUNET_TIME_relative_to_absolute(GNUNET_TIME_UNIT_HOURS),
633                    GNUNET_TIME_UNIT_MINUTES,
634                    NULL,
635                    NULL);
636
637     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_HOURS,
638                                   publish_name,
639                                   NULL);
640 }
641
642 /**
643  * @param cls closure
644  * @param server the initialized server
645  * @param cfg_ configuration to use
646  */
647 static void
648 run (void *cls,
649      struct GNUNET_SERVER_Handle *server,
650      const struct GNUNET_CONFIGURATION_Handle *cfg_)
651 {
652   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
653       /* callback, cls, type, size */
654         {&receive_query, NULL, GNUNET_MESSAGE_TYPE_LOCAL_QUERY_DNS, 0},
655         {&rehijack, NULL, GNUNET_MESSAGE_TYPE_REHIJACK, sizeof(struct GNUNET_MessageHeader)},
656         {NULL, NULL, 0, 0}
657   };
658
659   cfg = cfg_;
660
661   unsigned int i;
662   for (i = 0; i < 65536; i++) {
663       query_states[i].valid = GNUNET_NO;
664   }
665
666   dht = GNUNET_DHT_connect(cfg, 1024);
667
668   struct sockaddr_in addr;
669
670   dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
671   if (dnsout == NULL)
672     return;
673   memset(&addr, 0, sizeof(struct sockaddr_in));
674
675   int err = GNUNET_NETWORK_socket_bind (dnsout,
676                                         (struct sockaddr*)&addr,
677                                         sizeof(struct sockaddr_in));
678
679   if (err != GNUNET_YES) {
680       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not bind a port, exiting\n");
681       return;
682   }
683
684   /* Read the port we bound to */
685   socklen_t addrlen = sizeof(struct sockaddr_in);
686   err = getsockname(GNUNET_NETWORK_get_fd(dnsout),
687                     (struct sockaddr*) &addr,
688                     &addrlen);
689
690   dnsoutport = htons(addr.sin_port);
691
692   GNUNET_SCHEDULER_add_now (publish_name, NULL);
693
694   GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL, dnsout, &read_response, NULL);
695
696   GNUNET_SERVER_add_handlers (server, handlers);
697   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
698                                 &cleanup_task,
699                                 cls);
700 }
701
702 /**
703  * The main function for the dns service.
704  *
705  * @param argc number of arguments from the command line
706  * @param argv command line arguments
707  * @return 0 ok, 1 on error
708  */
709 int
710 main (int argc, char *const *argv)
711 {
712   return (GNUNET_OK ==
713           GNUNET_SERVICE_run (argc,
714                               argv,
715                               "dns",
716                               GNUNET_SERVICE_OPTION_NONE,
717                               &run, NULL)) ? 0 : 1;
718 }