📄 pingpong.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2003, 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 server/pingpong.c * @brief Pings a host and triggers an action if a reply is received. * @author Christian Grothoff */#include "platform.h"#include "gnunet_util.h"#include "gnunet_protocols.h"#include "gnunet_pingpong_service.h"#include "gnunet_identity_service.h"#include "gnunet_stats_service.h"#include "gnunet_transport_service.h"/** * Ping message (test if address actually corresponds to * the advertised GNUnet host. The receiver responds with * exactly the same message, except that it is now a pong. * This message can be send in plaintext and without padding * and typically does make little sense (except keepalive) * for an encrypted (authenticated) tunnel. * <br> * There is also no proof that the other side actually * has the acclaimed identity, the only thing that is * proved is that the other side can be reached via * the underlying protocol and that it is a GNUnet node. * <br> * The challenge prevents an inept adversary from sending * us a hello and then an arbitrary PONG reply (adversary * must at least be able to sniff our outbound traffic). */typedef struct{ GNUNET_MessageHeader header; /** * Which peer is the target of the ping? This is important since for * plaintext-pings, we need to catch faulty advertisements that * advertise a correct address but with the wrong public key. */ GNUNET_PeerIdentity receiver; /** * The challenge is a (pseudo) random number that an adversary that * wants to fake a pong message would have to guess. Since even if * the number is guessed, the security impact is at most some wasted * resources, 32 bit are more than enough. */ int challenge;} P2P_pingpong_MESSAGE;#define DEBUG_PINGPONG GNUNET_NO#define MAX_PING_PONG 256typedef struct{ GNUNET_PeerIdentity receiverIdentity; int challenge; int plaintext; GNUNET_CronJob method; void *data; GNUNET_Int32Time sendTime;} PingPongEntry;static PingPongEntry *pingPongs;static struct GNUNET_Mutex *pingPongLock;static GNUNET_CoreAPIForPlugins *coreAPI;static GNUNET_Transport_ServiceAPI *transport;static GNUNET_Identity_ServiceAPI *identity;static GNUNET_Stats_ServiceAPI *stats;static struct GNUNET_GE_Context *ectx;static int stat_encryptedPongReceived;static int stat_plaintextPongReceived;static int stat_pingReceived;static int stat_pingCreated;static int stat_pongSent;static int stat_plaintextPongSent;static int stat_plaintextPongFailed;static int stat_plaintextPingSent;static int stat_ciphertextPingSent;/** * We received a PING message, send the PONG reply. */static intpingReceived (const GNUNET_PeerIdentity * sender, const GNUNET_MessageHeader * msg){ const P2P_pingpong_MESSAGE *pmsg; P2P_pingpong_MESSAGE pong; if (ntohs (msg->size) != sizeof (P2P_pingpong_MESSAGE)) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER | GNUNET_GE_DEVELOPER, _("Received malformed `%s' message. Dropping.\n"), "ping"); return GNUNET_SYSERR; } if (stats != NULL) stats->change (stat_pingReceived, 1); pmsg = (const P2P_pingpong_MESSAGE *) msg; if (0 != memcmp (coreAPI->my_identity, &pmsg->receiver, sizeof (GNUNET_PeerIdentity))) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_ADMIN, _("Received ping for another peer. Dropping.\n")); return GNUNET_SYSERR; /* not for us */ }#if DEBUG_PINGPONG GNUNET_EncName enc; GNUNET_hash_to_enc (&sender->hashPubKey, &enc); GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "Received ping from peer %s.\n", &enc);#endif pong = *pmsg; pong.header.type = htons (GNUNET_P2P_PROTO_PONG); if (stats != NULL) stats->change (stat_pingReceived, 1); coreAPI->ciphertext_send (sender, &pong.header, GNUNET_EXTREME_PRIORITY, 0); /* send now! */ if (stats != NULL) stats->change (stat_pongSent, 1); return GNUNET_OK;}static intconnection_send_plaintext (const GNUNET_PeerIdentity * peer, const P2P_pingpong_MESSAGE * msg){ GNUNET_TSession *mytsession; int ret; mytsession = transport->connect_freely (peer, GNUNET_YES, __FILE__); if (mytsession == NULL) return GNUNET_SYSERR; ret = coreAPI->plaintext_send (mytsession, (char *) msg, sizeof (P2P_pingpong_MESSAGE)); transport->disconnect (mytsession, __FILE__); return ret;}/** * We received a PING message, send the PONG reply and notify the * connection module that the session is still life. */static intplaintextPingReceived (const GNUNET_PeerIdentity * sender, const GNUNET_MessageHeader * hmsg, GNUNET_TSession * tsession){ GNUNET_EncName enc; const P2P_pingpong_MESSAGE *pmsg; P2P_pingpong_MESSAGE pong; int ret; if (ntohs (hmsg->size) != sizeof (P2P_pingpong_MESSAGE)) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER | GNUNET_GE_DEVELOPER, _("Received malformed `%s' message. Dropping.\n"), "ping"); GNUNET_GE_BREAK_OP (NULL, 0); return GNUNET_SYSERR; } pmsg = (const P2P_pingpong_MESSAGE *) hmsg; if (0 != memcmp (coreAPI->my_identity, &pmsg->receiver, sizeof (GNUNET_PeerIdentity))) { GNUNET_hash_to_enc (&sender->hashPubKey, &enc); GNUNET_GE_LOG (ectx, GNUNET_GE_INFO | GNUNET_GE_REQUEST | GNUNET_GE_ADMIN, _("Received PING from `%s' not destined for us!\n"), &enc); GNUNET_GE_BREAK_OP (NULL, 0); return GNUNET_SYSERR; /* not for us */ }#if DEBUG_PINGPONG GNUNET_hash_to_enc (&sender->hashPubKey, &enc); GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "Received plaintext ping from peer %s.\n", &enc);#endif pong = *pmsg; pong.header.type = htons (GNUNET_P2P_PROTO_PONG); /* allow using a different transport for sending the reply, the transport may have been uni-directional! */ ret = GNUNET_SYSERR; if (tsession != NULL) ret = coreAPI->plaintext_send (tsession, (char *) &pong, sizeof (P2P_pingpong_MESSAGE)); if (ret != GNUNET_OK) ret = connection_send_plaintext (sender, &pong); if (ret == GNUNET_OK) { if (stats != NULL) stats->change (stat_plaintextPongSent, 1); } else { if (stats != NULL) stats->change (stat_plaintextPongFailed, 1); } return ret;}/** * Handler for a pong. */static intpongReceived (const GNUNET_PeerIdentity * sender, const GNUNET_MessageHeader * msg){ int i; const P2P_pingpong_MESSAGE *pmsg; PingPongEntry *entry; int matched;#if DEBUG_PINGPONG GNUNET_EncName enc;#endif pmsg = (const P2P_pingpong_MESSAGE *) msg; if ((ntohs (msg->size) != sizeof (P2P_pingpong_MESSAGE)) || (0 != memcmp (sender, &pmsg->receiver, sizeof (GNUNET_PeerIdentity)))) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER | GNUNET_GE_DEVELOPER, _("Received malformed `%s' message. Dropping.\n"), "pong"); return GNUNET_SYSERR; /* bad pong */ }#if DEBUG_PINGPONG GNUNET_hash_to_enc (&sender->hashPubKey, &enc); GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "Received PONG from `%s'.\n", &enc);#endif matched = 0; if (stats != NULL) stats->change (stat_encryptedPongReceived, 1); GNUNET_mutex_lock (pingPongLock); for (i = 0; i < MAX_PING_PONG; i++) { entry = &pingPongs[i]; if (((int) ntohl (pmsg->challenge) == entry->challenge) && (0 == memcmp (sender, &entry->receiverIdentity, sizeof (GNUNET_PeerIdentity))) && (entry->plaintext == GNUNET_NO)) { entry->method (entry->data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -