authentication of ciphertexts (+ seed)
[oweals/gnunet.git] / src / vpn / gnunet-service-dns.c
index 90e789010e7ab0aa59ee9420b956033ac607db1e..7880bf22e55602bc9d2c3ae520953e70486f55dd 100644 (file)
@@ -29,6 +29,9 @@
 #include "gnunet_os_lib.h"
 #include "gnunet-service-dns-p.h"
 #include "gnunet_protocols.h"
+#include "gnunet-vpn-packet.h"
+#include "gnunet-vpn-pretty-print.h"
+#include "gnunet_container_lib.h"
 
 struct dns_cls {
        struct GNUNET_SCHEDULER_Handle *sched;
@@ -36,13 +39,24 @@ struct dns_cls {
        struct GNUNET_NETWORK_Handle *dnsout;
 
        unsigned short dnsoutport;
-};
 
+       struct answer_packet_list *head;
+       struct answer_packet_list *tail;
+};
 static struct dns_cls mycls;
 
+struct dns_query_id_state {
+       unsigned valid:1;
+       struct GNUNET_SERVER_Client* client;
+       unsigned local_ip:32;
+       unsigned local_port:16;
+};
+static struct dns_query_id_state query_states[65536]; /* This is < 1MiB */
+
 void hijack(unsigned short port) {
        char port_s[6];
 
+       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Hijacking, port is %d\n", port);
        snprintf(port_s, 6, "%d", port);
        GNUNET_OS_start_process(NULL, NULL, "gnunet-helper-hijack-dns", "gnunet-hijack-dns", port_s, NULL);
 }
@@ -50,18 +64,95 @@ void hijack(unsigned short port) {
 void unhijack(unsigned short port) {
        char port_s[6];
 
+       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "unHijacking, port is %d\n", port);
        snprintf(port_s, 6, "%d", port);
        GNUNET_OS_start_process(NULL, NULL, "gnunet-helper-hijack-dns", "gnunet-hijack-dns", "-d", port_s, NULL);
 }
 
 void receive_query(void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message)
 {
-       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received query!\n");
        struct query_packet* pkt = (struct query_packet*)message;
+       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received query of length %d\n", ntohs(pkt->hdr.size));
+       struct dns_pkt* dns = (struct dns_pkt*)pkt->data;
+
+       struct sockaddr_in dest;
+       memset(&dest, 0, sizeof dest);
+       dest.sin_port = htons(53);
+       dest.sin_addr.s_addr = pkt->orig_to;
+
+       query_states[dns->id].valid = 1;
+       query_states[dns->id].client = client;
+       query_states[dns->id].local_ip = pkt->orig_from;
+       query_states[dns->id].local_port = pkt->src_port;
+
+       int r = GNUNET_NETWORK_socket_sendto(mycls.dnsout, dns, ntohs(pkt->hdr.size) - sizeof(struct query_packet) + 1, (struct sockaddr*) &dest, sizeof dest);
+       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "send %d bytes to socket\n", r);
 
        GNUNET_SERVER_receive_done(client, GNUNET_OK);
 }
 
+size_t send_answer(void* cls, size_t size, void* buf) {
+       struct answer_packet_list* query = mycls.head;
+       size_t len = ntohs(query->pkt.hdr.size);
+
+       GNUNET_assert(len <= size);
+
+       memcpy(buf, &query->pkt.hdr, len);
+
+       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes.\n", len);
+
+       GNUNET_CONTAINER_DLL_remove (mycls.head, mycls.tail, query);
+
+       GNUNET_free(query);
+
+       if (mycls.head != NULL) {
+               GNUNET_SERVER_notify_transmit_ready(cls, ntohs(mycls.head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, &send_answer, cls);
+       }
+
+       return len;
+}
+
+static void read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
+       unsigned char buf[65536];
+       struct dns_pkt* dns = (struct dns_pkt*)buf;
+
+       if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
+               return;
+
+       struct sockaddr_in addr;
+       memset(&addr, 0, sizeof addr);
+       unsigned int addrlen = sizeof addr;
+
+       int r;
+       r = GNUNET_NETWORK_socket_recvfrom(mycls.dnsout, buf, 65536, (struct sockaddr*)&addr, &addrlen);
+
+       /* if (r < 0) TODO */
+
+       if (query_states[dns->id].valid == 1) {
+               query_states[dns->id].valid = 0;
+
+               size_t len = sizeof(struct answer_packet) + r - 1; /* 1 for the unsigned char data[1]; */
+               struct answer_packet_list* answer = GNUNET_malloc(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.from = addr.sin_addr.s_addr;
+               answer->pkt.to = query_states[dns->id].local_ip;
+               answer->pkt.dst_port = query_states[dns->id].local_port;
+               memcpy(answer->pkt.data, buf, r);
+
+               GNUNET_CONTAINER_DLL_insert_after(mycls.head, mycls.tail, mycls.tail, answer);
+
+               struct GNUNET_CONNECTION_TransmitHandle* th = GNUNET_SERVER_notify_transmit_ready(query_states[dns->id].client, len, GNUNET_TIME_UNIT_FOREVER_REL, &send_answer, query_states[dns->id].client);
+               if (th != NULL)
+                       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Queued sending of %d bytes.\n", len);
+               else
+                       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Already queued for %d bytes.\n", len);
+       }
+
+       GNUNET_SCHEDULER_add_read_net(mycls.sched, GNUNET_TIME_UNIT_FOREVER_REL, mycls.dnsout, &read_response, NULL);
+}
+
+
 /**
  * Task run during shutdown.
  *
@@ -93,20 +184,40 @@ run (void *cls,
     {NULL, NULL, 0, 0}
   };
 
-  mycls.sched = sched;
-
-  mycls.dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
+  {
+  int i;
+  for (i = 0; i < 65536; i++) {
+    query_states[i].valid = 0;
+  }
+  }
 
   struct sockaddr_in addr;
+
+  mycls.sched = sched;
+  mycls.dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
+  if (mycls.dnsout == NULL) 
+    return;
   memset(&addr, 0, sizeof(struct sockaddr_in));
 
-  int err = GNUNET_NETWORK_socket_bind (mycls.dnsout, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
-  err = getsockname(GNUNET_NETWORK_get_fd(mycls.dnsout), &addr, (unsigned int[]){sizeof(struct sockaddr_in)});
+  int err = GNUNET_NETWORK_socket_bind (mycls.dnsout,
+                                       (struct sockaddr*)&addr, 
+                                       sizeof(struct sockaddr_in));
+
+  if (err != GNUNET_YES) {
+       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not bind a port, exiting\n");
+       return;
+  }
+  socklen_t addrlen = sizeof(struct sockaddr_in);
+  err = getsockname(GNUNET_NETWORK_get_fd(mycls.dnsout),
+                   (struct sockaddr*) &addr, 
+                   &addrlen);
 
   mycls.dnsoutport = htons(addr.sin_port);
 
   hijack(htons(addr.sin_port));
 
+       GNUNET_SCHEDULER_add_read_net(sched, GNUNET_TIME_UNIT_FOREVER_REL, mycls.dnsout, &read_response, NULL);
+
   GNUNET_SERVER_add_handlers (server, handlers);
   GNUNET_SCHEDULER_add_delayed (sched,
                  GNUNET_TIME_UNIT_FOREVER_REL,
@@ -127,7 +238,7 @@ main (int argc, char *const *argv)
   return (GNUNET_OK ==
           GNUNET_SERVICE_run (argc,
                               argv,
-                              "gnunet-service-dns",
+                              "dns",
                              GNUNET_SERVICE_OPTION_NONE,
                              &run, NULL)) ? 0 : 1;
 }