authentication of ciphertexts (+ seed)
[oweals/gnunet.git] / src / vpn / gnunet-service-dns.c
index f3566f84215b236a653bcb242c26cb28a2d02c0c..7880bf22e55602bc9d2c3ae520953e70486f55dd 100644 (file)
@@ -31,9 +31,7 @@
 #include "gnunet_protocols.h"
 #include "gnunet-vpn-packet.h"
 #include "gnunet-vpn-pretty-print.h"
-
-#define WE_DO_THIS_TO_GET_THE_PORT_WE_BOUND_TO_IN_ORDER_TO_HIJACK_EVERYTHING_BUT_THIS_PORT 1
-#define WHY_ON_EARTH_DO_WE_DO_THIS WE_DO_THIS_TO_GET_THE_PORT_WE_BOUND_TO_IN_ORDER_TO_HIJACK_EVERYTHING_BUT_THIS_PORT
+#include "gnunet_container_lib.h"
 
 struct dns_cls {
        struct GNUNET_SCHEDULER_Handle *sched;
@@ -41,10 +39,20 @@ 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];
 
@@ -63,16 +71,88 @@ void unhijack(unsigned short port) {
 
 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, "Of length %d\n", ntohs(pkt->hdr.size));
+       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;
 
-       pkt_printf_dns(dns);
+       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.
  *
@@ -103,6 +183,14 @@ run (void *cls,
     {&receive_query, NULL, GNUNET_MESSAGE_TYPE_LOCAL_QUERY_DNS, 0},
     {NULL, NULL, 0, 0}
   };
+
+  {
+  int i;
+  for (i = 0; i < 65536; i++) {
+    query_states[i].valid = 0;
+  }
+  }
+
   struct sockaddr_in addr;
 
   mycls.sched = sched;
@@ -119,17 +207,17 @@ run (void *cls,
        GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not bind a port, exiting\n");
        return;
   }
-#if WHY_ON_EARTH_DO_WE_DO_THIS
   socklen_t addrlen = sizeof(struct sockaddr_in);
   err = getsockname(GNUNET_NETWORK_get_fd(mycls.dnsout),
                    (struct sockaddr*) &addr, 
                    &addrlen);
-#endif
 
   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,
@@ -150,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;
 }