mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
da06bcb9b7
13 changed files with 248 additions and 28 deletions
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
Copyright (c) 2013-2019, High Fidelity, Inc.
|
||||
Copyright (c) 2019-2021, Vircadia contributors.
|
||||
Copyright (c) 2022-2023, Overte e.V.
|
||||
Copyright (c) 2022-2024, Overte e.V.
|
||||
All rights reserved.
|
||||
https://overte.org
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ int main(int argc, const char* argv[]) {
|
|||
);
|
||||
QCommandLineOption protocolVersionOption(
|
||||
"protocolVersion",
|
||||
"Writes the protocol version base64 signature to a file?",
|
||||
"Writes the protocol version base64 signature to a file",
|
||||
"path"
|
||||
);
|
||||
QCommandLineOption noUpdaterOption(
|
||||
|
@ -275,6 +275,14 @@ int main(int argc, const char* argv[]) {
|
|||
"abortAfterInit",
|
||||
"Debug option. Aborts after initialization, right before the program starts running the event loop."
|
||||
);
|
||||
QCommandLineOption getProtocolVersionHashOption(
|
||||
"getProtocolVersionHash",
|
||||
"Debug option. Returns the network protocol version MD5 hash."
|
||||
);
|
||||
QCommandLineOption getProtocolVersionDataOption(
|
||||
"getProtocolVersionData",
|
||||
"Debug option. Returns the network protocol detailed data in JSON."
|
||||
);
|
||||
|
||||
// "--qmljsdebugger", which appears in output from "--help-all".
|
||||
// Those below don't seem to be optional.
|
||||
|
@ -321,6 +329,8 @@ int main(int argc, const char* argv[]) {
|
|||
parser.addOption(abortAfterStartupOption);
|
||||
parser.addOption(abortAfterInitOption);
|
||||
parser.addOption(getPluginsOption);
|
||||
parser.addOption(getProtocolVersionHashOption);
|
||||
parser.addOption(getProtocolVersionDataOption);
|
||||
|
||||
|
||||
QString applicationPath;
|
||||
|
@ -455,6 +465,34 @@ int main(int argc, const char* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (parser.isSet(getProtocolVersionHashOption)) {
|
||||
std::cout << protocolVersionsSignatureHex().toStdString() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
if (parser.isSet(getProtocolVersionDataOption)) {
|
||||
auto protocolMap = protocolVersionsSignatureMap();
|
||||
QMetaEnum packetMetaEnum = QMetaEnum::fromType<PacketTypeEnum::Value>();
|
||||
|
||||
QJsonArray packetTypesList;
|
||||
auto keyList = protocolMap.keys();
|
||||
std::sort(keyList.begin(), keyList.end()); // Sort by numeric value
|
||||
|
||||
for(const auto packet : keyList) {
|
||||
QJsonObject data;
|
||||
int intValue = static_cast<int>(packet);
|
||||
QString keyName = packetMetaEnum.valueToKey(intValue);
|
||||
|
||||
data["name"] = keyName;
|
||||
data["value"] = intValue;
|
||||
data["version"] = versionForPacketType(packet);
|
||||
|
||||
packetTypesList.append(data);
|
||||
}
|
||||
|
||||
std::cout << QJsonDocument(packetTypesList).toJson().toStdString() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
|
||||
QDir applicationDir(applicationPath);
|
||||
|
|
|
@ -130,6 +130,10 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion) {
|
|||
|
||||
static QByteArray protocolVersionSignature;
|
||||
static QString protocolVersionSignatureBase64;
|
||||
static QString protocolVersionSignatureHex;
|
||||
static QMap<PacketType, uint8_t> protocolVersionMap;
|
||||
|
||||
|
||||
static void ensureProtocolVersionsSignature() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
|
@ -139,12 +143,14 @@ static void ensureProtocolVersionsSignature() {
|
|||
stream << numberOfProtocols;
|
||||
for (uint8_t packetType = 0; packetType < numberOfProtocols; packetType++) {
|
||||
uint8_t packetTypeVersion = static_cast<uint8_t>(versionForPacketType(static_cast<PacketType>(packetType)));
|
||||
protocolVersionMap[static_cast<PacketType>(packetType)] = packetTypeVersion;
|
||||
stream << packetTypeVersion;
|
||||
}
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.addData(buffer);
|
||||
protocolVersionSignature = hash.result();
|
||||
protocolVersionSignatureBase64 = protocolVersionSignature.toBase64();
|
||||
protocolVersionSignatureHex = protocolVersionSignature.toHex(0);
|
||||
});
|
||||
}
|
||||
QByteArray protocolVersionsSignature() {
|
||||
|
@ -161,3 +167,13 @@ QString protocolVersionsSignatureBase64() {
|
|||
ensureProtocolVersionsSignature();
|
||||
return protocolVersionSignatureBase64;
|
||||
}
|
||||
|
||||
QString protocolVersionsSignatureHex() {
|
||||
ensureProtocolVersionsSignature();
|
||||
return protocolVersionSignatureHex;
|
||||
}
|
||||
|
||||
QMap<PacketType, uint8_t> protocolVersionsSignatureMap() {
|
||||
ensureProtocolVersionsSignature();
|
||||
return protocolVersionMap;
|
||||
}
|
|
@ -31,8 +31,15 @@ class PacketTypeEnum {
|
|||
Q_GADGET
|
||||
Q_ENUMS(Value)
|
||||
public:
|
||||
// If adding a new packet packetType, you can replace one marked usable or add at the end.
|
||||
// This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t
|
||||
|
||||
/**
|
||||
* @brief Packet type identifier
|
||||
*
|
||||
* Identifies the type of packet being sent.
|
||||
*
|
||||
* @note If adding a new packet packetType, you can replace one marked usable or add at the end.
|
||||
* @note This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t
|
||||
*/
|
||||
enum class Value : uint8_t {
|
||||
Unknown,
|
||||
DomainConnectRequestPending,
|
||||
|
@ -143,6 +150,8 @@ public:
|
|||
NUM_PACKET_TYPE
|
||||
};
|
||||
|
||||
Q_ENUM(Value)
|
||||
|
||||
const static QHash<PacketTypeEnum::Value, PacketTypeEnum::Value> getReplicatedPacketMapping() {
|
||||
const static QHash<PacketTypeEnum::Value, PacketTypeEnum::Value> REPLICATED_PACKET_MAPPING {
|
||||
{ PacketTypeEnum::Value::MicrophoneAudioNoEcho, PacketTypeEnum::Value::ReplicatedMicrophoneAudioNoEcho },
|
||||
|
@ -219,10 +228,60 @@ const int NUM_BYTES_MD5_HASH = 16;
|
|||
// NOTE: There is a max limit of 255, hopefully we have a better way to manage this by then.
|
||||
typedef uint8_t PacketVersion;
|
||||
|
||||
/**
|
||||
* @brief Returns the version number of the given packet type
|
||||
*
|
||||
* If the implementation of a packet type is modified in an incompatible way, the implementation
|
||||
* of this function needs to be modified to return an incremented value.
|
||||
*
|
||||
* This is used to determine whether the protocol is compatible between client and server.
|
||||
*
|
||||
* @note Version is limited to a max of 255.
|
||||
*
|
||||
* @param packetType Type of packet
|
||||
* @return PacketVersion Version
|
||||
*/
|
||||
PacketVersion versionForPacketType(PacketType packetType);
|
||||
QByteArray protocolVersionsSignature(); /// returns a unique signature for all the current protocols
|
||||
|
||||
/**
|
||||
* @brief Returns a unique signature for all the current protocols
|
||||
*
|
||||
* This computes a MD5 hash that expresses the state of the protocol's specification. The calculation
|
||||
* is done in ensureProtocolVersionsSignature and accounts for the following:
|
||||
*
|
||||
* * Number of known packet types
|
||||
* * versionForPacketType(type) for each packet type.
|
||||
*
|
||||
* There's no provision for backwards compatibility, anything that changes this calculation is a protocol break.
|
||||
*
|
||||
* @return QByteArray MD5 digest as a byte array
|
||||
*/
|
||||
QByteArray protocolVersionsSignature();
|
||||
|
||||
/***
|
||||
* @brief Returns a unique signature for all the current protocols
|
||||
*
|
||||
* Same as protocolVersionsSignature(), in base64.
|
||||
*/
|
||||
QString protocolVersionsSignatureBase64();
|
||||
|
||||
/***
|
||||
* @brief Returns a unique signature for all the current protocols
|
||||
*
|
||||
* Same as protocolVersionsSignature(), in hex;
|
||||
*/
|
||||
QString protocolVersionsSignatureHex();
|
||||
|
||||
/***
|
||||
* @brief Returns the data used to compute the protocol version
|
||||
*
|
||||
* The key is the packet type. The value is the version for that packet type.
|
||||
*
|
||||
* Used for aiding in development.
|
||||
*/
|
||||
QMap<PacketType, uint8_t> protocolVersionsSignatureMap();
|
||||
|
||||
|
||||
#if (PR_BUILD || DEV_BUILD)
|
||||
void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debugging version negotiation
|
||||
#endif
|
||||
|
@ -428,4 +487,5 @@ enum class AvatarQueryVersion : PacketVersion {
|
|||
ConicalFrustums = 22
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -510,7 +510,7 @@ Rectangle {
|
|||
mess = mess.replace(arrow, "<");
|
||||
|
||||
var link = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
|
||||
mess = mess.replace(link, (match) => {return "<a onclick='Window.openUrl("+match+")' href='" + match + "'>" + match + "</a> <a onclick='Window.openUrl("+match+")'>⮺</a>"});
|
||||
mess = mess.replace(link, (match) => {return `<a style="color:#4EBAFD" onclick='Window.openUrl("+match+")' href='` + match + `'>` + match + `</a> <a onclick='Window.openUrl(`+match+`)'>⮺</a>`});
|
||||
|
||||
var newline = /\n/gi;
|
||||
mess = mess.replace(newline, "<br>");
|
||||
|
|
|
@ -58,7 +58,7 @@ function runDefaultsTogether() {
|
|||
function runDefaultsSeparately() {
|
||||
for (var i in CONTOLLER_SCRIPTS) {
|
||||
if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) {
|
||||
print("loading " + CONTOLLER_SCRIPTS[j]);
|
||||
print("loading " + CONTOLLER_SCRIPTS[i]);
|
||||
Script.load(CONTOLLER_SCRIPTS[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
// Program ----
|
||||
function onMouseLookChanged(newMouseLook) {
|
||||
disableMouseLook();
|
||||
mouseLookEnabled = newMouseLook;
|
||||
}
|
||||
|
||||
|
@ -38,8 +39,6 @@
|
|||
// Toggle using the m key
|
||||
if (event.text.toLowerCase() === "m") {
|
||||
if (Camera.captureMouse) {
|
||||
mouseLookActive = false;
|
||||
Settings.setValue("mouselook-active", false);
|
||||
disableMouseLook();
|
||||
} else {
|
||||
mouseLookActive = true;
|
||||
|
@ -82,12 +81,16 @@
|
|||
if (hmdActive) return;
|
||||
if (tablet.tabletShown) return;
|
||||
if (overlayActive) return;
|
||||
if (!mouseLookEnabled) return; // Mouse look disabled via setting
|
||||
if (!mouseLookActive) return; // Mouse look disabled via the hotkey
|
||||
|
||||
Camera.captureMouse = true;
|
||||
}
|
||||
|
||||
function disableMouseLook() {
|
||||
mouseLookActive = false;
|
||||
Settings.setValue("mouselook-active", false);
|
||||
|
||||
Camera.captureMouse = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
print("Loading hfudt")
|
||||
bit32 = require("bit32")
|
||||
|
||||
-- create the HFUDT protocol
|
||||
p_hfudt = Proto("hfudt", "HFUDT Protocol")
|
||||
|
@ -154,19 +155,55 @@ local packet_types = {
|
|||
[99] = "EntityQueryInitialResultsComplete",
|
||||
[100] = "BulkAvatarTraits",
|
||||
[101] = "AudioSoloRequest",
|
||||
[102] = "BulkAvatarTraitsAck"
|
||||
[102] = "BulkAvatarTraitsAck",
|
||||
[103] = "StopInjector",
|
||||
[104] = "AvatarZonePresence",
|
||||
[105] = "WebRTCSignaling"
|
||||
}
|
||||
|
||||
-- PacketHeaders.h, getNonSourcedPackets()
|
||||
local unsourced_packet_types = {
|
||||
["DomainList"] = true,
|
||||
["DomainConnectRequestPending"] = true,
|
||||
["CreateAssignment"] = true,
|
||||
["RequestAssignment"] = true,
|
||||
["DomainServerRequireDTLS"] = true,
|
||||
["DomainConnectRequest"] = true,
|
||||
["ICEPing"] = true,
|
||||
["ICEPingReply"] = true,
|
||||
["DomainList"] = true,
|
||||
["DomainConnectionDenied"] = true,
|
||||
["DomainServerPathQuery"] = true,
|
||||
["DomainServerPathResponse"] = true,
|
||||
["DomainServerAddedNode"] = true,
|
||||
["DomainServerConnectionToken"] = true,
|
||||
["DomainSettingsRequest"] = true,
|
||||
["ICEServerHeartbeatACK"] = true
|
||||
["OctreeDataFileRequest"] = true,
|
||||
["OctreeDataFileReply"] = true,
|
||||
["OctreeDataPersist"] = true,
|
||||
["DomainContentReplacementFromUrl"] = true,
|
||||
["DomainSettings"] = true,
|
||||
["ICEServerPeerInformation"] = true,
|
||||
["ICEServerQuery"] = true,
|
||||
["ICEServerHeartbeat"] = true,
|
||||
["ICEServerHeartbeatACK"] = true,
|
||||
["ICEPing"] = true,
|
||||
["ICEPingReply"] = true,
|
||||
["ICEServerHeartbeatDenied"] = true,
|
||||
["AssignmentClientStatus"] = true,
|
||||
["StopNode"] = true,
|
||||
["DomainServerRemovedNode"] = true,
|
||||
["UsernameFromIDReply"] = true,
|
||||
["OctreeFileReplacement"] = true,
|
||||
["ReplicatedMicrophoneAudioNoEcho"] = true,
|
||||
["ReplicatedMicrophoneAudioWithEcho"] = true,
|
||||
["ReplicatedInjectAudio"] = true,
|
||||
["ReplicatedSilentAudioFrame"] = true,
|
||||
["ReplicatedAvatarIdentity"] = true,
|
||||
["ReplicatedKillAvatar"] = true,
|
||||
["ReplicatedBulkAvatarData"] = true,
|
||||
["AvatarZonePresence"] = true,
|
||||
["WebRTCSignaling"] = true
|
||||
}
|
||||
|
||||
-- PacketHeaders.h, getNonVerifiedPackets()
|
||||
local nonverified_packet_types = {
|
||||
["NodeJsonStats"] = true,
|
||||
["EntityQuery"] = true,
|
||||
|
@ -222,6 +259,7 @@ function p_hfudt.dissector(buf, pinfo, tree)
|
|||
type:append_text(" (".. control_types[shifted_type][1] .. ")")
|
||||
|
||||
subtree:add(f_control_type_text, control_types[shifted_type][1])
|
||||
pinfo.cols.info:append(" [" .. control_types[shifted_type][1] .. "]")
|
||||
end
|
||||
|
||||
if shifted_type == 0 then
|
||||
|
@ -257,7 +295,7 @@ function p_hfudt.dissector(buf, pinfo, tree)
|
|||
-- read the obfuscation level
|
||||
local obfuscation_bits = bit32.band(0x03, bit32.rshift(first_word, 27))
|
||||
subtree:add(f_obfuscation_level, obfuscation_bits)
|
||||
|
||||
|
||||
-- read the sequence number
|
||||
subtree:add(f_sequence_number, bit32.band(first_word, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
|
@ -300,10 +338,12 @@ function p_hfudt.dissector(buf, pinfo, tree)
|
|||
local packet_type = buf(payload_offset, 1):le_uint()
|
||||
local ptype = subtree:add_le(f_type, buf(payload_offset, 1))
|
||||
local packet_type_text = packet_types[packet_type]
|
||||
|
||||
if packet_type_text ~= nil then
|
||||
subtree:add(f_type_text, packet_type_text)
|
||||
-- if we know this packet type then add the name
|
||||
ptype:append_text(" (".. packet_type_text .. ")")
|
||||
pinfo.cols.info:append(" [" .. packet_type_text .. "]")
|
||||
end
|
||||
|
||||
-- read the version
|
||||
|
@ -431,12 +471,12 @@ function deobfuscate(message_bit, buf, level)
|
|||
else
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local start = 4
|
||||
if message_bit == 1 then
|
||||
local start = 12
|
||||
end
|
||||
|
||||
|
||||
local p = 0
|
||||
for i = start, buf:len() - 1 do
|
||||
out:set_index(i, bit.bxor(buf(i, 1):le_uint(), key:get_index(7 - (p % 8))) )
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
print("Loading hf-audio")
|
||||
|
||||
bit32 = require("bit32")
|
||||
-- create the audio protocol
|
||||
p_hf_audio = Proto("hf-audio", "HF Audio Protocol")
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
print("Loading hf-avatar")
|
||||
bit32 = require("bit32")
|
||||
|
||||
-- create the avatar protocol
|
||||
p_hf_avatar = Proto("hf-avatar", "HF Avatar Protocol")
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
print("Loading hf-entity")
|
||||
bit32 = require("bit32")
|
||||
|
||||
-- create the entity protocol
|
||||
p_hf_entity = Proto("hf-entity", "HF Entity Protocol")
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
-- create the domain protocol
|
||||
print("Loading hf-domain")
|
||||
bit32 = require("bit32")
|
||||
p_hf_domain = Proto("hf-domain", "HF Domain Protocol")
|
||||
|
||||
-- domain packet fields
|
||||
|
|
|
@ -1,14 +1,73 @@
|
|||
High Fidelity Wireshark Plugins
|
||||
---------------------------------
|
||||
# High Fidelity Wireshark Plugins
|
||||
|
||||
Install wireshark 2.4.6 or higher.
|
||||
|
||||
Copy these lua files into c:\Users\username\AppData\Roaming\Wireshark\Plugins
|
||||
## Installation
|
||||
|
||||
After a capture any detected High Fidelity Packets should be easily identifiable by one of the following protocols
|
||||
|
||||
* HF-AUDIO - Streaming audio packets
|
||||
* HF-AVATAR - Streaming avatar mixer packets
|
||||
* HF-ENTITY - Entity server traffic
|
||||
* HF-DOMAIN - Domain server traffic
|
||||
* HFUDT - All other UDP traffic
|
||||
* Install wireshark 2.4.6 or higher.
|
||||
* Copy these lua files into `c:\Users\username\AppData\Roaming\Wireshark\Plugins` on Windows, or `$HOME/.local/lib/wireshark/plugins` on Linux.
|
||||
|
||||
## Lua version
|
||||
|
||||
This is a Lua plugin, which requires the bit32 module to be installed. You can find the Lua version wireshark uses in the About dialog, eg:
|
||||
|
||||
Version 4.2.5 (Git commit 798e06a0f7be).
|
||||
|
||||
Compiled (64-bit) using GCC 14.1.1 20240507 (Red Hat 14.1.1-1), with GLib
|
||||
2.80.2, with Qt 6.7.0, with libpcap, with POSIX capabilities (Linux), with libnl
|
||||
3, with zlib 1.3.0.zlib-ng, with PCRE2, with Lua 5.1.5, with GnuTLS 3.8.5 and
|
||||
|
||||
This indicates Lua 5.1 is used (see on the last line)
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
On Fedora 40:
|
||||
|
||||
* wireshark-devel
|
||||
* lua5.1-bit32
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
After a capture any detected Overte Packets should be easily identifiable by one of the following protocols
|
||||
|
||||
* `HF-AUDIO` - Streaming audio packets
|
||||
* `HF-AVATAR` - Streaming avatar mixer packets
|
||||
* `HF-ENTITY` - Entity server traffic
|
||||
* `HF-DOMAIN` - Domain server traffic
|
||||
* `HFUDT` - All other UDP traffic
|
||||
|
||||
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### attempt to index global 'bit32' (a nil value)
|
||||
|
||||
`[Expert Info (Error/Undecoded): Lua Error: /home/dale/.local/lib/wireshark/plugins/1-hfudt.lua:207: attempt to index global 'bit32' (a nil value)]`
|
||||
|
||||
See the installation requirements, you need to install the bit32 Lua module for the right Lua version.
|
||||
|
||||
## Development hints
|
||||
|
||||
|
||||
* Symlink files from the development tree to `$HOME/.local/lib/wireshark/plugins`, to have Wireshark work on the latest dissector code.
|
||||
* Capture packets for later analysis in a PCAPNG file.
|
||||
* Only save needed packets in the dump
|
||||
|
||||
Decode on the commandline with:
|
||||
|
||||
tshark -r packets.pcapng.gz -V
|
||||
|
||||
Decode only the first packet:
|
||||
|
||||
tshark -r packets.pcapng.gz -V -c 1
|
||||
|
||||
### Useful tshark arguments
|
||||
|
||||
* `-x` hex dump
|
||||
* `-c N` Only decode first N packets
|
||||
* `-O hfudt,hf-domain,hf-entity,hf-avatar,hf-audio` Only dump Overte protocol data, skip dumping UDP/etc parts.
|
||||
* `-V` decode protocols
|
||||
*
|
Loading…
Reference in a new issue