diff --git a/ntcore/doc/networktables4.adoc b/ntcore/doc/networktables4.adoc index 318afac7f85..e41bbdc3e7f 100644 --- a/ntcore/doc/networktables4.adoc +++ b/ntcore/doc/networktables4.adoc @@ -163,6 +163,11 @@ Clients may publish a value at any time following clock synchronization. Client Clients should subscribe to the `$sub$` meta topic for each topic published and use this metadata to determine how frequently to send updates to the network. However, this is not required--clients may choose to ignore this and send updates at any time. +[[ids]] +=== IDs and UIDs + +IDs and UIDs should be selected by clients and servers to be as small as possible for transmission efficiency. Clients and servers should support a signed 32-bit range for IDs and UIDs, but exceptions can be made for implementation reasons. Clients and servers must ignore messages with unsupported IDs and UIDs, and should report a diagnostic if this occurs. + [[meta-topics]] === Server-Published Meta Topics diff --git a/ntcore/src/main/native/cpp/net/WireDecoder.cpp b/ntcore/src/main/native/cpp/net/WireDecoder.cpp index 14a051d4798..e588229aa67 100644 --- a/ntcore/src/main/native/cpp/net/WireDecoder.cpp +++ b/ntcore/src/main/native/cpp/net/WireDecoder.cpp @@ -174,6 +174,12 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, goto err; } + // limit to 32-bit range and exclude endpoints used by DenseMap + if (pubuid >= 0x7fffffffLL || pubuid <= (-0x7fffffffLL - 1)) { + error = "pubuid out of range"; + goto err; + } + // properties; allow missing (treated as empty) wpi::json* properties = nullptr; auto propertiesIt = params->find("properties"); @@ -200,6 +206,12 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, goto err; } + // limit to 32-bit range and exclude endpoints used by DenseMap + if (pubuid >= 0x7fffffffLL || pubuid <= (-0x7fffffffLL - 1)) { + error = "pubuid out of range"; + goto err; + } + // complete out.ClientUnpublish(pubuid); rv = true; @@ -231,6 +243,12 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, goto err; } + // limit to 32-bit range and exclude endpoints used by DenseMap + if (subuid >= 0x7fffffffLL || subuid <= (-0x7fffffffLL - 1)) { + error = "subuid out of range"; + goto err; + } + // options PubSubOptionsImpl options; auto optionsIt = params->find("options"); @@ -303,6 +321,12 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, goto err; } + // limit to 32-bit range and exclude endpoints used by DenseMap + if (subuid >= 0x7fffffffLL || subuid <= (-0x7fffffffLL - 1)) { + error = "pubuid out of range"; + goto err; + } + // complete out.ClientUnsubscribe(subuid); rv = true; @@ -324,6 +348,12 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, goto err; } + // limit to 32-bit range and exclude endpoints used by DenseMap + if (id >= 0x7fffffffLL || id <= (-0x7fffffffLL - 1)) { + error = "id out of range"; + goto err; + } + // type auto typeStr = ObjGetString(*params, "type", &error); if (!typeStr) { @@ -339,6 +369,13 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, error = "pubuid value must be a number"; goto err; } + + // limit to 32-bit range and exclude endpoints used by DenseMap + if (val >= 0x7fffffffLL || val <= (-0x7fffffffLL - 1)) { + error = "pubuid out of range"; + goto err; + } + pubuid = val; } @@ -369,6 +406,12 @@ static bool WireDecodeTextImpl(std::string_view in, T& out, goto err; } + // limit to 32-bit range and exclude endpoints used by DenseMap + if (id >= 0x7fffffffLL || id <= (-0x7fffffffLL - 1)) { + error = "id out of range"; + goto err; + } + // complete out.ServerUnannounce(*name, id); } else if (*method == PropertiesUpdateMsg::kMethodStr) { diff --git a/ntcore/src/test/native/cpp/server/ServerImplTest.cpp b/ntcore/src/test/native/cpp/server/ServerImplTest.cpp index 0db7f15d5b8..2821e7c8f59 100644 --- a/ntcore/src/test/native/cpp/server/ServerImplTest.cpp +++ b/ntcore/src/test/native/cpp/server/ServerImplTest.cpp @@ -423,4 +423,20 @@ TEST_F(ServerImplTest, ZeroTimestampNegativeTime) { } } +TEST_F(ServerImplTest, InvalidPubUid) { + EXPECT_CALL(logger, Call(_, _, _, "0: pubuid out of range")); + server.SetLocal(&local, &queue); + + // connect client + ::testing::StrictMock wire; + MockSetPeriodicFunc setPeriodic; + auto [name, id] = server.AddClient("test", "connInfo", false, wire, + setPeriodic.AsStdFunction()); + + server.ProcessIncomingText( + id, + "[{\"method\":\"publish\",\"params\":{\"type\":\"string\",\"name\":" + "\"myvalue\",\"pubuid\":2147483647,\"properties\":{}}}]"); +} + } // namespace nt