aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-transport_validation.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-08-06 20:27:22 +0000
committerChristian Grothoff <christian@grothoff.org>2011-08-06 20:27:22 +0000
commit4700ee225497a1dbfbda029f0cee5321a40654da (patch)
treeed74fa3d45a4ba4dbf4f1860ec80a6e224eaab43 /src/transport/gnunet-service-transport_validation.c
parent79fdb70dea5c857406c26c77cce34f959a0adff7 (diff)
downloadgnunet-4700ee225497a1dbfbda029f0cee5321a40654da.tar.gz
gnunet-4700ee225497a1dbfbda029f0cee5321a40654da.zip
handle PONGs
Diffstat (limited to 'src/transport/gnunet-service-transport_validation.c')
-rw-r--r--src/transport/gnunet-service-transport_validation.c300
1 files changed, 243 insertions, 57 deletions
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
index d0331c192..4f0848c87 100644
--- a/src/transport/gnunet-service-transport_validation.c
+++ b/src/transport/gnunet-service-transport_validation.c
@@ -33,16 +33,6 @@
33 33
34 34
35/** 35/**
36 * How long until a HELLO verification attempt should time out?
37 * Must be rather small, otherwise a partially successful HELLO
38 * validation (some addresses working) might not be available
39 * before a client's request for a connection fails for good.
40 * Besides, if a single request to an address takes a long time,
41 * then the peer is unlikely worthwhile anyway.
42 */
43#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
44
45/**
46 * How long is a PONG signature valid? We'll recycle a signature until 36 * How long is a PONG signature valid? We'll recycle a signature until
47 * 1/4 of this time is remaining. PONGs should expire so that if our 37 * 1/4 of this time is remaining. PONGs should expire so that if our
48 * external addresses change an adversary cannot replay them indefinitely. 38 * external addresses change an adversary cannot replay them indefinitely.
@@ -66,25 +56,19 @@
66#define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) 56#define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
67 57
68/** 58/**
69 * How long before we try to check an address again (if it turned out to
70 * be invalid the first time)?
71 */
72#define MAX_REVALIDATION_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
73
74/**
75 * Size of the validation map hashmap. 59 * Size of the validation map hashmap.
76 */ 60 */
77#define VALIDATION_MAP_SIZE 256 61#define VALIDATION_MAP_SIZE 256
78 62
79/** 63/**
80 * Priority to use for PINGs and PONGs 64 * Priority to use for PINGs
81 */ 65 */
82#define PING_PRIORITY 1 66#define PING_PRIORITY 2
83 67
84/** 68/**
85 * Priority to use for PINGs and PONGs 69 * Priority to use for PONGs
86 */ 70 */
87#define PONG_PRIORITY 1 71#define PONG_PRIORITY 4
88 72
89 73
90/** 74/**
@@ -191,6 +175,11 @@ struct ValidationEntry
191 const void *addr; 175 const void *addr;
192 176
193 /** 177 /**
178 * Public key of the peer.
179 */
180 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
181
182 /**
194 * The identity of the peer. 183 * The identity of the peer.
195 */ 184 */
196 struct GNUNET_PeerIdentity pid; 185 struct GNUNET_PeerIdentity pid;
@@ -349,7 +338,6 @@ GST_validation_stop ()
349} 338}
350 339
351 340
352#if 0
353/** 341/**
354 * Address validation cleanup task (record no longer needed). 342 * Address validation cleanup task (record no longer needed).
355 * 343 *
@@ -374,7 +362,6 @@ timeout_hello_validation (void *cls,
374 GNUNET_free (va->transport_name); 362 GNUNET_free (va->transport_name);
375 GNUNET_free (va); 363 GNUNET_free (va);
376} 364}
377#endif
378 365
379 366
380/** 367/**
@@ -437,6 +424,7 @@ validation_entry_match (void *cls,
437 * the given address and transport. If none exists, create one (but 424 * the given address and transport. If none exists, create one (but
438 * without starting any validation). 425 * without starting any validation).
439 * 426 *
427 * @param public_key public key of the peer, NULL for unknown
440 * @param neighbour which peer we care about 428 * @param neighbour which peer we care about
441 * @param tname name of the transport plugin 429 * @param tname name of the transport plugin
442 * @param session session to look for, NULL for 'any'; otherwise 430 * @param session session to look for, NULL for 'any'; otherwise
@@ -444,10 +432,12 @@ validation_entry_match (void *cls,
444 * if 'addr' matches 432 * if 'addr' matches
445 * @param addr binary address 433 * @param addr binary address
446 * @param addrlen length of addr 434 * @param addrlen length of addr
447 * @return validation entry matching the given specifications 435 * @return validation entry matching the given specifications, NULL
436 * if we don't have an existing entry and no public key was given
448 */ 437 */
449static struct ValidationEntry * 438static struct ValidationEntry *
450find_validation_entry (struct GNUNET_PeerIdentity *neighbour, 439find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key,
440 const struct GNUNET_PeerIdentity *neighbour,
451 const char *tname, 441 const char *tname,
452 const char *addr, 442 const char *addr,
453 size_t addrlen) 443 size_t addrlen)
@@ -465,12 +455,15 @@ find_validation_entry (struct GNUNET_PeerIdentity *neighbour,
465 &vemc); 455 &vemc);
466 if (NULL != (ve = vemc.ve)) 456 if (NULL != (ve = vemc.ve))
467 return ve; 457 return ve;
458 if (public_key == NULL)
459 return NULL;
468 ve = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen); 460 ve = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
469 ve->transport_name = GNUNET_strdup (tname); 461 ve->transport_name = GNUNET_strdup (tname);
470 ve->addr = (void*) &ve[1]; 462 ve->addr = (void*) &ve[1];
463 ve->public_key = *public_key;
471 ve->pid = *neighbour; 464 ve->pid = *neighbour;
472 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 465 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
473 UINT32_MAX); 466 UINT32_MAX);
474 memcpy (&ve[1], addr, addrlen); 467 memcpy (&ve[1], addr, addrlen);
475 ve->addrlen = addrlen; 468 ve->addrlen = addrlen;
476 GNUNET_CONTAINER_multihashmap_put (validation_map, 469 GNUNET_CONTAINER_multihashmap_put (validation_map,
@@ -515,7 +508,7 @@ multicast_pong (void *cls,
515 (const char*) pong, 508 (const char*) pong,
516 ntohs (pong->header.size), 509 ntohs (pong->header.size),
517 PONG_PRIORITY, 510 PONG_PRIORITY,
518 HELLO_VERIFICATION_TIMEOUT, 511 HELLO_REVALIDATION_START_TIME,
519 NULL, 512 NULL,
520 plugin_address, 513 plugin_address,
521 plugin_address_len, 514 plugin_address_len,
@@ -594,7 +587,9 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
594 alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage); 587 alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage);
595 if (alen == 0) 588 if (alen == 0)
596 { 589 {
597 /* peer wants to confirm that we have an outbound connection to him */ 590 /* peer wants to confirm that we have an outbound connection to him;
591 we handle this case here even though it has nothing to do with
592 address validation (!) */
598 if (sender_address == NULL) 593 if (sender_address == NULL)
599 { 594 {
600 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 595 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -663,7 +658,8 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
663 } 658 }
664 else 659 else
665 { 660 {
666 /* peer wants to confirm that this is one of our addresses */ 661 /* peer wants to confirm that this is one of our addresses, this is what is
662 used for address validation */
667 addrend = memchr (addr, '\0', alen); 663 addrend = memchr (addr, '\0', alen);
668 if (NULL == addrend) 664 if (NULL == addrend)
669 { 665 {
@@ -756,7 +752,7 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
756 (const char*) pong, 752 (const char*) pong,
757 ntohs (pong->header.size), 753 ntohs (pong->header.size),
758 PONG_PRIORITY, 754 PONG_PRIORITY,
759 HELLO_VERIFICATION_TIMEOUT, 755 HELLO_REVALIDATION_START_TIME,
760 session, 756 session,
761 sender_address, 757 sender_address,
762 sender_address_len, 758 sender_address_len,
@@ -790,31 +786,27 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
790 786
791 787
792/** 788/**
793 * We've received a PONG. Check if it matches a pending PING and 789 * Context for the 'validate_address' function
794 * mark the respective address as confirmed.
795 *
796 * @param sender peer sending the PONG
797 * @param hdr the PONG
798 * @param plugin_name name of plugin that received the PONG
799 * @param sender_address address of the sender as known to the plugin, NULL
800 * if we did not initiate the connection
801 * @param sender_address_len number of bytes in sender_address
802 */ 790 */
803void 791struct ValidateAddressContext
804GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
805 const struct GNUNET_MessageHeader *hdr,
806 const char *plugin_name,
807 const void *sender_address,
808 size_t sender_address_len)
809{ 792{
810} 793 /**
794 * Hash of the public key of the peer whose address is being validated.
795 */
796 struct GNUNET_PeerIdentity pid;
797
798 /**
799 * Public key of the peer whose address is being validated.
800 */
801 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
802};
811 803
812 804
813/** 805/**
814 * Iterator callback to go over all addresses and try to validate them 806 * Iterator callback to go over all addresses and try to validate them
815 * (unless blocked or already validated). 807 * (unless blocked or already validated).
816 * 808 *
817 * @param cls pointer to the 'struct PeerIdentity' of the peer 809 * @param cls pointer to a 'struct ValidateAddressContext'
818 * @param tname name of the transport 810 * @param tname name of the transport
819 * @param expiration expiration time 811 * @param expiration expiration time
820 * @param addr the address 812 * @param addr the address
@@ -828,7 +820,8 @@ validate_address (void *cls,
828 const void *addr, 820 const void *addr,
829 uint16_t addrlen) 821 uint16_t addrlen)
830{ 822{
831 struct GNUNET_PeerIdentity *pid = cls; 823 const struct ValidateAddressContext *vac = cls;
824 const struct GNUNET_PeerIdentity *pid = &vac->pid;
832 struct ValidationEntry *ve; 825 struct ValidationEntry *ve;
833 struct TransportPingMessage ping; 826 struct TransportPingMessage ping;
834 struct GNUNET_TRANSPORT_PluginFunctions *papi; 827 struct GNUNET_TRANSPORT_PluginFunctions *papi;
@@ -838,13 +831,18 @@ validate_address (void *cls,
838 831
839 if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) 832 if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
840 return GNUNET_OK; /* expired */ 833 return GNUNET_OK; /* expired */
841 ve = find_validation_entry (pid, tname, addr, addrlen); 834 ve = find_validation_entry (&vac->public_key, pid, tname, addr, addrlen);
842 if (GNUNET_TIME_absolute_get_remaining (ve->validation_block).rel_value > 0) 835 if (GNUNET_TIME_absolute_get_remaining (ve->validation_block).rel_value > 0)
843 return GNUNET_OK; /* blocked */ 836 return GNUNET_OK; /* blocked */
844 if (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > 0) 837 if ( (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) &&
845 return GNUNET_OK; /* valid */ 838 (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > 0) )
846 ve->validation_block = GNUNET_TIME_relative_to_absolute (MAX_REVALIDATION_FREQUENCY); 839 return GNUNET_OK; /* revalidation task already scheduled & still valid */
847 840 ve->validation_block = GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME);
841 if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task)
842 GNUNET_SCHEDULER_cancel (ve->timeout_task);
843 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_REVALIDATION_START_TIME,
844 &timeout_hello_validation,
845 ve);
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "Transmitting plain PING to `%s'\n", 847 "Transmitting plain PING to `%s'\n",
850 GNUNET_i2s (pid)); 848 GNUNET_i2s (pid));
@@ -874,7 +872,7 @@ validate_address (void *cls,
874 message_buf, 872 message_buf,
875 tsize, 873 tsize,
876 PING_PRIORITY, 874 PING_PRIORITY,
877 HELLO_VERIFICATION_TIMEOUT, 875 HELLO_REVALIDATION_START_TIME,
878 NULL /* no session */, 876 NULL /* no session */,
879 ve->addr, 877 ve->addr,
880 ve->addrlen, 878 ve->addrlen,
@@ -894,6 +892,192 @@ validate_address (void *cls,
894 892
895 893
896/** 894/**
895 * Do address validation again to keep address valid.
896 *
897 * @param cls the 'struct ValidationEntry'
898 * @param tc scheduler context (unused)
899 */
900static void
901revalidate_address (void *cls,
902 const struct GNUNET_SCHEDULER_TaskContext *tc)
903{
904 struct ValidationEntry *ve = cls;
905 struct GNUNET_TIME_Relative delay;
906 struct ValidateAddressContext vac;
907
908 ve->timeout_task = GNUNET_SCHEDULER_NO_TASK;
909 delay = GNUNET_TIME_absolute_get_remaining (ve->validation_block);
910 if (delay.rel_value > 0)
911 {
912 /* should wait a bit longer */
913 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (delay,
914 &revalidate_address,
915 ve);
916 return;
917 }
918 GNUNET_STATISTICS_update (GST_stats,
919 gettext_noop ("# address revalidations started"),
920 1,
921 GNUNET_NO);
922 vac.pid = ve->pid;
923 vac.public_key = ve->public_key;
924 validate_address (&vac,
925 ve->transport_name,
926 ve->valid_until,
927 ve->addr,
928 (uint16_t) ve->addrlen);
929}
930
931
932/**
933 * Add the validated peer address to the HELLO.
934 *
935 * @param cls the 'struct ValidationEntry' with the validated address
936 * @param max space in buf
937 * @param buf where to add the address
938 */
939static size_t
940add_valid_peer_address (void *cls,
941 size_t max,
942 void *buf)
943{
944 struct ValidationEntry *ve = cls;
945
946 return GNUNET_HELLO_add_address (ve->transport_name,
947 ve->valid_until,
948 ve->addr,
949 ve->addrlen,
950 buf,
951 max);
952}
953
954
955/**
956 * We've received a PONG. Check if it matches a pending PING and
957 * mark the respective address as confirmed.
958 *
959 * @param sender peer sending the PONG
960 * @param hdr the PONG
961 * @param plugin_name name of plugin that received the PONG
962 * @param sender_address address of the sender as known to the plugin, NULL
963 * if we did not initiate the connection
964 * @param sender_address_len number of bytes in sender_address
965 */
966void
967GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
968 const struct GNUNET_MessageHeader *hdr,
969 const char *plugin_name,
970 const void *sender_address,
971 size_t sender_address_len)
972{
973 const struct TransportPongMessage *pong;
974 struct ValidationEntry *ve;
975 const char *addr;
976 const char *addrend;
977 size_t alen;
978 size_t slen;
979 uint32_t rdelay;
980 struct GNUNET_TIME_Relative delay;
981 struct GNUNET_HELLO_Message *hello;
982
983 if (ntohs (hdr->size) < sizeof (struct TransportPongMessage))
984 {
985 GNUNET_break_op (0);
986 return;
987 }
988 GNUNET_STATISTICS_update (GST_stats,
989 gettext_noop ("# PONG messages received"),
990 1,
991 GNUNET_NO);
992 pong = (const struct TransportPongMessage *) hdr;
993 if (0 != memcmp (&pong->pid,
994 sender,
995 sizeof (struct GNUNET_PeerIdentity)))
996 {
997 /* PONG is validating inbound session, not an address, not the case
998 used for address validation, ignore here! */
999 return;
1000 }
1001#if DEBUG_TRANSPORT
1002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1003 "Processing `%s' from `%s'\n",
1004 "PONG",
1005 (sender_address != NULL)
1006 ? GST_plugin_a2s (plugin_name,
1007 sender_address,
1008 sender_address_len)
1009 : "<inbound>");
1010#endif
1011 addr = (const char*) &pong[1];
1012 alen = ntohs (hdr->size) - sizeof (struct TransportPongMessage);
1013 addrend = memchr (addr, '\0', alen);
1014 if (NULL == addrend)
1015 {
1016 GNUNET_break_op (0);
1017 return;
1018 }
1019 addrend++;
1020 slen = strlen(addr);
1021 alen -= slen;
1022 ve = find_validation_entry (NULL,
1023 sender,
1024 addr,
1025 addrend,
1026 alen);
1027 if (NULL == ve)
1028 {
1029 GNUNET_STATISTICS_update (GST_stats,
1030 gettext_noop ("# PONGs dropped, no matching pending validation"),
1031 1,
1032 GNUNET_NO);
1033 return;
1034 }
1035 /* now check that PONG is well-formed */
1036 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
1037 {
1038 GNUNET_STATISTICS_update (GST_stats,
1039 gettext_noop ("# PONGs dropped, signature expired"),
1040 1,
1041 GNUNET_NO);
1042 return;
1043 }
1044 if (GNUNET_OK !=
1045 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
1046 &pong->purpose,
1047 &pong->signature,
1048 &ve->public_key))
1049 {
1050 GNUNET_break_op (0);
1051 return;
1052 }
1053
1054 /* validity achieved, remember it! */
1055 ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1056
1057 /* build HELLO to store in PEERINFO */
1058 hello = GNUNET_HELLO_create (&ve->public_key,
1059 &add_valid_peer_address,
1060 ve);
1061 GNUNET_PEERINFO_add_peer (GST_peerinfo,
1062 hello);
1063 GNUNET_free (hello);
1064
1065 if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task)
1066 GNUNET_SCHEDULER_cancel (ve->timeout_task);
1067
1068 /* randomly delay by up to 1h to avoid synchronous validations */
1069 rdelay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1070 60 * 60);
1071 delay = GNUNET_TIME_relative_add (HELLO_REVALIDATION_START_TIME,
1072 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1073 rdelay));
1074 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (delay,
1075 &revalidate_address,
1076 ve);
1077}
1078
1079
1080/**
897 * We've received a HELLO, check which addresses are new and trigger 1081 * We've received a HELLO, check which addresses are new and trigger
898 * validation. 1082 * validation.
899 * 1083 *
@@ -903,10 +1087,12 @@ void
903GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) 1087GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
904{ 1088{
905 const struct GNUNET_HELLO_Message* hm = (const struct GNUNET_HELLO_Message*) hello; 1089 const struct GNUNET_HELLO_Message* hm = (const struct GNUNET_HELLO_Message*) hello;
906 struct GNUNET_PeerIdentity pid; 1090 struct ValidateAddressContext vac;
907 1091
908 if (GNUNET_OK != 1092 if ( (GNUNET_OK !=
909 GNUNET_HELLO_get_id (hm, &pid)) 1093 GNUNET_HELLO_get_id (hm, &vac.pid)) ||
1094 (GNUNET_OK !=
1095 GNUNET_HELLO_get_key (hm, &vac.public_key)) )
910 { 1096 {
911 /* malformed HELLO */ 1097 /* malformed HELLO */
912 GNUNET_break (0); 1098 GNUNET_break (0);
@@ -916,7 +1102,7 @@ GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
916 GNUNET_HELLO_iterate_addresses (hm, 1102 GNUNET_HELLO_iterate_addresses (hm,
917 GNUNET_NO, 1103 GNUNET_NO,
918 &validate_address, 1104 &validate_address,
919 &pid)); 1105 &vac));
920} 1106}
921 1107
922 1108