#include "dvlnet/packet.h" #include "engine.h" namespace dvl { namespace net { #ifndef NONET static constexpr bool disable_encryption = false; #endif const char *packet_type_to_string(uint8_t packet_type) { switch (packet_type) { case PT_MESSAGE: return "PT_MESSAGE"; case PT_TURN: return "PT_TURN"; case PT_JOIN_REQUEST: return "PT_JOIN_REQUEST"; case PT_JOIN_ACCEPT: return "PT_JOIN_ACCEPT"; case PT_CONNECT: return "PT_CONNECT"; case PT_DISCONNECT: return "PT_DISCONNECT"; default: return NULL; } } wrong_packet_type_exception::wrong_packet_type_exception(std::initializer_list expected_types, std::uint8_t actual) { message_ = "Expected packet of type "; const auto append_packet_type = [this](std::uint8_t t) { const char *type_str = packet_type_to_string(t); if (type_str != NULL) message_.append(type_str); else message_.append(std::to_string(t)); }; constexpr char kJoinTypes[] = " or "; for (const packet_type t : expected_types) { append_packet_type(t); message_.append(kJoinTypes); } message_.resize(message_.size() - (sizeof(kJoinTypes) - 1)); message_.append(", got"); append_packet_type(actual); } namespace { void CheckPacketTypeOneOf(std::initializer_list expected_types, std::uint8_t actual_type) { for (std::uint8_t packet_type : expected_types) if (actual_type == packet_type) return; throw wrong_packet_type_exception(std::move(expected_types), actual_type); } } // namespace const buffer_t &packet::data() { if (!have_decrypted || !have_encrypted) ABORT(); return encrypted_buffer; } packet_type packet::type() { if (!have_decrypted) ABORT(); return m_type; } plr_t packet::src() { if (!have_decrypted) ABORT(); return m_src; } plr_t packet::dest() { if (!have_decrypted) ABORT(); return m_dest; } const buffer_t &packet::message() { if (!have_decrypted) ABORT(); CheckPacketTypeOneOf({ PT_MESSAGE }, m_type); return m_message; } turn_t packet::turn() { if (!have_decrypted) ABORT(); CheckPacketTypeOneOf({ PT_TURN }, m_type); return m_turn; } cookie_t packet::cookie() { if (!have_decrypted) ABORT(); CheckPacketTypeOneOf({ PT_JOIN_REQUEST, PT_JOIN_ACCEPT }, m_type); return m_cookie; } plr_t packet::newplr() { if (!have_decrypted) ABORT(); CheckPacketTypeOneOf({ PT_JOIN_ACCEPT, PT_CONNECT, PT_DISCONNECT }, m_type); return m_newplr; } const buffer_t &packet::info() { if (!have_decrypted) ABORT(); CheckPacketTypeOneOf({ PT_JOIN_REQUEST, PT_JOIN_ACCEPT }, m_type); return m_info; } leaveinfo_t packet::leaveinfo() { if (!have_decrypted) ABORT(); CheckPacketTypeOneOf({ PT_DISCONNECT }, m_type); return m_leaveinfo; } void packet_in::create(buffer_t buf) { if (have_encrypted || have_decrypted) ABORT(); encrypted_buffer = std::move(buf); have_encrypted = true; } void packet_in::decrypt() { if (!have_encrypted) ABORT(); if (have_decrypted) return; #ifndef NONET if (!disable_encryption) { if (encrypted_buffer.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES + sizeof(packet_type) + 2 * sizeof(plr_t)) throw packet_exception(); auto pktlen = (encrypted_buffer.size() - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES); decrypted_buffer.resize(pktlen); if (crypto_secretbox_open_easy(decrypted_buffer.data(), encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, encrypted_buffer.size() - crypto_secretbox_NONCEBYTES, encrypted_buffer.data(), key.data())) throw packet_exception(); } else #endif { if (encrypted_buffer.size() < sizeof(packet_type) + 2 * sizeof(plr_t)) throw packet_exception(); decrypted_buffer = encrypted_buffer; } process_data(); have_decrypted = true; } void packet_out::encrypt() { if (!have_decrypted) ABORT(); if (have_encrypted) return; process_data(); #ifndef NONET if (!disable_encryption) { auto len_cleartext = encrypted_buffer.size(); encrypted_buffer.insert(encrypted_buffer.begin(), crypto_secretbox_NONCEBYTES, 0); encrypted_buffer.insert(encrypted_buffer.end(), crypto_secretbox_MACBYTES, 0); randombytes_buf(encrypted_buffer.data(), crypto_secretbox_NONCEBYTES); if (crypto_secretbox_easy(encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, len_cleartext, encrypted_buffer.data(), key.data())) ABORT(); } #endif have_encrypted = true; } packet_factory::packet_factory(std::string pw) { #ifndef NONET if (sodium_init() < 0) ABORT(); pw.resize(std::min(pw.size(), crypto_pwhash_argon2id_PASSWD_MAX)); pw.resize(std::max(pw.size(), crypto_pwhash_argon2id_PASSWD_MIN), 0); std::string salt("W9bE9dQgVaeybwr2"); salt.resize(crypto_pwhash_argon2id_SALTBYTES, 0); if (crypto_pwhash(key.data(), crypto_secretbox_KEYBYTES, pw.data(), pw.size(), reinterpret_cast(salt.data()), crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE, crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_ARGON2ID13)) ABORT(); #endif } } // namespace net } // namespace dvl