📄 identity.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 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 identity/identity.c * @brief maintains list of known peers * * Code to maintain the list of currently known hosts (in memory * structure of data/hosts) and (temporary) blacklisting information * and a list of hellos that are temporary unless confirmed via PONG * (used to give the transport module the required information for the * PING). * * @author Christian Grothoff */#include "platform.h"#include "gnunet_util.h"#include "gnunet_protocols.h"#include "gnunet_directories.h"#include "gnunet_identity_service.h"#include "gnunet_transport_service.h"#include "identity.h"#include "hostkey.h"#define DEBUG_IDENTITY GNUNET_NO#define MAX_TEMP_HOSTS 32#define TRUSTDIR "data/credit/"#define HOST_DIR "data/hosts/"/** * Masks to keep track when the trust has changed and * to get the real trust value. */#define TRUST_REFRESH_MASK 0x80000000#define TRUST_ACTUAL_MASK 0x7FFFFFFF#define MAX_DATA_HOST_FREQ (5 * GNUNET_CRON_MINUTES)#define CRON_DATA_HOST_FREQ (15 * GNUNET_CRON_MINUTES)#define CRON_TRUST_FLUSH_FREQ (5 * GNUNET_CRON_MINUTES)#define CRON_DISCARD_HOSTS_INTERVAL (GNUNET_CRON_DAYS)#define CRON_DISCARDS_HOSTS_AFTER (3 * GNUNET_CRON_MONTHS)typedef struct{ GNUNET_PeerIdentity identity; /** * How long is this host blacklisted? (if at all) */ GNUNET_CronTime until; /** * what would be the next increment for blacklisting? */ GNUNET_CronTime delta; /** * hellos for the peer (maybe NULL)! */ GNUNET_MessageHello **hellos; unsigned int helloCount; /** * for which protocols is this host known? */ unsigned short *protocols; unsigned int protocolCount; /** * should we also reject incoming messages? (GNUNET_YES/GNUNET_NO) */ int strict; /** * trust rating for this peer */ unsigned int trust;} HostEntry;/** * The list of known hosts. */static HostEntry **hosts_ = NULL;/** * The current (allocated) size of knownHosts */static unsigned int sizeOfHosts_ = 0;/** * The number of actual entries in knownHosts */static unsigned int numberOfHosts_;/** * A lock for accessing knownHosts */static struct GNUNET_Mutex *lock_;/** * Directory where the hellos are stored in (data/hosts) */static char *networkIdDirectory;/** * Where do we store trust information? */static char *trustDirectory;/** * The list of temporarily known hosts */static HostEntry tempHosts[MAX_TEMP_HOSTS];static GNUNET_PeerIdentity myIdentity;static struct GNUNET_GE_Context *ectx;static GNUNET_CoreAPIForPlugins *coreAPI;/** * Get the filename under which we would store the GNUNET_MessageHello * for the given host and protocol. * @return filename of the form DIRECTORY/HOSTID.PROTOCOL */static char *getHostFileName (const GNUNET_PeerIdentity * id, unsigned short protocol){ GNUNET_EncName fil; char *fn; size_t n; GNUNET_hash_to_enc (&id->hashPubKey, &fil); n = strlen (networkIdDirectory) + sizeof (GNUNET_EncName) + 1 + 5 + 1; fn = GNUNET_malloc (n); GNUNET_snprintf (fn, n, "%s%s.%u", networkIdDirectory, (char *) &fil, protocol); return fn;}/** * Find the host entry for the given peer. Call * only when synchronized! * @return NULL if not found */static HostEntry *findHost (const GNUNET_PeerIdentity * id){ int i; GNUNET_GE_ASSERT (ectx, numberOfHosts_ <= sizeOfHosts_); for (i = 0; i < numberOfHosts_; i++) if ((0 == memcmp (id, &hosts_[i]->identity, sizeof (GNUNET_PeerIdentity)))) return hosts_[i]; return NULL;}/** * Add a host to the list. * * @param identity the identity of the host * @param protocol the protocol for the host */static voidaddHostToKnown (const GNUNET_PeerIdentity * identity, unsigned short protocol){ HostEntry *entry; int i; GNUNET_EncName fil; char *fn; unsigned int trust; GNUNET_GE_ASSERT (ectx, numberOfHosts_ <= sizeOfHosts_); GNUNET_mutex_lock (lock_); entry = findHost (identity); if (entry == NULL) { entry = GNUNET_malloc (sizeof (HostEntry)); entry->identity = *identity; entry->until = 0; entry->delta = 30 * GNUNET_CRON_SECONDS; entry->protocols = NULL; entry->protocolCount = 0; entry->strict = GNUNET_NO; entry->hellos = NULL; entry->helloCount = 0; GNUNET_hash_to_enc (&identity->hashPubKey, &fil); fn = GNUNET_malloc (strlen (trustDirectory) + sizeof (GNUNET_EncName) + 1); strcpy (fn, trustDirectory); strcat (fn, (char *) &fil); if ((GNUNET_disk_file_test (ectx, fn) == GNUNET_YES) && (sizeof (unsigned int) == GNUNET_disk_file_read (ectx, fn, sizeof (unsigned int), &trust))) { entry->trust = ntohl (trust); } else { entry->trust = 0; } GNUNET_free (fn); if (numberOfHosts_ == sizeOfHosts_) GNUNET_array_grow (hosts_, sizeOfHosts_, sizeOfHosts_ + 32); hosts_[numberOfHosts_++] = entry; } for (i = 0; i < entry->protocolCount; i++) { if (entry->protocols[i] == protocol) { GNUNET_mutex_unlock (lock_); return; /* already there */ } } GNUNET_array_grow (entry->protocols, entry->protocolCount, entry->protocolCount + 1); entry->protocols[entry->protocolCount - 1] = protocol; GNUNET_mutex_unlock (lock_);}/** * Increase the host credit by a value. * * @param hostId is the identity of the host * @param value is the int value by which the * host credit is to be increased or decreased * @returns the actual change in trust (positive or negative) */static intchangeHostTrust (const GNUNET_PeerIdentity * hostId, int value){ HostEntry *host; if (value == 0) return 0; GNUNET_mutex_lock (lock_); host = findHost (hostId); if (host == NULL) { addHostToKnown (hostId, GNUNET_TRANSPORT_PROTOCOL_NUMBER_NAT); host = findHost (hostId); if (host == NULL) { GNUNET_GE_BREAK (ectx, 0); GNUNET_mutex_unlock (lock_); return 0; } } if (((int) (host->trust & TRUST_ACTUAL_MASK)) + value < 0) { value = -(host->trust & TRUST_ACTUAL_MASK); host->trust = 0 | TRUST_REFRESH_MASK; /* 0 remaining */ } else { host->trust = ((host->trust & TRUST_ACTUAL_MASK) + value) | TRUST_REFRESH_MASK; } GNUNET_mutex_unlock (lock_); return value;}/** * Obtain the trust record of a peer. * * @param hostId the identity of the peer * @return the amount of trust we currently have in that peer */static unsigned intgetHostTrust (const GNUNET_PeerIdentity * hostId){ HostEntry *host; unsigned int trust; GNUNET_mutex_lock (lock_); host = findHost (hostId); if (host == NULL) trust = 0; else trust = host->trust & TRUST_ACTUAL_MASK; GNUNET_mutex_unlock (lock_); return trust;}static intcronHelper (const char *filename, const char *dirname, void *unused){ GNUNET_PeerIdentity identity; GNUNET_EncName id; unsigned int protoNumber; char *fullname; GNUNET_GE_ASSERT (ectx, numberOfHosts_ <= sizeOfHosts_); GNUNET_GE_ASSERT (ectx, sizeof (GNUNET_EncName) == 104); if (2 == sscanf (filename, "%103c.%u", (char *) &id, &protoNumber)) { id.encoding[sizeof (GNUNET_EncName) - 1] = '\0'; if (GNUNET_OK == GNUNET_enc_to_hash ((char *) &id, &identity.hashPubKey)) { addHostToKnown (&identity, (unsigned short) protoNumber); return GNUNET_OK; } } fullname = GNUNET_malloc (strlen (filename) + strlen (networkIdDirectory) + 1); strcpy (fullname, networkIdDirectory); strcat (fullname, filename); if (GNUNET_disk_file_test (ectx, fullname) == GNUNET_YES) { if (0 == UNLINK (fullname)) GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _ ("File `%s' in directory `%s' does not match naming convention. " "Removed.\n"), filename, networkIdDirectory); else GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_BULK, "unlink", fullname); } else if (GNUNET_disk_directory_test (ectx, fullname) == GNUNET_YES) { if (0 == RMDIR (fullname)) GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _ ("Directory `%s' in directory `%s' does not match naming convention. " "Removed.\n"), filename, networkIdDirectory); else GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_BULK, "rmdir", fullname); } GNUNET_free (fullname); return GNUNET_OK;}/** * Call this method periodically to scan data/hosts for new hosts. */static voidcronScanDirectoryDataHosts (void *unused){ static GNUNET_CronTime lastRun; static int retries; int count; GNUNET_CronTime now; now = GNUNET_get_time (); if (lastRun + MAX_DATA_HOST_FREQ > now) return; /* prevent scanning more than once every 5 min */ lastRun = now; count = GNUNET_disk_directory_scan (ectx, networkIdDirectory, &cronHelper, NULL); if (count <= 0) { retries++; if ((retries & 32) > 0) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK, _("Still no peers found in `%s'!\n"), networkIdDirectory); } } GNUNET_GE_ASSERT (ectx, numberOfHosts_ <= sizeOfHosts_);}/** * Obtain identity from publicPrivateKey. * @param pubKey the public key of the host * @param result address where to write the identity of the node */static voidgetPeerIdentity (const GNUNET_RSA_PublicKey * pubKey, GNUNET_PeerIdentity * result){ if (pubKey == NULL) { memset (&result, 0, sizeof (GNUNET_PeerIdentity)); } else { GNUNET_hash (pubKey, sizeof (GNUNET_RSA_PublicKey), &result->hashPubKey); }}/** * Add a host to the temporary list. */static voidaddHostTemporarily (const GNUNET_MessageHello * tmp){ static int tempHostsNextSlot; GNUNET_MessageHello *msg; HostEntry *entry; int i; int slot; GNUNET_PeerIdentity have; getPeerIdentity (&tmp->publicKey, &have); if (0 != memcmp (&have, &tmp->senderIdentity, sizeof (GNUNET_PeerIdentity))) { GNUNET_GE_BREAK (NULL, 0); return; } GNUNET_mutex_lock (lock_); entry = findHost (&tmp->senderIdentity); if ((entry != NULL) && (entry->helloCount > 0)) { GNUNET_mutex_unlock (lock_); return; } msg = GNUNET_malloc (GNUNET_sizeof_hello (tmp)); memcpy (msg, tmp, GNUNET_sizeof_hello (tmp)); slot = tempHostsNextSlot; for (i = 0; i < MAX_TEMP_HOSTS; i++) if (0 == memcmp (&tmp->senderIdentity, &tempHosts[i].identity, sizeof (GNUNET_PeerIdentity))) slot = i; if (slot == tempHostsNextSlot) { tempHostsNextSlot++; if (tempHostsNextSlot >= MAX_TEMP_HOSTS) tempHostsNextSlot = 0; } entry = &tempHosts[slot]; entry->identity = msg->senderIdentity; entry->until = 0; entry->delta = 0; for (i = 0; i < entry->helloCount; i++) GNUNET_free (entry->hellos[i]); GNUNET_array_grow (entry->hellos, entry->helloCount, 1); GNUNET_array_grow (entry->protocols, entry->protocolCount, 1); entry->hellos[0] = msg; entry->protocols[0] = ntohs (msg->protocol); entry->strict = GNUNET_NO; entry->trust = 0; GNUNET_mutex_unlock (lock_);}/** * Delete a host from the list. */static voiddelHostFromKnown (const GNUNET_PeerIdentity * identity, unsigned short protocol){ HostEntry *entry; char *fn; int i; int j; GNUNET_GE_ASSERT (ectx, numberOfHosts_ <= sizeOfHosts_); GNUNET_GE_ASSERT (ectx, protocol != GNUNET_TRANSPORT_PROTOCOL_NUMBER_ANY); GNUNET_mutex_lock (lock_); for (i = 0; i < numberOfHosts_; i++) { if ((0 == memcmp (identity,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -