diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-05 14:19:42 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-05 14:19:42 +0000 |
commit | ac2f5ee5b463af07b30c7064c7b7b8d39fbee117 (patch) | |
tree | 4f16d62cafab62686296519d352326f037b3af10 /src/transport | |
parent | bcec6624666bad99ee43625b0e5aa989f44bff5e (diff) | |
download | gnunet-ac2f5ee5b463af07b30c7064c7b7b8d39fbee117.tar.gz gnunet-ac2f5ee5b463af07b30c7064c7b7b8d39fbee117.zip |
stuff
Diffstat (limited to 'src/transport')
-rw-r--r-- | src/transport/gnunet-service-transport_validation.c | 426 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_validation.h | 4 |
2 files changed, 426 insertions, 4 deletions
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index 6cdd99e25..9b62881d6 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c | |||
@@ -25,6 +25,157 @@ | |||
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet-service-transport_validation.h" | 27 | #include "gnunet-service-transport_validation.h" |
28 | #include "gnunet-service-transport.h" | ||
29 | #include "gnunet_hello_lib.h" | ||
30 | #include "gnunet_peerinfo_service.h" | ||
31 | |||
32 | /** | ||
33 | * How long until a HELLO verification attempt should time out? | ||
34 | * Must be rather small, otherwise a partially successful HELLO | ||
35 | * validation (some addresses working) might not be available | ||
36 | * before a client's request for a connection fails for good. | ||
37 | * Besides, if a single request to an address takes a long time, | ||
38 | * then the peer is unlikely worthwhile anyway. | ||
39 | */ | ||
40 | #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
41 | |||
42 | /** | ||
43 | * How long is a PONG signature valid? We'll recycle a signature until | ||
44 | * 1/4 of this time is remaining. PONGs should expire so that if our | ||
45 | * external addresses change an adversary cannot replay them indefinitely. | ||
46 | * OTOH, we don't want to spend too much time generating PONG signatures, | ||
47 | * so they must have some lifetime to reduce our CPU usage. | ||
48 | */ | ||
49 | #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) | ||
50 | |||
51 | /** | ||
52 | * After how long do we expire an address in a HELLO that we just | ||
53 | * validated? This value is also used for our own addresses when we | ||
54 | * create a HELLO. | ||
55 | */ | ||
56 | #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) | ||
57 | |||
58 | |||
59 | /** | ||
60 | * How long before an existing address expires should we again try to | ||
61 | * validate it? Must be (significantly) smaller than | ||
62 | * HELLO_ADDRESS_EXPIRATION. | ||
63 | */ | ||
64 | #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) | ||
65 | |||
66 | /** | ||
67 | * Size of the validation map hashmap. | ||
68 | */ | ||
69 | #define VALIDATION_MAP_SIZE 256 | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Information about an address under validation | ||
74 | */ | ||
75 | struct ValidationEntry | ||
76 | { | ||
77 | |||
78 | /** | ||
79 | * Name of the transport. | ||
80 | */ | ||
81 | char *transport_name; | ||
82 | |||
83 | /** | ||
84 | * The address, actually a pointer to the end | ||
85 | * of this struct. Do not free! | ||
86 | */ | ||
87 | const void *addr; | ||
88 | |||
89 | /** | ||
90 | * The identity of the peer. | ||
91 | */ | ||
92 | struct GNUNET_PeerIdentity pid; | ||
93 | |||
94 | /** | ||
95 | * ID of task that will clean up this entry if nothing happens. | ||
96 | */ | ||
97 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
98 | |||
99 | /** | ||
100 | * At what time did we send the latest validation request? | ||
101 | */ | ||
102 | struct GNUNET_TIME_Absolute send_time; | ||
103 | |||
104 | /** | ||
105 | * When did we last succeed with validating this address? | ||
106 | * FOREVER if the address has not been validated (we're currently checking) | ||
107 | * ZERO if the address was validated a long time ago (from PEERINFO) | ||
108 | * otherwise a time in the past if this process validated the address | ||
109 | */ | ||
110 | struct GNUNET_TIME_Absolute last_validated_at; | ||
111 | |||
112 | /** | ||
113 | * How long until we can try to validate this address again? | ||
114 | * FOREVER if the address is for an unsupported plugin (from PEERINFO) | ||
115 | * ZERO if the address is considered valid (no validation needed) | ||
116 | * otherwise a time in the future if we're currently denying re-validation | ||
117 | */ | ||
118 | struct GNUNET_TIME_Absolute validation_block; | ||
119 | |||
120 | /** | ||
121 | * Challenge number we used. | ||
122 | */ | ||
123 | uint32_t challenge; | ||
124 | |||
125 | /** | ||
126 | * Length of addr. | ||
127 | */ | ||
128 | size_t addrlen; | ||
129 | |||
130 | }; | ||
131 | |||
132 | |||
133 | /** | ||
134 | * Context of currently active requests to peerinfo | ||
135 | * for validation of HELLOs. | ||
136 | */ | ||
137 | struct CheckHelloValidatedContext | ||
138 | { | ||
139 | |||
140 | /** | ||
141 | * This is a doubly-linked list. | ||
142 | */ | ||
143 | struct CheckHelloValidatedContext *next; | ||
144 | |||
145 | /** | ||
146 | * This is a doubly-linked list. | ||
147 | */ | ||
148 | struct CheckHelloValidatedContext *prev; | ||
149 | |||
150 | /** | ||
151 | * Hello that we are validating. | ||
152 | */ | ||
153 | const struct GNUNET_HELLO_Message *hello; | ||
154 | |||
155 | /** | ||
156 | * Context for peerinfo iteration. | ||
157 | */ | ||
158 | struct GNUNET_PEERINFO_IteratorContext *piter; | ||
159 | |||
160 | }; | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Head of linked list of HELLOs awaiting validation. | ||
165 | */ | ||
166 | static struct CheckHelloValidatedContext *chvc_head; | ||
167 | |||
168 | /** | ||
169 | * Tail of linked list of HELLOs awaiting validation | ||
170 | */ | ||
171 | static struct CheckHelloValidatedContext *chvc_tail; | ||
172 | |||
173 | /** | ||
174 | * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses | ||
175 | * of the given peer that we are currently validating, have validated | ||
176 | * or are blocked from re-validation for a while). | ||
177 | */ | ||
178 | static struct GNUNET_CONTAINER_MultiHashMap *validation_map; | ||
28 | 179 | ||
29 | 180 | ||
30 | /** | 181 | /** |
@@ -33,6 +184,33 @@ | |||
33 | void | 184 | void |
34 | GST_validation_start () | 185 | GST_validation_start () |
35 | { | 186 | { |
187 | validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE); | ||
188 | } | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Iterate over validation entries and free them. | ||
193 | * | ||
194 | * @param cls (unused) | ||
195 | * @param key peer identity (unused) | ||
196 | * @param value a 'struct ValidationEntry' to clean up | ||
197 | * @return GNUNET_YES (continue to iterate) | ||
198 | */ | ||
199 | static int | ||
200 | cleanup_validation_entry (void *cls, | ||
201 | const GNUNET_HashCode *key, | ||
202 | void *value) | ||
203 | { | ||
204 | struct ValidationEntry *ve = value; | ||
205 | |||
206 | GNUNET_free (ve->transport_name); | ||
207 | if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) | ||
208 | { | ||
209 | GNUNET_SCHEDULER_cancel (ve->timeout_task); | ||
210 | ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
211 | } | ||
212 | GNUNET_free (ve); | ||
213 | return GNUNET_OK; | ||
36 | } | 214 | } |
37 | 215 | ||
38 | 216 | ||
@@ -42,6 +220,152 @@ GST_validation_start () | |||
42 | void | 220 | void |
43 | GST_validation_stop () | 221 | GST_validation_stop () |
44 | { | 222 | { |
223 | struct CheckHelloValidatedContext *chvc; | ||
224 | |||
225 | GNUNET_CONTAINER_multihashmap_iterate (validation_map, | ||
226 | &cleanup_validation_entry, | ||
227 | NULL); | ||
228 | GNUNET_CONTAINER_multihashmap_destroy (validation_map); | ||
229 | validation_map = NULL; | ||
230 | while (NULL != (chvc = chvc_head)) | ||
231 | { | ||
232 | GNUNET_CONTAINER_DLL_remove (chvc_head, | ||
233 | chvc_tail, | ||
234 | chvc); | ||
235 | GNUNET_PEERINFO_iterate_cancel (chvc->piter); | ||
236 | GNUNET_free (chvc); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | |||
241 | #if 0 | ||
242 | /** | ||
243 | * Address validation cleanup task (record no longer needed). | ||
244 | * | ||
245 | * @param cls the 'struct ValidationEntry' | ||
246 | * @param tc scheduler context (unused) | ||
247 | */ | ||
248 | static void | ||
249 | timeout_hello_validation (void *cls, | ||
250 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
251 | { | ||
252 | struct ValidationEntry *va = cls; | ||
253 | |||
254 | va->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
255 | GNUNET_STATISTICS_update (GST_stats, | ||
256 | gettext_noop ("# address records discarded"), | ||
257 | 1, | ||
258 | GNUNET_NO); | ||
259 | GNUNET_break (GNUNET_OK == | ||
260 | GNUNET_CONTAINER_multihashmap_remove (validation_map, | ||
261 | &va->pid.hashPubKey, | ||
262 | va)); | ||
263 | GNUNET_free (va->transport_name); | ||
264 | GNUNET_free (va); | ||
265 | } | ||
266 | #endif | ||
267 | |||
268 | |||
269 | /** | ||
270 | * Context for the validation entry match function. | ||
271 | */ | ||
272 | struct ValidationEntryMatchContext | ||
273 | { | ||
274 | /** | ||
275 | * Where to store the result? | ||
276 | */ | ||
277 | struct ValidationEntry *ve; | ||
278 | |||
279 | /** | ||
280 | * Transport name we're looking for. | ||
281 | */ | ||
282 | const char *transport_name; | ||
283 | |||
284 | /** | ||
285 | * Address we're interested in. | ||
286 | */ | ||
287 | const char *addr; | ||
288 | |||
289 | /** | ||
290 | * Number of bytes in 'addr'. | ||
291 | */ | ||
292 | size_t addrlen; | ||
293 | }; | ||
294 | |||
295 | |||
296 | /** | ||
297 | * Iterate over validation entries until a matching one is found. | ||
298 | * | ||
299 | * @param cls the 'struct ValidationEntryMatchContext' | ||
300 | * @param key peer identity (unused) | ||
301 | * @param value a 'struct ValidationEntry' to match | ||
302 | * @return GNUNET_YES if the entry does not match, | ||
303 | * GNUNET_NO if the entry does match | ||
304 | */ | ||
305 | static int | ||
306 | validation_entry_match (void *cls, | ||
307 | const GNUNET_HashCode *key, | ||
308 | void *value) | ||
309 | { | ||
310 | struct ValidationEntryMatchContext *vemc = cls; | ||
311 | struct ValidationEntry *ve = value; | ||
312 | |||
313 | if ( (ve->addrlen == vemc->addrlen) && | ||
314 | (0 == memcmp (ve->addr, vemc->addr, ve->addrlen)) && | ||
315 | (0 == strcmp (ve->transport_name, vemc->transport_name)) ) | ||
316 | { | ||
317 | vemc->ve = ve; | ||
318 | return GNUNET_NO; | ||
319 | } | ||
320 | return GNUNET_YES; | ||
321 | } | ||
322 | |||
323 | |||
324 | /** | ||
325 | * Find a ValidationEntry entry for the given neighbour that matches | ||
326 | * the given address and transport. If none exists, create one (but | ||
327 | * without starting any validation). | ||
328 | * | ||
329 | * @param neighbour which peer we care about | ||
330 | * @param tname name of the transport plugin | ||
331 | * @param session session to look for, NULL for 'any'; otherwise | ||
332 | * can be used for the service to "learn" this session ID | ||
333 | * if 'addr' matches | ||
334 | * @param addr binary address | ||
335 | * @param addrlen length of addr | ||
336 | * @return validation entry matching the given specifications | ||
337 | */ | ||
338 | static struct ValidationEntry * | ||
339 | find_validation_entry (struct GNUNET_PeerIdentity *neighbour, | ||
340 | const char *tname, | ||
341 | const char *addr, | ||
342 | size_t addrlen) | ||
343 | { | ||
344 | struct ValidationEntryMatchContext vemc; | ||
345 | struct ValidationEntry *ve; | ||
346 | |||
347 | vemc.ve = NULL; | ||
348 | vemc.transport_name = tname; | ||
349 | vemc.addr = addr; | ||
350 | vemc.addrlen = addrlen; | ||
351 | GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, | ||
352 | &neighbour->hashPubKey, | ||
353 | &validation_entry_match, | ||
354 | &vemc); | ||
355 | if (NULL != (ve = vemc.ve)) | ||
356 | return ve; | ||
357 | ve = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen); | ||
358 | ve->transport_name = GNUNET_strdup (tname); | ||
359 | ve->addr = (void*) &ve[1]; | ||
360 | ve->pid = *neighbour; | ||
361 | memcpy (&ve[1], addr, addrlen); | ||
362 | ve->addrlen = addrlen; | ||
363 | ve->last_validated_at = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
364 | GNUNET_CONTAINER_multihashmap_put (validation_map, | ||
365 | &neighbour->hashPubKey, | ||
366 | ve, | ||
367 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
368 | return ve; | ||
45 | } | 369 | } |
46 | 370 | ||
47 | 371 | ||
@@ -87,6 +411,37 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, | |||
87 | 411 | ||
88 | 412 | ||
89 | /** | 413 | /** |
414 | * Iterator callback to go over all addresses and try to validate them | ||
415 | * (unless blocked or already validated). | ||
416 | * | ||
417 | * @param cls pointer to the 'struct PeerIdentity' of the peer | ||
418 | * @param tname name of the transport | ||
419 | * @param expiration expiration time | ||
420 | * @param addr the address | ||
421 | * @param addrlen length of the address | ||
422 | * @return GNUNET_OK (keep the address) | ||
423 | */ | ||
424 | static int | ||
425 | validate_address (void *cls, | ||
426 | const char *tname, | ||
427 | struct GNUNET_TIME_Absolute expiration, | ||
428 | const void *addr, | ||
429 | uint16_t addrlen) | ||
430 | { | ||
431 | struct GNUNET_PeerIdentity *pid = cls; | ||
432 | struct ValidationEntry *ve; | ||
433 | |||
434 | if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) | ||
435 | return GNUNET_OK; /* expired */ | ||
436 | ve = find_validation_entry (pid, tname, addr, addrlen); | ||
437 | // FIXME: check if validated/blocked, if not start validation... | ||
438 | ve++; // make compiler happy | ||
439 | return GNUNET_OK; | ||
440 | } | ||
441 | |||
442 | |||
443 | |||
444 | /** | ||
90 | * We've received a HELLO, check which addresses are new and trigger | 445 | * We've received a HELLO, check which addresses are new and trigger |
91 | * validation. | 446 | * validation. |
92 | * | 447 | * |
@@ -95,6 +450,21 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, | |||
95 | void | 450 | void |
96 | GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) | 451 | GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) |
97 | { | 452 | { |
453 | const struct GNUNET_HELLO_Message* hm = (const struct GNUNET_HELLO_Message*) hello; | ||
454 | struct GNUNET_PeerIdentity pid; | ||
455 | |||
456 | if (GNUNET_OK != | ||
457 | GNUNET_HELLO_get_id (hm, &pid)) | ||
458 | { | ||
459 | /* malformed HELLO */ | ||
460 | GNUNET_break (0); | ||
461 | return; | ||
462 | } | ||
463 | GNUNET_assert (NULL == | ||
464 | GNUNET_HELLO_iterate_addresses (hm, | ||
465 | GNUNET_NO, | ||
466 | &validate_address, | ||
467 | &pid)); | ||
98 | } | 468 | } |
99 | 469 | ||
100 | 470 | ||
@@ -103,10 +473,46 @@ GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) | |||
103 | */ | 473 | */ |
104 | struct GST_ValidationIteratorContext | 474 | struct GST_ValidationIteratorContext |
105 | { | 475 | { |
476 | /** | ||
477 | * Function to call on each address. | ||
478 | */ | ||
479 | GST_ValidationAddressCallback cb; | ||
480 | |||
481 | /** | ||
482 | * Closure for 'cb'. | ||
483 | */ | ||
484 | void *cb_cls; | ||
106 | }; | 485 | }; |
107 | 486 | ||
108 | 487 | ||
109 | /** | 488 | /** |
489 | * Call the callback in the closure for each validation entry. | ||
490 | * | ||
491 | * @param cls the 'struct GST_ValidationIteratorContext' | ||
492 | * @param key the peer's identity | ||
493 | * @param value the 'struct ValidationEntry' | ||
494 | * @return GNUNET_OK (continue to iterate) | ||
495 | */ | ||
496 | static int | ||
497 | iterate_addresses (void *cls, | ||
498 | const GNUNET_HashCode *key, | ||
499 | void *value) | ||
500 | { | ||
501 | struct GST_ValidationIteratorContext *vic = cls; | ||
502 | struct ValidationEntry *ve = value; | ||
503 | |||
504 | vic->cb (vic->cb_cls, | ||
505 | &ve->pid, | ||
506 | ve->last_validated_at, | ||
507 | ve->validation_block, | ||
508 | ve->transport_name, | ||
509 | ve->addr, | ||
510 | ve->addrlen); | ||
511 | return GNUNET_OK; | ||
512 | } | ||
513 | |||
514 | |||
515 | /** | ||
110 | * Call the given function for each address for the given target. | 516 | * Call the given function for each address for the given target. |
111 | * Can either give a snapshot (synchronous API) or be continuous. | 517 | * Can either give a snapshot (synchronous API) or be continuous. |
112 | * | 518 | * |
@@ -124,7 +530,22 @@ GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, | |||
124 | GST_ValidationAddressCallback cb, | 530 | GST_ValidationAddressCallback cb, |
125 | void *cb_cls) | 531 | void *cb_cls) |
126 | { | 532 | { |
127 | return NULL; | 533 | struct GST_ValidationIteratorContext *vic; |
534 | |||
535 | vic = GNUNET_malloc (sizeof (struct GST_ValidationIteratorContext)); | ||
536 | vic->cb = cb; | ||
537 | vic->cb_cls = cb_cls; | ||
538 | GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, | ||
539 | &target->hashPubKey, | ||
540 | &iterate_addresses, | ||
541 | vic); | ||
542 | if (GNUNET_YES == snapshot_only) | ||
543 | { | ||
544 | GNUNET_free (vic); | ||
545 | return NULL; | ||
546 | } | ||
547 | /* FIXME: install 'vic' somewhere */ | ||
548 | return vic; | ||
128 | } | 549 | } |
129 | 550 | ||
130 | 551 | ||
@@ -136,7 +557,8 @@ GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, | |||
136 | void | 557 | void |
137 | GST_validation_get_addresses_cancel (struct GST_ValidationIteratorContext *ctx) | 558 | GST_validation_get_addresses_cancel (struct GST_ValidationIteratorContext *ctx) |
138 | { | 559 | { |
139 | GNUNET_break (0); | 560 | /* FIXME: remove 'vic' from DS */ |
561 | GNUNET_free (ctx); | ||
140 | } | 562 | } |
141 | 563 | ||
142 | 564 | ||
diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h index 0d6e0ef5a..17f4a1cd7 100644 --- a/src/transport/gnunet-service-transport_validation.h +++ b/src/transport/gnunet-service-transport_validation.h | |||
@@ -105,10 +105,10 @@ struct GST_ValidationIteratorContext; | |||
105 | * @param target peer this change is about, never NULL | 105 | * @param target peer this change is about, never NULL |
106 | * @param last_validated_at is FOREVER if the address has not been validated (we're currently checking) | 106 | * @param last_validated_at is FOREVER if the address has not been validated (we're currently checking) |
107 | * is ZERO if the address was validated a long time ago (from PEERINFO) | 107 | * is ZERO if the address was validated a long time ago (from PEERINFO) |
108 | * is a time in the past if this process validated the address | 108 | * otherwise a time in the past if this process validated the address |
109 | * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) | 109 | * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) |
110 | * is ZERO if the address is considered valid (no validation needed) | 110 | * is ZERO if the address is considered valid (no validation needed) |
111 | * is a time in the future if we're currently denying re-validation | 111 | * otherwise a time in the future if we're currently denying re-validation |
112 | * @param plugin_name name of the plugin | 112 | * @param plugin_name name of the plugin |
113 | * @param plugin_address binary address | 113 | * @param plugin_address binary address |
114 | * @param plugin_address_len length of address | 114 | * @param plugin_address_len length of address |