diff options
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/dns_api_new.c | 21 | ||||
-rw-r--r-- | src/dns/dns_new.h | 18 | ||||
-rw-r--r-- | src/dns/gnunet-service-dns_new.c | 499 |
3 files changed, 371 insertions, 167 deletions
diff --git a/src/dns/dns_api_new.c b/src/dns/dns_api_new.c index a61676a47..b578c3a9d 100644 --- a/src/dns/dns_api_new.c +++ b/src/dns/dns_api_new.c | |||
@@ -125,6 +125,11 @@ struct GNUNET_DNS_Handle | |||
125 | * Re-connect counter, to make sure we did not reconnect in the meantime. | 125 | * Re-connect counter, to make sure we did not reconnect in the meantime. |
126 | */ | 126 | */ |
127 | uint32_t generation; | 127 | uint32_t generation; |
128 | |||
129 | /** | ||
130 | * Flags for events we care about. | ||
131 | */ | ||
132 | enum GNUNET_DNS_Flags flags; | ||
128 | 133 | ||
129 | /** | 134 | /** |
130 | * Did we start the receive loop yet? | 135 | * Did we start the receive loop yet? |
@@ -162,7 +167,7 @@ reconnect (void *cls, | |||
162 | { | 167 | { |
163 | struct GNUNET_DNS_Handle *dh = cls; | 168 | struct GNUNET_DNS_Handle *dh = cls; |
164 | struct ReplyQueueEntry *qe; | 169 | struct ReplyQueueEntry *qe; |
165 | struct GNUNET_MessageHeader *msg; | 170 | struct GNUNET_DNS_Register *msg; |
166 | 171 | ||
167 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | 172 | dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
168 | dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); | 173 | dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); |
@@ -170,11 +175,12 @@ reconnect (void *cls, | |||
170 | return; | 175 | return; |
171 | dh->generation++; | 176 | dh->generation++; |
172 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + | 177 | qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + |
173 | sizeof (struct GNUNET_MessageHeader)); | 178 | sizeof (struct GNUNET_DNS_Register)); |
174 | msg = (struct GNUNET_MessageHeader*) &qe[1]; | 179 | msg = (struct GNUNET_DNS_Register*) &qe[1]; |
175 | qe->msg = msg; | 180 | qe->msg = &msg->header; |
176 | msg->size = htons (sizeof (struct GNUNET_MessageHeader)); | 181 | msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); |
177 | msg->type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); | 182 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); |
183 | msg->flags = htonl (dh->flags); | ||
178 | queue_reply (dh, qe); | 184 | queue_reply (dh, qe); |
179 | } | 185 | } |
180 | 186 | ||
@@ -471,12 +477,14 @@ GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, | |||
471 | * Connect to the service-dns | 477 | * Connect to the service-dns |
472 | * | 478 | * |
473 | * @param cfg configuration to use | 479 | * @param cfg configuration to use |
480 | * @param flags when to call rh | ||
474 | * @param rh function to call with DNS requests | 481 | * @param rh function to call with DNS requests |
475 | * @param rh_cls closure to pass to rh | 482 | * @param rh_cls closure to pass to rh |
476 | * @return DNS handle | 483 | * @return DNS handle |
477 | */ | 484 | */ |
478 | struct GNUNET_DNS_Handle * | 485 | struct GNUNET_DNS_Handle * |
479 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 486 | GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, |
487 | enum GNUNET_DNS_Flags flags, | ||
480 | GNUNET_DNS_RequestHandler rh, | 488 | GNUNET_DNS_RequestHandler rh, |
481 | void *rh_cls) | 489 | void *rh_cls) |
482 | { | 490 | { |
@@ -484,6 +492,7 @@ GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
484 | 492 | ||
485 | dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); | 493 | dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); |
486 | dh->cfg = cfg; | 494 | dh->cfg = cfg; |
495 | dh->flags = flags; | ||
487 | dh->rh = rh; | 496 | dh->rh = rh; |
488 | dh->rh_cls = rh_cls; | 497 | dh->rh_cls = rh_cls; |
489 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); | 498 | dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); |
diff --git a/src/dns/dns_new.h b/src/dns/dns_new.h index 7cf3a316a..29a9f937b 100644 --- a/src/dns/dns_new.h +++ b/src/dns/dns_new.h | |||
@@ -28,6 +28,24 @@ | |||
28 | 28 | ||
29 | GNUNET_NETWORK_STRUCT_BEGIN | 29 | GNUNET_NETWORK_STRUCT_BEGIN |
30 | 30 | ||
31 | |||
32 | /** | ||
33 | * Message from client to DNS service to register itself. | ||
34 | */ | ||
35 | struct GNUNET_DNS_Register | ||
36 | { | ||
37 | /** | ||
38 | * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT | ||
39 | */ | ||
40 | struct GNUNET_MessageHeader header; | ||
41 | |||
42 | /** | ||
43 | * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. | ||
44 | */ | ||
45 | uint32_t flags; | ||
46 | }; | ||
47 | |||
48 | |||
31 | /** | 49 | /** |
32 | * Message from DNS service to client: please handle a request. | 50 | * Message from DNS service to client: please handle a request. |
33 | */ | 51 | */ |
diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c index ae57d9088..041b2d12b 100644 --- a/src/dns/gnunet-service-dns_new.c +++ b/src/dns/gnunet-service-dns_new.c | |||
@@ -22,27 +22,13 @@ | |||
22 | * @file dns/gnunet-service-dns_new.c | 22 | * @file dns/gnunet-service-dns_new.c |
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | */ | 24 | */ |
25 | // current thoughts: | ||
26 | // - for full compatibility to DNS and to avoid going insane here parsing/generating DNS packets, | ||
27 | // how about literally attaching the "original" DNS packet (request/response) to the IPC traffic? | ||
28 | // that way, clients can literally do arbitrary modifications and we are done with that issue here. | ||
29 | // All we'd do in here is add the IP/UDP headers and be DONE with it. | ||
30 | // => minor modifications to API and IPC protocol | ||
31 | // => minor modifications to our data structures | ||
32 | // => major gains in terms of simplicity here and what can (at least theoretically) be done with the service | ||
33 | // => can test much more quickly | ||
34 | // => but: need to really write a good libgnunetdnsparse to avoid making MANY clients really complicated | ||
35 | // (not the worst of worlds either, other than deferring this mess some...) | ||
36 | // -> also positive: can be tested independently of the rest of the mess | ||
37 | |||
38 | |||
39 | #include "platform.h" | 25 | #include "platform.h" |
40 | #include "gnunet_util_lib.h" | 26 | #include "gnunet_util_lib.h" |
41 | #include "gnunet_constants.h" | 27 | #include "gnunet_constants.h" |
42 | #include "gnunet_protocols.h" | 28 | #include "gnunet_protocols.h" |
43 | //#include "gnunet_dnsparser_lib.h" | ||
44 | #include "gnunet_signatures.h" | 29 | #include "gnunet_signatures.h" |
45 | #include "dns_new.h" | 30 | #include "dns_new.h" |
31 | #include "gnunet_dns_service-new.h" | ||
46 | 32 | ||
47 | GNUNET_NETWORK_STRUCT_BEGIN | 33 | GNUNET_NETWORK_STRUCT_BEGIN |
48 | struct ip4_hdr | 34 | struct ip4_hdr |
@@ -86,45 +72,58 @@ struct udp_pkt | |||
86 | uint16_t crc GNUNET_PACKED; | 72 | uint16_t crc GNUNET_PACKED; |
87 | }; | 73 | }; |
88 | 74 | ||
89 | struct dns_pkt | 75 | |
76 | struct dns_hdr | ||
90 | { | 77 | { |
91 | uint16_t id GNUNET_PACKED; | 78 | uint16_t id GNUNET_PACKED; |
92 | 79 | uint16_t flags GNUNET_PACKED; | |
93 | unsigned rd:1 GNUNET_PACKED; // recursion desired (client -> server) | 80 | uint16_t qdcount GNUNET_PACKED; |
94 | unsigned tc:1 GNUNET_PACKED; // message is truncated | 81 | uint16_t ancount GNUNET_PACKED; |
95 | unsigned aa:1 GNUNET_PACKED; // authoritative answer | 82 | uint16_t nscount GNUNET_PACKED; |
96 | unsigned op:4 GNUNET_PACKED; // query:0, inverse q.:1, status: 2 | 83 | uint16_t arcount GNUNET_PACKED; |
97 | unsigned qr:1 GNUNET_PACKED; // query:0, response:1 | ||
98 | |||
99 | unsigned rcode:4 GNUNET_PACKED; // 0 No error | ||
100 | // 1 Format error | ||
101 | // 2 Server failure | ||
102 | // 3 Name Error | ||
103 | // 4 Not Implemented | ||
104 | // 5 Refused | ||
105 | unsigned z:3 GNUNET_PACKED; // reserved | ||
106 | unsigned ra:1 GNUNET_PACKED; // recursion available (server -> client) | ||
107 | |||
108 | uint16_t qdcount GNUNET_PACKED; // number of questions | ||
109 | uint16_t ancount GNUNET_PACKED; // number of answers | ||
110 | uint16_t nscount GNUNET_PACKED; // number of authority-records | ||
111 | uint16_t arcount GNUNET_PACKED; // number of additional records | ||
112 | }; | 84 | }; |
85 | GNUNET_NETWORK_STRUCT_END | ||
113 | 86 | ||
114 | struct dns_query_line | ||
115 | { | ||
116 | uint16_t type; | ||
117 | uint16_t class; | ||
118 | }; | ||
119 | 87 | ||
120 | struct dns_record_line | 88 | /** |
89 | * Phases each request goes through. | ||
90 | */ | ||
91 | enum RequestPhase | ||
121 | { | 92 | { |
122 | uint16_t type; | 93 | /** |
123 | uint16_t class; | 94 | * Request has just been received. |
124 | uint32_t ttl; | 95 | */ |
125 | uint16_t data_len; | 96 | RP_INIT, |
97 | |||
98 | /** | ||
99 | * Showing the request to all monitor clients. If | ||
100 | * client list is empty, will enter QUERY phase. | ||
101 | */ | ||
102 | RP_MONITOR, | ||
103 | |||
104 | /** | ||
105 | * Showing the request to PRE-RESOLUTION clients to find an answer. | ||
106 | * If client list is empty, will trigger global DNS request. | ||
107 | */ | ||
108 | RP_QUERY, | ||
109 | |||
110 | /** | ||
111 | * Global Internet query is now pending. | ||
112 | */ | ||
113 | RP_INTERNET_DNS, | ||
114 | |||
115 | /** | ||
116 | * Client (or global DNS request) has resulted in a response. | ||
117 | * Forward to all POST-RESOLUTION clients. If client list is empty, | ||
118 | * give the result to the hijacker (and be done). | ||
119 | */ | ||
120 | RP_MODIFY, | ||
121 | |||
122 | /** | ||
123 | * Some client has told us to drop the request. | ||
124 | */ | ||
125 | RP_DROP | ||
126 | }; | 126 | }; |
127 | GNUNET_NETWORK_STRUCT_END | ||
128 | 127 | ||
129 | 128 | ||
130 | /** | 129 | /** |
@@ -147,6 +146,11 @@ struct ClientRecord | |||
147 | */ | 146 | */ |
148 | struct GNUNET_SERVER_Client *client; | 147 | struct GNUNET_SERVER_Client *client; |
149 | 148 | ||
149 | /** | ||
150 | * Flags for the client. | ||
151 | */ | ||
152 | enum GNUNET_DNS_Flags flags; | ||
153 | |||
150 | }; | 154 | }; |
151 | 155 | ||
152 | 156 | ||
@@ -157,25 +161,16 @@ struct RequestRecord | |||
157 | { | 161 | { |
158 | 162 | ||
159 | /** | 163 | /** |
160 | * Name for the request. | ||
161 | */ | ||
162 | char *name; | ||
163 | |||
164 | /** | ||
165 | * Response data, or NULL if not known. | ||
166 | */ | ||
167 | char *rdata; | ||
168 | |||
169 | /** | ||
170 | * List of clients that still need to see this request (each entry | 164 | * List of clients that still need to see this request (each entry |
171 | * is set to NULL when the client is done). | 165 | * is set to NULL when the client is done). |
172 | */ | 166 | */ |
173 | struct ClientRecord **client_wait_list; | 167 | struct ClientRecord **client_wait_list; |
174 | 168 | ||
175 | /** | 169 | /** |
176 | * Length of the client wait list. | 170 | * Payload of the UDP packet (the UDP payload), can be either query |
171 | * or already the response. | ||
177 | */ | 172 | */ |
178 | unsigned int client_wait_list_length; | 173 | char *payload; |
179 | 174 | ||
180 | /** | 175 | /** |
181 | * Source address of the original request (for sending response). | 176 | * Source address of the original request (for sending response). |
@@ -195,34 +190,19 @@ struct RequestRecord | |||
195 | uint64_t request_id; | 190 | uint64_t request_id; |
196 | 191 | ||
197 | /** | 192 | /** |
198 | * TTL if we know it, or 0. | 193 | * Number of bytes in payload. |
199 | */ | ||
200 | uint32_t dns_ttl; | ||
201 | |||
202 | /** | ||
203 | * Number of bytes in rdata. | ||
204 | */ | 194 | */ |
205 | uint16_t rdata_length; | 195 | size_t payload_length; |
206 | 196 | ||
207 | /** | 197 | /** |
208 | * Length of the 'name' string, including 0-terminator. | 198 | * Length of the client wait list. |
209 | */ | ||
210 | uint16_t name_length; | ||
211 | |||
212 | /** | ||
213 | * The DNS type (i.e. 1 == 'A'). | ||
214 | */ | ||
215 | uint16_t dns_type; | ||
216 | |||
217 | /** | ||
218 | * The DNS class (i.e. 1 == Internet) | ||
219 | */ | 199 | */ |
220 | uint16_t dns_class; | 200 | unsigned int client_wait_list_length; |
221 | 201 | ||
222 | /** | 202 | /** |
223 | * Original DNS Id we got from the client. | 203 | * In which phase this this request? |
224 | */ | 204 | */ |
225 | uint16_t original_dns_id; | 205 | enum RequestPhase phase; |
226 | 206 | ||
227 | }; | 207 | }; |
228 | 208 | ||
@@ -281,6 +261,11 @@ static struct ClientRecord *clients_head; | |||
281 | static struct ClientRecord *clients_tail; | 261 | static struct ClientRecord *clients_tail; |
282 | 262 | ||
283 | /** | 263 | /** |
264 | * Our notification context. | ||
265 | */ | ||
266 | static struct GNUNET_SERVER_NotificationContext *nc; | ||
267 | |||
268 | /** | ||
284 | * Array of all open requests. | 269 | * Array of all open requests. |
285 | */ | 270 | */ |
286 | static struct RequestRecord requests[UINT16_MAX]; | 271 | static struct RequestRecord requests[UINT16_MAX]; |
@@ -292,6 +277,23 @@ static uint64_t request_id_gen; | |||
292 | 277 | ||
293 | 278 | ||
294 | /** | 279 | /** |
280 | * We're done processing a DNS request, free associated memory. | ||
281 | * | ||
282 | * @param rr request to clean up | ||
283 | */ | ||
284 | static void | ||
285 | cleanup_rr (struct RequestRecord *rr) | ||
286 | { | ||
287 | GNUNET_free (rr->payload); | ||
288 | rr->payload = NULL; | ||
289 | rr->payload_length = 0; | ||
290 | GNUNET_array_grow (rr->client_wait_list, | ||
291 | rr->client_wait_list_length, | ||
292 | 0); | ||
293 | } | ||
294 | |||
295 | |||
296 | /** | ||
295 | * Task run during shutdown. | 297 | * Task run during shutdown. |
296 | * | 298 | * |
297 | * @param cls unused | 299 | * @param cls unused |
@@ -302,7 +304,6 @@ cleanup_task (void *cls GNUNET_UNUSED, | |||
302 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 304 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
303 | { | 305 | { |
304 | unsigned int i; | 306 | unsigned int i; |
305 | struct RequestRecord *rr; | ||
306 | 307 | ||
307 | GNUNET_HELPER_stop (hijacker); | 308 | GNUNET_HELPER_stop (hijacker); |
308 | hijacker = NULL; | 309 | hijacker = NULL; |
@@ -329,19 +330,16 @@ cleanup_task (void *cls GNUNET_UNUSED, | |||
329 | read6_task = GNUNET_SCHEDULER_NO_TASK; | 330 | read6_task = GNUNET_SCHEDULER_NO_TASK; |
330 | } | 331 | } |
331 | for (i=0;i<65536;i++) | 332 | for (i=0;i<65536;i++) |
332 | { | 333 | cleanup_rr (&requests[i]); |
333 | rr = &requests[i]; | 334 | GNUNET_SERVER_notification_context_destroy (nc); |
334 | GNUNET_free (rr->name); | 335 | nc = NULL; |
335 | GNUNET_free_non_null (rr->rdata); | ||
336 | GNUNET_array_grow (rr->client_wait_list, | ||
337 | rr->client_wait_list_length, | ||
338 | 0); | ||
339 | } | ||
340 | } | 336 | } |
341 | 337 | ||
342 | 338 | ||
343 | /** | 339 | /** |
344 | * We're done with some request, finish processing. | 340 | * We're done with some request, finish processing. |
341 | * | ||
342 | * @param rr request send to the network or just clean up. | ||
345 | */ | 343 | */ |
346 | static void | 344 | static void |
347 | request_done (struct RequestRecord *rr) | 345 | request_done (struct RequestRecord *rr) |
@@ -354,11 +352,10 @@ request_done (struct RequestRecord *rr) | |||
354 | GNUNET_array_grow (rr->client_wait_list, | 352 | GNUNET_array_grow (rr->client_wait_list, |
355 | rr->client_wait_list_length, | 353 | rr->client_wait_list_length, |
356 | 0); | 354 | 0); |
357 | if (NULL == rr->rdata) | 355 | if (RP_MODIFY != rr->phase) |
358 | { | 356 | { |
359 | /* no response, drop */ | 357 | /* no response, drop */ |
360 | GNUNET_free (rr->name); | 358 | cleanup_rr (rr); |
361 | rr->name = NULL; | ||
362 | return; | 359 | return; |
363 | } | 360 | } |
364 | 361 | ||
@@ -374,21 +371,16 @@ request_done (struct RequestRecord *rr) | |||
374 | break; | 371 | break; |
375 | default: | 372 | default: |
376 | GNUNET_break (0); | 373 | GNUNET_break (0); |
377 | GNUNET_free (rr->name); | 374 | cleanup_rr (rr); |
378 | rr->name = NULL; | ||
379 | return; | 375 | return; |
380 | } | 376 | } |
381 | reply_len += sizeof (struct udp_pkt); | 377 | reply_len += sizeof (struct udp_pkt); |
382 | reply_len += sizeof (struct dns_pkt); | 378 | reply_len += rr->payload_length; |
383 | reply_len += rr->name_length; | ||
384 | reply_len += sizeof (struct dns_record_line); | ||
385 | reply_len += rr->rdata_length; | ||
386 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | 379 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
387 | { | 380 | { |
388 | /* response too big, drop */ | 381 | /* response too big, drop */ |
389 | GNUNET_break (0); /* how can this be? */ | 382 | GNUNET_break (0); /* how can this be? */ |
390 | GNUNET_free (rr->name); | 383 | cleanup_rr(rr); |
391 | rr->name = NULL; | ||
392 | return; | 384 | return; |
393 | } | 385 | } |
394 | { | 386 | { |
@@ -433,6 +425,7 @@ request_done (struct RequestRecord *rr) | |||
433 | default: | 425 | default: |
434 | GNUNET_assert (0); | 426 | GNUNET_assert (0); |
435 | } | 427 | } |
428 | |||
436 | /* now UDP header */ | 429 | /* now UDP header */ |
437 | { | 430 | { |
438 | struct udp_pkt udp; | 431 | struct udp_pkt udp; |
@@ -444,51 +437,10 @@ request_done (struct RequestRecord *rr) | |||
444 | memcpy (&buf[off], &udp, sizeof (udp)); | 437 | memcpy (&buf[off], &udp, sizeof (udp)); |
445 | off += sizeof (udp); | 438 | off += sizeof (udp); |
446 | } | 439 | } |
447 | 440 | /* now DNS header */ | |
448 | /* now DNS header */ | ||
449 | { | ||
450 | struct dns_pkt dns; | ||
451 | |||
452 | dns.id = rr->original_dns_id; | ||
453 | dns.rd = 1; /* recursion desired / supported */ | ||
454 | dns.tc = 0; /* not truncated */ | ||
455 | dns.aa = 1; /* are we authoritative!? I say yes. */ | ||
456 | dns.op = 0; /* standard query */ | ||
457 | dns.qr = 1; /* this is a response */ | ||
458 | dns.rcode = 0; /* no error */ | ||
459 | dns.z = 0; /* reserved */ | ||
460 | dns.ra = 1; /* recursion available */ | ||
461 | dns.qdcount = htons (0); /* no queries */ | ||
462 | dns.ancount = htons (1); /* one answer */ | ||
463 | dns.nscount = htons (0); /* no authorities yet (fixme) */ | ||
464 | dns.arcount = htons (0); /* no additinal records yet (fixme) */ | ||
465 | memcpy (&buf[off], &dns, sizeof (dns)); | ||
466 | off += sizeof (dns); | ||
467 | } | ||
468 | |||
469 | /* now DNS name */ | ||
470 | { | ||
471 | // FIXME: fill in DNS name! | ||
472 | off += rr->name_length; | ||
473 | } | ||
474 | |||
475 | |||
476 | /* now DNS record line */ | ||
477 | { | ||
478 | struct dns_record_line drl; | ||
479 | |||
480 | drl.type = htons (rr->dns_type); | ||
481 | drl.class = htons (rr->dns_class); | ||
482 | drl.ttl = htonl (rr->dns_ttl); | ||
483 | drl.data_len = htons (rr->rdata_length); | ||
484 | memcpy (&buf[off], &drl, sizeof (drl)); | ||
485 | off += sizeof (drl); | ||
486 | } | ||
487 | |||
488 | /* now DNS rdata */ | ||
489 | { | 441 | { |
490 | memcpy (&buf[off], rr->rdata, rr->rdata_length); | 442 | memcpy (&buf[off], rr->payload, rr->payload_length); |
491 | off += rr->rdata_length; | 443 | off += rr->payload_length; |
492 | } | 444 | } |
493 | 445 | ||
494 | /* final checks & sending */ | 446 | /* final checks & sending */ |
@@ -499,8 +451,147 @@ request_done (struct RequestRecord *rr) | |||
499 | NULL, NULL); | 451 | NULL, NULL); |
500 | } | 452 | } |
501 | /* clean up, we're done */ | 453 | /* clean up, we're done */ |
502 | GNUNET_free (rr->name); | 454 | cleanup_rr (rr); |
503 | rr->name = NULL; | 455 | } |
456 | |||
457 | |||
458 | /** | ||
459 | * Show the payload of the given request record to the client | ||
460 | * (and wait for a response). | ||
461 | * | ||
462 | * @param rr request to send to client | ||
463 | * @param client client to send the response to | ||
464 | */ | ||
465 | static void | ||
466 | send_request_to_client (struct RequestRecord *rr, | ||
467 | struct GNUNET_SERVER_Client *client) | ||
468 | { | ||
469 | char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; | ||
470 | struct GNUNET_DNS_Request *req; | ||
471 | |||
472 | if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
473 | { | ||
474 | GNUNET_break (0); | ||
475 | cleanup_rr (rr); | ||
476 | return; | ||
477 | } | ||
478 | req = (struct GNUNET_DNS_Request*) buf; | ||
479 | req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); | ||
480 | req->header.size = htons (sizeof (buf)); | ||
481 | req->reserved = htonl (0); | ||
482 | req->request_id = rr->request_id; | ||
483 | memcpy (&req[1], rr->payload, rr->payload_length); | ||
484 | GNUNET_SERVER_notification_context_unicast (nc, | ||
485 | client, | ||
486 | &req->header, | ||
487 | GNUNET_NO); | ||
488 | } | ||
489 | |||
490 | |||
491 | /** | ||
492 | * A client has completed its processing for this | ||
493 | * request. Move on. | ||
494 | * | ||
495 | * @param rr request to process further | ||
496 | */ | ||
497 | static void | ||
498 | next_phase (struct RequestRecord *rr) | ||
499 | { | ||
500 | struct ClientRecord *cr; | ||
501 | int nz; | ||
502 | unsigned int j; | ||
503 | struct GNUNET_NETWORK_Handle *dnsout; | ||
504 | socklen_t salen; | ||
505 | |||
506 | if (rr->phase == RP_DROP) | ||
507 | { | ||
508 | cleanup_rr (rr); | ||
509 | return; | ||
510 | } | ||
511 | nz = -1; | ||
512 | for (j=0;j<rr->client_wait_list_length;j++) | ||
513 | { | ||
514 | if (NULL != rr->client_wait_list[j]) | ||
515 | { | ||
516 | nz = (int) j; | ||
517 | break; | ||
518 | } | ||
519 | } | ||
520 | if (-1 != nz) | ||
521 | { | ||
522 | send_request_to_client (rr, rr->client_wait_list[nz]->client); | ||
523 | return; | ||
524 | } | ||
525 | /* done with current phase, advance! */ | ||
526 | switch (rr->phase) | ||
527 | { | ||
528 | case RP_INIT: | ||
529 | rr->phase = RP_MONITOR; | ||
530 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
531 | { | ||
532 | if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) | ||
533 | GNUNET_array_append (rr->client_wait_list, | ||
534 | rr->client_wait_list_length, | ||
535 | cr); | ||
536 | } | ||
537 | next_phase (rr); | ||
538 | return; | ||
539 | case RP_MONITOR: | ||
540 | rr->phase = RP_QUERY; | ||
541 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
542 | { | ||
543 | if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) | ||
544 | GNUNET_array_append (rr->client_wait_list, | ||
545 | rr->client_wait_list_length, | ||
546 | cr); | ||
547 | } | ||
548 | next_phase (rr); | ||
549 | return; | ||
550 | case RP_QUERY: | ||
551 | rr->phase = RP_INTERNET_DNS; | ||
552 | switch (rr->dst_addr.ss_family) | ||
553 | { | ||
554 | case AF_INET: | ||
555 | dnsout = dnsout4; | ||
556 | salen = sizeof (struct ip4_hdr); | ||
557 | break; | ||
558 | case AF_INET6: | ||
559 | dnsout = dnsout6; | ||
560 | salen = sizeof (struct ip6_hdr); | ||
561 | break; | ||
562 | default: | ||
563 | GNUNET_break (0); | ||
564 | cleanup_rr (rr); | ||
565 | return; | ||
566 | } | ||
567 | GNUNET_NETWORK_socket_sendto (dnsout, | ||
568 | rr->payload, | ||
569 | rr->payload_length, | ||
570 | (struct sockaddr*) &rr->dst_addr, | ||
571 | salen); | ||
572 | return; | ||
573 | case RP_INTERNET_DNS: | ||
574 | rr->phase = RP_MODIFY; | ||
575 | for (cr = clients_head; NULL != cr; cr = cr->next) | ||
576 | { | ||
577 | if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) | ||
578 | GNUNET_array_append (rr->client_wait_list, | ||
579 | rr->client_wait_list_length, | ||
580 | cr); | ||
581 | } | ||
582 | next_phase (rr); | ||
583 | return; | ||
584 | case RP_MODIFY: | ||
585 | request_done (rr); | ||
586 | break; | ||
587 | case RP_DROP: | ||
588 | cleanup_rr (rr); | ||
589 | break; | ||
590 | default: | ||
591 | GNUNET_break (0); | ||
592 | cleanup_rr (rr); | ||
593 | break; | ||
594 | } | ||
504 | } | 595 | } |
505 | 596 | ||
506 | 597 | ||
@@ -517,7 +608,6 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | |||
517 | struct RequestRecord *rr; | 608 | struct RequestRecord *rr; |
518 | unsigned int i; | 609 | unsigned int i; |
519 | unsigned int j; | 610 | unsigned int j; |
520 | int az; | ||
521 | 611 | ||
522 | for (cr = clients_head; NULL != cr; cr = cr->next) | 612 | for (cr = clients_head; NULL != cr; cr = cr->next) |
523 | { | 613 | { |
@@ -532,16 +622,14 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | |||
532 | rr = &requests[i]; | 622 | rr = &requests[i]; |
533 | if (0 == rr->client_wait_list_length) | 623 | if (0 == rr->client_wait_list_length) |
534 | continue; /* not in use */ | 624 | continue; /* not in use */ |
535 | az = 1; | ||
536 | for (j=0;j<rr->client_wait_list_length;j++) | 625 | for (j=0;j<rr->client_wait_list_length;j++) |
537 | { | 626 | { |
538 | if (rr->client_wait_list[j] == cr) | 627 | if (rr->client_wait_list[j] == cr) |
628 | { | ||
539 | rr->client_wait_list[j] = NULL; | 629 | rr->client_wait_list[j] = NULL; |
540 | if (rr->client_wait_list[j] != NULL) | 630 | next_phase (rr); |
541 | az = 0; | 631 | } |
542 | } | 632 | } |
543 | if (1 == az) | ||
544 | request_done (rr); /* this was the last client... */ | ||
545 | } | 633 | } |
546 | GNUNET_free (cr); | 634 | GNUNET_free (cr); |
547 | return; | 635 | return; |
@@ -564,7 +652,9 @@ read_response (void *cls, | |||
564 | struct sockaddr_in addr4; | 652 | struct sockaddr_in addr4; |
565 | struct sockaddr_in6 addr6; | 653 | struct sockaddr_in6 addr6; |
566 | struct sockaddr *addr; | 654 | struct sockaddr *addr; |
655 | struct dns_hdr *dns; | ||
567 | socklen_t addrlen; | 656 | socklen_t addrlen; |
657 | struct RequestRecord *rr; | ||
568 | ssize_t r; | 658 | ssize_t r; |
569 | int len; | 659 | int len; |
570 | 660 | ||
@@ -612,9 +702,26 @@ read_response (void *cls, | |||
612 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); | 702 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); |
613 | return; | 703 | return; |
614 | } | 704 | } |
615 | // NOTE: struct dns_pkt *dns = (struct dns_pkt *) buf; | 705 | if (sizeof (struct dns_hdr) > r) |
616 | // FIXME: handle_response (buf, r, addr, addrlen); | 706 | { |
617 | } | 707 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
708 | _("Received DNS response that is too small (%u bytes)"), | ||
709 | r); | ||
710 | return; | ||
711 | } | ||
712 | dns = (struct dns_hdr *) buf; | ||
713 | rr = &requests[dns->id]; | ||
714 | if (rr->phase != RP_INTERNET_DNS) | ||
715 | { | ||
716 | /* FIXME: case for statistics */ | ||
717 | /* unexpected / bogus reply */ | ||
718 | return; | ||
719 | } | ||
720 | GNUNET_free_non_null (rr->payload); | ||
721 | rr->payload = GNUNET_malloc (len); | ||
722 | memcpy (rr->payload, buf, len); | ||
723 | next_phase (rr); | ||
724 | } | ||
618 | } | 725 | } |
619 | 726 | ||
620 | 727 | ||
@@ -744,16 +851,19 @@ open_port6 () | |||
744 | static void | 851 | static void |
745 | handle_client_init (void *cls GNUNET_UNUSED, | 852 | handle_client_init (void *cls GNUNET_UNUSED, |
746 | struct GNUNET_SERVER_Client *client, | 853 | struct GNUNET_SERVER_Client *client, |
747 | const struct GNUNET_MessageHeader *message GNUNET_UNUSED) | 854 | const struct GNUNET_MessageHeader *message) |
748 | { | 855 | { |
749 | struct ClientRecord *cr; | 856 | struct ClientRecord *cr; |
857 | const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; | ||
750 | 858 | ||
751 | cr = GNUNET_malloc (sizeof (struct ClientRecord)); | 859 | cr = GNUNET_malloc (sizeof (struct ClientRecord)); |
752 | cr->client = client; | 860 | cr->client = client; |
861 | cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); | ||
753 | GNUNET_SERVER_client_keep (client); | 862 | GNUNET_SERVER_client_keep (client); |
754 | GNUNET_CONTAINER_DLL_insert (clients_head, | 863 | GNUNET_CONTAINER_DLL_insert (clients_head, |
755 | clients_tail, | 864 | clients_tail, |
756 | cr); | 865 | cr); |
866 | GNUNET_SERVER_notification_context_add (nc, client); | ||
757 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 867 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
758 | } | 868 | } |
759 | 869 | ||
@@ -768,10 +878,73 @@ handle_client_init (void *cls GNUNET_UNUSED, | |||
768 | static void | 878 | static void |
769 | handle_client_response (void *cls GNUNET_UNUSED, | 879 | handle_client_response (void *cls GNUNET_UNUSED, |
770 | struct GNUNET_SERVER_Client *client, | 880 | struct GNUNET_SERVER_Client *client, |
771 | const struct GNUNET_MessageHeader *message GNUNET_UNUSED) | 881 | const struct GNUNET_MessageHeader *message) |
772 | { | 882 | { |
773 | // FIXME: validate and parse response, process response | 883 | const struct GNUNET_DNS_Response *resp; |
774 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 884 | struct RequestRecord *rr; |
885 | unsigned int i; | ||
886 | uint16_t msize; | ||
887 | uint16_t off; | ||
888 | |||
889 | msize = ntohs (message->size); | ||
890 | if (msize < sizeof (struct GNUNET_DNS_Response)) | ||
891 | { | ||
892 | GNUNET_break (0); | ||
893 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
894 | return; | ||
895 | } | ||
896 | resp = (const struct GNUNET_DNS_Response*) message; | ||
897 | off = (uint16_t) resp->request_id; | ||
898 | rr = &requests[off]; | ||
899 | if (rr->request_id != resp->request_id) | ||
900 | { | ||
901 | // FIXME: this is a case for calling statistics... | ||
902 | // (client is answering a request that we've lost | ||
903 | // track of -- more than 64k requests ago or so...) | ||
904 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
905 | return; | ||
906 | } | ||
907 | for (i=0;i<rr->client_wait_list_length;i++) | ||
908 | { | ||
909 | if (rr->client_wait_list[i]->client != client) | ||
910 | continue; | ||
911 | rr->client_wait_list[i] = NULL; | ||
912 | switch (ntohl (resp->drop_flag)) | ||
913 | { | ||
914 | case 0: /* drop */ | ||
915 | rr->phase = RP_DROP; | ||
916 | break; | ||
917 | case 1: /* no change */ | ||
918 | break; | ||
919 | case 2: /* update */ | ||
920 | msize -= sizeof (struct GNUNET_DNS_Response); | ||
921 | if ( (sizeof (struct dns_hdr) > msize) || | ||
922 | (RP_MONITOR == rr->phase) ) | ||
923 | { | ||
924 | GNUNET_break (0); | ||
925 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
926 | next_phase (rr); | ||
927 | return; | ||
928 | } | ||
929 | GNUNET_free_non_null (rr->payload); | ||
930 | rr->payload = GNUNET_malloc (msize); | ||
931 | memcpy (rr->payload, &resp[1], msize); | ||
932 | if (rr->phase == RP_QUERY) | ||
933 | { | ||
934 | /* clear wait list, we're moving to MODIFY phase next */ | ||
935 | GNUNET_array_grow (rr->client_wait_list, | ||
936 | rr->client_wait_list_length, | ||
937 | 0); | ||
938 | } | ||
939 | next_phase (rr); | ||
940 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
941 | return; | ||
942 | } | ||
943 | } | ||
944 | /* odd, client was not on our list for the request, that ought | ||
945 | to be an error */ | ||
946 | GNUNET_break (0); | ||
947 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
775 | } | 948 | } |
776 | 949 | ||
777 | 950 | ||
@@ -784,12 +957,14 @@ handle_client_response (void *cls GNUNET_UNUSED, | |||
784 | * @param message the actual message, a DNS request we should handle | 957 | * @param message the actual message, a DNS request we should handle |
785 | */ | 958 | */ |
786 | static void | 959 | static void |
787 | process_helper_messages (void *cls, void *client, | 960 | process_helper_messages (void *cls GNUNET_UNUSED, void *client, |
788 | const struct GNUNET_MessageHeader *message) | 961 | const struct GNUNET_MessageHeader *message) |
789 | { | 962 | { |
963 | struct RequestRecord *rr = NULL; | ||
790 | /* FIXME: parse message, create record, start processing! */ | 964 | /* FIXME: parse message, create record, start processing! */ |
791 | /* FIXME: put request into queue for clients / system DNS */ | 965 | /* FIXME: put request into queue for clients / system DNS */ |
792 | request_id_gen++; | 966 | request_id_gen++; |
967 | next_phase (rr); | ||
793 | } | 968 | } |
794 | 969 | ||
795 | 970 | ||
@@ -804,7 +979,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
804 | { | 979 | { |
805 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | 980 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { |
806 | /* callback, cls, type, size */ | 981 | /* callback, cls, type, size */ |
807 | {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, sizeof (struct GNUNET_MessageHeader)}, | 982 | {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, |
983 | sizeof (struct GNUNET_DNS_Register)}, | ||
808 | {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, | 984 | {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, |
809 | {NULL, NULL, 0, 0} | 985 | {NULL, NULL, 0, 0} |
810 | }; | 986 | }; |
@@ -816,6 +992,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
816 | char *ipv6prefix; | 992 | char *ipv6prefix; |
817 | 993 | ||
818 | cfg = cfg_; | 994 | cfg = cfg_; |
995 | nc = GNUNET_SERVER_notification_context_create (server, 1); | ||
819 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | 996 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, |
820 | cls); | 997 | cls); |
821 | if (GNUNET_YES == | 998 | if (GNUNET_YES == |