diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-15 20:41:40 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-15 20:41:40 +0000 |
commit | 1574e0f8c2a55363c024a95f440ba7be647efbe1 (patch) | |
tree | 5e4507d9aa404ac983c5774b71b25ec6174ee7cc /src/dns | |
parent | 5ec7048ed9ffeddbe06e34a31d388080fae143e5 (diff) | |
download | gnunet-1574e0f8c2a55363c024a95f440ba7be647efbe1.tar.gz gnunet-1574e0f8c2a55363c024a95f440ba7be647efbe1.zip |
-removing legacy dns/vpn/exit code and renaming -new versions to current
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/Makefile.am | 47 | ||||
-rw-r--r-- | src/dns/dns.h | 93 | ||||
-rw-r--r-- | src/dns/dns_api.c | 664 | ||||
-rw-r--r-- | src/dns/dns_api_new.c | 522 | ||||
-rw-r--r-- | src/dns/dns_new.h | 101 | ||||
-rw-r--r-- | src/dns/dnsparser.c | 329 | ||||
-rw-r--r-- | src/dns/gnunet-dns-monitor.c | 2 | ||||
-rw-r--r-- | src/dns/gnunet-dns-redirector.c | 2 | ||||
-rw-r--r-- | src/dns/gnunet-helper-hijack-dns.c | 328 | ||||
-rw-r--r-- | src/dns/gnunet-service-dns.c | 2445 | ||||
-rw-r--r-- | src/dns/gnunet-service-dns_new.c | 1293 |
11 files changed, 1503 insertions, 4323 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am index 99e78d7d6..f8bdae94e 100644 --- a/src/dns/Makefile.am +++ b/src/dns/Makefile.am | |||
@@ -16,26 +16,23 @@ pkgcfg_DATA = \ | |||
16 | dns.conf | 16 | dns.conf |
17 | 17 | ||
18 | if LINUX | 18 | if LINUX |
19 | HIJACKBIN = gnunet-helper-hijack-dns gnunet-helper-dns | 19 | HIJACKBIN = gnunet-helper-dns |
20 | install-exec-hook: | 20 | install-exec-hook: |
21 | $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-hijack-dns || true | ||
22 | $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-hijack-dns || true | ||
23 | $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true | 21 | $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true |
24 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true | 22 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true |
25 | $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true | 23 | $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true |
26 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns-new || true | 24 | $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true |
27 | $(SUDO_BINARY) chmod 2755 $(bindir)/gnunet-helper-dns || true | 25 | $(SUDO_BINARY) chmod 2755 $(bindir)/gnunet-service-dns || true |
28 | else | 26 | else |
29 | install-exec-hook: | 27 | install-exec-hook: |
30 | endif | 28 | endif |
31 | 29 | ||
32 | lib_LTLIBRARIES = \ | 30 | lib_LTLIBRARIES = \ |
33 | libgnunetdnsparser.la \ | 31 | libgnunetdnsparser.la \ |
34 | libgnunetdnsnew.la \ | ||
35 | libgnunetdns.la | 32 | libgnunetdns.la |
36 | 33 | ||
37 | bin_PROGRAMS = \ | 34 | bin_PROGRAMS = \ |
38 | gnunet-service-dns gnunet-service-dns-new $(HIJACKBIN) | 35 | gnunet-service-dns $(HIJACKBIN) |
39 | 36 | ||
40 | noinst_PROGRAMS = \ | 37 | noinst_PROGRAMS = \ |
41 | gnunet-dns-monitor gnunet-dns-redirector | 38 | gnunet-dns-monitor gnunet-dns-redirector |
@@ -44,50 +41,35 @@ plugin_LTLIBRARIES = \ | |||
44 | libgnunet_plugin_block_dns.la | 41 | libgnunet_plugin_block_dns.la |
45 | 42 | ||
46 | 43 | ||
47 | gnunet_helper_hijack_dns_SOURCES = \ | ||
48 | gnunet-helper-hijack-dns.c | ||
49 | |||
50 | gnunet_helper_dns_SOURCES = \ | 44 | gnunet_helper_dns_SOURCES = \ |
51 | gnunet-helper-dns.c | 45 | gnunet-helper-dns.c |
52 | 46 | ||
53 | gnunet_service_dns_SOURCES = \ | ||
54 | gnunet-service-dns.c | ||
55 | gnunet_service_dns_LDADD = \ | ||
56 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
57 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
58 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
59 | $(top_builddir)/src/dht/libgnunetdht.la \ | ||
60 | $(top_builddir)/src/mesh/libgnunetmesh.la \ | ||
61 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | ||
62 | $(GN_LIBINTL) | ||
63 | gnunet_service_dns_DEPENDENCIES = \ | ||
64 | libgnunetdnsparser.la | ||
65 | 47 | ||
66 | gnunet_dns_monitor_SOURCES = \ | 48 | gnunet_dns_monitor_SOURCES = \ |
67 | gnunet-dns-monitor.c | 49 | gnunet-dns-monitor.c |
68 | gnunet_dns_monitor_LDADD = \ | 50 | gnunet_dns_monitor_LDADD = \ |
69 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | 51 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ |
70 | $(top_builddir)/src/dns/libgnunetdnsnew.la \ | 52 | $(top_builddir)/src/dns/libgnunetdns.la \ |
71 | $(top_builddir)/src/util/libgnunetutil.la \ | 53 | $(top_builddir)/src/util/libgnunetutil.la \ |
72 | $(GN_LIBINTL) | 54 | $(GN_LIBINTL) |
73 | gnunet_dns_monitor_DEPENDENCIES = \ | 55 | gnunet_dns_monitor_DEPENDENCIES = \ |
74 | libgnunetdnsparser.la \ | 56 | libgnunetdnsparser.la \ |
75 | libgnunetdnsnew.la | 57 | libgnunetdns.la |
76 | 58 | ||
77 | gnunet_dns_redirector_SOURCES = \ | 59 | gnunet_dns_redirector_SOURCES = \ |
78 | gnunet-dns-redirector.c | 60 | gnunet-dns-redirector.c |
79 | gnunet_dns_redirector_LDADD = \ | 61 | gnunet_dns_redirector_LDADD = \ |
80 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ | 62 | $(top_builddir)/src/dns/libgnunetdnsparser.la \ |
81 | $(top_builddir)/src/dns/libgnunetdnsnew.la \ | 63 | $(top_builddir)/src/dns/libgnunetdns.la \ |
82 | $(top_builddir)/src/util/libgnunetutil.la \ | 64 | $(top_builddir)/src/util/libgnunetutil.la \ |
83 | $(GN_LIBINTL) | 65 | $(GN_LIBINTL) |
84 | gnunet_dns_redirector_DEPENDENCIES = \ | 66 | gnunet_dns_redirector_DEPENDENCIES = \ |
85 | libgnunetdnsparser.la \ | 67 | libgnunetdnsparser.la \ |
86 | libgnunetdnsnew.la | 68 | libgnunetdns.la |
87 | 69 | ||
88 | gnunet_service_dns_new_SOURCES = \ | 70 | gnunet_service_dns_SOURCES = \ |
89 | gnunet-service-dns_new.c | 71 | gnunet-service-dns.c |
90 | gnunet_service_dns_new_LDADD = \ | 72 | gnunet_service_dns_LDADD = \ |
91 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 73 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
92 | $(top_builddir)/src/util/libgnunetutil.la \ | 74 | $(top_builddir)/src/util/libgnunetutil.la \ |
93 | $(GN_LIBINTL) | 75 | $(GN_LIBINTL) |
@@ -106,13 +88,6 @@ libgnunetdns_la_LIBADD = \ | |||
106 | libgnunetdns_la_LDFLAGS = \ | 88 | libgnunetdns_la_LDFLAGS = \ |
107 | $(GN_LIB_LDFLAGS) | 89 | $(GN_LIB_LDFLAGS) |
108 | 90 | ||
109 | libgnunetdnsnew_la_SOURCES = \ | ||
110 | dns_api_new.c dns_new.h | ||
111 | libgnunetdnsnew_la_LIBADD = \ | ||
112 | $(top_builddir)/src/util/libgnunetutil.la $(XLIB) | ||
113 | libgnunetdnsnew_la_LDFLAGS = \ | ||
114 | $(GN_LIB_LDFLAGS) | ||
115 | |||
116 | libgnunet_plugin_block_dns_la_SOURCES = \ | 91 | libgnunet_plugin_block_dns_la_SOURCES = \ |
117 | plugin_block_dns.c | 92 | plugin_block_dns.c |
118 | libgnunet_plugin_block_dns_la_LIBADD = \ | 93 | libgnunet_plugin_block_dns_la_LIBADD = \ |
diff --git a/src/dns/dns.h b/src/dns/dns.h index dd0f55e16..29a9f937b 100644 --- a/src/dns/dns.h +++ b/src/dns/dns.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,36 +19,83 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file dns/dns.h | 22 | * @file dns/dns_new.h |
23 | * @brief IPC messages between DNS API and DNS service | 23 | * @brief IPC messages between DNS API and DNS service |
24 | * @author Philipp Toelke | ||
25 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
26 | */ | 25 | */ |
27 | #ifndef DNS_H | 26 | #ifndef DNS_NEW_H |
28 | #define DNS_H | 27 | #define DNS_NEW_H |
29 | 28 | ||
30 | GNUNET_NETWORK_STRUCT_BEGIN | 29 | GNUNET_NETWORK_STRUCT_BEGIN |
31 | 30 | ||
32 | struct query_packet | 31 | |
32 | /** | ||
33 | * Message from client to DNS service to register itself. | ||
34 | */ | ||
35 | struct GNUNET_DNS_Register | ||
36 | { | ||
37 | /** | ||
38 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. | ||
44 | */ | ||
45 | uint32_t flags; | ||
46 | }; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Message from DNS service to client: please handle a request. | ||
51 | */ | ||
52 | struct GNUNET_DNS_Request | ||
53 | { | ||
54 | /** | ||
55 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST | ||
56 | */ | ||
57 | struct GNUNET_MessageHeader header; | ||
58 | |||
59 | /** | ||
60 | * Always zero. | ||
61 | */ | ||
62 | uint32_t reserved GNUNET_PACKED; | ||
63 | |||
64 | /** | ||
65 | * Unique request ID. | ||
66 | */ | ||
67 | uint64_t request_id GNUNET_PACKED; | ||
68 | |||
69 | /* followed by original DNS request (without UDP header) */ | ||
70 | |||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Message from client to DNS service: here is my reply. | ||
76 | */ | ||
77 | struct GNUNET_DNS_Response | ||
33 | { | 78 | { |
34 | struct GNUNET_MessageHeader hdr; | 79 | /** |
35 | 80 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE | |
36 | /** | 81 | */ |
37 | * The IP-Address this query was originally sent to | 82 | struct GNUNET_MessageHeader header; |
38 | */ | 83 | |
39 | char orig_to[16]; | 84 | /** |
40 | /** | 85 | * Zero to drop, 1 for no change (no payload), 2 for update (message has payload). |
41 | * The IP-Address this query was originally sent from | 86 | */ |
42 | */ | 87 | uint32_t drop_flag GNUNET_PACKED; |
43 | char orig_from[16]; | 88 | |
44 | char addrlen; | 89 | /** |
45 | /** | 90 | * Unique request ID. |
46 | * The UDP-Port this query was originally sent from | 91 | */ |
47 | */ | 92 | uint64_t request_id GNUNET_PACKED; |
48 | uint16_t src_port GNUNET_PACKED; | 93 | |
49 | 94 | /* followed by original DNS request (without UDP header) */ | |
50 | unsigned char data[1]; /* The DNS-Packet */ | 95 | |
51 | }; | 96 | }; |
97 | |||
98 | |||
52 | GNUNET_NETWORK_STRUCT_END | 99 | GNUNET_NETWORK_STRUCT_END |
53 | 100 | ||
54 | #endif | 101 | #endif |
diff --git a/src/dns/dns_api.c b/src/dns/dns_api.c index b434fc1e7..dfce0af1b 100644 --- a/src/dns/dns_api.c +++ b/src/dns/dns_api.c | |||
@@ -1,342 +1,522 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet |
3 | (C) 2010 Christian Grothoff | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 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 | 7 | by the Free Software Foundation; either version 2, or (at your |
8 | option) any later version. | 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 | */ | ||
9 | 20 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 21 | /** |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 22 | * @file dns/dns_api_new.c |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 23 | * @brief API to access the DNS service. |
13 | General Public License for more details. | 24 | * @author Christian Grothoff |
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_dns_service.h" | ||
28 | #include "dns.h" | ||
14 | 29 | ||
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 | 30 | ||
21 | /** | 31 | /** |
22 | * @file dns/dns_api.c | 32 | * Reply to send to service. |
23 | * @brief | ||
24 | * @author Philipp Toelke | ||
25 | */ | 33 | */ |
26 | #include <platform.h> | 34 | struct ReplyQueueEntry |
27 | #include <gnunet_common.h> | 35 | { |
28 | #include <gnunet_client_lib.h> | 36 | /** |
29 | #include <gnunet_os_lib.h> | 37 | * Kept in DLL. |
30 | #include <gnunet_mesh_service.h> | 38 | */ |
31 | #include <gnunet_protocols.h> | 39 | struct ReplyQueueEntry *next; |
32 | #include <gnunet_server_lib.h> | ||
33 | #include <gnunet_container_lib.h> | ||
34 | #include <block_dns.h> | ||
35 | 40 | ||
36 | #include "gnunet_dns_service.h" | 41 | /** |
37 | #include "dns.h" | 42 | * Kept in DLL. |
43 | */ | ||
44 | struct ReplyQueueEntry *prev; | ||
45 | |||
46 | /** | ||
47 | * Message to transmit, allocated at the end of this struct. | ||
48 | */ | ||
49 | const struct GNUNET_MessageHeader *msg; | ||
38 | 50 | ||
39 | struct query_packet_list | 51 | }; |
52 | |||
53 | |||
54 | /** | ||
55 | * Handle to identify an individual DNS request. | ||
56 | */ | ||
57 | struct GNUNET_DNS_RequestHandle | ||
40 | { | 58 | { |
41 | struct query_packet_list *next; | 59 | |
42 | struct query_packet_list *prev; | 60 | /** |
43 | struct query_packet pkt; | 61 | * Handle to DNS API. |
62 | */ | ||
63 | struct GNUNET_DNS_Handle *dh; | ||
64 | |||
65 | /** | ||
66 | * Stored in network byte order (as for us, it is just a random number). | ||
67 | */ | ||
68 | uint64_t request_id; | ||
69 | |||
70 | /** | ||
71 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
72 | */ | ||
73 | uint32_t generation; | ||
74 | |||
44 | }; | 75 | }; |
45 | 76 | ||
46 | 77 | ||
78 | /** | ||
79 | * DNS handle | ||
80 | */ | ||
47 | struct GNUNET_DNS_Handle | 81 | struct GNUNET_DNS_Handle |
48 | { | 82 | { |
49 | struct query_packet_list *head; | 83 | |
50 | struct query_packet_list *tail; | 84 | /** |
85 | * Connection to DNS service, or NULL. | ||
86 | */ | ||
51 | struct GNUNET_CLIENT_Connection *dns_connection; | 87 | struct GNUNET_CLIENT_Connection *dns_connection; |
52 | unsigned char restart_hijack; | ||
53 | 88 | ||
89 | /** | ||
90 | * Handle to active transmission request, or NULL. | ||
91 | */ | ||
54 | struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; | 92 | struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; |
55 | 93 | ||
94 | /** | ||
95 | * Configuration to use. | ||
96 | */ | ||
56 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 97 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
57 | 98 | ||
58 | GNUNET_DNS_ResponseCallback process_answer_cb; | 99 | /** |
100 | * Function to call to get replies. | ||
101 | */ | ||
102 | GNUNET_DNS_RequestHandler rh; | ||
59 | 103 | ||
60 | void *process_answer_cb_cls; | 104 | /** |
61 | }; | 105 | * Closure for 'rh'. |
106 | */ | ||
107 | void *rh_cls; | ||
62 | 108 | ||
109 | /** | ||
110 | * Head of replies to transmit. | ||
111 | */ | ||
112 | struct ReplyQueueEntry *rq_head; | ||
63 | 113 | ||
64 | /** | 114 | /** |
65 | * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages | 115 | * Tail of replies to transmit. |
66 | * to the service-dns | 116 | */ |
67 | * {{{ | 117 | struct ReplyQueueEntry *rq_tail; |
68 | */ | ||
69 | size_t | ||
70 | send_query (void *cls GNUNET_UNUSED, size_t size, void *buf) | ||
71 | { | ||
72 | struct GNUNET_DNS_Handle *h = cls; | ||
73 | 118 | ||
74 | size_t len; | 119 | /** |
120 | * Task to reconnect to the service. | ||
121 | */ | ||
122 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
75 | 123 | ||
76 | h->dns_transmit_handle = NULL; | 124 | /** |
125 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
126 | */ | ||
127 | uint32_t generation; | ||
128 | |||
129 | /** | ||
130 | * Flags for events we care about. | ||
131 | */ | ||
132 | enum GNUNET_DNS_Flags flags; | ||
77 | 133 | ||
78 | /* | 134 | /** |
79 | * Send the rehijack-message | 135 | * Did we start the receive loop yet? |
80 | */ | 136 | */ |
81 | if (h->restart_hijack == 1) | 137 | int in_receive; |
82 | { | 138 | |
83 | h->restart_hijack = 0; | 139 | /** |
84 | /* | 140 | * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before |
85 | * The message is just a header | 141 | * we can be disconnected. |
86 | */ | 142 | */ |
87 | GNUNET_assert (sizeof (struct GNUNET_MessageHeader) <= size); | 143 | unsigned int pending_requests; |
88 | struct GNUNET_MessageHeader *hdr = buf; | 144 | }; |
89 | 145 | ||
90 | len = sizeof (struct GNUNET_MessageHeader); | ||
91 | hdr->size = htons (len); | ||
92 | hdr->type = htons (GNUNET_MESSAGE_TYPE_REHIJACK); | ||
93 | } | ||
94 | else if (h->head != NULL) | ||
95 | { | ||
96 | struct query_packet_list *query = h->head; | ||
97 | 146 | ||
98 | len = ntohs (query->pkt.hdr.size); | 147 | /** |
148 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
149 | * | ||
150 | * @param dh handle with the connection | ||
151 | * @param qe reply to queue | ||
152 | */ | ||
153 | static void | ||
154 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
155 | struct ReplyQueueEntry *qe); | ||
99 | 156 | ||
100 | GNUNET_assert (len <= size); | ||
101 | 157 | ||
102 | memcpy (buf, &query->pkt.hdr, len); | 158 | /** |
159 | * Reconnect to the DNS service. | ||
160 | * | ||
161 | * @param cls handle with the connection to connect | ||
162 | * @param tc scheduler context (unused) | ||
163 | */ | ||
164 | static void | ||
165 | reconnect (void *cls, | ||
166 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
167 | { | ||
168 | struct GNUNET_DNS_Handle *dh = cls; | ||
169 | struct ReplyQueueEntry *qe; | ||
170 | struct GNUNET_DNS_Register *msg; | ||
103 | 171 | ||
104 | GNUNET_CONTAINER_DLL_remove (h->head, h->tail, query); | 172 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
173 | dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); | ||
174 | if (NULL == dh->dns_connection) | ||
175 | return; | ||
176 | dh->generation++; | ||
177 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
178 | sizeof (struct GNUNET_DNS_Register)); | ||
179 | msg = (struct GNUNET_DNS_Register*) &qe[1]; | ||
180 | qe->msg = &msg->header; | ||
181 | msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); | ||
182 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); | ||
183 | msg->flags = htonl (dh->flags); | ||
184 | queue_reply (dh, qe); | ||
185 | } | ||
105 | 186 | ||
106 | GNUNET_free (query); | 187 | |
107 | } | 188 | /** |
108 | else | 189 | * Disconnect from the DNS service. |
190 | * | ||
191 | * @param dh handle with the connection to disconnect | ||
192 | */ | ||
193 | static void | ||
194 | disconnect (struct GNUNET_DNS_Handle *dh) | ||
195 | { | ||
196 | struct ReplyQueueEntry *qe; | ||
197 | |||
198 | if (NULL != dh->dns_transmit_handle) | ||
109 | { | 199 | { |
110 | GNUNET_break (0); | 200 | GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle); |
111 | len = 0; | 201 | dh->dns_transmit_handle = NULL; |
112 | } | 202 | } |
113 | 203 | if (NULL != dh->dns_connection) | |
114 | /* | ||
115 | * Check whether more data is to be sent | ||
116 | */ | ||
117 | if (h->head != NULL) | ||
118 | { | 204 | { |
119 | h->dns_transmit_handle = | 205 | GNUNET_CLIENT_disconnect (dh->dns_connection, GNUNET_NO); |
120 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 206 | dh->dns_connection = NULL; |
121 | ntohs (h->head->pkt.hdr.size), | ||
122 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
123 | GNUNET_YES, &send_query, h); | ||
124 | } | 207 | } |
125 | else if (h->restart_hijack == 1) | 208 | while (NULL != (qe = dh->rq_head)) |
126 | { | 209 | { |
127 | h->dns_transmit_handle = | 210 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, |
128 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 211 | dh->rq_tail, |
129 | sizeof (struct | 212 | qe); |
130 | GNUNET_MessageHeader), | 213 | GNUNET_free (qe); |
131 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
132 | GNUNET_YES, &send_query, h); | ||
133 | } | 214 | } |
134 | 215 | dh->in_receive = GNUNET_NO; | |
135 | return len; | ||
136 | } | 216 | } |
137 | 217 | ||
138 | /* }}} */ | ||
139 | |||
140 | |||
141 | 218 | ||
142 | /** | 219 | /** |
143 | * This receives packets from the service-dns and schedules process_answer to | 220 | * This receives packets from the DNS service and calls the application to |
144 | * handle it | 221 | * handle it. |
222 | * | ||
223 | * @param cls the struct GNUNET_DNS_Handle | ||
224 | * @param msg message from the service (request) | ||
145 | */ | 225 | */ |
146 | static void | 226 | static void |
147 | dns_answer_handler (void *cls, | 227 | request_handler (void *cls, |
148 | const struct GNUNET_MessageHeader *msg) | 228 | const struct GNUNET_MessageHeader *msg) |
149 | { | 229 | { |
150 | struct GNUNET_DNS_Handle *h = cls; | 230 | struct GNUNET_DNS_Handle *dh = cls; |
231 | const struct GNUNET_DNS_Request *req; | ||
232 | struct GNUNET_DNS_RequestHandle *rh; | ||
233 | size_t payload_length; | ||
151 | 234 | ||
152 | /* the service disconnected, reconnect after short wait */ | 235 | /* the service disconnected, reconnect after short wait */ |
153 | if (msg == NULL) | 236 | if (msg == NULL) |
154 | { | 237 | { |
155 | if (h->dns_transmit_handle != NULL) | 238 | disconnect (dh); |
156 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->dns_transmit_handle); | 239 | dh->reconnect_task = |
157 | h->dns_transmit_handle = NULL; | ||
158 | GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO); | ||
159 | h->dns_connection = NULL; | ||
160 | #if 0 | ||
161 | h->conn_task = | ||
162 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | 240 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, |
163 | &connect_to_service_dns, h); | 241 | &reconnect, dh); |
164 | #endif | ||
165 | return; | 242 | return; |
166 | } | 243 | } |
167 | 244 | if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || | |
168 | /* the service did something strange, reconnect immediately */ | 245 | (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) |
169 | if (msg->type != htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS)) | ||
170 | { | 246 | { |
247 | /* the service did something strange, reconnect immediately */ | ||
171 | GNUNET_break (0); | 248 | GNUNET_break (0); |
172 | GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO); | 249 | disconnect (dh); |
173 | h->dns_connection = NULL; | 250 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); |
174 | #if 0 | ||
175 | conn_task = GNUNET_SCHEDULER_add_now (&connect_to_service_dns, NULL); | ||
176 | #endif | ||
177 | return; | 251 | return; |
178 | } | 252 | } |
179 | h->process_answer_cb (h->process_answer_cb_cls, | 253 | req = (const struct GNUNET_DNS_Request *) msg; |
180 | (const struct answer_packet*) msg); | 254 | GNUNET_break (ntohl (req->reserved) == 0); |
181 | GNUNET_CLIENT_receive (h->dns_connection, &dns_answer_handler, h, | 255 | payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); |
256 | GNUNET_CLIENT_receive (dh->dns_connection, | ||
257 | &request_handler, dh, | ||
182 | GNUNET_TIME_UNIT_FOREVER_REL); | 258 | GNUNET_TIME_UNIT_FOREVER_REL); |
259 | |||
260 | /* finally, pass request to callback for answers */ | ||
261 | rh = GNUNET_malloc (sizeof (struct GNUNET_DNS_RequestHandle)); | ||
262 | rh->dh =dh; | ||
263 | rh->request_id = req->request_id; | ||
264 | rh->generation = dh->generation; | ||
265 | dh->pending_requests++; | ||
266 | dh->rh (dh->rh_cls, | ||
267 | rh, | ||
268 | payload_length, | ||
269 | (const char*) &req[1]); | ||
183 | } | 270 | } |
184 | 271 | ||
185 | 272 | ||
186 | /** | 273 | /** |
187 | * Connect to the service-dns | 274 | * Callback called by notify_transmit_ready; sends DNS replies |
275 | * to the DNS service. | ||
276 | * | ||
277 | * @param cls the struct GNUNET_DNS_Handle | ||
278 | * @param size number of bytes available in buf | ||
279 | * @param buf where to copy the message for transmission | ||
280 | * @return number of bytes copied to buf | ||
188 | */ | 281 | */ |
189 | struct GNUNET_DNS_Handle * | 282 | static size_t |
190 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 283 | send_response (void *cls, size_t size, void *buf) |
191 | GNUNET_DNS_ResponseCallback cb, | ||
192 | void *cb_cls) | ||
193 | { | 284 | { |
194 | struct GNUNET_DNS_Handle *h; | 285 | struct GNUNET_DNS_Handle *dh = cls; |
195 | 286 | struct ReplyQueueEntry *qe; | |
196 | h = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); | 287 | size_t len; |
197 | h->cfg = cfg; | 288 | |
198 | h->process_answer_cb = cb; | 289 | dh->dns_transmit_handle = NULL; |
199 | h->process_answer_cb_cls = cb_cls; | 290 | if (NULL == buf) |
200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to service-dns\n"); | 291 | { |
201 | h->dns_connection = GNUNET_CLIENT_connect ("dns", h->cfg); | 292 | disconnect (dh); |
202 | /* This would most likely be a misconfiguration */ | 293 | dh->reconnect_task = |
203 | GNUNET_assert (NULL != h->dns_connection); | 294 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, |
204 | GNUNET_CLIENT_receive (h->dns_connection, | 295 | &reconnect, dh); |
205 | &dns_answer_handler, NULL, | 296 | return 0; |
206 | GNUNET_TIME_UNIT_FOREVER_REL); | 297 | } |
207 | /* If a packet is already in the list, schedule to send it */ | 298 | qe = dh->rq_head; |
208 | if (h->dns_transmit_handle == NULL && h->head != NULL) | 299 | if (NULL == qe) |
209 | h->dns_transmit_handle = | 300 | return 0; |
210 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 301 | len = ntohs (qe->msg->size); |
211 | ntohs (h->head->pkt.hdr.size), | 302 | if (len > size) |
212 | GNUNET_TIME_UNIT_FOREVER_REL, | 303 | { |
213 | GNUNET_YES, &send_query, h); | 304 | dh->dns_transmit_handle = |
214 | else if (h->dns_transmit_handle == NULL && h->restart_hijack == 1) | 305 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, |
306 | len, | ||
307 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
308 | GNUNET_NO, | ||
309 | &send_response, dh); | ||
310 | return 0; | ||
311 | } | ||
312 | memcpy (buf, qe->msg, len); | ||
313 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, | ||
314 | dh->rq_tail, | ||
315 | qe); | ||
316 | GNUNET_free (qe); | ||
317 | if (GNUNET_NO == dh->in_receive) | ||
215 | { | 318 | { |
216 | h->dns_transmit_handle = | 319 | dh->in_receive = GNUNET_YES; |
217 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 320 | GNUNET_CLIENT_receive (dh->dns_connection, |
218 | sizeof (struct | 321 | &request_handler, dh, |
219 | GNUNET_MessageHeader), | 322 | GNUNET_TIME_UNIT_FOREVER_REL); |
220 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
221 | GNUNET_YES, &send_query, NULL); | ||
222 | } | 323 | } |
223 | return h; | 324 | if (NULL != (qe = dh->rq_head)) |
325 | { | ||
326 | dh->dns_transmit_handle = | ||
327 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
328 | ntohs (qe->msg->size), | ||
329 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
330 | GNUNET_NO, | ||
331 | &send_response, dh); | ||
332 | } | ||
333 | return len; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
339 | * | ||
340 | * @param dh handle with the connection | ||
341 | * @param qe reply to queue | ||
342 | */ | ||
343 | static void | ||
344 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
345 | struct ReplyQueueEntry *qe) | ||
346 | { | ||
347 | if (NULL == dh->dns_connection) | ||
348 | { | ||
349 | GNUNET_free (qe); | ||
350 | return; | ||
351 | } | ||
352 | GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head, | ||
353 | dh->rq_tail, | ||
354 | qe); | ||
355 | if (NULL != dh->dns_transmit_handle) | ||
356 | return; | ||
357 | /* trigger sending */ | ||
358 | dh->dns_transmit_handle = | ||
359 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
360 | ntohs (dh->rq_head->msg->size), | ||
361 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
362 | GNUNET_NO, | ||
363 | &send_response, dh); | ||
224 | } | 364 | } |
225 | 365 | ||
226 | 366 | ||
367 | /** | ||
368 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
369 | * given to other clients or the global DNS for resolution. Once a | ||
370 | * global response has been obtained, the request handler is AGAIN | ||
371 | * called to give it a chance to observe and modify the response after | ||
372 | * the "normal" resolution. It is not legal for the request handler | ||
373 | * to call this function if a response is already present. | ||
374 | * | ||
375 | * @param rh request that should now be forwarded | ||
376 | */ | ||
227 | void | 377 | void |
228 | GNUNET_DNS_restart_hijack (struct GNUNET_DNS_Handle *h) | 378 | GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh) |
229 | { | 379 | { |
230 | h->restart_hijack = 1; | 380 | struct ReplyQueueEntry *qe; |
231 | if (NULL != h->dns_connection && h->dns_transmit_handle == NULL) | 381 | struct GNUNET_DNS_Response *resp; |
232 | h->dns_transmit_handle = | 382 | |
233 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, | 383 | GNUNET_assert (0 < rh->dh->pending_requests--); |
234 | sizeof (struct | 384 | if (rh->generation != rh->dh->generation) |
235 | GNUNET_MessageHeader), | 385 | { |
236 | GNUNET_TIME_UNIT_FOREVER_REL, | 386 | GNUNET_free (rh); |
237 | GNUNET_YES, &send_query, h); | 387 | return; |
388 | } | ||
389 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
390 | sizeof (struct GNUNET_DNS_Response)); | ||
391 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
392 | qe->msg = &resp->header; | ||
393 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
394 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
395 | resp->drop_flag = htonl (1); | ||
396 | resp->request_id = rh->request_id; | ||
397 | queue_reply (rh->dh, qe); | ||
398 | GNUNET_free (rh); | ||
238 | } | 399 | } |
239 | 400 | ||
240 | 401 | ||
241 | /** | 402 | /** |
242 | * FIXME: we should not expost our internal structures like this. | 403 | * If a GNUNET_DNS_RequestHandler calls this function, the request is |
243 | * Just a quick initial hack. | 404 | * to be dropped and no response should be generated. |
405 | * | ||
406 | * @param rh request that should now be dropped | ||
244 | */ | 407 | */ |
245 | static void | 408 | void |
246 | queue_request (struct GNUNET_DNS_Handle *h, | 409 | GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh) |
247 | struct query_packet_list *q) | ||
248 | { | 410 | { |
249 | GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, q); | 411 | struct ReplyQueueEntry *qe; |
250 | if (h->dns_connection != NULL && h->dns_transmit_handle == NULL) | 412 | struct GNUNET_DNS_Response *resp; |
251 | h->dns_transmit_handle = | ||
252 | GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, ntohs(q->pkt.hdr.size), | ||
253 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
254 | GNUNET_YES, &send_query, | ||
255 | h); | ||
256 | } | ||
257 | 413 | ||
414 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
415 | if (rh->generation != rh->dh->generation) | ||
416 | { | ||
417 | GNUNET_free (rh); | ||
418 | return; | ||
419 | } | ||
420 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
421 | sizeof (struct GNUNET_DNS_Response)); | ||
422 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
423 | qe->msg = &resp->header; | ||
424 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
425 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
426 | resp->request_id = rh->request_id; | ||
427 | resp->drop_flag = htonl (0); | ||
428 | queue_reply (rh->dh, qe); | ||
429 | GNUNET_free (rh); | ||
430 | } | ||
258 | 431 | ||
259 | 432 | ||
260 | /** | 433 | /** |
261 | * Process a DNS request sent to an IPv4 resolver. Pass it | 434 | * If a GNUNET_DNS_RequestHandler calls this function, the request is |
262 | * to the DNS service for resolution. | 435 | * supposed to be answered with the data provided to this call (with |
436 | * the modifications the function might have made). | ||
263 | * | 437 | * |
264 | * @param h DNS handle | 438 | * @param rh request that should now be answered |
265 | * @param dst_ip destination IPv4 address | 439 | * @param reply_length size of reply (uint16_t to force sane size) |
266 | * @param src_ip source IPv4 address (usually local machine) | 440 | * @param reply reply data |
267 | * @param src_port source port (to be used for reply) | ||
268 | * @param udp_packet_len length of the UDP payload in bytes | ||
269 | * @param udp_packet UDP payload | ||
270 | */ | 441 | */ |
271 | void | 442 | void |
272 | GNUNET_DNS_queue_request_v4 (struct GNUNET_DNS_Handle *h, | 443 | GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, |
273 | const struct in_addr *dst_ip, | 444 | uint16_t reply_length, |
274 | const struct in_addr *src_ip, | 445 | const char *reply) |
275 | uint16_t src_port, | ||
276 | size_t udp_packet_len, | ||
277 | const char *udp_packet) | ||
278 | { | 446 | { |
279 | size_t len = sizeof (struct query_packet) + udp_packet_len - 1; | 447 | struct ReplyQueueEntry *qe; |
280 | struct query_packet_list *query = | 448 | struct GNUNET_DNS_Response *resp; |
281 | GNUNET_malloc (len + sizeof (struct query_packet_list) - | 449 | |
282 | sizeof (struct query_packet)); | 450 | GNUNET_assert (0 < rh->dh->pending_requests--); |
283 | query->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS); | 451 | if (rh->generation != rh->dh->generation) |
284 | query->pkt.hdr.size = htons (len); | 452 | { |
285 | memcpy (query->pkt.orig_to, dst_ip, 4); | 453 | GNUNET_free (rh); |
286 | memcpy (query->pkt.orig_from, src_ip, 4); | 454 | return; |
287 | query->pkt.addrlen = 4; | 455 | } |
288 | query->pkt.src_port = htons (src_port); | 456 | if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
289 | memcpy (query->pkt.data, udp_packet, udp_packet_len); | 457 | { |
290 | queue_request (h, query); | 458 | GNUNET_break (0); |
459 | GNUNET_free (rh); | ||
460 | return; | ||
461 | } | ||
462 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
463 | sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
464 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
465 | qe->msg = &resp->header; | ||
466 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
467 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
468 | resp->drop_flag = htonl (2); | ||
469 | resp->request_id = rh->request_id; | ||
470 | memcpy (&resp[1], reply, reply_length); | ||
471 | queue_reply (rh->dh, qe); | ||
472 | GNUNET_free (rh); | ||
291 | } | 473 | } |
292 | 474 | ||
293 | 475 | ||
294 | /** | 476 | /** |
295 | * Process a DNS request sent to an IPv6 resolver. Pass it | 477 | * Connect to the service-dns |
296 | * to the DNS service for resolution. | ||
297 | * | 478 | * |
298 | * @param h DNS handle | 479 | * @param cfg configuration to use |
299 | * @param dst_ip destination IPv6 address | 480 | * @param flags when to call rh |
300 | * @param src_ip source IPv6 address (usually local machine) | 481 | * @param rh function to call with DNS requests |
301 | * @param src_port source port (to be used for reply) | 482 | * @param rh_cls closure to pass to rh |
302 | * @param udp_packet_len length of the UDP payload in bytes | 483 | * @return DNS handle |
303 | * @param udp_packet UDP payload | ||
304 | */ | 484 | */ |
305 | void | 485 | struct GNUNET_DNS_Handle * |
306 | GNUNET_DNS_queue_request_v6 (struct GNUNET_DNS_Handle *h, | 486 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, |
307 | const struct in6_addr *dst_ip, | 487 | enum GNUNET_DNS_Flags flags, |
308 | const struct in6_addr *src_ip, | 488 | GNUNET_DNS_RequestHandler rh, |
309 | uint16_t src_port, | 489 | void *rh_cls) |
310 | size_t udp_packet_len, | ||
311 | const char *udp_packet) | ||
312 | { | 490 | { |
313 | size_t len = | 491 | struct GNUNET_DNS_Handle *dh; |
314 | sizeof (struct query_packet) + udp_packet_len - 1; | 492 | |
315 | struct query_packet_list *query = | 493 | dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); |
316 | GNUNET_malloc (len + sizeof (struct query_packet_list) - | 494 | dh->cfg = cfg; |
317 | sizeof (struct answer_packet)); | 495 | dh->flags = flags; |
318 | query->pkt.hdr.type = | 496 | dh->rh = rh; |
319 | htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS); | 497 | dh->rh_cls = rh_cls; |
320 | query->pkt.hdr.size = htons (len); | 498 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); |
321 | memcpy (query->pkt.orig_to, dst_ip, 16); | 499 | return dh; |
322 | memcpy (query->pkt.orig_from, src_ip, 16); | ||
323 | query->pkt.addrlen = 16; | ||
324 | query->pkt.src_port = htons (src_port); | ||
325 | memcpy (query->pkt.data, udp_packet, | ||
326 | udp_packet_len); | ||
327 | queue_request (h, query); | ||
328 | } | 500 | } |
329 | 501 | ||
330 | 502 | ||
503 | /** | ||
504 | * Disconnect from the DNS service. | ||
505 | * | ||
506 | * @param dh DNS handle | ||
507 | */ | ||
331 | void | 508 | void |
332 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *h) | 509 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh) |
333 | { | 510 | { |
334 | if (h->dns_connection != NULL) | 511 | if (GNUNET_SCHEDULER_NO_TASK != dh->reconnect_task) |
335 | { | 512 | { |
336 | GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO); | 513 | GNUNET_SCHEDULER_cancel (dh->reconnect_task); |
337 | h->dns_connection = NULL; | 514 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
338 | } | 515 | } |
339 | GNUNET_free (h); | 516 | disconnect (dh); |
517 | /* make sure client has no pending requests left over! */ | ||
518 | GNUNET_assert (0 == dh->pending_requests); | ||
519 | GNUNET_free (dh); | ||
340 | } | 520 | } |
341 | 521 | ||
342 | /* end of dns_api.c */ | 522 | /* end of dns_api_new.c */ |
diff --git a/src/dns/dns_api_new.c b/src/dns/dns_api_new.c deleted file mode 100644 index 9e479fce7..000000000 --- a/src/dns/dns_api_new.c +++ /dev/null | |||
@@ -1,522 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012 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 2, 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 dns/dns_api_new.c | ||
23 | * @brief API to access the DNS service. | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_dns_service-new.h" | ||
28 | #include "dns_new.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Reply to send to service. | ||
33 | */ | ||
34 | struct ReplyQueueEntry | ||
35 | { | ||
36 | /** | ||
37 | * Kept in DLL. | ||
38 | */ | ||
39 | struct ReplyQueueEntry *next; | ||
40 | |||
41 | /** | ||
42 | * Kept in DLL. | ||
43 | */ | ||
44 | struct ReplyQueueEntry *prev; | ||
45 | |||
46 | /** | ||
47 | * Message to transmit, allocated at the end of this struct. | ||
48 | */ | ||
49 | const struct GNUNET_MessageHeader *msg; | ||
50 | |||
51 | }; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Handle to identify an individual DNS request. | ||
56 | */ | ||
57 | struct GNUNET_DNS_RequestHandle | ||
58 | { | ||
59 | |||
60 | /** | ||
61 | * Handle to DNS API. | ||
62 | */ | ||
63 | struct GNUNET_DNS_Handle *dh; | ||
64 | |||
65 | /** | ||
66 | * Stored in network byte order (as for us, it is just a random number). | ||
67 | */ | ||
68 | uint64_t request_id; | ||
69 | |||
70 | /** | ||
71 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
72 | */ | ||
73 | uint32_t generation; | ||
74 | |||
75 | }; | ||
76 | |||
77 | |||
78 | /** | ||
79 | * DNS handle | ||
80 | */ | ||
81 | struct GNUNET_DNS_Handle | ||
82 | { | ||
83 | |||
84 | /** | ||
85 | * Connection to DNS service, or NULL. | ||
86 | */ | ||
87 | struct GNUNET_CLIENT_Connection *dns_connection; | ||
88 | |||
89 | /** | ||
90 | * Handle to active transmission request, or NULL. | ||
91 | */ | ||
92 | struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; | ||
93 | |||
94 | /** | ||
95 | * Configuration to use. | ||
96 | */ | ||
97 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
98 | |||
99 | /** | ||
100 | * Function to call to get replies. | ||
101 | */ | ||
102 | GNUNET_DNS_RequestHandler rh; | ||
103 | |||
104 | /** | ||
105 | * Closure for 'rh'. | ||
106 | */ | ||
107 | void *rh_cls; | ||
108 | |||
109 | /** | ||
110 | * Head of replies to transmit. | ||
111 | */ | ||
112 | struct ReplyQueueEntry *rq_head; | ||
113 | |||
114 | /** | ||
115 | * Tail of replies to transmit. | ||
116 | */ | ||
117 | struct ReplyQueueEntry *rq_tail; | ||
118 | |||
119 | /** | ||
120 | * Task to reconnect to the service. | ||
121 | */ | ||
122 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
123 | |||
124 | /** | ||
125 | * Re-connect counter, to make sure we did not reconnect in the meantime. | ||
126 | */ | ||
127 | uint32_t generation; | ||
128 | |||
129 | /** | ||
130 | * Flags for events we care about. | ||
131 | */ | ||
132 | enum GNUNET_DNS_Flags flags; | ||
133 | |||
134 | /** | ||
135 | * Did we start the receive loop yet? | ||
136 | */ | ||
137 | int in_receive; | ||
138 | |||
139 | /** | ||
140 | * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before | ||
141 | * we can be disconnected. | ||
142 | */ | ||
143 | unsigned int pending_requests; | ||
144 | }; | ||
145 | |||
146 | |||
147 | /** | ||
148 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
149 | * | ||
150 | * @param dh handle with the connection | ||
151 | * @param qe reply to queue | ||
152 | */ | ||
153 | static void | ||
154 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
155 | struct ReplyQueueEntry *qe); | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Reconnect to the DNS service. | ||
160 | * | ||
161 | * @param cls handle with the connection to connect | ||
162 | * @param tc scheduler context (unused) | ||
163 | */ | ||
164 | static void | ||
165 | reconnect (void *cls, | ||
166 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
167 | { | ||
168 | struct GNUNET_DNS_Handle *dh = cls; | ||
169 | struct ReplyQueueEntry *qe; | ||
170 | struct GNUNET_DNS_Register *msg; | ||
171 | |||
172 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
173 | dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); | ||
174 | if (NULL == dh->dns_connection) | ||
175 | return; | ||
176 | dh->generation++; | ||
177 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
178 | sizeof (struct GNUNET_DNS_Register)); | ||
179 | msg = (struct GNUNET_DNS_Register*) &qe[1]; | ||
180 | qe->msg = &msg->header; | ||
181 | msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); | ||
182 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); | ||
183 | msg->flags = htonl (dh->flags); | ||
184 | queue_reply (dh, qe); | ||
185 | } | ||
186 | |||
187 | |||
188 | /** | ||
189 | * Disconnect from the DNS service. | ||
190 | * | ||
191 | * @param dh handle with the connection to disconnect | ||
192 | */ | ||
193 | static void | ||
194 | disconnect (struct GNUNET_DNS_Handle *dh) | ||
195 | { | ||
196 | struct ReplyQueueEntry *qe; | ||
197 | |||
198 | if (NULL != dh->dns_transmit_handle) | ||
199 | { | ||
200 | GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle); | ||
201 | dh->dns_transmit_handle = NULL; | ||
202 | } | ||
203 | if (NULL != dh->dns_connection) | ||
204 | { | ||
205 | GNUNET_CLIENT_disconnect (dh->dns_connection, GNUNET_NO); | ||
206 | dh->dns_connection = NULL; | ||
207 | } | ||
208 | while (NULL != (qe = dh->rq_head)) | ||
209 | { | ||
210 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, | ||
211 | dh->rq_tail, | ||
212 | qe); | ||
213 | GNUNET_free (qe); | ||
214 | } | ||
215 | dh->in_receive = GNUNET_NO; | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * This receives packets from the DNS service and calls the application to | ||
221 | * handle it. | ||
222 | * | ||
223 | * @param cls the struct GNUNET_DNS_Handle | ||
224 | * @param msg message from the service (request) | ||
225 | */ | ||
226 | static void | ||
227 | request_handler (void *cls, | ||
228 | const struct GNUNET_MessageHeader *msg) | ||
229 | { | ||
230 | struct GNUNET_DNS_Handle *dh = cls; | ||
231 | const struct GNUNET_DNS_Request *req; | ||
232 | struct GNUNET_DNS_RequestHandle *rh; | ||
233 | size_t payload_length; | ||
234 | |||
235 | /* the service disconnected, reconnect after short wait */ | ||
236 | if (msg == NULL) | ||
237 | { | ||
238 | disconnect (dh); | ||
239 | dh->reconnect_task = | ||
240 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
241 | &reconnect, dh); | ||
242 | return; | ||
243 | } | ||
244 | if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || | ||
245 | (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) | ||
246 | { | ||
247 | /* the service did something strange, reconnect immediately */ | ||
248 | GNUNET_break (0); | ||
249 | disconnect (dh); | ||
250 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); | ||
251 | return; | ||
252 | } | ||
253 | req = (const struct GNUNET_DNS_Request *) msg; | ||
254 | GNUNET_break (ntohl (req->reserved) == 0); | ||
255 | payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); | ||
256 | GNUNET_CLIENT_receive (dh->dns_connection, | ||
257 | &request_handler, dh, | ||
258 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
259 | |||
260 | /* finally, pass request to callback for answers */ | ||
261 | rh = GNUNET_malloc (sizeof (struct GNUNET_DNS_RequestHandle)); | ||
262 | rh->dh =dh; | ||
263 | rh->request_id = req->request_id; | ||
264 | rh->generation = dh->generation; | ||
265 | dh->pending_requests++; | ||
266 | dh->rh (dh->rh_cls, | ||
267 | rh, | ||
268 | payload_length, | ||
269 | (const char*) &req[1]); | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Callback called by notify_transmit_ready; sends DNS replies | ||
275 | * to the DNS service. | ||
276 | * | ||
277 | * @param cls the struct GNUNET_DNS_Handle | ||
278 | * @param size number of bytes available in buf | ||
279 | * @param buf where to copy the message for transmission | ||
280 | * @return number of bytes copied to buf | ||
281 | */ | ||
282 | static size_t | ||
283 | send_response (void *cls, size_t size, void *buf) | ||
284 | { | ||
285 | struct GNUNET_DNS_Handle *dh = cls; | ||
286 | struct ReplyQueueEntry *qe; | ||
287 | size_t len; | ||
288 | |||
289 | dh->dns_transmit_handle = NULL; | ||
290 | if (NULL == buf) | ||
291 | { | ||
292 | disconnect (dh); | ||
293 | dh->reconnect_task = | ||
294 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
295 | &reconnect, dh); | ||
296 | return 0; | ||
297 | } | ||
298 | qe = dh->rq_head; | ||
299 | if (NULL == qe) | ||
300 | return 0; | ||
301 | len = ntohs (qe->msg->size); | ||
302 | if (len > size) | ||
303 | { | ||
304 | dh->dns_transmit_handle = | ||
305 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
306 | len, | ||
307 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
308 | GNUNET_NO, | ||
309 | &send_response, dh); | ||
310 | return 0; | ||
311 | } | ||
312 | memcpy (buf, qe->msg, len); | ||
313 | GNUNET_CONTAINER_DLL_remove (dh->rq_head, | ||
314 | dh->rq_tail, | ||
315 | qe); | ||
316 | GNUNET_free (qe); | ||
317 | if (GNUNET_NO == dh->in_receive) | ||
318 | { | ||
319 | dh->in_receive = GNUNET_YES; | ||
320 | GNUNET_CLIENT_receive (dh->dns_connection, | ||
321 | &request_handler, dh, | ||
322 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
323 | } | ||
324 | if (NULL != (qe = dh->rq_head)) | ||
325 | { | ||
326 | dh->dns_transmit_handle = | ||
327 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
328 | ntohs (qe->msg->size), | ||
329 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
330 | GNUNET_NO, | ||
331 | &send_response, dh); | ||
332 | } | ||
333 | return len; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Add the given reply to our transmission queue and trigger sending if needed. | ||
339 | * | ||
340 | * @param dh handle with the connection | ||
341 | * @param qe reply to queue | ||
342 | */ | ||
343 | static void | ||
344 | queue_reply (struct GNUNET_DNS_Handle *dh, | ||
345 | struct ReplyQueueEntry *qe) | ||
346 | { | ||
347 | if (NULL == dh->dns_connection) | ||
348 | { | ||
349 | GNUNET_free (qe); | ||
350 | return; | ||
351 | } | ||
352 | GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head, | ||
353 | dh->rq_tail, | ||
354 | qe); | ||
355 | if (NULL != dh->dns_transmit_handle) | ||
356 | return; | ||
357 | /* trigger sending */ | ||
358 | dh->dns_transmit_handle = | ||
359 | GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, | ||
360 | ntohs (dh->rq_head->msg->size), | ||
361 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
362 | GNUNET_NO, | ||
363 | &send_response, dh); | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
369 | * given to other clients or the global DNS for resolution. Once a | ||
370 | * global response has been obtained, the request handler is AGAIN | ||
371 | * called to give it a chance to observe and modify the response after | ||
372 | * the "normal" resolution. It is not legal for the request handler | ||
373 | * to call this function if a response is already present. | ||
374 | * | ||
375 | * @param rh request that should now be forwarded | ||
376 | */ | ||
377 | void | ||
378 | GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh) | ||
379 | { | ||
380 | struct ReplyQueueEntry *qe; | ||
381 | struct GNUNET_DNS_Response *resp; | ||
382 | |||
383 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
384 | if (rh->generation != rh->dh->generation) | ||
385 | { | ||
386 | GNUNET_free (rh); | ||
387 | return; | ||
388 | } | ||
389 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
390 | sizeof (struct GNUNET_DNS_Response)); | ||
391 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
392 | qe->msg = &resp->header; | ||
393 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
394 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
395 | resp->drop_flag = htonl (1); | ||
396 | resp->request_id = rh->request_id; | ||
397 | queue_reply (rh->dh, qe); | ||
398 | GNUNET_free (rh); | ||
399 | } | ||
400 | |||
401 | |||
402 | /** | ||
403 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
404 | * to be dropped and no response should be generated. | ||
405 | * | ||
406 | * @param rh request that should now be dropped | ||
407 | */ | ||
408 | void | ||
409 | GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh) | ||
410 | { | ||
411 | struct ReplyQueueEntry *qe; | ||
412 | struct GNUNET_DNS_Response *resp; | ||
413 | |||
414 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
415 | if (rh->generation != rh->dh->generation) | ||
416 | { | ||
417 | GNUNET_free (rh); | ||
418 | return; | ||
419 | } | ||
420 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
421 | sizeof (struct GNUNET_DNS_Response)); | ||
422 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
423 | qe->msg = &resp->header; | ||
424 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); | ||
425 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
426 | resp->request_id = rh->request_id; | ||
427 | resp->drop_flag = htonl (0); | ||
428 | queue_reply (rh->dh, qe); | ||
429 | GNUNET_free (rh); | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * If a GNUNET_DNS_RequestHandler calls this function, the request is | ||
435 | * supposed to be answered with the data provided to this call (with | ||
436 | * the modifications the function might have made). | ||
437 | * | ||
438 | * @param rh request that should now be answered | ||
439 | * @param reply_length size of reply (uint16_t to force sane size) | ||
440 | * @param reply reply data | ||
441 | */ | ||
442 | void | ||
443 | GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, | ||
444 | uint16_t reply_length, | ||
445 | const char *reply) | ||
446 | { | ||
447 | struct ReplyQueueEntry *qe; | ||
448 | struct GNUNET_DNS_Response *resp; | ||
449 | |||
450 | GNUNET_assert (0 < rh->dh->pending_requests--); | ||
451 | if (rh->generation != rh->dh->generation) | ||
452 | { | ||
453 | GNUNET_free (rh); | ||
454 | return; | ||
455 | } | ||
456 | if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
457 | { | ||
458 | GNUNET_break (0); | ||
459 | GNUNET_free (rh); | ||
460 | return; | ||
461 | } | ||
462 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | ||
463 | sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
464 | resp = (struct GNUNET_DNS_Response*) &qe[1]; | ||
465 | qe->msg = &resp->header; | ||
466 | resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length); | ||
467 | resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); | ||
468 | resp->drop_flag = htonl (2); | ||
469 | resp->request_id = rh->request_id; | ||
470 | memcpy (&resp[1], reply, reply_length); | ||
471 | queue_reply (rh->dh, qe); | ||
472 | GNUNET_free (rh); | ||
473 | } | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Connect to the service-dns | ||
478 | * | ||
479 | * @param cfg configuration to use | ||
480 | * @param flags when to call rh | ||
481 | * @param rh function to call with DNS requests | ||
482 | * @param rh_cls closure to pass to rh | ||
483 | * @return DNS handle | ||
484 | */ | ||
485 | struct GNUNET_DNS_Handle * | ||
486 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
487 | enum GNUNET_DNS_Flags flags, | ||
488 | GNUNET_DNS_RequestHandler rh, | ||
489 | void *rh_cls) | ||
490 | { | ||
491 | struct GNUNET_DNS_Handle *dh; | ||
492 | |||
493 | dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); | ||
494 | dh->cfg = cfg; | ||
495 | dh->flags = flags; | ||
496 | dh->rh = rh; | ||
497 | dh->rh_cls = rh_cls; | ||
498 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); | ||
499 | return dh; | ||
500 | } | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Disconnect from the DNS service. | ||
505 | * | ||
506 | * @param dh DNS handle | ||
507 | */ | ||
508 | void | ||
509 | GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh) | ||
510 | { | ||
511 | if (GNUNET_SCHEDULER_NO_TASK != dh->reconnect_task) | ||
512 | { | ||
513 | GNUNET_SCHEDULER_cancel (dh->reconnect_task); | ||
514 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
515 | } | ||
516 | disconnect (dh); | ||
517 | /* make sure client has no pending requests left over! */ | ||
518 | GNUNET_assert (0 == dh->pending_requests); | ||
519 | GNUNET_free (dh); | ||
520 | } | ||
521 | |||
522 | /* end of dns_api_new.c */ | ||
diff --git a/src/dns/dns_new.h b/src/dns/dns_new.h deleted file mode 100644 index 29a9f937b..000000000 --- a/src/dns/dns_new.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012 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 2, 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 dns/dns_new.h | ||
23 | * @brief IPC messages between DNS API and DNS service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef DNS_NEW_H | ||
27 | #define DNS_NEW_H | ||
28 | |||
29 | GNUNET_NETWORK_STRUCT_BEGIN | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Message from client to DNS service to register itself. | ||
34 | */ | ||
35 | struct GNUNET_DNS_Register | ||
36 | { | ||
37 | /** | ||
38 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. | ||
44 | */ | ||
45 | uint32_t flags; | ||
46 | }; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Message from DNS service to client: please handle a request. | ||
51 | */ | ||
52 | struct GNUNET_DNS_Request | ||
53 | { | ||
54 | /** | ||
55 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST | ||
56 | */ | ||
57 | struct GNUNET_MessageHeader header; | ||
58 | |||
59 | /** | ||
60 | * Always zero. | ||
61 | */ | ||
62 | uint32_t reserved GNUNET_PACKED; | ||
63 | |||
64 | /** | ||
65 | * Unique request ID. | ||
66 | */ | ||
67 | uint64_t request_id GNUNET_PACKED; | ||
68 | |||
69 | /* followed by original DNS request (without UDP header) */ | ||
70 | |||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Message from client to DNS service: here is my reply. | ||
76 | */ | ||
77 | struct GNUNET_DNS_Response | ||
78 | { | ||
79 | /** | ||
80 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE | ||
81 | */ | ||
82 | struct GNUNET_MessageHeader header; | ||
83 | |||
84 | /** | ||
85 | * Zero to drop, 1 for no change (no payload), 2 for update (message has payload). | ||
86 | */ | ||
87 | uint32_t drop_flag GNUNET_PACKED; | ||
88 | |||
89 | /** | ||
90 | * Unique request ID. | ||
91 | */ | ||
92 | uint64_t request_id GNUNET_PACKED; | ||
93 | |||
94 | /* followed by original DNS request (without UDP header) */ | ||
95 | |||
96 | }; | ||
97 | |||
98 | |||
99 | GNUNET_NETWORK_STRUCT_END | ||
100 | |||
101 | #endif | ||
diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c index 2e9e73f1c..12253a2e7 100644 --- a/src/dns/dnsparser.c +++ b/src/dns/dnsparser.c | |||
@@ -793,331 +793,4 @@ GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, | |||
793 | return GNUNET_OK; | 793 | return GNUNET_OK; |
794 | } | 794 | } |
795 | 795 | ||
796 | 796 | /* end of dnsparser.c */ | |
797 | |||
798 | |||
799 | |||
800 | |||
801 | |||
802 | |||
803 | |||
804 | |||
805 | |||
806 | |||
807 | |||
808 | |||
809 | |||
810 | |||
811 | |||
812 | |||
813 | |||
814 | |||
815 | |||
816 | |||
817 | |||
818 | |||
819 | |||
820 | |||
821 | |||
822 | |||
823 | |||
824 | |||
825 | /* legacy code follows */ | ||
826 | |||
827 | /** | ||
828 | * Parse a name from DNS to a normal .-delimited, 0-terminated string. | ||
829 | * | ||
830 | * @param d The destination of the name. Should have at least 255 bytes allocated. | ||
831 | * @param src The DNS-Packet | ||
832 | * @param idx The offset inside the Packet from which on the name should be read | ||
833 | * @returns The offset of the first unparsed byte (the byte right behind the name) | ||
834 | */ | ||
835 | static unsigned int | ||
836 | parse_dns_name (char *d, const unsigned char *src, unsigned short idx) | ||
837 | { /*{{{ */ | ||
838 | char *dest = d; | ||
839 | |||
840 | int len = src[idx++]; | ||
841 | |||
842 | while (len != 0) | ||
843 | { | ||
844 | if (len & 0xC0) | ||
845 | { /* Compressed name, offset in this and the next octet */ | ||
846 | unsigned short offset = ((len & 0x3F) << 8) | src[idx++]; | ||
847 | |||
848 | parse_dns_name (dest, src, offset - 12); /* 12 for the Header of the DNS-Packet, idx starts at 0 which is 12 bytes from the start of the packet */ | ||
849 | return idx; | ||
850 | } | ||
851 | memcpy (dest, src + idx, len); | ||
852 | idx += len; | ||
853 | dest += len; | ||
854 | *dest = '.'; | ||
855 | dest++; | ||
856 | len = src[idx++]; | ||
857 | }; | ||
858 | *dest = 0; | ||
859 | |||
860 | return idx; | ||
861 | } | ||
862 | |||
863 | /*}}}*/ | ||
864 | |||
865 | /** | ||
866 | * Parse a complete DNS-Record from raw DNS-data to a struct dns_record | ||
867 | * | ||
868 | * @param data The DNS-data | ||
869 | * @param dst Pointer to count pointers; individual pointers will be allocated | ||
870 | * @param count Number of records to parse | ||
871 | * @param idx The offset inside the Packet from which on the name should be read | ||
872 | * @returns The offset of the first unparsed byte (the byte right behind the last record) | ||
873 | */ | ||
874 | static unsigned short | ||
875 | parse_dns_record (unsigned char *data, /*{{{ */ | ||
876 | struct dns_record **dst, unsigned short count, | ||
877 | unsigned short idx) | ||
878 | { | ||
879 | int i; | ||
880 | unsigned short _idx; | ||
881 | |||
882 | for (i = 0; i < count; i++) | ||
883 | { | ||
884 | dst[i] = GNUNET_malloc (sizeof (struct dns_record)); | ||
885 | dst[i]->name = alloca (255); // see RFC1035, no name can be longer than this. | ||
886 | char *name = dst[i]->name; | ||
887 | |||
888 | _idx = parse_dns_name (name, data, idx); | ||
889 | dst[i]->namelen = _idx - idx; | ||
890 | |||
891 | dst[i]->name = GNUNET_malloc (dst[i]->namelen); | ||
892 | memcpy (dst[i]->name, name, dst[i]->namelen); | ||
893 | |||
894 | idx = _idx; | ||
895 | |||
896 | dst[i]->type = *((unsigned short *) (data + idx)); | ||
897 | idx += 2; | ||
898 | dst[i]->class = *((unsigned short *) (data + idx)); | ||
899 | idx += 2; | ||
900 | dst[i]->ttl = *((unsigned int *) (data + idx)); | ||
901 | idx += 4; | ||
902 | dst[i]->data_len = *((unsigned short *) (data + idx)); | ||
903 | idx += 2; | ||
904 | dst[i]->data = GNUNET_malloc (ntohs (dst[i]->data_len)); | ||
905 | memcpy (dst[i]->data, data + idx, ntohs (dst[i]->data_len)); | ||
906 | idx += ntohs (dst[i]->data_len); | ||
907 | } | ||
908 | return idx; | ||
909 | } /*}}} */ | ||
910 | |||
911 | /** | ||
912 | * Parse a raw DNS-Packet into an usable struct | ||
913 | */ | ||
914 | struct dns_pkt_parsed * | ||
915 | parse_dns_packet (struct dns_pkt *pkt) | ||
916 | { /*{{{ */ | ||
917 | struct dns_pkt_parsed *ppkt = GNUNET_malloc (sizeof (struct dns_pkt_parsed)); | ||
918 | |||
919 | memcpy (&ppkt->s, &pkt->s, sizeof pkt->s); | ||
920 | |||
921 | unsigned short qdcount = ntohs (ppkt->s.qdcount); | ||
922 | unsigned short ancount = ntohs (ppkt->s.ancount); | ||
923 | unsigned short nscount = ntohs (ppkt->s.nscount); | ||
924 | unsigned short arcount = ntohs (ppkt->s.arcount); | ||
925 | |||
926 | ppkt->queries = GNUNET_malloc (qdcount * sizeof (struct dns_query *)); | ||
927 | ppkt->answers = GNUNET_malloc (ancount * sizeof (struct dns_record *)); | ||
928 | ppkt->nameservers = GNUNET_malloc (nscount * sizeof (struct dns_record *)); | ||
929 | ppkt->additional = GNUNET_malloc (arcount * sizeof (struct dns_record *)); | ||
930 | |||
931 | unsigned short idx = 0, _idx; /* This keeps track how far we have parsed the data */ | ||
932 | |||
933 | /* Parse the Query */ | ||
934 | int i; | ||
935 | |||
936 | for (i = 0; i < qdcount; i++) | ||
937 | { /*{{{ */ | ||
938 | ppkt->queries[i] = GNUNET_malloc (sizeof (struct dns_query)); | ||
939 | char *name = alloca (255); /* see RFC1035, it can't be more than this. */ | ||
940 | |||
941 | _idx = parse_dns_name (name, pkt->data, idx); | ||
942 | ppkt->queries[i]->namelen = _idx - idx; | ||
943 | idx = _idx; | ||
944 | |||
945 | ppkt->queries[i]->name = GNUNET_malloc (ppkt->queries[i]->namelen); | ||
946 | memcpy (ppkt->queries[i]->name, name, ppkt->queries[i]->namelen); | ||
947 | |||
948 | ppkt->queries[i]->qtype = *((unsigned short *) (pkt->data + idx)); | ||
949 | idx += 2; | ||
950 | ppkt->queries[i]->qclass = *((unsigned short *) (pkt->data + idx)); | ||
951 | idx += 2; | ||
952 | } | ||
953 | /*}}} */ | ||
954 | idx = parse_dns_record (pkt->data, ppkt->answers, ancount, idx); | ||
955 | idx = parse_dns_record (pkt->data, ppkt->nameservers, nscount, idx); | ||
956 | idx = parse_dns_record (pkt->data, ppkt->additional, arcount, idx); | ||
957 | return ppkt; | ||
958 | } /*}}} */ | ||
959 | |||
960 | static void | ||
961 | unparse_dns_name (char *dest, char *src, size_t len) | ||
962 | { | ||
963 | char *b = dest; | ||
964 | char cnt = 0; | ||
965 | |||
966 | dest++; | ||
967 | while (*src != 0) | ||
968 | { | ||
969 | while (*src != '.' && *src != 0) | ||
970 | { | ||
971 | *dest = *src; | ||
972 | src++; | ||
973 | dest++; | ||
974 | cnt++; | ||
975 | } | ||
976 | *b = cnt; | ||
977 | cnt = 0; | ||
978 | b = dest; | ||
979 | dest++; | ||
980 | src++; | ||
981 | } | ||
982 | *b = 0; | ||
983 | } | ||
984 | |||
985 | struct dns_pkt * | ||
986 | unparse_dns_packet (struct dns_pkt_parsed *ppkt) | ||
987 | { | ||
988 | size_t size = sizeof (struct dns_pkt) - 1; | ||
989 | int i; | ||
990 | |||
991 | for (i = 0; i < ntohs (ppkt->s.qdcount); i++) | ||
992 | size += ppkt->queries[i]->namelen + 1; | ||
993 | |||
994 | for (i = 0; i < ntohs (ppkt->s.ancount); i++) | ||
995 | { | ||
996 | size += ppkt->answers[i]->namelen + 1; | ||
997 | size += ppkt->answers[i]->data_len; | ||
998 | } | ||
999 | for (i = 0; i < ntohs (ppkt->s.nscount); i++) | ||
1000 | { | ||
1001 | size += ppkt->nameservers[i]->namelen + 1; | ||
1002 | size += ppkt->nameservers[i]->data_len; | ||
1003 | } | ||
1004 | for (i = 0; i < ntohs (ppkt->s.arcount); i++) | ||
1005 | { | ||
1006 | size += ppkt->additional[i]->namelen + 1; | ||
1007 | size += ppkt->additional[i]->data_len; | ||
1008 | } | ||
1009 | |||
1010 | size += | ||
1011 | 4 * ntohs (ppkt->s.qdcount) + 10 * (ntohs (ppkt->s.ancount) + | ||
1012 | ntohs (ppkt->s.arcount) + | ||
1013 | ntohs (ppkt->s.nscount)); | ||
1014 | |||
1015 | struct dns_pkt *pkt = GNUNET_malloc (size); | ||
1016 | char *pkt_c = (char *) pkt; | ||
1017 | |||
1018 | memcpy (&pkt->s, &ppkt->s, sizeof ppkt->s); | ||
1019 | size_t idx = sizeof ppkt->s; | ||
1020 | |||
1021 | for (i = 0; i < ntohs (ppkt->s.qdcount); i++) | ||
1022 | { | ||
1023 | unparse_dns_name (&pkt_c[idx], ppkt->queries[i]->name, | ||
1024 | ppkt->queries[i]->namelen); | ||
1025 | idx += ppkt->queries[i]->namelen; | ||
1026 | struct dns_query_line *d = (struct dns_query_line *) &pkt_c[idx]; | ||
1027 | |||
1028 | d->class = ppkt->queries[i]->qclass; | ||
1029 | d->type = ppkt->queries[i]->qtype; | ||
1030 | idx += sizeof (struct dns_query_line); | ||
1031 | } | ||
1032 | |||
1033 | for (i = 0; i < ntohs (ppkt->s.ancount); i++) | ||
1034 | { | ||
1035 | unparse_dns_name (&pkt_c[idx], ppkt->answers[i]->name, | ||
1036 | ppkt->answers[i]->namelen); | ||
1037 | idx += ppkt->answers[i]->namelen; | ||
1038 | struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx]; | ||
1039 | |||
1040 | r->type = ppkt->answers[i]->type; | ||
1041 | r->class = ppkt->answers[i]->class; | ||
1042 | r->ttl = ppkt->answers[i]->ttl; | ||
1043 | r->data_len = ppkt->answers[i]->data_len; | ||
1044 | idx += sizeof (struct dns_record_line); | ||
1045 | memcpy (&r->data, ppkt->answers[i]->data, ppkt->answers[i]->data_len); | ||
1046 | idx += ppkt->answers[i]->data_len; | ||
1047 | } | ||
1048 | |||
1049 | for (i = 0; i < ntohs (ppkt->s.nscount); i++) | ||
1050 | { | ||
1051 | unparse_dns_name (&pkt_c[idx], ppkt->nameservers[i]->name, | ||
1052 | ppkt->nameservers[i]->namelen); | ||
1053 | idx += ppkt->nameservers[i]->namelen; | ||
1054 | struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx]; | ||
1055 | |||
1056 | r->type = ppkt->nameservers[i]->type; | ||
1057 | r->class = ppkt->nameservers[i]->class; | ||
1058 | r->ttl = ppkt->nameservers[i]->ttl; | ||
1059 | r->data_len = ppkt->nameservers[i]->data_len; | ||
1060 | idx += sizeof (struct dns_record_line); | ||
1061 | memcpy (&r->data, ppkt->nameservers[i]->data, | ||
1062 | ppkt->nameservers[i]->data_len); | ||
1063 | idx += ppkt->nameservers[i]->data_len; | ||
1064 | } | ||
1065 | |||
1066 | for (i = 0; i < ntohs (ppkt->s.arcount); i++) | ||
1067 | { | ||
1068 | unparse_dns_name (&pkt_c[idx], ppkt->additional[i]->name, | ||
1069 | ppkt->additional[i]->namelen); | ||
1070 | idx += ppkt->additional[i]->namelen; | ||
1071 | struct dns_record_line *r = (struct dns_record_line *) &pkt_c[idx]; | ||
1072 | |||
1073 | r->type = ppkt->additional[i]->type; | ||
1074 | r->class = ppkt->additional[i]->class; | ||
1075 | r->ttl = ppkt->additional[i]->ttl; | ||
1076 | r->data_len = ppkt->additional[i]->data_len; | ||
1077 | idx += sizeof (struct dns_record_line); | ||
1078 | memcpy (&r->data, ppkt->additional[i]->data, ppkt->additional[i]->data_len); | ||
1079 | idx += ppkt->additional[i]->data_len; | ||
1080 | } | ||
1081 | |||
1082 | return pkt; | ||
1083 | } | ||
1084 | |||
1085 | void | ||
1086 | free_parsed_dns_packet (struct dns_pkt_parsed *ppkt) | ||
1087 | { | ||
1088 | unsigned short qdcount = ntohs (ppkt->s.qdcount); | ||
1089 | unsigned short ancount = ntohs (ppkt->s.ancount); | ||
1090 | unsigned short nscount = ntohs (ppkt->s.nscount); | ||
1091 | unsigned short arcount = ntohs (ppkt->s.arcount); | ||
1092 | |||
1093 | int i; | ||
1094 | |||
1095 | for (i = 0; i < qdcount; i++) | ||
1096 | { | ||
1097 | GNUNET_free (ppkt->queries[i]->name); | ||
1098 | GNUNET_free (ppkt->queries[i]); | ||
1099 | } | ||
1100 | GNUNET_free (ppkt->queries); | ||
1101 | for (i = 0; i < ancount; i++) | ||
1102 | { | ||
1103 | GNUNET_free (ppkt->answers[i]->name); | ||
1104 | GNUNET_free (ppkt->answers[i]->data); | ||
1105 | GNUNET_free (ppkt->answers[i]); | ||
1106 | } | ||
1107 | GNUNET_free (ppkt->answers); | ||
1108 | for (i = 0; i < nscount; i++) | ||
1109 | { | ||
1110 | GNUNET_free (ppkt->nameservers[i]->name); | ||
1111 | GNUNET_free (ppkt->nameservers[i]->data); | ||
1112 | GNUNET_free (ppkt->nameservers[i]); | ||
1113 | } | ||
1114 | GNUNET_free (ppkt->nameservers); | ||
1115 | for (i = 0; i < arcount; i++) | ||
1116 | { | ||
1117 | GNUNET_free (ppkt->additional[i]->name); | ||
1118 | GNUNET_free (ppkt->additional[i]->data); | ||
1119 | GNUNET_free (ppkt->additional[i]); | ||
1120 | } | ||
1121 | GNUNET_free (ppkt->additional); | ||
1122 | GNUNET_free (ppkt); | ||
1123 | } | ||
diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c index 9e86f9c2d..3c7f31985 100644 --- a/src/dns/gnunet-dns-monitor.c +++ b/src/dns/gnunet-dns-monitor.c | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
29 | #include "gnunet_dns_service-new.h" | 29 | #include "gnunet_dns_service.h" |
30 | #include "gnunet_dnsparser_lib.h" | 30 | #include "gnunet_dnsparser_lib.h" |
31 | 31 | ||
32 | /** | 32 | /** |
diff --git a/src/dns/gnunet-dns-redirector.c b/src/dns/gnunet-dns-redirector.c index 4eabc8c79..41667ee9f 100644 --- a/src/dns/gnunet-dns-redirector.c +++ b/src/dns/gnunet-dns-redirector.c | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
29 | #include "gnunet_dns_service-new.h" | 29 | #include "gnunet_dns_service.h" |
30 | #include "gnunet_dnsparser_lib.h" | 30 | #include "gnunet_dnsparser_lib.h" |
31 | 31 | ||
32 | /** | 32 | /** |
diff --git a/src/dns/gnunet-helper-hijack-dns.c b/src/dns/gnunet-helper-hijack-dns.c deleted file mode 100644 index 833bda8ad..000000000 --- a/src/dns/gnunet-helper-hijack-dns.c +++ /dev/null | |||
@@ -1,328 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010, 2011, 2012 Christian Grothoff | ||
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 dns/gnunet-helper-hijack-dns.c | ||
23 | * @brief helper to install firewall rules to hijack all DNS traffic | ||
24 | * and send it to our virtual interface except for DNS traffic | ||
25 | * that originates on the specified port. | ||
26 | * @author Philipp Tölke | ||
27 | * @author Christian Grothoff | ||
28 | * | ||
29 | * This program alters the Linux firewall rules so that DNS traffic | ||
30 | * that ordinarily exits the system can be intercepted and managed by | ||
31 | * a virtual interface. In order to achieve this, DNS traffic is | ||
32 | * marked with the DNS_MARK given in below and re-routed to a custom | ||
33 | * table with the DNS_TABLE ID given below. Systems and | ||
34 | * administrators must take care to not cause conflicts with these | ||
35 | * values (it was deemed safest to hardcode them as passing these | ||
36 | * values as arguments might permit messing with arbitrary firewall | ||
37 | * rules, which would be dangerous). | ||
38 | * | ||
39 | * Note that having this binary SUID is only partially safe: it will | ||
40 | * allow redirecting (and intercepting / mangling) of all DNS traffic | ||
41 | * originating from this system by any user who can create a virtual | ||
42 | * interface (and this is again enabled by other GNUnet SUID | ||
43 | * binaries). Furthermore, even without the ability to create a | ||
44 | * tunnel interface, this code will make it possible to DoS all DNS | ||
45 | * traffic originating from the current system, simply by sending it | ||
46 | * to nowhere. | ||
47 | * | ||
48 | * Naturally, neither of these problems can be helped as this is the | ||
49 | * fundamental purpose of the binary. Certifying that this code is | ||
50 | * "safe" thus only means that it doesn't allow anything else (such | ||
51 | * as local priv. escalation, etc.). | ||
52 | * | ||
53 | * The following list of people have reviewed this code and considered | ||
54 | * it safe (within specifications) since the last modification (if you | ||
55 | * reviewed it, please have your name added to the list): | ||
56 | * | ||
57 | * - Christian Grothoff | ||
58 | */ | ||
59 | #include "platform.h" | ||
60 | |||
61 | /** | ||
62 | * Name and full path of IPTABLES binary. | ||
63 | */ | ||
64 | #define SBIN_IPTABLES "/sbin/iptables" | ||
65 | |||
66 | /** | ||
67 | * Name and full path of IPTABLES binary. | ||
68 | */ | ||
69 | #define SBIN_IP "/sbin/ip" | ||
70 | |||
71 | /** | ||
72 | * Port for DNS traffic. | ||
73 | */ | ||
74 | #define DNS_PORT "53" | ||
75 | |||
76 | /** | ||
77 | * Marker we set for our hijacked DNS traffic. We use GNUnet's | ||
78 | * port (2086) plus the DNS port (53) in HEX to make a 32-bit mark | ||
79 | * (which is hopefully long enough to not collide); so | ||
80 | * 0x08260035 = 136708149 (hopefully unique enough...). | ||
81 | */ | ||
82 | #define DNS_MARK "136708149" | ||
83 | |||
84 | /** | ||
85 | * Table we use for our DNS rules. 0-255 is the range and | ||
86 | * 0, 253, 254 and 255 are already reserved. As this is about | ||
87 | * DNS and as "53" is likely (fingers crossed!) high enough to | ||
88 | * not usually conflict with a normal user's setup, we use 53 | ||
89 | * to give a hint that this has something to do with DNS. | ||
90 | */ | ||
91 | #define DNS_TABLE "53" | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Run the given command and wait for it to complete. | ||
96 | * | ||
97 | * @param file name of the binary to run | ||
98 | * @param cmd command line arguments (as given to 'execv') | ||
99 | * @return 0 on success, 1 on any error | ||
100 | */ | ||
101 | static int | ||
102 | fork_and_exec (const char *file, | ||
103 | char *const cmd[]) | ||
104 | { | ||
105 | int status; | ||
106 | pid_t pid; | ||
107 | pid_t ret; | ||
108 | |||
109 | pid = fork (); | ||
110 | if (-1 == pid) | ||
111 | { | ||
112 | fprintf (stderr, | ||
113 | "fork failed: %s\n", | ||
114 | strerror (errno)); | ||
115 | return 1; | ||
116 | } | ||
117 | if (0 == pid) | ||
118 | { | ||
119 | /* we are the child process */ | ||
120 | (void) execv (file, cmd); | ||
121 | /* can only get here on error */ | ||
122 | fprintf (stderr, | ||
123 | "exec `%s' failed: %s\n", | ||
124 | file, | ||
125 | strerror (errno)); | ||
126 | _exit (1); | ||
127 | } | ||
128 | /* keep running waitpid as long as the only error we get is 'EINTR' */ | ||
129 | while ( (-1 == (ret = waitpid (pid, &status, 0))) && | ||
130 | (errno == EINTR) ); | ||
131 | if (-1 == ret) | ||
132 | { | ||
133 | fprintf (stderr, | ||
134 | "waitpid failed: %s\n", | ||
135 | strerror (errno)); | ||
136 | return 1; | ||
137 | } | ||
138 | if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) | ||
139 | return 1; | ||
140 | /* child process completed and returned success, we're happy */ | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | |||
145 | /** | ||
146 | * Main function of "gnunet-helper-hijack-dns". | ||
147 | * Use "-d" as the first argument to remove the firewall rules. | ||
148 | * The other arguments are the DNS source port to NOT affect | ||
149 | * by the rules, followed by the name of the virtual interface | ||
150 | * to redirect all of the remaining DNS traffic to. | ||
151 | * | ||
152 | * @param argc number of arguments | ||
153 | * @param argv ["-d"] PORT VTUN | ||
154 | * @return 0 on success, otherwise code indicating type of error: | ||
155 | * 1 wrong number of arguments | ||
156 | * 2 invalid port number | ||
157 | * 3 iptables not executable | ||
158 | * 4 ip not executable | ||
159 | * 8 failed to change routing table, cleanup successfull | ||
160 | * 16-31 failed to undo some changes to routing table | ||
161 | * 31-47 failed to fully change routing table and then might have failed to undo everything | ||
162 | */ | ||
163 | int | ||
164 | main (int argc, char *const*argv) | ||
165 | { | ||
166 | int delete; | ||
167 | unsigned int port; | ||
168 | char *virt_dns; | ||
169 | char localport[6]; | ||
170 | int r; | ||
171 | |||
172 | /* check command-line arguments */ | ||
173 | if (argc < 3) | ||
174 | { | ||
175 | fprintf (stderr, | ||
176 | "Syntax: gnunet-helper-hijack-dns [-d] PORT INTERFACENAME\n"); | ||
177 | return 1; | ||
178 | } | ||
179 | if (0 == strcmp (argv[1], "-d")) | ||
180 | delete = 1; | ||
181 | else | ||
182 | delete = 0; | ||
183 | if (argc != 3 + delete) | ||
184 | { | ||
185 | fprintf (stderr, | ||
186 | "Syntax: gnunet-helper-hijack-dns [-d] PORT INTERFACENAME\n"); | ||
187 | return 1; | ||
188 | } | ||
189 | port = atoi (argv[1 + delete]); | ||
190 | virt_dns = argv[2 + delete]; | ||
191 | if ( (port == 0) || (port >= 65536) ) | ||
192 | { | ||
193 | fprintf (stderr, | ||
194 | "Port `%u' is invalid\n", | ||
195 | port); | ||
196 | return 2; | ||
197 | } | ||
198 | /* verify that the binaries were care about are executable */ | ||
199 | if (0 != access (SBIN_IPTABLES, X_OK)) | ||
200 | { | ||
201 | fprintf (stderr, | ||
202 | "`%s' is not executable: %s\n", | ||
203 | SBIN_IPTABLES, | ||
204 | strerror (errno)); | ||
205 | return 3; | ||
206 | } | ||
207 | if (0 != access (SBIN_IP, X_OK)) | ||
208 | { | ||
209 | fprintf (stderr, | ||
210 | "`%s' is not executable: %s\n", | ||
211 | SBIN_IP, | ||
212 | strerror (errno)); | ||
213 | return 4; | ||
214 | } | ||
215 | |||
216 | /* print port number to string for command-line use*/ | ||
217 | (void) snprintf (localport, | ||
218 | sizeof (localport), | ||
219 | "%u", | ||
220 | port); | ||
221 | |||
222 | /* update routing tables -- this is why we are SUID! */ | ||
223 | if (! delete) | ||
224 | { | ||
225 | /* Forward everything from the given local port (with destination | ||
226 | to port 53, and only for UDP) without hijacking */ | ||
227 | { | ||
228 | char *const mangle_args[] = | ||
229 | { | ||
230 | "iptables", "-t", "mangle", "-I", "OUTPUT", "1", "-p", | ||
231 | "udp", "--sport", localport, "--dport", DNS_PORT, "-j", | ||
232 | "ACCEPT", NULL | ||
233 | }; | ||
234 | if (0 != fork_and_exec (SBIN_IPTABLES, mangle_args)) | ||
235 | goto cleanup_mangle_1; | ||
236 | } | ||
237 | /* Mark all of the other DNS traffic using our mark DNS_MARK */ | ||
238 | { | ||
239 | char *const mark_args[] = | ||
240 | { | ||
241 | "iptables", "-t", "mangle", "-I", "OUTPUT", DNS_TABLE, "-p", | ||
242 | "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, | ||
243 | NULL | ||
244 | }; | ||
245 | if (0 != fork_and_exec (SBIN_IPTABLES, mark_args)) | ||
246 | goto cleanup_mark_2; | ||
247 | } | ||
248 | /* Forward all marked DNS traffic to our DNS_TABLE */ | ||
249 | { | ||
250 | char *const forward_args[] = | ||
251 | { | ||
252 | "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
253 | }; | ||
254 | if (0 != fork_and_exec (SBIN_IP, forward_args)) | ||
255 | goto cleanup_forward_3; | ||
256 | } | ||
257 | /* Finally, add rule in our forwarding table to pass to our virtual interface */ | ||
258 | { | ||
259 | char *const route_args[] = | ||
260 | { | ||
261 | "ip", "route", "add", "default", "via", virt_dns, | ||
262 | "table", DNS_TABLE, NULL | ||
263 | }; | ||
264 | if (0 != fork_and_exec (SBIN_IP, route_args)) | ||
265 | goto cleanup_route_4; | ||
266 | } | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | r = 0; | ||
271 | /* delete or clean-up-on-error case */ | ||
272 | cleanup_route_4: | ||
273 | { | ||
274 | char *const route_clean_args[] = | ||
275 | { | ||
276 | "ip", "route", "del", "default", "via", virt_dns, | ||
277 | "table", DNS_TABLE, NULL | ||
278 | }; | ||
279 | if (0 != fork_and_exec (SBIN_IP, route_clean_args)) | ||
280 | r += 1; | ||
281 | } | ||
282 | cleanup_forward_3: | ||
283 | { | ||
284 | char *const forward_clean_args[] = | ||
285 | { | ||
286 | "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
287 | }; | ||
288 | if (0 != fork_and_exec (SBIN_IP, forward_clean_args)) | ||
289 | r += 2; | ||
290 | } | ||
291 | cleanup_mark_2: | ||
292 | { | ||
293 | char *const mark_clean_args[] = | ||
294 | { | ||
295 | "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
296 | "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL | ||
297 | }; | ||
298 | if (0 != fork_and_exec (SBIN_IPTABLES, mark_clean_args)) | ||
299 | r += 4; | ||
300 | } | ||
301 | cleanup_mangle_1: | ||
302 | { | ||
303 | char *const mangle_clean_args[] = | ||
304 | { | ||
305 | "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
306 | "--sport", localport, "--dport", DNS_PORT, "-j", "ACCEPT", | ||
307 | NULL | ||
308 | }; | ||
309 | if (0 != fork_and_exec (SBIN_IPTABLES, mangle_clean_args)) | ||
310 | r += 8; | ||
311 | } | ||
312 | if (r != 0) | ||
313 | { | ||
314 | if (delete) | ||
315 | return 16 + r; /* failed to delete */ | ||
316 | return 32 + r; /* first failed to install, then also failed to clean up! */ | ||
317 | } | ||
318 | if (! delete) | ||
319 | { | ||
320 | /* got here via goto to clean up handler, failed to install, succeeded with clean up */ | ||
321 | return 8; | ||
322 | } | ||
323 | } | ||
324 | /* success ! */ | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* end of gnunet-helper-hijack-dns.c */ | ||
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c index c0e7e56ff..764ede782 100644 --- a/src/dns/gnunet-service-dns.c +++ b/src/dns/gnunet-service-dns.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009 Christian Grothoff (and other contributing authors) | 3 | (C) 2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -20,119 +20,177 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file dns/gnunet-service-dns.c | 22 | * @file dns/gnunet-service-dns.c |
23 | * @author Philipp Toelke | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_getopt_lib.h" | 26 | #include "gnunet_util_lib.h" |
27 | #include "gnunet_service_lib.h" | 27 | #include "gnunet_constants.h" |
28 | #include <gnunet_constants.h> | ||
29 | #include "gnunet_network_lib.h" | ||
30 | #include "gnunet_os_lib.h" | ||
31 | #include "gnunet_dns_service.h" | ||
32 | #include "gnunet_connection_lib.h" | ||
33 | #include "gnunet_protocols.h" | 28 | #include "gnunet_protocols.h" |
34 | #include "gnunet_applications.h" | ||
35 | #include "gnunet_container_lib.h" | ||
36 | #include "gnunet_dnsparser_lib.h" | ||
37 | #include "gnunet_dht_service.h" | ||
38 | #include "gnunet_block_lib.h" | ||
39 | #include "block_dns.h" | ||
40 | #include "gnunet_crypto_lib.h" | ||
41 | #include "gnunet_mesh_service.h" | ||
42 | #include "gnunet_signatures.h" | 29 | #include "gnunet_signatures.h" |
43 | |||
44 | #include "dns.h" | 30 | #include "dns.h" |
31 | #include "gnunet_dns_service.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include "tcpip_tun.h" | ||
45 | 34 | ||
46 | /** | 35 | #ifndef IPVERSION |
47 | * A structure containing a mapping from network-byte-ordered DNS-id (16 bit) to | 36 | #define IPVERSION 4 |
48 | * some information needed to handle this query | 37 | #endif |
49 | * | ||
50 | * It currently allocates at least | ||
51 | * (1 + machine-width + machine-width + 32 + 32 + 16 + machine-width + 8) * 65536 bit | ||
52 | * = 17 MiB on 64 bit. | ||
53 | * = 11 MiB on 32 bit. | ||
54 | */ | ||
55 | static struct | ||
56 | { | ||
57 | unsigned valid:1; | ||
58 | struct GNUNET_SERVER_Client *client; | ||
59 | struct GNUNET_MESH_Tunnel *tunnel; | ||
60 | char local_ip[16]; | ||
61 | char remote_ip[16]; | ||
62 | char addrlen; | ||
63 | uint16_t local_port; | ||
64 | char *name; | ||
65 | uint8_t namelen; | ||
66 | uint16_t qtype; | ||
67 | } query_states[UINT16_MAX + 1]; | ||
68 | 38 | ||
69 | /** | 39 | /** |
70 | * A struct used to give more than one value as | 40 | * Phases each request goes through. |
71 | * closure to receive_dht | ||
72 | */ | 41 | */ |
73 | struct receive_dht_cls | 42 | enum RequestPhase |
74 | { | 43 | { |
75 | uint16_t id; | 44 | /** |
76 | struct GNUNET_DHT_GetHandle *handle; | 45 | * Request has just been received. |
77 | }; | 46 | */ |
47 | RP_INIT, | ||
78 | 48 | ||
79 | struct tunnel_notify_queue | 49 | /** |
80 | { | 50 | * Showing the request to all monitor clients. If |
81 | struct tunnel_notify_queue *next; | 51 | * client list is empty, will enter QUERY phase. |
82 | struct tunnel_notify_queue *prev; | 52 | */ |
83 | void *cls; | 53 | RP_REQUEST_MONITOR, |
84 | size_t len; | ||
85 | GNUNET_CONNECTION_TransmitReadyNotify cb; | ||
86 | }; | ||
87 | 54 | ||
88 | struct tunnel_state | 55 | /** |
89 | { | 56 | * Showing the request to PRE-RESOLUTION clients to find an answer. |
90 | struct tunnel_notify_queue *head, *tail; | 57 | * If client list is empty, will trigger global DNS request. |
91 | struct GNUNET_MESH_TransmitHandle *th; | 58 | */ |
59 | RP_QUERY, | ||
60 | |||
61 | /** | ||
62 | * Global Internet query is now pending. | ||
63 | */ | ||
64 | RP_INTERNET_DNS, | ||
65 | |||
66 | /** | ||
67 | * Client (or global DNS request) has resulted in a response. | ||
68 | * Forward to all POST-RESOLUTION clients. If client list is empty, | ||
69 | * will enter RESPONSE_MONITOR phase. | ||
70 | */ | ||
71 | RP_MODIFY, | ||
72 | |||
73 | /** | ||
74 | * Showing the request to all monitor clients. If | ||
75 | * client list is empty, give the result to the hijacker (and be done). | ||
76 | */ | ||
77 | RP_RESPONSE_MONITOR, | ||
78 | |||
79 | /** | ||
80 | * Some client has told us to drop the request. | ||
81 | */ | ||
82 | RP_DROP | ||
92 | }; | 83 | }; |
93 | 84 | ||
94 | 85 | ||
95 | struct answer_packet_list | 86 | /** |
87 | * Entry we keep for each client. | ||
88 | */ | ||
89 | struct ClientRecord | ||
96 | { | 90 | { |
97 | struct answer_packet_list *next; | 91 | /** |
98 | struct answer_packet_list *prev; | 92 | * Kept in doubly-linked list. |
93 | */ | ||
94 | struct ClientRecord *next; | ||
95 | |||
96 | /** | ||
97 | * Kept in doubly-linked list. | ||
98 | */ | ||
99 | struct ClientRecord *prev; | ||
100 | |||
101 | /** | ||
102 | * Handle to the client. | ||
103 | */ | ||
99 | struct GNUNET_SERVER_Client *client; | 104 | struct GNUNET_SERVER_Client *client; |
100 | struct answer_packet pkt; | 105 | |
106 | /** | ||
107 | * Flags for the client. | ||
108 | */ | ||
109 | enum GNUNET_DNS_Flags flags; | ||
110 | |||
101 | }; | 111 | }; |
102 | 112 | ||
103 | GNUNET_NETWORK_STRUCT_BEGIN | 113 | |
104 | struct tunnel_cls | 114 | /** |
115 | * Entry we keep for each active request. | ||
116 | */ | ||
117 | struct RequestRecord | ||
105 | { | 118 | { |
106 | struct GNUNET_MESH_Tunnel *tunnel; | ||
107 | struct GNUNET_MessageHeader hdr; | ||
108 | struct dns_pkt dns; | ||
109 | }; | ||
110 | GNUNET_NETWORK_STRUCT_END | ||
111 | 119 | ||
112 | struct tunnel_cls *remote_pending[UINT16_MAX]; | 120 | /** |
121 | * List of clients that still need to see this request (each entry | ||
122 | * is set to NULL when the client is done). | ||
123 | */ | ||
124 | struct ClientRecord **client_wait_list; | ||
113 | 125 | ||
126 | /** | ||
127 | * Payload of the UDP packet (the UDP payload), can be either query | ||
128 | * or already the response. | ||
129 | */ | ||
130 | char *payload; | ||
114 | 131 | ||
115 | static struct GNUNET_MESH_Handle *mesh_handle; | 132 | /** |
133 | * Source address of the original request (for sending response). | ||
134 | */ | ||
135 | struct sockaddr_storage src_addr; | ||
136 | |||
137 | /** | ||
138 | * Destination address of the original request (for potential use as exit). | ||
139 | */ | ||
140 | struct sockaddr_storage dst_addr; | ||
141 | |||
142 | /** | ||
143 | * ID of this request, also basis for hashing. Lowest 16 bit will | ||
144 | * be our message ID when doing a global DNS request and our index | ||
145 | * into the 'requests' array. | ||
146 | */ | ||
147 | uint64_t request_id; | ||
148 | |||
149 | /** | ||
150 | * Number of bytes in payload. | ||
151 | */ | ||
152 | size_t payload_length; | ||
153 | |||
154 | /** | ||
155 | * Length of the client wait list. | ||
156 | */ | ||
157 | unsigned int client_wait_list_length; | ||
158 | |||
159 | /** | ||
160 | * In which phase this this request? | ||
161 | */ | ||
162 | enum RequestPhase phase; | ||
163 | |||
164 | }; | ||
116 | 165 | ||
117 | static struct GNUNET_CONNECTION_TransmitHandle *server_notify; | ||
118 | 166 | ||
119 | /** | 167 | /** |
120 | * The UDP-Socket through which DNS-Resolves will be sent if they are not to be | 168 | * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be |
121 | * sent through gnunet. The port of this socket will not be hijacked. | 169 | * sent through gnunet. The port of this socket will not be hijacked. |
122 | */ | 170 | */ |
123 | static struct GNUNET_NETWORK_Handle *dnsout; | 171 | static struct GNUNET_NETWORK_Handle *dnsout4; |
124 | 172 | ||
173 | /** | ||
174 | * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be | ||
175 | * sent through gnunet. The port of this socket will not be hijacked. | ||
176 | */ | ||
125 | static struct GNUNET_NETWORK_Handle *dnsout6; | 177 | static struct GNUNET_NETWORK_Handle *dnsout6; |
126 | 178 | ||
127 | /** | 179 | /** |
128 | * The port bound to the socket dnsout | 180 | * Task for reading from dnsout4. |
129 | */ | 181 | */ |
130 | static unsigned short dnsoutport; | 182 | static GNUNET_SCHEDULER_TaskIdentifier read4_task; |
131 | 183 | ||
132 | /** | 184 | /** |
133 | * A handle to the DHT-Service | 185 | * Task for reading from dnsout6. |
134 | */ | 186 | */ |
135 | static struct GNUNET_DHT_Handle *dht; | 187 | static GNUNET_SCHEDULER_TaskIdentifier read6_task; |
188 | |||
189 | /** | ||
190 | * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind | ||
191 | * both sockets to the same port. | ||
192 | */ | ||
193 | static uint16_t dnsoutport; | ||
136 | 194 | ||
137 | /** | 195 | /** |
138 | * The configuration to use | 196 | * The configuration to use |
@@ -140,1538 +198,975 @@ static struct GNUNET_DHT_Handle *dht; | |||
140 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 198 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
141 | 199 | ||
142 | /** | 200 | /** |
143 | * A list of DNS-Responses that have to be sent to the requesting client | 201 | * Statistics. |
144 | */ | 202 | */ |
145 | static struct answer_packet_list *head; | 203 | static struct GNUNET_STATISTICS_Handle *stats; |
146 | 204 | ||
147 | /** | 205 | /** |
148 | * The tail of the list of DNS-responses | 206 | * Handle to DNS hijacker helper process ("gnunet-helper-dns"). |
149 | */ | 207 | */ |
150 | static struct answer_packet_list *tail; | 208 | static struct GNUNET_HELPER_Handle *hijacker; |
151 | 209 | ||
210 | /** | ||
211 | * Command-line arguments we are giving to the hijacker process. | ||
212 | */ | ||
213 | static char *helper_argv[8]; | ||
152 | 214 | ||
153 | static size_t | 215 | /** |
154 | send_answer (void *cls, size_t size, void *buf); | 216 | * Head of DLL of clients we consult. |
217 | */ | ||
218 | static struct ClientRecord *clients_head; | ||
155 | 219 | ||
156 | static void | 220 | /** |
157 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | 221 | * Tail of DLL of clients we consult. |
158 | { | 222 | */ |
159 | if (NULL == head) | 223 | static struct ClientRecord *clients_tail; |
160 | return; | ||
161 | 224 | ||
162 | if (head->client == client) | 225 | /** |
163 | { | 226 | * Our notification context. |
164 | GNUNET_CONNECTION_notify_transmit_ready_cancel (server_notify); | 227 | */ |
165 | server_notify = | 228 | static struct GNUNET_SERVER_NotificationContext *nc; |
166 | GNUNET_SERVER_notify_transmit_ready (head->next->client, | ||
167 | ntohs (head->next->pkt.hdr.size), | ||
168 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
169 | &send_answer, NULL); | ||
170 | } | ||
171 | 229 | ||
172 | struct answer_packet_list *element = head; | 230 | /** |
231 | * Array of all open requests. | ||
232 | */ | ||
233 | static struct RequestRecord requests[UINT16_MAX + 1]; | ||
173 | 234 | ||
174 | while (element != NULL) | 235 | /** |
175 | { | 236 | * Generator for unique request IDs. |
176 | if (element->client == client) | 237 | */ |
177 | { | 238 | static uint64_t request_id_gen; |
178 | GNUNET_SERVER_client_drop (client); | ||
179 | GNUNET_CONTAINER_DLL_remove (head, tail, element); | ||
180 | struct answer_packet_list *t = element; | ||
181 | 239 | ||
182 | element = element->next; | ||
183 | GNUNET_free (t); | ||
184 | } | ||
185 | else | ||
186 | element = element->next; | ||
187 | } | ||
188 | } | ||
189 | 240 | ||
190 | /** | 241 | /** |
191 | * Hijack all outgoing DNS-Traffic but for traffic leaving "our" port. | 242 | * We're done processing a DNS request, free associated memory. |
243 | * | ||
244 | * @param rr request to clean up | ||
192 | */ | 245 | */ |
193 | static void | 246 | static void |
194 | hijack (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tc) | 247 | cleanup_rr (struct RequestRecord *rr) |
195 | { | 248 | { |
196 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 249 | GNUNET_free_non_null (rr->payload); |
197 | return; | 250 | rr->payload = NULL; |
198 | 251 | rr->payload_length = 0; | |
199 | if (0 == dnsoutport) | 252 | GNUNET_array_grow (rr->client_wait_list, |
200 | { | 253 | rr->client_wait_list_length, |
201 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 254 | 0); |
202 | "Delaying the hijacking, port is still %d!\n", dnsoutport); | ||
203 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | ||
204 | return; | ||
205 | } | ||
206 | |||
207 | char port_s[6]; | ||
208 | char *virt_dns; | ||
209 | struct GNUNET_OS_Process *proc; | ||
210 | |||
211 | if (GNUNET_SYSERR == | ||
212 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", &virt_dns)) | ||
213 | { | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
215 | "No entry 'VIRTDNS' in configuration!\n"); | ||
216 | exit (1); | ||
217 | } | ||
218 | |||
219 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacking, port is %d\n", dnsoutport); | ||
220 | snprintf (port_s, 6, "%d", dnsoutport); | ||
221 | if (NULL != | ||
222 | (proc = | ||
223 | GNUNET_OS_start_process (NULL, NULL, "gnunet-helper-hijack-dns", | ||
224 | "gnunet-hijack-dns", port_s, virt_dns, NULL))) | ||
225 | { | ||
226 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); | ||
227 | GNUNET_OS_process_close (proc); | ||
228 | } | ||
229 | GNUNET_free (virt_dns); | ||
230 | } | ||
231 | |||
232 | static void * | ||
233 | new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
234 | const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, | ||
235 | const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) | ||
236 | { | ||
237 | struct tunnel_state *s = GNUNET_malloc (sizeof *s); | ||
238 | |||
239 | s->head = NULL; | ||
240 | s->tail = NULL; | ||
241 | s->th = NULL; | ||
242 | return s; | ||
243 | } | 255 | } |
244 | 256 | ||
245 | static void | ||
246 | clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, | ||
247 | void *tunnel_ctx) | ||
248 | { | ||
249 | GNUNET_free (tunnel_ctx); | ||
250 | } | ||
251 | 257 | ||
252 | /** | 258 | /** |
253 | * Delete the hijacking-routes | 259 | * Task run during shutdown. |
260 | * | ||
261 | * @param cls unused | ||
262 | * @param tc unused | ||
254 | */ | 263 | */ |
255 | static void | 264 | static void |
256 | unhijack (unsigned short port) | 265 | cleanup_task (void *cls GNUNET_UNUSED, |
266 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
257 | { | 267 | { |
258 | char port_s[6]; | 268 | unsigned int i; |
259 | char *virt_dns; | ||
260 | struct GNUNET_OS_Process *proc; | ||
261 | 269 | ||
262 | if (GNUNET_SYSERR == | 270 | GNUNET_HELPER_stop (hijacker); |
263 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", &virt_dns)) | 271 | hijacker = NULL; |
272 | for (i=0;i<8;i++) | ||
273 | GNUNET_free_non_null (helper_argv[i]); | ||
274 | if (NULL != dnsout4) | ||
264 | { | 275 | { |
265 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 276 | GNUNET_NETWORK_socket_close (dnsout4); |
266 | "No entry 'VIRTDNS' in configuration!\n"); | 277 | dnsout4 = NULL; |
267 | exit (1); | ||
268 | } | 278 | } |
269 | 279 | if (GNUNET_SCHEDULER_NO_TASK != read4_task) | |
270 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unHijacking, port is %d\n", port); | ||
271 | snprintf (port_s, 6, "%d", port); | ||
272 | if (NULL != | ||
273 | (proc = | ||
274 | GNUNET_OS_start_process (NULL, NULL, "gnunet-helper-hijack-dns", | ||
275 | "gnunet-hijack-dns", "-d", port_s, virt_dns, | ||
276 | NULL))) | ||
277 | { | 280 | { |
278 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); | 281 | GNUNET_SCHEDULER_cancel (read4_task); |
279 | GNUNET_OS_process_close (proc); | 282 | read4_task = GNUNET_SCHEDULER_NO_TASK; |
280 | } | 283 | } |
281 | GNUNET_free (virt_dns); | 284 | if (NULL != dnsout6) |
282 | } | ||
283 | |||
284 | /** | ||
285 | * Send the DNS-Response to the client. Gets called via the notify_transmit_ready- | ||
286 | * system. | ||
287 | */ | ||
288 | static size_t | ||
289 | send_answer (void *cls, size_t size, void *buf) | ||
290 | { | ||
291 | server_notify = NULL; | ||
292 | struct answer_packet_list *query = head; | ||
293 | size_t len = ntohs (query->pkt.hdr.size); | ||
294 | |||
295 | GNUNET_assert (len <= size); | ||
296 | |||
297 | memcpy (buf, &query->pkt.hdr, len); | ||
298 | |||
299 | GNUNET_CONTAINER_DLL_remove (head, tail, query); | ||
300 | |||
301 | /* When more data is to be sent, reschedule */ | ||
302 | if (head != NULL) | ||
303 | server_notify = | ||
304 | GNUNET_SERVER_notify_transmit_ready (head->client, | ||
305 | ntohs (head->pkt.hdr.size), | ||
306 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
307 | &send_answer, NULL); | ||
308 | |||
309 | GNUNET_SERVER_client_drop (query->client); | ||
310 | GNUNET_free (query); | ||
311 | return len; | ||
312 | } | ||
313 | |||
314 | |||
315 | static size_t | ||
316 | mesh_send_response (void *cls, size_t size, void *buf) | ||
317 | { | ||
318 | GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); | ||
319 | struct GNUNET_MessageHeader *hdr = buf; | ||
320 | uint32_t *sz = cls; | ||
321 | struct GNUNET_MESH_Tunnel **tunnel = (struct GNUNET_MESH_Tunnel **) (sz + 1); | ||
322 | struct dns_pkt *dns = (struct dns_pkt *) (tunnel + 1); | ||
323 | |||
324 | GNUNET_MESH_tunnel_set_data (*tunnel, NULL); | ||
325 | |||
326 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_ANSWER_DNS); | ||
327 | hdr->size = htons (*sz + sizeof (struct GNUNET_MessageHeader)); | ||
328 | |||
329 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
330 | "Sending response, size=%d, sz=%d, sz+hdr=%d\n", size, *sz, | ||
331 | *sz + sizeof (struct GNUNET_MessageHeader)); | ||
332 | |||
333 | GNUNET_assert (size >= (*sz + sizeof (struct GNUNET_MessageHeader))); | ||
334 | |||
335 | memcpy (hdr + 1, dns, *sz); | ||
336 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
337 | |||
338 | if (NULL != s->head) | ||
339 | { | 285 | { |
340 | struct tunnel_notify_queue *element = s->head; | 286 | GNUNET_NETWORK_socket_close (dnsout6); |
341 | struct tunnel_notify_queue *head = s->head; | 287 | dnsout6 = NULL; |
342 | struct tunnel_notify_queue *tail = s->tail; | ||
343 | |||
344 | GNUNET_CONTAINER_DLL_remove (head, tail, element); | ||
345 | |||
346 | s->th = | ||
347 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
348 | GNUNET_TIME_relative_divide | ||
349 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
350 | (const struct GNUNET_PeerIdentity *) | ||
351 | NULL, element->len, element->cb, | ||
352 | element->cls); | ||
353 | } | 288 | } |
354 | 289 | if (GNUNET_SCHEDULER_NO_TASK != read6_task) | |
355 | GNUNET_free (cls); | ||
356 | |||
357 | return ntohs (hdr->size); | ||
358 | } | ||
359 | |||
360 | static size_t | ||
361 | mesh_send (void *cls, size_t size, void *buf) | ||
362 | { | ||
363 | struct tunnel_cls *cls_ = (struct tunnel_cls *) cls; | ||
364 | |||
365 | GNUNET_MESH_tunnel_set_data (cls_->tunnel, NULL); | ||
366 | |||
367 | GNUNET_assert (cls_->hdr.size <= size); | ||
368 | |||
369 | size = cls_->hdr.size; | ||
370 | cls_->hdr.size = htons (cls_->hdr.size); | ||
371 | |||
372 | memcpy (buf, &cls_->hdr, size); | ||
373 | |||
374 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (cls_->tunnel); | ||
375 | |||
376 | if (NULL != s->head) | ||
377 | { | 290 | { |
378 | struct tunnel_notify_queue *element = s->head; | 291 | GNUNET_SCHEDULER_cancel (read6_task); |
379 | struct tunnel_notify_queue *head = s->head; | 292 | read6_task = GNUNET_SCHEDULER_NO_TASK; |
380 | struct tunnel_notify_queue *tail = s->tail;; | ||
381 | |||
382 | GNUNET_CONTAINER_DLL_remove (head, tail, element); | ||
383 | |||
384 | s->th = | ||
385 | GNUNET_MESH_notify_transmit_ready (cls_->tunnel, GNUNET_NO, 42, | ||
386 | GNUNET_TIME_relative_divide | ||
387 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
388 | (const struct GNUNET_PeerIdentity *) | ||
389 | NULL, element->len, element->cb, | ||
390 | element->cls); | ||
391 | |||
392 | GNUNET_free (element); | ||
393 | } | 293 | } |
394 | 294 | for (i=0;i<65536;i++) | |
395 | return size; | 295 | cleanup_rr (&requests[i]); |
396 | } | 296 | GNUNET_SERVER_notification_context_destroy (nc); |
397 | 297 | nc = NULL; | |
398 | 298 | if (stats != NULL) | |
399 | static void | ||
400 | mesh_connect (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
401 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
402 | { | ||
403 | if (NULL == peer) | ||
404 | return; | ||
405 | struct tunnel_cls *cls_ = (struct tunnel_cls *) cls; | ||
406 | |||
407 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
408 | "Connected to peer %s, %x, sending query with id %d\n", | ||
409 | GNUNET_i2s (peer), peer, ntohs (cls_->dns.s.id)); | ||
410 | |||
411 | struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (cls_->tunnel); | ||
412 | |||
413 | if (NULL == s->head) | ||
414 | { | ||
415 | s->th = | ||
416 | GNUNET_MESH_notify_transmit_ready (cls_->tunnel, GNUNET_YES, 42, | ||
417 | GNUNET_TIME_UNIT_MINUTES, NULL, | ||
418 | cls_->hdr.size, mesh_send, cls); | ||
419 | |||
420 | } | ||
421 | else | ||
422 | { | 299 | { |
423 | struct tunnel_notify_queue *head = s->head; | 300 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); |
424 | struct tunnel_notify_queue *tail = s->tail; | 301 | stats = NULL; |
425 | |||
426 | struct tunnel_notify_queue *element = | ||
427 | GNUNET_malloc (sizeof (struct tunnel_notify_queue)); | ||
428 | element->cls = cls; | ||
429 | element->len = cls_->hdr.size; | ||
430 | element->cb = mesh_send; | ||
431 | |||
432 | GNUNET_CONTAINER_DLL_insert_tail (head, tail, element); | ||
433 | } | 302 | } |
434 | } | 303 | } |
435 | 304 | ||
436 | 305 | ||
306 | /** | ||
307 | * We're done with some request, finish processing. | ||
308 | * | ||
309 | * @param rr request send to the network or just clean up. | ||
310 | */ | ||
437 | static void | 311 | static void |
438 | send_mesh_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 312 | request_done (struct RequestRecord *rr) |
439 | { | ||
440 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
441 | return; | ||
442 | |||
443 | struct tunnel_cls *cls_ = (struct tunnel_cls *) cls; | ||
444 | |||
445 | struct tunnel_state *s = GNUNET_malloc (sizeof *s); | ||
446 | |||
447 | s->head = NULL; | ||
448 | s->tail = NULL; | ||
449 | s->th = NULL; | ||
450 | |||
451 | cls_->tunnel = | ||
452 | GNUNET_MESH_tunnel_create (mesh_handle, s, mesh_connect, NULL, cls_); | ||
453 | |||
454 | GNUNET_MESH_peer_request_connect_by_type (cls_->tunnel, | ||
455 | GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER); | ||
456 | |||
457 | remote_pending[cls_->dns.s.id] = cls_; | ||
458 | } | ||
459 | |||
460 | static int | ||
461 | receive_mesh_query (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
462 | void **ctx GNUNET_UNUSED, | ||
463 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
464 | const struct GNUNET_MessageHeader *message, | ||
465 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
466 | { | 313 | { |
467 | struct dns_pkt *dns = (struct dns_pkt *) (message + 1); | 314 | struct GNUNET_MessageHeader *hdr; |
468 | 315 | size_t reply_len; | |
469 | struct sockaddr_in dest; | 316 | uint16_t spt; |
470 | 317 | uint16_t dpt; | |
471 | struct dns_pkt_parsed *pdns = parse_dns_packet (dns); | 318 | |
472 | 319 | GNUNET_array_grow (rr->client_wait_list, | |
473 | memset (&dest, 0, sizeof dest); | 320 | rr->client_wait_list_length, |
474 | dest.sin_port = htons (53); | 321 | 0); |
475 | char *dns_resolver; | 322 | if (RP_RESPONSE_MONITOR != rr->phase) |
476 | |||
477 | if (GNUNET_OK != | ||
478 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "EXTERNAL_DNS", | ||
479 | &dns_resolver) || | ||
480 | 1 != inet_pton (AF_INET, dns_resolver, &dest.sin_addr)) | ||
481 | inet_pton (AF_INET, "8.8.8.8", &dest.sin_addr); | ||
482 | |||
483 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Querying for remote, id=%d\n", | ||
484 | ntohs (dns->s.id)); | ||
485 | query_states[dns->s.id].tunnel = tunnel; | ||
486 | query_states[dns->s.id].valid = GNUNET_YES; | ||
487 | |||
488 | int i; | ||
489 | |||
490 | for (i = 0; i < ntohs (pdns->s.qdcount); i++) | ||
491 | { | 323 | { |
492 | if (pdns->queries[i]->qtype == htons (28) || | 324 | /* no response, drop */ |
493 | pdns->queries[i]->qtype == htons (1)) | 325 | cleanup_rr (rr); |
494 | { | 326 | return; |
495 | query_states[dns->s.id].qtype = pdns->queries[i]->qtype; | ||
496 | break; | ||
497 | } | ||
498 | } | ||
499 | free_parsed_dns_packet (pdns); | ||
500 | |||
501 | GNUNET_NETWORK_socket_sendto (dnsout, dns, | ||
502 | ntohs (message->size) - | ||
503 | sizeof (struct GNUNET_MessageHeader), | ||
504 | (struct sockaddr *) &dest, sizeof dest); | ||
505 | |||
506 | return GNUNET_SYSERR; | ||
507 | } | ||
508 | |||
509 | static int | ||
510 | receive_mesh_answer (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
511 | void **ctx GNUNET_UNUSED, | ||
512 | const struct GNUNET_PeerIdentity *sender, | ||
513 | const struct GNUNET_MessageHeader *message, | ||
514 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
515 | { | ||
516 | /* TODo: size check */ | ||
517 | struct dns_pkt *dns = (struct dns_pkt *) (message + 1); | ||
518 | |||
519 | /* They sent us a packet we were not waiting for */ | ||
520 | if (remote_pending[dns->s.id] == NULL || | ||
521 | remote_pending[dns->s.id]->tunnel != tunnel) | ||
522 | return GNUNET_OK; | ||
523 | |||
524 | GNUNET_free (remote_pending[dns->s.id]); | ||
525 | remote_pending[dns->s.id] = NULL; | ||
526 | |||
527 | if (query_states[dns->s.id].valid != GNUNET_YES) | ||
528 | return GNUNET_SYSERR; | ||
529 | query_states[dns->s.id].valid = GNUNET_NO; | ||
530 | |||
531 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
532 | "Received answer from peer %s, dns-id %d\n", GNUNET_i2s (sender), | ||
533 | ntohs (dns->s.id)); | ||
534 | |||
535 | size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[dns->s.id].namelen + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */ | ||
536 | + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */ | ||
537 | |||
538 | struct answer_packet_list *answer = | ||
539 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
540 | sizeof (struct answer_packet)); | ||
541 | |||
542 | answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
543 | answer->pkt.hdr.size = htons (len); | ||
544 | |||
545 | struct dns_pkt_parsed *pdns = parse_dns_packet (dns); | ||
546 | |||
547 | if (ntohs (pdns->s.ancount) < 1) | ||
548 | { | ||
549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer only contains %d answers.\n", | ||
550 | ntohs (pdns->s.ancount)); | ||
551 | free_parsed_dns_packet (pdns); | ||
552 | GNUNET_free (answer); | ||
553 | return GNUNET_OK; | ||
554 | } | ||
555 | |||
556 | int i = 0; | ||
557 | |||
558 | while (i < ntohs (pdns->s.ancount) && ntohs (pdns->answers[i]->type) != 28 && | ||
559 | ntohs (pdns->answers[i]->type) != 1) | ||
560 | { | ||
561 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer contains %d.\n", | ||
562 | ntohs (pdns->answers[i]->type)); | ||
563 | i++; | ||
564 | } | 327 | } |
565 | 328 | ||
566 | if (i >= ntohs (pdns->s.ancount)) | 329 | /* send response via hijacker */ |
330 | reply_len = sizeof (struct GNUNET_MessageHeader); | ||
331 | reply_len += sizeof (struct tun_header); | ||
332 | switch (rr->src_addr.ss_family) | ||
567 | { | 333 | { |
568 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 334 | case AF_INET: |
569 | "Answer does not contain any usable answers.\n"); | 335 | reply_len += sizeof (struct ip4_header); |
570 | free_parsed_dns_packet (pdns); | 336 | break; |
571 | GNUNET_free (answer); | 337 | case AF_INET6: |
572 | return GNUNET_OK; | 338 | reply_len += sizeof (struct ip6_header); |
339 | break; | ||
340 | default: | ||
341 | GNUNET_break (0); | ||
342 | cleanup_rr (rr); | ||
343 | return; | ||
573 | } | 344 | } |
574 | 345 | reply_len += sizeof (struct udp_packet); | |
575 | answer->pkt.addrsize = ntohs (pdns->answers[i]->data_len); | 346 | reply_len += rr->payload_length; |
576 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The first answer has the addrlen %d\n", | 347 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
577 | answer->pkt.addrsize); | ||
578 | memcpy (answer->pkt.addr, pdns->answers[i]->data, | ||
579 | ntohs (pdns->answers[i]->data_len)); | ||
580 | |||
581 | memcpy (answer->pkt.from, query_states[dns->s.id].remote_ip, | ||
582 | query_states[dns->s.id].addrlen); | ||
583 | memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, | ||
584 | query_states[dns->s.id].addrlen); | ||
585 | answer->pkt.addrlen = query_states[dns->s.id].addrlen; | ||
586 | answer->pkt.dst_port = query_states[dns->s.id].local_port; | ||
587 | |||
588 | struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data; | ||
589 | |||
590 | dpkt->s.id = dns->s.id; | ||
591 | dpkt->s.aa = 1; | ||
592 | dpkt->s.qr = 1; | ||
593 | dpkt->s.ra = 1; | ||
594 | dpkt->s.qdcount = htons (1); | ||
595 | dpkt->s.ancount = htons (1); | ||
596 | |||
597 | memcpy (dpkt->data, query_states[dns->s.id].name, | ||
598 | query_states[dns->s.id].namelen); | ||
599 | GNUNET_free (query_states[dns->s.id].name); | ||
600 | query_states[dns->s.id].name = NULL; | ||
601 | |||
602 | struct dns_query_line *dque = | ||
603 | (struct dns_query_line *) (dpkt->data + | ||
604 | (query_states[dns->s.id].namelen)); | ||
605 | |||
606 | struct dns_record_line *drec_data = | ||
607 | (struct dns_record_line *) (dpkt->data + | ||
608 | (query_states[dns->s.id].namelen) + | ||
609 | sizeof (struct dns_query_line) + 2); | ||
610 | if (htons (28) == query_states[dns->s.id].qtype) | ||
611 | { | 348 | { |
612 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE_AAAA; | 349 | /* response too big, drop */ |
613 | dque->type = htons (28); /* AAAA */ | 350 | GNUNET_break (0); /* how can this be? */ |
614 | drec_data->type = htons (28); /* AAAA */ | 351 | cleanup_rr(rr); |
615 | drec_data->data_len = htons (16); | 352 | return; |
616 | } | 353 | } |
617 | else if (htons (1) == query_states[dns->s.id].qtype) | ||
618 | { | 354 | { |
619 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE_A; | 355 | char buf[reply_len]; |
620 | dque->type = htons (1); /* A */ | 356 | size_t off; |
621 | drec_data->type = htons (1); /* A */ | 357 | uint32_t udp_crc_sum; |
622 | drec_data->data_len = htons (4); | ||
623 | } | ||
624 | else | ||
625 | { | ||
626 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "dns-answer with pending qtype = %d\n", | ||
627 | query_states[dns->s.id].qtype); | ||
628 | GNUNET_assert (0); | ||
629 | } | ||
630 | dque->class = htons (1); /* IN */ | ||
631 | |||
632 | char *anname = | ||
633 | (char *) (dpkt->data + (query_states[dns->s.id].namelen) + | ||
634 | sizeof (struct dns_query_line)); | ||
635 | memcpy (anname, "\xc0\x0c", 2); | ||
636 | drec_data->class = htons (1); /* IN */ | ||
637 | |||
638 | drec_data->ttl = pdns->answers[i]->ttl; | ||
639 | 358 | ||
640 | /* Calculate at which offset in the packet the IPv6-Address belongs, it is | 359 | /* first, GNUnet message header */ |
641 | * filled in by the daemon-vpn */ | 360 | hdr = (struct GNUNET_MessageHeader*) buf; |
642 | answer->pkt.addroffset = | 361 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); |
643 | htons ((unsigned short) ((unsigned long) (&drec_data->data) - | 362 | hdr->size = htons ((uint16_t) reply_len); |
644 | (unsigned long) (&answer->pkt))); | 363 | off = sizeof (struct GNUNET_MessageHeader); |
645 | 364 | ||
646 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | 365 | /* first, TUN header */ |
647 | answer->client = query_states[dns->s.id].client; | 366 | { |
367 | struct tun_header tun; | ||
648 | 368 | ||
649 | if (server_notify == NULL) | 369 | tun.flags = htons (0); |
650 | server_notify = | 370 | if (rr->src_addr.ss_family == AF_INET) |
651 | GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client, | 371 | tun.proto = htons (ETH_P_IPV4); |
652 | len, GNUNET_TIME_UNIT_FOREVER_REL, | 372 | else |
653 | &send_answer, NULL); | 373 | tun.proto = htons (ETH_P_IPV6); |
374 | memcpy (&buf[off], &tun, sizeof (struct tun_header)); | ||
375 | off += sizeof (struct tun_header); | ||
376 | } | ||
654 | 377 | ||
655 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 378 | /* now IP header */ |
656 | "Sent answer of length %d on to client, addroffset = %d\n", len, | 379 | udp_crc_sum = 0; |
657 | answer->pkt.addroffset); | 380 | switch (rr->src_addr.ss_family) |
381 | { | ||
382 | case AF_INET: | ||
383 | { | ||
384 | struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; | ||
385 | struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; | ||
386 | struct ip4_header ip; | ||
387 | |||
388 | spt = dst->sin_port; | ||
389 | dpt = src->sin_port; | ||
390 | ip.header_length = sizeof (struct ip4_header) / 4; | ||
391 | ip.version = IPVERSION; /* aka 4 */ | ||
392 | ip.diff_serv = 0; | ||
393 | ip.total_length = htons ((uint16_t) reply_len - off); | ||
394 | ip.identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
395 | 65536); | ||
396 | ip.flags = 0; | ||
397 | ip.fragmentation_offset = 0; | ||
398 | ip.ttl = 255; /* or lower? */ | ||
399 | ip.protocol = IPPROTO_UDP; | ||
400 | ip.checksum = 0; /* checksum is optional */ | ||
401 | ip.source_address = dst->sin_addr; | ||
402 | ip.destination_address = src->sin_addr; | ||
403 | ip.checksum = GNUNET_CRYPTO_crc16_n (&ip, sizeof (ip)); | ||
404 | |||
405 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
406 | &ip.source_address, | ||
407 | sizeof (struct in_addr) * 2); | ||
408 | { | ||
409 | uint16_t tmp; | ||
410 | |||
411 | tmp = htons (IPPROTO_UDP); | ||
412 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
413 | &tmp, | ||
414 | sizeof (uint16_t)); | ||
415 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
416 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
417 | &tmp, | ||
418 | sizeof (uint16_t)); | ||
419 | } | ||
420 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
421 | off += sizeof (ip); | ||
422 | } | ||
423 | break; | ||
424 | case AF_INET6: | ||
425 | { | ||
426 | struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; | ||
427 | struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; | ||
428 | struct ip6_header ip; | ||
429 | |||
430 | spt = dst->sin6_port; | ||
431 | dpt = src->sin6_port; | ||
432 | ip.traffic_class_h = 0; | ||
433 | ip.version = 6; /* is there a named constant? I couldn't find one */ | ||
434 | ip.traffic_class_l = 0; | ||
435 | ip.flow_label = 0; | ||
436 | ip.payload_length = htons ((uint16_t) reply_len); | ||
437 | ip.next_header = IPPROTO_UDP; | ||
438 | ip.hop_limit = 255; /* or lower? */ | ||
439 | ip.source_address = dst->sin6_addr; | ||
440 | ip.destination_address = src->sin6_addr; | ||
441 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
442 | &ip.source_address, | ||
443 | sizeof (struct in6_addr) * 2); | ||
444 | { | ||
445 | uint32_t tmp; | ||
446 | |||
447 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
448 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
449 | &tmp, | ||
450 | sizeof (uint32_t)); | ||
451 | tmp = htons (IPPROTO_UDP); | ||
452 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
453 | &tmp, | ||
454 | sizeof (uint32_t)); | ||
455 | } | ||
456 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
457 | off += sizeof (ip); | ||
458 | } | ||
459 | break; | ||
460 | default: | ||
461 | GNUNET_assert (0); | ||
462 | } | ||
658 | 463 | ||
659 | free_parsed_dns_packet (pdns); | 464 | /* now UDP header */ |
660 | return GNUNET_OK; | 465 | { |
466 | struct udp_packet udp; | ||
467 | |||
468 | udp.spt = spt; | ||
469 | udp.dpt = dpt; | ||
470 | udp.len = htons (reply_len - off); | ||
471 | udp.crc = 0; | ||
472 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
473 | &udp, | ||
474 | sizeof (udp)); | ||
475 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
476 | rr->payload, | ||
477 | rr->payload_length); | ||
478 | udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum); | ||
479 | memcpy (&buf[off], &udp, sizeof (udp)); | ||
480 | off += sizeof (udp); | ||
481 | } | ||
482 | /* now DNS payload */ | ||
483 | { | ||
484 | memcpy (&buf[off], rr->payload, rr->payload_length); | ||
485 | off += rr->payload_length; | ||
486 | } | ||
487 | /* final checks & sending */ | ||
488 | GNUNET_assert (off == reply_len); | ||
489 | GNUNET_HELPER_send (hijacker, | ||
490 | hdr, | ||
491 | GNUNET_YES, | ||
492 | NULL, NULL); | ||
493 | GNUNET_STATISTICS_update (stats, | ||
494 | gettext_noop ("# DNS requests answered via TUN interface"), | ||
495 | 1, GNUNET_NO); | ||
496 | } | ||
497 | /* clean up, we're done */ | ||
498 | cleanup_rr (rr); | ||
661 | } | 499 | } |
662 | 500 | ||
663 | 501 | ||
664 | static void | ||
665 | send_rev_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
666 | { | ||
667 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
668 | return; | ||
669 | |||
670 | struct dns_pkt_parsed *pdns = (struct dns_pkt_parsed *) cls; | ||
671 | |||
672 | unsigned short id = pdns->s.id; | ||
673 | |||
674 | free_parsed_dns_packet (pdns); | ||
675 | |||
676 | if (query_states[id].valid != GNUNET_YES) | ||
677 | return; | ||
678 | query_states[id].valid = GNUNET_NO; | ||
679 | |||
680 | GNUNET_assert (query_states[id].namelen == 74); | ||
681 | |||
682 | size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + 74 /* this is the length of a reverse ipv6-lookup */ | ||
683 | + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */ | ||
684 | + sizeof (struct dns_record_line) - 1 - | ||
685 | 2 /* We do not know the lenght of the answer yet */ ; | ||
686 | |||
687 | struct answer_packet_list *answer = | ||
688 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
689 | sizeof (struct answer_packet)); | ||
690 | |||
691 | answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
692 | answer->pkt.hdr.size = htons (len); | ||
693 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REV; | ||
694 | |||
695 | memcpy (answer->pkt.from, query_states[id].remote_ip, | ||
696 | query_states[id].addrlen); | ||
697 | memcpy (answer->pkt.to, query_states[id].local_ip, query_states[id].addrlen); | ||
698 | |||
699 | answer->pkt.dst_port = query_states[id].local_port; | ||
700 | |||
701 | struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data; | ||
702 | |||
703 | dpkt->s.id = id; | ||
704 | dpkt->s.aa = 1; | ||
705 | dpkt->s.qr = 1; | ||
706 | dpkt->s.ra = 1; | ||
707 | dpkt->s.qdcount = htons (1); | ||
708 | dpkt->s.ancount = htons (1); | ||
709 | |||
710 | memcpy (dpkt->data, query_states[id].name, query_states[id].namelen); | ||
711 | GNUNET_free (query_states[id].name); | ||
712 | query_states[id].name = NULL; | ||
713 | |||
714 | struct dns_query_line *dque = | ||
715 | (struct dns_query_line *) (dpkt->data + (query_states[id].namelen)); | ||
716 | dque->type = htons (12); /* PTR */ | ||
717 | dque->class = htons (1); /* IN */ | ||
718 | |||
719 | char *anname = | ||
720 | (char *) (dpkt->data + (query_states[id].namelen) + | ||
721 | sizeof (struct dns_query_line)); | ||
722 | memcpy (anname, "\xc0\x0c", 2); | ||
723 | |||
724 | struct dns_record_line *drec_data = | ||
725 | (struct dns_record_line *) (dpkt->data + (query_states[id].namelen) + | ||
726 | sizeof (struct dns_query_line) + 2); | ||
727 | drec_data->type = htons (12); /* AAAA */ | ||
728 | drec_data->class = htons (1); /* IN */ | ||
729 | /* FIXME: read the TTL from block: | ||
730 | * GNUNET_TIME_absolute_get_remaining(rec->expiration_time) | ||
731 | * | ||
732 | * But how to get the seconds out of this? | ||
733 | */ | ||
734 | drec_data->ttl = htonl (3600); | ||
735 | |||
736 | /* Calculate at which offset in the packet the length of the name and the | ||
737 | * name, it is filled in by the daemon-vpn */ | ||
738 | answer->pkt.addroffset = | ||
739 | htons ((unsigned short) ((unsigned long) (&drec_data->data_len) - | ||
740 | (unsigned long) (&answer->pkt))); | ||
741 | |||
742 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | ||
743 | answer->client = query_states[id].client; | ||
744 | |||
745 | if (server_notify == NULL) | ||
746 | server_notify = | ||
747 | GNUNET_SERVER_notify_transmit_ready (query_states[id].client, len, | ||
748 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
749 | &send_answer, NULL); | ||
750 | } | ||
751 | |||
752 | /** | 502 | /** |
753 | * Receive a block from the dht. | 503 | * Show the payload of the given request record to the client |
504 | * (and wait for a response). | ||
505 | * | ||
506 | * @param rr request to send to client | ||
507 | * @param client client to send the response to | ||
754 | */ | 508 | */ |
755 | static void | 509 | static void |
756 | receive_dht (void *cls, struct GNUNET_TIME_Absolute exp GNUNET_UNUSED, | 510 | send_request_to_client (struct RequestRecord *rr, |
757 | const GNUNET_HashCode * key GNUNET_UNUSED, | 511 | struct GNUNET_SERVER_Client *client) |
758 | const struct GNUNET_PeerIdentity *get_path GNUNET_UNUSED, | ||
759 | unsigned int get_path_length GNUNET_UNUSED, | ||
760 | const struct GNUNET_PeerIdentity *put_path GNUNET_UNUSED, | ||
761 | unsigned int put_path_length GNUNET_UNUSED, | ||
762 | enum GNUNET_BLOCK_Type type, size_t size, const void *data) | ||
763 | { | 512 | { |
513 | char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; | ||
514 | struct GNUNET_DNS_Request *req; | ||
764 | 515 | ||
765 | unsigned short id = ((struct receive_dht_cls *) cls)->id; | 516 | if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
766 | struct GNUNET_DHT_GetHandle *handle = | 517 | { |
767 | ((struct receive_dht_cls *) cls)->handle; | 518 | GNUNET_break (0); |
768 | GNUNET_free (cls); | 519 | cleanup_rr (rr); |
769 | |||
770 | GNUNET_DHT_get_stop (handle); | ||
771 | |||
772 | GNUNET_assert (type == GNUNET_BLOCK_TYPE_DNS); | ||
773 | |||
774 | /* If no query with this id is pending, ignore the block */ | ||
775 | if (query_states[id].valid != GNUNET_YES) | ||
776 | return; | 520 | return; |
777 | query_states[id].valid = GNUNET_NO; | 521 | } |
778 | 522 | req = (struct GNUNET_DNS_Request*) buf; | |
779 | const struct GNUNET_DNS_Record *rec = data; | 523 | req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); |
780 | 524 | req->header.size = htons (sizeof (buf)); | |
781 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 525 | req->reserved = htonl (0); |
782 | "Got block of size %d, peer: %08x, desc: %08x\n", size, | 526 | req->request_id = rr->request_id; |
783 | *((unsigned int *) &rec->peer), | 527 | memcpy (&req[1], rr->payload, rr->payload_length); |
784 | *((unsigned int *) &rec->service_descriptor)); | 528 | GNUNET_SERVER_notification_context_unicast (nc, |
785 | 529 | client, | |
786 | size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[id].namelen + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */ | 530 | &req->header, |
787 | + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */ | 531 | GNUNET_NO); |
788 | |||
789 | struct answer_packet_list *answer = | ||
790 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
791 | sizeof (struct answer_packet)); | ||
792 | |||
793 | answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
794 | answer->pkt.hdr.size = htons (len); | ||
795 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_SERVICE; | ||
796 | answer->client = query_states[id].client; | ||
797 | |||
798 | GNUNET_CRYPTO_hash (&rec->peer, | ||
799 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
800 | &answer->pkt.service_descr.peer); | ||
801 | |||
802 | memcpy (&answer->pkt.service_descr.service_descriptor, | ||
803 | &rec->service_descriptor, sizeof (GNUNET_HashCode)); | ||
804 | memcpy (&answer->pkt.service_descr.service_type, &rec->service_type, | ||
805 | sizeof (answer->pkt.service_descr.service_type)); | ||
806 | memcpy (&answer->pkt.service_descr.ports, &rec->ports, | ||
807 | sizeof (answer->pkt.service_descr.ports)); | ||
808 | |||
809 | memcpy (answer->pkt.from, query_states[id].remote_ip, | ||
810 | query_states[id].addrlen); | ||
811 | memcpy (answer->pkt.to, query_states[id].local_ip, query_states[id].addrlen); | ||
812 | answer->pkt.addrlen = query_states[id].addrlen; | ||
813 | |||
814 | answer->pkt.dst_port = query_states[id].local_port; | ||
815 | |||
816 | struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data; | ||
817 | |||
818 | dpkt->s.id = id; | ||
819 | dpkt->s.aa = 1; | ||
820 | dpkt->s.qr = 1; | ||
821 | dpkt->s.ra = 1; | ||
822 | dpkt->s.qdcount = htons (1); | ||
823 | dpkt->s.ancount = htons (1); | ||
824 | |||
825 | memcpy (dpkt->data, query_states[id].name, query_states[id].namelen); | ||
826 | GNUNET_free (query_states[id].name); | ||
827 | query_states[id].name = NULL; | ||
828 | |||
829 | struct dns_query_line *dque = | ||
830 | (struct dns_query_line *) (dpkt->data + (query_states[id].namelen)); | ||
831 | dque->type = htons (28); /* AAAA */ | ||
832 | dque->class = htons (1); /* IN */ | ||
833 | |||
834 | char *anname = | ||
835 | (char *) (dpkt->data + (query_states[id].namelen) + | ||
836 | sizeof (struct dns_query_line)); | ||
837 | memcpy (anname, "\xc0\x0c", 2); | ||
838 | |||
839 | struct dns_record_line *drec_data = | ||
840 | (struct dns_record_line *) (dpkt->data + (query_states[id].namelen) + | ||
841 | sizeof (struct dns_query_line) + 2); | ||
842 | drec_data->type = htons (28); /* AAAA */ | ||
843 | drec_data->class = htons (1); /* IN */ | ||
844 | |||
845 | /* FIXME: read the TTL from block: | ||
846 | * GNUNET_TIME_absolute_get_remaining(rec->expiration_time) | ||
847 | * | ||
848 | * But how to get the seconds out of this? | ||
849 | */ | ||
850 | drec_data->ttl = htonl (3600); | ||
851 | drec_data->data_len = htons (16); | ||
852 | |||
853 | /* Calculate at which offset in the packet the IPv6-Address belongs, it is | ||
854 | * filled in by the daemon-vpn */ | ||
855 | answer->pkt.addroffset = | ||
856 | htons ((unsigned short) ((unsigned long) (&drec_data->data) - | ||
857 | (unsigned long) (&answer->pkt))); | ||
858 | |||
859 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | ||
860 | |||
861 | if (server_notify == NULL) | ||
862 | server_notify = | ||
863 | GNUNET_SERVER_notify_transmit_ready (answer->client, len, | ||
864 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
865 | &send_answer, NULL); | ||
866 | } | 532 | } |
867 | 533 | ||
868 | /** | ||
869 | * This receives a GNUNET_MESSAGE_TYPE_REHIJACK and rehijacks the DNS | ||
870 | */ | ||
871 | static void | ||
872 | rehijack (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, | ||
873 | const struct GNUNET_MessageHeader *message GNUNET_UNUSED) | ||
874 | { | ||
875 | unhijack (dnsoutport); | ||
876 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | ||
877 | |||
878 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
879 | } | ||
880 | 534 | ||
881 | /** | 535 | /** |
882 | * This receives the dns-payload from the daemon-vpn and sends it on over the udp-socket | 536 | * A client has completed its processing for this |
537 | * request. Move on. | ||
538 | * | ||
539 | * @param rr request to process further | ||
883 | */ | 540 | */ |
884 | static void | 541 | static void |
885 | receive_query (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, | 542 | next_phase (struct RequestRecord *rr) |
886 | const struct GNUNET_MessageHeader *message) | ||
887 | { | 543 | { |
888 | struct query_packet *pkt = (struct query_packet *) message; | 544 | struct ClientRecord *cr; |
889 | struct dns_pkt *dns = (struct dns_pkt *) pkt->data; | 545 | int nz; |
890 | struct dns_pkt_parsed *pdns = parse_dns_packet (dns); | 546 | unsigned int j; |
547 | struct GNUNET_NETWORK_Handle *dnsout; | ||
548 | socklen_t salen; | ||
891 | 549 | ||
892 | query_states[dns->s.id].valid = GNUNET_YES; | 550 | if (rr->phase == RP_DROP) |
893 | query_states[dns->s.id].client = client; | 551 | { |
894 | GNUNET_SERVER_client_keep (client); | 552 | cleanup_rr (rr); |
895 | memcpy (query_states[dns->s.id].local_ip, pkt->orig_from, pkt->addrlen); | 553 | return; |
896 | query_states[dns->s.id].addrlen = pkt->addrlen; | 554 | } |
897 | query_states[dns->s.id].local_port = pkt->src_port; | 555 | nz = -1; |
898 | memcpy (query_states[dns->s.id].remote_ip, pkt->orig_to, pkt->addrlen); | 556 | for (j=0;j<rr->client_wait_list_length;j++) |
899 | query_states[dns->s.id].namelen = strlen ((char *) dns->data) + 1; | ||
900 | if (query_states[dns->s.id].name != NULL) | ||
901 | GNUNET_free (query_states[dns->s.id].name); | ||
902 | query_states[dns->s.id].name = | ||
903 | GNUNET_malloc (query_states[dns->s.id].namelen); | ||
904 | memcpy (query_states[dns->s.id].name, dns->data, | ||
905 | query_states[dns->s.id].namelen); | ||
906 | |||
907 | int i; | ||
908 | |||
909 | for (i = 0; i < ntohs (pdns->s.qdcount); i++) | ||
910 | { | 557 | { |
911 | if (pdns->queries[i]->qtype == htons (28) || | 558 | if (NULL != rr->client_wait_list[j]) |
912 | pdns->queries[i]->qtype == htons (1)) | ||
913 | { | 559 | { |
914 | query_states[dns->s.id].qtype = pdns->queries[i]->qtype; | 560 | nz = (int) j; |
915 | break; | 561 | break; |
916 | } | 562 | } |
917 | } | 563 | } |
918 | 564 | if (-1 != nz) | |
919 | /* The query is for a .gnunet-address */ | ||
920 | if (pdns->queries[0]->namelen > 9 && | ||
921 | 0 == strncmp (pdns->queries[0]->name + (pdns->queries[0]->namelen - 9), | ||
922 | ".gnunet.", 9)) | ||
923 | { | 565 | { |
924 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Query for .gnunet!\n"); | 566 | send_request_to_client (rr, rr->client_wait_list[nz]->client); |
925 | GNUNET_HashCode key; | 567 | return; |
926 | |||
927 | GNUNET_CRYPTO_hash (pdns->queries[0]->name, pdns->queries[0]->namelen, | ||
928 | &key); | ||
929 | |||
930 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting with key %08x, len is %d\n", | ||
931 | *((unsigned int *) &key), pdns->queries[0]->namelen); | ||
932 | |||
933 | struct receive_dht_cls *cls = | ||
934 | GNUNET_malloc (sizeof (struct receive_dht_cls)); | ||
935 | cls->id = dns->s.id; | ||
936 | |||
937 | cls->handle = | ||
938 | GNUNET_DHT_get_start (dht, GNUNET_TIME_UNIT_MINUTES, | ||
939 | GNUNET_BLOCK_TYPE_DNS, &key, | ||
940 | 5 /* DEFAULT_GET_REPLICATION */ , | ||
941 | GNUNET_DHT_RO_NONE, NULL, 0, &receive_dht, cls); | ||
942 | |||
943 | goto outfree; | ||
944 | } | 568 | } |
945 | 569 | /* done with current phase, advance! */ | |
946 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Query for '%s'; namelen=%d\n", | 570 | switch (rr->phase) |
947 | pdns->queries[0]->name, pdns->queries[0]->namelen); | ||
948 | |||
949 | /* This is a PTR-Query. Check if it is for "our" network */ | ||
950 | if (htons (pdns->queries[0]->qtype) == 12 && 74 == pdns->queries[0]->namelen) | ||
951 | { | 571 | { |
952 | char *ipv6addr; | 572 | case RP_INIT: |
953 | char ipv6[16]; | 573 | rr->phase = RP_REQUEST_MONITOR; |
954 | char ipv6rev[74] = | 574 | for (cr = clients_head; NULL != cr; cr = cr->next) |
955 | "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."; | ||
956 | unsigned int i; | ||
957 | unsigned long long ipv6prefix; | ||
958 | unsigned int comparelen; | ||
959 | |||
960 | GNUNET_assert (GNUNET_OK == | ||
961 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
962 | "IPV6ADDR", | ||
963 | &ipv6addr)); | ||
964 | inet_pton (AF_INET6, ipv6addr, ipv6); | ||
965 | GNUNET_free (ipv6addr); | ||
966 | |||
967 | GNUNET_assert (GNUNET_OK == | ||
968 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
969 | "IPV6PREFIX", | ||
970 | &ipv6prefix)); | ||
971 | GNUNET_assert (ipv6prefix < 127); | ||
972 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
973 | |||
974 | for (i = ipv6prefix; i < 16; i++) | ||
975 | ipv6[i] = 0; | ||
976 | |||
977 | for (i = 0; i < 16; i++) | ||
978 | { | 575 | { |
979 | unsigned char c1 = ipv6[i] >> 4; | 576 | if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) |
980 | unsigned char c2 = ipv6[i] & 0xf; | 577 | GNUNET_array_append (rr->client_wait_list, |
981 | 578 | rr->client_wait_list_length, | |
982 | if (c1 <= 9) | 579 | cr); |
983 | ipv6rev[62 - (4 * i)] = c1 + '0'; | ||
984 | else | ||
985 | ipv6rev[62 - (4 * i)] = c1 + 87; /* 87 is the difference between 'a' and 10 */ | ||
986 | |||
987 | if (c2 <= 9) | ||
988 | ipv6rev[62 - ((4 * i) + 2)] = c2 + '0'; | ||
989 | else | ||
990 | ipv6rev[62 - ((4 * i) + 2)] = c2 + 87; | ||
991 | } | 580 | } |
992 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "My network is %s'.\n", ipv6rev); | 581 | next_phase (rr); |
993 | comparelen = 10 + 4 * ipv6prefix; | 582 | return; |
994 | if (0 == | 583 | case RP_REQUEST_MONITOR: |
995 | strncmp (pdns->queries[0]->name + | 584 | rr->phase = RP_QUERY; |
996 | (pdns->queries[0]->namelen - comparelen), | 585 | for (cr = clients_head; NULL != cr; cr = cr->next) |
997 | ipv6rev + (74 - comparelen), comparelen)) | ||
998 | { | 586 | { |
999 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reverse-Query for .gnunet!\n"); | 587 | if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) |
1000 | 588 | GNUNET_array_append (rr->client_wait_list, | |
1001 | GNUNET_SCHEDULER_add_now (send_rev_query, pdns); | 589 | rr->client_wait_list_length, |
1002 | 590 | cr); | |
1003 | goto out; | ||
1004 | } | 591 | } |
1005 | } | 592 | next_phase (rr); |
1006 | 593 | return; | |
1007 | unsigned char virt_dns_bytes[16]; | 594 | case RP_QUERY: |
1008 | 595 | rr->phase = RP_INTERNET_DNS; | |
1009 | if (pkt->addrlen == 4) | 596 | switch (rr->dst_addr.ss_family) |
1010 | { | ||
1011 | char *virt_dns; | ||
1012 | |||
1013 | if (GNUNET_SYSERR == | ||
1014 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", | ||
1015 | &virt_dns)) | ||
1016 | { | 597 | { |
1017 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 598 | case AF_INET: |
1018 | "No entry 'VIRTDNS' in configuration!\n"); | 599 | dnsout = dnsout4; |
1019 | exit (1); | 600 | salen = sizeof (struct ip4_header); |
601 | break; | ||
602 | case AF_INET6: | ||
603 | dnsout = dnsout6; | ||
604 | salen = sizeof (struct ip6_header); | ||
605 | break; | ||
606 | default: | ||
607 | GNUNET_break (0); | ||
608 | cleanup_rr (rr); | ||
609 | return; | ||
1020 | } | 610 | } |
1021 | 611 | if (NULL == dnsout) | |
1022 | if (1 != inet_pton (AF_INET, virt_dns, &virt_dns_bytes)) | ||
1023 | { | 612 | { |
1024 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing 'VIRTDNS': %s; %m!\n", | 613 | GNUNET_STATISTICS_update (stats, |
1025 | virt_dns); | 614 | gettext_noop ("# DNS exit failed (address family not supported)"), |
1026 | exit (1); | 615 | 1, GNUNET_NO); |
616 | cleanup_rr (rr); | ||
617 | return; | ||
1027 | } | 618 | } |
1028 | 619 | GNUNET_NETWORK_socket_sendto (dnsout, | |
1029 | GNUNET_free (virt_dns); | 620 | rr->payload, |
1030 | } | 621 | rr->payload_length, |
1031 | else if (pkt->addrlen == 16) | 622 | (struct sockaddr*) &rr->dst_addr, |
1032 | { | 623 | salen); |
1033 | char *virt_dns; | 624 | return; |
1034 | 625 | case RP_INTERNET_DNS: | |
1035 | if (GNUNET_SYSERR == | 626 | rr->phase = RP_MODIFY; |
1036 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS6", | 627 | for (cr = clients_head; NULL != cr; cr = cr->next) |
1037 | &virt_dns)) | ||
1038 | { | 628 | { |
1039 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 629 | if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) |
1040 | "No entry 'VIRTDNS6' in configuration!\n"); | 630 | GNUNET_array_append (rr->client_wait_list, |
1041 | exit (1); | 631 | rr->client_wait_list_length, |
632 | cr); | ||
1042 | } | 633 | } |
1043 | 634 | next_phase (rr); | |
1044 | if (1 != inet_pton (AF_INET6, virt_dns, &virt_dns_bytes)) | 635 | return; |
636 | case RP_MODIFY: | ||
637 | rr->phase = RP_RESPONSE_MONITOR; | ||
638 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
1045 | { | 639 | { |
1046 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 640 | if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) |
1047 | "Error parsing 'VIRTDNS6': %s; %m!\n", virt_dns); | 641 | GNUNET_array_append (rr->client_wait_list, |
1048 | exit (1); | 642 | rr->client_wait_list_length, |
643 | cr); | ||
1049 | } | 644 | } |
1050 | 645 | next_phase (rr); | |
1051 | GNUNET_free (virt_dns); | 646 | return; |
1052 | } | 647 | case RP_RESPONSE_MONITOR: |
1053 | else | 648 | request_done (rr); |
1054 | { | 649 | break; |
1055 | GNUNET_assert (0); | 650 | case RP_DROP: |
651 | cleanup_rr (rr); | ||
652 | break; | ||
653 | default: | ||
654 | GNUNET_break (0); | ||
655 | cleanup_rr (rr); | ||
656 | break; | ||
1056 | } | 657 | } |
658 | } | ||
1057 | 659 | ||
1058 | if (memcmp (virt_dns_bytes, pkt->orig_to, pkt->addrlen) == 0) | ||
1059 | { | ||
1060 | /* This is a packet that was sent directly to the virtual dns-server | ||
1061 | * | ||
1062 | * This means we have to send this query over gnunet | ||
1063 | */ | ||
1064 | |||
1065 | size_t size = | ||
1066 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
1067 | sizeof (struct GNUNET_MessageHeader) + (ntohs (message->size) - | ||
1068 | sizeof (struct query_packet) + | ||
1069 | 1); | ||
1070 | struct tunnel_cls *cls_ = GNUNET_malloc (size); | ||
1071 | |||
1072 | cls_->hdr.size = size - sizeof (struct GNUNET_MESH_Tunnel *); | ||
1073 | |||
1074 | cls_->hdr.type = ntohs (GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS); | ||
1075 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size); | ||
1076 | 660 | ||
1077 | memcpy (&cls_->dns, dns, | 661 | /** |
1078 | cls_->hdr.size - sizeof (struct GNUNET_MessageHeader)); | 662 | * A client disconnected, clean up after it. |
1079 | GNUNET_SCHEDULER_add_now (send_mesh_query, cls_); | 663 | * |
664 | * @param cls unused | ||
665 | * @param client handle of client that disconnected | ||
666 | */ | ||
667 | static void | ||
668 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
669 | { | ||
670 | struct ClientRecord *cr; | ||
671 | struct RequestRecord *rr; | ||
672 | unsigned int i; | ||
673 | unsigned int j; | ||
1080 | 674 | ||
1081 | if (ntohs (pdns->s.qdcount) == 1) | 675 | for (cr = clients_head; NULL != cr; cr = cr->next) |
676 | { | ||
677 | if (cr->client == client) | ||
1082 | { | 678 | { |
1083 | if (ntohs (pdns->queries[0]->qtype) == 1) | 679 | GNUNET_SERVER_client_drop (client); |
1084 | pdns->queries[0]->qtype = htons (28); | 680 | GNUNET_CONTAINER_DLL_remove (clients_head, |
1085 | else if (ntohs (pdns->queries[0]->qtype) == 28) | 681 | clients_tail, |
1086 | pdns->queries[0]->qtype = htons (1); | 682 | cr); |
1087 | else | 683 | for (i=0;i<UINT16_MAX;i++) |
1088 | { | 684 | { |
1089 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "not sending second packet\n"); | 685 | rr = &requests[i]; |
1090 | goto outfree; | 686 | if (0 == rr->client_wait_list_length) |
687 | continue; /* not in use */ | ||
688 | for (j=0;j<rr->client_wait_list_length;j++) | ||
689 | { | ||
690 | if (rr->client_wait_list[j] == cr) | ||
691 | { | ||
692 | rr->client_wait_list[j] = NULL; | ||
693 | next_phase (rr); | ||
694 | } | ||
695 | } | ||
1091 | } | 696 | } |
1092 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending second packet\n"); | 697 | GNUNET_free (cr); |
1093 | struct dns_pkt *rdns = unparse_dns_packet (pdns); | 698 | return; |
1094 | size_t size = | ||
1095 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
1096 | sizeof (struct GNUNET_MessageHeader) + (ntohs (message->size) - | ||
1097 | sizeof (struct query_packet) + | ||
1098 | 1); | ||
1099 | struct tunnel_cls *cls_ = GNUNET_malloc (size); | ||
1100 | |||
1101 | cls_->hdr.size = size - sizeof (struct GNUNET_MESH_Tunnel *); | ||
1102 | |||
1103 | cls_->hdr.type = ntohs (GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS); | ||
1104 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size); | ||
1105 | |||
1106 | memcpy (&cls_->dns, rdns, | ||
1107 | cls_->hdr.size - sizeof (struct GNUNET_MessageHeader)); | ||
1108 | GNUNET_SCHEDULER_add_now (send_mesh_query, cls_); | ||
1109 | GNUNET_free (rdns); | ||
1110 | } | 699 | } |
1111 | |||
1112 | goto outfree; | ||
1113 | } | ||
1114 | |||
1115 | |||
1116 | /* The query should be sent to the network */ | ||
1117 | if (pkt->addrlen == 4) | ||
1118 | { | ||
1119 | struct sockaddr_in dest; | ||
1120 | |||
1121 | memset (&dest, 0, sizeof dest); | ||
1122 | dest.sin_port = htons (53); | ||
1123 | memcpy (&dest.sin_addr.s_addr, pkt->orig_to, pkt->addrlen); | ||
1124 | |||
1125 | GNUNET_NETWORK_socket_sendto (dnsout, dns, | ||
1126 | ntohs (pkt->hdr.size) - | ||
1127 | sizeof (struct query_packet) + 1, | ||
1128 | (struct sockaddr *) &dest, sizeof dest); | ||
1129 | } | 700 | } |
1130 | else if (pkt->addrlen == 16) | ||
1131 | { | ||
1132 | struct sockaddr_in6 dest; | ||
1133 | |||
1134 | memset (&dest, 0, sizeof dest); | ||
1135 | dest.sin6_port = htons (53); | ||
1136 | memcpy (&dest.sin6_addr, pkt->orig_to, pkt->addrlen); | ||
1137 | |||
1138 | GNUNET_NETWORK_socket_sendto (dnsout6, dns, | ||
1139 | ntohs (pkt->hdr.size) - | ||
1140 | sizeof (struct query_packet) + 1, | ||
1141 | (struct sockaddr *) &dest, sizeof dest); | ||
1142 | } | ||
1143 | |||
1144 | outfree: | ||
1145 | free_parsed_dns_packet (pdns); | ||
1146 | pdns = NULL; | ||
1147 | out: | ||
1148 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1149 | } | 701 | } |
1150 | 702 | ||
1151 | static void | ||
1152 | read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
1153 | 703 | ||
704 | /** | ||
705 | * Read a DNS response from the (unhindered) UDP-Socket | ||
706 | * | ||
707 | * @param cls socket to read from | ||
708 | * @param tc scheduler context (must be shutdown or read ready) | ||
709 | */ | ||
1154 | static void | 710 | static void |
1155 | read_response6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | 711 | read_response (void *cls, |
1156 | 712 | const struct GNUNET_SCHEDULER_TaskContext *tc) | |
1157 | static int | ||
1158 | open_port6 () | ||
1159 | { | 713 | { |
1160 | struct sockaddr_in6 addr; | 714 | struct GNUNET_NETWORK_Handle *dnsout = cls; |
715 | struct sockaddr_in addr4; | ||
716 | struct sockaddr_in6 addr6; | ||
717 | struct sockaddr *addr; | ||
718 | struct dns_header *dns; | ||
719 | socklen_t addrlen; | ||
720 | struct RequestRecord *rr; | ||
721 | ssize_t r; | ||
722 | int len; | ||
1161 | 723 | ||
1162 | dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0); | 724 | if (dnsout == dnsout4) |
1163 | if (dnsout6 == NULL) | ||
1164 | { | 725 | { |
1165 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create socket: %m\n"); | 726 | addrlen = sizeof (struct sockaddr_in); |
1166 | return GNUNET_SYSERR; | 727 | addr = (struct sockaddr* ) &addr4; |
728 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
729 | dnsout, | ||
730 | &read_response, | ||
731 | dnsout); | ||
1167 | } | 732 | } |
1168 | memset (&addr, 0, sizeof (struct sockaddr_in6)); | 733 | else |
1169 | 734 | { | |
1170 | addr.sin6_family = AF_INET6; | 735 | addrlen = sizeof (struct sockaddr_in6); |
1171 | int err = GNUNET_NETWORK_socket_bind (dnsout6, | 736 | addr = (struct sockaddr* ) &addr6; |
1172 | (struct sockaddr *) &addr, | 737 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1173 | sizeof (struct sockaddr_in6)); | 738 | dnsout, |
739 | &read_response, | ||
740 | dnsout); | ||
741 | } | ||
742 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
743 | return; | ||
1174 | 744 | ||
1175 | if (err != GNUNET_OK) | 745 | #ifndef MINGW |
746 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) | ||
1176 | { | 747 | { |
1177 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not bind a port: %m\n"); | 748 | /* conservative choice: */ |
1178 | return GNUNET_SYSERR; | 749 | len = 65536; |
1179 | } | 750 | } |
751 | #else | ||
752 | /* port the code above? */ | ||
753 | len = 65536; | ||
754 | #endif | ||
1180 | 755 | ||
1181 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout6, | 756 | { |
1182 | &read_response6, NULL); | 757 | unsigned char buf[len]; |
1183 | 758 | ||
1184 | return GNUNET_YES; | 759 | memset (addr, 0, addrlen); |
760 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, | ||
761 | buf, sizeof (buf), | ||
762 | addr, &addrlen); | ||
763 | if (-1 == r) | ||
764 | { | ||
765 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); | ||
766 | return; | ||
767 | } | ||
768 | if (sizeof (struct dns_header) > r) | ||
769 | { | ||
770 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
771 | _("Received DNS response that is too small (%u bytes)"), | ||
772 | r); | ||
773 | return; | ||
774 | } | ||
775 | dns = (struct dns_header *) buf; | ||
776 | rr = &requests[dns->id]; | ||
777 | if (rr->phase != RP_INTERNET_DNS) | ||
778 | { | ||
779 | /* unexpected / bogus reply */ | ||
780 | GNUNET_STATISTICS_update (stats, | ||
781 | gettext_noop ("# External DNS response discarded (no matching request)"), | ||
782 | 1, GNUNET_NO); | ||
783 | return; | ||
784 | } | ||
785 | GNUNET_free_non_null (rr->payload); | ||
786 | rr->payload = GNUNET_malloc (len); | ||
787 | memcpy (rr->payload, buf, len); | ||
788 | rr->payload_length = len; | ||
789 | next_phase (rr); | ||
790 | } | ||
1185 | } | 791 | } |
1186 | 792 | ||
793 | |||
794 | /** | ||
795 | * Open source port for sending DNS request on IPv4. | ||
796 | * | ||
797 | * @return GNUNET_OK on success | ||
798 | */ | ||
1187 | static int | 799 | static int |
1188 | open_port () | 800 | open_port4 () |
1189 | { | 801 | { |
1190 | struct sockaddr_in addr; | 802 | struct sockaddr_in addr; |
803 | socklen_t addrlen; | ||
1191 | 804 | ||
1192 | dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); | 805 | dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); |
1193 | if (dnsout == NULL) | 806 | if (dnsout4 == NULL) |
1194 | return GNUNET_SYSERR; | 807 | return GNUNET_SYSERR; |
1195 | memset (&addr, 0, sizeof (struct sockaddr_in)); | ||
1196 | 808 | ||
809 | memset (&addr, 0, sizeof (struct sockaddr_in)); | ||
1197 | addr.sin_family = AF_INET; | 810 | addr.sin_family = AF_INET; |
1198 | int err = GNUNET_NETWORK_socket_bind (dnsout, | 811 | int err = GNUNET_NETWORK_socket_bind (dnsout4, |
1199 | (struct sockaddr *) &addr, | 812 | (struct sockaddr *) &addr, |
1200 | sizeof (struct sockaddr_in)); | 813 | sizeof (struct sockaddr_in)); |
1201 | 814 | ||
1202 | if (err != GNUNET_OK) | 815 | if (err != GNUNET_OK) |
1203 | { | 816 | { |
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not bind a port: %m\n"); | 817 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
818 | _("Could not bind to any port: %s\n"), | ||
819 | STRERROR (errno)); | ||
820 | GNUNET_NETWORK_socket_close (dnsout4); | ||
821 | dnsout4 = NULL; | ||
1205 | return GNUNET_SYSERR; | 822 | return GNUNET_SYSERR; |
1206 | } | 823 | } |
1207 | 824 | ||
1208 | /* Read the port we bound to */ | 825 | /* Read the port we bound to */ |
1209 | socklen_t addrlen = sizeof (struct sockaddr_in); | 826 | addrlen = sizeof (struct sockaddr_in); |
1210 | 827 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4), | |
1211 | err = | 828 | (struct sockaddr *) &addr, |
1212 | getsockname (GNUNET_NETWORK_get_fd (dnsout), (struct sockaddr *) &addr, | 829 | &addrlen)) |
1213 | &addrlen); | 830 | { |
1214 | 831 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | |
832 | _("Could not determine port I got: %s\n"), | ||
833 | STRERROR (errno)); | ||
834 | GNUNET_NETWORK_socket_close (dnsout4); | ||
835 | dnsout4 = NULL; | ||
836 | return GNUNET_SYSERR; | ||
837 | } | ||
1215 | dnsoutport = htons (addr.sin_port); | 838 | dnsoutport = htons (addr.sin_port); |
1216 | 839 | ||
1217 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bound to port %d.\n", dnsoutport); | 840 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1218 | 841 | _("GNUnet DNS will exit on source port %u\n"), | |
1219 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout, | 842 | (unsigned int) dnsoutport); |
1220 | &read_response, NULL); | 843 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1221 | 844 | dnsout4, | |
1222 | return GNUNET_YES; | 845 | &read_response, dnsout4); |
846 | return GNUNET_OK; | ||
1223 | } | 847 | } |
1224 | 848 | ||
1225 | static void | ||
1226 | handle_response (struct dns_pkt *dns, struct sockaddr *addr, socklen_t addrlen, | ||
1227 | int r); | ||
1228 | 849 | ||
1229 | /** | 850 | /** |
1230 | * Read a response-packet of the UDP-Socket | 851 | * Open source port for sending DNS request on IPv6. Should be |
1231 | */ | 852 | * called AFTER open_port4. |
1232 | static void | 853 | * |
1233 | read_response6 (void *cls GNUNET_UNUSED, | 854 | * @return GNUNET_OK on success |
1234 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 855 | */ |
856 | static int | ||
857 | open_port6 () | ||
1235 | { | 858 | { |
1236 | struct sockaddr_in6 addr; | 859 | struct sockaddr_in6 addr; |
1237 | socklen_t addrlen = sizeof (addr); | 860 | socklen_t addrlen; |
1238 | int r; | ||
1239 | int len; | ||
1240 | |||
1241 | if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) | ||
1242 | return; | ||
1243 | |||
1244 | memset (&addr, 0, sizeof addr); | ||
1245 | |||
1246 | #ifndef MINGW | ||
1247 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout6), FIONREAD, &len)) | ||
1248 | { | ||
1249 | (void) open_port6 (); | ||
1250 | return; | ||
1251 | } | ||
1252 | #else | ||
1253 | /* port the code above? */ | ||
1254 | len = 65536; | ||
1255 | #endif | ||
1256 | |||
1257 | unsigned char buf[len]; | ||
1258 | struct dns_pkt *dns = (struct dns_pkt *) buf; | ||
1259 | |||
1260 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf), | ||
1261 | (struct sockaddr *) &addr, &addrlen); | ||
1262 | |||
1263 | if (r < 0) | ||
1264 | { | ||
1265 | (void) open_port6 (); | ||
1266 | return; | ||
1267 | } | ||
1268 | |||
1269 | struct sockaddr *addr_ = GNUNET_malloc (sizeof addr); | ||
1270 | 861 | ||
1271 | memcpy (addr_, &addr, sizeof addr); | 862 | dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0); |
1272 | handle_response (dns, addr_, 4, r); | 863 | if (dnsout6 == NULL) |
1273 | |||
1274 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout6, | ||
1275 | &read_response6, NULL); | ||
1276 | } | ||
1277 | |||
1278 | /** | ||
1279 | * Read a response-packet of the UDP-Socket | ||
1280 | */ | ||
1281 | static void | ||
1282 | read_response (void *cls GNUNET_UNUSED, | ||
1283 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1284 | { | ||
1285 | struct sockaddr_in addr; | ||
1286 | socklen_t addrlen = sizeof (addr); | ||
1287 | int r; | ||
1288 | int len; | ||
1289 | |||
1290 | if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) | ||
1291 | return; | ||
1292 | |||
1293 | memset (&addr, 0, sizeof addr); | ||
1294 | |||
1295 | #ifndef MINGW | ||
1296 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) | ||
1297 | { | 864 | { |
1298 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl"); | 865 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1299 | unhijack (dnsoutport); | 866 | _("Could not create IPv6 socket: %s\n"), |
1300 | if (GNUNET_YES == open_port ()) | 867 | STRERROR (errno)); |
1301 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | 868 | return GNUNET_SYSERR; |
1302 | return; | ||
1303 | } | 869 | } |
1304 | #else | 870 | memset (&addr, 0, sizeof (struct sockaddr_in6)); |
1305 | /* port the code above? */ | 871 | addr.sin6_family = AF_INET6; |
1306 | len = 65536; | 872 | addr.sin6_port = htons (dnsoutport); |
1307 | #endif | 873 | int err = GNUNET_NETWORK_socket_bind (dnsout6, |
1308 | 874 | (struct sockaddr *) &addr, | |
1309 | unsigned char buf[len]; | 875 | sizeof (struct sockaddr_in6)); |
1310 | struct dns_pkt *dns = (struct dns_pkt *) buf; | ||
1311 | |||
1312 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf), | ||
1313 | (struct sockaddr *) &addr, &addrlen); | ||
1314 | 876 | ||
1315 | if (r < 0) | 877 | if (err != GNUNET_OK) |
1316 | { | 878 | { |
1317 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom"); | 879 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1318 | unhijack (dnsoutport); | 880 | _("Could not bind to port %u: %s\n"), |
1319 | if (GNUNET_YES == open_port ()) | 881 | (unsigned int) dnsoutport, |
1320 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL); | 882 | STRERROR (errno)); |
1321 | return; | 883 | GNUNET_NETWORK_socket_close (dnsout6); |
884 | dnsout6 = NULL; | ||
885 | return GNUNET_SYSERR; | ||
1322 | } | 886 | } |
1323 | 887 | if (0 == dnsoutport) | |
1324 | struct sockaddr *addr_ = GNUNET_malloc (sizeof addr); | ||
1325 | |||
1326 | memcpy (addr_, &addr, sizeof addr); | ||
1327 | handle_response (dns, addr_, 4, r); | ||
1328 | |||
1329 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout, | ||
1330 | &read_response, NULL); | ||
1331 | } | ||
1332 | |||
1333 | static void | ||
1334 | handle_response (struct dns_pkt *dns, struct sockaddr *addr, socklen_t addrlen, | ||
1335 | int r) | ||
1336 | { | ||
1337 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer to query %d\n", | ||
1338 | ntohs (dns->s.id)); | ||
1339 | |||
1340 | |||
1341 | if (query_states[dns->s.id].valid == GNUNET_YES) | ||
1342 | { | 888 | { |
1343 | if (query_states[dns->s.id].tunnel != NULL) | 889 | addrlen = sizeof (struct sockaddr_in6); |
890 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6), | ||
891 | (struct sockaddr *) &addr, | ||
892 | &addrlen)) | ||
1344 | { | 893 | { |
1345 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 894 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1346 | "Answer to query %d for a remote peer!\n", ntohs (dns->s.id)); | 895 | _("Could not determine port I got: %s\n"), |
1347 | /* This response should go through a tunnel */ | 896 | STRERROR (errno)); |
1348 | uint32_t *c = | 897 | GNUNET_NETWORK_socket_close (dnsout6); |
1349 | GNUNET_malloc (4 + sizeof (struct GNUNET_MESH_Tunnel *) + r); | 898 | dnsout6 = NULL; |
1350 | *c = r; | 899 | return GNUNET_SYSERR; |
1351 | struct GNUNET_MESH_Tunnel **t = (struct GNUNET_MESH_Tunnel **) (c + 1); | ||
1352 | |||
1353 | *t = query_states[dns->s.id].tunnel; | ||
1354 | memcpy (t + 1, dns, r); | ||
1355 | struct tunnel_state *s = | ||
1356 | GNUNET_MESH_tunnel_get_data (query_states[dns->s.id].tunnel); | ||
1357 | if (NULL == s->th) | ||
1358 | { | ||
1359 | s->th = | ||
1360 | GNUNET_MESH_notify_transmit_ready (query_states[dns->s.id].tunnel, | ||
1361 | GNUNET_YES, 32, | ||
1362 | GNUNET_TIME_UNIT_MINUTES, NULL, | ||
1363 | r + | ||
1364 | sizeof (struct | ||
1365 | GNUNET_MessageHeader), | ||
1366 | mesh_send_response, c); | ||
1367 | } | ||
1368 | else | ||
1369 | { | ||
1370 | struct tunnel_notify_queue *element = | ||
1371 | GNUNET_malloc (sizeof (struct tunnel_notify_queue)); | ||
1372 | element->cls = c; | ||
1373 | element->len = r + sizeof (struct GNUNET_MessageHeader); | ||
1374 | element->cb = mesh_send_response; | ||
1375 | |||
1376 | GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element); | ||
1377 | } | ||
1378 | } | ||
1379 | else | ||
1380 | { | ||
1381 | query_states[dns->s.id].valid = GNUNET_NO; | ||
1382 | |||
1383 | size_t len = sizeof (struct answer_packet) + r - 1; /* 1 for the unsigned char data[1]; */ | ||
1384 | struct answer_packet_list *answer = | ||
1385 | GNUNET_malloc (len + sizeof (struct answer_packet_list) - | ||
1386 | (sizeof (struct answer_packet))); | ||
1387 | answer->pkt.hdr.type = | ||
1388 | htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS); | ||
1389 | answer->pkt.hdr.size = htons (len); | ||
1390 | answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP; | ||
1391 | answer->pkt.addrlen = addrlen; | ||
1392 | if (addrlen == 16) | ||
1393 | { | ||
1394 | struct sockaddr_in6 *addr_ = (struct sockaddr_in6 *) addr; | ||
1395 | |||
1396 | memcpy (answer->pkt.from, &addr_->sin6_addr, addrlen); | ||
1397 | memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, addrlen); | ||
1398 | } | ||
1399 | else if (addrlen == 4) | ||
1400 | { | ||
1401 | struct sockaddr_in *addr_ = (struct sockaddr_in *) addr; | ||
1402 | |||
1403 | memcpy (answer->pkt.from, &addr_->sin_addr.s_addr, addrlen); | ||
1404 | memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, addrlen); | ||
1405 | } | ||
1406 | else | ||
1407 | { | ||
1408 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "addrlen = %d\n", addrlen); | ||
1409 | GNUNET_assert (0); | ||
1410 | } | ||
1411 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending answer with addrlen = %d\n", | ||
1412 | addrlen); | ||
1413 | answer->pkt.dst_port = query_states[dns->s.id].local_port; | ||
1414 | memcpy (answer->pkt.data, dns, r); | ||
1415 | answer->client = query_states[dns->s.id].client; | ||
1416 | |||
1417 | GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer); | ||
1418 | |||
1419 | if (server_notify == NULL) | ||
1420 | server_notify = | ||
1421 | GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client, | ||
1422 | len, | ||
1423 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1424 | &send_answer, NULL); | ||
1425 | } | 900 | } |
1426 | } | 901 | } |
1427 | GNUNET_free (addr); | 902 | dnsoutport = htons (addr.sin6_port); |
903 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
904 | dnsout6, | ||
905 | &read_response, dnsout6); | ||
906 | return GNUNET_YES; | ||
1428 | } | 907 | } |
1429 | 908 | ||
1430 | 909 | ||
1431 | /** | 910 | /** |
1432 | * Task run during shutdown. | 911 | * We got a new client. Make sure all new DNS requests pass by its desk. |
1433 | * | 912 | * |
1434 | * @param cls unused | 913 | * @param cls unused |
1435 | * @param tc unused | 914 | * @param client the new client |
915 | * @param message the init message (unused) | ||
1436 | */ | 916 | */ |
1437 | static void | 917 | static void |
1438 | cleanup_task (void *cls GNUNET_UNUSED, | 918 | handle_client_init (void *cls GNUNET_UNUSED, |
1439 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 919 | struct GNUNET_SERVER_Client *client, |
920 | const struct GNUNET_MessageHeader *message) | ||
1440 | { | 921 | { |
1441 | GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)); | 922 | struct ClientRecord *cr; |
923 | const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; | ||
1442 | 924 | ||
1443 | unhijack (dnsoutport); | 925 | cr = GNUNET_malloc (sizeof (struct ClientRecord)); |
1444 | GNUNET_DHT_disconnect (dht); | 926 | cr->client = client; |
1445 | GNUNET_MESH_disconnect (mesh_handle); | 927 | cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); |
928 | GNUNET_SERVER_client_keep (client); | ||
929 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
930 | clients_tail, | ||
931 | cr); | ||
932 | GNUNET_SERVER_notification_context_add (nc, client); | ||
933 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1446 | } | 934 | } |
1447 | 935 | ||
936 | |||
1448 | /** | 937 | /** |
1449 | * @brief Create a port-map from udp and tcp redirects | 938 | * We got a response from a client. |
1450 | * | ||
1451 | * @param udp_redirects | ||
1452 | * @param tcp_redirects | ||
1453 | * | 939 | * |
1454 | * @return | 940 | * @param cls unused |
941 | * @param client the client | ||
942 | * @param message the response | ||
1455 | */ | 943 | */ |
1456 | static uint64_t | 944 | static void |
1457 | get_port_from_redirects (const char *udp_redirects, const char *tcp_redirects) | 945 | handle_client_response (void *cls GNUNET_UNUSED, |
946 | struct GNUNET_SERVER_Client *client, | ||
947 | const struct GNUNET_MessageHeader *message) | ||
1458 | { | 948 | { |
1459 | uint64_t ret = 0; | 949 | const struct GNUNET_DNS_Response *resp; |
1460 | char *cpy, *hostname, *redirect; | 950 | struct RequestRecord *rr; |
1461 | int local_port; | 951 | unsigned int i; |
1462 | unsigned int count = 0; | 952 | uint16_t msize; |
1463 | 953 | uint16_t off; | |
1464 | cpy = NULL; | 954 | |
1465 | if (NULL != udp_redirects) | 955 | msize = ntohs (message->size); |
956 | if (msize < sizeof (struct GNUNET_DNS_Response)) | ||
1466 | { | 957 | { |
1467 | cpy = GNUNET_strdup (udp_redirects); | 958 | GNUNET_break (0); |
1468 | for (redirect = strtok (cpy, " "); redirect != NULL; | 959 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
1469 | redirect = strtok (NULL, " ")) | 960 | return; |
1470 | { | ||
1471 | if (NULL == (hostname = strstr (redirect, ":"))) | ||
1472 | { | ||
1473 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1474 | "Warning: option %s is not formatted correctly!\n", | ||
1475 | redirect); | ||
1476 | continue; | ||
1477 | } | ||
1478 | hostname[0] = '\0'; | ||
1479 | local_port = atoi (redirect); | ||
1480 | if (!((local_port > 0) && (local_port < 65536))) | ||
1481 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1482 | "Warning: %s is not a correct port.", redirect); | ||
1483 | |||
1484 | ret |= (0xFFFF & htons (local_port)); | ||
1485 | ret <<= 16; | ||
1486 | count++; | ||
1487 | |||
1488 | if (count > 4) | ||
1489 | { | ||
1490 | ret = 0; | ||
1491 | goto out; | ||
1492 | } | ||
1493 | } | ||
1494 | GNUNET_free (cpy); | ||
1495 | cpy = NULL; | ||
1496 | } | 961 | } |
1497 | 962 | resp = (const struct GNUNET_DNS_Response*) message; | |
1498 | if (NULL != tcp_redirects) | 963 | off = (uint16_t) resp->request_id; |
964 | rr = &requests[off]; | ||
965 | if (rr->request_id != resp->request_id) | ||
1499 | { | 966 | { |
1500 | cpy = GNUNET_strdup (tcp_redirects); | 967 | GNUNET_STATISTICS_update (stats, |
1501 | for (redirect = strtok (cpy, " "); redirect != NULL; | 968 | gettext_noop ("# Client response discarded (no matching request)"), |
1502 | redirect = strtok (NULL, " ")) | 969 | 1, GNUNET_NO); |
970 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
971 | return; | ||
972 | } | ||
973 | for (i=0;i<rr->client_wait_list_length;i++) | ||
974 | { | ||
975 | if (NULL == rr->client_wait_list[i]) | ||
976 | continue; | ||
977 | if (rr->client_wait_list[i]->client != client) | ||
978 | continue; | ||
979 | rr->client_wait_list[i] = NULL; | ||
980 | switch (ntohl (resp->drop_flag)) | ||
1503 | { | 981 | { |
1504 | if (NULL == (hostname = strstr (redirect, ":"))) | 982 | case 0: /* drop */ |
983 | rr->phase = RP_DROP; | ||
984 | break; | ||
985 | case 1: /* no change */ | ||
986 | break; | ||
987 | case 2: /* update */ | ||
988 | msize -= sizeof (struct GNUNET_DNS_Response); | ||
989 | if ( (sizeof (struct dns_header) > msize) || | ||
990 | (RP_REQUEST_MONITOR == rr->phase) || | ||
991 | (RP_RESPONSE_MONITOR == rr->phase) ) | ||
1505 | { | 992 | { |
1506 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 993 | GNUNET_break (0); |
1507 | "Warning: option %s is not formatted correctly!\n", | 994 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
1508 | redirect); | 995 | next_phase (rr); |
1509 | continue; | 996 | return; |
1510 | } | 997 | } |
1511 | hostname[0] = '\0'; | 998 | GNUNET_free_non_null (rr->payload); |
1512 | local_port = atoi (redirect); | 999 | #if DEBUG_DNS |
1513 | if (!((local_port > 0) && (local_port < 65536))) | 1000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1514 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1001 | _("Changing DNS reply according to client specifications\n")); |
1515 | "Warning: %s is not a correct port.", redirect); | 1002 | #endif |
1516 | 1003 | rr->payload = GNUNET_malloc (msize); | |
1517 | ret |= (0xFFFF & htons (local_port)); | 1004 | rr->payload_length = msize; |
1518 | ret <<= 16; | 1005 | memcpy (rr->payload, &resp[1], msize); |
1519 | count++; | 1006 | if (rr->phase == RP_QUERY) |
1520 | |||
1521 | if (count > 4) | ||
1522 | { | 1007 | { |
1523 | ret = 0; | 1008 | /* clear wait list, we're moving to MODIFY phase next */ |
1524 | goto out; | 1009 | GNUNET_array_grow (rr->client_wait_list, |
1010 | rr->client_wait_list_length, | ||
1011 | 0); | ||
1525 | } | 1012 | } |
1013 | break; | ||
1526 | } | 1014 | } |
1527 | GNUNET_free (cpy); | 1015 | next_phase (rr); |
1528 | cpy = NULL; | 1016 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
1017 | return; | ||
1529 | } | 1018 | } |
1530 | 1019 | /* odd, client was not on our list for the request, that ought | |
1531 | out: | 1020 | to be an error */ |
1532 | GNUNET_free_non_null (cpy); | 1021 | GNUNET_break (0); |
1533 | return ret; | 1022 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
1534 | } | ||
1535 | |||
1536 | static void | ||
1537 | publish_name (const char *name, uint64_t ports, uint32_t service_type, | ||
1538 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key) | ||
1539 | { | ||
1540 | size_t size = sizeof (struct GNUNET_DNS_Record); | ||
1541 | struct GNUNET_DNS_Record data; | ||
1542 | |||
1543 | memset (&data, 0, size); | ||
1544 | |||
1545 | data.purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); | ||
1546 | data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD; | ||
1547 | |||
1548 | GNUNET_CRYPTO_hash (name, strlen (name) + 1, &data.service_descriptor); | ||
1549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n", | ||
1550 | *((unsigned long long *) &data.service_descriptor)); | ||
1551 | |||
1552 | data.service_type = service_type; | ||
1553 | data.ports = ports; | ||
1554 | |||
1555 | GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &data.peer); | ||
1556 | |||
1557 | data.expiration_time = | ||
1558 | GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute | ||
1559 | (GNUNET_TIME_relative_multiply | ||
1560 | (GNUNET_TIME_UNIT_HOURS, 2))); | ||
1561 | |||
1562 | /* Sign the block */ | ||
1563 | if (GNUNET_OK != | ||
1564 | GNUNET_CRYPTO_rsa_sign (my_private_key, &data.purpose, &data.signature)) | ||
1565 | { | ||
1566 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n"); | ||
1567 | return; | ||
1568 | } | ||
1569 | |||
1570 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting with key %08x, size = %d\n", | ||
1571 | *((unsigned int *) &data.service_descriptor), size); | ||
1572 | |||
1573 | GNUNET_DHT_put (dht, &data.service_descriptor, | ||
1574 | 5 /* DEFAULT_PUT_REPLICATION */ , | ||
1575 | GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_DNS, size, | ||
1576 | (char *) &data, | ||
1577 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), | ||
1578 | GNUNET_TIME_UNIT_MINUTES, NULL, NULL); | ||
1579 | } | 1023 | } |
1580 | 1024 | ||
1581 | 1025 | ||
1582 | /** | 1026 | /** |
1583 | * @brief Publishes the record defined by the section section | 1027 | * Functions with this signature are called whenever a complete |
1028 | * message is received by the tokenizer from the DNS hijack process. | ||
1584 | * | 1029 | * |
1585 | * @param cls closure | 1030 | * @param cls closure |
1586 | * @param section the current section | 1031 | * @param client identification of the client |
1032 | * @param message the actual message, a DNS request we should handle | ||
1587 | */ | 1033 | */ |
1588 | static void | 1034 | static void |
1589 | publish_iterate (void *cls GNUNET_UNUSED, const char *section) | 1035 | process_helper_messages (void *cls GNUNET_UNUSED, void *client, |
1036 | const struct GNUNET_MessageHeader *message) | ||
1590 | { | 1037 | { |
1591 | char *udp_redirects; | 1038 | uint16_t msize; |
1592 | char *tcp_redirects; | 1039 | const struct tun_header *tun; |
1593 | char *alternative_names; | 1040 | const struct ip4_header *ip4; |
1594 | char *alternative_name; | 1041 | const struct ip6_header *ip6; |
1595 | char *keyfile; | 1042 | const struct udp_packet *udp; |
1596 | 1043 | const struct dns_header *dns; | |
1597 | if ((strlen (section) < 8) || | 1044 | struct RequestRecord *rr; |
1598 | (0 != strcmp (".gnunet.", section + (strlen (section) - 8)))) | 1045 | struct sockaddr_in *srca4; |
1599 | return; | 1046 | struct sockaddr_in6 *srca6; |
1600 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing dns-name %s\n", section); | 1047 | struct sockaddr_in *dsta4; |
1601 | if (GNUNET_OK != | 1048 | struct sockaddr_in6 *dsta6; |
1602 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS", | 1049 | |
1603 | &udp_redirects)) | 1050 | msize = ntohs (message->size); |
1604 | udp_redirects = NULL; | 1051 | if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header)) |
1605 | if (GNUNET_OK != | ||
1606 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS", | ||
1607 | &tcp_redirects)) | ||
1608 | tcp_redirects = NULL; | ||
1609 | |||
1610 | if (GNUNET_OK != | ||
1611 | GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", | ||
1612 | &keyfile)) | ||
1613 | { | 1052 | { |
1614 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not read keyfile-value\n"); | 1053 | /* non-IP packet received on TUN!? */ |
1615 | if (keyfile != NULL) | 1054 | GNUNET_break (0); |
1616 | GNUNET_free (keyfile); | ||
1617 | return; | 1055 | return; |
1618 | } | 1056 | } |
1619 | 1057 | msize -= sizeof (struct GNUNET_MessageHeader); | |
1620 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key = | 1058 | tun = (const struct tun_header *) &message[1]; |
1621 | GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | 1059 | msize -= sizeof (struct tun_header); |
1622 | GNUNET_free (keyfile); | 1060 | switch (ntohs (tun->proto)) |
1623 | GNUNET_assert (my_private_key != NULL); | ||
1624 | |||
1625 | uint64_t ports = get_port_from_redirects (udp_redirects, tcp_redirects); | ||
1626 | uint32_t service_type = 0; | ||
1627 | |||
1628 | if (NULL != udp_redirects) | ||
1629 | service_type = GNUNET_DNS_SERVICE_TYPE_UDP; | ||
1630 | |||
1631 | if (NULL != tcp_redirects) | ||
1632 | service_type |= GNUNET_DNS_SERVICE_TYPE_TCP; | ||
1633 | |||
1634 | service_type = htonl (service_type); | ||
1635 | |||
1636 | |||
1637 | publish_name (section, ports, service_type, my_private_key); | ||
1638 | if (GNUNET_OK == | ||
1639 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "ALTERNATIVE_NAMES", | ||
1640 | &alternative_names)) | ||
1641 | { | 1061 | { |
1642 | for (alternative_name = strtok (alternative_names, " "); | 1062 | case ETH_P_IPV4: |
1643 | alternative_name != NULL; alternative_name = strtok (NULL, " ")) | 1063 | ip4 = (const struct ip4_header *) &tun[1]; |
1064 | if ( (msize < sizeof (struct ip4_header)) || | ||
1065 | (ip4->version != IPVERSION) || | ||
1066 | (ip4->header_length != sizeof (struct ip4_header) / 4) || | ||
1067 | (ntohs(ip4->total_length) != msize) || | ||
1068 | (ip4->protocol != IPPROTO_UDP) ) | ||
1644 | { | 1069 | { |
1645 | char *altname = | 1070 | /* non-IP/UDP packet received on TUN (or with options) */ |
1646 | alloca (strlen (alternative_name) + strlen (section) + 1 + 1); | 1071 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1647 | strcpy (altname, alternative_name); | 1072 | _("Received malformed IPv4-UDP packet on TUN interface.\n")); |
1648 | strcpy (altname + strlen (alternative_name) + 1, section); | 1073 | return; |
1649 | altname[strlen (alternative_name)] = '.'; | 1074 | } |
1650 | 1075 | udp = (const struct udp_packet*) &ip4[1]; | |
1651 | publish_name (altname, ports, service_type, my_private_key); | 1076 | msize -= sizeof (struct ip4_header); |
1077 | break; | ||
1078 | case ETH_P_IPV6: | ||
1079 | ip6 = (const struct ip6_header *) &tun[1]; | ||
1080 | if ( (msize < sizeof (struct ip6_header)) || | ||
1081 | (ip6->version != 6) || | ||
1082 | (ntohs (ip6->payload_length) != msize) || | ||
1083 | (ip6->next_header != IPPROTO_UDP) ) | ||
1084 | { | ||
1085 | /* non-IP/UDP packet received on TUN (or with extensions) */ | ||
1086 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1087 | _("Received malformed IPv6-UDP packet on TUN interface.\n")); | ||
1088 | return; | ||
1652 | } | 1089 | } |
1653 | GNUNET_free (alternative_names); | 1090 | udp = (const struct udp_packet*) &ip6[1]; |
1091 | msize -= sizeof (struct ip6_header); | ||
1092 | break; | ||
1093 | default: | ||
1094 | /* non-IP packet received on TUN!? */ | ||
1095 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1096 | _("Got non-IP packet with %u bytes and protocol %u from TUN\n"), | ||
1097 | (unsigned int) msize, | ||
1098 | ntohs (tun->proto)); | ||
1099 | return; | ||
1654 | } | 1100 | } |
1655 | GNUNET_CRYPTO_rsa_key_free (my_private_key); | 1101 | if (msize <= sizeof (struct udp_packet) + sizeof (struct dns_header)) |
1656 | GNUNET_free_non_null (udp_redirects); | 1102 | { |
1657 | GNUNET_free_non_null (tcp_redirects); | 1103 | /* non-DNS packet received on TUN, ignore */ |
1658 | } | 1104 | GNUNET_STATISTICS_update (stats, |
1659 | 1105 | gettext_noop ("# Non-DNS UDP packet received via TUN interface"), | |
1660 | /** | 1106 | 1, GNUNET_NO); |
1661 | * Publish a DNS-record in the DHT. | ||
1662 | */ | ||
1663 | static void | ||
1664 | publish_names (void *cls GNUNET_UNUSED, | ||
1665 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1666 | { | ||
1667 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1668 | return; | 1107 | return; |
1669 | 1108 | } | |
1670 | GNUNET_CONFIGURATION_iterate_sections (cfg, &publish_iterate, NULL); | 1109 | msize -= sizeof (struct udp_packet); |
1671 | 1110 | dns = (const struct dns_header*) &udp[1]; | |
1672 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_HOURS, &publish_names, NULL); | 1111 | rr = &requests[dns->id]; |
1112 | |||
1113 | /* clean up from previous request */ | ||
1114 | GNUNET_free_non_null (rr->payload); | ||
1115 | rr->payload = NULL; | ||
1116 | GNUNET_array_grow (rr->client_wait_list, | ||
1117 | rr->client_wait_list_length, | ||
1118 | 0); | ||
1119 | |||
1120 | /* setup new request */ | ||
1121 | rr->phase = RP_INIT; | ||
1122 | if (ip4->version == IPVERSION) | ||
1123 | { | ||
1124 | srca4 = (struct sockaddr_in*) &rr->src_addr; | ||
1125 | dsta4 = (struct sockaddr_in*) &rr->dst_addr; | ||
1126 | memset (srca4, 0, sizeof (struct sockaddr_in)); | ||
1127 | memset (dsta4, 0, sizeof (struct sockaddr_in)); | ||
1128 | srca4->sin_family = AF_INET; | ||
1129 | dsta4->sin_family = AF_INET; | ||
1130 | srca4->sin_addr = ip4->source_address; | ||
1131 | dsta4->sin_addr = ip4->destination_address; | ||
1132 | srca4->sin_port = udp->spt; | ||
1133 | dsta4->sin_port = udp->dpt; | ||
1134 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1135 | srca4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1136 | dsta4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1137 | #endif | ||
1138 | } | ||
1139 | else /* ipv6 */ | ||
1140 | { | ||
1141 | srca6 = (struct sockaddr_in6*) &rr->src_addr; | ||
1142 | dsta6 = (struct sockaddr_in6*) &rr->dst_addr; | ||
1143 | memset (srca6, 0, sizeof (struct sockaddr_in6)); | ||
1144 | memset (dsta6, 0, sizeof (struct sockaddr_in6)); | ||
1145 | srca6->sin6_family = AF_INET6; | ||
1146 | dsta6->sin6_family = AF_INET6; | ||
1147 | srca6->sin6_addr = ip6->source_address; | ||
1148 | dsta6->sin6_addr = ip6->destination_address; | ||
1149 | srca6->sin6_port = udp->spt; | ||
1150 | dsta6->sin6_port = udp->dpt; | ||
1151 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1152 | srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1153 | dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1154 | #endif | ||
1155 | } | ||
1156 | rr->payload = GNUNET_malloc (msize); | ||
1157 | rr->payload_length = msize; | ||
1158 | memcpy (rr->payload, dns, msize); | ||
1159 | rr->request_id = dns->id | (request_id_gen << 16); | ||
1160 | request_id_gen++; | ||
1161 | |||
1162 | GNUNET_STATISTICS_update (stats, | ||
1163 | gettext_noop ("# DNS requests received via TUN interface"), | ||
1164 | 1, GNUNET_NO); | ||
1165 | /* start request processing state machine */ | ||
1166 | next_phase (rr); | ||
1673 | } | 1167 | } |
1674 | 1168 | ||
1169 | |||
1675 | /** | 1170 | /** |
1676 | * @param cls closure | 1171 | * @param cls closure |
1677 | * @param server the initialized server | 1172 | * @param server the initialized server |
@@ -1683,51 +1178,102 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
1683 | { | 1178 | { |
1684 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | 1179 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { |
1685 | /* callback, cls, type, size */ | 1180 | /* callback, cls, type, size */ |
1686 | {&receive_query, NULL, GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS, 0}, | 1181 | {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, |
1687 | {&rehijack, NULL, GNUNET_MESSAGE_TYPE_REHIJACK, | 1182 | sizeof (struct GNUNET_DNS_Register)}, |
1688 | sizeof (struct GNUNET_MessageHeader)}, | 1183 | {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, |
1689 | {NULL, NULL, 0, 0} | 1184 | {NULL, NULL, 0, 0} |
1690 | }; | 1185 | }; |
1186 | char port_s[6]; | ||
1187 | char *ifc_name; | ||
1188 | char *ipv4addr; | ||
1189 | char *ipv4mask; | ||
1190 | char *ipv6addr; | ||
1191 | char *ipv6prefix; | ||
1691 | 1192 | ||
1692 | static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = { | 1193 | cfg = cfg_; |
1693 | {receive_mesh_query, GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS, 0}, | 1194 | stats = GNUNET_STATISTICS_create ("dns", cfg); |
1694 | {receive_mesh_answer, GNUNET_MESSAGE_TYPE_VPN_REMOTE_ANSWER_DNS, 0}, | 1195 | nc = GNUNET_SERVER_notification_context_create (server, 1); |
1695 | {NULL, 0, 0} | 1196 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, |
1696 | }; | 1197 | cls); |
1697 | 1198 | if (GNUNET_YES == | |
1698 | static GNUNET_MESH_ApplicationType apptypes[] = { | 1199 | GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) |
1699 | GNUNET_APPLICATION_TYPE_END, | 1200 | { |
1700 | GNUNET_APPLICATION_TYPE_END | 1201 | if ( (GNUNET_OK != open_port4 ()) && |
1701 | }; | 1202 | (GNUNET_OK != open_port6 ()) ) |
1203 | { | ||
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1205 | _("Failed to open any port to provide DNS exit\n")); | ||
1206 | GNUNET_SCHEDULER_shutdown (); | ||
1207 | return; | ||
1208 | } | ||
1209 | } | ||
1702 | 1210 | ||
1703 | if (GNUNET_YES != open_port6 ()) | 1211 | helper_argv[0] = GNUNET_strdup ("gnunet-dns"); |
1212 | if (GNUNET_SYSERR == | ||
1213 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) | ||
1704 | { | 1214 | { |
1215 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1216 | "No entry 'IFNAME' in configuration!\n"); | ||
1705 | GNUNET_SCHEDULER_shutdown (); | 1217 | GNUNET_SCHEDULER_shutdown (); |
1706 | return; | 1218 | return; |
1707 | } | 1219 | } |
1708 | 1220 | helper_argv[1] = ifc_name; | |
1709 | if (GNUNET_YES != open_port ()) | 1221 | if ( (GNUNET_SYSERR == |
1222 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR", | ||
1223 | &ipv6addr)) ) | ||
1710 | { | 1224 | { |
1225 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1226 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1711 | GNUNET_SCHEDULER_shutdown (); | 1227 | GNUNET_SCHEDULER_shutdown (); |
1712 | return; | 1228 | return; |
1713 | } | 1229 | } |
1230 | helper_argv[2] = ipv6addr; | ||
1231 | if (GNUNET_SYSERR == | ||
1232 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX", | ||
1233 | &ipv6prefix)) | ||
1234 | { | ||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1236 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1237 | GNUNET_SCHEDULER_shutdown (); | ||
1238 | return; | ||
1239 | } | ||
1240 | helper_argv[3] = ipv6prefix; | ||
1714 | 1241 | ||
1715 | if (GNUNET_YES == | 1242 | if (GNUNET_SYSERR == |
1716 | GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) | 1243 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR", |
1717 | apptypes[0] = GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER; | 1244 | &ipv4addr)) |
1718 | mesh_handle = | 1245 | { |
1719 | GNUNET_MESH_connect (cfg_, 42, NULL, new_tunnel, clean_tunnel, | 1246 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1720 | mesh_handlers, apptypes); | 1247 | "No entry 'IPV4ADDR' in configuration!\n"); |
1721 | 1248 | GNUNET_SCHEDULER_shutdown (); | |
1722 | cfg = cfg_; | 1249 | return; |
1723 | dht = GNUNET_DHT_connect (cfg, 1024); | 1250 | } |
1724 | GNUNET_SCHEDULER_add_now (publish_names, NULL); | 1251 | helper_argv[4] = ipv4addr; |
1252 | if (GNUNET_SYSERR == | ||
1253 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", | ||
1254 | &ipv4mask)) | ||
1255 | { | ||
1256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1257 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1258 | GNUNET_SCHEDULER_shutdown (); | ||
1259 | return; | ||
1260 | } | ||
1261 | helper_argv[5] = ipv4mask; | ||
1262 | GNUNET_snprintf (port_s, | ||
1263 | sizeof (port_s), | ||
1264 | "%u", | ||
1265 | (unsigned int) dnsoutport); | ||
1266 | helper_argv[6] = GNUNET_strdup (port_s); | ||
1267 | helper_argv[7] = NULL; | ||
1268 | hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", | ||
1269 | helper_argv, | ||
1270 | &process_helper_messages, | ||
1271 | NULL); | ||
1725 | GNUNET_SERVER_add_handlers (server, handlers); | 1272 | GNUNET_SERVER_add_handlers (server, handlers); |
1726 | GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); | 1273 | GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); |
1727 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | ||
1728 | cls); | ||
1729 | } | 1274 | } |
1730 | 1275 | ||
1276 | |||
1731 | /** | 1277 | /** |
1732 | * The main function for the dns service. | 1278 | * The main function for the dns service. |
1733 | * | 1279 | * |
@@ -1742,3 +1288,6 @@ main (int argc, char *const *argv) | |||
1742 | GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, | 1288 | GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, |
1743 | &run, NULL)) ? 0 : 1; | 1289 | &run, NULL)) ? 0 : 1; |
1744 | } | 1290 | } |
1291 | |||
1292 | |||
1293 | /* end of gnunet-service-dns_new.c */ | ||
diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c deleted file mode 100644 index 0bb7fb21c..000000000 --- a/src/dns/gnunet-service-dns_new.c +++ /dev/null | |||
@@ -1,1293 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2012 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 dns/gnunet-service-dns_new.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_constants.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_signatures.h" | ||
30 | #include "dns_new.h" | ||
31 | #include "gnunet_dns_service-new.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include "tcpip_tun.h" | ||
34 | |||
35 | #ifndef IPVERSION | ||
36 | #define IPVERSION 4 | ||
37 | #endif | ||
38 | |||
39 | /** | ||
40 | * Phases each request goes through. | ||
41 | */ | ||
42 | enum RequestPhase | ||
43 | { | ||
44 | /** | ||
45 | * Request has just been received. | ||
46 | */ | ||
47 | RP_INIT, | ||
48 | |||
49 | /** | ||
50 | * Showing the request to all monitor clients. If | ||
51 | * client list is empty, will enter QUERY phase. | ||
52 | */ | ||
53 | RP_REQUEST_MONITOR, | ||
54 | |||
55 | /** | ||
56 | * Showing the request to PRE-RESOLUTION clients to find an answer. | ||
57 | * If client list is empty, will trigger global DNS request. | ||
58 | */ | ||
59 | RP_QUERY, | ||
60 | |||
61 | /** | ||
62 | * Global Internet query is now pending. | ||
63 | */ | ||
64 | RP_INTERNET_DNS, | ||
65 | |||
66 | /** | ||
67 | * Client (or global DNS request) has resulted in a response. | ||
68 | * Forward to all POST-RESOLUTION clients. If client list is empty, | ||
69 | * will enter RESPONSE_MONITOR phase. | ||
70 | */ | ||
71 | RP_MODIFY, | ||
72 | |||
73 | /** | ||
74 | * Showing the request to all monitor clients. If | ||
75 | * client list is empty, give the result to the hijacker (and be done). | ||
76 | */ | ||
77 | RP_RESPONSE_MONITOR, | ||
78 | |||
79 | /** | ||
80 | * Some client has told us to drop the request. | ||
81 | */ | ||
82 | RP_DROP | ||
83 | }; | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Entry we keep for each client. | ||
88 | */ | ||
89 | struct ClientRecord | ||
90 | { | ||
91 | /** | ||
92 | * Kept in doubly-linked list. | ||
93 | */ | ||
94 | struct ClientRecord *next; | ||
95 | |||
96 | /** | ||
97 | * Kept in doubly-linked list. | ||
98 | */ | ||
99 | struct ClientRecord *prev; | ||
100 | |||
101 | /** | ||
102 | * Handle to the client. | ||
103 | */ | ||
104 | struct GNUNET_SERVER_Client *client; | ||
105 | |||
106 | /** | ||
107 | * Flags for the client. | ||
108 | */ | ||
109 | enum GNUNET_DNS_Flags flags; | ||
110 | |||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
115 | * Entry we keep for each active request. | ||
116 | */ | ||
117 | struct RequestRecord | ||
118 | { | ||
119 | |||
120 | /** | ||
121 | * List of clients that still need to see this request (each entry | ||
122 | * is set to NULL when the client is done). | ||
123 | */ | ||
124 | struct ClientRecord **client_wait_list; | ||
125 | |||
126 | /** | ||
127 | * Payload of the UDP packet (the UDP payload), can be either query | ||
128 | * or already the response. | ||
129 | */ | ||
130 | char *payload; | ||
131 | |||
132 | /** | ||
133 | * Source address of the original request (for sending response). | ||
134 | */ | ||
135 | struct sockaddr_storage src_addr; | ||
136 | |||
137 | /** | ||
138 | * Destination address of the original request (for potential use as exit). | ||
139 | */ | ||
140 | struct sockaddr_storage dst_addr; | ||
141 | |||
142 | /** | ||
143 | * ID of this request, also basis for hashing. Lowest 16 bit will | ||
144 | * be our message ID when doing a global DNS request and our index | ||
145 | * into the 'requests' array. | ||
146 | */ | ||
147 | uint64_t request_id; | ||
148 | |||
149 | /** | ||
150 | * Number of bytes in payload. | ||
151 | */ | ||
152 | size_t payload_length; | ||
153 | |||
154 | /** | ||
155 | * Length of the client wait list. | ||
156 | */ | ||
157 | unsigned int client_wait_list_length; | ||
158 | |||
159 | /** | ||
160 | * In which phase this this request? | ||
161 | */ | ||
162 | enum RequestPhase phase; | ||
163 | |||
164 | }; | ||
165 | |||
166 | |||
167 | /** | ||
168 | * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be | ||
169 | * sent through gnunet. The port of this socket will not be hijacked. | ||
170 | */ | ||
171 | static struct GNUNET_NETWORK_Handle *dnsout4; | ||
172 | |||
173 | /** | ||
174 | * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be | ||
175 | * sent through gnunet. The port of this socket will not be hijacked. | ||
176 | */ | ||
177 | static struct GNUNET_NETWORK_Handle *dnsout6; | ||
178 | |||
179 | /** | ||
180 | * Task for reading from dnsout4. | ||
181 | */ | ||
182 | static GNUNET_SCHEDULER_TaskIdentifier read4_task; | ||
183 | |||
184 | /** | ||
185 | * Task for reading from dnsout6. | ||
186 | */ | ||
187 | static GNUNET_SCHEDULER_TaskIdentifier read6_task; | ||
188 | |||
189 | /** | ||
190 | * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind | ||
191 | * both sockets to the same port. | ||
192 | */ | ||
193 | static uint16_t dnsoutport; | ||
194 | |||
195 | /** | ||
196 | * The configuration to use | ||
197 | */ | ||
198 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
199 | |||
200 | /** | ||
201 | * Statistics. | ||
202 | */ | ||
203 | static struct GNUNET_STATISTICS_Handle *stats; | ||
204 | |||
205 | /** | ||
206 | * Handle to DNS hijacker helper process ("gnunet-helper-dns"). | ||
207 | */ | ||
208 | static struct GNUNET_HELPER_Handle *hijacker; | ||
209 | |||
210 | /** | ||
211 | * Command-line arguments we are giving to the hijacker process. | ||
212 | */ | ||
213 | static char *helper_argv[8]; | ||
214 | |||
215 | /** | ||
216 | * Head of DLL of clients we consult. | ||
217 | */ | ||
218 | static struct ClientRecord *clients_head; | ||
219 | |||
220 | /** | ||
221 | * Tail of DLL of clients we consult. | ||
222 | */ | ||
223 | static struct ClientRecord *clients_tail; | ||
224 | |||
225 | /** | ||
226 | * Our notification context. | ||
227 | */ | ||
228 | static struct GNUNET_SERVER_NotificationContext *nc; | ||
229 | |||
230 | /** | ||
231 | * Array of all open requests. | ||
232 | */ | ||
233 | static struct RequestRecord requests[UINT16_MAX + 1]; | ||
234 | |||
235 | /** | ||
236 | * Generator for unique request IDs. | ||
237 | */ | ||
238 | static uint64_t request_id_gen; | ||
239 | |||
240 | |||
241 | /** | ||
242 | * We're done processing a DNS request, free associated memory. | ||
243 | * | ||
244 | * @param rr request to clean up | ||
245 | */ | ||
246 | static void | ||
247 | cleanup_rr (struct RequestRecord *rr) | ||
248 | { | ||
249 | GNUNET_free_non_null (rr->payload); | ||
250 | rr->payload = NULL; | ||
251 | rr->payload_length = 0; | ||
252 | GNUNET_array_grow (rr->client_wait_list, | ||
253 | rr->client_wait_list_length, | ||
254 | 0); | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Task run during shutdown. | ||
260 | * | ||
261 | * @param cls unused | ||
262 | * @param tc unused | ||
263 | */ | ||
264 | static void | ||
265 | cleanup_task (void *cls GNUNET_UNUSED, | ||
266 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
267 | { | ||
268 | unsigned int i; | ||
269 | |||
270 | GNUNET_HELPER_stop (hijacker); | ||
271 | hijacker = NULL; | ||
272 | for (i=0;i<8;i++) | ||
273 | GNUNET_free_non_null (helper_argv[i]); | ||
274 | if (NULL != dnsout4) | ||
275 | { | ||
276 | GNUNET_NETWORK_socket_close (dnsout4); | ||
277 | dnsout4 = NULL; | ||
278 | } | ||
279 | if (GNUNET_SCHEDULER_NO_TASK != read4_task) | ||
280 | { | ||
281 | GNUNET_SCHEDULER_cancel (read4_task); | ||
282 | read4_task = GNUNET_SCHEDULER_NO_TASK; | ||
283 | } | ||
284 | if (NULL != dnsout6) | ||
285 | { | ||
286 | GNUNET_NETWORK_socket_close (dnsout6); | ||
287 | dnsout6 = NULL; | ||
288 | } | ||
289 | if (GNUNET_SCHEDULER_NO_TASK != read6_task) | ||
290 | { | ||
291 | GNUNET_SCHEDULER_cancel (read6_task); | ||
292 | read6_task = GNUNET_SCHEDULER_NO_TASK; | ||
293 | } | ||
294 | for (i=0;i<65536;i++) | ||
295 | cleanup_rr (&requests[i]); | ||
296 | GNUNET_SERVER_notification_context_destroy (nc); | ||
297 | nc = NULL; | ||
298 | if (stats != NULL) | ||
299 | { | ||
300 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
301 | stats = NULL; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | |||
306 | /** | ||
307 | * We're done with some request, finish processing. | ||
308 | * | ||
309 | * @param rr request send to the network or just clean up. | ||
310 | */ | ||
311 | static void | ||
312 | request_done (struct RequestRecord *rr) | ||
313 | { | ||
314 | struct GNUNET_MessageHeader *hdr; | ||
315 | size_t reply_len; | ||
316 | uint16_t spt; | ||
317 | uint16_t dpt; | ||
318 | |||
319 | GNUNET_array_grow (rr->client_wait_list, | ||
320 | rr->client_wait_list_length, | ||
321 | 0); | ||
322 | if (RP_RESPONSE_MONITOR != rr->phase) | ||
323 | { | ||
324 | /* no response, drop */ | ||
325 | cleanup_rr (rr); | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | /* send response via hijacker */ | ||
330 | reply_len = sizeof (struct GNUNET_MessageHeader); | ||
331 | reply_len += sizeof (struct tun_header); | ||
332 | switch (rr->src_addr.ss_family) | ||
333 | { | ||
334 | case AF_INET: | ||
335 | reply_len += sizeof (struct ip4_header); | ||
336 | break; | ||
337 | case AF_INET6: | ||
338 | reply_len += sizeof (struct ip6_header); | ||
339 | break; | ||
340 | default: | ||
341 | GNUNET_break (0); | ||
342 | cleanup_rr (rr); | ||
343 | return; | ||
344 | } | ||
345 | reply_len += sizeof (struct udp_packet); | ||
346 | reply_len += rr->payload_length; | ||
347 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
348 | { | ||
349 | /* response too big, drop */ | ||
350 | GNUNET_break (0); /* how can this be? */ | ||
351 | cleanup_rr(rr); | ||
352 | return; | ||
353 | } | ||
354 | { | ||
355 | char buf[reply_len]; | ||
356 | size_t off; | ||
357 | uint32_t udp_crc_sum; | ||
358 | |||
359 | /* first, GNUnet message header */ | ||
360 | hdr = (struct GNUNET_MessageHeader*) buf; | ||
361 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); | ||
362 | hdr->size = htons ((uint16_t) reply_len); | ||
363 | off = sizeof (struct GNUNET_MessageHeader); | ||
364 | |||
365 | /* first, TUN header */ | ||
366 | { | ||
367 | struct tun_header tun; | ||
368 | |||
369 | tun.flags = htons (0); | ||
370 | if (rr->src_addr.ss_family == AF_INET) | ||
371 | tun.proto = htons (ETH_P_IPV4); | ||
372 | else | ||
373 | tun.proto = htons (ETH_P_IPV6); | ||
374 | memcpy (&buf[off], &tun, sizeof (struct tun_header)); | ||
375 | off += sizeof (struct tun_header); | ||
376 | } | ||
377 | |||
378 | /* now IP header */ | ||
379 | udp_crc_sum = 0; | ||
380 | switch (rr->src_addr.ss_family) | ||
381 | { | ||
382 | case AF_INET: | ||
383 | { | ||
384 | struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; | ||
385 | struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; | ||
386 | struct ip4_header ip; | ||
387 | |||
388 | spt = dst->sin_port; | ||
389 | dpt = src->sin_port; | ||
390 | ip.header_length = sizeof (struct ip4_header) / 4; | ||
391 | ip.version = IPVERSION; /* aka 4 */ | ||
392 | ip.diff_serv = 0; | ||
393 | ip.total_length = htons ((uint16_t) reply_len - off); | ||
394 | ip.identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
395 | 65536); | ||
396 | ip.flags = 0; | ||
397 | ip.fragmentation_offset = 0; | ||
398 | ip.ttl = 255; /* or lower? */ | ||
399 | ip.protocol = IPPROTO_UDP; | ||
400 | ip.checksum = 0; /* checksum is optional */ | ||
401 | ip.source_address = dst->sin_addr; | ||
402 | ip.destination_address = src->sin_addr; | ||
403 | ip.checksum = GNUNET_CRYPTO_crc16_n (&ip, sizeof (ip)); | ||
404 | |||
405 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
406 | &ip.source_address, | ||
407 | sizeof (struct in_addr) * 2); | ||
408 | { | ||
409 | uint16_t tmp; | ||
410 | |||
411 | tmp = htons (IPPROTO_UDP); | ||
412 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
413 | &tmp, | ||
414 | sizeof (uint16_t)); | ||
415 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
416 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
417 | &tmp, | ||
418 | sizeof (uint16_t)); | ||
419 | } | ||
420 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
421 | off += sizeof (ip); | ||
422 | } | ||
423 | break; | ||
424 | case AF_INET6: | ||
425 | { | ||
426 | struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; | ||
427 | struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; | ||
428 | struct ip6_header ip; | ||
429 | |||
430 | spt = dst->sin6_port; | ||
431 | dpt = src->sin6_port; | ||
432 | ip.traffic_class_h = 0; | ||
433 | ip.version = 6; /* is there a named constant? I couldn't find one */ | ||
434 | ip.traffic_class_l = 0; | ||
435 | ip.flow_label = 0; | ||
436 | ip.payload_length = htons ((uint16_t) reply_len); | ||
437 | ip.next_header = IPPROTO_UDP; | ||
438 | ip.hop_limit = 255; /* or lower? */ | ||
439 | ip.source_address = dst->sin6_addr; | ||
440 | ip.destination_address = src->sin6_addr; | ||
441 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
442 | &ip.source_address, | ||
443 | sizeof (struct in6_addr) * 2); | ||
444 | { | ||
445 | uint32_t tmp; | ||
446 | |||
447 | tmp = htons (rr->payload_length + sizeof (struct udp_packet)); | ||
448 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
449 | &tmp, | ||
450 | sizeof (uint32_t)); | ||
451 | tmp = htons (IPPROTO_UDP); | ||
452 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
453 | &tmp, | ||
454 | sizeof (uint32_t)); | ||
455 | } | ||
456 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
457 | off += sizeof (ip); | ||
458 | } | ||
459 | break; | ||
460 | default: | ||
461 | GNUNET_assert (0); | ||
462 | } | ||
463 | |||
464 | /* now UDP header */ | ||
465 | { | ||
466 | struct udp_packet udp; | ||
467 | |||
468 | udp.spt = spt; | ||
469 | udp.dpt = dpt; | ||
470 | udp.len = htons (reply_len - off); | ||
471 | udp.crc = 0; | ||
472 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
473 | &udp, | ||
474 | sizeof (udp)); | ||
475 | udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, | ||
476 | rr->payload, | ||
477 | rr->payload_length); | ||
478 | udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum); | ||
479 | memcpy (&buf[off], &udp, sizeof (udp)); | ||
480 | off += sizeof (udp); | ||
481 | } | ||
482 | /* now DNS payload */ | ||
483 | { | ||
484 | memcpy (&buf[off], rr->payload, rr->payload_length); | ||
485 | off += rr->payload_length; | ||
486 | } | ||
487 | /* final checks & sending */ | ||
488 | GNUNET_assert (off == reply_len); | ||
489 | GNUNET_HELPER_send (hijacker, | ||
490 | hdr, | ||
491 | GNUNET_YES, | ||
492 | NULL, NULL); | ||
493 | GNUNET_STATISTICS_update (stats, | ||
494 | gettext_noop ("# DNS requests answered via TUN interface"), | ||
495 | 1, GNUNET_NO); | ||
496 | } | ||
497 | /* clean up, we're done */ | ||
498 | cleanup_rr (rr); | ||
499 | } | ||
500 | |||
501 | |||
502 | /** | ||
503 | * Show the payload of the given request record to the client | ||
504 | * (and wait for a response). | ||
505 | * | ||
506 | * @param rr request to send to client | ||
507 | * @param client client to send the response to | ||
508 | */ | ||
509 | static void | ||
510 | send_request_to_client (struct RequestRecord *rr, | ||
511 | struct GNUNET_SERVER_Client *client) | ||
512 | { | ||
513 | char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; | ||
514 | struct GNUNET_DNS_Request *req; | ||
515 | |||
516 | if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
517 | { | ||
518 | GNUNET_break (0); | ||
519 | cleanup_rr (rr); | ||
520 | return; | ||
521 | } | ||
522 | req = (struct GNUNET_DNS_Request*) buf; | ||
523 | req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); | ||
524 | req->header.size = htons (sizeof (buf)); | ||
525 | req->reserved = htonl (0); | ||
526 | req->request_id = rr->request_id; | ||
527 | memcpy (&req[1], rr->payload, rr->payload_length); | ||
528 | GNUNET_SERVER_notification_context_unicast (nc, | ||
529 | client, | ||
530 | &req->header, | ||
531 | GNUNET_NO); | ||
532 | } | ||
533 | |||
534 | |||
535 | /** | ||
536 | * A client has completed its processing for this | ||
537 | * request. Move on. | ||
538 | * | ||
539 | * @param rr request to process further | ||
540 | */ | ||
541 | static void | ||
542 | next_phase (struct RequestRecord *rr) | ||
543 | { | ||
544 | struct ClientRecord *cr; | ||
545 | int nz; | ||
546 | unsigned int j; | ||
547 | struct GNUNET_NETWORK_Handle *dnsout; | ||
548 | socklen_t salen; | ||
549 | |||
550 | if (rr->phase == RP_DROP) | ||
551 | { | ||
552 | cleanup_rr (rr); | ||
553 | return; | ||
554 | } | ||
555 | nz = -1; | ||
556 | for (j=0;j<rr->client_wait_list_length;j++) | ||
557 | { | ||
558 | if (NULL != rr->client_wait_list[j]) | ||
559 | { | ||
560 | nz = (int) j; | ||
561 | break; | ||
562 | } | ||
563 | } | ||
564 | if (-1 != nz) | ||
565 | { | ||
566 | send_request_to_client (rr, rr->client_wait_list[nz]->client); | ||
567 | return; | ||
568 | } | ||
569 | /* done with current phase, advance! */ | ||
570 | switch (rr->phase) | ||
571 | { | ||
572 | case RP_INIT: | ||
573 | rr->phase = RP_REQUEST_MONITOR; | ||
574 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
575 | { | ||
576 | if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) | ||
577 | GNUNET_array_append (rr->client_wait_list, | ||
578 | rr->client_wait_list_length, | ||
579 | cr); | ||
580 | } | ||
581 | next_phase (rr); | ||
582 | return; | ||
583 | case RP_REQUEST_MONITOR: | ||
584 | rr->phase = RP_QUERY; | ||
585 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
586 | { | ||
587 | if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) | ||
588 | GNUNET_array_append (rr->client_wait_list, | ||
589 | rr->client_wait_list_length, | ||
590 | cr); | ||
591 | } | ||
592 | next_phase (rr); | ||
593 | return; | ||
594 | case RP_QUERY: | ||
595 | rr->phase = RP_INTERNET_DNS; | ||
596 | switch (rr->dst_addr.ss_family) | ||
597 | { | ||
598 | case AF_INET: | ||
599 | dnsout = dnsout4; | ||
600 | salen = sizeof (struct ip4_header); | ||
601 | break; | ||
602 | case AF_INET6: | ||
603 | dnsout = dnsout6; | ||
604 | salen = sizeof (struct ip6_header); | ||
605 | break; | ||
606 | default: | ||
607 | GNUNET_break (0); | ||
608 | cleanup_rr (rr); | ||
609 | return; | ||
610 | } | ||
611 | if (NULL == dnsout) | ||
612 | { | ||
613 | GNUNET_STATISTICS_update (stats, | ||
614 | gettext_noop ("# DNS exit failed (address family not supported)"), | ||
615 | 1, GNUNET_NO); | ||
616 | cleanup_rr (rr); | ||
617 | return; | ||
618 | } | ||
619 | GNUNET_NETWORK_socket_sendto (dnsout, | ||
620 | rr->payload, | ||
621 | rr->payload_length, | ||
622 | (struct sockaddr*) &rr->dst_addr, | ||
623 | salen); | ||
624 | return; | ||
625 | case RP_INTERNET_DNS: | ||
626 | rr->phase = RP_MODIFY; | ||
627 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
628 | { | ||
629 | if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) | ||
630 | GNUNET_array_append (rr->client_wait_list, | ||
631 | rr->client_wait_list_length, | ||
632 | cr); | ||
633 | } | ||
634 | next_phase (rr); | ||
635 | return; | ||
636 | case RP_MODIFY: | ||
637 | rr->phase = RP_RESPONSE_MONITOR; | ||
638 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
639 | { | ||
640 | if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) | ||
641 | GNUNET_array_append (rr->client_wait_list, | ||
642 | rr->client_wait_list_length, | ||
643 | cr); | ||
644 | } | ||
645 | next_phase (rr); | ||
646 | return; | ||
647 | case RP_RESPONSE_MONITOR: | ||
648 | request_done (rr); | ||
649 | break; | ||
650 | case RP_DROP: | ||
651 | cleanup_rr (rr); | ||
652 | break; | ||
653 | default: | ||
654 | GNUNET_break (0); | ||
655 | cleanup_rr (rr); | ||
656 | break; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | |||
661 | /** | ||
662 | * A client disconnected, clean up after it. | ||
663 | * | ||
664 | * @param cls unused | ||
665 | * @param client handle of client that disconnected | ||
666 | */ | ||
667 | static void | ||
668 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
669 | { | ||
670 | struct ClientRecord *cr; | ||
671 | struct RequestRecord *rr; | ||
672 | unsigned int i; | ||
673 | unsigned int j; | ||
674 | |||
675 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
676 | { | ||
677 | if (cr->client == client) | ||
678 | { | ||
679 | GNUNET_SERVER_client_drop (client); | ||
680 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
681 | clients_tail, | ||
682 | cr); | ||
683 | for (i=0;i<UINT16_MAX;i++) | ||
684 | { | ||
685 | rr = &requests[i]; | ||
686 | if (0 == rr->client_wait_list_length) | ||
687 | continue; /* not in use */ | ||
688 | for (j=0;j<rr->client_wait_list_length;j++) | ||
689 | { | ||
690 | if (rr->client_wait_list[j] == cr) | ||
691 | { | ||
692 | rr->client_wait_list[j] = NULL; | ||
693 | next_phase (rr); | ||
694 | } | ||
695 | } | ||
696 | } | ||
697 | GNUNET_free (cr); | ||
698 | return; | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | |||
703 | |||
704 | /** | ||
705 | * Read a DNS response from the (unhindered) UDP-Socket | ||
706 | * | ||
707 | * @param cls socket to read from | ||
708 | * @param tc scheduler context (must be shutdown or read ready) | ||
709 | */ | ||
710 | static void | ||
711 | read_response (void *cls, | ||
712 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
713 | { | ||
714 | struct GNUNET_NETWORK_Handle *dnsout = cls; | ||
715 | struct sockaddr_in addr4; | ||
716 | struct sockaddr_in6 addr6; | ||
717 | struct sockaddr *addr; | ||
718 | struct dns_header *dns; | ||
719 | socklen_t addrlen; | ||
720 | struct RequestRecord *rr; | ||
721 | ssize_t r; | ||
722 | int len; | ||
723 | |||
724 | if (dnsout == dnsout4) | ||
725 | { | ||
726 | addrlen = sizeof (struct sockaddr_in); | ||
727 | addr = (struct sockaddr* ) &addr4; | ||
728 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
729 | dnsout, | ||
730 | &read_response, | ||
731 | dnsout); | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | addrlen = sizeof (struct sockaddr_in6); | ||
736 | addr = (struct sockaddr* ) &addr6; | ||
737 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
738 | dnsout, | ||
739 | &read_response, | ||
740 | dnsout); | ||
741 | } | ||
742 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
743 | return; | ||
744 | |||
745 | #ifndef MINGW | ||
746 | if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) | ||
747 | { | ||
748 | /* conservative choice: */ | ||
749 | len = 65536; | ||
750 | } | ||
751 | #else | ||
752 | /* port the code above? */ | ||
753 | len = 65536; | ||
754 | #endif | ||
755 | |||
756 | { | ||
757 | unsigned char buf[len]; | ||
758 | |||
759 | memset (addr, 0, addrlen); | ||
760 | r = GNUNET_NETWORK_socket_recvfrom (dnsout, | ||
761 | buf, sizeof (buf), | ||
762 | addr, &addrlen); | ||
763 | if (-1 == r) | ||
764 | { | ||
765 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); | ||
766 | return; | ||
767 | } | ||
768 | if (sizeof (struct dns_header) > r) | ||
769 | { | ||
770 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
771 | _("Received DNS response that is too small (%u bytes)"), | ||
772 | r); | ||
773 | return; | ||
774 | } | ||
775 | dns = (struct dns_header *) buf; | ||
776 | rr = &requests[dns->id]; | ||
777 | if (rr->phase != RP_INTERNET_DNS) | ||
778 | { | ||
779 | /* unexpected / bogus reply */ | ||
780 | GNUNET_STATISTICS_update (stats, | ||
781 | gettext_noop ("# External DNS response discarded (no matching request)"), | ||
782 | 1, GNUNET_NO); | ||
783 | return; | ||
784 | } | ||
785 | GNUNET_free_non_null (rr->payload); | ||
786 | rr->payload = GNUNET_malloc (len); | ||
787 | memcpy (rr->payload, buf, len); | ||
788 | rr->payload_length = len; | ||
789 | next_phase (rr); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Open source port for sending DNS request on IPv4. | ||
796 | * | ||
797 | * @return GNUNET_OK on success | ||
798 | */ | ||
799 | static int | ||
800 | open_port4 () | ||
801 | { | ||
802 | struct sockaddr_in addr; | ||
803 | socklen_t addrlen; | ||
804 | |||
805 | dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); | ||
806 | if (dnsout4 == NULL) | ||
807 | return GNUNET_SYSERR; | ||
808 | |||
809 | memset (&addr, 0, sizeof (struct sockaddr_in)); | ||
810 | addr.sin_family = AF_INET; | ||
811 | int err = GNUNET_NETWORK_socket_bind (dnsout4, | ||
812 | (struct sockaddr *) &addr, | ||
813 | sizeof (struct sockaddr_in)); | ||
814 | |||
815 | if (err != GNUNET_OK) | ||
816 | { | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
818 | _("Could not bind to any port: %s\n"), | ||
819 | STRERROR (errno)); | ||
820 | GNUNET_NETWORK_socket_close (dnsout4); | ||
821 | dnsout4 = NULL; | ||
822 | return GNUNET_SYSERR; | ||
823 | } | ||
824 | |||
825 | /* Read the port we bound to */ | ||
826 | addrlen = sizeof (struct sockaddr_in); | ||
827 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4), | ||
828 | (struct sockaddr *) &addr, | ||
829 | &addrlen)) | ||
830 | { | ||
831 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
832 | _("Could not determine port I got: %s\n"), | ||
833 | STRERROR (errno)); | ||
834 | GNUNET_NETWORK_socket_close (dnsout4); | ||
835 | dnsout4 = NULL; | ||
836 | return GNUNET_SYSERR; | ||
837 | } | ||
838 | dnsoutport = htons (addr.sin_port); | ||
839 | |||
840 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
841 | _("GNUnet DNS will exit on source port %u\n"), | ||
842 | (unsigned int) dnsoutport); | ||
843 | read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
844 | dnsout4, | ||
845 | &read_response, dnsout4); | ||
846 | return GNUNET_OK; | ||
847 | } | ||
848 | |||
849 | |||
850 | /** | ||
851 | * Open source port for sending DNS request on IPv6. Should be | ||
852 | * called AFTER open_port4. | ||
853 | * | ||
854 | * @return GNUNET_OK on success | ||
855 | */ | ||
856 | static int | ||
857 | open_port6 () | ||
858 | { | ||
859 | struct sockaddr_in6 addr; | ||
860 | socklen_t addrlen; | ||
861 | |||
862 | dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0); | ||
863 | if (dnsout6 == NULL) | ||
864 | { | ||
865 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
866 | _("Could not create IPv6 socket: %s\n"), | ||
867 | STRERROR (errno)); | ||
868 | return GNUNET_SYSERR; | ||
869 | } | ||
870 | memset (&addr, 0, sizeof (struct sockaddr_in6)); | ||
871 | addr.sin6_family = AF_INET6; | ||
872 | addr.sin6_port = htons (dnsoutport); | ||
873 | int err = GNUNET_NETWORK_socket_bind (dnsout6, | ||
874 | (struct sockaddr *) &addr, | ||
875 | sizeof (struct sockaddr_in6)); | ||
876 | |||
877 | if (err != GNUNET_OK) | ||
878 | { | ||
879 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
880 | _("Could not bind to port %u: %s\n"), | ||
881 | (unsigned int) dnsoutport, | ||
882 | STRERROR (errno)); | ||
883 | GNUNET_NETWORK_socket_close (dnsout6); | ||
884 | dnsout6 = NULL; | ||
885 | return GNUNET_SYSERR; | ||
886 | } | ||
887 | if (0 == dnsoutport) | ||
888 | { | ||
889 | addrlen = sizeof (struct sockaddr_in6); | ||
890 | if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6), | ||
891 | (struct sockaddr *) &addr, | ||
892 | &addrlen)) | ||
893 | { | ||
894 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
895 | _("Could not determine port I got: %s\n"), | ||
896 | STRERROR (errno)); | ||
897 | GNUNET_NETWORK_socket_close (dnsout6); | ||
898 | dnsout6 = NULL; | ||
899 | return GNUNET_SYSERR; | ||
900 | } | ||
901 | } | ||
902 | dnsoutport = htons (addr.sin6_port); | ||
903 | read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
904 | dnsout6, | ||
905 | &read_response, dnsout6); | ||
906 | return GNUNET_YES; | ||
907 | } | ||
908 | |||
909 | |||
910 | /** | ||
911 | * We got a new client. Make sure all new DNS requests pass by its desk. | ||
912 | * | ||
913 | * @param cls unused | ||
914 | * @param client the new client | ||
915 | * @param message the init message (unused) | ||
916 | */ | ||
917 | static void | ||
918 | handle_client_init (void *cls GNUNET_UNUSED, | ||
919 | struct GNUNET_SERVER_Client *client, | ||
920 | const struct GNUNET_MessageHeader *message) | ||
921 | { | ||
922 | struct ClientRecord *cr; | ||
923 | const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; | ||
924 | |||
925 | cr = GNUNET_malloc (sizeof (struct ClientRecord)); | ||
926 | cr->client = client; | ||
927 | cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); | ||
928 | GNUNET_SERVER_client_keep (client); | ||
929 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
930 | clients_tail, | ||
931 | cr); | ||
932 | GNUNET_SERVER_notification_context_add (nc, client); | ||
933 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
934 | } | ||
935 | |||
936 | |||
937 | /** | ||
938 | * We got a response from a client. | ||
939 | * | ||
940 | * @param cls unused | ||
941 | * @param client the client | ||
942 | * @param message the response | ||
943 | */ | ||
944 | static void | ||
945 | handle_client_response (void *cls GNUNET_UNUSED, | ||
946 | struct GNUNET_SERVER_Client *client, | ||
947 | const struct GNUNET_MessageHeader *message) | ||
948 | { | ||
949 | const struct GNUNET_DNS_Response *resp; | ||
950 | struct RequestRecord *rr; | ||
951 | unsigned int i; | ||
952 | uint16_t msize; | ||
953 | uint16_t off; | ||
954 | |||
955 | msize = ntohs (message->size); | ||
956 | if (msize < sizeof (struct GNUNET_DNS_Response)) | ||
957 | { | ||
958 | GNUNET_break (0); | ||
959 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
960 | return; | ||
961 | } | ||
962 | resp = (const struct GNUNET_DNS_Response*) message; | ||
963 | off = (uint16_t) resp->request_id; | ||
964 | rr = &requests[off]; | ||
965 | if (rr->request_id != resp->request_id) | ||
966 | { | ||
967 | GNUNET_STATISTICS_update (stats, | ||
968 | gettext_noop ("# Client response discarded (no matching request)"), | ||
969 | 1, GNUNET_NO); | ||
970 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
971 | return; | ||
972 | } | ||
973 | for (i=0;i<rr->client_wait_list_length;i++) | ||
974 | { | ||
975 | if (NULL == rr->client_wait_list[i]) | ||
976 | continue; | ||
977 | if (rr->client_wait_list[i]->client != client) | ||
978 | continue; | ||
979 | rr->client_wait_list[i] = NULL; | ||
980 | switch (ntohl (resp->drop_flag)) | ||
981 | { | ||
982 | case 0: /* drop */ | ||
983 | rr->phase = RP_DROP; | ||
984 | break; | ||
985 | case 1: /* no change */ | ||
986 | break; | ||
987 | case 2: /* update */ | ||
988 | msize -= sizeof (struct GNUNET_DNS_Response); | ||
989 | if ( (sizeof (struct dns_header) > msize) || | ||
990 | (RP_REQUEST_MONITOR == rr->phase) || | ||
991 | (RP_RESPONSE_MONITOR == rr->phase) ) | ||
992 | { | ||
993 | GNUNET_break (0); | ||
994 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
995 | next_phase (rr); | ||
996 | return; | ||
997 | } | ||
998 | GNUNET_free_non_null (rr->payload); | ||
999 | #if DEBUG_DNS | ||
1000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1001 | _("Changing DNS reply according to client specifications\n")); | ||
1002 | #endif | ||
1003 | rr->payload = GNUNET_malloc (msize); | ||
1004 | rr->payload_length = msize; | ||
1005 | memcpy (rr->payload, &resp[1], msize); | ||
1006 | if (rr->phase == RP_QUERY) | ||
1007 | { | ||
1008 | /* clear wait list, we're moving to MODIFY phase next */ | ||
1009 | GNUNET_array_grow (rr->client_wait_list, | ||
1010 | rr->client_wait_list_length, | ||
1011 | 0); | ||
1012 | } | ||
1013 | break; | ||
1014 | } | ||
1015 | next_phase (rr); | ||
1016 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1017 | return; | ||
1018 | } | ||
1019 | /* odd, client was not on our list for the request, that ought | ||
1020 | to be an error */ | ||
1021 | GNUNET_break (0); | ||
1022 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1023 | } | ||
1024 | |||
1025 | |||
1026 | /** | ||
1027 | * Functions with this signature are called whenever a complete | ||
1028 | * message is received by the tokenizer from the DNS hijack process. | ||
1029 | * | ||
1030 | * @param cls closure | ||
1031 | * @param client identification of the client | ||
1032 | * @param message the actual message, a DNS request we should handle | ||
1033 | */ | ||
1034 | static void | ||
1035 | process_helper_messages (void *cls GNUNET_UNUSED, void *client, | ||
1036 | const struct GNUNET_MessageHeader *message) | ||
1037 | { | ||
1038 | uint16_t msize; | ||
1039 | const struct tun_header *tun; | ||
1040 | const struct ip4_header *ip4; | ||
1041 | const struct ip6_header *ip6; | ||
1042 | const struct udp_packet *udp; | ||
1043 | const struct dns_header *dns; | ||
1044 | struct RequestRecord *rr; | ||
1045 | struct sockaddr_in *srca4; | ||
1046 | struct sockaddr_in6 *srca6; | ||
1047 | struct sockaddr_in *dsta4; | ||
1048 | struct sockaddr_in6 *dsta6; | ||
1049 | |||
1050 | msize = ntohs (message->size); | ||
1051 | if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header)) | ||
1052 | { | ||
1053 | /* non-IP packet received on TUN!? */ | ||
1054 | GNUNET_break (0); | ||
1055 | return; | ||
1056 | } | ||
1057 | msize -= sizeof (struct GNUNET_MessageHeader); | ||
1058 | tun = (const struct tun_header *) &message[1]; | ||
1059 | msize -= sizeof (struct tun_header); | ||
1060 | switch (ntohs (tun->proto)) | ||
1061 | { | ||
1062 | case ETH_P_IPV4: | ||
1063 | ip4 = (const struct ip4_header *) &tun[1]; | ||
1064 | if ( (msize < sizeof (struct ip4_header)) || | ||
1065 | (ip4->version != IPVERSION) || | ||
1066 | (ip4->header_length != sizeof (struct ip4_header) / 4) || | ||
1067 | (ntohs(ip4->total_length) != msize) || | ||
1068 | (ip4->protocol != IPPROTO_UDP) ) | ||
1069 | { | ||
1070 | /* non-IP/UDP packet received on TUN (or with options) */ | ||
1071 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1072 | _("Received malformed IPv4-UDP packet on TUN interface.\n")); | ||
1073 | return; | ||
1074 | } | ||
1075 | udp = (const struct udp_packet*) &ip4[1]; | ||
1076 | msize -= sizeof (struct ip4_header); | ||
1077 | break; | ||
1078 | case ETH_P_IPV6: | ||
1079 | ip6 = (const struct ip6_header *) &tun[1]; | ||
1080 | if ( (msize < sizeof (struct ip6_header)) || | ||
1081 | (ip6->version != 6) || | ||
1082 | (ntohs (ip6->payload_length) != msize) || | ||
1083 | (ip6->next_header != IPPROTO_UDP) ) | ||
1084 | { | ||
1085 | /* non-IP/UDP packet received on TUN (or with extensions) */ | ||
1086 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1087 | _("Received malformed IPv6-UDP packet on TUN interface.\n")); | ||
1088 | return; | ||
1089 | } | ||
1090 | udp = (const struct udp_packet*) &ip6[1]; | ||
1091 | msize -= sizeof (struct ip6_header); | ||
1092 | break; | ||
1093 | default: | ||
1094 | /* non-IP packet received on TUN!? */ | ||
1095 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1096 | _("Got non-IP packet with %u bytes and protocol %u from TUN\n"), | ||
1097 | (unsigned int) msize, | ||
1098 | ntohs (tun->proto)); | ||
1099 | return; | ||
1100 | } | ||
1101 | if (msize <= sizeof (struct udp_packet) + sizeof (struct dns_header)) | ||
1102 | { | ||
1103 | /* non-DNS packet received on TUN, ignore */ | ||
1104 | GNUNET_STATISTICS_update (stats, | ||
1105 | gettext_noop ("# Non-DNS UDP packet received via TUN interface"), | ||
1106 | 1, GNUNET_NO); | ||
1107 | return; | ||
1108 | } | ||
1109 | msize -= sizeof (struct udp_packet); | ||
1110 | dns = (const struct dns_header*) &udp[1]; | ||
1111 | rr = &requests[dns->id]; | ||
1112 | |||
1113 | /* clean up from previous request */ | ||
1114 | GNUNET_free_non_null (rr->payload); | ||
1115 | rr->payload = NULL; | ||
1116 | GNUNET_array_grow (rr->client_wait_list, | ||
1117 | rr->client_wait_list_length, | ||
1118 | 0); | ||
1119 | |||
1120 | /* setup new request */ | ||
1121 | rr->phase = RP_INIT; | ||
1122 | if (ip4->version == IPVERSION) | ||
1123 | { | ||
1124 | srca4 = (struct sockaddr_in*) &rr->src_addr; | ||
1125 | dsta4 = (struct sockaddr_in*) &rr->dst_addr; | ||
1126 | memset (srca4, 0, sizeof (struct sockaddr_in)); | ||
1127 | memset (dsta4, 0, sizeof (struct sockaddr_in)); | ||
1128 | srca4->sin_family = AF_INET; | ||
1129 | dsta4->sin_family = AF_INET; | ||
1130 | srca4->sin_addr = ip4->source_address; | ||
1131 | dsta4->sin_addr = ip4->destination_address; | ||
1132 | srca4->sin_port = udp->spt; | ||
1133 | dsta4->sin_port = udp->dpt; | ||
1134 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1135 | srca4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1136 | dsta4->sin_len = sizeof (sizeof (struct sockaddr_in)); | ||
1137 | #endif | ||
1138 | } | ||
1139 | else /* ipv6 */ | ||
1140 | { | ||
1141 | srca6 = (struct sockaddr_in6*) &rr->src_addr; | ||
1142 | dsta6 = (struct sockaddr_in6*) &rr->dst_addr; | ||
1143 | memset (srca6, 0, sizeof (struct sockaddr_in6)); | ||
1144 | memset (dsta6, 0, sizeof (struct sockaddr_in6)); | ||
1145 | srca6->sin6_family = AF_INET6; | ||
1146 | dsta6->sin6_family = AF_INET6; | ||
1147 | srca6->sin6_addr = ip6->source_address; | ||
1148 | dsta6->sin6_addr = ip6->destination_address; | ||
1149 | srca6->sin6_port = udp->spt; | ||
1150 | dsta6->sin6_port = udp->dpt; | ||
1151 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1152 | srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1153 | dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6)); | ||
1154 | #endif | ||
1155 | } | ||
1156 | rr->payload = GNUNET_malloc (msize); | ||
1157 | rr->payload_length = msize; | ||
1158 | memcpy (rr->payload, dns, msize); | ||
1159 | rr->request_id = dns->id | (request_id_gen << 16); | ||
1160 | request_id_gen++; | ||
1161 | |||
1162 | GNUNET_STATISTICS_update (stats, | ||
1163 | gettext_noop ("# DNS requests received via TUN interface"), | ||
1164 | 1, GNUNET_NO); | ||
1165 | /* start request processing state machine */ | ||
1166 | next_phase (rr); | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | /** | ||
1171 | * @param cls closure | ||
1172 | * @param server the initialized server | ||
1173 | * @param cfg_ configuration to use | ||
1174 | */ | ||
1175 | static void | ||
1176 | run (void *cls, struct GNUNET_SERVER_Handle *server, | ||
1177 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1178 | { | ||
1179 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
1180 | /* callback, cls, type, size */ | ||
1181 | {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, | ||
1182 | sizeof (struct GNUNET_DNS_Register)}, | ||
1183 | {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, | ||
1184 | {NULL, NULL, 0, 0} | ||
1185 | }; | ||
1186 | char port_s[6]; | ||
1187 | char *ifc_name; | ||
1188 | char *ipv4addr; | ||
1189 | char *ipv4mask; | ||
1190 | char *ipv6addr; | ||
1191 | char *ipv6prefix; | ||
1192 | |||
1193 | cfg = cfg_; | ||
1194 | stats = GNUNET_STATISTICS_create ("dns", cfg); | ||
1195 | nc = GNUNET_SERVER_notification_context_create (server, 1); | ||
1196 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | ||
1197 | cls); | ||
1198 | if (GNUNET_YES == | ||
1199 | GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) | ||
1200 | { | ||
1201 | if ( (GNUNET_OK != open_port4 ()) && | ||
1202 | (GNUNET_OK != open_port6 ()) ) | ||
1203 | { | ||
1204 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1205 | _("Failed to open any port to provide DNS exit\n")); | ||
1206 | GNUNET_SCHEDULER_shutdown (); | ||
1207 | return; | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | helper_argv[0] = GNUNET_strdup ("gnunet-dns"); | ||
1212 | if (GNUNET_SYSERR == | ||
1213 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) | ||
1214 | { | ||
1215 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1216 | "No entry 'IFNAME' in configuration!\n"); | ||
1217 | GNUNET_SCHEDULER_shutdown (); | ||
1218 | return; | ||
1219 | } | ||
1220 | helper_argv[1] = ifc_name; | ||
1221 | if ( (GNUNET_SYSERR == | ||
1222 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR", | ||
1223 | &ipv6addr)) ) | ||
1224 | { | ||
1225 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1226 | "No entry 'IPV6ADDR' in configuration!\n"); | ||
1227 | GNUNET_SCHEDULER_shutdown (); | ||
1228 | return; | ||
1229 | } | ||
1230 | helper_argv[2] = ipv6addr; | ||
1231 | if (GNUNET_SYSERR == | ||
1232 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX", | ||
1233 | &ipv6prefix)) | ||
1234 | { | ||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1236 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1237 | GNUNET_SCHEDULER_shutdown (); | ||
1238 | return; | ||
1239 | } | ||
1240 | helper_argv[3] = ipv6prefix; | ||
1241 | |||
1242 | if (GNUNET_SYSERR == | ||
1243 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR", | ||
1244 | &ipv4addr)) | ||
1245 | { | ||
1246 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1247 | "No entry 'IPV4ADDR' in configuration!\n"); | ||
1248 | GNUNET_SCHEDULER_shutdown (); | ||
1249 | return; | ||
1250 | } | ||
1251 | helper_argv[4] = ipv4addr; | ||
1252 | if (GNUNET_SYSERR == | ||
1253 | GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", | ||
1254 | &ipv4mask)) | ||
1255 | { | ||
1256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1257 | "No entry 'IPV4MASK' in configuration!\n"); | ||
1258 | GNUNET_SCHEDULER_shutdown (); | ||
1259 | return; | ||
1260 | } | ||
1261 | helper_argv[5] = ipv4mask; | ||
1262 | GNUNET_snprintf (port_s, | ||
1263 | sizeof (port_s), | ||
1264 | "%u", | ||
1265 | (unsigned int) dnsoutport); | ||
1266 | helper_argv[6] = GNUNET_strdup (port_s); | ||
1267 | helper_argv[7] = NULL; | ||
1268 | hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", | ||
1269 | helper_argv, | ||
1270 | &process_helper_messages, | ||
1271 | NULL); | ||
1272 | GNUNET_SERVER_add_handlers (server, handlers); | ||
1273 | GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); | ||
1274 | } | ||
1275 | |||
1276 | |||
1277 | /** | ||
1278 | * The main function for the dns service. | ||
1279 | * | ||
1280 | * @param argc number of arguments from the command line | ||
1281 | * @param argv command line arguments | ||
1282 | * @return 0 ok, 1 on error | ||
1283 | */ | ||
1284 | int | ||
1285 | main (int argc, char *const *argv) | ||
1286 | { | ||
1287 | return (GNUNET_OK == | ||
1288 | GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, | ||
1289 | &run, NULL)) ? 0 : 1; | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | /* end of gnunet-service-dns_new.c */ | ||