Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Michal Zima
coincer
Commits
33f1a37d
Commit
33f1a37d
authored
Sep 15, 2018
by
xpetrak2
Browse files
Peer representation created
parent
99a8e65d
Changes
9
Hide whitespace changes
Inline
Side-by-side
Makefile.am
View file @
33f1a37d
...
...
@@ -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)
...
...
README
View file @
33f1a37d
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
src/daemon_events.c
View file @
33f1a37d
...
...
@@ -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 c
heck the number of neighbours and ask for more if needed.
*
C
heck 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 second
s */
interval
.
tv_sec
=
10
;
/*
register the short time-interval loop update
s */
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.
*
...
...
src/global_state.c
View file @
33f1a37d
...
...
@@ -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
;
...
...
src/global_state.h
View file @
33f1a37d
...
...
@@ -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
);
...
...
src/neighbours.c
View file @
33f1a37d
...
...
@@ -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.
...
...
src/neighbours.h
View file @
33f1a37d
...
...
@@ -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
,
...
...
src/peers.c
0 → 100644
View file @
33f1a37d
/*
* 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
;
}
return
NULL
;