📄 advertising.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file advertising/advertising.c * @brief Cron-jobs that exchange hellos to ensure that the network is * connected (nodes know of each other). This is implemented as * an application and not a service (since no API is provided for * clients to call on -- this just happens in the background). * * Nevertheless, every GNUnet peer should probably run advertising * at the moment. * * @author Christian Grothoff */#include "platform.h"#include "gnunet_util.h"#include "gnunet_protocols.h"#include "gnunet_identity_service.h"#include "gnunet_transport_service.h"#include "gnunet_pingpong_service.h"#include "gnunet_stats_service.h"#include "gnunet_topology_service.h"#include "bootstrap.h"/** * Send our hello to a random connected host on a regular basis. */#define HELLO_BROADCAST_FREQUENCY (2 * GNUNET_CRON_MINUTES)/** * From time to time, forward one hello from one peer to * a random other peer. */#define HELLO_FORWARD_FREQUENCY (45 * GNUNET_CRON_SECONDS)/** * Meanings of the bits in activeCronJobs (ACJ). */#define ACJ_NONE 0#define ACJ_ANNOUNCE 1#define ACJ_FORWARD 2#define ACJ_ALL (ACJ_ANNOUNCE | ACJ_FORWARD)#define DEBUG_ADVERTISING GNUNET_NOstatic GNUNET_CoreAPIForPlugins *coreAPI;static GNUNET_Transport_ServiceAPI *transport;static GNUNET_Identity_ServiceAPI *identity;static GNUNET_Pingpong_ServiceAPI *pingpong;static GNUNET_Topology_ServiceAPI *topology;static GNUNET_Stats_ServiceAPI *stats;static struct GNUNET_GE_Context *ectx;static int stat_hello_in;static int stat_hello_nat_in;static int stat_hello_verified;static int stat_hello_update;static int stat_hello_discard;static int stat_hello_no_transport;static int stat_hello_ping_busy;static int stat_hello_noselfad;static int stat_hello_send_error;static int stat_hello_out;static int stat_hello_fwd;static int stat_plaintextPingSent;/** * Which types of cron-jobs are currently scheduled * with cron? */static int activeCronJobs = ACJ_NONE;static GNUNET_CronTime lasthelloMsg = 0;static doublegetConnectPriority (){ double preference; /* we should'nt give lots of bandwidth for hellos if we're close to the connection goal */ preference = topology->getSaturation (); if (preference <= 0.0001) preference = 0xFFFF; else preference = 1 / preference; /* always give some decent, but compared to (migrated) content competitive amount of bandwidth to peers sending (valid) hellos */ if (preference < 0.2) preference = 0.2; return preference;}static voidcallAddHost (void *cls){ GNUNET_MessageHello *hello = cls; if (stats != NULL) stats->change (stat_hello_verified, 1); identity->addHost (hello); GNUNET_free (hello);}/** * We have received a hello. Verify (signature, integrity, * ping-pong) and store identity if ok. * * @param message the hello message * @return GNUNET_SYSERR on error, GNUNET_OK on success */static intreceivedhello (const GNUNET_PeerIdentity * sender, const GNUNET_MessageHeader * message){ GNUNET_TSession *tsession; GNUNET_MessageHello *copy; GNUNET_PeerIdentity foreignId; const GNUNET_MessageHello *msg; GNUNET_MessageHeader *ping; char *buffer; int helloEnd; int mtu; int res; GNUNET_CronTime now; GNUNET_EncName enc; /* first verify that it is actually a valid hello */ msg = (const GNUNET_MessageHello *) message; if ((ntohs (msg->header.size) < sizeof (GNUNET_MessageHello)) || (ntohs (msg->header.size) != GNUNET_sizeof_hello (msg))) { GNUNET_GE_BREAK_OP (ectx, 0); return GNUNET_SYSERR; } identity->getPeerIdentity (&msg->publicKey, &foreignId); if (0 != memcmp (&msg->senderIdentity.hashPubKey, &foreignId.hashPubKey, sizeof (GNUNET_HashCode))) { GNUNET_GE_BREAK_OP (ectx, 0); return GNUNET_SYSERR; /* public key and host GNUNET_hash do not match */ } if (GNUNET_SYSERR == GNUNET_RSA_verify (&msg->senderIdentity, GNUNET_sizeof_hello (msg) - sizeof (GNUNET_RSA_Signature) - sizeof (GNUNET_RSA_PublicKey) - sizeof (GNUNET_MessageHeader), &msg->signature, &msg->publicKey)) { IF_GELOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER, GNUNET_hash_to_enc (&msg->senderIdentity.hashPubKey, &enc)); GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER, _ ("HELLO message from `%s' has an invalid signature. Dropping.\n"), (char *) &enc); GNUNET_GE_BREAK_OP (ectx, 0); return GNUNET_SYSERR; /* message invalid */ } if ((GNUNET_Int32Time) ntohl (msg->expiration_time) > GNUNET_get_time_int32 (NULL) + GNUNET_MAX_HELLO_EXPIRES) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER, _ ("HELLO message has expiration too far in the future. Dropping.\n")); GNUNET_GE_BREAK_OP (ectx, 0); return GNUNET_SYSERR; } if (GNUNET_SYSERR == transport->hello_verify (msg)) {#if DEBUG_ADVERTISING IF_GELOG (ectx, GNUNET_GE_INFO | GNUNET_GE_BULK | GNUNET_GE_USER, GNUNET_hash_to_enc (&msg->senderIdentity.hashPubKey, &enc)); GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_BULK | GNUNET_GE_USER, "Transport verification of HELLO message from `%s' failed (%u).\n", &enc, ntohs (msg->protocol));#endif return GNUNET_OK; /* not good, but do process rest of message */ } if (stats != NULL) stats->change (stat_hello_in, 1);#if DEBUG_ADVERTISING IF_GELOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_USER, GNUNET_hash_to_enc (&msg->senderIdentity.hashPubKey, &enc)); GNUNET_GE_LOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_USER, "HELLO advertisement from `%s' for protocol %d received.\n", &enc, ntohs (msg->protocol));#endif if (ntohs (msg->protocol) == GNUNET_TRANSPORT_PROTOCOL_NUMBER_NAT) { /* We *can* not verify NAT. Ever. So all we can do is just accept it. The best thing that we may do is check that it was not forwarded by another peer (forwarding NAT advertisements is invalid), but even that check can not be done securely (since we have to accept hellos in plaintext). Thus we take NAT advertisements at face value (which is GNUNET_OK since we never attempt to connect to a NAT). */ identity->addHost (msg); if (stats != NULL) stats->change (stat_hello_nat_in, 1);#if DEBUG_ADVERTISING IF_GELOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_USER, GNUNET_hash_to_enc (&msg->senderIdentity.hashPubKey, &enc)); GNUNET_GE_LOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_USER, "HELLO advertisement from `%s' for NAT, no verification required.\n", &enc);#endif return GNUNET_OK; } /* Then check if we have seen this hello before, if it is identical except for the TTL, we trust it and do not play PING-PONG */ copy = identity->identity2Hello (&foreignId, ntohs (msg->protocol), GNUNET_NO); if (NULL != copy) { if ((ntohs (copy->senderAddressSize) == ntohs (msg->senderAddressSize)) && (0 == memcmp (&msg->MTU, ©->MTU, sizeof (unsigned short) * 2 + sizeof (unsigned int) + ntohs (copy->senderAddressSize)))) { /* ok, we've seen this one exactly like this before (at most the TTL has changed); thus we can 'trust' it without playing ping-pong */ identity->addHost (msg); if (stats != NULL) stats->change (stat_hello_update, 1); GNUNET_free (copy);#if DEBUG_ADVERTISING IF_GELOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_USER, GNUNET_hash_to_enc (&msg->senderIdentity.hashPubKey, &enc)); GNUNET_GE_LOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_USER, "HELLO advertisement from `%s' for protocol %d updates old advertisement, no verification required.\n", &enc, ntohs (msg->protocol));#endif return GNUNET_OK; }#if DEBUG_ADVERTISING GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "HELLO advertisement differs from prior knowledge," " requireing ping-pong confirmation.\n");#endif GNUNET_free (copy); } if (GNUNET_YES == GNUNET_GC_get_configuration_value_yesno (coreAPI->cfg, "GNUNETD", "PRIVATE-NETWORK", GNUNET_NO)) { /* the option 'PRIVATE-NETWORK' can be used to limit the connections of this peer to peers of which the hostkey has been copied by hand to data/hosts; if this option is given, GNUnet will not accept advertisements of peers that the local node does not already know about. Note that in order for this option to work, HOSTLISTURL should either not be set at all or be set to a trusted peer that only advertises the private network. Also, the option does NOT work at the moment if the NAT transport is loaded; for that, a couple of lines above would need some minor editing :-). */#if DEBUG_ADVERTISING GNUNET_GE_LOG (ectx, GNUNET_GE_INFO | GNUNET_GE_BULK | GNUNET_GE_USER, "Private network, discarding unknown advertisements\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -