fc02da5b456cd0fb6e767d4e87ed335fcd9a6b96
[oweals/gnunet.git] / src / transport / gnunet-service-transport_validation.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2015 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file transport/gnunet-service-transport_validation.c
21  * @brief address validation subsystem
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet-service-transport_ats.h"
26 #include "gnunet-service-transport_hello.h"
27 #include "gnunet-service-transport_neighbours.h"
28 #include "gnunet-service-transport_plugins.h"
29 #include "gnunet-service-transport_validation.h"
30 #include "gnunet-service-transport.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_ats_service.h"
33 #include "gnunet_peerinfo_service.h"
34 #include "gnunet_signatures.h"
35
36 /**
37  * Current state of a validation process.
38  *
39  * FIXME: what state is used to indicate that a validation
40  * was successful? If that is clarified/determined, "UGH" in
41  * ~gnunetpeerinfogtk.c:1103 should be resolved.
42  */
43 enum GNUNET_TRANSPORT_ValidationState
44 {
45   /**
46    * Undefined state
47    *
48    * Used for final callback indicating operation done
49    */
50   GNUNET_TRANSPORT_VS_NONE,
51
52   /**
53    * Fresh validation entry
54    *
55    * Entry was just created, no validation process was executed
56    */
57   GNUNET_TRANSPORT_VS_NEW,
58
59   /**
60    * Updated validation entry
61    *
62    * This is an update for an existing validation entry
63    */
64   GNUNET_TRANSPORT_VS_UPDATE,
65
66   /**
67    * Timeout for validation entry
68    *
69    * A timeout occured during the validation process
70    */
71   GNUNET_TRANSPORT_VS_TIMEOUT,
72
73   /**
74    * Validation entry is removed
75    *
76    * The validation entry is getting removed due to a failed validation
77    */
78   GNUNET_TRANSPORT_VS_REMOVE
79 };
80
81
82
83
84 /**
85  * How long is a PONG signature valid?  We'll recycle a signature until
86  * 1/4 of this time is remaining.  PONGs should expire so that if our
87  * external addresses change an adversary cannot replay them indefinitely.
88  * OTOH, we don't want to spend too much time generating PONG signatures,
89  * so they must have some lifetime to reduce our CPU usage.
90  */
91 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
92
93 /**
94  * After how long do we expire an address in a HELLO that we just
95  * validated?  This value is also used for our own addresses when we
96  * create a HELLO.
97  */
98 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
99
100 /**
101  * How often do we allow PINGing an address that we have not yet
102  * validated?  This also determines how long we track an address that
103  * we cannot validate (because after this time we can destroy the
104  * validation record).
105  */
106 #define UNVALIDATED_PING_KEEPALIVE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
107
108 /**
109  * How often do we PING an address that we have successfully validated
110  * in the past but are not actively using?  Should be (significantly)
111  * smaller than HELLO_ADDRESS_EXPIRATION.
112  */
113 #define VALIDATED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
114
115 /**
116  * How often do we PING an address that we are currently using?
117  */
118 #define CONNECTED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
119
120 /**
121  * How much delay is acceptable for sending the PING or PONG?
122  */
123 #define ACCEPTABLE_PING_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
124
125 /**
126  * Size of the validation map hashmap.
127  */
128 #define VALIDATION_MAP_SIZE 256
129
130 /**
131  * Priority to use for PINGs
132  */
133 #define PING_PRIORITY 2
134
135 /**
136  * Priority to use for PONGs
137  */
138 #define PONG_PRIORITY 4
139
140
141 GNUNET_NETWORK_STRUCT_BEGIN
142
143 /**
144  * Message used to ask a peer to validate receipt (to check an address
145  * from a HELLO).  Followed by the address we are trying to validate,
146  * or an empty address if we are just sending a PING to confirm that a
147  * connection which the receiver (of the PING) initiated is still valid.
148  */
149 struct TransportPingMessage
150 {
151
152   /**
153    * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_PING
154    */
155   struct GNUNET_MessageHeader header;
156
157   /**
158    * Challenge code (to ensure fresh reply).
159    */
160   uint32_t challenge GNUNET_PACKED;
161
162   /**
163    * Who is the intended recipient?
164    */
165   struct GNUNET_PeerIdentity target;
166
167 };
168
169
170 /**
171  * Message used to validate a HELLO.  The challenge is included in the
172  * confirmation to make matching of replies to requests possible.  The
173  * signature signs our public key, an expiration time and our address.<p>
174  *
175  * This message is followed by our transport address that the PING tried
176  * to confirm (if we liked it).  The address can be empty (zero bytes)
177  * if the PING had not address either (and we received the request via
178  * a connection that we initiated).
179  */
180 struct TransportPongMessage
181 {
182
183   /**
184    * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
185    */
186   struct GNUNET_MessageHeader header;
187
188   /**
189    * Challenge code from PING (showing freshness).  Not part of what
190    * is signed so that we can re-use signatures.
191    */
192   uint32_t challenge GNUNET_PACKED;
193
194   /**
195    * Signature.
196    */
197   struct GNUNET_CRYPTO_EddsaSignature signature;
198
199   /**
200    * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
201    * plausible address for the signing peer.
202    */
203   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
204
205   /**
206    * When does this signature expire?
207    */
208   struct GNUNET_TIME_AbsoluteNBO expiration;
209
210   /**
211    * Size of address appended to this message (part of what is
212    * being signed, hence not redundant).
213    */
214   uint32_t addrlen GNUNET_PACKED;
215
216 };
217 GNUNET_NETWORK_STRUCT_END
218
219 /**
220  * Information about an address under validation
221  */
222 struct ValidationEntry
223 {
224
225   /**
226    * The address.
227    */
228   struct GNUNET_HELLO_Address *address;
229
230   /**
231    * Handle to the blacklist check (if we're currently in it).
232    */
233   struct GST_BlacklistCheck *bc;
234
235   /**
236    * Cached PONG signature
237    */
238   struct GNUNET_CRYPTO_EddsaSignature pong_sig_cache;
239
240   /**
241    * ID of task that will clean up this entry if nothing happens.
242    */
243   struct GNUNET_SCHEDULER_Task *timeout_task;
244
245   /**
246    * ID of task that will trigger address revalidation.
247    */
248   struct GNUNET_SCHEDULER_Task *revalidation_task;
249
250   /**
251    * At what time did we send the latest validation request (PING)?
252    */
253   struct GNUNET_TIME_Absolute send_time;
254
255   /**
256    * At what time do we send the next validation request (PING)?
257    */
258   struct GNUNET_TIME_Absolute next_validation;
259
260   /**
261    * Until when is this address valid?
262    * ZERO if it is not currently considered valid.
263    */
264   struct GNUNET_TIME_Absolute valid_until;
265
266   /**
267    * Until when is the cached PONG signature valid?
268    * ZERO if it is not currently considered valid.
269    */
270   struct GNUNET_TIME_Absolute pong_sig_valid_until;
271
272   /**
273    * How long until we can try to validate this address again?
274    * FOREVER if the address is for an unsupported plugin (from PEERINFO)
275    * ZERO if the address is considered valid (no validation needed)
276    * otherwise a time in the future if we're currently denying re-validation
277    */
278   struct GNUNET_TIME_Absolute revalidation_block;
279
280   /**
281    * Last observed latency for this address (round-trip), delay between
282    * last PING sent and PONG received; FOREVER if we never got a PONG.
283    */
284   struct GNUNET_TIME_Relative latency;
285
286   /**
287    * Current state of this validation entry
288    */
289   enum GNUNET_TRANSPORT_ValidationState state;
290
291   /**
292    * Challenge number we used.
293    */
294   uint32_t challenge;
295
296   /**
297    * When passing the address in #add_valid_peer_address(), did we
298    * copy the address to the HELLO yet?
299    */
300   int copied;
301
302   /**
303    * Are we currently using this address for a connection?
304    */
305   int in_use;
306
307   /**
308    * Are we expecting a PONG message for this validation entry?
309    */
310   int expecting_pong;
311
312   /**
313    * Is this address known to ATS as valid right now?
314    */
315   int known_to_ats;
316
317   /**
318    * Which network type does our address belong to?
319    */
320   enum GNUNET_NetworkType network;
321 };
322
323
324 /**
325  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
326  * of the given peer that we are currently validating, have validated
327  * or are blocked from re-validation for a while).
328  */
329 static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
330
331 /**
332  * Context for peerinfo iteration.
333  */
334 static struct GNUNET_PEERINFO_NotifyContext *pnc;
335
336 /**
337  * Minimum delay between to validations
338  */
339 static struct GNUNET_TIME_Relative validation_delay;
340
341 /**
342  * Number of validations running; any PING that was not yet
343  * matched by a PONG and for which we have not yet hit the
344  * timeout is considered a running 'validation'.
345  */
346 static unsigned int validations_running;
347
348 /**
349  * Validition fast start threshold
350  */
351 static unsigned int validations_fast_start_threshold;
352
353 /**
354  * When is next validation allowed
355  */
356 static struct GNUNET_TIME_Absolute validation_next;
357
358
359 /**
360  * Context for the validation entry match function.
361  */
362 struct ValidationEntryMatchContext
363 {
364   /**
365    * Where to store the result?
366    */
367   struct ValidationEntry *ve;
368
369   /**
370    * Address we're interested in.
371    */
372   const struct GNUNET_HELLO_Address *address;
373
374 };
375
376
377 /**
378  * Provide an update on the `validation_map` map size to statistics.
379  * This function should be called whenever the `validation_map`
380  * is changed.
381  */
382 static void
383 publish_ve_stat_update ()
384 {
385   GNUNET_STATISTICS_set (GST_stats,
386                          gettext_noop ("# Addresses in validation map"),
387                          GNUNET_CONTAINER_multipeermap_size (validation_map),
388                          GNUNET_NO);
389 }
390
391
392 /**
393  * Iterate over validation entries until a matching one is found.
394  *
395  * @param cls the `struct ValidationEntryMatchContext *`
396  * @param key peer identity (unused)
397  * @param value a `struct ValidationEntry *` to match
398  * @return #GNUNET_YES if the entry does not match,
399  *         #GNUNET_NO if the entry does match
400  */
401 static int
402 validation_entry_match (void *cls,
403                         const struct GNUNET_PeerIdentity *key,
404                         void *value)
405 {
406   struct ValidationEntryMatchContext *vemc = cls;
407   struct ValidationEntry *ve = value;
408
409   if (0 == GNUNET_HELLO_address_cmp (ve->address,
410                                      vemc->address))
411   {
412     vemc->ve = ve;
413     return GNUNET_NO;
414   }
415   return GNUNET_YES;
416 }
417
418
419 /**
420  * A validation entry changed.  Update the state and notify
421  * monitors.
422  *
423  * @param ve validation entry that changed
424  * @param state new state
425  */
426 static void
427 validation_entry_changed (struct ValidationEntry *ve,
428                           enum GNUNET_TRANSPORT_ValidationState state)
429 {
430   ve->state = state;
431 }
432
433
434 /**
435  * Iterate over validation entries and free them.
436  *
437  * @param cls (unused)
438  * @param key peer identity (unused)
439  * @param value a `struct ValidationEntry *` to clean up
440  * @return #GNUNET_YES (continue to iterate)
441  */
442 static int
443 cleanup_validation_entry (void *cls,
444                           const struct GNUNET_PeerIdentity *key,
445                           void *value)
446 {
447   struct ValidationEntry *ve = value;
448
449   ve->next_validation = GNUNET_TIME_UNIT_ZERO_ABS;
450   ve->valid_until = GNUNET_TIME_UNIT_ZERO_ABS;
451
452   /* Notify about deleted entry */
453   validation_entry_changed (ve,
454                             GNUNET_TRANSPORT_VS_REMOVE);
455
456   if (NULL != ve->bc)
457   {
458     GST_blacklist_test_cancel (ve->bc);
459     ve->bc = NULL;
460   }
461   GNUNET_break (GNUNET_OK ==
462                 GNUNET_CONTAINER_multipeermap_remove (validation_map,
463                                                       &ve->address->peer,
464                                                       ve));
465   publish_ve_stat_update ();
466   if (GNUNET_YES == ve->known_to_ats)
467   {
468     GST_ats_expire_address (ve->address);
469     GNUNET_assert (GNUNET_NO ==
470                    GST_ats_is_known_no_session (ve->address));
471     ve->known_to_ats = GNUNET_NO;
472   }
473   GNUNET_HELLO_address_free (ve->address);
474   if (NULL != ve->timeout_task)
475   {
476     GNUNET_SCHEDULER_cancel (ve->timeout_task);
477     ve->timeout_task = NULL;
478   }
479   if (NULL != ve->revalidation_task)
480   {
481     GNUNET_SCHEDULER_cancel (ve->revalidation_task);
482     ve->revalidation_task = NULL;
483   }
484   if ( (GNUNET_YES == ve->expecting_pong) &&
485        (validations_running > 0) )
486   {
487     validations_running--;
488     GNUNET_STATISTICS_set (GST_stats,
489                            gettext_noop ("# validations running"),
490                            validations_running,
491                            GNUNET_NO);
492   }
493   GNUNET_free (ve);
494   return GNUNET_OK;
495 }
496
497
498 /**
499  * Address validation cleanup task.  Assesses if the record is no
500  * longer valid and then possibly triggers its removal.
501  *
502  * @param cls the `struct ValidationEntry`
503  */
504 static void
505 timeout_hello_validation (void *cls)
506 {
507   struct ValidationEntry *ve = cls;
508   struct GNUNET_TIME_Absolute max;
509   struct GNUNET_TIME_Relative left;
510
511   ve->timeout_task = NULL;
512   /* For valid addresses, we want to wait until the expire;
513      for addresses under PING validation, we want to wait
514      until we give up on the PING */
515   max = GNUNET_TIME_absolute_max (ve->valid_until,
516                                   ve->revalidation_block);
517   left = GNUNET_TIME_absolute_get_remaining (max);
518   if (left.rel_value_us > 0)
519   {
520     /* We should wait a bit longer. This happens when
521        address lifetimes are extended due to successful
522        validations. */
523     ve->timeout_task =
524         GNUNET_SCHEDULER_add_delayed (left,
525                                       &timeout_hello_validation,
526                                       ve);
527     return;
528   }
529   GNUNET_STATISTICS_update (GST_stats,
530                             gettext_noop ("# address records discarded (timeout)"),
531                             1,
532                             GNUNET_NO);
533   cleanup_validation_entry (NULL,
534                             &ve->address->peer,
535                             ve);
536 }
537
538
539 /**
540  * Function called with the result from blacklisting.
541  * Send a PING to the other peer if a communication is allowed.
542  *
543  * @param cls our `struct ValidationEntry`
544  * @param pid identity of the other peer
545  * @param address_null address associated with the request, always NULL
546  * @param session_null session associated with the request, always NULL
547  * @param result #GNUNET_OK if the connection is allowed,
548  *               #GNUNET_NO if not,
549  *               #GNUNET_SYSERR if operation was aborted
550  */
551 static void
552 transmit_ping_if_allowed (void *cls,
553                           const struct GNUNET_PeerIdentity *pid,
554                           const struct GNUNET_HELLO_Address *address_null,
555                           struct GNUNET_ATS_Session *session_null,
556                           int result)
557 {
558   struct ValidationEntry *ve = cls;
559   struct TransportPingMessage ping;
560   struct GNUNET_TRANSPORT_PluginFunctions *papi;
561   struct GNUNET_TIME_Absolute next;
562   const struct GNUNET_MessageHeader *hello;
563   ssize_t ret;
564   size_t tsize;
565   size_t slen;
566   uint16_t hsize;
567   struct GNUNET_ATS_Session *session;
568
569   ve->bc = NULL;
570   if (GNUNET_OK != result)
571   {
572     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
573                 "Blacklist denies sending PING to `%s' `%s' `%s'\n",
574                 GNUNET_i2s (pid),
575                 GST_plugins_a2s (ve->address),
576                 ve->address->transport_name);
577     GNUNET_STATISTICS_update (GST_stats,
578                               gettext_noop ("# address records discarded (blacklist)"),
579                               1,
580                               GNUNET_NO);
581     cleanup_validation_entry (NULL,
582                               pid,
583                               ve);
584     return;
585   }
586   hello = GST_hello_get ();
587   GNUNET_assert (NULL != hello);
588   slen = strlen (ve->address->transport_name) + 1;
589   hsize = ntohs (hello->size);
590   tsize = sizeof (struct TransportPingMessage) +
591     ve->address->address_length + slen + hsize;
592
593   ping.header.size =
594       htons (sizeof (struct TransportPingMessage) +
595              ve->address->address_length + slen);
596   ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
597   ping.challenge = htonl (ve->challenge);
598   ping.target = *pid;
599
600   if (tsize >= GNUNET_MAX_MESSAGE_SIZE)
601   {
602     GNUNET_break (0);
603     hsize = 0;
604     tsize =
605         sizeof (struct TransportPingMessage) + ve->address->address_length +
606         slen + hsize;
607   }
608   {
609     char message_buf[tsize] GNUNET_ALIGN;
610
611     GNUNET_memcpy (message_buf,
612             hello,
613             hsize);
614     GNUNET_memcpy (&message_buf[hsize],
615             &ping,
616             sizeof (struct TransportPingMessage));
617     GNUNET_memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize],
618             ve->address->transport_name,
619             slen);
620     GNUNET_memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize],
621             ve->address->address,
622             ve->address->address_length);
623     papi = GST_plugins_find (ve->address->transport_name);
624     GNUNET_assert (NULL != papi);
625     session = papi->get_session (papi->cls,
626                                  ve->address);
627     if (NULL == session)
628     {
629       /* Could not get a valid session */
630       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631                   "Failed to get session to send PING to `%s' at `%s'\n",
632                   GNUNET_i2s (pid),
633                   GST_plugins_a2s (ve->address));
634       return;
635     }
636
637     ret = papi->send (papi->cls, session,
638                       message_buf, tsize,
639                       PING_PRIORITY,
640                       ACCEPTABLE_PING_DELAY,
641                       NULL, NULL);
642     if (-1 == ret)
643     {
644       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
645                   "Failed to send PING to `%s' at `%s'\n",
646                   GNUNET_i2s (pid),
647                   GST_plugins_a2s (ve->address));
648       return;
649     }
650     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651                 "Transmitted plain PING to `%s' `%s' `%s'\n",
652                 GNUNET_i2s (pid),
653                 GST_plugins_a2s (ve->address),
654                 ve->address->transport_name);
655     ve->network = papi->get_network (papi->cls,
656                                      session);
657     GNUNET_break (GNUNET_NT_UNSPECIFIED != ve->network);
658     GST_neighbours_notify_data_sent (ve->address,
659                                      session,
660                                      tsize);
661     next = GNUNET_TIME_relative_to_absolute (validation_delay);
662     validation_next = GNUNET_TIME_absolute_max (next,
663                                                 validation_next);
664     ve->send_time = GNUNET_TIME_absolute_get ();
665     GNUNET_STATISTICS_update (GST_stats,
666                               gettext_noop ("# PINGs for address validation sent"),
667                               1,
668                               GNUNET_NO);
669     ve->expecting_pong = GNUNET_YES;
670     validations_running++;
671     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672                 "Validation started, %u validation processes running\n",
673                 validations_running);
674     GNUNET_STATISTICS_set (GST_stats,
675                            gettext_noop ("# validations running"),
676                            validations_running,
677                            GNUNET_NO);
678     /*  Notify about PING sent */
679     validation_entry_changed (ve,
680                               GNUNET_TRANSPORT_VS_UPDATE);
681
682   }
683 }
684
685
686 /**
687  * Do address validation again to keep address valid.
688  *
689  * @param cls the `struct ValidationEntry`
690  */
691 static void
692 revalidate_address (void *cls)
693 {
694   struct ValidationEntry *ve = cls;
695   struct GNUNET_TIME_Relative canonical_delay;
696   struct GNUNET_TIME_Relative delay;
697   struct GNUNET_TIME_Relative blocked_for;
698   struct GST_BlacklistCheck *bc;
699   uint32_t rdelay;
700
701   ve->revalidation_task = NULL;
702   delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block);
703   /* Considering current connectivity situation, what is the maximum
704      block period permitted? */
705   if (GNUNET_YES == ve->in_use)
706     canonical_delay = CONNECTED_PING_FREQUENCY;
707   else if (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value_us > 0)
708     canonical_delay = VALIDATED_PING_FREQUENCY;
709   else
710     canonical_delay = UNVALIDATED_PING_KEEPALIVE;
711   /* Use delay that is MIN of original delay and possibly adjusted
712      new maximum delay (which may be lower); the real delay
713      is originally randomized between "canonical_delay" and "2 * canonical_delay",
714      so continue to permit that window for the operation. */
715   delay = GNUNET_TIME_relative_min (delay,
716                                     GNUNET_TIME_relative_multiply (canonical_delay,
717                                                                    2));
718   ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay);
719   if (delay.rel_value_us > 0)
720   {
721     /* should wait a bit longer */
722     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723                 "Waiting for %s longer before (re)validating address `%s'\n",
724                 GNUNET_STRINGS_relative_time_to_string (delay,
725                                                         GNUNET_YES),
726                 GST_plugins_a2s (ve->address));
727     ve->revalidation_task =
728         GNUNET_SCHEDULER_add_delayed (delay,
729                                       &revalidate_address, ve);
730     ve->next_validation = GNUNET_TIME_relative_to_absolute (delay);
731     return;
732   }
733   /* check if globally we have too many active validations at a
734      too high rate, if so, delay ours */
735   blocked_for = GNUNET_TIME_absolute_get_remaining (validation_next);
736   if ( (validations_running > validations_fast_start_threshold) &&
737        (blocked_for.rel_value_us > 0) )
738   {
739     /* Validations are blocked, have to wait for blocked_for time */
740     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
741                 "Validations blocked for another %s, delaying validating address `%s'\n",
742                 GNUNET_STRINGS_relative_time_to_string (blocked_for,
743                                                         GNUNET_YES),
744                 GST_plugins_a2s (ve->address));
745     GNUNET_STATISTICS_update (GST_stats,
746                               gettext_noop ("# validations delayed by global throttle"),
747                               1,
748                               GNUNET_NO);
749     ve->revalidation_task =
750       GNUNET_SCHEDULER_add_delayed (blocked_for,
751                                     &revalidate_address,
752                                     ve);
753     ve->next_validation = GNUNET_TIME_relative_to_absolute (blocked_for);
754     return;
755   }
756
757   /* We are good to go; remember to not go again for `canonical_delay` time;
758      add up to `canonical_delay` to randomize start time */
759   ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay);
760   /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */
761   rdelay =
762       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
763                                 canonical_delay.rel_value_us);
764
765   delay = GNUNET_TIME_relative_add (canonical_delay,
766                                     GNUNET_TIME_relative_multiply
767                                     (GNUNET_TIME_UNIT_MICROSECONDS,
768                                      rdelay));
769
770   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771               "Validating now, next scheduled for %s, now validating address `%s'\n",
772               GNUNET_STRINGS_relative_time_to_string (blocked_for,
773                                                       GNUNET_YES),
774               GST_plugins_a2s (ve->address));
775   ve->revalidation_task =
776       GNUNET_SCHEDULER_add_delayed (delay,
777                                     &revalidate_address,
778                                     ve);
779   ve->next_validation = GNUNET_TIME_relative_to_absolute (delay);
780
781   /* start PINGing by checking blacklist */
782   GNUNET_STATISTICS_update (GST_stats,
783                             gettext_noop ("# address revalidations started"), 1,
784                             GNUNET_NO);
785   if (NULL != ve->bc)
786   {
787     GST_blacklist_test_cancel (ve->bc);
788     ve->bc = NULL;
789   }
790   bc = GST_blacklist_test_allowed (&ve->address->peer,
791                                    ve->address->transport_name,
792                                    &transmit_ping_if_allowed,
793                                    ve,
794                                    NULL,
795                                    NULL);
796   if (NULL != bc)
797   {
798     /* If transmit_ping_if_allowed was already called it may have freed ve,
799      * so only set ve->bc if it has not been called.
800      */
801     ve->bc = bc;
802   }
803 }
804
805
806 /**
807  * Find a ValidationEntry entry for the given neighbour that matches
808  * the given address and transport.  If none exists, create one (but
809  * without starting any validation).
810  *
811  * @param address address to find
812  * @return validation entry matching the given specifications, NULL
813  *         if we don't have an existing entry and no public key was given
814  */
815 static struct ValidationEntry *
816 find_validation_entry (const struct GNUNET_HELLO_Address *address)
817 {
818   struct ValidationEntryMatchContext vemc;
819   struct ValidationEntry *ve;
820
821   vemc.ve = NULL;
822   vemc.address = address;
823   GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
824                                               &address->peer,
825                                               &validation_entry_match, &vemc);
826   if (NULL != (ve = vemc.ve))
827     return ve;
828   GNUNET_assert (GNUNET_NO ==
829                  GST_ats_is_known_no_session (address));
830   ve = GNUNET_new (struct ValidationEntry);
831   ve->in_use = GNUNET_SYSERR; /* not defined */
832   ve->address = GNUNET_HELLO_address_copy (address);
833   ve->pong_sig_valid_until = GNUNET_TIME_UNIT_ZERO_ABS;
834   memset (&ve->pong_sig_cache,
835           '\0',
836           sizeof (struct GNUNET_CRYPTO_EddsaSignature));
837   ve->latency = GNUNET_TIME_UNIT_FOREVER_REL;
838   ve->challenge =
839       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
840   ve->timeout_task =
841       GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE,
842                                     &timeout_hello_validation,
843                                     ve);
844   GNUNET_CONTAINER_multipeermap_put (validation_map,
845                                      &address->peer,
846                                      ve,
847                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
848   publish_ve_stat_update ();
849   validation_entry_changed (ve,
850                             GNUNET_TRANSPORT_VS_NEW);
851   return ve;
852 }
853
854
855 /**
856  * Iterator which adds the given address to the set of validated
857  * addresses.
858  *
859  * @param cls original HELLO message
860  * @param address the address
861  * @param expiration expiration time
862  * @return #GNUNET_OK (keep the address), could return
863  *         #GNUNET_NO (delete address, but this is ignored);
864  *         #GNUNET_SYSERR would abort iteration (but we always iterate all)
865  */
866 static int
867 add_valid_address (void *cls,
868                    const struct GNUNET_HELLO_Address *address,
869                    struct GNUNET_TIME_Absolute expiration)
870 {
871   const struct GNUNET_HELLO_Message *hello = cls;
872   struct ValidationEntry *ve;
873   struct GNUNET_PeerIdentity pid;
874   struct GNUNET_ATS_Properties prop;
875   struct GNUNET_TRANSPORT_PluginFunctions *papi;
876
877   if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
878     return GNUNET_OK;           /* expired */
879   if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
880   {
881     GNUNET_break (0);
882     return GNUNET_OK;           /* invalid HELLO !? */
883   }
884   if (NULL == (papi = GST_plugins_find (address->transport_name)))
885   {
886     /* might have been valid in the past, but we don't have that
887        plugin loaded right now */
888     return GNUNET_OK;
889   }
890   if (NULL ==
891       papi->address_to_string (papi->cls,
892                                address->address,
893                                address->address_length))
894   {
895     /* Why do we try to add an ill-formed address? */
896     GNUNET_break (0);
897     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
898                 "Address with %u bytes for plugin %s and peer %s is malformed\n",
899                 (unsigned int) address->address_length,
900                 address->transport_name,
901                 GNUNET_i2s (&pid));
902     return GNUNET_OK;
903   }
904
905   ve = find_validation_entry (address);
906   ve->network = papi->get_network_for_address (papi->cls,
907                                                address);
908   GNUNET_break (GNUNET_NT_UNSPECIFIED != ve->network);
909   ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until,
910                                               expiration);
911   if (NULL == ve->revalidation_task)
912   {
913     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
914                 "Starting revalidations for valid address `%s'\n",
915                 GST_plugins_a2s (ve->address));
916     ve->next_validation = GNUNET_TIME_absolute_get();
917     ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
918   }
919   validation_entry_changed (ve,
920                             GNUNET_TRANSPORT_VS_UPDATE);
921   memset (&prop, 0, sizeof (prop));
922   prop.scope = ve->network;
923   prop.delay = GNUNET_TIME_relative_divide (ve->latency, 2);
924   if (GNUNET_YES != ve->known_to_ats)
925   {
926     ve->known_to_ats = GNUNET_YES;
927     GST_ats_add_address (address, &prop);
928     GNUNET_assert (GNUNET_YES ==
929                    GST_ats_is_known_no_session (ve->address));
930   }
931   return GNUNET_OK;
932 }
933
934
935 /**
936  * Function called for any HELLO known to PEERINFO.
937  *
938  * @param cls unused (NULL)
939  * @param peer id of the peer, NULL for last call (during iteration,
940  *             as we are monitoring, this should never happen)
941  * @param hello hello message for the peer (can be NULL)
942  * @param err_msg error message
943  */
944 static void
945 process_peerinfo_hello (void *cls,
946                         const struct GNUNET_PeerIdentity *peer,
947                         const struct GNUNET_HELLO_Message *hello,
948                         const char *err_msg)
949 {
950   GNUNET_assert (NULL != peer);
951   if (NULL == hello)
952     return;
953   if (0 == memcmp (&GST_my_identity,
954                    peer,
955                    sizeof (struct GNUNET_PeerIdentity)))
956   {
957     /* Peerinfo returned own identity, skip validation */
958     return;
959   }
960   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961               "Handling HELLO for peer `%s'\n",
962               GNUNET_i2s (peer));
963   GNUNET_assert (NULL ==
964                  GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO,
965                                                  &add_valid_address,
966                                                  (void *) hello));
967 }
968
969
970 /**
971  * Start the validation subsystem.
972  *
973  * @param max_fds maximum number of fds to use
974  */
975 void
976 GST_validation_start (unsigned int max_fds)
977 {
978   /**
979    * Initialization for validation throttling
980    *
981    * We have a maximum number max_fds of connections we can use for validation
982    * We monitor the number of validations in parallel and start to throttle it
983    * when doing to many validations in parallel:
984    * if (running validations < (max_fds / 2))
985    * - "fast start": run validation immediately
986    * - have delay of (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2)
987    *   (300 sec / ~150 == ~2 sec.) between two validations
988    */
989
990   validation_next = GNUNET_TIME_absolute_get();
991   validation_delay.rel_value_us = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2);
992   validations_fast_start_threshold = (max_fds / 2);
993   validations_running = 0;
994   GNUNET_STATISTICS_set (GST_stats,
995                          gettext_noop ("# validations running"),
996                          validations_running,
997                          GNUNET_NO);
998   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
999               "Validation uses a fast start threshold of %u connections and a delay of %s\n",
1000               validations_fast_start_threshold,
1001               GNUNET_STRINGS_relative_time_to_string (validation_delay,
1002                                                       GNUNET_YES));
1003   validation_map = GNUNET_CONTAINER_multipeermap_create (VALIDATION_MAP_SIZE,
1004                                                          GNUNET_NO);
1005   pnc = GNUNET_PEERINFO_notify (GST_cfg, GNUNET_YES,
1006                                 &process_peerinfo_hello, NULL);
1007 }
1008
1009
1010 /**
1011  * Stop the validation subsystem.
1012  */
1013 void
1014 GST_validation_stop ()
1015 {
1016   GNUNET_CONTAINER_multipeermap_iterate (validation_map,
1017                                          &cleanup_validation_entry,
1018                                          NULL);
1019   GNUNET_CONTAINER_multipeermap_destroy (validation_map);
1020   validation_map = NULL;
1021   GNUNET_PEERINFO_notify_cancel (pnc);
1022 }
1023
1024
1025 /**
1026  * Send the given PONG to the given address.
1027  *
1028  * @param cls the PONG message
1029  * @param valid_until is ZERO if we never validated the address,
1030  *                    otherwise a time up to when we consider it (or was) valid
1031  * @param validation_block  is FOREVER if the address is for an unsupported plugin (from PEERINFO)
1032  *                          is ZERO if the address is considered valid (no validation needed)
1033  *                          otherwise a time in the future if we're currently denying re-validation
1034  * @param address target address
1035  */
1036 static void
1037 multicast_pong (void *cls,
1038                 struct GNUNET_TIME_Absolute valid_until,
1039                 struct GNUNET_TIME_Absolute validation_block,
1040                 const struct GNUNET_HELLO_Address *address)
1041 {
1042   struct TransportPongMessage *pong = cls;
1043   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1044   struct GNUNET_ATS_Session *session;
1045
1046   papi = GST_plugins_find (address->transport_name);
1047   if (NULL == papi)
1048   {
1049     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1050                 "Plugin %s not supported, cannot send PONG\n",
1051                 address->transport_name);
1052     return;
1053   }
1054   GNUNET_assert (NULL != papi->send);
1055   GNUNET_assert (NULL != papi->get_session);
1056   session = papi->get_session(papi->cls, address);
1057   if (NULL == session)
1058   {
1059      GNUNET_break (0);
1060      return;
1061   }
1062   GST_ats_new_session (address, session);
1063   papi->send (papi->cls, session,
1064               (const char *) pong,
1065               ntohs (pong->header.size),
1066               PONG_PRIORITY,
1067               ACCEPTABLE_PING_DELAY,
1068               NULL, NULL);
1069   GST_neighbours_notify_data_sent (address,
1070                                    session,
1071                                    pong->header.size);
1072 }
1073
1074
1075 /**
1076  * We've received a PING.  If appropriate, generate a PONG.
1077  *
1078  * @param sender peer sending the PING
1079  * @param hdr the PING
1080  * @param sender_address the sender address as we got it
1081  * @param session session we got the PING from
1082  * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
1083  */
1084 int
1085 GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
1086                             const struct GNUNET_MessageHeader *hdr,
1087                             const struct GNUNET_HELLO_Address *sender_address,
1088                             struct GNUNET_ATS_Session *session)
1089 {
1090   const struct TransportPingMessage *ping;
1091   struct TransportPongMessage *pong;
1092   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1093   struct GNUNET_CRYPTO_EddsaSignature *sig_cache;
1094   struct GNUNET_TIME_Absolute *sig_cache_exp;
1095   const char *addr;
1096   const char *addrend;
1097   char *plugin_name;
1098   char *pos;
1099   size_t len_address;
1100   size_t len_plugin;
1101   ssize_t ret;
1102   struct GNUNET_HELLO_Address address;
1103
1104   if (0 ==
1105       memcmp (&GST_my_identity,
1106               sender,
1107               sizeof (struct GNUNET_PeerIdentity)))
1108     return GNUNET_OK; /* our own, ignore! */
1109   if (ntohs (hdr->size) < sizeof (struct TransportPingMessage))
1110   {
1111     GNUNET_break_op (0);
1112     return GNUNET_SYSERR;
1113   }
1114   ping = (const struct TransportPingMessage *) hdr;
1115   if (0 !=
1116       memcmp (&ping->target, &GST_my_identity,
1117               sizeof (struct GNUNET_PeerIdentity)))
1118   {
1119     GNUNET_STATISTICS_update (GST_stats,
1120                               gettext_noop
1121                               ("# PING message for different peer received"), 1,
1122                               GNUNET_NO);
1123     return GNUNET_SYSERR;
1124   }
1125   GNUNET_STATISTICS_update (GST_stats,
1126                             gettext_noop ("# PING messages received"), 1,
1127                             GNUNET_NO);
1128   addr = (const char *) &ping[1];
1129   len_address = ntohs (hdr->size) - sizeof (struct TransportPingMessage);
1130   /* peer wants to confirm that this is one of our addresses, this is what is
1131    * used for address validation */
1132
1133   sig_cache = NULL;
1134   sig_cache_exp = NULL;
1135   papi = NULL;
1136   if (len_address > 0)
1137   {
1138     addrend = memchr (addr, '\0', len_address);
1139     if (NULL == addrend)
1140     {
1141       GNUNET_break_op (0);
1142       return GNUNET_SYSERR;
1143     }
1144     addrend++;
1145     len_plugin = strlen (addr) + 1;
1146     len_address -= len_plugin;
1147     address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
1148     address.address = addrend;
1149     address.address_length = len_address;
1150     address.transport_name = addr;
1151     address.peer = GST_my_identity;
1152
1153     if (NULL == address.transport_name)
1154     {
1155       GNUNET_break (0);
1156     }
1157
1158     if (0 != strstr (address.transport_name, "_client"))
1159     {
1160       plugin_name = GNUNET_strdup (address.transport_name);
1161       pos = strstr (plugin_name, "_client");
1162       GNUNET_assert (NULL != pos);
1163       GNUNET_snprintf (pos, strlen ("_server") + 1, "%s", "_server");
1164     }
1165     else
1166       plugin_name = GNUNET_strdup (address.transport_name);
1167
1168     if (NULL == (papi = GST_plugins_find (plugin_name)))
1169     {
1170       /* we don't have the plugin for this address */
1171       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1172                   _("Plugin `%s' not available, cannot confirm having this address\n"),
1173                   plugin_name);
1174       GNUNET_free (plugin_name);
1175       return GNUNET_SYSERR;
1176     }
1177     GNUNET_free (plugin_name);
1178     if (GNUNET_OK !=
1179         papi->check_address (papi->cls,
1180                              addrend,
1181                              len_address))
1182     {
1183       GNUNET_STATISTICS_update (GST_stats,
1184                                 gettext_noop
1185                                 ("# failed address checks during validation"), 1,
1186                                 GNUNET_NO);
1187       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1188                   _("Address `%s' is not one of my addresses, not confirming PING\n"),
1189                   GST_plugins_a2s (&address));
1190       return GNUNET_SYSERR;
1191     }
1192     else
1193     {
1194       GNUNET_STATISTICS_update (GST_stats,
1195                                 gettext_noop
1196                                 ("# successful address checks during validation"), 1,
1197                                 GNUNET_NO);
1198       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1199                   "Address `%s' is one of my addresses, confirming PING\n",
1200                   GST_plugins_a2s (&address));
1201     }
1202
1203     if (GNUNET_YES !=
1204         GST_hello_test_address (&address,
1205                                 &sig_cache,
1206                                 &sig_cache_exp))
1207     {
1208       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1209                   _("Not confirming PING from peer `%s' with address `%s' since I cannot confirm having this address.\n"),
1210                   GNUNET_i2s (sender),
1211                   GST_plugins_a2s (&address));
1212       return GNUNET_SYSERR;
1213     }
1214   }
1215   else
1216   {
1217     addrend = NULL;             /* make gcc happy */
1218     len_plugin = 0;
1219     static struct GNUNET_CRYPTO_EddsaSignature no_address_signature;
1220     static struct GNUNET_TIME_Absolute no_address_signature_expiration;
1221
1222     sig_cache = &no_address_signature;
1223     sig_cache_exp = &no_address_signature_expiration;
1224   }
1225
1226   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1227               "I am `%s', sending PONG to peer `%s'\n",
1228               GNUNET_i2s_full (&GST_my_identity),
1229               GNUNET_i2s (sender));
1230
1231   /* message with structure:
1232    * [TransportPongMessage][Transport name][Address] */
1233
1234   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + len_address + len_plugin);
1235   pong->header.size =
1236       htons (sizeof (struct TransportPongMessage) + len_address + len_plugin);
1237   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
1238   pong->purpose.size =
1239       htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
1240              sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
1241              len_address + len_plugin);
1242   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
1243   GNUNET_memcpy (&pong->challenge, &ping->challenge, sizeof (ping->challenge));
1244   pong->addrlen = htonl (len_address + len_plugin);
1245   GNUNET_memcpy (&pong[1], addr, len_plugin);   /* Copy transport plugin */
1246   if (len_address > 0)
1247   {
1248     GNUNET_assert (NULL != addrend);
1249     GNUNET_memcpy (&((char *) &pong[1])[len_plugin], addrend, len_address);
1250   }
1251   if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value_us <
1252       PONG_SIGNATURE_LIFETIME.rel_value_us / 4)
1253   {
1254     /* create / update cached sig */
1255     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1256                 "Creating PONG signature to indicate ownership.\n");
1257     *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
1258     pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
1259     if (GNUNET_OK !=
1260                    GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, &pong->purpose,
1261                                            sig_cache))
1262     {
1263         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1264                 _("Failed to create PONG signature for peer `%s'\n"), GNUNET_i2s (sender));
1265     }
1266   }
1267   else
1268   {
1269     pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
1270   }
1271   pong->signature = *sig_cache;
1272
1273   GNUNET_assert (NULL != sender_address);
1274
1275   /* first see if the session we got this PING from can be used to transmit
1276    * a response reliably */
1277   if (NULL == papi)
1278   {
1279     ret = -1;
1280   }
1281   else
1282   {
1283     GNUNET_assert (NULL != papi->send);
1284     GNUNET_assert (NULL != papi->get_session);
1285     if (NULL == session)
1286     {
1287       session = papi->get_session (papi->cls, sender_address);
1288     }
1289     if (NULL == session)
1290     {
1291       GNUNET_break (0);
1292       ret = -1;
1293     }
1294     else
1295     {
1296       ret = papi->send (papi->cls, session,
1297                         (const char *) pong,
1298                         ntohs (pong->header.size),
1299                         PONG_PRIORITY, ACCEPTABLE_PING_DELAY,
1300                         NULL, NULL);
1301       if (-1 != ret)
1302         GST_neighbours_notify_data_sent (sender_address,
1303                                          session,
1304                                          pong->header.size);
1305     }
1306   }
1307   if (-1 != ret)
1308   {
1309     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1310                 "Transmitted PONG to `%s' via reliable mechanism\n",
1311                 GNUNET_i2s (sender));
1312     /* done! */
1313     GNUNET_STATISTICS_update (GST_stats,
1314                               gettext_noop
1315                               ("# PONGs unicast via reliable transport"), 1,
1316                               GNUNET_NO);
1317     GNUNET_free (pong);
1318     return GNUNET_OK;
1319   }
1320
1321   /* no reliable method found, try transmission via all known addresses */
1322   GNUNET_STATISTICS_update (GST_stats,
1323                             gettext_noop
1324                             ("# PONGs multicast to all available addresses"), 1,
1325                             GNUNET_NO);
1326   GST_validation_get_addresses (sender,
1327                                 &multicast_pong, pong);
1328   GNUNET_free (pong);
1329   return GNUNET_OK;
1330 }
1331
1332
1333 /**
1334  * Validate an individual address.
1335  *
1336  * @param address address we should try to validate
1337  */
1338 void
1339 GST_validation_handle_address (const struct GNUNET_HELLO_Address *address)
1340 {
1341   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1342   struct ValidationEntry *ve;
1343
1344   papi = GST_plugins_find (address->transport_name);
1345   if (NULL == papi)
1346   {
1347     /* This plugin is currently unvailable ... ignore */
1348     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1349                 "No plugin available for %s\n",
1350                 address->transport_name);
1351     return;
1352   }
1353   ve = find_validation_entry (address);
1354   if (NULL == ve->revalidation_task)
1355   {
1356     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1357                 "Validation process started for fresh address `%s' of %s\n",
1358                 GST_plugins_a2s (ve->address),
1359                 GNUNET_i2s (&ve->address->peer));
1360     ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
1361   }
1362   else
1363   {
1364     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1365                 "Validation already running for address `%s' of %s\n",
1366                 GST_plugins_a2s (ve->address),
1367                 GNUNET_i2s (&ve->address->peer));
1368   }
1369 }
1370
1371
1372 /**
1373  * Iterator callback to go over all addresses and try to validate them
1374  * (unless blocked or already validated).
1375  *
1376  * @param cls NULL
1377  * @param address the address
1378  * @param expiration expiration time
1379  * @return #GNUNET_OK (keep the address)
1380  */
1381 static int
1382 validate_address_iterator (void *cls,
1383                            const struct GNUNET_HELLO_Address *address,
1384                            struct GNUNET_TIME_Absolute expiration)
1385 {
1386   if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
1387   {
1388     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1389                 "Skipping expired address from HELLO\n");
1390     return GNUNET_OK;           /* expired */
1391   }
1392   GST_validation_handle_address (address);
1393   return GNUNET_OK;
1394 }
1395
1396
1397 /**
1398  * Add the validated peer address to the HELLO.
1399  *
1400  * @param cls the `struct ValidationEntry *` with the validated address
1401  * @param max space in @a buf
1402  * @param buf where to add the address
1403  * @return number of bytes written, #GNUNET_SYSERR to signal the
1404  *         end of the iteration.
1405  */
1406 static ssize_t
1407 add_valid_peer_address (void *cls,
1408                         size_t max,
1409                         void *buf)
1410 {
1411   struct ValidationEntry *ve = cls;
1412
1413   if (GNUNET_YES == ve->copied)
1414     return GNUNET_SYSERR; /* Done */
1415   ve->copied = GNUNET_YES;
1416   return GNUNET_HELLO_add_address (ve->address,
1417                                    ve->valid_until,
1418                                    buf,
1419                                    max);
1420 }
1421
1422
1423 /**
1424  * We've received a PONG.  Check if it matches a pending PING and
1425  * mark the respective address as confirmed.
1426  *
1427  * @param sender peer sending the PONG
1428  * @param hdr the PONG
1429  * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
1430  */
1431 int
1432 GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
1433                             const struct GNUNET_MessageHeader *hdr)
1434 {
1435   const struct TransportPongMessage *pong;
1436   struct ValidationEntry *ve;
1437   const char *tname;
1438   const char *addr;
1439   size_t addrlen;
1440   size_t slen;
1441   size_t size;
1442   struct GNUNET_HELLO_Message *hello;
1443   struct GNUNET_HELLO_Address address;
1444   int sig_res;
1445   int do_verify;
1446
1447   if (0 ==
1448       memcmp (&GST_my_identity,
1449               sender,
1450               sizeof (struct GNUNET_PeerIdentity)))
1451     return GNUNET_OK; /* our own, ignore! */
1452
1453   if (ntohs (hdr->size) < sizeof (struct TransportPongMessage))
1454   {
1455     GNUNET_break_op (0);
1456     return GNUNET_SYSERR;
1457   }
1458   GNUNET_STATISTICS_update (GST_stats,
1459                             gettext_noop ("# PONG messages received"), 1,
1460                             GNUNET_NO);
1461
1462   /* message with structure:
1463    * [TransportPongMessage][Transport name][Address] */
1464
1465   pong = (const struct TransportPongMessage *) hdr;
1466   tname = (const char *) &pong[1];
1467   size = ntohs (hdr->size) - sizeof (struct TransportPongMessage);
1468   addr = memchr (tname, '\0', size);
1469   if (NULL == addr)
1470   {
1471     GNUNET_break_op (0);
1472     return GNUNET_SYSERR;
1473   }
1474   addr++;
1475   slen = strlen (tname) + 1;
1476   addrlen = size - slen;
1477
1478   if (NULL == GST_plugins_find (tname))
1479   {
1480     /* we got the PONG, but the transport plugin specified in it
1481        is not supported by this peer, so this cannot be a good
1482        PONG for us. */
1483     GNUNET_break_op (0);
1484     return GNUNET_OK;
1485   }
1486
1487   address.peer = *sender;
1488   address.address = addr;
1489   address.address_length = addrlen;
1490   address.transport_name = tname;
1491   address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
1492   ve = find_validation_entry (&address);
1493   if ((NULL == ve) || (GNUNET_NO == ve->expecting_pong))
1494   {
1495     GNUNET_STATISTICS_update (GST_stats,
1496                               gettext_noop
1497                               ("# PONGs dropped, no matching pending validation"),
1498                               1, GNUNET_NO);
1499     return GNUNET_OK;
1500   }
1501   /* now check that PONG is well-formed */
1502   if (0 != memcmp (&ve->address->peer,
1503                    sender,
1504                    sizeof (struct GNUNET_PeerIdentity)))
1505   {
1506     GNUNET_break_op (0);
1507     return GNUNET_SYSERR;
1508   }
1509   if (0 ==
1510       GNUNET_TIME_absolute_get_remaining
1511       (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value_us)
1512   {
1513     GNUNET_STATISTICS_update (GST_stats,
1514                               gettext_noop
1515                               ("# PONGs dropped, signature expired"), 1,
1516                               GNUNET_NO);
1517     return GNUNET_SYSERR;
1518   }
1519
1520   sig_res = GNUNET_SYSERR;
1521   do_verify = GNUNET_YES;
1522   if (0 != GNUNET_TIME_absolute_get_remaining (ve->pong_sig_valid_until).rel_value_us)
1523   {
1524     /* We have a cached and valid signature for this peer,
1525      * try to compare instead of verify */
1526     if (0 == memcmp (&ve->pong_sig_cache,
1527                      &pong->signature,
1528                      sizeof (struct GNUNET_CRYPTO_EddsaSignature)))
1529     {
1530       /* signatures are identical, we can skip verification */
1531       sig_res = GNUNET_OK;
1532       do_verify = GNUNET_NO;
1533     }
1534     else
1535     {
1536       sig_res = GNUNET_SYSERR;
1537       /* signatures do not match, we have to verify */
1538     }
1539   }
1540
1541   if (GNUNET_YES == do_verify)
1542   {
1543     /* Do expensive verification */
1544     sig_res = GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
1545                                           &pong->purpose,
1546                                           &pong->signature,
1547                                           &ve->address->peer.public_key);
1548     if (sig_res == GNUNET_SYSERR)
1549     {
1550       GNUNET_break_op (0);
1551       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1552                   "Failed to verify: invalid signature on address `%s':%s from peer `%s'\n",
1553                   tname,
1554                   GST_plugins_a2s (ve->address),
1555                   GNUNET_i2s (sender));
1556     }
1557   }
1558   if (sig_res == GNUNET_SYSERR)
1559   {
1560     GNUNET_break_op (0);
1561     return GNUNET_SYSERR;
1562   }
1563
1564   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1565               "Validation process successful for peer `%s' with plugin `%s' address `%s'\n",
1566               GNUNET_i2s (sender),
1567               tname,
1568               GST_plugins_a2s (ve->address));
1569   GNUNET_STATISTICS_update (GST_stats,
1570                             gettext_noop ("# validations succeeded"),
1571                             1,
1572                             GNUNET_NO);
1573   /* validity achieved, remember it! */
1574   ve->expecting_pong = GNUNET_NO;
1575   ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1576   ve->pong_sig_cache = pong->signature;
1577   ve->pong_sig_valid_until = GNUNET_TIME_absolute_ntoh (pong->expiration);
1578   ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
1579   {
1580     if (GNUNET_YES == ve->known_to_ats)
1581     {
1582       GNUNET_assert (GNUNET_YES ==
1583                      GST_ats_is_known_no_session (ve->address));
1584       GST_ats_update_delay (ve->address,
1585                             GNUNET_TIME_relative_divide (ve->latency, 2));
1586     }
1587     else
1588     {
1589       struct GNUNET_ATS_Properties prop;
1590
1591       memset (&prop, 0, sizeof (prop));
1592       GNUNET_break (GNUNET_NT_UNSPECIFIED != ve->network);
1593       prop.scope = ve->network;
1594       prop.delay = GNUNET_TIME_relative_divide (ve->latency, 2);
1595       GNUNET_assert (GNUNET_NO ==
1596                      GST_ats_is_known_no_session (ve->address));
1597       ve->known_to_ats = GNUNET_YES;
1598       GST_ats_add_address (ve->address, &prop);
1599       GNUNET_assert (GNUNET_YES ==
1600                      GST_ats_is_known_no_session (ve->address));
1601     }
1602   }
1603   if (validations_running > 0)
1604   {
1605     validations_running--;
1606     GNUNET_STATISTICS_set (GST_stats,
1607                            gettext_noop ("# validations running"),
1608                            validations_running,
1609                            GNUNET_NO);
1610     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1611                 "Validation finished, %u validation processes running\n",
1612                 validations_running);
1613   }
1614   else
1615   {
1616     GNUNET_break (0);
1617   }
1618
1619   /* Notify about new validity */
1620   validation_entry_changed (ve,
1621                             GNUNET_TRANSPORT_VS_UPDATE);
1622
1623   /* build HELLO to store in PEERINFO */
1624   GNUNET_STATISTICS_update (GST_stats,
1625                             gettext_noop ("# HELLOs given to peerinfo"),
1626                             1,
1627                             GNUNET_NO);
1628   ve->copied = GNUNET_NO;
1629   hello = GNUNET_HELLO_create (&ve->address->peer.public_key,
1630                                &add_valid_peer_address,
1631                                ve,
1632                                GNUNET_NO);
1633   GNUNET_break (NULL !=
1634                 GNUNET_PEERINFO_add_peer (GST_peerinfo,
1635                                           hello,
1636                                           NULL,
1637                                           NULL));
1638   GNUNET_free (hello);
1639   return GNUNET_OK;
1640 }
1641
1642
1643 /**
1644  * We've received a HELLO, check which addresses are new and trigger
1645  * validation.
1646  *
1647  * @param hello the HELLO we received
1648  * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
1649  */
1650 int
1651 GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
1652 {
1653   const struct GNUNET_HELLO_Message *hm =
1654       (const struct GNUNET_HELLO_Message *) hello;
1655   struct GNUNET_PeerIdentity pid;
1656   int friend;
1657
1658   friend = GNUNET_HELLO_is_friend_only (hm);
1659   if ( ( (GNUNET_YES != friend) &&
1660          (GNUNET_NO != friend) ) ||
1661        (GNUNET_OK != GNUNET_HELLO_get_id (hm, &pid)) )
1662   {
1663     /* malformed HELLO */
1664     GNUNET_break_op (0);
1665     return GNUNET_SYSERR;
1666   }
1667   if (0 ==
1668       memcmp (&GST_my_identity,
1669               &pid,
1670               sizeof (struct GNUNET_PeerIdentity)))
1671   {
1672     /* got our own HELLO, how boring */
1673     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1674                 "Validation received our own HELLO (%s), ignoring\n",
1675                 GNUNET_i2s (&pid));
1676     return GNUNET_OK;
1677   }
1678   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1679               "Validation received HELLO message for peer `%s' with size %u, checking for new addresses\n",
1680               GNUNET_i2s (&pid),
1681               ntohs (hello->size));
1682   GNUNET_assert (NULL ==
1683                  GNUNET_HELLO_iterate_addresses (hm,
1684                                                  GNUNET_NO,
1685                                                  &validate_address_iterator,
1686                                                  NULL));
1687   return GNUNET_OK;
1688 }
1689
1690
1691 /**
1692  * Closure for #iterate_addresses().
1693  */
1694 struct IteratorContext
1695 {
1696   /**
1697    * Function to call on each address.
1698    */
1699   GST_ValidationAddressCallback cb;
1700
1701   /**
1702    * Closure for @e cb.
1703    */
1704   void *cb_cls;
1705
1706 };
1707
1708
1709 /**
1710  * Call the callback in the closure for each validation entry.
1711  *
1712  * @param cls the `struct IteratorContext`
1713  * @param key the peer's identity
1714  * @param value the `struct ValidationEntry`
1715  * @return #GNUNET_OK (continue to iterate)
1716  */
1717 static int
1718 iterate_addresses (void *cls,
1719                    const struct GNUNET_PeerIdentity *key,
1720                    void *value)
1721 {
1722   struct IteratorContext *ic = cls;
1723   struct ValidationEntry *ve = value;
1724
1725   ic->cb (ic->cb_cls,
1726           ve->valid_until,
1727           ve->revalidation_block,
1728           ve->address);
1729   return GNUNET_OK;
1730 }
1731
1732
1733 /**
1734  * Call the given function for each address for the given target.
1735  * Can either give a snapshot (synchronous API) or be continuous.
1736  *
1737  * @param target peer information is requested for
1738  * @param cb function to call; will not be called after this function returns
1739  * @param cb_cls closure for @a cb
1740  */
1741 void
1742 GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target,
1743                               GST_ValidationAddressCallback cb,
1744                               void *cb_cls)
1745 {
1746   struct IteratorContext ic;
1747
1748   ic.cb = cb;
1749   ic.cb_cls = cb_cls;
1750   GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
1751                                               target,
1752                                               &iterate_addresses, &ic);
1753 }
1754
1755
1756 /**
1757  * Update if we are using an address for a connection actively right now.
1758  * Based on this, the validation module will measure latency for the
1759  * address more or less often.
1760  *
1761  * @param address the address that we are now using (or not)
1762  * @param in_use #GNUNET_YES if we are now using the address for a connection,
1763  *               #GNUNET_NO if we are no longer using the address for a connection
1764  */
1765 void
1766 GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address,
1767                                 int in_use)
1768 {
1769   struct ValidationEntry *ve;
1770
1771   if (GNUNET_HELLO_address_check_option (address,
1772                                          GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1773     return; /* ignore inbound for validation */
1774   if (NULL == GST_plugins_find (address->transport_name))
1775   {
1776     /* How can we use an address for which we don't have the plugin? */
1777     GNUNET_break (0);
1778     return;
1779   }
1780   ve = find_validation_entry (address);
1781   if (NULL == ve)
1782   {
1783     GNUNET_break (0);
1784     return;
1785   }
1786   if (in_use == ve->in_use)
1787     return;
1788   ve->in_use = in_use;
1789   if (GNUNET_YES == in_use)
1790   {
1791     /* from now on, higher frequeny, so reschedule now */
1792     if (NULL != ve->revalidation_task)
1793       GNUNET_SCHEDULER_cancel (ve->revalidation_task);
1794     ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address,
1795                                                       ve);
1796   }
1797 }
1798
1799
1800 /* end of file gnunet-service-transport_validation.c */