Added ping functionality to multistream
This commit is contained in:
parent
e4a4226f5d
commit
8139dc9d48
11 changed files with 181 additions and 45 deletions
16
crypto/rsa.c
16
crypto/rsa.c
|
@ -1,6 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libp2p/crypto/key.h"
|
||||
#include "libp2p/crypto/rsa.h"
|
||||
#include "libp2p/crypto/sha256.h"
|
||||
|
||||
|
@ -16,6 +17,21 @@
|
|||
#include "mbedtls/oid.h"
|
||||
#include "mbedtls/pk.h"
|
||||
|
||||
struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in) {
|
||||
struct PrivateKey* out = libp2p_crypto_private_key_new();
|
||||
if (out != NULL) {
|
||||
out->data = (unsigned char*)malloc(in->der_length);
|
||||
if (out->data == NULL) {
|
||||
libp2p_crypto_private_key_free(out);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(out->data, in->der, in->der_length);
|
||||
out->data_size = in->der_length;
|
||||
out->type = KEYTYPE_RSA;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an rsa context and turn it into a der formatted byte stream.
|
||||
* NOTE: the stream starts from the right. So there could be a lot of padding in front.
|
||||
|
|
|
@ -27,6 +27,13 @@ struct RsaPrivateKey {
|
|||
size_t public_key_length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a struct RsaPrivateKey to a struct PrivateKey
|
||||
* @param in the RsaPrivateKey
|
||||
* @returns a struct PrivateKey
|
||||
*/
|
||||
struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in);
|
||||
|
||||
/**
|
||||
* generate a new private key
|
||||
* @param private_key the new private key
|
||||
|
|
|
@ -28,3 +28,27 @@ int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* result
|
|||
* @returns the socket file descriptor of the connection, or -1 on error
|
||||
*/
|
||||
int libp2p_net_multistream_connect(const char* hostname, int port);
|
||||
|
||||
/**
|
||||
* Negotiate the multistream protocol by sending and receiving the protocol id. This is a server side function.
|
||||
* Servers should send the protocol ID, and then expect it back.
|
||||
* @param fd the socket file descriptor
|
||||
* @returns true(1) if the negotiation was successful.
|
||||
*/
|
||||
int libp2p_net_multistream_negotiate(int fd);
|
||||
|
||||
/**
|
||||
* Expect to read a message, and follow its instructions
|
||||
* @param fd the socket file descriptor
|
||||
* @returns true(1) on success, false(0) if not
|
||||
*/
|
||||
int libp2p_net_multistream_handle_message(int fd);
|
||||
|
||||
/**
|
||||
* Connect to a multistream host, and this includes the multistream handshaking.
|
||||
* @param hostname the host
|
||||
* @param port the port
|
||||
* @returns the socket file descriptor of the connection, or -1 on error
|
||||
*/
|
||||
int libp2p_net_multistream_connect(const char* hostname, int port);
|
||||
|
||||
|
|
|
@ -64,3 +64,4 @@ int libp2p_message_protobuf_encode(struct Libp2pMessage* in, unsigned char* buff
|
|||
* @returns true(1) on success, otherwise false(0)
|
||||
*/
|
||||
int libp2p_message_protobuf_decode(unsigned char* buffer, size_t buffer_size, struct Libp2pMessage** out);
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "libp2p/net/p2pnet.h"
|
||||
#include "libp2p/record/message.h"
|
||||
#include "varint.h"
|
||||
|
||||
/***
|
||||
|
@ -135,3 +137,67 @@ int libp2p_net_multistream_connect(const char* hostname, int port) {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
int libp2p_net_multistream_negotiate(int fd) {
|
||||
const char* protocolID = "/multistream/1.0.0\n";
|
||||
char* results;
|
||||
size_t results_length = 0;
|
||||
// send the protocol id
|
||||
if (!libp2p_net_multistream_send(fd, (unsigned char*)protocolID, strlen(protocolID)))
|
||||
return 0;
|
||||
// expect the same back
|
||||
libp2p_net_multistream_receive(fd, &results, &results_length);
|
||||
if (results_length == 0)
|
||||
return 0;
|
||||
if (strncmp(results, protocolID, strlen(protocolID)) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The remote client requested a ping
|
||||
* @param fd the socket file descriptor
|
||||
* @param msg the incoming ping message
|
||||
* @returns true(1) on success, otherwise false(0)
|
||||
*/
|
||||
int libp2p_net_multistream_handle_ping(int fd, struct Libp2pMessage* msg) {
|
||||
// protobuf the message
|
||||
size_t protobuf_size = libp2p_message_protobuf_encode_size(msg);
|
||||
unsigned char protobuf[protobuf_size];
|
||||
libp2p_message_protobuf_encode(msg, &protobuf[0], protobuf_size, &protobuf_size);
|
||||
libp2p_net_multistream_send(fd, protobuf, protobuf_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect to read a message, and follow its instructions
|
||||
* @param fd the socket file descriptor
|
||||
* @returns true(1) on success, false(0) if not
|
||||
*/
|
||||
int libp2p_net_multistream_handle_message(int fd) {
|
||||
int retVal = 0;
|
||||
unsigned char* results = NULL;
|
||||
size_t results_size = 0;
|
||||
struct Libp2pMessage* msg = NULL;
|
||||
// read what they sent
|
||||
libp2p_net_multistream_receive(fd, (char**)&results, &results_size);
|
||||
// unprotobuf it
|
||||
if (!libp2p_message_protobuf_decode(results, results_size, &msg))
|
||||
goto exit;
|
||||
// do what they ask
|
||||
switch (msg->message_type) {
|
||||
case (MESSAGE_TYPE_PING):
|
||||
libp2p_net_multistream_handle_ping(fd, msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// clean up
|
||||
retVal = 1;
|
||||
exit:
|
||||
if (results != NULL)
|
||||
free(results);
|
||||
if (msg != NULL)
|
||||
libp2p_message_free(msg);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
|
21
peer/peer.c
21
peer/peer.c
|
@ -71,15 +71,18 @@ struct Libp2pPeer* libp2p_peer_copy(struct Libp2pPeer* in) {
|
|||
}
|
||||
|
||||
size_t libp2p_peer_protobuf_encode_size(struct Libp2pPeer* in) {
|
||||
// id + connection_type
|
||||
int sz = 11 + in->id_size + 11;
|
||||
// loop through the multiaddresses
|
||||
struct Libp2pLinkedList* current = in->addr_head;
|
||||
while (current != NULL) {
|
||||
// find the length of the MultiAddress converted into bytes
|
||||
struct MultiAddress* data = (struct MultiAddress*)current->item;
|
||||
sz += 11 + data->bsize;
|
||||
current = current->next;
|
||||
int sz = 0;
|
||||
if (in != NULL) {
|
||||
// id + connection_type
|
||||
sz = 11 + in->id_size + 11;
|
||||
// loop through the multiaddresses
|
||||
struct Libp2pLinkedList* current = in->addr_head;
|
||||
while (current != NULL) {
|
||||
// find the length of the MultiAddress converted into bytes
|
||||
struct MultiAddress* data = (struct MultiAddress*)current->item;
|
||||
sz += 11 + data->bsize;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
|
|
@ -82,25 +82,34 @@ int libp2p_message_protobuf_encode(struct Libp2pMessage* in, unsigned char* buff
|
|||
size_t bytes_used = 0;
|
||||
*bytes_written = 0;
|
||||
int retVal = 0;
|
||||
size_t protobuf_size = 0;
|
||||
unsigned char* protobuf = NULL;
|
||||
// field 1
|
||||
retVal = protobuf_encode_varint(1, WIRETYPE_VARINT, in->message_type, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||
if (retVal == 0)
|
||||
return 0;
|
||||
*bytes_written += bytes_used;
|
||||
// field 2
|
||||
retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->key, in->key_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||
if (retVal == 0)
|
||||
return 0;
|
||||
*bytes_written += bytes_used;
|
||||
if (in->key != NULL) {
|
||||
retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->key, in->key_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||
if (retVal == 0)
|
||||
return 0;
|
||||
*bytes_written += bytes_used;
|
||||
}
|
||||
// field 3
|
||||
size_t protobuf_size = libp2p_record_protobuf_encode_size(in->record);
|
||||
unsigned char protobuf[protobuf_size];
|
||||
if (!libp2p_record_protobuf_encode(in->record, protobuf, protobuf_size, &protobuf_size))
|
||||
return 0;
|
||||
retVal = protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, protobuf, protobuf_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||
if (retVal == 0)
|
||||
return 0;
|
||||
*bytes_written += bytes_used;
|
||||
if (in->record != NULL) {
|
||||
protobuf_size = libp2p_record_protobuf_encode_size(in->record);
|
||||
protobuf = (unsigned char*) malloc(protobuf_size);
|
||||
if (!libp2p_record_protobuf_encode(in->record, protobuf, protobuf_size, &protobuf_size)) {
|
||||
free(protobuf);
|
||||
return 0;
|
||||
}
|
||||
retVal = protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, protobuf, protobuf_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
||||
free(protobuf);
|
||||
if (retVal == 0)
|
||||
return 0;
|
||||
*bytes_written += bytes_used;
|
||||
}
|
||||
// field 8 (repeated)
|
||||
struct Libp2pLinkedList* current = in->closer_peer_head;
|
||||
while (current != NULL) {
|
||||
|
|
|
@ -97,11 +97,14 @@ int libp2p_record_protobuf_encode(const struct Libp2pRecord* in, unsigned char*
|
|||
* @returns the approximate number of bytes required
|
||||
*/
|
||||
size_t libp2p_record_protobuf_encode_size(const struct Libp2pRecord* in) {
|
||||
size_t retVal = 11 + in->key_size;
|
||||
retVal += 11 + in->value_size;
|
||||
retVal += 11 + in->author_size;
|
||||
retVal += 11 + in->signature_size;
|
||||
retVal += 11 + in->time_received_size;
|
||||
size_t retVal = 0;
|
||||
if (in != NULL) {
|
||||
retVal = 11 + in->key_size;
|
||||
retVal += 11 + in->value_size;
|
||||
retVal += 11 + in->author_size;
|
||||
retVal += 11 + in->signature_size;
|
||||
retVal += 11 + in->time_received_size;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -499,21 +499,6 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
|
|||
char* remote_peer_id = NULL;
|
||||
struct EphemeralPrivateKey* e_private_key = NULL;
|
||||
|
||||
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
|
||||
|
||||
bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, protocol, strlen((char*)protocol));
|
||||
if (bytes_written <= 0)
|
||||
goto exit;
|
||||
|
||||
// we should get back the secio confirmation
|
||||
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
|
||||
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
|
||||
goto exit;
|
||||
|
||||
free(results);
|
||||
results = NULL;
|
||||
results_size = 0;
|
||||
|
||||
//TODO: make sure we're not talking to ourself
|
||||
|
||||
// generate 16 byte nonce
|
||||
|
@ -561,9 +546,31 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
|
|||
if (libp2p_secio_propose_protobuf_encode(propose_out, propose_out_bytes, propose_out_size, &propose_out_size) == 0)
|
||||
goto exit;
|
||||
|
||||
// prepare the multistream send
|
||||
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
|
||||
int protocol_len = strlen((char*)protocol);
|
||||
unsigned char* total = malloc(protocol_len + propose_out_size);
|
||||
memcpy(total, protocol, protocol_len);
|
||||
memcpy(&total[protocol_len], propose_out_bytes, propose_out_size);
|
||||
|
||||
bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, total, protocol_len + propose_out_size);
|
||||
free(total);
|
||||
if (bytes_written <= 0)
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
bytes_written = libp2p_secio_write(local_session, propose_out_bytes, propose_out_size);
|
||||
if (bytes_written < propose_out_size)
|
||||
goto exit;
|
||||
*/
|
||||
// we should get back the secio confirmation
|
||||
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
|
||||
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
|
||||
goto exit;
|
||||
|
||||
free(results);
|
||||
results = NULL;
|
||||
results_size = 0;
|
||||
|
||||
// now receive the proposal from the new connection
|
||||
bytes_written = libp2p_secio_read(local_session, &propose_in_bytes, &propose_in_size);
|
||||
|
|
|
@ -42,7 +42,7 @@ int test_secio_handshake() {
|
|||
if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key))
|
||||
goto exit;
|
||||
|
||||
secure_session.host = "10.0.1.9";
|
||||
secure_session.host = "192.210.179.217";
|
||||
secure_session.port = 4001;
|
||||
secure_session.traffic_type = TCP;
|
||||
// connect to host
|
||||
|
|
|
@ -34,7 +34,7 @@ const char* names[] = {
|
|||
//"test_crypto_rsa_sign",
|
||||
"test_crypto_encoding_base32_encode",
|
||||
"test_protobuf_private_key",
|
||||
//"test_secio_handshake",
|
||||
"test_secio_handshake",
|
||||
"test_multistream_connect",
|
||||
"test_multistream_get_list",
|
||||
"test_ephemeral_key_generate",
|
||||
|
@ -70,7 +70,7 @@ int (*funcs[])(void) = {
|
|||
//test_crypto_rsa_sign,
|
||||
test_crypto_encoding_base32_encode,
|
||||
test_protobuf_private_key,
|
||||
//test_secio_handshake,
|
||||
test_secio_handshake,
|
||||
test_multistream_connect,
|
||||
test_multistream_get_list,
|
||||
test_ephemeral_key_generate,
|
||||
|
|
Loading…
Reference in a new issue