summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-04-19 17:42:56 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-04-19 17:42:56 +0200
commit8c91443808ce376947ff387eaffca6e8cfbe9251 (patch)
tree227a4367a2c013bbee40dc99c8abafc52da5ee2e
parentc5b12202c834fe484634131ee9a91465b9e6e7bc (diff)
downloadfastd-8c91443808ce376947ff387eaffca6e8cfbe9251.tar
fastd-8c91443808ce376947ff387eaffca6e8cfbe9251.zip
Don't regenerate session handshake keypair for every handshake so a global state can be used; remove the concept of temporary peers
These changes will fix the possibility of a TCP-SYN-Flood-like DoS attack, at the cost of another protocol change: as we can't count request IDs when we don't know have temporary peers, request IDs are removed completely.
-rw-r--r--src/config.c3
-rw-r--r--src/fastd.c89
-rw-r--r--src/fastd.h12
-rw-r--r--src/handshake.c49
-rw-r--r--src/handshake.h7
-rw-r--r--src/method_xsalsa20_poly1305.c2
-rw-r--r--src/packet.h4
-rw-r--r--src/peer.c116
-rw-r--r--src/peer.h26
-rw-r--r--src/printf.c81
-rw-r--r--src/protocol_ec25519_fhmqvc.c434
-rw-r--r--src/types.h8
12 files changed, 348 insertions, 483 deletions
diff --git a/src/config.c b/src/config.c
index 3e42f38..c5c4c65 100644
--- a/src/config.c
+++ b/src/config.c
@@ -55,7 +55,6 @@ static void default_config(fastd_config *conf) {
conf->keepalive_interval = 60;
conf->peer_stale_time = 300;
- conf->peer_stale_time_temp = 30;
conf->eth_addr_stale_time = 300;
conf->ifname = NULL;
@@ -668,7 +667,7 @@ static void reconfigure_handle_old_peers(fastd_context *ctx, fastd_peer_config *
static void reconfigure_reset_waiting(fastd_context *ctx) {
fastd_peer *peer;
for (peer = ctx->peers; peer; peer = peer->next) {
- if (fastd_peer_is_waiting(peer))
+ if (!fastd_peer_is_established(peer))
fastd_peer_reset(ctx, peer);
}
}
diff --git a/src/fastd.c b/src/fastd.c
index 89b764d..0c7e6f5 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -202,20 +202,20 @@ static void close_sockets(fastd_context *ctx) {
}
}
-static void fastd_send_type(fastd_context *ctx, fastd_peer *peer, uint8_t packet_type, fastd_buffer buffer) {
+static void fastd_send_type(fastd_context *ctx, const fastd_peer_address *address, uint8_t packet_type, fastd_buffer buffer) {
int sockfd;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
- switch (peer->address.sa.sa_family) {
+ switch (address->sa.sa_family) {
case AF_INET:
- msg.msg_name = &peer->address.in;
+ msg.msg_name = (void*)&address->in;
msg.msg_namelen = sizeof(struct sockaddr_in);
sockfd = ctx->sockfd;
break;
case AF_INET6:
- msg.msg_name = &peer->address.in6;
+ msg.msg_name = (void*)&address->in6;
msg.msg_namelen = sizeof(struct sockaddr_in6);
sockfd = ctx->sock6fd;
break;
@@ -243,12 +243,12 @@ static void fastd_send_type(fastd_context *ctx, fastd_peer *peer, uint8_t packet
fastd_buffer_free(buffer);
}
-void fastd_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) {
- fastd_send_type(ctx, peer, PACKET_DATA, buffer);
+void fastd_send(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer) {
+ fastd_send_type(ctx, address, PACKET_DATA, buffer);
}
-void fastd_send_handshake(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) {
- fastd_send_type(ctx, peer, PACKET_HANDSHAKE, buffer);
+void fastd_send_handshake(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer) {
+ fastd_send_type(ctx, address, PACKET_HANDSHAKE, buffer);
}
void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) {
@@ -268,7 +268,7 @@ void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buf
if (fastd_eth_addr_is_unicast(dest_addr)) {
fastd_peer *dest_peer = fastd_peer_find_by_eth_addr(ctx, dest_addr);
- if (dest_peer && dest_peer != peer && dest_peer->state == STATE_ESTABLISHED) {
+ if (dest_peer && dest_peer != peer && fastd_peer_is_established(dest_peer)) {
ctx->conf->protocol->send(ctx, dest_peer, buffer);
}
else {
@@ -278,7 +278,7 @@ void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buf
else {
fastd_peer *dest_peer;
for (dest_peer = ctx->peers; dest_peer; dest_peer = dest_peer->next) {
- if (dest_peer != peer && dest_peer->state == STATE_ESTABLISHED) {
+ if (dest_peer != peer && fastd_peer_is_established(dest_peer)) {
fastd_buffer send_buffer = fastd_buffer_alloc(buffer.len, ctx->conf->method->min_encrypt_head_space(ctx), 0);
memcpy(send_buffer.data, buffer.data, buffer.len);
ctx->conf->protocol->send(ctx, dest_peer, send_buffer);
@@ -379,7 +379,7 @@ static inline void update_time(fastd_context *ctx) {
static inline void send_handshake(fastd_context *ctx, fastd_peer *peer) {
if (peer->address.sa.sa_family != AF_UNSPEC) {
pr_debug(ctx, "sending handshake to %P...", peer);
- ctx->conf->protocol->handshake_init(ctx, peer);
+ ctx->conf->protocol->handshake_init(ctx, &peer->address, peer->config);
}
fastd_task_schedule_handshake(ctx, peer, fastd_rand(ctx, 17500, 22500));
@@ -390,7 +390,7 @@ static void handle_tasks(fastd_context *ctx) {
while ((task = fastd_task_get(ctx)) != NULL) {
switch (task->type) {
case TASK_HANDSHAKE:
- if (task->peer->state == STATE_RESOLVE)
+ if (fastd_peer_is_dynamic(task->peer))
fastd_resolve_peer(ctx, task->peer->config);
else
send_handshake(ctx, task->peer);
@@ -437,7 +437,7 @@ static void handle_tun(fastd_context *ctx) {
return;
}
- if (peer->state == STATE_ESTABLISHED) {
+ if (fastd_peer_is_established(peer)) {
ctx->conf->protocol->send(ctx, peer, buffer);
}
else {
@@ -447,7 +447,7 @@ static void handle_tun(fastd_context *ctx) {
}
if (peer == NULL) {
for (peer = ctx->peers; peer; peer = peer->next) {
- if (peer->state == STATE_ESTABLISHED) {
+ if (fastd_peer_is_established(peer)) {
fastd_buffer send_buffer = fastd_buffer_alloc(len, ctx->conf->method->min_encrypt_head_space(ctx), 0);
memcpy(send_buffer.data, buffer.data, len);
ctx->conf->protocol->send(ctx, peer, send_buffer);
@@ -490,28 +490,8 @@ static void handle_socket(fastd_context *ctx, int sockfd) {
fastd_peer *peer;
for (peer = ctx->peers; peer; peer = peer->next) {
- if (peer->address.sa.sa_family != recvaddr.sa.sa_family)
- continue;
-
- if (recvaddr.sa.sa_family == AF_INET) {
- if (peer->address.in.sin_addr.s_addr != recvaddr.in.sin_addr.s_addr)
- continue;
- if (peer->address.in.sin_port != recvaddr.in.sin_port)
- continue;
-
+ if (fastd_peer_address_equal(&peer->address, &recvaddr))
break;
- }
- else if (recvaddr.sa.sa_family == AF_INET6) {
- if (!IN6_ARE_ADDR_EQUAL(&peer->address.in6.sin6_addr, &recvaddr.in6.sin6_addr))
- continue;
- if (peer->address.in6.sin6_port != recvaddr.in6.sin6_port)
- continue;
-
- break;
- }
- else {
- exit_bug(ctx, "unsupported address family");
- }
}
if (peer) {
@@ -521,7 +501,7 @@ static void handle_socket(fastd_context *ctx, int sockfd) {
break;
case PACKET_HANDSHAKE:
- fastd_handshake_handle(ctx, peer, buffer);
+ fastd_handshake_handle(ctx, &recvaddr, peer->config, buffer);
break;
default:
@@ -533,13 +513,11 @@ static void handle_socket(fastd_context *ctx, int sockfd) {
(recvaddr.sa.sa_family == AF_INET6 && ctx->conf->n_dynamic_v6)) {
switch (packet_type) {
case PACKET_DATA:
- peer = fastd_peer_add_temp(ctx, (fastd_peer_address*)&recvaddr);
- ctx->conf->protocol->handle_recv(ctx, peer, buffer);
+ ctx->conf->protocol->handshake_init(ctx, &recvaddr, NULL);
break;
case PACKET_HANDSHAKE:
- peer = fastd_peer_add_temp(ctx, (fastd_peer_address*)&recvaddr);
- fastd_handshake_handle(ctx, peer, buffer);
+ fastd_handshake_handle(ctx, &recvaddr, NULL, buffer);
break;
default:
@@ -547,7 +525,7 @@ static void handle_socket(fastd_context *ctx, int sockfd) {
}
}
else {
- pr_debug(ctx, "received packet from unknown peer");
+ pr_debug(ctx, "received packet from unknown peer %I", &recvaddr);
fastd_buffer_free(buffer);
}
}
@@ -590,26 +568,13 @@ static void cleanup_peers(fastd_context *ctx) {
for (peer = ctx->peers; peer; peer = next) {
next = peer->next;
- if (fastd_peer_is_temporary(peer)) {
- if (timespec_diff(&ctx->now, &peer->seen) > ctx->conf->peer_stale_time_temp*1000)
- fastd_peer_reset(ctx, peer);
- }
- else if (fastd_peer_is_established(peer)) {
+ if (fastd_peer_is_established(peer)) {
if (timespec_diff(&ctx->now, &peer->seen) > ctx->conf->peer_stale_time*1000)
fastd_peer_reset(ctx, peer);
}
}
}
-static void cleanup_peer_with_address(fastd_context *ctx, const fastd_peer_address *addr) {
- fastd_peer *peer;
- for (peer = ctx->peers; peer; peer = peer->next) {
- if (fastd_peer_is_temporary(peer) && fastd_peer_addr_equal(&peer->address, addr)) {
- fastd_peer_reset(ctx, peer);
- return;
- }
- }
-}
static void handle_resolv_returns(fastd_context *ctx) {
while (ctx->resolve_returns) {
@@ -624,11 +589,13 @@ static void handle_resolv_returns(fastd_context *ctx) {
if (!fastd_peer_config_matches_dynamic(peer->config, &ctx->resolve_returns->constraints))
continue;
- cleanup_peer_with_address(ctx, &ctx->resolve_returns->addr);
- peer->address = ctx->resolve_returns->addr;
-
- if (peer->state == STATE_RESOLVE)
- send_handshake(ctx, peer);
+ if (fastd_peer_claim_address(ctx, peer, &ctx->resolve_returns->addr)) {
+ if (!fastd_peer_is_established(peer))
+ send_handshake(ctx, peer);
+ }
+ else {
+ pr_warn(ctx, "hostname `%s' resolved to address %I which is used by a fixed peer", ctx->resolve_returns->hostname, ctx->resolve_returns->addr);
+ }
break;
}
@@ -696,6 +663,8 @@ int main(int argc, char *argv[]) {
close_sockets(&ctx);
close_tuntap(&ctx);
+ free(ctx.protocol_state);
+
fastd_config_release(&ctx, &conf);
return 0;
diff --git a/src/fastd.h b/src/fastd.h
index c681d34..08ef666 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -64,10 +64,9 @@ struct _fastd_protocol {
fastd_protocol_config* (*init)(fastd_context *ctx);
void (*peer_configure)(fastd_context *ctx, fastd_peer_config *peer_conf);
- void (*peer_config_purged)(fastd_context *ctx, fastd_peer_config *peer_conf);
- void (*handshake_init)(fastd_context *ctx, fastd_peer *peer);
- void (*handshake_handle)(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake);
+ void (*handshake_init)(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf);
+ void (*handshake_handle)(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake);
void (*handle_recv)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
void (*send)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
@@ -116,7 +115,6 @@ struct _fastd_config {
unsigned keepalive_interval;
unsigned peer_stale_time;
- unsigned peer_stale_time_temp;
unsigned eth_addr_stale_time;
char *ifname;
@@ -182,6 +180,8 @@ struct _fastd_context {
unsigned int randseed;
+ fastd_protocol_state *protocol_state;
+
fastd_resolve_return *resolve_returns;
};
@@ -191,8 +191,8 @@ struct _fastd_string_stack {
};
-void fastd_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
-void fastd_send_handshake(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
+void fastd_send(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer);
+void fastd_send_handshake(fastd_context *ctx, const fastd_peer_address *address, fastd_buffer buffer);
void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
void fastd_resolve_peer(fastd_context *ctx, const fastd_peer_config *peer);
diff --git a/src/handshake.c b/src/handshake.c
index c301e4e..eb33f4f 100644
--- a/src/handshake.c
+++ b/src/handshake.c
@@ -58,7 +58,7 @@ static const char const *REPLY_TYPES[REPLY_MAX] = {
#define AS_UINT16(ptr) ((*(uint8_t*)(ptr).data) + (*((uint8_t*)(ptr).data+1) << 8))
-fastd_buffer fastd_handshake_new_init(fastd_context *ctx, fastd_peer *peer, size_t tail_space) {
+fastd_buffer fastd_handshake_new_init(fastd_context *ctx, size_t tail_space) {
size_t protocol_len = strlen(ctx->conf->protocol->name);
size_t method_len = strlen(ctx->conf->method->name);
fastd_buffer buffer = fastd_buffer_alloc(sizeof(fastd_packet), 0,
@@ -70,8 +70,8 @@ fastd_buffer fastd_handshake_new_init(fastd_context *ctx, fastd_peer *peer, size
);
fastd_packet *request = buffer.data;
- request->req_id = ++peer->last_req_id;
- request->rsv = 0;
+ request->rsv1 = 0;
+ request->rsv2 = 0;
fastd_handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, 1);
fastd_handshake_add_uint8(ctx, &buffer, RECORD_MODE, ctx->conf->mode);
@@ -83,7 +83,7 @@ fastd_buffer fastd_handshake_new_init(fastd_context *ctx, fastd_peer *peer, size
return buffer;
}
-fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake, size_t tail_space) {
+fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, const fastd_handshake *handshake, size_t tail_space) {
bool first = (AS_UINT8(handshake->records[RECORD_HANDSHAKE_TYPE]) == 1);
size_t mtu_size = 0;
@@ -97,8 +97,8 @@ fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, fastd_peer *peer, con
);
fastd_packet *request = buffer.data;
- request->req_id = handshake->req_id;
- request->rsv = 0;
+ request->rsv1 = 0;
+ request->rsv2 = 0;
fastd_handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, AS_UINT8(handshake->records[RECORD_HANDSHAKE_TYPE])+1);
fastd_handshake_add_uint8(ctx, &buffer, RECORD_REPLY_CODE, 0);
@@ -109,10 +109,9 @@ fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, fastd_peer *peer, con
return buffer;
}
-
-void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) {
+void fastd_handshake_handle(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer) {
if (buffer.len < sizeof(fastd_packet)) {
- pr_warn(ctx, "received a short handshake from %P", peer);
+ pr_warn(ctx, "received a short handshake from %I", address);
goto end_free;
}
@@ -140,10 +139,8 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b
ptr += 4+len;
}
- handshake.req_id = packet->req_id;
-
if (handshake.records[RECORD_HANDSHAKE_TYPE].length != 1) {
- pr_debug(ctx, "received handshake without handshake type from %P", peer);
+ pr_debug(ctx, "received handshake without handshake type from %I", address);
goto end_free;
}
@@ -151,8 +148,8 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b
if (handshake.records[RECORD_MTU].length == 2) {
if (AS_UINT16(handshake.records[RECORD_MTU]) != ctx->conf->mtu) {
- pr_warn(ctx, "MTU configuration differs with peer %P: local MTU is %u, remote MTU is %u",
- peer, ctx->conf->mtu, AS_UINT16(handshake.records[RECORD_MTU]));
+ pr_warn(ctx, "MTU configuration differs with peer %I: local MTU is %u, remote MTU is %u",
+ address, ctx->conf->mtu, AS_UINT16(handshake.records[RECORD_MTU]));
}
}
@@ -203,47 +200,47 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b
fastd_buffer reply_buffer = fastd_buffer_alloc(sizeof(fastd_packet), 0, 3*5 /* enough space for handshake type, reply code and error detail */);
fastd_packet *reply = reply_buffer.data;
- reply->req_id = packet->req_id;
- reply->rsv = 0;
+ reply->rsv1 = 0;
+ reply->rsv2 = 0;
fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_HANDSHAKE_TYPE, 2);
fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_REPLY_CODE, reply_code);
fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_ERROR_DETAIL, error_detail);
- fastd_send_handshake(ctx, peer, reply_buffer);
+ fastd_send_handshake(ctx, address, reply_buffer);
}
else {
- ctx->conf->protocol->handshake_handle(ctx, peer, &handshake);
+ ctx->conf->protocol->handshake_handle(ctx, address, peer_conf, &handshake);
}
}
else {
if ((handshake.type & 1) == 0) {
- if (packet->req_id != peer->last_req_id) {
+ /*if (packet->req_id != peer->last_req_id) {
pr_warn(ctx, "received handshake reply with request ID %u from %P while %u was expected", packet->req_id, peer, peer->last_req_id);
goto end_free;
- }
+ }*/
}
if (handshake.records[RECORD_REPLY_CODE].length != 1) {
- pr_warn(ctx, "received handshake reply without reply code from %P", peer);
+ pr_warn(ctx, "received handshake reply without reply code from %I", address);
goto end_free;
}
uint8_t reply_code = AS_UINT8(handshake.records[RECORD_REPLY_CODE]);
if (reply_code == REPLY_SUCCESS) {
- ctx->conf->protocol->handshake_handle(ctx, peer, &handshake);
+ ctx->conf->protocol->handshake_handle(ctx, address, peer_conf, &handshake);
}
else {
const char *error_field_str;
if (reply_code >= REPLY_MAX) {
- pr_warn(ctx, "Handshake with %P failed with unknown code %i", peer, reply_code);
+ pr_warn(ctx, "Handshake with %I failed with unknown code %I", address, reply_code);
goto end_free;
}
if (handshake.records[RECORD_ERROR_DETAIL].length != 1) {
- pr_warn(ctx, "Handshake with %P failed with code %s", peer, REPLY_TYPES[reply_code]);
+ pr_warn(ctx, "Handshake with %I failed with code %s", address, REPLY_TYPES[reply_code]);
goto end_free;
}
@@ -255,11 +252,11 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b
switch (reply_code) {
case REPLY_MANDATORY_MISSING:
- pr_warn(ctx, "Handshake with %P failed: mandatory field `%s' missing", peer, error_field_str);
+ pr_warn(ctx, "Handshake with %I failed: mandatory field `%s' missing", address, error_field_str);
break;
case REPLY_UNACCEPTABLE_VALUE:
- pr_warn(ctx, "Handshake with %P failed: unacceptable value for field `%s'", peer, error_field_str);
+ pr_warn(ctx, "Handshake with %I failed: unacceptable value for field `%s'", address, error_field_str);
break;
default: /* just to silence the warning */
diff --git a/src/handshake.h b/src/handshake.h
index 9bb1a56..5e7ee1d 100644
--- a/src/handshake.h
+++ b/src/handshake.h
@@ -61,16 +61,15 @@ typedef struct _fastd_handshake_record {
} fastd_handshake_record;
struct _fastd_handshake {
- uint8_t req_id;
uint8_t type;
fastd_handshake_record records[RECORD_MAX];
};
-fastd_buffer fastd_handshake_new_init(fastd_context *ctx, fastd_peer *peer, size_t tail_space);
-fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake, size_t tail_space);
+fastd_buffer fastd_handshake_new_init(fastd_context *ctx, size_t tail_space);
+fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, const fastd_handshake *handshake, size_t tail_space);
-void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer);
+void fastd_handshake_handle(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer);
static inline void fastd_handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) {
diff --git a/src/method_xsalsa20_poly1305.c b/src/method_xsalsa20_poly1305.c
index 5194a4d..9331265 100644
--- a/src/method_xsalsa20_poly1305.c
+++ b/src/method_xsalsa20_poly1305.c
@@ -118,7 +118,7 @@ static bool method_session_is_initiator(fastd_context *ctx, fastd_method_session
}
static bool method_session_want_refresh(fastd_context *ctx, fastd_method_session_state *session) {
- return (method_session_is_initiator(ctx, session) && timespec_after(&ctx->now, &session->refresh_after));
+ return timespec_after(&ctx->now, &session->refresh_after);
}
static void method_session_free(fastd_context *ctx, fastd_method_session_state *session) {
diff --git a/src/packet.h b/src/packet.h
index 76a64d1..210955d 100644
--- a/src/packet.h
+++ b/src/packet.h
@@ -37,8 +37,8 @@ typedef enum _fastd_packet_type {
} fastd_packet_type;
typedef struct __attribute__ ((__packed__)) _fastd_packet {
- uint8_t req_id;
- uint16_t rsv;
+ uint8_t rsv1;
+ uint16_t rsv2;
uint8_t tlv_data[];
} fastd_packet;
diff --git a/src/peer.c b/src/peer.c
index 1ad4c7f..f3d9da8 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -152,7 +152,7 @@ static void on_disestablish(fastd_context *ctx, fastd_peer *peer) {
}
static inline void reset_peer(fastd_context *ctx, fastd_peer *peer) {
- if (peer->state == STATE_ESTABLISHED)
+ if (peer->established)
on_disestablish(ctx, peer);
ctx->conf->protocol->free_peer_state(ctx, peer);
@@ -179,12 +179,9 @@ static inline void setup_peer(fastd_context *ctx, fastd_peer *peer) {
else
peer->address = peer->config->address;
- if (peer->config->hostname)
- peer->state = STATE_RESOLVE;
- else
- peer->state = STATE_WAIT;
-
+ peer->established = false;
peer->seen = (struct timespec){0, 0};
+ peer->protocol_state = NULL;
if (!fastd_peer_is_floating(peer))
fastd_task_schedule_handshake(ctx, peer, 0);
@@ -247,11 +244,10 @@ void fastd_peer_config_purge(fastd_context *ctx, fastd_peer_config *conf) {
fastd_peer_delete(ctx, peer);
}
- ctx->conf->protocol->peer_config_purged(ctx, conf);
fastd_peer_config_free(conf);
}
-bool fastd_peer_addr_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2) {
+bool fastd_peer_address_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2) {
if (addr1->sa.sa_family != addr2->sa.sa_family)
return false;
@@ -262,13 +258,41 @@ bool fastd_peer_addr_equal(const fastd_peer_address *addr1, const fastd_peer_add
case AF_INET:
if (addr1->in.sin_addr.s_addr != addr2->in.sin_addr.s_addr)
return false;
+ if (addr1->in.sin_port != addr2->in.sin_port)
+ return false;
break;
case AF_INET6:
if (!IN6_ARE_ADDR_EQUAL(&addr1->in6.sin6_addr, &addr2->in6.sin6_addr))
return false;
+ if (addr1->in6.sin6_port != addr2->in6.sin6_port)
+ return false;
+ }
+
+ return true;
+}
+
+bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const fastd_peer_address *addr) {
+ fastd_peer *peer;
+ for (peer = ctx->peers; peer; peer = peer->next) {
+ if (fastd_peer_address_equal(&peer->address, addr)) {
+ if (peer == new_peer)
+ break;
+
+ if (fastd_peer_is_floating(peer) || fastd_peer_is_dynamic(peer)) {
+ if (fastd_peer_is_established(peer))
+ fastd_peer_reset(ctx, peer);
+
+ memset(&peer->address, 0, sizeof(fastd_peer_address));
+ break;
+ }
+ else {
+ return false;
+ }
+ }
}
+ new_peer->address = *addr;
return true;
}
@@ -279,7 +303,7 @@ bool fastd_peer_config_equal(const fastd_peer_config *peer1, const fastd_peer_co
if (!strequal(peer1->hostname, peer2->hostname))
return false;
- if (!fastd_peer_addr_equal(&peer1->address, &peer2->address))
+ if (!fastd_peer_address_equal(&peer1->address, &peer2->address))
return false;
if (!strequal(peer1->key, peer2->key))
@@ -292,11 +316,7 @@ void fastd_peer_reset(fastd_context *ctx, fastd_peer *peer) {
pr_debug(ctx, "resetting peer %P", peer);
reset_peer(ctx, peer);
-
- if (fastd_peer_is_temporary(peer))
- delete_peer(ctx, peer);
- else
- setup_peer(ctx, peer);
+ setup_peer(ctx, peer);
}
void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer) {
@@ -304,21 +324,12 @@ void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer) {
delete_peer(ctx, peer);
}
-static fastd_peer* add_peer(fastd_context *ctx) {
+fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) {
fastd_peer *peer = malloc(sizeof(fastd_peer));
peer->next = ctx->peers;
- peer->last_req_id = 0;
- peer->protocol_state = NULL;
-
ctx->peers = peer;
- return peer;
-}
-
-fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) {
- fastd_peer *peer = add_peer(ctx);
-
peer->config = peer_conf;
setup_peer(ctx, peer);
@@ -327,64 +338,11 @@ fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) {
return peer;
}
-fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *address) {
- fastd_peer *peer = add_peer(ctx);
-
- peer->config = NULL;
- peer->address = *address;
- peer->state = STATE_TEMP;
- peer->seen = ctx->now;
-
- pr_debug(ctx, "added peer %P", peer);
-
- return peer;
-}
-
-fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer) {
- pr_debug(ctx, "merging peer %P into %P", temp_peer, perm_peer);
-
- ctx->conf->protocol->free_peer_state(ctx, perm_peer);
-
- if (perm_peer->state == STATE_ESTABLISHED)
- on_disestablish(ctx, perm_peer);
-
- perm_peer->address = temp_peer->address;
- perm_peer->state = STATE_ESTABLISHED;
- perm_peer->seen = temp_peer->seen;
- perm_peer->protocol_state = temp_peer->protocol_state;
- temp_peer->protocol_state = NULL;
-
- int i;
- for (i = 0; i < ctx->n_eth_addr; i++) {
- if (ctx->eth_addr[i].peer == temp_peer) {
- ctx->eth_addr[i].peer = perm_peer;
- }
- }
-
- fastd_task_replace_peer(ctx, temp_peer, perm_peer);
-
- fastd_peer_reset(ctx, temp_peer);
-
- on_establish(ctx, perm_peer);
- pr_info(ctx, "Connection with %P established.", perm_peer);
-
- return perm_peer;
-}
-
void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer) {
- switch(peer->state) {
- case STATE_RESOLVE:
- case STATE_WAIT:
- peer->state = STATE_ESTABLISHED;
+ if (!peer->established) {
+ peer->established = true;
on_establish(ctx, peer);
pr_info(ctx, "Connection with %P established.", peer);
- break;
-
- case STATE_TEMP:
- exit_bug(ctx, "tried to set a temporary connection to established");
-
- default:
- return;
}
}
diff --git a/src/peer.h b/src/peer.h
index f8b0f84..cf16629 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -37,8 +37,7 @@ struct _fastd_peer {
fastd_peer_address address;
- fastd_peer_state state;
- uint8_t last_req_id;
+ bool established;
struct timespec seen;
@@ -67,7 +66,7 @@ struct _fastd_peer_eth_addr {
};
-bool fastd_peer_addr_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2);
+bool fastd_peer_address_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2);
fastd_peer_config* fastd_peer_config_new(fastd_context *ctx, fastd_config *conf);
void fastd_peer_config_free(fastd_peer_config *peer);
@@ -78,9 +77,8 @@ bool fastd_peer_config_equal(const fastd_peer_config *peer1, const fastd_peer_co
void fastd_peer_reset(fastd_context *ctx, fastd_peer *peer);
void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer);
fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *conf);
-fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *address);
-fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer);
void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer);
+bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *peer, const fastd_peer_address *addr);
const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer);
const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer);
@@ -89,26 +87,22 @@ static inline bool fastd_peer_config_is_floating(const fastd_peer_config *config
return (config->hostname == NULL && config->address.sa.sa_family == AF_UNSPEC);
}
+static inline bool fastd_peer_config_is_dynamic(const fastd_peer_config *config) {
+ return (config->hostname != NULL);
+}
+
bool fastd_peer_config_matches_dynamic(const fastd_peer_config *config, const fastd_peer_address *addr);
static inline bool fastd_peer_is_floating(const fastd_peer *peer) {
- return (peer->config && fastd_peer_config_is_floating(peer->config));
+ return fastd_peer_config_is_floating(peer->config);
}
static inline bool fastd_peer_is_dynamic(const fastd_peer *peer) {
- return (peer->config && peer->config->hostname);
-}
-
-static inline bool fastd_peer_is_waiting(const fastd_peer *peer) {
- return (peer->state == STATE_WAIT);
-}
-
-static inline bool fastd_peer_is_temporary(const fastd_peer *peer) {
- return (peer->state == STATE_TEMP);
+ return fastd_peer_config_is_dynamic(peer->config);
}
static inline bool fastd_peer_is_established(const fastd_peer *peer) {
- return (peer->state == STATE_ESTABLISHED);
+ return peer->established;
}
static inline void fastd_peer_seen(fastd_context *ctx, fastd_peer *peer) {
diff --git a/src/printf.c b/src/printf.c
index 7c922c5..cbecbc8 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -31,37 +31,35 @@
#include <stdarg.h>
-static void print_peer_str(const fastd_context *ctx, const fastd_peer *peer) {
+static void print_peer_address(const fastd_context *ctx, const fastd_peer_address *address) {
char addr_buf[INET6_ADDRSTRLEN] = "";
- char pl = '<', pr = '>';
- if (fastd_peer_is_temporary(peer)) {
- pl = '{';
- pr = '}';
+ switch (address->sa.sa_family) {
+ case AF_UNSPEC:
+ fputs("floating", stderr);
+ return;
+
+ case AF_INET:
+ if (inet_ntop(AF_INET, &address->in.sin_addr, addr_buf, sizeof(addr_buf)))
+ fprintf(stderr, "%s:%u", addr_buf, ntohs(address->in.sin_port));
+ return;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6, &address->in6.sin6_addr, addr_buf, sizeof(addr_buf)))
+ fprintf(stderr, "[%s]:%u", addr_buf, ntohs(address->in6.sin6_port));
+ break;
+
+ default:
+ exit_bug(ctx, "unsupported address family");
}
+}
+static void print_peer_str(const fastd_context *ctx, const fastd_peer *peer) {
if (peer->config && peer->config->name) {
- fprintf(stderr, "%c%s%c", pl, peer->config->name, pr);
+ fprintf(stderr, "<%s>", peer->config->name);
}
else {
- switch (peer->address.sa.sa_family) {
- case AF_UNSPEC:
- fprintf(stderr, "%cfloating%c", pl, pr);
- return;
-
- case AF_INET:
- if (inet_ntop(AF_INET, &peer->address.in.sin_addr, addr_buf, sizeof(addr_buf)))
- fprintf(stderr, "%c%s:%u%c", pl, addr_buf, ntohs(peer->address.in.sin_port), pr);
- return;
-
- case AF_INET6:
- if (inet_ntop(AF_INET6, &peer->address.in6.sin6_addr, addr_buf, sizeof(addr_buf)))
- fprintf(stderr, "%c[%s]:%u%c", pl, addr_buf, ntohs(peer->address.in6.sin6_port), pr);
- break;
-
- default:
- exit_bug(ctx, "unsupported address family");
- }
+ fputs("<(null)>", stderr);
}
}
@@ -84,10 +82,8 @@ void fastd_printf(const fastd_context *ctx, const char *format, ...) {
for(len = 1; str[len]; len++) {
char last;
bool finished = true;
- char addr_buf[INET6_ADDRSTRLEN];
- void *p;
- fastd_peer *peer;
- fastd_eth_addr *eth_addr;
+ const void *p;
+ const fastd_eth_addr *eth_addr;
switch (str[len]) {
case 'l':
@@ -190,20 +186,8 @@ void fastd_printf(const fastd_context *ctx, const char *format, ...) {
str[len+1] = last;
break;
- case 'I':
- p = va_arg(ap, void*);
-
- if (p) {
- if (inet_ntop(flag_l ? AF_INET6 : AF_INET, p, addr_buf, sizeof(addr_buf)))
- fputs(addr_buf, stderr);
- }
- else {
- fputs("(null)", stderr);
- }
- break;
-
case 'E':
- eth_addr = va_arg(ap, fastd_eth_addr*);
+ eth_addr = va_arg(ap, const fastd_eth_addr*);
if (eth_addr) {
fprintf(stderr, "%02x:%02x:%02x:%02x:%02x:%02x",
@@ -216,10 +200,19 @@ void fastd_printf(const fastd_context *ctx, const char *format, ...) {
break;
case 'P':
- peer = va_arg(ap, void*);
+ p = va_arg(ap, const fastd_peer*);
+
+ if (p)
+ print_peer_str(ctx, (const fastd_peer*)p);
+ else
+ fputs("(null)", stderr);
+ break;
+
+ case 'I':
+ p = va_arg(ap, const fastd_peer_address*);
- if (peer)
- print_peer_str(ctx, peer);
+ if (p)
+ print_peer_address(ctx, (const fastd_peer_address*)p);
else
fputs("(null)", stderr);
break;
diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c
index 93fd9c4..e4a0e93 100644
--- a/src/protocol_ec25519_fhmqvc.c
+++ b/src/protocol_ec25519_fhmqvc.c
@@ -58,26 +58,22 @@ struct _fastd_protocol_config {
ecc_public_key_256 public_key;
};
-typedef enum _handshake_state {
- HANDSHAKE_STATE_INIT,
- HANDSHAKE_STATE_RESPONSE,
- HANDSHAKE_STATE_ESTABLISHED
-} handshake_state;
+typedef struct _handshake_key {
+ struct timespec preferred_till;
+ struct timespec valid_till;
-struct _fastd_protocol_peer_config {
+ ecc_secret_key_256 secret_key;
ecc_public_key_256 public_key;
-};
+} handshake_key;
-typedef struct _protocol_handshake {
- const fastd_peer_config *peer_config;
+struct _fastd_protocol_state {
+ handshake_key prev_handshake_key;
+ handshake_key handshake_key;
+};
- handshake_state state;
- ecc_secret_key_256 secret_key;
+struct _fastd_protocol_peer_config {
ecc_public_key_256 public_key;
- ecc_public_key_256 peer_key;
- ecc_public_key_256 sigma;
- uint8_t shared_handshake_key[HASHBYTES];
-} protocol_handshake;
+};
typedef struct _protocol_session {
bool handshakes_cleaned;
@@ -89,9 +85,6 @@ typedef struct _protocol_session {
struct _fastd_protocol_peer_state {
protocol_session old_session;
protocol_session session;
-
- protocol_handshake *initiating_handshake;
- protocol_handshake *accepting_handshake;
};
@@ -116,6 +109,14 @@ static inline bool read_key(uint8_t key[32], const char *hexkey) {
return true;
}
+static inline bool is_handshake_key_valid(fastd_context *ctx, const handshake_key *handshake_key) {
+ return timespec_after(&handshake_key->valid_till, &ctx->now);
+}
+
+static inline bool is_handshake_key_preferred(fastd_context *ctx, const handshake_key *handshake_key) {
+ return timespec_after(&handshake_key->preferred_till, &ctx->now);
+}
+
static inline bool is_session_valid(fastd_context *ctx, const protocol_session *session) {
return ctx->conf->method->session_is_valid(ctx, session->method_state);
}
@@ -123,7 +124,7 @@ static inline bool is_session_valid(fastd_context *ctx, const protocol_session *
static inline void check_session_refresh(fastd_context *ctx, fastd_peer *peer) {
protocol_session *session = &peer->protocol_state->session;
- if (!session->refreshing && ctx->conf->method->session_want_refresh(ctx, session->method_state)) {
+ if (!session->refreshing && ctx->conf->method->session_is_initiator(ctx, session->method_state) && ctx->conf->method->session_want_refresh(ctx, session->method_state)) {
pr_debug(ctx, "refreshing session with %P", peer);
session->refreshing = true;
fastd_task_schedule_handshake(ctx, peer, 0);
@@ -173,89 +174,67 @@ static void init_peer_state(fastd_context *ctx, fastd_peer *peer) {
memset(peer->protocol_state, 0, sizeof(fastd_protocol_peer_state));
}
-static inline void free_handshake(protocol_handshake *handshake) {
+static inline void free_handshake_key(handshake_key *handshake) {
if (handshake) {
- memset(handshake, 0, sizeof(protocol_handshake));
+ memset(handshake, 0, sizeof(handshake_key));
free(handshake);
}
}
-static void protocol_peer_config_purged(fastd_context *ctx, fastd_peer_config *peer_conf) {
- fastd_peer *peer;
- for (peer = ctx->peers; peer; peer = peer->next) {
- if (!peer->protocol_state)
- continue;
-
- if (peer->protocol_state->initiating_handshake &&
- peer->protocol_state->initiating_handshake->peer_config == peer_conf) {
- free_handshake(peer->protocol_state->initiating_handshake);
- peer->protocol_state->initiating_handshake = NULL;
- }
-
- if (peer->protocol_state->accepting_handshake &&
- peer->protocol_state->accepting_handshake->peer_config == peer_conf) {
- free_handshake(peer->protocol_state->accepting_handshake);
- peer->protocol_state->accepting_handshake = NULL;
- }
+static void maintenance(fastd_context *ctx) {
+ if (!ctx->protocol_state) {
+ ctx->protocol_state = malloc(sizeof(fastd_protocol_state));
+ memset(ctx->protocol_state, 0, sizeof(fastd_protocol_state));
}
-}
-static protocol_handshake* new_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiate) {
- protocol_handshake **handshake;
+ if (!is_handshake_key_preferred(ctx, &ctx->protocol_state->handshake_key)) {
+ pr_debug(ctx, "generating new handshake key");
- if (initiate)
- handshake = &peer->protocol_state->initiating_handshake;
- else
- handshake = &peer->protocol_state->accepting_handshake;
-
- free_handshake(*handshake);
-
- *handshake = malloc(sizeof(protocol_handshake));
+ ctx->protocol_state->prev_handshake_key = ctx->protocol_state->handshake_key;
- (*handshake)->peer_config = peer_config;
+ fastd_random_bytes(ctx, ctx->protocol_state->handshake_key.secret_key.s, 32, false);
+ ecc_25519_secret_sanitize(&ctx->protocol_state->handshake_key.secret_key, &ctx->protocol_state->handshake_key.secret_key);
- (*handshake)->state = HANDSHAKE_STATE_INIT;
+ ecc_25519_work work;
+ ecc_25519_scalarmult_base(&work, &ctx->protocol_state->handshake_key.secret_key);
+ ecc_25519_store(&ctx->protocol_state->handshake_key.public_key, &work);
- fastd_random_bytes(ctx, (*handshake)->secret_key.s, 32, false);
- ecc_25519_secret_sanitize(&(*handshake)->secret_key, &(*handshake)->secret_key);
+ ctx->protocol_state->handshake_key.preferred_till = ctx->now;
+ ctx->protocol_state->handshake_key.preferred_till.tv_sec += 15;
- ecc_25519_work work;
- ecc_25519_scalarmult_base(&work, &(*handshake)->secret_key);
- ecc_25519_store(&(*handshake)->public_key, &work);
-
- return *handshake;
+ ctx->protocol_state->handshake_key.valid_till = ctx->now;
+ ctx->protocol_state->handshake_key.valid_till.tv_sec += 30;
+ }
}
-static void protocol_handshake_init(fastd_context *ctx, fastd_peer *peer) {
- init_peer_state(ctx, peer);
-
- fastd_buffer buffer = fastd_handshake_new_init(ctx, peer, 3*(4+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */);
+static void protocol_handshake_init(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf) {
+ maintenance(ctx);
- protocol_handshake *handshake = new_handshake(ctx, peer, peer->config, true);
+ fastd_buffer buffer = fastd_handshake_new_init(ctx, 3*(4+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */);
fastd_handshake_add(ctx, &buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p);
- if (handshake->peer_config)
- fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, handshake->peer_config->protocol_config->public_key.p);
+ if (peer_conf)
+ fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer_conf->protocol_config->public_key.p);
else
- pr_debug(ctx, "sending handshake to unknown peer %P", peer);
+ pr_debug(ctx, "sending handshake to unknown peer %I", address);
- fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, handshake->public_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, ctx->protocol_state->handshake_key.public_key.p);
- fastd_send_handshake(ctx, peer, buffer);
+ fastd_send_handshake(ctx, address, buffer);
}
-static void respond_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) {
- pr_debug(ctx, "responding handshake with %P...", peer);
+static void respond_handshake(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, const fastd_handshake *handshake) {
+ pr_debug(ctx, "responding handshake with %I...", address);
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hashbuf[HASHBYTES];
uint8_t hmacbuf[HMACBYTES];
- memcpy(hashinput, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput, handshake_key->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+PUBLICKEYBYTES, peer_handshake_key->p, PUBLICKEYBYTES);
memcpy(hashinput+2*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+3*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+3*PUBLICKEYBYTES, peer_conf->protocol_config->public_key.p, PUBLICKEYBYTES);
crypto_hash_sha256(hashbuf, hashinput, 4*PUBLICKEYBYTES);
@@ -268,11 +247,11 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_
e.s[15] |= 0x80;
ecc_25519_secret_mult(&eb, &e, &ctx->conf->protocol_config->secret_key);
- ecc_25519_secret_add(&s, &eb, &peer->protocol_state->accepting_handshake->secret_key);
+ ecc_25519_secret_add(&s, &eb, &handshake_key->secret_key);
ecc_25519_work work, workX;
- ecc_25519_load(&work, &peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key);
- ecc_25519_load(&workX, &peer->protocol_state->accepting_handshake->peer_key);
+ ecc_25519_load(&work, &peer_conf->protocol_config->public_key);
+ ecc_25519_load(&workX, peer_handshake_key);
ecc_25519_scalarmult(&work, &d, &work);
ecc_25519_add(&work, &workX, &work);
@@ -281,36 +260,46 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_
if (ecc_25519_is_identity(&work))
return;
- ecc_25519_store(&peer->protocol_state->accepting_handshake->sigma, &work);
+ ecc_public_key_256 sigma;
+ ecc_25519_store(&sigma, &work);
- memcpy(hashinput+4*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->sigma.p, PUBLICKEYBYTES);
- crypto_hash_sha256(peer->protocol_state->accepting_handshake->shared_handshake_key, hashinput, 5*PUBLICKEYBYTES);
+ uint8_t shared_handshake_key[HASHBYTES];
+ memcpy(hashinput+4*PUBLICKEYBYTES, sigma.p, PUBLICKEYBYTES);
+ crypto_hash_sha256(shared_handshake_key, hashinput, 5*PUBLICKEYBYTES);
memcpy(hashinput, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+PUBLICKEYBYTES, handshake_key->public_key.p, PUBLICKEYBYTES);
- crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->shared_handshake_key);
+ crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key);
- fastd_buffer buffer = fastd_handshake_new_reply(ctx, peer, handshake, 4*(4+PUBLICKEYBYTES) + 4+HMACBYTES);
+ fastd_buffer buffer = fastd_handshake_new_reply(ctx, handshake, 4*(4+PUBLICKEYBYTES) + 4+HMACBYTES);
fastd_handshake_add(ctx, &buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p);
- fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p);
- fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->public_key.p);
- fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer_conf->protocol_config->public_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, handshake_key->public_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key->p);
fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf);
- fastd_send_handshake(ctx, peer, buffer);
-
- peer->protocol_state->accepting_handshake->state = HANDSHAKE_STATE_RESPONSE;
+ fastd_send_handshake(ctx, address, buffer);
}
-static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiator,
+static void establish(fastd_context *ctx, const fastd_peer_config *peer_conf, const fastd_peer_address *address, bool initiator,
const ecc_public_key_256 *A, const ecc_public_key_256 *B, const ecc_public_key_256 *X,
const ecc_public_key_256 *Y, const ecc_public_key_256 *sigma) {
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hash[HASHBYTES];
- pr_verbose(ctx, "New session with %P established.", peer);
+ fastd_peer *peer;
+ for (peer = ctx->peers; peer; peer = peer->next) {
+ if (peer->config == peer_conf)
+ break;
+ }
+ if (!peer)
+ exit_bug(ctx, "no peer for config found");
+
+ pr_verbose(ctx, "%I authorized as %P", address, peer);
+
+ init_peer_state(ctx, peer);
if (is_session_valid(ctx, &peer->protocol_state->session) && !is_session_valid(ctx, &peer->protocol_state->old_session)) {
ctx->conf->method->session_free(ctx, peer->protocol_state->old_session.method_state);
@@ -331,43 +320,34 @@ static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_con
peer->protocol_state->session.refreshing = false;
peer->protocol_state->session.method_state = ctx->conf->method->session_init(ctx, hash, HASHBYTES, initiator);
- free_handshake(peer->protocol_state->initiating_handshake);
- peer->protocol_state->initiating_handshake = NULL;
-
- free_handshake(peer->protocol_state->accepting_handshake);
- peer->protocol_state->accepting_handshake = NULL;
-
fastd_peer_seen(ctx, peer);
- if (peer_config != peer->config) {
- fastd_peer *perm_peer;
- for (perm_peer = ctx->peers; perm_peer; perm_peer = perm_peer->next) {
- if (perm_peer->config == peer_config) {
- peer = fastd_peer_set_established_merge(ctx, perm_peer, peer);
- break;
- }
- }
- }
- else {
- fastd_peer_set_established(ctx, peer);
+ if (!fastd_peer_claim_address(ctx, peer, address)) {
+ pr_warn(ctx, "can't set address %I which is used by a fixed peer", ctx->resolve_returns->addr);
+ fastd_peer_reset(ctx, peer);
+ return;
}
+ fastd_peer_set_established(ctx, peer);
+
+ pr_verbose(ctx, "new session with %P established.", peer);
+
fastd_task_schedule_keepalive(ctx, peer, ctx->conf->keepalive_interval*1000);
if (!initiator)
protocol_send(ctx, peer, fastd_buffer_alloc(0, ctx->conf->method->min_encrypt_head_space(ctx), 0));
}
-static void finish_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) {
- pr_debug(ctx, "finishing handshake with %P...", peer);
+static void finish_handshake(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, const fastd_handshake *handshake) {
+ pr_debug(ctx, "finishing handshake with %I...", address);
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hashbuf[HASHBYTES];
uint8_t hmacbuf[HMACBYTES];
- memcpy(hashinput, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput, peer_handshake_key->p, PUBLICKEYBYTES);
+ memcpy(hashinput+PUBLICKEYBYTES, handshake_key->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+2*PUBLICKEYBYTES, peer_conf->protocol_config->public_key.p, PUBLICKEYBYTES);
memcpy(hashinput+3*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES);
crypto_hash_sha256(hashbuf, hashinput, 4*PUBLICKEYBYTES);
@@ -381,11 +361,11 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_h
e.s[15] |= 0x80;
ecc_25519_secret_mult(&da, &d, &ctx->conf->protocol_config->secret_key);
- ecc_25519_secret_add(&s, &da, &peer->protocol_state->initiating_handshake->secret_key);
+ ecc_25519_secret_add(&s, &da, &handshake_key->secret_key);
ecc_25519_work work, workY;
- ecc_25519_load(&work, &peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key);
- ecc_25519_load(&workY, &peer->protocol_state->initiating_handshake->peer_key);
+ ecc_25519_load(&work, &peer_conf->protocol_config->public_key);
+ ecc_25519_load(&workY, peer_handshake_key);
ecc_25519_scalarmult(&work, &e, &work);
ecc_25519_add(&work, &workY, &work);
@@ -394,72 +374,103 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_h
if (ecc_25519_is_identity(&work))
return;
- ecc_25519_store(&peer->protocol_state->initiating_handshake->sigma, &work);
+ ecc_public_key_256 sigma;
+ ecc_25519_store(&sigma, &work);
- memcpy(hashinput+4*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->sigma.p, PUBLICKEYBYTES);
- crypto_hash_sha256(peer->protocol_state->initiating_handshake->shared_handshake_key, hashinput, 5*PUBLICKEYBYTES);
+ uint8_t shared_handshake_key[HASHBYTES];
+ memcpy(hashinput+4*PUBLICKEYBYTES, sigma.p, PUBLICKEYBYTES);
+ crypto_hash_sha256(shared_handshake_key, hashinput, 5*PUBLICKEYBYTES);
- memcpy(hashinput, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput, peer_conf->protocol_config->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+PUBLICKEYBYTES, peer_handshake_key->p, PUBLICKEYBYTES);
- if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->shared_handshake_key) != 0) {
- pr_warn(ctx, "received invalid protocol handshake response from %P", peer);
+ if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key) != 0) {
+ pr_warn(ctx, "received invalid protocol handshake response from %I", address);
return;
}
memcpy(hashinput, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES);
- crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->shared_handshake_key);
+ memcpy(hashinput+PUBLICKEYBYTES, handshake_key->public_key.p, PUBLICKEYBYTES);
+ crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key);
- fastd_buffer buffer = fastd_handshake_new_reply(ctx, peer, handshake, 4*(4+PUBLICKEYBYTES) + 4+HMACBYTES);
+ fastd_buffer buffer = fastd_handshake_new_reply(ctx, handshake, 4*(4+PUBLICKEYBYTES) + 4+HMACBYTES);
fastd_handshake_add(ctx, &buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p);
- fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p);
- fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p);
- fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer_conf->protocol_config->public_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, handshake_key->public_key.p);
+ fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key->p);
fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf);
- fastd_send_handshake(ctx, peer, buffer);
+ fastd_send_handshake(ctx, address, buffer);
- establish(ctx, peer, peer->protocol_state->initiating_handshake->peer_config, true,
- &peer->protocol_state->initiating_handshake->public_key,
- &peer->protocol_state->initiating_handshake->peer_key,
- &ctx->conf->protocol_config->public_key,
- &peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key,
- &peer->protocol_state->initiating_handshake->sigma);
+ establish(ctx, peer_conf, address, true, &handshake_key->public_key, peer_handshake_key, &ctx->conf->protocol_config->public_key,
+ &peer_conf->protocol_config->public_key, &sigma);
}
-static void handle_finish_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) {
- pr_debug(ctx, "handling handshake finish with %P...", peer);
+static void handle_finish_handshake(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, const fastd_handshake *handshake) {
+ pr_debug(ctx, "handling handshake finish with %I...", address);
+
+ uint8_t hashinput[5*PUBLICKEYBYTES];
+ uint8_t hashbuf[HASHBYTES];
+
+ memcpy(hashinput, handshake_key->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+PUBLICKEYBYTES, peer_handshake_key->p, PUBLICKEYBYTES);
+ memcpy(hashinput+2*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+3*PUBLICKEYBYTES, peer_conf->protocol_config->public_key.p, PUBLICKEYBYTES);
+
+ crypto_hash_sha256(hashbuf, hashinput, 4*PUBLICKEYBYTES);
+
+ ecc_secret_key_256 d = {{0}}, e = {{0}}, eb, s;
+
+ memcpy(d.s, hashbuf, HASHBYTES/2);
+ memcpy(e.s, hashbuf+HASHBYTES/2, HASHBYTES/2);
+
+ d.s[15] |= 0x80;
+ e.s[15] |= 0x80;
- uint8_t hashinput[2*PUBLICKEYBYTES];
+ ecc_25519_secret_mult(&eb, &e, &ctx->conf->protocol_config->secret_key);
+ ecc_25519_secret_add(&s, &eb, &handshake_key->secret_key);
- memcpy(hashinput, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES);
- memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES);
+ ecc_25519_work work, workX;
+ ecc_25519_load(&work, &peer_conf->protocol_config->public_key);
+ ecc_25519_load(&workX, peer_handshake_key);
- if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->shared_handshake_key) != 0) {
- pr_warn(ctx, "received invalid protocol handshake finish from %P", peer);
+ ecc_25519_scalarmult(&work, &d, &work);
+ ecc_25519_add(&work, &workX, &work);
+ ecc_25519_scalarmult(&work, &s, &work);
+
+ if (ecc_25519_is_identity(&work))
+ return;
+
+ ecc_public_key_256 sigma;
+ ecc_25519_store(&sigma, &work);
+
+ uint8_t shared_handshake_key[HASHBYTES];
+ memcpy(hashinput+4*PUBLICKEYBYTES, sigma.p, PUBLICKEYBYTES);
+ crypto_hash_sha256(shared_handshake_key, hashinput, 5*PUBLICKEYBYTES);
+
+ memcpy(hashinput, peer_conf->protocol_config->public_key.p, PUBLICKEYBYTES);
+ memcpy(hashinput+PUBLICKEYBYTES, peer_handshake_key->p, PUBLICKEYBYTES);
+
+ if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key) != 0) {
+ pr_warn(ctx, "received invalid protocol handshake finish from %I", address);
return;
}
- establish(ctx, peer, peer->protocol_state->accepting_handshake->peer_config, false,
- &peer->protocol_state->accepting_handshake->peer_key,
- &peer->protocol_state->accepting_handshake->public_key,
- &peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key,
- &ctx->conf->protocol_config->public_key,
- &peer->protocol_state->accepting_handshake->sigma);
+ establish(ctx, peer_conf, address, false, peer_handshake_key, &handshake_key->public_key, &peer_conf->protocol_config->public_key,
+ &ctx->conf->protocol_config->public_key, &sigma);
}
-static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, fastd_peer *peer, const unsigned char key[32]) {
- if (peer->config) {
- if (memcmp(peer->config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0)
- return peer->config;
+static const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const unsigned char key[32]) {
+ if (peer_conf) {
+ if (memcmp(peer_conf->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0)
+ return peer_conf;
}
- if (fastd_peer_is_temporary(peer) || fastd_peer_is_floating(peer) || fastd_peer_is_dynamic(peer)) {
+ if (!peer_conf || fastd_peer_config_is_floating(peer_conf) || fastd_peer_config_is_dynamic(peer_conf)) {
fastd_peer_config *config;
for (config = ctx->conf->peers; config; config = config->next) {
- if (!fastd_peer_config_is_floating(config) && !fastd_peer_config_matches_dynamic(config, &peer->address))
+ if (!fastd_peer_config_is_floating(config) && !fastd_peer_config_matches_dynamic(config, address))
continue;
if (memcmp(config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) {
@@ -477,129 +488,89 @@ static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, fast
return NULL;
}
-static void kill_handshakes(fastd_context *ctx, fastd_peer *peer) {
- pr_debug(ctx, "there is a handshake conflict, retrying in a moment...");
-
- free_handshake(peer->protocol_state->initiating_handshake);
- peer->protocol_state->initiating_handshake = NULL;
-
- free_handshake(peer->protocol_state->accepting_handshake);
- peer->protocol_state->accepting_handshake = NULL;
-}
-
static inline bool has_field(const fastd_handshake *handshake, uint8_t type, size_t length) {
return (handshake->records[type].length == length);
}
-static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) {
- init_peer_state(ctx, peer);
+static void protocol_handshake_handle(fastd_context *ctx, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake) {
+ handshake_key *handshake_key;
+
+ maintenance(ctx);
if (!has_field(handshake, RECORD_SENDER_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake without sender key from %P", peer);
+ pr_debug(ctx, "received handshake without sender key from %I", address);
return;
}
- const fastd_peer_config *peer_config = match_sender_key(ctx, peer, handshake->records[RECORD_SENDER_KEY].data);
- if (!peer_config) {
- pr_debug(ctx, "ignoring handshake from %P (unknown key or unresolved host)", peer);
+ peer_conf = match_sender_key(ctx, address, peer_conf, handshake->records[RECORD_SENDER_KEY].data);
+ if (!peer_conf) {
+ pr_debug(ctx, "ignoring handshake from %I (unknown key or unresolved host)", address);
return;
}
if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake reply without receipient key from %P", peer);
+ pr_debug(ctx, "received handshake reply without receipient key from %I", address);
return;
}
else if(has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) {
if (memcmp(ctx->conf->protocol_config->public_key.p, handshake->records[RECORD_RECEIPIENT_KEY].data, PUBLICKEYBYTES) != 0) {
- pr_debug(ctx, "received protocol handshake with wrong receipient key from %P", peer);
+ pr_debug(ctx, "received protocol handshake with wrong receipient key from %I", address);
return;
}
}
if (!has_field(handshake, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake without sender handshake key from %P", peer);
+ pr_debug(ctx, "received handshake without sender handshake key from %I", address);
return;
}
if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake reply without receipient handshake key from %P", peer);
+ pr_debug(ctx, "received handshake reply without receipient handshake key from %I", address);
return;
}
if (handshake->type > 1 && !has_field(handshake, RECORD_T, HMACBYTES)) {
- pr_debug(ctx, "received handshake reply without HMAC from %P", peer);
+ pr_debug(ctx, "received handshake reply without HMAC from %I", address);
return;
}
switch(handshake->type) {
case 1:
- new_handshake(ctx, peer, peer_config, false);
- memcpy(peer->protocol_state->accepting_handshake->peer_key.p, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES);
- respond_handshake(ctx, peer, handshake);
+ respond_handshake(ctx, address, peer_conf, &ctx->protocol_state->handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake);
break;
case 2:
- if (!peer->protocol_state->initiating_handshake || peer->protocol_state->initiating_handshake->state != HANDSHAKE_STATE_INIT) {
- pr_debug(ctx, "received unexpected handshake response from %P", peer);
- return;
- }
-
- if (peer->protocol_state->initiating_handshake->peer_config != peer_config) {
- if (peer->protocol_state->initiating_handshake->peer_config) {
- pr_debug(ctx, "received handshake response with wrong sender key from %P", peer);
- return;
- }
- else {
- peer->protocol_state->initiating_handshake->peer_config = peer_config;
- }
+ if (is_handshake_key_valid(ctx, &ctx->protocol_state->handshake_key) && memcmp(ctx->protocol_state->handshake_key.public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) {
+ handshake_key = &ctx->protocol_state->handshake_key;
}
-
- if (memcmp(peer->protocol_state->initiating_handshake->public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) != 0) {
- pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P", peer);
- return;
+ else if (is_handshake_key_valid(ctx, &ctx->protocol_state->prev_handshake_key) && memcmp(ctx->protocol_state->prev_handshake_key.public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) {
+ handshake_key = &ctx->protocol_state->prev_handshake_key;
}
-
- pr_debug(ctx, "received handshake response from %P", peer);
-
- if (peer->protocol_state->accepting_handshake) {
- kill_handshakes(ctx, peer);
+ else {
+ pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %I", address);
return;
}
- memcpy(peer->protocol_state->initiating_handshake->peer_key.p, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES);
+ pr_debug(ctx, "received handshake response from %I", address);
- finish_handshake(ctx, peer, handshake);
+ finish_handshake(ctx, address, peer_conf, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake);
break;
case 3:
- if (!peer->protocol_state->accepting_handshake || peer->protocol_state->accepting_handshake->state != HANDSHAKE_STATE_RESPONSE) {
- pr_debug(ctx, "received unexpected protocol handshake finish from %P", peer);
- return;
+ if (is_handshake_key_valid(ctx, &ctx->protocol_state->handshake_key) && memcmp(ctx->protocol_state->handshake_key.public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) {
+ handshake_key = &ctx->protocol_state->handshake_key;
}
-
- if (peer->protocol_state->accepting_handshake->peer_config != peer_config) {
- pr_debug(ctx, "received protocol handshake finish with wrong sender key from %P", peer);
- return;
+ else if (is_handshake_key_valid(ctx, &ctx->protocol_state->prev_handshake_key) && memcmp(ctx->protocol_state->prev_handshake_key.public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) {
+ handshake_key = &ctx->protocol_state->prev_handshake_key;
}
-
- if (memcmp(peer->protocol_state->accepting_handshake->public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) != 0) {
- pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P", peer);
+ else {
+ pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %I", address);
return;
}
- if (memcmp(peer->protocol_state->accepting_handshake->peer_key.p, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES) != 0) {
- pr_debug(ctx, "received handshake response with unexpected sender handshake key from %P", peer);
- return;
- }
+ pr_debug(ctx, "received handshake finish from %I", address);
- pr_debug(ctx, "received handshake finish from %P", peer);
-
- if (peer->protocol_state->initiating_handshake && peer->protocol_state->initiating_handshake->state != HANDSHAKE_STATE_INIT) {
- kill_handshakes(ctx, peer);
- return;
- }
-
- handle_finish_handshake(ctx, peer, handshake);
+ handle_finish_handshake(ctx, address, peer_conf, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake);
break;
default:
@@ -609,12 +580,8 @@ static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, cons
static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) {
if (!fastd_peer_is_established(peer)) {
- pr_debug(ctx, "received unexpected packet from %P", peer);
-
- if (fastd_peer_is_temporary(peer)) {
- pr_debug(ctx, "sending handshake to temporary peer %P", peer);
- fastd_task_schedule_handshake(ctx, peer, 0);
- }
+ pr_debug(ctx, "received unexpected packet from %P, scheduling handshake", peer);
+ fastd_task_schedule_handshake(ctx, peer, 0);
goto fail;
}
@@ -690,7 +657,7 @@ static void protocol_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buf
if (!ctx->conf->method->encrypt(ctx, session->method_state, &send_buffer, buffer))
goto fail;
- fastd_send(ctx, peer, send_buffer);
+ fastd_send(ctx, &peer->address, send_buffer);
fastd_task_delete_peer_keepalives(ctx, peer);
fastd_task_schedule_keepalive(ctx, peer, ctx->conf->keepalive_interval*1000);
@@ -702,9 +669,6 @@ static void protocol_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buf
static void protocol_free_peer_state(fastd_context *ctx, fastd_peer *peer) {
if (peer->protocol_state) {
- free_handshake(peer->protocol_state->initiating_handshake);
- free_handshake(peer->protocol_state->accepting_handshake);
-
ctx->conf->method->session_free(ctx, peer->protocol_state->old_session.method_state);
ctx->conf->method->session_free(ctx, peer->protocol_state->session.method_state);
@@ -712,7 +676,6 @@ static void protocol_free_peer_state(fastd_context *ctx, fastd_peer *peer) {
}
}
-
static void hexdump(const char *desc, unsigned char d[32]) {
printf("%s", desc);
@@ -746,7 +709,6 @@ const fastd_protocol fastd_protocol_ec25519_fhmqvc = {
.init = protocol_init,
.peer_configure = protocol_peer_configure,
- .peer_config_purged = protocol_peer_config_purged,
.handshake_init = protocol_handshake_init,
.handshake_handle = protocol_handshake_handle,
diff --git a/src/types.h b/src/types.h
index c48cf59..6efd224 100644
--- a/src/types.h
+++ b/src/types.h
@@ -47,13 +47,6 @@ typedef enum _fastd_mode {
MODE_TUN,
} fastd_mode;
-typedef enum _fastd_peer_state {
- STATE_RESOLVE,
- STATE_WAIT,
- STATE_TEMP,
- STATE_ESTABLISHED,
-} fastd_peer_state;
-
typedef struct _fastd_buffer fastd_buffer;
@@ -78,6 +71,7 @@ typedef struct _fastd_resolve_return fastd_resolve_return;
/* May be defined by the protocol/method however it likes */
typedef struct _fastd_protocol_config fastd_protocol_config;
+typedef struct _fastd_protocol_state fastd_protocol_state;
typedef struct _fastd_protocol_peer_config fastd_protocol_peer_config;
typedef struct _fastd_protocol_peer_state fastd_protocol_peer_state;
typedef struct _fastd_method_session_state fastd_method_session_state;