From 3065f96f7b833701a03f5759bfc593a7f6943c4e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 27 Mar 2012 22:43:19 +0200 Subject: New handshake format; don't respond to data packets from unknown peers with handshakes, but request a re-handshake --- src/fastd.c | 8 +- src/handshake.c | 98 +++++++++++++++++-------- src/handshake.h | 1 + src/packet.h | 24 +++--- src/peer.c | 2 +- src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c | 21 +++--- src/protocol_null.c | 3 +- src/task.c | 3 +- src/task.h | 7 +- 9 files changed, 106 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/fastd.c b/src/fastd.c index d2e0881..70f4248 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -180,14 +180,14 @@ static void handle_tasks(fastd_context *ctx) { break; case TASK_HANDSHAKE: - if (task->peer->state != STATE_WAIT && task->peer->state != STATE_TEMP) + if (task->peer->state != STATE_WAIT && task->peer->state != STATE_TEMP && !task->handshake.force) break; pr_debug(ctx, "Sending handshake to %P...", task->peer); fastd_handshake_send(ctx, task->peer); if (task->peer->state == STATE_WAIT) - fastd_task_schedule_handshake(ctx, task->peer, 20000); + fastd_task_schedule_handshake(ctx, task->peer, 20000, false); break; default: @@ -314,7 +314,9 @@ static void handle_socket(fastd_context *ctx, int sockfd) { fastd_buffer_free(buffer); peer = fastd_peer_add_temp(ctx, (fastd_peer_address*)&recvaddr); - fastd_task_schedule_handshake(ctx, peer, 0); + ctx->conf->protocol->handle_recv(ctx, peer, buffer); + pr_debug(ctx, "Requesting re-handshake from %P", peer); + fastd_handshake_rehandshake(ctx, peer); break; case PACKET_HANDSHAKE: diff --git a/src/handshake.c b/src/handshake.c index 97ddde4..29ed692 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -34,6 +34,7 @@ static const char const *RECORD_TYPES[RECORD_MAX] = { + "handshake type", "reply code", "error detail", "flags", @@ -47,6 +48,7 @@ static const char const *REPLY_TYPES[REPLY_MAX] = { "unacceptable value", }; +#define AS_UINT8(ptr) (*(uint8_t*)(ptr)) static inline void handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) { if ((uint8_t*)buffer->data + buffer->len + 2 + len > (uint8_t*)buffer->base + buffer->base_len) @@ -61,32 +63,54 @@ static inline void handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd buffer->len += 2 + len; } +static inline void handshake_add_uint8(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, uint8_t value) { + if ((uint8_t*)buffer->data + buffer->len + 3 > (uint8_t*)buffer->base + buffer->base_len) + exit_bug(ctx, "not enough buffer allocated for handshake"); + + uint8_t *dst = (uint8_t*)buffer->data + buffer->len; + + dst[0] = type; + dst[1] = 1; + dst[2] = value; + + buffer->len += 3; +} + void fastd_handshake_send(fastd_context *ctx, fastd_peer *peer) { size_t protocol_len = strlen(ctx->conf->protocol->name); fastd_buffer buffer = fastd_buffer_alloc(sizeof(fastd_packet), 0, - 2+1 + /* mode */ + 2*3 + /* handshake type, mode */ 2+protocol_len /* protocol name */ ); fastd_packet *request = buffer.data; - request->reply = 0; - request->cp = 0; request->req_id = ++peer->last_req_id; request->rsv = 0; - uint8_t mode = ctx->conf->mode; - handshake_add(ctx, &buffer, RECORD_MODE, 1, &mode); + handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, HANDSHAKE_REQUEST); + handshake_add_uint8(ctx, &buffer, RECORD_MODE, ctx->conf->mode); handshake_add(ctx, &buffer, RECORD_PROTOCOL_NAME, protocol_len, ctx->conf->protocol->name); fastd_task_put_send_handshake(ctx, peer, buffer); } +void fastd_handshake_rehandshake(fastd_context *ctx, fastd_peer *peer) { + size_t protocol_len = strlen(ctx->conf->protocol->name); + fastd_buffer buffer = fastd_buffer_alloc(sizeof(fastd_packet), 0, 3 /* handshake type */); + fastd_packet *request = buffer.data; + + request->req_id = ++peer->last_req_id; + request->rsv = 0; + + handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, HANDSHAKE_REHANDSHAKE_REQUEST); + fastd_task_put_send_handshake(ctx, peer, buffer); +} void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { if (buffer.len < sizeof(fastd_packet)) { - pr_warn(ctx, "received an invalid handshake from %P", peer); + pr_warn(ctx, "received a short handshake from %P", peer); goto end_free; } @@ -112,12 +136,22 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b ptr += 2+len; } - if (!packet->reply) { - fastd_buffer reply_buffer; - fastd_packet *reply; + if (!records[RECORD_HANDSHAKE_TYPE]) { + pr_warn(ctx, "received a handshake without type from %P", peer); + goto end_free; + } - uint8_t reply_code = REPLY_SUCCESS; - uint8_t error_detail = 0; + fastd_buffer reply_buffer; + fastd_packet *reply; + + uint8_t reply_code; + uint8_t error_detail; + const char *error_field_str; + + switch (AS_UINT8(records[RECORD_HANDSHAKE_TYPE])) { + case HANDSHAKE_REQUEST: + reply_code = REPLY_SUCCESS; + error_detail = 0; if (!records[RECORD_MODE]) { reply_code = REPLY_MANDATORY_MISSING; @@ -125,7 +159,7 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b goto send_reply; } - if (lengths[RECORD_MODE] != 1 || *(uint8_t*)records[RECORD_MODE] != ctx->conf->mode) { + if (lengths[RECORD_MODE] != 1 || AS_UINT8(records[RECORD_MODE]) != ctx->conf->mode) { reply_code = REPLY_UNACCEPTABLE_VALUE; error_detail = RECORD_MODE; goto send_reply; @@ -145,30 +179,26 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b } send_reply: - reply_buffer = fastd_buffer_alloc(sizeof(fastd_packet), 0, 6 /* enough space for reply code and error detail */); + reply_buffer = fastd_buffer_alloc(sizeof(fastd_packet), 0, 3*3 /* enough space for handshake type, reply code and error detail */); reply = reply_buffer.data; - reply->reply = 1; - reply->cp = packet->cp; reply->req_id = packet->req_id; reply->rsv = 0; - handshake_add(ctx, &reply_buffer, RECORD_REPLY_CODE, 1, &reply_code); + handshake_add_uint8(ctx, &reply_buffer, RECORD_HANDSHAKE_TYPE, HANDSHAKE_REPLY); + handshake_add_uint8(ctx, &reply_buffer, RECORD_REPLY_CODE, reply_code); if (reply_code) - handshake_add(ctx, &reply_buffer, RECORD_ERROR_DETAIL, 1, &error_detail); + handshake_add_uint8(ctx, &reply_buffer, RECORD_ERROR_DETAIL, error_detail); fastd_task_put_send_handshake(ctx, peer, reply_buffer); - } - else { - if (!packet->cp) { - 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; - } - } - else { - goto end_free; /* TODO */ + + break; + + case HANDSHAKE_REPLY: + 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 (!records[RECORD_REPLY_CODE] || lengths[RECORD_REPLY_CODE] != 1) { @@ -176,9 +206,7 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b goto end_free; } - uint8_t reply_code = *(uint8_t*)records[RECORD_REPLY_CODE]; - uint8_t error_detail; - const char *error_field_str; + reply_code = AS_UINT8(records[RECORD_REPLY_CODE]); switch (reply_code) { case REPLY_SUCCESS: @@ -198,7 +226,7 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b break; } - error_detail = *(uint8_t*)records[RECORD_ERROR_DETAIL]; + error_detail = AS_UINT8(records[RECORD_ERROR_DETAIL]); if (error_detail >= RECORD_MAX) error_field_str = ""; else @@ -217,6 +245,14 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b break; } } + break; + + case HANDSHAKE_REHANDSHAKE_REQUEST: + fastd_task_schedule_handshake(ctx, peer, 0, true); + break; + + default: + pr_warn(ctx, "received a handshake with unknown type from %P", peer); } end_free: diff --git a/src/handshake.h b/src/handshake.h index 3457a0e..c485576 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -31,6 +31,7 @@ #include "fastd.h" void fastd_handshake_send(fastd_context *ctx, fastd_peer *peer); +void fastd_handshake_rehandshake(fastd_context *ctx, fastd_peer *peer); void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); #endif /* _FASTD_HANDSHAKE_H_ */ diff --git a/src/packet.h b/src/packet.h index 0960cce..b99f7de 100644 --- a/src/packet.h +++ b/src/packet.h @@ -28,7 +28,6 @@ #ifndef _FASTD_PACKET_H_ #define _FASTD_PACKET_H_ -#include #include @@ -39,7 +38,8 @@ typedef enum _fastd_packet_type { } fastd_packet_type; typedef enum _fastd_handshake_record_type { - RECORD_REPLY_CODE = 0, + RECORD_HANDSHAKE_TYPE = 0, + RECORD_REPLY_CODE, RECORD_ERROR_DETAIL, RECORD_FLAGS, RECORD_MODE, @@ -47,6 +47,13 @@ typedef enum _fastd_handshake_record_type { RECORD_MAX, } fastd_handshake_record_type; +typedef enum _fastd_handshake_type { + HANDSHAKE_REQUEST = 0, + HANDSHAKE_REPLY, + HANDSHAKE_REHANDSHAKE_REQUEST, + HANDSHAKE_MAX, +} fastd_handshake_type; + typedef enum _fastd_reply_code { REPLY_SUCCESS = 0, REPLY_MANDATORY_MISSING, @@ -56,18 +63,7 @@ typedef enum _fastd_reply_code { typedef struct __attribute__ ((__packed__)) _fastd_packet { -#if defined(__LITTLE_ENDIAN_BITFIELD) - unsigned req_id : 6; - unsigned cp : 1; - unsigned reply : 1; -#elif defined (__BIG_ENDIAN_BITFIELD) - unsigned reply : 1; - unsigned cp : 1; - unsigned req_id : 6; -#else -#error "Bitfield endianess not defined." -#endif - + uint8_t req_id; uint16_t rsv; uint8_t tlv_data[]; } fastd_packet; diff --git a/src/peer.c b/src/peer.c index cae108f..f2f79dd 100644 --- a/src/peer.c +++ b/src/peer.c @@ -60,7 +60,7 @@ static inline void setup_peer(fastd_context *ctx, fastd_peer *peer) { peer->seen = (struct timespec){0, 0}; if (!fastd_peer_is_floating(peer)) - fastd_task_schedule_handshake(ctx, peer, 0); + fastd_task_schedule_handshake(ctx, peer, 0, false); } diff --git a/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c b/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c index 6f59323..8ef0efb 100644 --- a/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c +++ b/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c @@ -281,18 +281,21 @@ static void protocol_init_peer(fastd_context *ctx, fastd_peer *peer) { } create_peer_state(ctx, peer); - new_handshake(ctx, peer, true); - fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_init_packet), 0, 0); - protocol_handshake_init_packet *packet = buffer.data; + if (!fastd_peer_is_temporary(peer)) { + new_handshake(ctx, peer, true); - memset(packet->common.noncepad, 0, NONCEBYTES); - packet->common.type = HANDSHAKE_PACKET_INIT; - memcpy(packet->common.sender_key, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(packet->common.receipient_key, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(packet->handshake_key, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); + fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_init_packet), 0, 0); + protocol_handshake_init_packet *packet = buffer.data; - fastd_task_put_send(ctx, peer, buffer); + memset(packet->common.noncepad, 0, NONCEBYTES); + packet->common.type = HANDSHAKE_PACKET_INIT; + memcpy(packet->common.sender_key, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(packet->common.receipient_key, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(packet->handshake_key, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); + + fastd_task_put_send(ctx, peer, buffer); + } } static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { diff --git a/src/protocol_null.c b/src/protocol_null.c index b22e03e..24cb58b 100644 --- a/src/protocol_null.c +++ b/src/protocol_null.c @@ -50,7 +50,8 @@ static size_t protocol_min_head_space(fastd_context *ctx) { static void protocol_init_peer(fastd_context *ctx, fastd_peer *peer) { pr_info(ctx, "Connection with %P established.", peer); - fastd_task_put_send(ctx, peer, fastd_buffer_alloc(0, 0, 0)); + if (!fastd_peer_is_temporary(peer)) + fastd_task_put_send(ctx, peer, fastd_buffer_alloc(0, 0, 0)); } static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { diff --git a/src/task.c b/src/task.c index 2726ced..472d491 100644 --- a/src/task.c +++ b/src/task.c @@ -61,11 +61,12 @@ void fastd_task_put_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buff fastd_queue_put(ctx, &ctx->task_queue, &task->entry, 0); } -void fastd_task_schedule_handshake(fastd_context *ctx, fastd_peer *peer, int timeout) { +void fastd_task_schedule_handshake(fastd_context *ctx, fastd_peer *peer, int timeout, bool force) { fastd_task *task = malloc(sizeof(fastd_task)); task->type = TASK_HANDSHAKE; task->peer = peer; + task->handshake.force = force; fastd_queue_put(ctx, &ctx->task_queue, &task->entry, timeout); } diff --git a/src/task.h b/src/task.h index 367502e..80c6852 100644 --- a/src/task.h +++ b/src/task.h @@ -52,6 +52,10 @@ typedef struct _fastd_task_handle_recv { fastd_buffer buffer; } fastd_task_handle_recv; +typedef struct _fastd_task_handshake { + bool force; +} fastd_task_handshake; + typedef struct _fastd_task { fastd_queue_entry entry; @@ -61,6 +65,7 @@ typedef struct _fastd_task { union { fastd_task_send send; fastd_task_handle_recv handle_recv; + fastd_task_handshake handshake; }; } fastd_task; @@ -77,7 +82,7 @@ void fastd_task_put_send_handshake(fastd_context *ctx, fastd_peer *peer, fastd_b void fastd_task_put_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); void fastd_task_put_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); -void fastd_task_schedule_handshake(fastd_context *ctx, fastd_peer *peer, int timeout); +void fastd_task_schedule_handshake(fastd_context *ctx, fastd_peer *peer, int timeout, bool force); void fastd_task_delete_peer(fastd_context *ctx, fastd_peer *peer); -- cgit v1.2.3