#include "gnunet-service-dns-p.h"
#include "gnunet_client_lib.h"
#include "gnunet_container_lib.h"
+#include "block_dns.h"
/**
* Final status code.
struct GNUNET_SCHEDULER_Handle *sched;
struct GNUNET_CLIENT_Connection *dns_connection;
+ unsigned char restart_hijack;
pid_t helper_pid;
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
struct query_packet_list *head;
struct query_packet_list *tail;
- struct answer_packet_list *answer_head;
- struct answer_packet_list *answer_tail;
+ struct answer_packet_list *answer_proc_head;
+ struct answer_packet_list *answer_proc_tail;
};
static struct vpn_cls mycls;
+size_t send_query(void* cls, size_t size, void* buf);
+
static void cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
- if (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) {
- PLIBC_KILL(mycls.helper_pid, SIGTERM);
- GNUNET_OS_process_wait(mycls.helper_pid);
- }
+ GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
+ PLIBC_KILL(mycls.helper_pid, SIGTERM);
+ GNUNET_OS_process_wait(mycls.helper_pid);
+ if (mycls.dns_connection != NULL)
+ {
+ GNUNET_CLIENT_disconnect (mycls.dns_connection, GNUNET_NO);
+ mycls.dns_connection = NULL;
+ }
}
static void helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx);
-static void start_helper_and_schedule() {
- mycls.helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);;
+static void start_helper_and_schedule(void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc) {
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ mycls.helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
mycls.helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
if (mycls.helper_in == NULL || mycls.helper_out == NULL) return;
static void restart_helper(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
- // FIXME: Ratelimit this!
-
// Kill the helper
PLIBC_KILL(mycls.helper_pid, SIGKILL);
GNUNET_OS_process_wait(mycls.helper_pid);
- // FIXME: send msg to service-dns -- the hijacker has to be started again, too, the routing table is flushed if it depends on one interface
+ /* Tell the dns-service to rehijack the dns-port
+ * The routing-table gets flushed if an interface disappears.
+ */
+ mycls.restart_hijack = 1;
+ GNUNET_CLIENT_notify_transmit_ready(mycls.dns_connection, sizeof(struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL);
GNUNET_DISK_pipe_close(mycls.helper_in);
GNUNET_DISK_pipe_close(mycls.helper_out);
// Restart the helper
- start_helper_and_schedule(mycls);
+ GNUNET_SCHEDULER_add_delayed (mycls.sched, GNUNET_TIME_UNIT_SECONDS, start_helper_and_schedule, NULL);
}
static void helper_write(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx) {
if (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
return;
- struct answer_packet_list* ans = mycls.answer_head;
+ struct answer_packet_list* ans = mycls.answer_proc_head;
size_t len = ntohs(ans->pkt.hdr.size);
+ GNUNET_assert(ans->pkt.subtype == GNUNET_DNS_ANSWER_TYPE_IP);
+
size_t data_len = len - sizeof(struct answer_packet) + 1;
size_t net_len = sizeof(struct ip_hdr) + sizeof(struct udp_dns) + data_len;
size_t pkt_len = sizeof(struct GNUNET_MessageHeader) + sizeof(struct pkt_tun) + net_len;
struct ip_udp_dns* pkt = alloca(pkt_len);
+ memset(pkt, 0, pkt_len);
pkt->shdr.size = htons(pkt_len);
pkt->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
memcpy(&pkt->udp_dns.data, ans->pkt.data, data_len);
- GNUNET_CONTAINER_DLL_remove (mycls.answer_head, mycls.answer_tail, ans);
+ GNUNET_CONTAINER_DLL_remove (mycls.answer_proc_head, mycls.answer_proc_tail, ans);
GNUNET_free(ans);
/* FIXME */ GNUNET_DISK_file_write(mycls.fh_to_helper, pkt, pkt_len);
- if (mycls.answer_head != NULL)
+ if (mycls.answer_proc_head != NULL)
GNUNET_SCHEDULER_add_write_file (mycls.sched, GNUNET_TIME_UNIT_FOREVER_REL, mycls.fh_to_helper, &helper_write, NULL);
}
size_t send_query(void* cls, size_t size, void* buf)
{
+ size_t len;
+ if (mycls.restart_hijack == 1)
+ {
+ mycls.restart_hijack = 0;
+ GNUNET_assert(sizeof(struct GNUNET_MessageHeader) >= size);
+ struct GNUNET_MessageHeader* hdr = buf;
+ len = sizeof(struct GNUNET_MessageHeader);
+ hdr->size = htons(len);
+ hdr->type = htons(GNUNET_MESSAGE_TYPE_REHIJACK);
+ }
+ else
+ {
struct query_packet_list* query = mycls.head;
- size_t len = ntohs(query->pkt.hdr.size);
+ len = ntohs(query->pkt.hdr.size);
GNUNET_assert(len <= size);
GNUNET_CONTAINER_DLL_remove (mycls.head, mycls.tail, query);
GNUNET_free(query);
+ }
- if (mycls.head != NULL) {
+ if (mycls.head != NULL || mycls.restart_hijack == 1) {
GNUNET_CLIENT_notify_transmit_ready(mycls.dns_connection, ntohs(mycls.head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL);
}
GNUNET_CONTAINER_DLL_insert_after(mycls.head, mycls.tail, mycls.tail, query);
- /* struct GNUNET_CLIENT_TransmitHandle* th = */ GNUNET_CLIENT_notify_transmit_ready(mycls.dns_connection, len, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL);
+ if (mycls.dns_connection != NULL)
+ /* struct GNUNET_CLIENT_TransmitHandle* th = */ GNUNET_CLIENT_notify_transmit_ready(mycls.dns_connection, len, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL);
}
}
}
-void dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg) {
- if (msg == NULL) return;
+static void
+dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg);
+
+static void
+reconnect_to_service_dns (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc) {
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting\n");
+ GNUNET_assert (mycls.dns_connection == NULL);
+ mycls.dns_connection = GNUNET_CLIENT_connect (mycls.sched, "dns", mycls.cfg);
+ GNUNET_CLIENT_receive(mycls.dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL);
+ if (mycls.head != NULL)
+ /* struct GNUNET_CLIENT_TransmitHandle* th = */ GNUNET_CLIENT_notify_transmit_ready(mycls.dns_connection, ntohs(mycls.head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL);
+}
+
+static void
+process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc) {
+ struct answer_packet* pkt = cls;
+
+ if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_SERVICE)
+ {
+ pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP;
+ unsigned char ip6addr[16];
+ memcpy(ip6addr, (int[]){htons(0x1234)}, 2);
+ memcpy(ip6addr+2, &pkt->peer, 7);
+ memcpy(ip6addr+9, &pkt->service_descriptor, 7);
+
+ memcpy(((char*)pkt)+ntohs(pkt->addroffset), ip6addr, 16);
- if (msg->type != htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS)) goto out;
+ /*FIXME:
+ * -save DNS_Record into hashmap, pointed to by ip
+ * -regularily walk through hashmap, deleting old entries
+ * when is an entry old?
+ * have a last-used field
+ * don't remove if last-used "recent", ask dht again if record expired
+ */
+ }
- struct answer_packet_list* pkt = GNUNET_malloc(ntohs(msg->size) + 2*sizeof(struct answer_packet_list*));
+ struct answer_packet_list* list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*));
- memcpy(&pkt->pkt, msg, ntohs(msg->size));
+ memcpy(&list->pkt, pkt, htons(pkt->hdr.size));
- GNUNET_CONTAINER_DLL_insert_after(mycls.answer_head, mycls.answer_tail, mycls.answer_tail, pkt);
+ GNUNET_CONTAINER_DLL_insert_after(mycls.answer_proc_head, mycls.answer_proc_tail, mycls.answer_proc_tail, list);
GNUNET_SCHEDULER_add_write_file (mycls.sched, GNUNET_TIME_UNIT_FOREVER_REL, mycls.fh_to_helper, &helper_write, NULL);
-out:
- GNUNET_CLIENT_receive(mycls.dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL);
+ return;
+}
+
+static void
+dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg)
+{
+ if (msg == NULL)
+ {
+ GNUNET_CLIENT_disconnect(mycls.dns_connection, GNUNET_NO);
+ mycls.dns_connection = NULL;
+ GNUNET_SCHEDULER_add_delayed (mycls.sched,
+ GNUNET_TIME_UNIT_SECONDS,
+ &reconnect_to_service_dns,
+ NULL);
+ return;
+ }
+
+ if (msg->type != htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS))
+ {
+ GNUNET_break (0);
+ GNUNET_CLIENT_disconnect(mycls.dns_connection, GNUNET_NO);
+ mycls.dns_connection = NULL;
+ GNUNET_SCHEDULER_add_now (mycls.sched,
+ &reconnect_to_service_dns,
+ NULL);
+ return;
+ }
+ void *pkt = GNUNET_malloc(ntohs(msg->size));
+
+ memcpy(pkt, msg, ntohs(msg->size));
+
+ GNUNET_SCHEDULER_add_now(mycls.sched, process_answer, pkt);
+ GNUNET_CLIENT_receive(mycls.dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL);
}
/**
{
mycls.sched = sched;
mycls.mst = GNUNET_SERVER_mst_create(&message_token, NULL);
-
- mycls.dns_connection = GNUNET_CLIENT_connect (sched, "dns", cfg);
-
- GNUNET_CLIENT_receive(mycls.dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL);
-
+ mycls.cfg = cfg;
+ mycls.restart_hijack = 0;
+ GNUNET_SCHEDULER_add_now (sched, &reconnect_to_service_dns, NULL);
GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
- start_helper_and_schedule(mycls);
+ GNUNET_SCHEDULER_add_now (sched, start_helper_and_schedule, NULL);
}