diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-02 17:03:12 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-02 17:03:12 +0000 |
commit | 7abe8a4171588af22d4e64dade3956a15fcec6fd (patch) | |
tree | 5233d99cee4617d124048fbce74023432bef1409 /src/dns | |
parent | b63b061c6fc20d9ad1db85911a83321d2a55a6e1 (diff) | |
download | gnunet-7abe8a4171588af22d4e64dade3956a15fcec6fd.tar.gz gnunet-7abe8a4171588af22d4e64dade3956a15fcec6fd.zip |
-towards dns service
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/gnunet-service-dns_new.c | 378 |
1 files changed, 346 insertions, 32 deletions
diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c index afaf13196..5ae56873c 100644 --- a/src/dns/gnunet-service-dns_new.c +++ b/src/dns/gnunet-service-dns_new.c | |||
@@ -26,29 +26,91 @@ | |||
26 | #include "gnunet_util_lib.h" | 26 | #include "gnunet_util_lib.h" |
27 | #include "gnunet_constants.h" | 27 | #include "gnunet_constants.h" |
28 | #include "gnunet_protocols.h" | 28 | #include "gnunet_protocols.h" |
29 | #include "gnunet_dnsparser_lib.h" | 29 | //#include "gnunet_dnsparser_lib.h" |
30 | #include "gnunet_signatures.h" | 30 | #include "gnunet_signatures.h" |
31 | #include "dns_new.h" | 31 | #include "dns_new.h" |
32 | 32 | ||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | struct ip4_hdr | ||
35 | { | ||
36 | unsigned hdr_lngth:4 GNUNET_PACKED; | ||
37 | unsigned version:4 GNUNET_PACKED; | ||
33 | 38 | ||
34 | /** | 39 | uint8_t diff_serv; |
35 | * Entry we keep for each active request. | 40 | uint16_t tot_lngth GNUNET_PACKED; |
36 | */ | 41 | |
37 | struct RequestRecord | 42 | uint16_t ident GNUNET_PACKED; |
43 | unsigned flags:3 GNUNET_PACKED; | ||
44 | unsigned frag_off:13 GNUNET_PACKED; | ||
45 | |||
46 | uint8_t ttl; | ||
47 | uint8_t proto; | ||
48 | uint16_t chks GNUNET_PACKED; | ||
49 | |||
50 | struct in_addr sadr GNUNET_PACKED; | ||
51 | struct in_addr dadr GNUNET_PACKED; | ||
52 | }; | ||
53 | |||
54 | struct ip6_hdr | ||
38 | { | 55 | { |
56 | unsigned tclass_h:4 GNUNET_PACKED; | ||
57 | unsigned version:4 GNUNET_PACKED; | ||
58 | unsigned tclass_l:4 GNUNET_PACKED; | ||
59 | unsigned flowlbl:20 GNUNET_PACKED; | ||
60 | uint16_t paylgth GNUNET_PACKED; | ||
61 | uint8_t nxthdr; | ||
62 | uint8_t hoplmt; | ||
63 | struct in6_addr sadr GNUNET_PACKED; | ||
64 | struct in6_addr dadr GNUNET_PACKED; | ||
65 | }; | ||
39 | 66 | ||
67 | struct udp_pkt | ||
68 | { | ||
69 | uint16_t spt GNUNET_PACKED; | ||
70 | uint16_t dpt GNUNET_PACKED; | ||
71 | uint16_t len GNUNET_PACKED; | ||
72 | uint16_t crc GNUNET_PACKED; | ||
73 | }; | ||
40 | 74 | ||
41 | /** | 75 | struct dns_pkt |
42 | * Entry of this request record in the heap (for fast removal). | 76 | { |
43 | */ | 77 | uint16_t id GNUNET_PACKED; |
44 | struct GNUNET_CONTAINER_HeapNode *hentry; | 78 | |
79 | unsigned rd:1 GNUNET_PACKED; // recursion desired (client -> server) | ||
80 | unsigned tc:1 GNUNET_PACKED; // message is truncated | ||
81 | unsigned aa:1 GNUNET_PACKED; // authoritative answer | ||
82 | unsigned op:4 GNUNET_PACKED; // query:0, inverse q.:1, status: 2 | ||
83 | unsigned qr:1 GNUNET_PACKED; // query:0, response:1 | ||
84 | |||
85 | unsigned rcode:4 GNUNET_PACKED; // 0 No error | ||
86 | // 1 Format error | ||
87 | // 2 Server failure | ||
88 | // 3 Name Error | ||
89 | // 4 Not Implemented | ||
90 | // 5 Refused | ||
91 | unsigned z:3 GNUNET_PACKED; // reserved | ||
92 | unsigned ra:1 GNUNET_PACKED; // recursion available (server -> client) | ||
93 | |||
94 | uint16_t qdcount GNUNET_PACKED; // number of questions | ||
95 | uint16_t ancount GNUNET_PACKED; // number of answers | ||
96 | uint16_t nscount GNUNET_PACKED; // number of authority-records | ||
97 | uint16_t arcount GNUNET_PACKED; // number of additional records | ||
98 | }; | ||
45 | 99 | ||
46 | /** | 100 | struct dns_query_line |
47 | * Array of clients and their answers. | 101 | { |
48 | */ | 102 | uint16_t type; |
49 | struct GNUNET_SERVER_Client *client; | 103 | uint16_t class; |
104 | }; | ||
50 | 105 | ||
106 | struct dns_record_line | ||
107 | { | ||
108 | uint16_t type; | ||
109 | uint16_t class; | ||
110 | uint32_t ttl; | ||
111 | uint16_t data_len; | ||
51 | }; | 112 | }; |
113 | GNUNET_NETWORK_STRUCT_END | ||
52 | 114 | ||
53 | 115 | ||
54 | /** | 116 | /** |
@@ -75,6 +137,83 @@ struct ClientRecord | |||
75 | 137 | ||
76 | 138 | ||
77 | /** | 139 | /** |
140 | * Entry we keep for each active request. | ||
141 | */ | ||
142 | struct RequestRecord | ||
143 | { | ||
144 | |||
145 | /** | ||
146 | * Name for the request. | ||
147 | */ | ||
148 | char *name; | ||
149 | |||
150 | /** | ||
151 | * Response data, or NULL if not known. | ||
152 | */ | ||
153 | char *rdata; | ||
154 | |||
155 | /** | ||
156 | * List of clients that still need to see this request (each entry | ||
157 | * is set to NULL when the client is done). | ||
158 | */ | ||
159 | struct ClientRecord **client_wait_list; | ||
160 | |||
161 | /** | ||
162 | * Length of the client wait list. | ||
163 | */ | ||
164 | unsigned int client_wait_list_length; | ||
165 | |||
166 | /** | ||
167 | * Source address of the original request (for sending response). | ||
168 | */ | ||
169 | struct sockaddr_storage src_addr; | ||
170 | |||
171 | /** | ||
172 | * Destination address of the original request (for potential use as exit). | ||
173 | */ | ||
174 | struct sockaddr_storage dst_addr; | ||
175 | |||
176 | /** | ||
177 | * ID of this request, also basis for hashing. Lowest 16 bit will | ||
178 | * be our message ID when doing a global DNS request and our index | ||
179 | * into the 'requests' array. | ||
180 | */ | ||
181 | uint64_t request_id; | ||
182 | |||
183 | /** | ||
184 | * TTL if we know it, or 0. | ||
185 | */ | ||
186 | uint32_t dns_ttl; | ||
187 | |||
188 | /** | ||
189 | * Number of bytes in rdata. | ||
190 | */ | ||
191 | uint16_t rdata_length; | ||
192 | |||
193 | /** | ||
194 | * Length of the 'name' string, including 0-terminator. | ||
195 | */ | ||
196 | uint16_t name_length; | ||
197 | |||
198 | /** | ||
199 | * The DNS type (i.e. 1 == 'A'). | ||
200 | */ | ||
201 | uint16_t dns_type; | ||
202 | |||
203 | /** | ||
204 | * The DNS class (i.e. 1 == Internet) | ||
205 | */ | ||
206 | uint16_t dns_class; | ||
207 | |||
208 | /** | ||
209 | * Original DNS Id we got from the client. | ||
210 | */ | ||
211 | uint16_t original_dns_id; | ||
212 | |||
213 | }; | ||
214 | |||
215 | |||
216 | /** | ||
78 | * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be | 217 | * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be |
79 | * sent through gnunet. The port of this socket will not be hijacked. | 218 | * sent through gnunet. The port of this socket will not be hijacked. |
80 | */ | 219 | */ |
@@ -128,15 +267,14 @@ static struct ClientRecord *clients_head; | |||
128 | static struct ClientRecord *clients_tail; | 267 | static struct ClientRecord *clients_tail; |
129 | 268 | ||
130 | /** | 269 | /** |
131 | * Hash map of open requests. | 270 | * Array of all open requests. |
132 | */ | 271 | */ |
133 | static struct GNUNET_CONTAINER_MultiHashMap *request_map; | 272 | static struct RequestRecord requests[UINT16_MAX]; |
134 | 273 | ||
135 | /** | 274 | /** |
136 | * Heap with open requests (sorted by time received, oldest on top). | 275 | * Generator for unique request IDs. |
137 | */ | 276 | */ |
138 | static struct GNUNET_CONTAINER_Heap *request_heap; | 277 | static uint64_t request_id_gen; |
139 | |||
140 | 278 | ||
141 | 279 | ||
142 | /** | 280 | /** |
@@ -176,21 +314,179 @@ cleanup_task (void *cls GNUNET_UNUSED, | |||
176 | GNUNET_SCHEDULER_cancel (read6_task); | 314 | GNUNET_SCHEDULER_cancel (read6_task); |
177 | read6_task = GNUNET_SCHEDULER_NO_TASK; | 315 | read6_task = GNUNET_SCHEDULER_NO_TASK; |
178 | } | 316 | } |
179 | if (NULL != request_heap) | 317 | for (i=0;i<65536;i++) |
180 | { | 318 | { |
181 | while (NULL != (rr = GNUNET_CONTAINER_heap_remove_root (request_heap))) | 319 | rr = &requests[i]; |
182 | { | 320 | GNUNET_free (rr->name); |
183 | // FIXME: free rest of 'rr' | 321 | GNUNET_free_non_null (rr->rdata); |
184 | GNUNET_free (rr); | 322 | GNUNET_array_grow (rr->client_wait_list, |
185 | } | 323 | rr->client_wait_list_length, |
186 | GNUNET_CONTAINER_heap_destroy (request_heap); | 324 | 0); |
187 | request_heap = NULL; | 325 | } |
326 | } | ||
327 | |||
328 | |||
329 | /** | ||
330 | * We're done with some request, finish processing. | ||
331 | */ | ||
332 | static void | ||
333 | request_done (struct RequestRecord *rr) | ||
334 | { | ||
335 | struct GNUNET_MessageHeader *hdr; | ||
336 | size_t reply_len; | ||
337 | uint16_t spt; | ||
338 | uint16_t dpt; | ||
339 | |||
340 | GNUNET_array_grow (rr->client_wait_list, | ||
341 | rr->client_wait_list_length, | ||
342 | 0); | ||
343 | if (NULL == rr->rdata) | ||
344 | { | ||
345 | /* no response, drop */ | ||
346 | GNUNET_free (rr->name); | ||
347 | rr->name = NULL; | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | /* send response via hijacker */ | ||
352 | reply_len = sizeof (struct GNUNET_MessageHeader); | ||
353 | switch (rr->src_addr.ss_family) | ||
354 | { | ||
355 | case AF_INET: | ||
356 | reply_len += sizeof (struct ip4_hdr); | ||
357 | break; | ||
358 | case AF_INET6: | ||
359 | reply_len += sizeof (struct ip6_hdr); | ||
360 | break; | ||
361 | default: | ||
362 | GNUNET_break (0); | ||
363 | GNUNET_free (rr->name); | ||
364 | rr->name = NULL; | ||
365 | return; | ||
188 | } | 366 | } |
189 | if (NULL != request_map) | 367 | reply_len += sizeof (struct udp_pkt); |
368 | reply_len += sizeof (struct dns_pkt); | ||
369 | reply_len += rr->name_length; | ||
370 | reply_len += sizeof (struct dns_record_line); | ||
371 | reply_len += rr->rdata_length; | ||
372 | if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
190 | { | 373 | { |
191 | GNUNET_CONTAINER_multihashmap_destroy (request_map); | 374 | /* response too big, drop */ |
192 | request_map = NULL; | 375 | GNUNET_break (0); /* how can this be? */ |
376 | GNUNET_free (rr->name); | ||
377 | rr->name = NULL; | ||
378 | return; | ||
193 | } | 379 | } |
380 | { | ||
381 | char buf[reply_len]; | ||
382 | size_t off; | ||
383 | |||
384 | /* first, GNUnet message header */ | ||
385 | hdr = (struct GNUNET_MessageHeader*) buf; | ||
386 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); | ||
387 | hdr->size = htons ((uint16_t) reply_len); | ||
388 | off = sizeof (struct GNUNET_MessageHeader); | ||
389 | |||
390 | /* now IP header */ | ||
391 | switch (rr->src_addr.ss_family) | ||
392 | { | ||
393 | case AF_INET: | ||
394 | { | ||
395 | struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; | ||
396 | struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; | ||
397 | struct ip4_hdr ip; | ||
398 | |||
399 | spt = dst->sin_port; | ||
400 | dpt = src->sin_port; | ||
401 | // FIXME: fill in IP header! | ||
402 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
403 | off += sizeof (ip); | ||
404 | break; | ||
405 | } | ||
406 | case AF_INET6: | ||
407 | { | ||
408 | struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; | ||
409 | struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; | ||
410 | struct ip6_hdr ip; | ||
411 | |||
412 | spt = dst->sin6_port; | ||
413 | dpt = src->sin6_port; | ||
414 | // FIXME: fill in IP header! | ||
415 | memcpy (&buf[off], &ip, sizeof (ip)); | ||
416 | off += sizeof (ip); | ||
417 | } | ||
418 | break; | ||
419 | default: | ||
420 | GNUNET_assert (0); | ||
421 | } | ||
422 | /* now UDP header */ | ||
423 | { | ||
424 | struct udp_pkt udp; | ||
425 | |||
426 | udp.spt = spt; | ||
427 | udp.dpt = dpt; | ||
428 | udp.len = htons (reply_len - off); | ||
429 | udp.crc = 0; /* checksum is optional */ | ||
430 | memcpy (&buf[off], &udp, sizeof (udp)); | ||
431 | off += sizeof (udp); | ||
432 | } | ||
433 | |||
434 | /* now DNS header */ | ||
435 | { | ||
436 | struct dns_pkt dns; | ||
437 | |||
438 | dns.id = rr->original_dns_id; | ||
439 | dns.rd = 1; /* recursion desired / supported */ | ||
440 | dns.tc = 0; /* not truncated */ | ||
441 | dns.aa = 1; /* are we authoritative!? I say yes. */ | ||
442 | dns.op = 0; /* standard query */ | ||
443 | dns.qr = 1; /* this is a response */ | ||
444 | dns.rcode = 0; /* no error */ | ||
445 | dns.z = 0; /* reserved */ | ||
446 | dns.ra = 1; /* recursion available */ | ||
447 | dns.qdcount = htons (0); /* no queries */ | ||
448 | dns.ancount = htons (1); /* one answer */ | ||
449 | dns.nscount = htons (0); /* no authorities yet (fixme) */ | ||
450 | dns.arcount = htons (0); /* no additinal records yet (fixme) */ | ||
451 | memcpy (&buf[off], &dns, sizeof (dns)); | ||
452 | off += sizeof (dns); | ||
453 | } | ||
454 | |||
455 | /* now DNS name */ | ||
456 | { | ||
457 | // FIXME: fill in DNS name! | ||
458 | off += rr->name_length; | ||
459 | } | ||
460 | |||
461 | |||
462 | /* now DNS record line */ | ||
463 | { | ||
464 | struct dns_record_line drl; | ||
465 | |||
466 | drl.type = htons (rr->dns_type); | ||
467 | drl.class = htons (rr->dns_class); | ||
468 | drl.ttl = htonl (rr->dns_ttl); | ||
469 | drl.data_len = htons (rr->rdata_length); | ||
470 | memcpy (&buf[off], &drl, sizeof (drl)); | ||
471 | off += sizeof (drl); | ||
472 | } | ||
473 | |||
474 | /* now DNS rdata */ | ||
475 | { | ||
476 | memcpy (&buf[off], rr->rdata, rr->rdata_length); | ||
477 | off += rr->rdata_length; | ||
478 | } | ||
479 | |||
480 | /* final checks & sending */ | ||
481 | GNUNET_assert (off == reply_len); | ||
482 | GNUNET_HELPER_send (hijacker, | ||
483 | hdr, | ||
484 | GNUNET_YES, | ||
485 | NULL, NULL); | ||
486 | } | ||
487 | /* clean up, we're done */ | ||
488 | GNUNET_free (rr->name); | ||
489 | rr->name = NULL; | ||
194 | } | 490 | } |
195 | 491 | ||
196 | 492 | ||
@@ -204,8 +500,11 @@ static void | |||
204 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | 500 | client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) |
205 | { | 501 | { |
206 | struct ClientRecord *cr; | 502 | struct ClientRecord *cr; |
503 | struct RequestRecord *rr; | ||
504 | unsigned int i; | ||
505 | unsigned int j; | ||
506 | int az; | ||
207 | 507 | ||
208 | /* FIXME: clean up after client */ | ||
209 | for (cr = clients_head; NULL != cr; cr = cr->next) | 508 | for (cr = clients_head; NULL != cr; cr = cr->next) |
210 | { | 509 | { |
211 | if (cr->client == client) | 510 | if (cr->client == client) |
@@ -214,6 +513,22 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | |||
214 | GNUNET_CONTAINER_DLL_remove (clients_head, | 513 | GNUNET_CONTAINER_DLL_remove (clients_head, |
215 | clients_tail, | 514 | clients_tail, |
216 | cr); | 515 | cr); |
516 | for (i=0;i<UINT16_MAX;i++) | ||
517 | { | ||
518 | rr = &requests[i]; | ||
519 | if (0 == rr->client_wait_list_length) | ||
520 | continue; /* not in use */ | ||
521 | az = 1; | ||
522 | for (j=0;j<rr->client_wait_list_length;j++) | ||
523 | { | ||
524 | if (rr->client_wait_list[j] == cr) | ||
525 | rr->client_wait_list[j] = NULL; | ||
526 | if (rr->client_wait_list[j] != NULL) | ||
527 | az = 0; | ||
528 | } | ||
529 | if (1 == az) | ||
530 | request_done (rr); /* this was the last client... */ | ||
531 | } | ||
217 | GNUNET_free (cr); | 532 | GNUNET_free (cr); |
218 | return; | 533 | return; |
219 | } | 534 | } |
@@ -460,6 +775,7 @@ process_helper_messages (void *cls, void *client, | |||
460 | { | 775 | { |
461 | /* FIXME: parse message, create record, start processing! */ | 776 | /* FIXME: parse message, create record, start processing! */ |
462 | /* FIXME: put request into queue for clients / system DNS */ | 777 | /* FIXME: put request into queue for clients / system DNS */ |
778 | request_id_gen++; | ||
463 | } | 779 | } |
464 | 780 | ||
465 | 781 | ||
@@ -486,8 +802,6 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
486 | char *ipv6prefix; | 802 | char *ipv6prefix; |
487 | 803 | ||
488 | cfg = cfg_; | 804 | cfg = cfg_; |
489 | request_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
490 | request_map = GNUNET_CONTAINER_multihashmap_create (1024 * 16); | ||
491 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | 805 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, |
492 | cls); | 806 | cls); |
493 | if (GNUNET_YES == | 807 | if (GNUNET_YES == |