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/gnunet-service-dns.c | |
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/gnunet-service-dns.c')
-rw-r--r-- | src/dns/gnunet-service-dns.c | 2445 |
1 files changed, 997 insertions, 1448 deletions
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 */ | ||