assert
[oweals/gnunet.git] / src / vpn / gnunet-service-dns.c
index 3e69f86603da234bc22a5aad3c9ebe292e1490df..02dc16494f78e12bea29117ef9f39f1345f8124f 100644 (file)
 #include "gnunet_crypto_lib.h"
 #include "gnunet_signatures.h"
 
-/**
- * The scheduler to use throughout the service
- */
-static struct GNUNET_SCHEDULER_Handle *sched;
-
 /**
  * The UDP-Socket through which DNS-Resolves will be sent if they are not to be
  * sent through gnunet. The port of this socket will not be hijacked.
@@ -166,6 +161,81 @@ send_answer(void* cls, size_t size, void* buf) {
     return len;
 }
 
+static void
+send_rev_query(void * cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
+    struct dns_pkt_parsed* pdns = (struct dns_pkt_parsed*) cls;
+
+    unsigned short id = pdns->s.id;
+
+    if (query_states[id].valid != GNUNET_YES) return;
+    query_states[id].valid = GNUNET_NO;
+
+    GNUNET_assert(query_states[id].namelen == 74);
+
+    size_t len = sizeof(struct answer_packet) - 1 \
+                + sizeof(struct dns_static) \
+                + 74 /* this is the length of a reverse ipv6-lookup */ \
+                + sizeof(struct dns_query_line) \
+                + 2 /* To hold the pointer (as defined in RFC1035) to the name */ \
+                + sizeof(struct dns_record_line) - 1 \
+                - 2 /* We do not know the lenght of the answer yet*/ \
+                - 2 /* No idea why... */ ;
+
+    struct answer_packet_list* answer = GNUNET_malloc(len + 2*sizeof(struct answer_packet_list*));
+    memset(answer, 0, len + 2*sizeof(struct answer_packet_list*));
+
+    answer->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS);
+    answer->pkt.hdr.size = htons(len);
+    answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REV;
+
+    answer->pkt.from = query_states[id].remote_ip;
+
+    answer->pkt.to = query_states[id].local_ip;
+    answer->pkt.dst_port = query_states[id].local_port;
+
+    struct dns_pkt *dpkt = (struct dns_pkt*)answer->pkt.data;
+
+    dpkt->s.id = id;
+    dpkt->s.aa = 1;
+    dpkt->s.qr = 1;
+    dpkt->s.ra = 1;
+    dpkt->s.qdcount = htons(1);
+    dpkt->s.ancount = htons(1);
+
+    memcpy(dpkt->data, query_states[id].name, query_states[id].namelen);
+    GNUNET_free(query_states[id].name);
+
+    struct dns_query_line* dque = (struct dns_query_line*)(dpkt->data+(query_states[id].namelen));
+    dque->type = htons(12); /* PTR */
+    dque->class = htons(1); /* IN */
+
+    char* anname = (char*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line));
+    memcpy(anname, (char[]){0xc0, 0x0c}, 2);
+
+    struct dns_record_line *drec_data = (struct dns_record_line*)(dpkt->data+(query_states[id].namelen)+sizeof(struct dns_query_line)+2);
+    drec_data->type = htons(12); /* AAAA */
+    drec_data->class = htons(1); /* IN */
+    drec_data->ttl = htonl(3600); /* FIXME: read from block */
+
+    /* Calculate at which offset in the packet the length of the name and the
+     * name, it is filled in by the daemon-vpn */
+    answer->pkt.addroffset = htons((unsigned short)((unsigned long)(&drec_data->data_len)-(unsigned long)(&answer->pkt)));
+
+    GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, answer);
+
+    GNUNET_SERVER_notify_transmit_ready(query_states[id].client,
+                                       len,
+                                       GNUNET_TIME_UNIT_FOREVER_REL,
+                                       &send_answer,
+                                       query_states[id].client);
+
+    /*
+     * build
+     * complete dns-packet with empty name in the answer
+     * provide offsett of the name
+     */
+}
+
 /**
  * Receive a block from the dht.
  */
@@ -213,15 +283,15 @@ receive_dht(void *cls,
 
     GNUNET_CRYPTO_hash(&rec->peer,
                       sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                      &answer->pkt.peer);
+                      &answer->pkt.service_descr.peer);
 
-    memcpy(&answer->pkt.service_descriptor,
+    memcpy(&answer->pkt.service_descr.service_descriptor,
           &rec->service_descriptor,
           sizeof(GNUNET_HashCode));
-    memcpy(&answer->pkt.service_type,
+    memcpy(&answer->pkt.service_descr.service_type,
           &rec->service_type,
-          sizeof(answer->pkt.service_type));
-    memcpy(&answer->pkt.ports, &rec->ports, sizeof(answer->pkt.ports));
+          sizeof(answer->pkt.service_descr.service_type));
+    memcpy(&answer->pkt.service_descr.ports, &rec->ports, sizeof(answer->pkt.service_descr.ports));
 
     answer->pkt.from = query_states[id].remote_ip;
 
@@ -240,7 +310,6 @@ receive_dht(void *cls,
     memcpy(dpkt->data, query_states[id].name, query_states[id].namelen);
     GNUNET_free(query_states[id].name);
 
-
     struct dns_query_line* dque = (struct dns_query_line*)(dpkt->data+(query_states[id].namelen));
     dque->type = htons(28); /* AAAA */
     dque->class = htons(1); /* IN */
@@ -277,7 +346,7 @@ rehijack(void *cls,
         struct GNUNET_SERVER_Client *client,
         const struct GNUNET_MessageHeader *message) {
     unhijack(dnsoutport);
-    GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_UNIT_SECONDS, hijack, NULL);
+    GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS, hijack, NULL);
 
     GNUNET_SERVER_receive_done(client, GNUNET_OK);
 }
