349 lines
11 KiB
C
349 lines
11 KiB
C
#include "include/conf.h"
|
||
|
||
#include "include/pow.h"
|
||
#include "include/proto.h"
|
||
|
||
#include "server/include/pow.h"
|
||
#include "server/include/proto.h"
|
||
|
||
static int dc_see_error(SSL *ssl, dp_Logger *logger, uint8_t type) {
|
||
if (type != (uint8_t)dp_PacketType_error) {
|
||
return 0; /* Not an error packet, nothing to do */
|
||
}
|
||
|
||
uint8_t msg_len_buf[2] = {0};
|
||
if (SSL_read(ssl, msg_len_buf, sizeof(msg_len_buf)) !=
|
||
sizeof(msg_len_buf)) {
|
||
return -1;
|
||
}
|
||
const uint16_t msg_len =
|
||
(uint16_t)msg_len_buf[0] |
|
||
(uint16_t)((uint16_t)msg_len_buf[1] << (uint16_t)8);
|
||
if (msg_len == 0) {
|
||
return -1;
|
||
}
|
||
|
||
uint8_t error_code_buf[2] = {0};
|
||
if (SSL_read(ssl, error_code_buf, sizeof(error_code_buf)) !=
|
||
sizeof(error_code_buf)) {
|
||
return -1;
|
||
}
|
||
const uint16_t error_code =
|
||
(uint16_t)error_code_buf[0] |
|
||
(uint16_t)((uint16_t)error_code_buf[1] << (uint16_t)8);
|
||
const char *error_label = dp_PacketError_to_str(error_code);
|
||
|
||
char *msg = DC_MALLOC(msg_len + 1);
|
||
if (SSL_read(ssl, msg, msg_len) != msg_len) {
|
||
DC_FREE(msg);
|
||
return -1;
|
||
}
|
||
msg[msg_len] = '\0';
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG, "Received %s error (%u): %s",
|
||
error_label, error_code, msg);
|
||
DC_FREE(msg);
|
||
|
||
return 1;
|
||
}
|
||
|
||
bool dc_proto_read_server_info(SSL *ssl, dp_Logger *logger) {
|
||
if (!ssl || !logger) {
|
||
return false;
|
||
}
|
||
|
||
uint8_t server_version = 0;
|
||
if (SSL_read(ssl, &server_version, 1) != 1) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/server_info",
|
||
"Unable to read server version");
|
||
return false;
|
||
}
|
||
if (server_version != 0x00) {
|
||
return false;
|
||
}
|
||
|
||
uint8_t server_info_size = 0;
|
||
if (SSL_read(ssl, &server_info_size, 1) != 1) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/server_info",
|
||
"Unable to read server info size");
|
||
return false;
|
||
}
|
||
|
||
char server_info[257] = {0};
|
||
if (SSL_read(ssl, server_info, server_info_size) != server_info_size) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/server_info",
|
||
"Unable to read %u bytes of server info", server_info_size);
|
||
return false;
|
||
}
|
||
|
||
dp_logf(logger, DP_LOG_INFO, DC_PROTO_LOG "/server_info",
|
||
"Server information (version %u): %s", server_version, server_info);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool dc_proto_pow_solve(SSL *ssl, dp_Logger *logger) {
|
||
if (!ssl || !logger) {
|
||
return false;
|
||
}
|
||
|
||
uint8_t challenge[DP_POW_CHALLENGE_SIZE] = {0};
|
||
uint8_t difficulty = 0;
|
||
uint8_t ones = 0;
|
||
|
||
if (SSL_read(ssl, challenge, sizeof(challenge)) != sizeof(challenge)) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Unable to read %zu bytes for PoW challenge",
|
||
sizeof(challenge));
|
||
return false;
|
||
}
|
||
if (SSL_read(ssl, &difficulty, 1) != 1) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Unable to read PoW difficulty");
|
||
return false;
|
||
}
|
||
if (SSL_read(ssl, &ones, 1) != 1) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Unable to read PoW XOR ones");
|
||
return false;
|
||
}
|
||
|
||
uint8_t pings = 0;
|
||
uint8_t ping_reply = 0;
|
||
|
||
uint64_t nonce = 0;
|
||
bool solved = false;
|
||
|
||
dp_logf(logger, DP_LOG_INFO, DC_PROTO_LOG "/pow_solve",
|
||
"Solving PoW (difficulty=%u, ones=%u)", difficulty, ones);
|
||
|
||
while (pings < 64 && !solved) {
|
||
if (!dp_proto_ping(ssl)) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Failed to send POW_PING to PoW");
|
||
return false;
|
||
}
|
||
if (SSL_read(ssl, &ping_reply, 1) != 1) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Failed to read POW_PING_REPLY");
|
||
return false;
|
||
}
|
||
if (ping_reply != (uint8_t)dp_PacketType_ping_reply) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Got unexpected ping response: %x", ping_reply);
|
||
dc_see_error(ssl, logger, ping_reply);
|
||
return false;
|
||
}
|
||
++pings;
|
||
|
||
const int status = dc_pow_solve_batch(
|
||
logger, difficulty, ones, challenge, &nonce, (size_t)(256 * 1024));
|
||
|
||
if (status < 0 || status > 1) {
|
||
return false;
|
||
}
|
||
|
||
if (status == 1) {
|
||
solved = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (solved) {
|
||
dp_logf(logger, DP_LOG_INFO, DC_PROTO_LOG "/pow_solve",
|
||
"Solved PoW: %lu", nonce);
|
||
|
||
/* Send ready */
|
||
if (!dp_proto_ready(ssl)) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Unable to set state to ready in PoW");
|
||
return false;
|
||
}
|
||
|
||
/* Send solution */
|
||
uint8_t nonce_buf[8] = {0};
|
||
if (!dp_u642buf_le(nonce_buf, nonce)) {
|
||
return false;
|
||
}
|
||
if (SSL_write(ssl, nonce_buf, sizeof(nonce_buf)) != sizeof(nonce_buf)) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Unable to send PoW nonce solution %lu to server", nonce);
|
||
return false;
|
||
}
|
||
|
||
/* Check status */
|
||
uint8_t allowed = 0x00;
|
||
if (SSL_read(ssl, &allowed, 1) != 1) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"Unable to read allow status from server");
|
||
return false;
|
||
}
|
||
if (allowed != (uint8_t)dp_PacketType_allowed) {
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"We were not allowed through");
|
||
dc_see_error(ssl, logger, allowed);
|
||
return false;
|
||
}
|
||
} else {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/pow_solve",
|
||
"PoW solution could not be found");
|
||
}
|
||
|
||
return solved;
|
||
}
|
||
|
||
bool dc_proto_command(SSL *ssl,
|
||
dp_Logger *logger,
|
||
dp_DeployCommand command,
|
||
bool is_unsafe,
|
||
uint64_t tid,
|
||
uint8_t domain_len,
|
||
const char *domain,
|
||
const uint8_t key[DP_AUTH_KEY_SIZE],
|
||
const uint8_t token[DP_AUTH_TOKEN_SIZE],
|
||
bool stream_logs) {
|
||
if (!ssl || !logger || !domain || !key || !token) {
|
||
return false;
|
||
}
|
||
|
||
/*
|
||
* Packet:
|
||
* type (1 byte)
|
||
* command (1 byte)
|
||
* is_unsafe (1 byte)
|
||
* id (8 bytes, little-endian 64 bit unsigned integer)
|
||
* domain_len (1 byte, value - up to DP_DOMAIN_LEN)
|
||
* domain (domain_len bytes)
|
||
* key (DP_AUTH_KEY_SIZE bytes, always static)
|
||
* token (DP_AUTH_TOKEN_SIZE bytes, changing)
|
||
*/
|
||
|
||
/* Calculate total packet size */
|
||
const size_t packet_size =
|
||
1 + 1 + 1 + 8 + 1 + domain_len + DP_AUTH_KEY_SIZE + DP_AUTH_TOKEN_SIZE;
|
||
|
||
/* Allocate buffer on stack */
|
||
uint8_t buffer[1 + 1 + 1 + 8 + 1 + DP_DOMAIN_LEN + DP_AUTH_KEY_SIZE +
|
||
DP_AUTH_TOKEN_SIZE] = {0};
|
||
uint8_t *ptr = buffer;
|
||
|
||
/* Pack packet type (1 byte) */
|
||
*ptr++ = (uint8_t)dp_PacketType_command;
|
||
|
||
/* Pack command (1 byte) */
|
||
*ptr++ = (uint8_t)command;
|
||
|
||
/* Pack is_unsafe (1 byte), assuming storing as 0 or 1 */
|
||
*ptr++ = (uint8_t)(is_unsafe ? 1 : 0);
|
||
|
||
/* Pack tid (8 bytes little-endian) */
|
||
for (uint8_t idx = 0; idx < 8; ++idx) {
|
||
*ptr++ = (uint8_t)((tid >> (uint8_t)(8 * idx)) & (uint8_t)0xFF);
|
||
}
|
||
|
||
/* Pack domain_len (1 byte) */
|
||
*ptr++ = domain_len;
|
||
|
||
/* Pack domain (domain_len bytes) */
|
||
memcpy(ptr, domain, domain_len);
|
||
ptr += domain_len;
|
||
|
||
/* Pack key (DP_AUTH_KEY_SIZE bytes) */
|
||
memcpy(ptr, key, DP_AUTH_KEY_SIZE);
|
||
ptr += DP_AUTH_KEY_SIZE;
|
||
|
||
/* Pack token (DP_AUTH_TOKEN_SIZE bytes) */
|
||
memcpy(ptr, token, DP_AUTH_TOKEN_SIZE);
|
||
ptr += DP_AUTH_TOKEN_SIZE;
|
||
|
||
/* (ptr - buffer) should equal packet_size now (sanity) */
|
||
if ((size_t)(ptr - buffer) != packet_size) {
|
||
return false;
|
||
}
|
||
|
||
/* Now the buffer is ready – send it */
|
||
const int sent = SSL_write(ssl, buffer, (int)packet_size);
|
||
if (sent != (int)packet_size) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/command",
|
||
"Failed to send full packet");
|
||
return false;
|
||
}
|
||
|
||
char log_buf[1024] = {0};
|
||
uint8_t log_packet_type = 0;
|
||
while (true) {
|
||
if (SSL_read(ssl, &log_packet_type, 1) != 1) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/command",
|
||
"Failed to read log packet type");
|
||
return false;
|
||
}
|
||
|
||
switch ((dp_PacketType)log_packet_type) {
|
||
case dp_PacketType_log:
|
||
{
|
||
uint8_t log_size_buf[2] = {0};
|
||
|
||
if (SSL_read(ssl, log_size_buf, sizeof(log_size_buf)) !=
|
||
sizeof(log_size_buf)) {
|
||
return -1;
|
||
}
|
||
|
||
uint16_t log_size =
|
||
(uint16_t)log_size_buf[0] |
|
||
(uint16_t)((uint16_t)log_size_buf[1] << (uint16_t)8);
|
||
|
||
if (log_size == 0) {
|
||
return false;
|
||
}
|
||
|
||
while (log_size > 0) {
|
||
const int bytes =
|
||
SSL_read(ssl, log_buf,
|
||
DP_MIN(log_size, sizeof(log_buf) - 1));
|
||
if (bytes <= 0) {
|
||
break;
|
||
}
|
||
log_buf[bytes] = '\0';
|
||
|
||
if (stream_logs) {
|
||
(void)fputs(log_buf, stdout);
|
||
(void)fflush(stdout);
|
||
}
|
||
|
||
log_size -= (uint16_t)bytes;
|
||
}
|
||
|
||
if (stream_logs) {
|
||
(void)putchar('\n');
|
||
(void)fflush(stdout);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case dp_PacketType_logs_end:
|
||
case dp_PacketType_exit:
|
||
return true;
|
||
break;
|
||
|
||
case dp_PacketType_ping:
|
||
if (!dp_proto_ping_reply(ssl)) {
|
||
dp_log(logger, DP_LOG_ERROR, DC_PROTO_LOG "/command",
|
||
"Unable to reply to deploy ping");
|
||
return false;
|
||
}
|
||
break;
|
||
|
||
case dp_PacketType_error:
|
||
dc_see_error(ssl, logger, log_packet_type);
|
||
return false;
|
||
break;
|
||
|
||
default:
|
||
dp_logf(logger, DP_LOG_ERROR, DC_PROTO_LOG "/command",
|
||
"Received invalid packet type %x", log_packet_type);
|
||
return false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|