From 6d9473069ba17a37dab71d5e33088eb62bb74f5d Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 2 Mar 2017 16:14:52 -0500 Subject: [PATCH] Many fixes around secio --- conn/dialer.c | 28 ++++++- conn/tcp_transport_dialer.c | 44 ++-------- conn/transport_dialer.c | 4 +- crypto/aes.c | 20 +++++ include/libp2p/conn/dialer.h | 26 +++++- include/libp2p/conn/transport_dialer.h | 6 +- include/libp2p/crypto/aes.h | 11 +++ include/libp2p/crypto/ephemeral.h | 2 +- include/libp2p/peer/peer.h | 4 +- include/libp2p/secio/secio.h | 4 +- include/libp2p/utils/multiaddress.h | 13 +++ net/multistream.c | 8 +- net/socket.c | 32 ++++--- secio/exchange.c | 2 +- secio/propose.c | 14 ++-- secio/secio.c | 112 ++++++++++++++++--------- test/test_conn.h | 54 ++++++++++-- test/test_multistream.h | 12 ++- test/test_secio.h | 14 ++-- test/testit.c | 2 + utils/Makefile | 4 +- utils/multiaddress.c | 38 +++++++++ 22 files changed, 317 insertions(+), 137 deletions(-) create mode 100644 crypto/aes.c create mode 100644 include/libp2p/crypto/aes.h create mode 100644 include/libp2p/utils/multiaddress.h create mode 100644 utils/multiaddress.c diff --git a/conn/dialer.c b/conn/dialer.c index dceb261..56899fa 100644 --- a/conn/dialer.c +++ b/conn/dialer.c @@ -8,6 +8,8 @@ #include "libp2p/conn/transport_dialer.h" #include "libp2p/crypto/key.h" #include "libp2p/utils/linked_list.h" +#include "libp2p/utils/multiaddress.h" +#include "libp2p/net/multistream.h" struct TransportDialer* libp2p_conn_tcp_transport_dialer_new(); @@ -60,14 +62,38 @@ void libp2p_conn_dialer_free(struct Dialer* in) { /** * Retrieve a Connection struct from the dialer + * NOTE: This should no longer be used. _get_stream should + * be used instead (which calls this method internally). * @param dialer the dialer to use * @param muiltiaddress who to connect to * @returns a Connection, or NULL */ -struct Connection* libp2p_conn_dialer_get_connection(struct Dialer* dialer, struct MultiAddress* multiaddress) { +struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress) { struct Connection* conn = libp2p_conn_transport_dialer_get(dialer->transport_dialers, multiaddress); if (conn == NULL) { conn = dialer->fallback_dialer->dial(dialer->fallback_dialer, multiaddress); } return conn; } + +/** + * return a Stream that is already set up to use the passed in protocol + * @param dialer the dialer to use + * @param multiaddress the host to dial + * @param protocol the protocol to use (right now only 'multistream' is supported) + * @returns the ready-to-use stream + */ +struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct MultiAddress* multiaddress, const char* protocol) { + // this is a shortcut for now. Other protocols will soon be implemented + if (strcmp(protocol, "multistream") != 0) + return NULL; + char* ip; + int port; + if (!libp2p_utils_multiaddress_parse_ip4_tcp(multiaddress, &ip, &port)) { + free(ip); + return NULL; + } + struct Stream* stream = libp2p_net_multistream_connect(ip, port); + free(ip); + return stream; +} diff --git a/conn/tcp_transport_dialer.c b/conn/tcp_transport_dialer.c index 3b0dc7e..0ae1133 100644 --- a/conn/tcp_transport_dialer.c +++ b/conn/tcp_transport_dialer.c @@ -6,43 +6,13 @@ #include "libp2p/net/p2pnet.h" #include "libp2p/conn/connection.h" #include "libp2p/conn/transport_dialer.h" +#include "libp2p/utils/multiaddress.h" /** * An implementation of a tcp transport dialer */ - -struct TcpIp { - char* ip; - int port; -}; - -struct TcpIp* libp2p_conn_parse_ip_multiaddress(struct MultiAddress* addr) { - struct TcpIp* out = (struct TcpIp*)malloc(sizeof(struct TcpIp)); - char* address = malloc(strlen(addr->string) + 1); - strcpy(address, addr->string); - char* tok = strtok(address, "/"); - int pos = 0; - while (tok != NULL) { - switch (pos) { - case 1: { - out->ip = malloc(strlen(tok) + 1); - strcpy(out->ip, tok); - break; - } - case 3: { - out->port = strtol(tok, NULL, 10); - break; - } - } - tok = strtok(NULL, "/"); - pos++; - } - //TODO: do a better job of parsing the results - return out; -} - -int libp2p_conn_tcp_can_handle(struct MultiAddress* addr) { +int libp2p_conn_tcp_can_handle(const struct MultiAddress* addr) { return 1; } @@ -59,13 +29,15 @@ int libp2p_conn_tcp_write(const struct Connection* connection, const char* in, s return bytes == num_bytes; } -struct Connection* libp2p_conn_tcp_dial(struct TransportDialer* transport_dialer, struct MultiAddress* addr) { +struct Connection* libp2p_conn_tcp_dial(const struct TransportDialer* transport_dialer, const struct MultiAddress* addr) { struct Connection* conn = (struct Connection*) malloc(sizeof(struct Connection*)); conn->socket_handle = socket_open4(); - struct TcpIp* results = libp2p_conn_parse_ip_multiaddress(addr); - struct hostent* host = gethostbyname(results->ip); + char* ip; + int port; + libp2p_utils_multiaddress_parse_ip4_tcp(addr, &ip, &port); + struct hostent* host = gethostbyname(ip); struct in_addr** addr_list = (struct in_addr**)host->h_addr_list; - socket_connect4(conn->socket_handle, (*addr_list[0]).s_addr, results->port); + socket_connect4(conn->socket_handle, (*addr_list[0]).s_addr, port); conn->read = libp2p_conn_tcp_read; conn->write = libp2p_conn_tcp_write; return conn; diff --git a/conn/transport_dialer.c b/conn/transport_dialer.c index 2c59696..88fb044 100644 --- a/conn/transport_dialer.c +++ b/conn/transport_dialer.c @@ -33,8 +33,8 @@ void libp2p_conn_transport_dialer_free(struct TransportDialer* in) { * @param multiaddr the address * @returns a connection, or NULL if no appropriate dialer was found */ -struct Connection* libp2p_conn_transport_dialer_get(struct Libp2pLinkedList* transport_dialers, struct MultiAddress* multiaddr) { - struct Libp2pLinkedList* current = transport_dialers; +struct Connection* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr) { + const struct Libp2pLinkedList* current = transport_dialers; struct TransportDialer* t_dialer = NULL; while (current != NULL) { t_dialer = (struct TransportDialer*)current->item; diff --git a/crypto/aes.c b/crypto/aes.c new file mode 100644 index 0000000..e719ed3 --- /dev/null +++ b/crypto/aes.c @@ -0,0 +1,20 @@ +#include "mbedtls/aes.h" + +/** + * Encrypt a block of text + * @param key the aes key + * @param iv the random part of encryption + * @param input the text to encrypt + * @param input_size the length of the array + * @param output where the output will be placed + * @param output_size the length of the memory allocated for output + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_aes_encrypt(char* key, char* iv, char* input, size_t input_size, unsigned char* output, size_t* output_size) { + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_enc(&ctx, key, 256); + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 24, iv, input, output); + //TODO Implement this method + return 0; +} diff --git a/include/libp2p/conn/dialer.h b/include/libp2p/conn/dialer.h index c7c66d6..0d25550 100644 --- a/include/libp2p/conn/dialer.h +++ b/include/libp2p/conn/dialer.h @@ -1,7 +1,12 @@ /*** * A local dialer. Uses MultiAddr to figure out the best way to * connect to a client, then returns an open Connection that can be - * closed, read from and written to. + * closed, read from and written to. The normal procedure is as follows: + * 1) Create a Dialer struct, with the required information about the local host + * 2) Call _get_connection to create the connection with a specific host + * NOTE: 1 Dialer could be used to create all connections, saving time and resources + * if it is not too difficult to pass it around. The struct has enough information to + * build connections that negotiate many protocols */ #include "libp2p/crypto/key.h" @@ -29,11 +34,16 @@ struct Dialer { /** * Create a Dialer with the specified local information + * NOTE: This fills in the fallback_dialer too + * @param peer_id the local PeerID + * @param private_key the local private key + * @returns a new Dialer struct */ struct Dialer* libp2p_conn_dialer_new(char* peer_id, struct PrivateKey* private_key); /** - * free resources from the Dialer + * free resources from the Dialer struct + * @param in the Dialer struct to relieve of their resources */ void libp2p_conn_dialer_free(struct Dialer* in); @@ -43,4 +53,14 @@ void libp2p_conn_dialer_free(struct Dialer* in); * @param muiltiaddress who to connect to * @returns a Connection, or NULL */ -struct Connection* libp2p_conn_dialer_get_connection(struct Dialer* dialer, struct MultiAddress* multiaddress); +struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress); + +/** + * return a Stream that is already set up to use the passed in protocol + * @param dialer the dialer to use + * @param multiaddress the host to dial + * @param protocol the protocol to use (right now only 'multistream' is supported) + * @returns the ready-to-use stream + */ +struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct MultiAddress* multiaddress, const char* protocol); + diff --git a/include/libp2p/conn/transport_dialer.h b/include/libp2p/conn/transport_dialer.h index b75f5a1..d767005 100644 --- a/include/libp2p/conn/transport_dialer.h +++ b/include/libp2p/conn/transport_dialer.h @@ -6,11 +6,11 @@ struct TransportDialer { char* peer_id; struct PrivateKey* private_key; - int (*can_handle)(struct MultiAddress* multiaddr); - struct Connection* (*dial)(struct TransportDialer* transport_dialer, struct MultiAddress* multiaddr); + int (*can_handle)(const struct MultiAddress* multiaddr); + struct Connection* (*dial)(const struct TransportDialer* transport_dialer, const struct MultiAddress* multiaddr); }; struct TransportDialer* libp2p_conn_transport_dialer_new(char* peer_id, struct PrivateKey* private_key); void libp2p_conn_transport_dialer_free(struct TransportDialer* in); -struct Connection* libp2p_conn_transport_dialer_get(struct Libp2pLinkedList* transport_dialers, struct MultiAddress* multiaddr); +struct Connection* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr); diff --git a/include/libp2p/crypto/aes.h b/include/libp2p/crypto/aes.h new file mode 100644 index 0000000..660c891 --- /dev/null +++ b/include/libp2p/crypto/aes.h @@ -0,0 +1,11 @@ +#pragma once + +/** + * Encrypt a block of text + * @param input the text to encrypt + * @param input_size the length of the array + * @param output where the output will be placed + * @param output_size the length of the memory allocated for output + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_aes_encrypt(char* input, size_t input_size, unsigned char* output, size_t& output_size); diff --git a/include/libp2p/crypto/ephemeral.h b/include/libp2p/crypto/ephemeral.h index 923cd9b..3c02f3e 100644 --- a/include/libp2p/crypto/ephemeral.h +++ b/include/libp2p/crypto/ephemeral.h @@ -11,7 +11,7 @@ struct StretchedKey { size_t iv_size; char* cipher_key; size_t cipher_size; - char* mac_key; + unsigned char* mac_key; size_t mac_size; }; diff --git a/include/libp2p/peer/peer.h b/include/libp2p/peer/peer.h index 8b161a9..120f029 100644 --- a/include/libp2p/peer/peer.h +++ b/include/libp2p/peer/peer.h @@ -14,8 +14,8 @@ enum ConnectionType { }; struct Libp2pPeer { - char* id; // protobuf field 1 - size_t id_size; + char* id; // protobuf field 1; the ID (aka peer id) of the peer + size_t id_size; // the length of id struct Libp2pLinkedList* addr_head; // protobuf field 2 of multiaddr bytes (repeatable) (stored here as a struct MultiAddr) enum ConnectionType connection_type; // protobuf field 3 (a varint) }; diff --git a/include/libp2p/secio/secio.h b/include/libp2p/secio/secio.h index c36e5d4..4502a53 100644 --- a/include/libp2p/secio/secio.h +++ b/include/libp2p/secio/secio.h @@ -15,7 +15,7 @@ struct SecureSession { int port; enum IPTrafficType traffic_type; // once the connection is established - int socket_descriptor; + struct Stream* stream; struct PublicKey remote_key; char* remote_peer_id; // filled in during negotiations @@ -28,6 +28,8 @@ struct SecureSession { size_t shared_key_size; char nonce[16]; struct StretchedKey* stretched_key; + unsigned char* mac; + size_t mac_size; }; /*** diff --git a/include/libp2p/utils/multiaddress.h b/include/libp2p/utils/multiaddress.h new file mode 100644 index 0000000..274d946 --- /dev/null +++ b/include/libp2p/utils/multiaddress.h @@ -0,0 +1,13 @@ +#pragma once +#include "multiaddr/multiaddr.h" + +/** + * This is a hack to get ip4/tcp working + * TODO: this should be moved further down in the networking stack and generified for different multiaddresses + * This makes too many assumptions + * @param address the multiaddress to parse + * @param ip the first IP address in the multiaddress + * @param port the first port in the multiaddress + * @returns true(1) on success, false(0) on failure + */ +int libp2p_utils_multiaddress_parse_ip4_tcp(const struct MultiAddress* address, char** ip, int* port); diff --git a/net/multistream.c b/net/multistream.c index 213099b..5884cf6 100644 --- a/net/multistream.c +++ b/net/multistream.c @@ -128,15 +128,15 @@ struct Stream* libp2p_net_multistream_connect(const char* hostname, int port) { if (stream == NULL) goto exit; - num_bytes = libp2p_net_multistream_write(stream, (unsigned char*)protocol_buffer, strlen(protocol_buffer)); - if (num_bytes <= 0) - goto exit; - // try to receive the protocol id return_result = libp2p_net_multistream_read(stream, &results, &results_size); if (return_result == 0 || results_size < 1) goto exit; + num_bytes = libp2p_net_multistream_write(stream, (unsigned char*)protocol_buffer, strlen(protocol_buffer)); + if (num_bytes <= 0) + goto exit; + if (strstr((char*)results, "multistream") == NULL) goto exit; diff --git a/net/socket.c b/net/socket.c index f6ad619..0d9dd11 100644 --- a/net/socket.c +++ b/net/socket.c @@ -184,19 +184,27 @@ ssize_t socket_write_size(int s, unsigned long size, int flags) { */ uint32_t hostname_to_ip(const char* hostname) { - struct hostent *he; - struct in_addr **addr_list; + struct sockaddr_in sa; + int result = inet_pton(AF_INET, hostname, &(sa.sin_addr)); + if (result != 0) { + // an ip address was passed in instead of a hostname + return sa.sin_addr.s_addr; + } else { + // it is probably an actual host name and not just an ip address + struct hostent *he; + struct in_addr **addr_list; - if ( (he = gethostbyname( hostname ) ) == NULL) - { - // get the host info - herror("gethostbyname"); - return 1; - } + if ( (he = gethostbyname( hostname ) ) == NULL) + { + // get the host info + herror("gethostbyname"); + return 1; + } - addr_list = (struct in_addr **) he->h_addr_list; - if ((*addr_list) == NULL) - return 0; + addr_list = (struct in_addr **) he->h_addr_list; + if ((*addr_list) == NULL) + return 0; - return addr_list[0]->s_addr; + return addr_list[0]->s_addr; + } } diff --git a/secio/exchange.c b/secio/exchange.c index 00fd5bd..1d98b2e 100644 --- a/secio/exchange.c +++ b/secio/exchange.c @@ -71,7 +71,7 @@ int libp2p_secio_exchange_protobuf_decode(unsigned char* buffer, size_t buffer_l size_t pos = 0; int retVal = 0; - if (libp2p_secio_exchange_new(out) == 0) + if ( (*out = libp2p_secio_exchange_new()) == NULL) goto exit; while(pos < buffer_length) { diff --git a/secio/propose.c b/secio/propose.c index 784e305..2ee1520 100644 --- a/secio/propose.c +++ b/secio/propose.c @@ -78,11 +78,11 @@ int libp2p_secio_propose_protobuf_encode(struct Propose* in, unsigned char* buff return 0; *bytes_written += bytes_used; // exchanges - if (!protobuf_encode_length_delimited(4, secio_propose_message_fields[3], in->exchanges, in->exchanges_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) + if (!protobuf_encode_length_delimited(3, secio_propose_message_fields[2], in->exchanges, in->exchanges_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) return 0; *bytes_written += bytes_used; // ciphers - if (!protobuf_encode_length_delimited(3, secio_propose_message_fields[2], in->ciphers, in->ciphers_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) + if (!protobuf_encode_length_delimited(4, secio_propose_message_fields[3], in->ciphers, in->ciphers_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) return 0; *bytes_written += bytes_used; // hashes @@ -131,11 +131,11 @@ int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t buffer_le got_something = 1; break; case (3): // exchanges - if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0) - goto exit; - pos += bytes_read; - got_something = 1; - break; + if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0) + goto exit; + pos += bytes_read; + got_something = 1; + break; case (4): // ciphers if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->ciphers), &((*out)->ciphers_size), &bytes_read) == 0) goto exit; diff --git a/secio/secio.c b/secio/secio.c index 83595ce..c69da8c 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -29,7 +29,7 @@ struct SecureSession* libp2p_secio_secure_session_new() { struct SecureSession* ss = (struct SecureSession*) malloc(sizeof(struct SecureSession)); if (ss == NULL) return NULL; - ss->socket_descriptor = -1; + ss->stream = NULL; return ss; } @@ -291,8 +291,10 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s if (num_needed > hash_size) num_needed = hash_size; // combine current_hash with first_seed - if (temp != NULL) + if (temp != NULL) { free(temp); + temp = NULL; + } seed_size = secret_size + strlen(first_seed) + hash_size; temp = malloc(seed_size); memcpy(temp, secret, secret_size); @@ -305,6 +307,7 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s num_filled += num_needed; // redo the hashes by adding the secret to the current hash free(temp); + temp = NULL; seed_size = secret_size + hash_size; temp = malloc(seed_size); memcpy(temp, secret, secret_size); @@ -336,6 +339,8 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s memcpy(k2->mac_key, temp, k2->mac_size); temp += k2->mac_size; + temp = NULL; + retVal = 1; // cleanup @@ -362,8 +367,35 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s } int libp2p_secio_make_mac_and_cipher(struct SecureSession* session) { - // TODO: Implement this method - return 0; + // mac + int (*mac_func)(const char*, size_t, unsigned char*); + if (strcmp(session->chosen_hash, "SHA1") == 0) { + session->stretched_key->mac_size = 40; + mac_func = libp2p_crypto_hashing_sha1; + } else if (strcmp(session->chosen_hash, "SHA512") == 0) { + session->stretched_key->mac_size = 32; + mac_func = libp2p_crypto_hashing_sha512; + } else if (strcmp(session->chosen_hash, "SHA256") == 0) { + session->stretched_key->mac_size = 16; + mac_func = libp2p_crypto_hashing_sha256; + } else { + return 0; + } + session->stretched_key->mac_key = malloc(session->stretched_key->mac_size); + mac_func(session->stretched_key->cipher_key, session->stretched_key->cipher_size, session->stretched_key->mac_key); + + // block cipher + if (strcmp(session->chosen_cipher, "AES-128") == 0) { + + } else if (strcmp(session->chosen_cipher, "AES-256") == 0) { + + } else if (strcmp(session->chosen_cipher, "Blowfish") == 0) { + + } else { + return 0; + } + + return 1; } int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size_t data_length) { @@ -377,7 +409,7 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size int written = 0; int written_this_time = 0; do { - written_this_time = socket_write(session->socket_descriptor, &size_as_char[written], left, 0); + written_this_time = socket_write(*((int*)session->stream->socket_descriptor), &size_as_char[written], left, 0); if (written_this_time < 0) { written_this_time = 0; if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { @@ -393,7 +425,7 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size left = data_length; written = 0; do { - written_this_time = socket_write(session->socket_descriptor, (char*)&bytes[written], left, 0); + written_this_time = socket_write(*((int*)session->stream->socket_descriptor), (char*)&bytes[written], left, 0); if (written_this_time < 0) { written_this_time = 0; if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { @@ -420,7 +452,7 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si int read = 0; int read_this_time = 0; do { - read_this_time = socket_read(session->socket_descriptor, &size[read], 1, 0); + read_this_time = socket_read(*((int*)session->stream->socket_descriptor), &size[read], 1, 0); if (read_this_time < 0) { read_this_time = 0; if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { @@ -449,7 +481,7 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si *results = malloc(left); unsigned char* ptr = *results; do { - read_this_time = socket_read(session->socket_descriptor, (char*)&ptr[read], left, 0); + read_this_time = socket_read(*((int*)session->stream->socket_descriptor), (char*)&ptr[read], left, 0); if (read_this_time < 0) { read_this_time = 0; if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { @@ -474,9 +506,6 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si * @returns true(1) on success, false(0) otherwise */ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivateKey* private_key) { - // this needs to be redone - return 0; - /* int retVal = 0; size_t results_size = 0, bytes_written = 0; unsigned char* propose_in_bytes = NULL; // the remote protobuf @@ -504,6 +533,27 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat //TODO: make sure we're not talking to ourself + // prepare the multistream send of the protocol ID + 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_write(local_session->stream, total, protocol_len + propose_out_size); + free(total); + if (bytes_written <= 0) + goto exit; + + // we should get back the secio confirmation + bytes_written = libp2p_net_multistream_read(local_session->stream, &results, &results_size); + if (bytes_written < 5 || strstr((char*)results, "secio") == NULL) + goto exit; + + free(results); + results = NULL; + results_size = 0; + // generate 16 byte nonce if (!libp2p_secio_generate_nonce(&local_session->nonce[0], 16)) { goto exit; @@ -549,30 +599,11 @@ 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_write(local_session->socket_descriptor, total, protocol_len + propose_out_size); - free(total); - if (bytes_written <= 0) + bytes_written = libp2p_secio_write(local_session, propose_out_bytes, propose_out_size); + if (bytes_written < propose_out_size) 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); if (bytes_written <= 0) @@ -587,6 +618,11 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat // generate their peer id libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id); + // receive Exchange packet + bytes_written = libp2p_secio_read(local_session, &results, &results_size); + if (bytes_written == 0) + goto exit; + libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in); // negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work // first determine order @@ -653,12 +689,6 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat free(exchange_out_protobuf); exchange_out_protobuf = NULL; - // receive Exchange packet - bytes_written = libp2p_secio_read(local_session, &results, &results_size); - if (bytes_written == 0) - goto exit; - libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in); - // parse and verify remote_session.ephemeral_public_key = exchange_in->epubkey; remote_session.ephemeral_public_key_size = exchange_in->epubkey_size; @@ -669,8 +699,9 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size); libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size); libp2p_utils_vector_add(char_buffer, remote_session.ephemeral_public_key, remote_session.ephemeral_public_key_size); - if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature)) - goto exit; + // TODO: signature verification + //if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature)) + // goto exit; libp2p_utils_vector_free(char_buffer); char_buffer = NULL; @@ -727,5 +758,4 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat libp2p_secio_propose_free(propose_in); return retVal; - */ } diff --git a/test/test_conn.h b/test/test_conn.h index 2eb724e..14d740a 100644 --- a/test/test_conn.h +++ b/test/test_conn.h @@ -1,6 +1,7 @@ #include #include "libp2p/conn/dialer.h" +#include "libp2p/net/stream.h" #include "test_helper.h" int test_dialer_new() { @@ -42,15 +43,6 @@ int test_dialer_dial() { if (conn == NULL) goto exit; - if (conn->write(conn, "ping", 4) == 0) - goto exit; - - if (conn->read(conn, &result, &result_size) == 0) - goto exit; - - if (result_size < 4 || strncmp(result, "pong", 4) != 0) - goto exit; - // clean up resources retVal = 1; exit: @@ -63,3 +55,47 @@ int test_dialer_dial() { libp2p_conn_connection_free(conn); return retVal; } + +int test_dialer_dial_multistream() { + int retVal = 0; + char* config_dir = "/home/parallels/.ipfs/config"; + char* destination_string = "/ip4/192.210.179.217/tcp/4001/"; + char* peer_id = NULL; + struct PrivateKey* private_key = NULL; + struct Dialer* dialer = NULL; + struct MultiAddress* destination_address = NULL; + struct Stream* stream = NULL; + char* result = NULL; + size_t result_size = 0; + + test_helper_get_id_from_config(config_dir, &private_key, &peer_id); + if (private_key == NULL) + goto exit; + + dialer = libp2p_conn_dialer_new(peer_id, private_key); + if (dialer == NULL) + goto exit; + + destination_address = multiaddress_new_from_string(destination_string); + if (destination_address == NULL) + goto exit; + + // now try to dial + stream = libp2p_conn_dialer_get_stream(dialer, destination_address, "multistream"); + if (stream == NULL) + goto exit; + + // now ping + + // clean up resources + retVal = 1; + exit: + if (result != NULL) + free(result); + free(peer_id); + multiaddress_free(destination_address); + libp2p_conn_dialer_free(dialer); + libp2p_crypto_private_key_free(private_key); + stream->close(stream); + return retVal; +} diff --git a/test/test_multistream.h b/test/test_multistream.h index 9b2d6c7..a57ec02 100644 --- a/test/test_multistream.h +++ b/test/test_multistream.h @@ -23,12 +23,13 @@ int test_multistream_connect() { } int test_multistream_get_list() { - int retVal = 0, socket_fd = -1; + int retVal = 0; unsigned char* response; size_t response_size; + char* filtered = NULL; struct Stream* stream = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001); - if (socket_fd < 0) + if (*((int*)stream->socket_descriptor) < 0) goto exit; // try to respond something, ls command @@ -42,7 +43,12 @@ int test_multistream_get_list() { if (retVal <= 0) goto exit; - fprintf(stdout, "Response from multistream ls: %s", (char*)response); + filtered = malloc(response_size + 1); + strncpy(filtered, response, response_size); + filtered[response_size] = 0; + + fprintf(stdout, "Response from multistream ls: %s", (char*)filtered); + free(filtered); retVal = 1; diff --git a/test/test_secio.h b/test/test_secio.h index 05fa448..961b713 100644 --- a/test/test_secio.h +++ b/test/test_secio.h @@ -5,16 +5,13 @@ #include "libp2p/net/p2pnet.h" int test_secio_handshake() { - return 0; - /* - * this needs to be redone int retVal = 0; size_t decode_base64_size = 0; unsigned char* decode_base64 = NULL; // this is a base64 encoded private key. It makes it easier to test if it is in base64 form // these were pulled from the GO version of ipfs - char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQCwfp3DpbTP/nD1R+1PcP7nDOV9MEDiLUoNf9cBVhWGefJT0ES81do1COwLXiD/k7gAHJu197F7AfFYKt+NQu6jpCDC/uRtK0M0MpeDGI0LV1oz0rKLTN79zQwKDHFimWCmNyOZRLfR3PF5TgLc0qiFOZw9WwYNJkohu6k6yVMDJiy3l/+K5Vdw9VVyz7mRulXdDvEMxccraKaTvjLAUNFjiqm5Zs3hrcZszuuP2RhcpZU40kuWDtyN9TAEge0NfhS5Fj7GtgQsHWJ4RxTdebHkQmX49ltI/nIw9TxGIVcA50g7eF/3a3zZtkh48JadbHiT2Mfr6SPXl0328gyg7v7tAgMBAAECggEABGlFvCwaFtC/NgI0NjYWyOOToMth88U6AphdYVUreI73tYyRCz81EvpEHAygOoMQqEAOzD+CmhZ0V8XKjJdNq51gjD8eqnPYXCefjdFBRTVLtdvgRocHU8SaNm4VL2ex+LWMGDqVdZNWHbgLbkV9nMbR1t69ifqZA7rTAfsiLgPtneu4kGjrO1nr+uFC0srch2o0stmiqxmcGOrkD9x2kXkw33O8wTSyBp3+STlTOehePuUqEho9BXdT7b2nXC8MNdTCekG9f3oUeKsK9pxH7ZlG3yUOBoM0mEm/N7BrPfJnQbogomUapWOpssWKSz0LCpKuy4El3mFpua0jmd3nAQKBgQDWvVHj44gSecjsrWH/QpMIn8W/ISXfJRxJKrdVBRC5Ey0h3wdLnF6Olz4kuD7KurPOWNR+IKaLzOWxZdX79aQn+oY8lB+UCM+0w1TWJeSWBUYATPtUU4xpKdD6YZ8ksOdgZ4hbn9VD49uu/SJUPVNGV+eHibnvdR+/sFJuHTAb4QKBgQDSaBd1V7z5R6NK8373QNMDHZnSa2qH8uAGvoSuajYGgcpAzDY3aueQFpQS66scrZK6zLQyOQgtyrIg/hKbeP+vV5LGBirzOtAH7Kko5BYeY/SCXOkHBsHhuPGyghqWl6KR2Vj8cjJZFCAiUvoqf3Ws0vW58kp/KgDCnlKGmgQkjQKBgDPYi7/4vG6xhqhWCDYIDdXkNWs7BpjErfqgXJkjWvFERv5Jicpgm5fTvkZBUa/CugzU96DoIy3Xr5FQJATsPtEENIrFvIYSRou/KWl2xqTN6yPBcmDetyTg2rrI/RJvv71P4eU1RtlYVz79kN9D2yo9qQHZZ9H/tkWivZQmaeohAoGAIafa0L9HEAzAdvW6AmzRE/eBKmJaOQLFiO6ipI+CssnCA1lm9rhX7/lcmCYwSbcN+GlUDZCH2WNJ2PMrIMlbBL4aUSidaCipLAtUB6FsVFIiw1N/Rsty6ds+dhJPlHUO4QuGK2NM4GjStwrUz0VyGkHoYmT6O5sJYhgXFUa/kOUCgYEAv1VGeX6EPsFgp+FKM1Q/8MYi7PPpSUI2fqMhnwe36u7UdNYa3Ismmo/ipfCw7DdX5qRcUh44PodTp4Zwp67Bd2KRzEAZmMvIurzclQB7VWUT7pB7yfbO9bjBUVbPTagjiqb30zq9A4kt+B/0MSPxa/Kh8EkgI02Jqh2Q97Ij4sc="; - char* orig_peer_id = "QmYm3WdMQqqQuEyCWmRVNEjtXjhGhyRRNshdvqV7YLGvpA"; + char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQCo+BYd213u8PNHNcnXZ6TcUc7oXEoCtWL12XJEFqAiC7emadkp+WtujmuR993L6uCRPU/+mNXIvetodMQ5GORq0MxsPlKFNuVuqHS4PCdWYYFKeel4QsG17T3XMo72Kxm7/pQ1Dbs6tzWD4Ie4Zsa7ziyffjeak1/EExkFf0AKtj4UdXErNRI5gZhkDnWp6Si117Z2VVTslE+kKXWpLK0RYZ4w8DhhZa+ykt2tleOOJt8ocJ3s3yVZQxOafL1lwA8f10VEEeJLPGKJ1Y7mmW7OJhLmrq9tvdTLhum1H5kdYu/pheCm5b6/NSGKS+XbQztu5zedsKSPHsOlYhxYu3GJAgMBAAECggEAZIz93Fam14Jbw4ymyKDM4q9sSapiAKqgcV0tOoecU6ZVa5qhuPDMlcX7DapLOwZTDRtHd2LMFeGvLUIPY0sE4uvOOrv7r3qznd5xVxG09xqfLgrOfNp9HB5KJr3XhXawocclu0yolpBgMFJ1ca73pNtUgrVBsaLx4mTbBwJqwfQpQb/Xdkrdgc663bwXkSl4vApwhZGzi5CFJ6SFC6l6fMKoteWM1ay5e2VCfxi/1g41EINkrqm+QPWhy11bo21ScozxiFiywcxQ8Huo+I5GDHI5EUfIHP97NSRG24/IDSebxsGTukMdpLmiiwizV7hHP2eDlikHAhxBBAF2GkbkAQKBgQDg69jPHrETvHGlKjlEDE8sYQUrwpmGLHfsfZYqBxcz65jPYFAypG4icIU6f8Uhz9c42jLEBssNPT8LyLl2uY467hZZA2SkeWKS66Vi5wBGTN5qOBWUejhzTx8UzasYroWl/0RqFZhU9Xhwg4YqT9X8jYw5mXyOMLatp/d/Y96p0QKBgQDAUQodQZc9yc7olsmNvbuHZtBA+VndKCokFOuJ6YLRK69AL7y6n6eUjne6JqcEIKDC7vr33ryuOdFI+zNzMsdYykE8xcg2c5itWRqG7EdMxgR1dYLUqGC5ustRM/mmhmRzW8DXy88sS+vM4U84yPKv/rfeKAoYgE722R0kkpQCOQKBgQCKfm63yiw6/NP1YXR1hCbUKsFmWqLxzTvisMngAxG0dKNZPfLj2/+80RAYH0ihMztQ1Hph3dT1x/qkJOqeQk9j1eqI0OANrniWAueJaLfwkbB6MyKGlGNiDRwUUTfDMOM2fWIA+F8eITASB8p7D0GyCu6HIQ1i+HfjogNxu2sFoQKBgE4ZGthiqH6JE6NUiKks4ZjM4clg+WNcSjC45iXtVBiJevO/7w6Cg1VKvcg0piKA9Yfz8Kr0Iv9Fr33JtU0U0+t0xyVc1D94lgnfY2xjS1kcGPdyLx0Y+56xApwJVVqQvP4zxo5bz9gXRLzAyqEuyY87C4QGEoN8p5SK+tC9TanRAoGAbC+uVaBtqRqv3LY16+H58BW8lVfN+8dqtBOWluM2uImB1qL2EbKk0X/OChz3Dgzef5VTox6nHcMyYPwXLirS9aIYPggjdpDTjfbWPxUcwYmIB1U++F/mRk1IeDgl9g7t/OlPMg4snxQGEzMPPDVrj/KeLEKv5x+T5yFZ/y+8xNo="; + char* orig_peer_id = "QmZigcoDKaAafGSwot2tchJarCafxKapoRmnYTrZ69ckjb"; size_t orig_peer_id_size = strlen(orig_peer_id); struct RsaPrivateKey* rsa_private_key = NULL; unsigned char hashed[32] = {0}; @@ -45,12 +42,12 @@ int test_secio_handshake() { if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key)) goto exit; - secure_session.host = "192.210.179.217"; + secure_session.host = "www.jmjatlanta.com"; secure_session.port = 4001; secure_session.traffic_type = TCP; // connect to host - secure_session.socket_descriptor = libp2p_net_multistream_connect(secure_session.host, secure_session.port); - if (secure_session.socket_descriptor == -1) { + secure_session.stream = libp2p_net_multistream_connect(secure_session.host, secure_session.port); + if (*((int*)secure_session.stream->socket_descriptor) == -1) { fprintf(stderr, "test_secio_handshake: Unable to get socket descriptor\n"); goto exit; } @@ -77,5 +74,4 @@ int test_secio_handshake() { if (rsa_private_key != NULL) libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key); return retVal; - */ } diff --git a/test/testit.c b/test/testit.c index 915ddc6..4cafc5b 100644 --- a/test/testit.c +++ b/test/testit.c @@ -40,6 +40,7 @@ const char* names[] = { "test_ephemeral_key_generate", "test_dialer_new", "test_dialer_dial", + "test_dialer_dial_multistream", "test_record_protobuf", "test_record_make_put_record", "test_record_peer_protobuf", @@ -76,6 +77,7 @@ int (*funcs[])(void) = { test_ephemeral_key_generate, test_dialer_new, test_dialer_dial, + test_dialer_dial_multistream, test_record_protobuf, test_record_make_put_record, test_record_peer_protobuf, diff --git a/utils/Makefile b/utils/Makefile index 15f7747..6df187a 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -O0 -Wall -I../include +CFLAGS = -O0 -Wall -I../include -I../../c-multiaddr/include ifdef DEBUG CFLAGS += -g3 @@ -7,7 +7,7 @@ endif LFLAGS = DEPS = -OBJS = string_list.o vector.o linked_list.o +OBJS = string_list.o vector.o linked_list.o multiaddress.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/utils/multiaddress.c b/utils/multiaddress.c new file mode 100644 index 0000000..163603a --- /dev/null +++ b/utils/multiaddress.c @@ -0,0 +1,38 @@ +#include +/** + * A central repository for parsing Multiaddress structs + */ + +#include "libp2p/utils/multiaddress.h" + +/** + * This is a hack to get ip4/tcp working + * TODO: this should be moved further down in the networking stack and generified for different multiaddresses + * This makes too many assumptions + * @param address the multiaddress to parse + * @param ip the first IP address in the multiaddress + * @param port the first port in the multiaddress + * @returns true(1) on success, false(0) on failure + */ +int libp2p_utils_multiaddress_parse_ip4_tcp(const struct MultiAddress* address, char** ip, int* port) { + // the incoming address is not what was expected + if (strncmp(address->string, "/ip4/", 5) != 0) + return 0; + if (strstr(address->string, "/tcp/") == NULL) + return 0; + // ip + char* str = malloc(strlen(address->string)); + if (str == NULL) + return 0; + strcpy(str, &address->string[5]); // gets rid of /ip4/ + char* pos = strchr(str, '/'); + pos[0] = 0; + *ip = malloc(strlen(str) + 1); + strcpy(*ip, str); + free(str); + // port + str = strstr(address->string, "/tcp/"); + str += 5; + *port = atoi(str); + return 1; +}