Commit 33f1a37d authored by xpetrak2's avatar xpetrak2
Browse files

Peer representation created

parent 99a8e65d
......@@ -15,7 +15,8 @@ src_coincerd_SOURCES = \
src/log.c src/log.h \
src/neighbours.c src/neighbours.h \
src/p2p.c src/p2p.h \
src/paths.c src/paths.h
src/paths.c src/paths.h \
src/peers.c src/peers.h
src_coincerd_CFLAGS = $(AM_CFLAGS) $(JANSSON_CFLAGS) $(LIBEVENT_CFLAGS) $(LIBSODIUM_CFLAGS)
src_coincerd_LDADD = $(AM_LDADD) $(JANSSON_LIBS) $(LIBEVENT_LIBS) $(LIBSODIUM_LIBS)
......
Coincer
=======
# Coincer
## Terminology
- Host: A device that is possibly connected to the Coincer network
- Identifier: The public key of a cryptographic keypair
- Identity: A peer representation that we own (identifier + its corresponding secret key)
- Neighbour: A host that we are interconnected with
- Nonce: Ever-increasing integer tied to every message sent for message repetiton or replay attack detection
- Peer: The Coincer network participant
......@@ -25,31 +25,39 @@
#include "log.h"
#include "neighbours.h"
#include "p2p.h"
#include "peers.h"
/** The time interval in seconds between loop_update_long calls. */
#define UPDATE_TIME_LONG 60
/** The time interval in seconds between loop_update_short calls. */
#define UPDATE_TIME_SHORT 10
static void loop_update_long(evutil_socket_t fd __attribute__((unused)),
short events __attribute__((unused)),
void *ctx);
static void loop_update_short(evutil_socket_t fd __attribute__((unused)),
short events __attribute__((unused)),
void *ctx);
static void remove_stale_records(global_state_t *global_state);
static void signal_cb(evutil_socket_t signal __attribute__((unused)),
short events __attribute__((unused)),
void *ctx);
/**
* Actively check the number of neighbours and ask for more if needed.
* Check the number of neighbours and ask for more if needed.
*
* @param fd File descriptor.
* @param events Event flags.
* @param ctx Global state.
* @param global_state The global state.
*/
static void conns_cb(int fd __attribute__((unused)),
short events __attribute__((unused)),
void *ctx)
static void connections_maintain(global_state_t *global_state)
{
global_state_t *global_state;
int needed_conns;
global_state = (global_state_t *) ctx;
int needed_conns;
needed_conns = MIN_NEIGHBOURS -
linkedlist_size(&global_state->neighbours);
if (needed_conns > 0) {
log_debug("conns_cb - we need %d more neighbours");
log_debug("conns_cb - need %d more neighbours", needed_conns);
/* ask twice more hosts than we need; it's preferable
* to have more neighbours than minimum */
add_more_connections(global_state, 2 * needed_conns);
......@@ -96,25 +104,127 @@ int daemon_events_setup(global_state_t *global_state)
return 1;
}
/* check the number of neighbours every 10 seconds */
interval.tv_sec = 10;
/* register the short time-interval loop updates */
interval.tv_sec = UPDATE_TIME_SHORT;
interval.tv_usec = 0;
event = event_new(global_state->event_loop,
-1,
EV_PERSIST,
conns_cb,
loop_update_short,
global_state);
if (!event ||
event_add(event, &interval) < 0 ||
!linkedlist_append(events, event)) {
log_error("Creating or adding Connections event");
log_error("Creating or adding short loop update callback");
return 1;
}
/* register the long time-interval loop updates */
interval.tv_sec = UPDATE_TIME_LONG;
interval.tv_usec = 0;
event = event_new(global_state->event_loop,
-1,
EV_PERSIST,
loop_update_long,
global_state);
if (!event ||
event_add(event, &interval) < 0 ||
!linkedlist_append(events, event)) {
log_error("Creating or adding long loop update callback");
return 1;
}
return 0;
}
/**
* The long time-triggered loop update.
*
* @param fd File descriptor.
* @param events Event flags.
* @param ctx Global state.
*/
static void loop_update_long(evutil_socket_t fd __attribute__((unused)),
short events __attribute__((unused)),
void *ctx)
{
global_state_t *global_state = (global_state_t *) ctx;
remove_stale_records(global_state);
}
/**
* The short time-triggered loop update.
*
* @param fd File descriptor.
* @param events Event flags.
* @param ctx Global state.
*/
static void loop_update_short(evutil_socket_t fd __attribute__((unused)),
short events __attribute__((unused)),
void *ctx)
{
global_state_t *global_state = (global_state_t *) ctx;
connections_maintain(global_state);
}
/**
* Remove old records from every global state's container.
*
* @param global_state The global state.
*/
static void remove_stale_records(global_state_t *global_state)
{
identity_t *current_identity;
linkedlist_t *current_list;
neighbour_t *current_neighbour;
linkedlist_node_t *current_node;
peer_t *current_peer;
linkedlist_node_t *next_node;
current_time = time(NULL);
/* remove stale nonces of known peers */
current_list = &global_state->peers;
current_node = linkedlist_get_first(current_list);
while (current_node) {
current_peer = (peer_t *) current_node->data;
nonces_remove_stale(&current_peer->nonces);
current_node = linkedlist_get_next(current_list, current_node);
}
/* remove stale nonces of the pseudonyms of our neighbours */
current_list = &global_state->neighbours;
current_node = linkedlist_get_first(current_list);
while (current_node) {
current_neighbour = (neighbour_t *) current_node->data;
nonces_remove_stale(&current_neighbour->pseudonym.nonces);
current_node = linkedlist_get_next(current_list, current_node);
}
/* remove unneeded identities */
current_list = &global_state->identities;
current_node = linkedlist_get_first(current_list);
while (current_node) {
current_identity = (identity_t *) current_node->data;
next_node = linkedlist_get_next(current_list, current_node);
if (current_identity->flags & IDENTITY_TMP) {
linkedlist_delete(current_node);
}
current_node = next_node;
}
}
/**
* Callback function for a received signal.
*
......
......@@ -23,6 +23,7 @@
#include "log.h"
#include "neighbours.h"
#include "paths.h"
#include "peers.h"
/**
* Clear global state variables.
......@@ -32,10 +33,12 @@
void global_state_clear(global_state_t *global_state)
{
linkedlist_destroy(&global_state->pending_neighbours, clear_neighbour);
linkedlist_destroy(&global_state->peers, peer_clear);
linkedlist_destroy(&global_state->neighbours, clear_neighbour);
linkedlist_destroy(&global_state->hosts, NULL);
/* event nodes' data are not malloc'd; just apply the removal */
linkedlist_apply(&global_state->events, event_free, linkedlist_remove);
linkedlist_destroy(&global_state->identities, NULL);
clear_paths(&global_state->filepaths);
event_base_free(global_state->event_loop);
......@@ -54,9 +57,18 @@ int global_state_init(global_state_t *global_state)
return 1;
}
linkedlist_init(&global_state->identities);
if (!(global_state->true_identity = identity_generate(0x00))) {
log_error("Creating our true identity");
return 1;
}
linkedlist_append(&global_state->identities,
global_state->true_identity);
linkedlist_init(&global_state->events);
linkedlist_init(&global_state->hosts);
linkedlist_init(&global_state->neighbours);
linkedlist_init(&global_state->peers);
linkedlist_init(&global_state->pending_neighbours);
return 0;
......
......@@ -23,6 +23,7 @@
#include "linkedlist.h"
#include "paths.h"
#include "peers.h"
/**
* Event loop works with the data stored in an instance of this struct.
......@@ -36,10 +37,16 @@ typedef struct s_global_state {
filepaths_t filepaths;
/** Linked list of some known hosts in the network. */
linkedlist_t hosts;
/** List of our identities. */
linkedlist_t identities;
/** Linked list of our neighbours. */
linkedlist_t neighbours;
/** Known peers. */
linkedlist_t peers;
/** Hosts that didn't accept/reject us yet. */
linkedlist_t pending_neighbours;
/** Our true identity. */
identity_t *true_identity;
} global_state_t;
void global_state_clear(global_state_t *global_state);
......
......@@ -19,13 +19,16 @@
#include <assert.h>
#include <event2/bufferevent.h>
#include <netinet/in.h>
#include <sodium.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crypto.h"
#include "linkedlist.h"
#include "log.h"
#include "neighbours.h"
#include "peers.h"
/**
* Add new neighbour into neighbours.
......@@ -65,6 +68,17 @@ neighbour_t *add_new_neighbour(linkedlist_t *neighbours,
new_neighbour->failed_pings = 0;
new_neighbour->flags = 0x0;
new_neighbour->host = NULL;
/* create our pseudonym */
generate_keypair(&new_neighbour->my_pseudonym.keypair);
new_neighbour->my_pseudonym.nonce_value = get_random_uint64_t();
/* initialize neighbour's pseudonym */
memset(new_neighbour->pseudonym.identifier,
0x0,
crypto_box_PUBLICKEYBYTES);
linkedlist_init(&new_neighbour->pseudonym.nonces);
memset(&new_neighbour->pseudonym.presence_nonce,
0x0,
sizeof(nonce_t));
if (!(new_neighbour->node = linkedlist_append(neighbours,
new_neighbour))) {
......@@ -84,6 +98,7 @@ neighbour_t *add_new_neighbour(linkedlist_t *neighbours,
void clear_neighbour(neighbour_t *neighbour)
{
bufferevent_free(neighbour->buffer_event);
peer_clear(&neighbour->pseudonym);
}
/**
......@@ -117,6 +132,42 @@ int compare_neighbour_bufferevents(const neighbour_t *neighbour,
return neighbour->buffer_event != bev;
}
/**
* Comparing function between our neighbour-specific pseudonym and a public key.
*
* @param neighbour Use this neighbour.
* @param public_key Compare to this public key.
*
* @return 0 The public keys equal.
* @return <0 'public_key' is greater.
* @return >0 The pseudonym's public key is greater.
*/
int compare_neighbour_my_pseudonyms(const neighbour_t *neighbour,
unsigned char *public_key)
{
return memcmp(neighbour->my_pseudonym.keypair.public_key,
public_key,
crypto_box_PUBLICKEYBYTES);
}
/**
* Comparing function between neighbour's pseudonym and a public key.
*
* @param neighbour Use this neighbour.
* @param public_key Compare to this public key.
*
* @return 0 The public keys equal.
* @return <0 'public_key' is greater.
* @return >0 The pseudonym's public key is greater.
*/
int compare_neighbour_pseudonyms(const neighbour_t *neighbour,
unsigned char *public_key)
{
return memcmp(neighbour->pseudonym.identifier,
public_key,
crypto_box_PUBLICKEYBYTES);
}
/**
* Fetch pointers to neighbours with specific flags set, into an array
* that is being allocated in here.
......
......@@ -25,6 +25,7 @@
#include "hosts.h"
#include "linkedlist.h"
#include "peers.h"
/** Request for addresses. */
#define NEIGHBOUR_ADDRS_REQ 0x01
......@@ -42,8 +43,12 @@ typedef struct s_neighbour {
int flags;
/** Corresponding host. */
host_t *host;
/** Our peer pseudonym for this neighbour. */
identity_t my_pseudonym;
/** Neighbour's node in the neighbours container. */
linkedlist_node_t *node;
/** Neighbour's peer pseudonym for us. */
peer_t pseudonym;
} neighbour_t;
neighbour_t *add_new_neighbour(linkedlist_t *neighbours,
......@@ -58,6 +63,11 @@ int compare_neighbour_addrs(const neighbour_t *neighbour,
int compare_neighbour_bufferevents(const neighbour_t *neighbour,
const struct bufferevent *bev);
int compare_neighbour_my_pseudonyms(const neighbour_t *neighbour,
unsigned char *public_key);
int compare_neighbour_pseudonyms(const neighbour_t *neighbour,
unsigned char *public_key);
int fetch_specific_neighbours(const linkedlist_t *neighbours,
neighbour_t ***output,
......
/*
* Coincer
* Copyright (C) 2017-2018 Coincer Developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sodium.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypto.h"
#include "linkedlist.h"
#include "log.h"
#include "peers.h"
/**
* Determine whether an identifier is empty (if all its bytes are set to 0x0).
*
* @param id Check this identifier.
*
* @return 1 The identifier is empty.
* @return 0 The identifier is not empty.
*/
int identifier_empty(const unsigned char id[crypto_box_PUBLICKEYBYTES])
{
return id[0] == 0x0 && !memcmp(id,
id + 1,
crypto_box_PUBLICKEYBYTES - 1);
}
/**
* Find the identity for an identifier.
*
* @param identities List of our identities.
* @param identifier Search for this identifier.
*
* @return identity_t Corresponding identity for the
* identifier.
* @return NULL The identifier doesn't belong to any
* of our identities.
*/
identity_t *identity_find(const linkedlist_t *identities,
const unsigned char *identifier)
{
identity_t *identity;
const linkedlist_node_t *node;
node = linkedlist_get_first(identities);
while (node) {
identity = (identity_t *) node->data;
/* if the identifier represents one of our identities */
if (!memcmp(identity->keypair.public_key,
identifier,
crypto_box_PUBLICKEYBYTES)) {
return identity;
}
node = linkedlist_get_next(identities, node);
}
return NULL;
}
/**
* Set flags on given identity.
*
* @param identity Set flags on this identity.
* @param flags Set these flags on the identity.
*/
void identity_flags_set(identity_t *identity, int flags)
{
identity->flags |= flags;
}
/**
* Unset flags on given identity.
*
* @param identity Unset flags on this identity.
* @param flags Unset these flags on the identity.
*/
void identity_flags_unset(identity_t *identity, int flags)
{
identity->flags &= ~flags;
}
/**
* Generate an identity, including its initial nonce value.
*
* @param flags The flags of the identity.
*
* @return identity_t Dynamically allocated identity.
* @return NULL Allocation failure.
*/
identity_t *identity_generate(int flags)
{
identity_t *identity;
identity = (identity_t *) malloc(sizeof(identity_t));
if (!identity) {
log_error("Creating a new identity");
return NULL;
}
generate_keypair(&identity->keypair);
identity->nonce_value = get_random_uint64_t();
identity->last_adv = 0;
identity->flags = 0x0;
identity_flags_set(identity, flags);
return identity;
}
/**
* Nonce staleness predicate.
*
* @param nonce Check staleness of this nonce.
* @param current_time The time to compare to.
*
* @return 1 The nonce is stale.
* @return 0 The nonce is not stale.
*/
int nonce_is_stale(const nonce_t *nonce, const time_t current_time)
{
return difftime(current_time, nonce->creation) >= NONCE_STALE_TIME;
}
/**
* Store a nonce into ascendingly sorted (by nonce value) container of nonces.
*
* @param nonces The nonces container.
* @param value The nonce's value.
*
* @return 0 Successfully stored.
* @return 1 Failure.
*/
int nonce_store(linkedlist_t *nonces, uint64_t value)
{
linkedlist_node_t *cur_node;
nonce_t *cur_nonce;
nonce_t *nonce;
nonce = (nonce_t *) malloc(sizeof(nonce_t));
if (!nonce) {
log_error("Creating a nonce");
return 1;
}
nonce->value = value;
/* place the nonce into appropriate position */
cur_node = linkedlist_get_last(nonces);
while (cur_node) {
cur_nonce = (nonce_t *) cur_node->data;
/* appropriate position found */
if (value > cur_nonce->value) {
if (cur_node == linkedlist_get_last(nonces)) {
nonce->creation = time(NULL);
} else {
nonce->creation = cur_nonce->creation;
}
if (!linkedlist_insert_after(nonces, cur_node, nonce)) {
log_error("Storing a nonce");
free(nonce);
return 1;
}
return 0;
}
cur_node = linkedlist_get_prev(nonces, cur_node);
}
/* at this point we know the nonce should be placed at the beginning
* of the container; do that only if the container is empty */
if (linkedlist_empty(nonces)) {
nonce->creation = time(NULL);
if (!linkedlist_insert_after(nonces, &nonces->first, nonce)) {
log_error("Storing a nonce");
free(nonce);
return 1;
}
return 0;
}
free(nonce);
return 1;
}
/**
* Find nonce by its value in a list of nonces.
*
* @param nonces Choose the nonce from these nonces.
* @param value Nonce's value.
*
* @return nonce_t Requested nonce.
* @return NULL The nonce is absent.
*/
nonce_t *nonces_find(const linkedlist_t *nonces, uint64_t value)
{
const linkedlist_node_t *node;
nonce_t *nonce;
node = linkedlist_get_first(nonces);
while (node) {
nonce = (nonce_t *) node->data;
if (nonce->value == value) {
return nonce;
/* the nonces are ascendingly sorted */
} else if (nonce->value > value) {
return NULL;
}
node = linkedlist_get_next(nonces, node);
}
return NULL;
}
/**
* Get the first nonce (the nonce with the lowest value) from a list of nonces.
*
* @param nonces Use these nonces.
*
* @return nonce_t The first nonce.
* @return NULL The nonces are empty.
*/
nonce_t *nonces_get_first(const linkedlist_t *nonces)
{
linkedlist_node_t *node;
if ((node = linkedlist_get_first(nonces))) {
return node->data;
}