@@ -302,6 +371,7 @@ receive_query(void *cls,
     query_states[dns->s.id].name = GNUNET_malloc(query_states[dns->s.id].namelen);
     memcpy(query_states[dns->s.id].name, dns->data, query_states[dns->s.id].namelen);
 
+    /* The query is for a .gnunet-address */
     if (pdns->queries[0]->namelen > 9 &&
        0 == strncmp(pdns->queries[0]->name+(pdns->queries[0]->namelen - 9), ".gnunet.", 9))
       {
@@ -321,6 +391,7 @@ receive_query(void *cls,
                                           GNUNET_TIME_UNIT_MINUTES,
                                           GNUNET_BLOCK_TYPE_DNS,
                                           &key,
+                                          DEFAULT_GET_REPLICATION,
                                           GNUNET_DHT_RO_NONE,
                                           NULL,
                                           0,
@@ -329,6 +400,18 @@ receive_query(void *cls,
                                           receive_dht,
                                           cls);
 
+       goto outfree;
+      }
+
+    /* The query is for a PTR of a previosly resolved virtual IP */
+    if (htons(pdns->queries[0]->qtype) == 12 &&
+       pdns->queries[0]->namelen > 19 &&
+       0 == strncmp(pdns->queries[0]->name+(pdns->queries[0]->namelen - 19), ".4.3.2.1.ip6.arpa.", 19))
+      {
+       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Reverse-Query for .gnunet!\n");
+
+       GNUNET_SCHEDULER_add_now(send_rev_query, pdns);
+
        goto out;
       }
 
@@ -345,9 +428,10 @@ receive_query(void *cls,
                                 (struct sockaddr*) &dest,
                                 sizeof dest);
 
-out:
+outfree:
     free_parsed_dns_packet(pdns);
     pdns = NULL;
+out:
     GNUNET_SERVER_receive_done(client, GNUNET_OK);
 }
 
@@ -364,7 +448,7 @@ read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
 
     struct sockaddr_in addr;
     memset(&addr, 0, sizeof addr);
-    unsigned int addrlen = sizeof addr;
+    socklen_t addrlen = sizeof addr;
 
     int r;
     r = GNUNET_NETWORK_socket_recvfrom(dnsout,
@@ -397,8 +481,7 @@ read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
                                            query_states[dns->s.id].client);
     }
 
-    GNUNET_SCHEDULER_add_read_net(sched,
-                                 GNUNET_TIME_UNIT_FOREVER_REL,
+    GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL,
                                  dnsout,
                                  &read_response,
                                  NULL);
@@ -438,6 +521,9 @@ publish_name (void *cls,
 
     GNUNET_CRYPTO_hash(name, strlen(name)+1, &data.service_descriptor);
 
+    data.service_type = htonl(GNUNET_DNS_SERVICE_TYPE_UDP);
+    data.ports = htons(69);
+
     char* keyfile;
     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename(cfg, "GNUNETD",
                                                             "HOSTKEY", &keyfile))
@@ -470,6 +556,7 @@ publish_name (void *cls,
 
     GNUNET_DHT_put(dht,
                   &data.service_descriptor,
+                  DEFAULT_PUT_REPLICATION,
                   GNUNET_DHT_RO_NONE,
                   GNUNET_BLOCK_TYPE_DNS,
                   size,
@@ -479,8 +566,7 @@ publish_name (void *cls,
                   NULL,
                   NULL);
 
-    GNUNET_SCHEDULER_add_delayed (sched,
-                                 GNUNET_TIME_UNIT_HOURS,
+    GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_HOURS,
                                  publish_name,
                                  NULL);
 }
@@ -493,7 +579,6 @@ publish_name (void *cls,
  */
 static void
 run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *sched_,
      struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *cfg_)
 {
@@ -505,14 +590,13 @@ run (void *cls,
   };
 
   cfg = cfg_;
-  sched = sched_;
 
   unsigned int i;
   for (i = 0; i < 65536; i++) {
       query_states[i].valid = GNUNET_NO;
   }
 
-  dht = GNUNET_DHT_connect(sched, cfg, 1024);
+  dht = GNUNET_DHT_connect(cfg, 1024);
 
   struct sockaddr_in addr;
 
@@ -538,13 +622,12 @@ run (void *cls,
 
   dnsoutport = htons(addr.sin_port);
 
-  GNUNET_SCHEDULER_add_now (sched, publish_name, NULL);
+  GNUNET_SCHEDULER_add_now (publish_name, NULL);
 
-  GNUNET_SCHEDULER_add_read_net(sched, GNUNET_TIME_UNIT_FOREVER_REL, dnsout, &read_response, NULL);
+  GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL, dnsout, &read_response, NULL);
 
   GNUNET_SERVER_add_handlers (server, handlers);
-  GNUNET_SCHEDULER_add_delayed (sched,
-                               GNUNET_TIME_UNIT_FOREVER_REL,
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
                                &cleanup_task,
                                cls);
 }