diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-07-12 15:31:11 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-07-12 15:31:11 +0000 |
commit | 868126cd639e63cd6f4db19a19e49778fc67e0ad (patch) | |
tree | 05bbcc2c6cef1c3a9eec7e799d265f138cf9685c | |
parent | 0700c60ef320c8ccbd417833441697c64d6c525c (diff) | |
download | gnunet-868126cd639e63cd6f4db19a19e49778fc67e0ad.tar.gz gnunet-868126cd639e63cd6f4db19a19e49778fc67e0ad.zip |
improving HELLO validation by transports
-rw-r--r-- | src/transport/gnunet-service-transport.c | 514 | ||||
-rw-r--r-- | src/transport/plugin_transport.h | 77 | ||||
-rw-r--r-- | src/transport/plugin_transport_tcp.c | 372 | ||||
-rw-r--r-- | src/transport/plugin_transport_template.c | 38 |
4 files changed, 508 insertions, 493 deletions
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 079dc1703..c34efec6c 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c | |||
@@ -437,70 +437,6 @@ struct TransportClient | |||
437 | 437 | ||
438 | 438 | ||
439 | /** | 439 | /** |
440 | * Message used to ask a peer to validate receipt (to check an address | ||
441 | * from a HELLO). Followed by the address used. Note that the | ||
442 | * recipients response does not affirm that he has this address, | ||
443 | * only that he got the challenge message. | ||
444 | */ | ||
445 | struct ValidationChallengeMessage | ||
446 | { | ||
447 | |||
448 | /** | ||
449 | * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING | ||
450 | */ | ||
451 | struct GNUNET_MessageHeader header; | ||
452 | |||
453 | /** | ||
454 | * What are we signing and why? | ||
455 | */ | ||
456 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
457 | |||
458 | /** | ||
459 | * Random challenge number (in network byte order). | ||
460 | */ | ||
461 | uint32_t challenge GNUNET_PACKED; | ||
462 | |||
463 | /** | ||
464 | * Who is the intended recipient? | ||
465 | */ | ||
466 | struct GNUNET_PeerIdentity target; | ||
467 | }; | ||
468 | |||
469 | |||
470 | /** | ||
471 | * Message used to validate a HELLO. If this was | ||
472 | * the right recipient, the response is a signature | ||
473 | * of the original validation request. The | ||
474 | * challenge is included in the confirmation to make | ||
475 | * matching of replies to requests possible. | ||
476 | */ | ||
477 | struct ValidationChallengeResponse | ||
478 | { | ||
479 | |||
480 | /** | ||
481 | * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG | ||
482 | */ | ||
483 | struct GNUNET_MessageHeader header; | ||
484 | |||
485 | /** | ||
486 | * Random challenge number (in network byte order). | ||
487 | */ | ||
488 | uint32_t challenge GNUNET_PACKED; | ||
489 | |||
490 | /** | ||
491 | * Who signed this message? | ||
492 | */ | ||
493 | struct GNUNET_PeerIdentity sender; | ||
494 | |||
495 | /** | ||
496 | * Signature. | ||
497 | */ | ||
498 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
499 | |||
500 | }; | ||
501 | |||
502 | |||
503 | /** | ||
504 | * For each HELLO, we may have to validate multiple addresses; | 440 | * For each HELLO, we may have to validate multiple addresses; |
505 | * each address gets its own request entry. | 441 | * each address gets its own request entry. |
506 | */ | 442 | */ |
@@ -512,12 +448,6 @@ struct ValidationAddress | |||
512 | struct ValidationAddress *next; | 448 | struct ValidationAddress *next; |
513 | 449 | ||
514 | /** | 450 | /** |
515 | * Our challenge message. Points to after this | ||
516 | * struct, so this field should not be freed. | ||
517 | */ | ||
518 | struct ValidationChallengeMessage *msg; | ||
519 | |||
520 | /** | ||
521 | * Name of the transport. | 451 | * Name of the transport. |
522 | */ | 452 | */ |
523 | char *transport_name; | 453 | char *transport_name; |
@@ -533,6 +463,11 @@ struct ValidationAddress | |||
533 | size_t addr_len; | 463 | size_t addr_len; |
534 | 464 | ||
535 | /** | 465 | /** |
466 | * Challenge number we used. | ||
467 | */ | ||
468 | uint32_t challenge; | ||
469 | |||
470 | /** | ||
536 | * Set to GNUNET_YES if the challenge was met, | 471 | * Set to GNUNET_YES if the challenge was met, |
537 | * GNUNET_SYSERR if we know it failed, GNUNET_NO | 472 | * GNUNET_SYSERR if we know it failed, GNUNET_NO |
538 | * if we are waiting on a response. | 473 | * if we are waiting on a response. |
@@ -940,115 +875,6 @@ transmit_send_continuation (void *cls, | |||
940 | } | 875 | } |
941 | 876 | ||
942 | 877 | ||
943 | |||
944 | |||
945 | /** | ||
946 | * We could not use an existing (or validated) connection to | ||
947 | * talk to a peer. Try addresses that have not yet been | ||
948 | * validated. | ||
949 | * | ||
950 | * @param n neighbour we want to communicate with | ||
951 | * @return plugin ready to talk, or NULL if none is available | ||
952 | */ | ||
953 | static struct ReadyList * | ||
954 | try_unvalidated_addresses (struct NeighbourList *n) | ||
955 | { | ||
956 | struct ValidationList *vl; | ||
957 | struct ValidationAddress *va; | ||
958 | struct GNUNET_PeerIdentity id; | ||
959 | struct GNUNET_TIME_Absolute now; | ||
960 | unsigned int total; | ||
961 | unsigned int cnt; | ||
962 | struct ReadyList *rl; | ||
963 | struct TransportPlugin *plugin; | ||
964 | |||
965 | #if DEBUG_TRANSPORT | ||
966 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
967 | "Trying to connect to `%4s' using unvalidated addresses\n", | ||
968 | GNUNET_i2s (&n->id)); | ||
969 | #endif | ||
970 | /* NOTE: this function needs to not only identify the | ||
971 | plugin but also setup "plugin_handle", binding it to the | ||
972 | right address using the plugin's "send_to" API */ | ||
973 | now = GNUNET_TIME_absolute_get (); | ||
974 | vl = pending_validations; | ||
975 | while (vl != NULL) | ||
976 | { | ||
977 | GNUNET_CRYPTO_hash (&vl->publicKey, | ||
978 | sizeof (struct | ||
979 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
980 | &id.hashPubKey); | ||
981 | if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity))) | ||
982 | break; | ||
983 | vl = vl->next; | ||
984 | } | ||
985 | if (vl == NULL) | ||
986 | { | ||
987 | #if DEBUG_TRANSPORT | ||
988 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
989 | "No unvalidated address found for peer `%4s'\n", | ||
990 | GNUNET_i2s (&n->id)); | ||
991 | #endif | ||
992 | return NULL; | ||
993 | } | ||
994 | total = 0; | ||
995 | cnt = 0; | ||
996 | va = vl->addresses; | ||
997 | while (va != NULL) | ||
998 | { | ||
999 | cnt++; | ||
1000 | if (va->expiration.value > now.value) | ||
1001 | total++; | ||
1002 | va = va->next; | ||
1003 | } | ||
1004 | if (total == 0) | ||
1005 | { | ||
1006 | #if DEBUG_TRANSPORT | ||
1007 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1008 | "All %u unvalidated addresses for peer have expired\n", | ||
1009 | cnt); | ||
1010 | #endif | ||
1011 | return NULL; | ||
1012 | } | ||
1013 | total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); | ||
1014 | for (va = vl->addresses; va != NULL; va = va->next) | ||
1015 | { | ||
1016 | if (va->expiration.value <= now.value) | ||
1017 | continue; | ||
1018 | if (total > 0) | ||
1019 | { | ||
1020 | total--; | ||
1021 | continue; | ||
1022 | } | ||
1023 | #if DEBUG_TRANSPORT | ||
1024 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1025 | "Trying unvalidated address of `%s' transport\n", | ||
1026 | va->transport_name); | ||
1027 | #endif | ||
1028 | plugin = find_transport (va->transport_name); | ||
1029 | if (plugin == NULL) | ||
1030 | { | ||
1031 | GNUNET_break (0); | ||
1032 | break; | ||
1033 | } | ||
1034 | rl = GNUNET_malloc (sizeof (struct ReadyList)); | ||
1035 | rl->next = n->plugins; | ||
1036 | n->plugins = rl; | ||
1037 | rl->plugin = plugin; | ||
1038 | rl->plugin_handle = plugin->api->send_to (plugin->api->cls, | ||
1039 | &n->id, | ||
1040 | 0, | ||
1041 | NULL, | ||
1042 | NULL, | ||
1043 | GNUNET_TIME_UNIT_ZERO, | ||
1044 | &va->msg[1], va->addr_len); | ||
1045 | rl->transmit_ready = GNUNET_YES; | ||
1046 | return rl; | ||
1047 | } | ||
1048 | return NULL; | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | /** | 878 | /** |
1053 | * Check the ready list for the given neighbour and | 879 | * Check the ready list for the given neighbour and |
1054 | * if a plugin is ready for transmission (and if we | 880 | * if a plugin is ready for transmission (and if we |
@@ -1094,8 +920,6 @@ try_transmission_to_peer (struct NeighbourList *neighbour) | |||
1094 | pos = pos->next; | 920 | pos = pos->next; |
1095 | } | 921 | } |
1096 | if (rl == NULL) | 922 | if (rl == NULL) |
1097 | rl = try_unvalidated_addresses (neighbour); | ||
1098 | if (rl == NULL) | ||
1099 | { | 923 | { |
1100 | #if DEBUG_TRANSPORT | 924 | #if DEBUG_TRANSPORT |
1101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 925 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1568,7 +1392,7 @@ list_validated_addresses (void *cls, size_t max, void *buf) | |||
1568 | return 0; | 1392 | return 0; |
1569 | ret = GNUNET_HELLO_add_address ((*va)->transport_name, | 1393 | ret = GNUNET_HELLO_add_address ((*va)->transport_name, |
1570 | (*va)->expiration, | 1394 | (*va)->expiration, |
1571 | &(*va)->msg[1], (*va)->addr_len, buf, max); | 1395 | &(*va)[1], (*va)->addr_len, buf, max); |
1572 | *va = (*va)->next; | 1396 | *va = (*va)->next; |
1573 | return ret; | 1397 | return ret; |
1574 | } | 1398 | } |
@@ -1648,6 +1472,101 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1648 | } | 1472 | } |
1649 | 1473 | ||
1650 | 1474 | ||
1475 | |||
1476 | |||
1477 | /** | ||
1478 | * Function that will be called if we receive a validation | ||
1479 | * of an address challenge that we transmitted to another | ||
1480 | * peer. Note that the validation should only be considered | ||
1481 | * acceptable if the challenge matches AND if the sender | ||
1482 | * address is at least a plausible address for this peer | ||
1483 | * (otherwise we may be seeing a MiM attack). | ||
1484 | * | ||
1485 | * @param cls closure | ||
1486 | * @param name name of the transport that generated the address | ||
1487 | * @param peer who responded to our challenge | ||
1488 | * @param challenge the challenge number we presumably used | ||
1489 | * @param sender_addr string describing our sender address (as observed | ||
1490 | * by the other peer in human-readable format) | ||
1491 | */ | ||
1492 | static void | ||
1493 | plugin_env_notify_validation (void *cls, | ||
1494 | const char *name, | ||
1495 | const struct GNUNET_PeerIdentity *peer, | ||
1496 | uint32_t challenge, | ||
1497 | const char *sender_addr) | ||
1498 | { | ||
1499 | int all_done; | ||
1500 | int matched; | ||
1501 | struct ValidationList *pos; | ||
1502 | struct ValidationAddress *va; | ||
1503 | struct GNUNET_PeerIdentity id; | ||
1504 | |||
1505 | pos = pending_validations; | ||
1506 | while (pos != NULL) | ||
1507 | { | ||
1508 | GNUNET_CRYPTO_hash (&pos->publicKey, | ||
1509 | sizeof (struct | ||
1510 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1511 | &id.hashPubKey); | ||
1512 | if (0 == | ||
1513 | memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity))) | ||
1514 | break; | ||
1515 | pos = pos->next; | ||
1516 | } | ||
1517 | if (pos == NULL) | ||
1518 | { | ||
1519 | /* TODO: call statistics (unmatched PONG) */ | ||
1520 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1521 | _ | ||
1522 | ("Received validation response but have no record of a matching validation request. Ignoring.\n")); | ||
1523 | return; | ||
1524 | } | ||
1525 | all_done = GNUNET_YES; | ||
1526 | matched = GNUNET_NO; | ||
1527 | va = pos->addresses; | ||
1528 | while (va != NULL) | ||
1529 | { | ||
1530 | if (va->challenge == challenge) | ||
1531 | { | ||
1532 | #if DEBUG_TRANSPORT | ||
1533 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1534 | "Confirmed validity of peer address.\n"); | ||
1535 | #endif | ||
1536 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | ||
1537 | _("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"), | ||
1538 | sender_addr, | ||
1539 | name); | ||
1540 | va->ok = GNUNET_YES; | ||
1541 | va->expiration = | ||
1542 | GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); | ||
1543 | matched = GNUNET_YES; | ||
1544 | } | ||
1545 | if (va->ok != GNUNET_YES) | ||
1546 | all_done = GNUNET_NO; | ||
1547 | va = va->next; | ||
1548 | } | ||
1549 | if (GNUNET_NO == matched) | ||
1550 | { | ||
1551 | /* TODO: call statistics (unmatched PONG) */ | ||
1552 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1553 | _ | ||
1554 | ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), | ||
1555 | "PONG", "PING"); | ||
1556 | } | ||
1557 | if (GNUNET_YES == all_done) | ||
1558 | { | ||
1559 | pos->timeout.value = 0; | ||
1560 | GNUNET_SCHEDULER_add_delayed (sched, | ||
1561 | GNUNET_NO, | ||
1562 | GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
1563 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, | ||
1564 | GNUNET_TIME_UNIT_ZERO, | ||
1565 | &cleanup_validation, NULL); | ||
1566 | } | ||
1567 | } | ||
1568 | |||
1569 | |||
1651 | struct CheckHelloValidatedContext | 1570 | struct CheckHelloValidatedContext |
1652 | { | 1571 | { |
1653 | /** | 1572 | /** |
@@ -1681,7 +1600,6 @@ run_validation (void *cls, | |||
1681 | struct ValidationList *e = cls; | 1600 | struct ValidationList *e = cls; |
1682 | struct TransportPlugin *tp; | 1601 | struct TransportPlugin *tp; |
1683 | struct ValidationAddress *va; | 1602 | struct ValidationAddress *va; |
1684 | struct ValidationChallengeMessage *vcm; | ||
1685 | struct GNUNET_PeerIdentity id; | 1603 | struct GNUNET_PeerIdentity id; |
1686 | 1604 | ||
1687 | tp = find_transport (tname); | 1605 | tp = find_transport (tname); |
@@ -1704,25 +1622,14 @@ run_validation (void *cls, | |||
1704 | tname, | 1622 | tname, |
1705 | GNUNET_i2s(&id)); | 1623 | GNUNET_i2s(&id)); |
1706 | 1624 | ||
1707 | va = GNUNET_malloc (sizeof (struct ValidationAddress) + | 1625 | va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen); |
1708 | sizeof (struct ValidationChallengeMessage) + addrlen); | ||
1709 | va->next = e->addresses; | 1626 | va->next = e->addresses; |
1710 | e->addresses = va; | 1627 | e->addresses = va; |
1711 | vcm = (struct ValidationChallengeMessage *) &va[1]; | ||
1712 | va->msg = vcm; | ||
1713 | va->transport_name = GNUNET_strdup (tname); | 1628 | va->transport_name = GNUNET_strdup (tname); |
1714 | va->addr_len = addrlen; | 1629 | va->addr_len = addrlen; |
1715 | vcm->header.size = | 1630 | va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, |
1716 | htons (sizeof (struct ValidationChallengeMessage) + addrlen); | 1631 | (unsigned int) -1); |
1717 | vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); | 1632 | memcpy (&va[1], addr, addrlen); |
1718 | vcm->purpose.size = | ||
1719 | htonl (sizeof (struct ValidationChallengeMessage) + addrlen - | ||
1720 | sizeof (struct GNUNET_MessageHeader)); | ||
1721 | vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO); | ||
1722 | vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1723 | (unsigned int) -1); | ||
1724 | vcm->target = id; | ||
1725 | memcpy (&vcm[1], addr, addrlen); | ||
1726 | return GNUNET_OK; | 1633 | return GNUNET_OK; |
1727 | } | 1634 | } |
1728 | 1635 | ||
@@ -1735,7 +1642,8 @@ run_validation (void *cls, | |||
1735 | static void | 1642 | static void |
1736 | check_hello_validated (void *cls, | 1643 | check_hello_validated (void *cls, |
1737 | const struct GNUNET_PeerIdentity *peer, | 1644 | const struct GNUNET_PeerIdentity *peer, |
1738 | const struct GNUNET_HELLO_Message *h, uint32_t trust) | 1645 | const struct GNUNET_HELLO_Message *h, |
1646 | uint32_t trust) | ||
1739 | { | 1647 | { |
1740 | struct CheckHelloValidatedContext *chvc = cls; | 1648 | struct CheckHelloValidatedContext *chvc = cls; |
1741 | struct ValidationAddress *va; | 1649 | struct ValidationAddress *va; |
@@ -1776,20 +1684,19 @@ check_hello_validated (void *cls, | |||
1776 | { | 1684 | { |
1777 | #if DEBUG_TRANSPORT | 1685 | #if DEBUG_TRANSPORT |
1778 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1686 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1779 | "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n", | 1687 | "Establishing `%s' connection to validate `%s' of `%4s'\n", |
1780 | va->transport_name, | 1688 | va->transport_name, |
1781 | "HELLO", GNUNET_i2s (&va->msg->target), "HELLO"); | 1689 | "HELLO", GNUNET_i2s (peer)); |
1782 | #endif | 1690 | #endif |
1783 | tp = find_transport (va->transport_name); | 1691 | tp = find_transport (va->transport_name); |
1784 | GNUNET_assert (tp != NULL); | 1692 | GNUNET_assert (tp != NULL); |
1785 | if (NULL == | 1693 | if (GNUNET_OK != |
1786 | tp->api->send_to (tp->api->cls, | 1694 | tp->api->validate (tp->api->cls, |
1787 | &va->msg->target, | 1695 | peer, |
1788 | 0, | 1696 | va->challenge, |
1789 | (const struct GNUNET_MessageHeader *) our_hello, | 1697 | HELLO_VERIFICATION_TIMEOUT, |
1790 | &va->msg->header, | 1698 | &va[1], |
1791 | HELLO_VERIFICATION_TIMEOUT, | 1699 | va->addr_len)) |
1792 | &va->msg[1], va->addr_len)) | ||
1793 | va->ok = GNUNET_SYSERR; | 1700 | va->ok = GNUNET_SYSERR; |
1794 | va = va->next; | 1701 | va = va->next; |
1795 | } | 1702 | } |
@@ -1885,186 +1792,6 @@ process_hello (struct TransportPlugin *plugin, | |||
1885 | } | 1792 | } |
1886 | 1793 | ||
1887 | 1794 | ||
1888 | /** | ||
1889 | * Handle PING-message. If the plugin that gave us the message is | ||
1890 | * able to queue the PONG immediately, we only queue one PONG. | ||
1891 | * Otherwise we send at most TWO PONG messages, one via an unconfirmed | ||
1892 | * transport and one via a confirmed transport. Both addresses are | ||
1893 | * selected randomly among those available. | ||
1894 | * | ||
1895 | * @param plugin plugin that gave us the message | ||
1896 | * @param sender claimed sender of the PING | ||
1897 | * @param plugin_context context that might be used to send response | ||
1898 | * @param message the actual message | ||
1899 | */ | ||
1900 | static void | ||
1901 | process_ping (struct TransportPlugin *plugin, | ||
1902 | const struct GNUNET_PeerIdentity *sender, | ||
1903 | void *plugin_context, | ||
1904 | const struct GNUNET_MessageHeader *message) | ||
1905 | { | ||
1906 | const struct ValidationChallengeMessage *vcm; | ||
1907 | struct ValidationChallengeResponse vcr; | ||
1908 | uint16_t msize; | ||
1909 | struct NeighbourList *n; | ||
1910 | |||
1911 | #if DEBUG_TRANSPORT | ||
1912 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1913 | "Processing PING\n"); | ||
1914 | #endif | ||
1915 | msize = ntohs (message->size); | ||
1916 | if (msize < sizeof (struct ValidationChallengeMessage)) | ||
1917 | { | ||
1918 | GNUNET_break_op (0); | ||
1919 | return; | ||
1920 | } | ||
1921 | vcm = (const struct ValidationChallengeMessage *) message; | ||
1922 | if (0 != memcmp (&vcm->target, | ||
1923 | &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
1924 | { | ||
1925 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1926 | _("Received `%s' message not destined for me!\n"), "PING"); | ||
1927 | /* TODO: call statistics */ | ||
1928 | return; | ||
1929 | } | ||
1930 | if ((ntohl (vcm->purpose.size) != | ||
1931 | msize - sizeof (struct GNUNET_MessageHeader)) | ||
1932 | || (ntohl (vcm->purpose.purpose) != | ||
1933 | GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO)) | ||
1934 | { | ||
1935 | GNUNET_break_op (0); | ||
1936 | return; | ||
1937 | } | ||
1938 | msize -= sizeof (struct ValidationChallengeMessage); | ||
1939 | if (GNUNET_OK != | ||
1940 | plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize)) | ||
1941 | { | ||
1942 | GNUNET_break_op (0); | ||
1943 | return; | ||
1944 | } | ||
1945 | vcr.header.size = htons (sizeof (struct ValidationChallengeResponse)); | ||
1946 | vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); | ||
1947 | vcr.challenge = vcm->challenge; | ||
1948 | vcr.sender = my_identity; | ||
1949 | GNUNET_assert (GNUNET_OK == | ||
1950 | GNUNET_CRYPTO_rsa_sign (my_private_key, | ||
1951 | &vcm->purpose, &vcr.signature)); | ||
1952 | #if EXTRA_CHECKS | ||
1953 | GNUNET_assert (GNUNET_OK == | ||
1954 | GNUNET_CRYPTO_rsa_verify | ||
1955 | (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose, | ||
1956 | &vcr.signature, &my_public_key)); | ||
1957 | #endif | ||
1958 | #if DEBUG_TRANSPORT | ||
1959 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1960 | "Trying to transmit PONG using inbound connection\n"); | ||
1961 | #endif | ||
1962 | n = find_neighbour (sender); | ||
1963 | if (n == NULL) | ||
1964 | { | ||
1965 | GNUNET_break (0); | ||
1966 | return; | ||
1967 | } | ||
1968 | transmit_to_peer (NULL, 0, &vcr.header, GNUNET_YES, n); | ||
1969 | } | ||
1970 | |||
1971 | |||
1972 | /** | ||
1973 | * Handle PONG-message. | ||
1974 | * | ||
1975 | * @param message the actual message | ||
1976 | */ | ||
1977 | static void | ||
1978 | process_pong (struct TransportPlugin *plugin, | ||
1979 | const struct GNUNET_MessageHeader *message) | ||
1980 | { | ||
1981 | const struct ValidationChallengeResponse *vcr; | ||
1982 | struct ValidationList *pos; | ||
1983 | struct GNUNET_PeerIdentity peer; | ||
1984 | struct ValidationAddress *va; | ||
1985 | int all_done; | ||
1986 | int matched; | ||
1987 | |||
1988 | #if DEBUG_TRANSPORT | ||
1989 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1990 | "Processing PONG\n"); | ||
1991 | #endif | ||
1992 | vcr = (const struct ValidationChallengeResponse *) message; | ||
1993 | pos = pending_validations; | ||
1994 | while (pos != NULL) | ||
1995 | { | ||
1996 | GNUNET_CRYPTO_hash (&pos->publicKey, | ||
1997 | sizeof (struct | ||
1998 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1999 | &peer.hashPubKey); | ||
2000 | if (0 == | ||
2001 | memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity))) | ||
2002 | break; | ||
2003 | pos = pos->next; | ||
2004 | } | ||
2005 | if (pos == NULL) | ||
2006 | { | ||
2007 | /* TODO: call statistics (unmatched PONG) */ | ||
2008 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2009 | _ | ||
2010 | ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), | ||
2011 | "PONG", "PING"); | ||
2012 | return; | ||
2013 | } | ||
2014 | all_done = GNUNET_YES; | ||
2015 | matched = GNUNET_NO; | ||
2016 | va = pos->addresses; | ||
2017 | while (va != NULL) | ||
2018 | { | ||
2019 | if (va->msg->challenge == vcr->challenge) | ||
2020 | { | ||
2021 | if (GNUNET_OK != | ||
2022 | GNUNET_CRYPTO_rsa_verify | ||
2023 | (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose, | ||
2024 | &vcr->signature, &pos->publicKey)) | ||
2025 | { | ||
2026 | /* this could rarely happen if we used the same | ||
2027 | challenge number for the peer for two different | ||
2028 | transports / addresses, but the likelihood is | ||
2029 | very small... */ | ||
2030 | GNUNET_break_op (0); | ||
2031 | } | ||
2032 | else | ||
2033 | { | ||
2034 | #if DEBUG_TRANSPORT | ||
2035 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2036 | "Confirmed validity of peer address.\n"); | ||
2037 | #endif | ||
2038 | va->ok = GNUNET_YES; | ||
2039 | va->expiration = | ||
2040 | GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); | ||
2041 | matched = GNUNET_YES; | ||
2042 | } | ||
2043 | } | ||
2044 | if (va->ok != GNUNET_YES) | ||
2045 | all_done = GNUNET_NO; | ||
2046 | va = va->next; | ||
2047 | } | ||
2048 | if (GNUNET_NO == matched) | ||
2049 | { | ||
2050 | /* TODO: call statistics (unmatched PONG) */ | ||
2051 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2052 | _ | ||
2053 | ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), | ||
2054 | "PONG", "PING"); | ||
2055 | } | ||
2056 | if (GNUNET_YES == all_done) | ||
2057 | { | ||
2058 | pos->timeout.value = 0; | ||
2059 | GNUNET_SCHEDULER_add_delayed (sched, | ||
2060 | GNUNET_NO, | ||
2061 | GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
2062 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, | ||
2063 | GNUNET_TIME_UNIT_ZERO, | ||
2064 | &cleanup_validation, NULL); | ||
2065 | } | ||
2066 | } | ||
2067 | |||
2068 | 1795 | ||
2069 | /** | 1796 | /** |
2070 | * The peer specified by the given neighbour has timed-out. Update | 1797 | * The peer specified by the given neighbour has timed-out. Update |
@@ -2342,12 +2069,6 @@ plugin_env_receive (void *cls, | |||
2342 | #endif | 2069 | #endif |
2343 | transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n); | 2070 | transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n); |
2344 | break; | 2071 | break; |
2345 | case GNUNET_MESSAGE_TYPE_TRANSPORT_PING: | ||
2346 | process_ping (plugin, peer, plugin_context, message); | ||
2347 | break; | ||
2348 | case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG: | ||
2349 | process_pong (plugin, message); | ||
2350 | break; | ||
2351 | case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK: | 2072 | case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK: |
2352 | n->saw_ack = GNUNET_YES; | 2073 | n->saw_ack = GNUNET_YES; |
2353 | /* intentional fall-through! */ | 2074 | /* intentional fall-through! */ |
@@ -2639,10 +2360,13 @@ create_environment (struct TransportPlugin *plug) | |||
2639 | plug->env.cfg = cfg; | 2360 | plug->env.cfg = cfg; |
2640 | plug->env.sched = sched; | 2361 | plug->env.sched = sched; |
2641 | plug->env.my_public_key = &my_public_key; | 2362 | plug->env.my_public_key = &my_public_key; |
2363 | plug->env.my_private_key = my_private_key; | ||
2364 | plug->env.my_identity = &my_identity; | ||
2642 | plug->env.cls = plug; | 2365 | plug->env.cls = plug; |
2643 | plug->env.receive = &plugin_env_receive; | 2366 | plug->env.receive = &plugin_env_receive; |
2644 | plug->env.lookup = &plugin_env_lookup_address; | 2367 | plug->env.lookup = &plugin_env_lookup_address; |
2645 | plug->env.notify_address = &plugin_env_notify_address; | 2368 | plug->env.notify_address = &plugin_env_notify_address; |
2369 | plug->env.notify_validation = &plugin_env_notify_validation; | ||
2646 | plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000); | 2370 | plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000); |
2647 | plug->env.max_connections = max_connect_per_transport; | 2371 | plug->env.max_connections = max_connect_per_transport; |
2648 | } | 2372 | } |
diff --git a/src/transport/plugin_transport.h b/src/transport/plugin_transport.h index e0f83880a..10fad4886 100644 --- a/src/transport/plugin_transport.h +++ b/src/transport/plugin_transport.h | |||
@@ -91,6 +91,29 @@ typedef struct ReadyList * | |||
91 | 91 | ||
92 | 92 | ||
93 | /** | 93 | /** |
94 | * Function that will be called if we receive a validation | ||
95 | * of an address challenge that we transmitted to another | ||
96 | * peer. Note that the validation should only be considered | ||
97 | * acceptable if the challenge matches AND if the sender | ||
98 | * address is at least a plausible address for this peer | ||
99 | * (otherwise we may be seeing a MiM attack). | ||
100 | * | ||
101 | * @param cls closure | ||
102 | * @param name name of the transport that generated the address | ||
103 | * @param peer who responded to our challenge | ||
104 | * @param challenge the challenge number we presumably used | ||
105 | * @param sender_addr string describing our sender address (as observed | ||
106 | * by the other peer in human-readable format) | ||
107 | */ | ||
108 | typedef void (*GNUNET_TRANSPORT_ValidationNotification) (void *cls, | ||
109 | const char *name, | ||
110 | const struct GNUNET_PeerIdentity *peer, | ||
111 | uint32_t challenge, | ||
112 | const char *sender_addr); | ||
113 | |||
114 | |||
115 | |||
116 | /** | ||
94 | * Function that will be called for each address the transport | 117 | * Function that will be called for each address the transport |
95 | * is aware that it might be reachable under. | 118 | * is aware that it might be reachable under. |
96 | * | 119 | * |
@@ -167,6 +190,16 @@ struct GNUNET_TRANSPORT_PluginEnvironment | |||
167 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *my_public_key; | 190 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *my_public_key; |
168 | 191 | ||
169 | /** | 192 | /** |
193 | * Our private key. | ||
194 | */ | ||
195 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
196 | |||
197 | /** | ||
198 | * Identity of this peer. | ||
199 | */ | ||
200 | const struct GNUNET_PeerIdentity *my_identity; | ||
201 | |||
202 | /** | ||
170 | * Closure for the various callbacks. | 203 | * Closure for the various callbacks. |
171 | */ | 204 | */ |
172 | void *cls; | 205 | void *cls; |
@@ -190,6 +223,14 @@ struct GNUNET_TRANSPORT_PluginEnvironment | |||
190 | GNUNET_TRANSPORT_AddressNotification notify_address; | 223 | GNUNET_TRANSPORT_AddressNotification notify_address; |
191 | 224 | ||
192 | /** | 225 | /** |
226 | * Function that must be called by each plugin to notify the | ||
227 | * transport service about a successful validation of an | ||
228 | * address of another peer (or at least likely successful | ||
229 | * validation). | ||
230 | */ | ||
231 | GNUNET_TRANSPORT_ValidationNotification notify_validation; | ||
232 | |||
233 | /** | ||
193 | * What is the default quota (in terms of incoming bytes per | 234 | * What is the default quota (in terms of incoming bytes per |
194 | * ms) for new connections? | 235 | * ms) for new connections? |
195 | */ | 236 | */ |
@@ -206,34 +247,28 @@ struct GNUNET_TRANSPORT_PluginEnvironment | |||
206 | 247 | ||
207 | 248 | ||
208 | /** | 249 | /** |
209 | * Function that can be used by the transport service to transmit | 250 | * Function that can be used by the transport service to validate |
210 | * a message using the plugin using a fresh connection (even if | 251 | * the address of another peer. Even if |
211 | * we already have a connection to this peer, this function is | 252 | * we already have a connection to this peer, this function is |
212 | * required to establish a new one). | 253 | * required to establish a new one. |
213 | * | 254 | * |
214 | * @param cls closure | 255 | * @param cls closure |
215 | * @param target who should receive this message | 256 | * @param target who should receive this message |
216 | * @param priority how important is the message | 257 | * @param challenge challenge code to use |
217 | * @param msg1 first message to transmit | ||
218 | * @param msg2 second message to transmit (can be NULL) | ||
219 | * @param timeout how long should we try to transmit these? | 258 | * @param timeout how long should we try to transmit these? |
220 | * @param addrlen length of the address | 259 | * @param addrlen length of the address |
221 | * @param addr the address | 260 | * @param addr the address |
222 | * @return session instance if the transmission has been scheduled | 261 | * @return GNUNET_OK on success, GNUNET_SYSERR if the address |
223 | * NULL if the address format is invalid | 262 | * format is invalid |
224 | */ | 263 | */ |
225 | typedef void * | 264 | typedef int |
226 | (*GNUNET_TRANSPORT_TransmitToAddressFunction) (void *cls, | 265 | (*GNUNET_TRANSPORT_ValidationFunction) (void *cls, |
227 | const struct | 266 | const struct |
228 | GNUNET_PeerIdentity * target, | 267 | GNUNET_PeerIdentity * target, |
229 | unsigned int priority, | 268 | uint32_t challenge, |
230 | const struct | 269 | struct GNUNET_TIME_Relative |
231 | GNUNET_MessageHeader * msg1, | 270 | timeout, const void *addr, |
232 | const struct | 271 | size_t addrlen); |
233 | GNUNET_MessageHeader * msg2, | ||
234 | struct GNUNET_TIME_Relative | ||
235 | timeout, const void *addr, | ||
236 | size_t addrlen); | ||
237 | 272 | ||
238 | /** | 273 | /** |
239 | * Function called by the GNUNET_TRANSPORT_TransmitFunction | 274 | * Function called by the GNUNET_TRANSPORT_TransmitFunction |
@@ -415,7 +450,7 @@ struct GNUNET_TRANSPORT_PluginFunctions | |||
415 | * peer using the specified address. Used to validate | 450 | * peer using the specified address. Used to validate |
416 | * HELLOs. | 451 | * HELLOs. |
417 | */ | 452 | */ |
418 | GNUNET_TRANSPORT_TransmitToAddressFunction send_to; | 453 | GNUNET_TRANSPORT_ValidationFunction validate; |
419 | 454 | ||
420 | /** | 455 | /** |
421 | * Function that the transport service will use to transmit data to | 456 | * Function that the transport service will use to transmit data to |
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 2fc707196..9a2a54890 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "gnunet_resolver_service.h" | 33 | #include "gnunet_resolver_service.h" |
34 | #include "gnunet_server_lib.h" | 34 | #include "gnunet_server_lib.h" |
35 | #include "gnunet_service_lib.h" | 35 | #include "gnunet_service_lib.h" |
36 | #include "gnunet_signatures.h" | ||
36 | #include "gnunet_statistics_service.h" | 37 | #include "gnunet_statistics_service.h" |
37 | #include "gnunet_transport_service.h" | 38 | #include "gnunet_transport_service.h" |
38 | #include "plugin_transport.h" | 39 | #include "plugin_transport.h" |
@@ -62,6 +63,84 @@ | |||
62 | */ | 63 | */ |
63 | #define ACK_LOG_SIZE 32 | 64 | #define ACK_LOG_SIZE 32 |
64 | 65 | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Message used to ask a peer to validate receipt (to check an address | ||
70 | * from a HELLO). Followed by the address used. Note that the | ||
71 | * recipients response does not affirm that he has this address, | ||
72 | * only that he got the challenge message. | ||
73 | */ | ||
74 | struct ValidationChallengeMessage | ||
75 | { | ||
76 | |||
77 | /** | ||
78 | * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING | ||
79 | */ | ||
80 | struct GNUNET_MessageHeader header; | ||
81 | |||
82 | /** | ||
83 | * Random challenge number (in network byte order). | ||
84 | */ | ||
85 | uint32_t challenge GNUNET_PACKED; | ||
86 | |||
87 | /** | ||
88 | * Who is the intended recipient? | ||
89 | */ | ||
90 | struct GNUNET_PeerIdentity target; | ||
91 | |||
92 | }; | ||
93 | |||
94 | |||
95 | /** | ||
96 | * Message used to validate a HELLO. The challenge is included in the | ||
97 | * confirmation to make matching of replies to requests possible. The | ||
98 | * signature signs the original challenge number, our public key, the | ||
99 | * sender's address (so that the sender can check that the address we | ||
100 | * saw is plausible for him and possibly detect a MiM attack) and a | ||
101 | * timestamp (to limit replay).<p> | ||
102 | * | ||
103 | * This message is followed by the address of the | ||
104 | * client that we are observing (which is part of what | ||
105 | * is being signed). | ||
106 | */ | ||
107 | struct ValidationChallengeResponse | ||
108 | { | ||
109 | |||
110 | /** | ||
111 | * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG | ||
112 | */ | ||
113 | struct GNUNET_MessageHeader header; | ||
114 | |||
115 | /** | ||
116 | * For padding, always zero. | ||
117 | */ | ||
118 | uint32_t reserved GNUNET_PACKED; | ||
119 | |||
120 | /** | ||
121 | * Signature. | ||
122 | */ | ||
123 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
124 | |||
125 | /** | ||
126 | * What are we signing and why? | ||
127 | */ | ||
128 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
129 | |||
130 | /** | ||
131 | * Random challenge number (in network byte order). | ||
132 | */ | ||
133 | uint32_t challenge GNUNET_PACKED; | ||
134 | |||
135 | /** | ||
136 | * Who signed this message? | ||
137 | */ | ||
138 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer; | ||
139 | |||
140 | }; | ||
141 | |||
142 | |||
143 | |||
65 | /** | 144 | /** |
66 | * Initial handshake message for a session. This header | 145 | * Initial handshake message for a session. This header |
67 | * is followed by the address that the other peer used to | 146 | * is followed by the address that the other peer used to |
@@ -625,35 +704,30 @@ process_pending_messages (struct Session *session) | |||
625 | 704 | ||
626 | 705 | ||
627 | /** | 706 | /** |
628 | * Function that can be used by the transport service to transmit | 707 | * Function that can be used by the transport service to validate that |
629 | * a message using the plugin using a fresh connection (even if | 708 | * another peer is reachable at a particular address (even if we |
630 | * we already have a connection to this peer, this function is | 709 | * already have a connection to this peer, this function is required |
631 | * required to establish a new one). | 710 | * to establish a new one). |
632 | * | 711 | * |
633 | * @param cls closure | 712 | * @param cls closure |
634 | * @param target who should receive this message | 713 | * @param target who should receive this message |
635 | * @param priority how important is the message | 714 | * @param challenge challenge code to use |
636 | * @param msg1 first message to transmit | ||
637 | * @param msg2 second message to transmit (can be NULL) | ||
638 | * @param timeout how long should we try to transmit these? | ||
639 | * @param addrlen length of the address | 715 | * @param addrlen length of the address |
640 | * @param addr the address | 716 | * @param addr the address |
641 | * @return session if the transmission has been scheduled | 717 | * @param timeout how long should we try to transmit these? |
642 | * NULL if the address format is invalid | 718 | * @return GNUNET_OK if the transmission has been scheduled |
643 | */ | 719 | */ |
644 | static void * | 720 | static int |
645 | tcp_plugin_send_to (void *cls, | 721 | tcp_plugin_validate (void *cls, |
646 | const struct GNUNET_PeerIdentity *target, | 722 | const struct GNUNET_PeerIdentity *target, |
647 | unsigned int priority, | 723 | uint32_t challenge, |
648 | const struct GNUNET_MessageHeader *msg1, | 724 | struct GNUNET_TIME_Relative timeout, |
649 | const struct GNUNET_MessageHeader *msg2, | 725 | const void *addr, size_t addrlen) |
650 | struct GNUNET_TIME_Relative timeout, | ||
651 | const void *addr, size_t addrlen) | ||
652 | { | 726 | { |
653 | struct Plugin *plugin = cls; | 727 | struct Plugin *plugin = cls; |
654 | struct Session *session; | 728 | struct Session *session; |
655 | struct PendingMessage *pl; | ||
656 | struct PendingMessage *pm; | 729 | struct PendingMessage *pm; |
730 | struct ValidationChallengeMessage *vcm; | ||
657 | 731 | ||
658 | session = connect_and_create_session (plugin, target, addr, addrlen); | 732 | session = connect_and_create_session (plugin, target, addr, addrlen); |
659 | if (session == NULL) | 733 | if (session == NULL) |
@@ -662,44 +736,24 @@ tcp_plugin_send_to (void *cls, | |||
662 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | 736 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
663 | "tcp", "Failed to create fresh session.\n"); | 737 | "tcp", "Failed to create fresh session.\n"); |
664 | #endif | 738 | #endif |
665 | return NULL; | 739 | return GNUNET_SYSERR; |
666 | } | ||
667 | pl = NULL; | ||
668 | if (msg2 != NULL) | ||
669 | { | ||
670 | pm = GNUNET_malloc (sizeof (struct PendingMessage) + | ||
671 | ntohs (msg2->size)); | ||
672 | pm->msg = (struct GNUNET_MessageHeader *) &pm[1]; | ||
673 | memcpy (pm->msg, msg2, ntohs (msg2->size)); | ||
674 | pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
675 | pm->is_welcome = GNUNET_NO; | ||
676 | pl = pm; | ||
677 | } | ||
678 | if (msg1 != NULL) | ||
679 | { | ||
680 | pm = GNUNET_malloc (sizeof (struct PendingMessage) + | ||
681 | ntohs (msg1->size)); | ||
682 | pm->msg = (struct GNUNET_MessageHeader *) &pm[1]; | ||
683 | memcpy (pm->msg, msg1, ntohs (msg1->size)); | ||
684 | pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
685 | pm->is_welcome = GNUNET_NO; | ||
686 | pm->next = pl; | ||
687 | pl = pm; | ||
688 | } | ||
689 | /* append */ | ||
690 | if (session->pending_messages != NULL) | ||
691 | { | ||
692 | pm = session->pending_messages; | ||
693 | while (pm->next != NULL) | ||
694 | pm = pm->next; | ||
695 | pm->next = pl; | ||
696 | } | ||
697 | else | ||
698 | { | ||
699 | session->pending_messages = pl; | ||
700 | } | 740 | } |
741 | pm = GNUNET_malloc (sizeof (struct PendingMessage) + | ||
742 | sizeof (struct ValidationChallengeMessage) + addrlen); | ||
743 | pm->msg = (struct GNUNET_MessageHeader *) &pm[1]; | ||
744 | pm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
745 | pm->is_welcome = GNUNET_YES; | ||
746 | vcm = (struct ValidationChallengeMessage*) &pm[1]; | ||
747 | vcm->header.size = | ||
748 | htons (sizeof (struct ValidationChallengeMessage) + addrlen); | ||
749 | vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING); | ||
750 | vcm->challenge = htonl(challenge); | ||
751 | vcm->target = *target; | ||
752 | memcpy (&vcm[1], addr, addrlen); | ||
753 | GNUNET_assert (session->pending_messages == NULL); | ||
754 | session->pending_messages = pm; | ||
701 | process_pending_messages (session); | 755 | process_pending_messages (session); |
702 | return session; | 756 | return GNUNET_OK; |
703 | } | 757 | } |
704 | 758 | ||
705 | 759 | ||
@@ -1346,6 +1400,210 @@ tcp_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | |||
1346 | 1400 | ||
1347 | 1401 | ||
1348 | /** | 1402 | /** |
1403 | * Send a validation challenge response. | ||
1404 | */ | ||
1405 | static size_t | ||
1406 | send_vcr (void *cls, | ||
1407 | size_t size, | ||
1408 | void *buf) | ||
1409 | { | ||
1410 | struct ValidationChallengeResponse *vcr = cls; | ||
1411 | uint16_t msize; | ||
1412 | |||
1413 | if (NULL == buf) | ||
1414 | { | ||
1415 | GNUNET_free (vcr); | ||
1416 | return 0; | ||
1417 | } | ||
1418 | msize = ntohs(vcr->header.size); | ||
1419 | GNUNET_assert (size >= msize); | ||
1420 | memcpy (buf, vcr, msize); | ||
1421 | GNUNET_free (vcr); | ||
1422 | return msize; | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | /** | ||
1427 | * We've received a PING from this peer via TCP. | ||
1428 | * Send back our PONG. | ||
1429 | * | ||
1430 | * @param cls closure | ||
1431 | * @param client identification of the client | ||
1432 | * @param message the actual message | ||
1433 | */ | ||
1434 | static void | ||
1435 | handle_tcp_ping (void *cls, | ||
1436 | struct GNUNET_SERVER_Client *client, | ||
1437 | const struct GNUNET_MessageHeader *message) | ||
1438 | { | ||
1439 | struct Plugin *plugin = cls; | ||
1440 | const struct ValidationChallengeMessage *vcm; | ||
1441 | struct ValidationChallengeResponse *vcr; | ||
1442 | uint16_t msize; | ||
1443 | size_t addrlen; | ||
1444 | void *addr; | ||
1445 | |||
1446 | #if DEBUG_TRANSPORT | ||
1447 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1448 | "Processing PING\n"); | ||
1449 | #endif | ||
1450 | msize = ntohs (message->size); | ||
1451 | if (msize < sizeof (struct ValidationChallengeMessage)) | ||
1452 | { | ||
1453 | GNUNET_break_op (0); | ||
1454 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1455 | return; | ||
1456 | } | ||
1457 | vcm = (const struct ValidationChallengeMessage *) message; | ||
1458 | if (0 != memcmp (&vcm->target, | ||
1459 | plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
1460 | { | ||
1461 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1462 | _("Received `%s' message not destined for me!\n"), "PING"); | ||
1463 | /* TODO: call statistics */ | ||
1464 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1465 | return; | ||
1466 | } | ||
1467 | msize -= sizeof (struct ValidationChallengeMessage); | ||
1468 | if (GNUNET_OK != | ||
1469 | tcp_plugin_address_suggested (plugin, &vcm[1], msize)) | ||
1470 | { | ||
1471 | GNUNET_break_op (0); | ||
1472 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1473 | return; | ||
1474 | } | ||
1475 | if (GNUNET_OK != | ||
1476 | GNUNET_SERVER_client_get_address (client, | ||
1477 | &addr, | ||
1478 | &addrlen)) | ||
1479 | { | ||
1480 | GNUNET_break (0); | ||
1481 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1482 | return; | ||
1483 | } | ||
1484 | vcr = GNUNET_malloc (sizeof (struct ValidationChallengeResponse) + addrlen); | ||
1485 | vcr->header.size = htons (sizeof (struct ValidationChallengeResponse) + addrlen); | ||
1486 | vcr->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG); | ||
1487 | vcr->purpose.size = | ||
1488 | htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + | ||
1489 | sizeof (uint32_t) + | ||
1490 | sizeof ( struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + | ||
1491 | addrlen); | ||
1492 | vcr->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING); | ||
1493 | vcr->challenge = vcm->challenge; | ||
1494 | vcr->signer = *plugin->env->my_public_key; | ||
1495 | memcpy (&vcr[1], | ||
1496 | addr, | ||
1497 | addrlen); | ||
1498 | GNUNET_assert (GNUNET_OK == | ||
1499 | GNUNET_CRYPTO_rsa_sign (plugin->env->my_private_key, | ||
1500 | &vcr->purpose, | ||
1501 | &vcr->signature)); | ||
1502 | #if EXTRA_CHECKS | ||
1503 | GNUNET_assert (GNUNET_OK == | ||
1504 | GNUNET_CRYPTO_rsa_verify | ||
1505 | (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING, | ||
1506 | &vcr->purpose, | ||
1507 | &vcr->signature, | ||
1508 | plugin->env->my_public_key)); | ||
1509 | #endif | ||
1510 | GNUNET_free (addr); | ||
1511 | if (NULL == | ||
1512 | GNUNET_SERVER_notify_transmit_ready (client, | ||
1513 | sizeof (struct ValidationChallengeResponse) + addrlen, | ||
1514 | GNUNET_TIME_UNIT_SECONDS, | ||
1515 | &send_vcr, | ||
1516 | vcr)) | ||
1517 | { | ||
1518 | GNUNET_break (0); | ||
1519 | GNUNET_free (vcr); | ||
1520 | } | ||
1521 | /* after a PING, we always close the connection */ | ||
1522 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1523 | } | ||
1524 | |||
1525 | |||
1526 | /** | ||
1527 | * Handle PING-message. If the plugin that gave us the message is | ||
1528 | * able to queue the PONG immediately, we only queue one PONG. | ||
1529 | * Otherwise we send at most TWO PONG messages, one via an unconfirmed | ||
1530 | * transport and one via a confirmed transport. Both addresses are | ||
1531 | * selected randomly among those available. | ||
1532 | * | ||
1533 | * @param plugin plugin that gave us the message | ||
1534 | * @param sender claimed sender of the PING | ||
1535 | * @param plugin_context context that might be used to send response | ||
1536 | * @param message the actual message | ||
1537 | */ | ||
1538 | /** | ||
1539 | * We've received a PING from this peer via TCP. | ||
1540 | * Send back our PONG. | ||
1541 | * | ||
1542 | * @param cls closure | ||
1543 | * @param client identification of the client | ||
1544 | * @param message the actual message | ||
1545 | */ | ||
1546 | static void | ||
1547 | handle_tcp_pong (void *cls, | ||
1548 | struct GNUNET_SERVER_Client *client, | ||
1549 | const struct GNUNET_MessageHeader *message) | ||
1550 | { | ||
1551 | struct Plugin *plugin = cls; | ||
1552 | const struct ValidationChallengeResponse *vcr; | ||
1553 | struct GNUNET_PeerIdentity peer; | ||
1554 | char *sender_addr; | ||
1555 | size_t addrlen; | ||
1556 | |||
1557 | #if DEBUG_TRANSPORT | ||
1558 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
1559 | "Processing PONG\n"); | ||
1560 | #endif | ||
1561 | if (ntohs(message->size) < sizeof(struct ValidationChallengeResponse)) | ||
1562 | { | ||
1563 | GNUNET_break_op (0); | ||
1564 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1565 | return; | ||
1566 | } | ||
1567 | addrlen = ntohs(message->size) - sizeof(struct ValidationChallengeResponse); | ||
1568 | vcr = (const struct ValidationChallengeResponse *) message; | ||
1569 | if ( (ntohs(vcr->purpose.size) != | ||
1570 | sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + | ||
1571 | sizeof (uint32_t) + | ||
1572 | sizeof ( struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + | ||
1573 | addrlen)) | ||
1574 | { | ||
1575 | GNUNET_break_op (0); | ||
1576 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1577 | return; | ||
1578 | } | ||
1579 | if (GNUNET_OK != | ||
1580 | GNUNET_CRYPTO_rsa_verify | ||
1581 | (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING, | ||
1582 | &vcr->purpose, | ||
1583 | &vcr->signature, | ||
1584 | &vcr->signer)) | ||
1585 | { | ||
1586 | GNUNET_break_op (0); | ||
1587 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1588 | return; | ||
1589 | } | ||
1590 | GNUNET_CRYPTO_hash (&vcr->signer, | ||
1591 | sizeof( struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1592 | &peer.hashPubKey); | ||
1593 | sender_addr = GNUNET_strdup (GNUNET_a2s((const struct sockaddr*) &vcr[1], | ||
1594 | addrlen)); | ||
1595 | plugin->env->notify_validation (plugin->env->cls, | ||
1596 | "tcp", | ||
1597 | &peer, | ||
1598 | ntohs(vcr->challenge), | ||
1599 | sender_addr); | ||
1600 | GNUNET_free (sender_addr); | ||
1601 | /* after a PONG, we always close the connection */ | ||
1602 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1603 | } | ||
1604 | |||
1605 | |||
1606 | /** | ||
1349 | * We've received a welcome from this peer via TCP. | 1607 | * We've received a welcome from this peer via TCP. |
1350 | * Possibly create a fresh client record and send back | 1608 | * Possibly create a fresh client record and send back |
1351 | * our welcome. | 1609 | * our welcome. |
@@ -1562,6 +1820,8 @@ handle_tcp_data (void *cls, | |||
1562 | * Handlers for the various TCP messages. | 1820 | * Handlers for the various TCP messages. |
1563 | */ | 1821 | */ |
1564 | static struct GNUNET_SERVER_MessageHandler my_handlers[] = { | 1822 | static struct GNUNET_SERVER_MessageHandler my_handlers[] = { |
1823 | {&handle_tcp_ping, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING, 0}, | ||
1824 | {&handle_tcp_pong, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG, 0}, | ||
1565 | {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, 0}, | 1825 | {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, 0}, |
1566 | {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA, 0}, | 1826 | {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA, 0}, |
1567 | {NULL, NULL, 0, 0} | 1827 | {NULL, NULL, 0, 0} |
@@ -1728,7 +1988,7 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
1728 | plugin->statistics = NULL; | 1988 | plugin->statistics = NULL; |
1729 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 1989 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
1730 | api->cls = plugin; | 1990 | api->cls = plugin; |
1731 | api->send_to = &tcp_plugin_send_to; | 1991 | api->validate = &tcp_plugin_validate; |
1732 | api->send = &tcp_plugin_send; | 1992 | api->send = &tcp_plugin_send; |
1733 | api->cancel = &tcp_plugin_cancel; | 1993 | api->cancel = &tcp_plugin_cancel; |
1734 | api->address_pretty_printer = &tcp_plugin_address_pretty_printer; | 1994 | api->address_pretty_printer = &tcp_plugin_address_pretty_printer; |
diff --git a/src/transport/plugin_transport_template.c b/src/transport/plugin_transport_template.c index 496e2cf78..bce4bbc52 100644 --- a/src/transport/plugin_transport_template.c +++ b/src/transport/plugin_transport_template.c | |||
@@ -132,33 +132,29 @@ struct Plugin | |||
132 | 132 | ||
133 | 133 | ||
134 | /** | 134 | /** |
135 | * Function that can be used by the transport service to transmit | 135 | * Function that can be used by the transport service to validate that |
136 | * a message using the plugin using a fresh connection (even if | 136 | * another peer is reachable at a particular address (even if we |
137 | * we already have a connection to this peer, this function is | 137 | * already have a connection to this peer, this function is required |
138 | * required to establish a new one). | 138 | * to establish a new one). |
139 | * | 139 | * |
140 | * @param cls closure | 140 | * @param cls closure |
141 | * @param target who should receive this message | 141 | * @param target who should receive this message |
142 | * @param priority how important is the message | 142 | * @param challenge challenge code to use |
143 | * @param msg1 first message to transmit | ||
144 | * @param msg2 second message to transmit (can be NULL) | ||
145 | * @param timeout how long until we give up? | ||
146 | * @param addr the address | ||
147 | * @param addrlen length of the address | 143 | * @param addrlen length of the address |
148 | * @return non-null session if the transmission has been scheduled | 144 | * @param addr the address |
149 | * NULL if the address format is invalid | 145 | * @param timeout how long should we try to transmit these? |
146 | * @return GNUNET_OK if the transmission has been scheduled | ||
150 | */ | 147 | */ |
151 | static void * | 148 | static int |
152 | template_plugin_send_to (void *cls, | 149 | template_plugin_validate (void *cls, |
153 | const struct GNUNET_PeerIdentity *target, | 150 | const struct GNUNET_PeerIdentity *target, |
154 | unsigned int priority, | 151 | uint32_t challenge, |
155 | const struct GNUNET_MessageHeader *msg1, | 152 | struct GNUNET_TIME_Relative timeout, |
156 | const struct GNUNET_MessageHeader *msg2, | 153 | const void *addr, |
157 | struct GNUNET_TIME_Relative timeout, | 154 | size_t addrlen) |
158 | const void *addr, size_t addrlen) | ||
159 | { | 155 | { |
160 | // FIXME | 156 | // FIXME |
161 | return NULL; | 157 | return GNUNET_SYSERR; |
162 | } | 158 | } |
163 | 159 | ||
164 | 160 | ||
@@ -311,7 +307,7 @@ gnunet_plugin_transport_template_init (void *cls) | |||
311 | plugin->statistics = NULL; | 307 | plugin->statistics = NULL; |
312 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 308 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
313 | api->cls = plugin; | 309 | api->cls = plugin; |
314 | api->send_to = &template_plugin_send_to; | 310 | api->validate = &template_plugin_validate; |
315 | api->send = &template_plugin_send; | 311 | api->send = &template_plugin_send; |
316 | api->cancel = &template_plugin_cancel; | 312 | api->cancel = &template_plugin_cancel; |
317 | api->address_pretty_printer = &template_plugin_address_pretty_printer; | 313 | api->address_pretty_printer = &template_plugin_address_pretty_printer; |