/** * Iterator which adds the given address to the set of validated * addresses. * * @param cls original HELLO message * @param address the address * @param expiration expiration time * @return GNUNET_OK (keep the address) */ static int add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { const struct GNUNET_HELLO_Message *hello = cls; struct ValidationEntry *ve; struct GNUNET_PeerIdentity pid; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) return GNUNET_OK; /* expired */ if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) || (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key))) { GNUNET_break (0); return GNUNET_OK; /* invalid HELLO !? */ } if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) { /* Peerinfo returned own identity, skip validation */ return GNUNET_OK; } ve = find_validation_entry (&public_key, address); ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0); return GNUNET_OK; }
/** * We've received a HELLO, check which addresses are new and trigger * validation. * * @param hello the HELLO we received */ void GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) { const struct GNUNET_HELLO_Message *hm = (const struct GNUNET_HELLO_Message *) hello; struct ValidateAddressContext vac; struct GNUNET_HELLO_Message *h; if ((GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) || (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key))) { /* malformed HELLO */ GNUNET_break (0); return; } if (0 == memcmp (&GST_my_identity, &vac.pid, sizeof (struct GNUNET_PeerIdentity))) return; /* Add peer identity without addresses to peerinfo service */ h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL); GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL); #if VERBOSE_VALIDATION GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Adding `%s' without addresses for peer `%s'\n"), "HELLO", GNUNET_i2s (&vac.pid)); #endif GNUNET_free (h); GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, &validate_address_iterator, &vac)); }
/** * We've gotten a HELLO from another peer. Consider it for * advertising. * * @param hello the HELLO we got */ static void consider_for_advertising (const struct GNUNET_HELLO_Message *hello) { int have_address; struct GNUNET_PeerIdentity pid; struct GNUNET_TIME_Absolute dt; struct GNUNET_HELLO_Message *nh; struct Peer *peer; uint16_t size; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { GNUNET_break (0); return; } if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity))) return; /* that's me! */ have_address = GNUNET_NO; GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator, &have_address); if (GNUNET_NO == have_address) return; /* no point in advertising this one... */ peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); if (NULL == peer) { peer = make_peer (&pid, hello, GNUNET_NO); } else if (peer->hello != NULL) { dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ()); if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) return; /* nothing new here */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' from peer `%s' for advertising\n", "HELLO", GNUNET_i2s (&pid)); if (peer->hello != NULL) { nh = GNUNET_HELLO_merge (peer->hello, hello); GNUNET_free (peer->hello); peer->hello = nh; } else { size = GNUNET_HELLO_size (hello); peer->hello = GNUNET_malloc (size); memcpy (peer->hello, hello, size); } if (peer->filter != NULL) GNUNET_CONTAINER_bloomfilter_free (peer->filter); setup_filter (peer); /* since we have a new HELLO to pick from, re-schedule all * HELLO requests that are not bound by the HELLO send rate! */ GNUNET_CONTAINER_multihashmap_iterate (peers, &reschedule_hellos, peer); }
/** * Function that is called on each HELLO file in a particular directory. * Try to parse the file and add the HELLO to our list. * * @param cls pointer to 'unsigned int' to increment for each file, or NULL * if the file is from a read-only, read-once resource directory * @param fullname name of the file to parse * @return GNUNET_OK (continue iteration) */ static int hosts_directory_scan_callback (void *cls, const char *fullname) { unsigned int *matched = cls; struct GNUNET_PeerIdentity identity; const char *filename; struct HostEntry *entry; struct GNUNET_HELLO_Message *hello; if (GNUNET_DISK_file_test (fullname) != GNUNET_YES) return GNUNET_OK; /* ignore non-files */ if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) { if (NULL != matched) remove_garbage (fullname); return GNUNET_OK; } filename = &fullname[strlen (fullname) - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1]; if (filename[-1] != DIR_SEPARATOR) { if (NULL != matched) remove_garbage (fullname); return GNUNET_OK; } if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (filename, &identity.hashPubKey)) { if (NULL != (hello = read_host_file (filename))) { entry = GNUNET_malloc (sizeof (struct HostEntry)); if (GNUNET_OK == GNUNET_HELLO_get_id (hello, &entry->identity)) { GNUNET_CONTAINER_multihashmap_put (hostmap, &entry->identity.hashPubKey, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); entry->hello = hello; notify_all (entry); return GNUNET_OK; } GNUNET_free (entry); } if (NULL != matched) remove_garbage (fullname); return GNUNET_OK; } if (NULL != matched) (*matched)++; add_host_to_known_hosts (&identity); return GNUNET_OK; }
/** * This function is called whenever an encrypted HELLO message is * received. * * @param cls closure with the peer identity of the sender * @param message the actual HELLO message * @return #GNUNET_OK if @a message is well-formed * #GNUNET_SYSERR if @a message is invalid */ static int check_hello (void *cls, const struct GNUNET_HELLO_Message *message) { struct GNUNET_PeerIdentity pid; if (GNUNET_OK != GNUNET_HELLO_get_id (message, &pid)) { GNUNET_break_op (0); return GNUNET_SYSERR; } return GNUNET_OK; }
/** * Handle HELLO-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_hello (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity pid; hello = (const struct GNUNET_HELLO_Message *) message; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n", "HELLO", GNUNET_i2s (&pid)); bind_address (&pid, hello); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
/** * This function is called whenever an encrypted HELLO message is * received. * * @param cls closure with the peer identity of the sender * @param message the actual HELLO message */ static void handle_hello (void *cls, const struct GNUNET_HELLO_Message *message) { const struct GNUNET_PeerIdentity *other = cls; struct Peer *peer; struct GNUNET_PeerIdentity pid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted HELLO from peer `%s'", GNUNET_i2s (other)); GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (message, &pid)); GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received"), 1, GNUNET_NO); peer = GNUNET_CONTAINER_multipeermap_get (peers, &pid); if (NULL == peer) { if ( (GNUNET_YES == friends_only) || (friend_count < minimum_friend_count) ) return; } else { if ( (GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only) ) return; if ((GNUNET_YES != peer->is_friend) && (friend_count < minimum_friend_count)) return; } if (NULL != oh) GNUNET_TRANSPORT_offer_hello_cancel (oh); oh = GNUNET_TRANSPORT_offer_hello (cfg, &message->header, &done_offer_hello, NULL); }
static void get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cb_cls; struct GNUNET_PeerIdentity hello_id; GNUNET_assert (message != NULL); GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &hello_id)); GNUNET_assert (0 == memcmp (&hello_id, &p->id, sizeof (hello_id))); GNUNET_free_non_null (p->hello); p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message); if (NULL != p->start_cb) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Peer %u (`%s') successfully started\n", p->no, GNUNET_i2s (&p->id)); p->start_cb (p, p->cb_cls); p->start_cb = NULL; } }
/** * This function is called whenever an encrypted HELLO message is * received. * * @param cls closure * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual HELLO message * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct Peer *peer; struct GNUNET_PeerIdentity pid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer `%s'", "HELLO", GNUNET_i2s (other)); if (GNUNET_OK != GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &pid)) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received"), 1, GNUNET_NO); peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); if (NULL == peer) { if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_count)) return GNUNET_OK; } else { if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only)) return GNUNET_OK; if ((GNUNET_YES != peer->is_friend) && (friend_count < minimum_friend_count)) return GNUNET_OK; } if (transport != NULL) GNUNET_TRANSPORT_offer_hello (transport, message, NULL, NULL); return GNUNET_OK; }
/** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes @a block * @param key set to the key (query) for the given block * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_dht_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, struct GNUNET_HashCode * key) { const struct GNUNET_MessageHeader *msg; const struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity *pid; if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) return GNUNET_SYSERR; if (block_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", _("Block not of type %u\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); return GNUNET_NO; } msg = block; if (block_size != ntohs (msg->size)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", _("Size mismatch for block\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); return GNUNET_NO; } hello = block; memset (key, 0, sizeof (*key)); pid = (struct GNUNET_PeerIdentity *) key; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, pid)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", _("Block of type %u is malformed\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); return GNUNET_NO; } return GNUNET_OK; }
/** * Add a host to the persistent list. This method operates in * semi-reliable mode: if the transmission is not completed by * the time 'GNUNET_PEERINFO_disconnect' is called, it will be * aborted. Furthermore, if a second HELLO is added for the * same peer before the first one was transmitted, PEERINFO may * merge the two HELLOs prior to transmission to the service. * * @param h handle to the peerinfo service * @param hello the verified (!) HELLO message * @param cont continuation to call when done, NULL is allowed * @param cont_cls closure for 'cont' * @return handle to cancel add operation; all pending * 'add' operations will be cancelled automatically * on disconnect, so it is not necessary to keep this * handle (unless 'cont' is NULL and at some point * calling 'cont' must be prevented) */ struct GNUNET_PEERINFO_AddContext * GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h, const struct GNUNET_HELLO_Message *hello, GNUNET_PEERINFO_Continuation cont, void *cont_cls) { uint16_t hs = GNUNET_HELLO_size (hello); struct GNUNET_PEERINFO_AddContext *ac; struct GNUNET_PeerIdentity peer; GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding peer `%s' to PEERINFO database (%u bytes of `%s')\n", GNUNET_i2s (&peer), hs, "HELLO"); ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + hs); ac->h = h; ac->size = hs; ac->cont = cont; ac->cont_cls = cont_cls; memcpy (&ac[1], hello, hs); GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac); trigger_transmit (h); return ac; }
/** * Type of a function to call when we receive a message from the * service. Call the iterator with the result and (if applicable) * continue to receive more messages or trigger processing the next * event (if applicable). * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_PEERINFO_Handle *h = cls; struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head; const struct InfoMessage *im; const struct GNUNET_HELLO_Message *hello; GNUNET_PEERINFO_Processor cb; struct GNUNET_PeerIdentity id; void *cb_cls; uint16_t ms; GNUNET_assert (NULL != ic); h->in_receive = GNUNET_NO; ic->in_receive = GNUNET_NO; cb = ic->callback; cb_cls = ic->callback_cls; if (NULL == msg) { /* peerinfo service died, signal error */ GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Failed to receive response from `PEERINFO' service.")); return; } if (GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END == ntohs (msg->type)) { /* normal end of list of peers, signal end, process next pending request */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of list of peers from `%s' service\n", "PEERINFO"); GNUNET_PEERINFO_iterate_cancel (ic); trigger_transmit (h); if (NULL != cb) cb (cb_cls, NULL, NULL, NULL); return; } ms = ntohs (msg->size); if ((ms < sizeof (struct InfoMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO)) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } im = (const struct InfoMessage *) msg; GNUNET_break (0 == ntohl (im->reserved)); if ( (GNUNET_YES == ic->have_peer) && (0 != memcmp (&ic->peer, &im->peer, sizeof (struct GNUNET_PeerIdentity))) ) { /* bogus message (from a different iteration call?); out of sequence! */ LOG (GNUNET_ERROR_TYPE_ERROR, "Received HELLO for peer `%s', expected peer `%s'\n", GNUNET_h2s (&im->peer.hashPubKey), GNUNET_i2s (&ic->peer)); GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } hello = NULL; if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader)) { hello = (const struct GNUNET_HELLO_Message *) &im[1]; if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello)) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &id)) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } if (0 != memcmp (&im->peer, &id, sizeof (struct GNUNET_PeerIdentity))) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } } /* normal data message */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received %u bytes of `%s' information about peer `%s' from `%s' service\n", (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello), "HELLO", GNUNET_i2s (&im->peer), "PEERINFO"); h->in_receive = GNUNET_YES; ic->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h, GNUNET_TIME_absolute_get_remaining (ic->timeout)); if (NULL != cb) cb (cb_cls, &im->peer, hello, NULL); }
/** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the @a reply_block. * * @param cls closure * @param type block type * @param eo control flags * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for @a bf * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in @a xquery * @param reply_block response to validate * @param reply_block_size number of bytes in @a reply_block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_dht_evaluate (void *cls, enum GNUNET_BLOCK_Type type, enum GNUNET_BLOCK_EvaluationOptions eo, const struct GNUNET_HashCode *query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { struct GNUNET_HashCode mhash; const struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity pid; const struct GNUNET_MessageHeader *msg; struct GNUNET_HashCode phash; if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; if (xquery_size != 0) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (reply_block_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } msg = reply_block; if (reply_block_size != ntohs (msg->size)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } hello = reply_block; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (NULL != bf) { GNUNET_CRYPTO_hash (&pid, sizeof (pid), &phash); GNUNET_BLOCK_mingle_hash (&phash, bf_mutator, &mhash); if (NULL != *bf) { if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } else { *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K); } GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); } return GNUNET_BLOCK_EVALUATION_OK_MORE; }