diff --git a/Protocol/src/include/protocol/protocol.hxx b/Protocol/src/include/protocol/protocol.hxx index 1494ae3..606a7c6 100644 --- a/Protocol/src/include/protocol/protocol.hxx +++ b/Protocol/src/include/protocol/protocol.hxx @@ -22,4 +22,13 @@ struct SignedMessage { bool valid(unsigned char pub_key[crypto_sign_PUBLICKEYBYTES]); }; +struct StunReplay { + uint32_t addr; // ipv4 only support! + uint16_t port; + bool is_behind_symmetric_nat = false; + + StunReplay(std::string ip, uint16_t port); + StunReplay(uint32_t ip, uint16_t port); +}; + } // namespace Protocol diff --git a/Protocol/src/protocol.cxx b/Protocol/src/protocol.cxx index 70572c2..61e99f3 100644 --- a/Protocol/src/protocol.cxx +++ b/Protocol/src/protocol.cxx @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace Protocol { @@ -57,4 +58,29 @@ bool SignedMessage::valid(unsigned char pub_key[crypto_sign_PUBLICKEYBYTES]) { return true; } +StunReplay::StunReplay(std::string ip, uint16_t port) : port(port) { + auto parts = + ip | std::views::split('.') | std::views::transform([](auto &&range) { + return std::string_view(range.cbegin(), range.cend()); + }); + if (std::ranges::distance(parts) != 4) { + goto invalid_addr; + } + + for (auto part : parts) { + auto val = std::atoi(part.data()); + if (val > 255 || val < 1) { + goto invalid_addr; + } + addr = (addr << 8) | static_cast(val); + } + + goto end; +invalid_addr: + throw std::runtime_error("Invalid ipv4 string"); +end: +} + +StunReplay::StunReplay(uint32_t ip, uint16_t port) : addr(ip), port(port) {} + } // namespace Protocol diff --git a/Protocol/tests/test_protocol.cxx b/Protocol/tests/test_protocol.cxx index c5454fd..6368104 100644 --- a/Protocol/tests/test_protocol.cxx +++ b/Protocol/tests/test_protocol.cxx @@ -3,7 +3,24 @@ #include #include -TEST_CASE("SignedMessage", "[protocol]") { +TEST_CASE("Protocol::StunReplay", "[protocol]") { + SECTION("str to ipv4") { + auto replay = Protocol::StunReplay("1.1.255.255", 1337); + REQUIRE(replay.addr == 16908287); + } + SECTION("invalid ipv4 str (range)") { + REQUIRE_THROWS_AS(Protocol::StunReplay("1.1.255.256", 1337), + std::runtime_error); + REQUIRE_THROWS_AS(Protocol::StunReplay("0.1.255.255", 1337), + std::runtime_error); + } + SECTION("invalid ipv4 str (len)") { + REQUIRE_THROWS_AS(Protocol::StunReplay("1.1.1", 1337), + std::runtime_error); + } +} + +TEST_CASE("Protocol::SignedMessage", "[protocol]") { REQUIRE(sodium_init() >= 0); unsigned char pub_key[crypto_sign_PUBLICKEYBYTES];