mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-12-11 09:20:46 +01:00
135 lines
4.3 KiB
C++
135 lines
4.3 KiB
C++
#include "WuStun.h"
|
|
#include <arpa/inet.h>
|
|
#include <string.h>
|
|
#include "CRC32.h"
|
|
#include "WuCrypto.h"
|
|
|
|
const int32_t kStunHeaderLength = 20;
|
|
const int32_t kStunAlignment = 4;
|
|
|
|
bool ParseStun(const uint8_t* src, int32_t len, StunPacket* packet) {
|
|
if (len < kStunHeaderLength || src[0] != 0 || src[1] != 1) {
|
|
return false;
|
|
}
|
|
|
|
src += ReadScalarSwapped(src, &packet->type);
|
|
|
|
if (packet->type != Stun_BindingRequest) {
|
|
return false;
|
|
}
|
|
|
|
src += ReadScalarSwapped(src, &packet->length);
|
|
|
|
if (packet->length < 4 || packet->length > len - kStunHeaderLength) {
|
|
// Need at least 1 attribute
|
|
return false;
|
|
}
|
|
|
|
src += ReadScalarSwapped(src, &packet->cookie);
|
|
|
|
for (int32_t i = 0; i < kStunTransactionIdLength; i++) {
|
|
packet->transactionId[i] = src[i];
|
|
}
|
|
|
|
src += kStunTransactionIdLength;
|
|
|
|
int32_t maxOffset = int32_t(packet->length) - 1;
|
|
int32_t payloadOffset = 0;
|
|
while (payloadOffset < maxOffset) {
|
|
int32_t remain = len - kStunHeaderLength - payloadOffset;
|
|
if (remain >= 4) {
|
|
uint16_t payloadType = 0;
|
|
uint16_t payloadLength = 0;
|
|
|
|
payloadOffset += ReadScalarSwapped(src + payloadOffset, &payloadType);
|
|
payloadOffset += ReadScalarSwapped(src + payloadOffset, &payloadLength);
|
|
remain -= 4;
|
|
|
|
int32_t paddedLength =
|
|
payloadLength + PadSize(payloadLength, kStunAlignment);
|
|
|
|
if (payloadType == StunAttrib_User) {
|
|
// fragment = min 4 chars
|
|
// username = fragment:fragment (at least 9 characters)
|
|
if (paddedLength <= remain && payloadLength >= 9) {
|
|
const char* uname = (const char*)src + payloadOffset;
|
|
int32_t colonIndex = FindTokenIndex(uname, payloadLength, ':');
|
|
if (colonIndex >= 4) {
|
|
int32_t serverUserLength = colonIndex;
|
|
int32_t remoteUserLength = payloadLength - colonIndex - 1;
|
|
if (serverUserLength > kMaxStunIdentifierLength ||
|
|
remoteUserLength > kMaxStunIdentifierLength) {
|
|
return false;
|
|
} else {
|
|
packet->serverUser.length = serverUserLength;
|
|
packet->remoteUser.length = remoteUserLength;
|
|
memcpy(packet->serverUser.identifier, uname, serverUserLength);
|
|
memcpy(packet->remoteUser.identifier, uname + colonIndex + 1,
|
|
remoteUserLength);
|
|
return true;
|
|
}
|
|
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
// Actual length > reported length
|
|
return false;
|
|
}
|
|
}
|
|
|
|
payloadOffset += paddedLength;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int32_t SerializeStunPacket(const StunPacket* packet, const uint8_t* password,
|
|
int32_t passwordLen, uint8_t* dest, int32_t len) {
|
|
memset(dest, 0, len);
|
|
int32_t offset = WriteScalar(dest, htons(Stun_SuccessResponse));
|
|
// X-MAPPED-ADDRESS (ip4) + MESSAGE-INTEGRITY SHA1
|
|
int32_t contentLength = 12 + 24;
|
|
int32_t contentLengthIntegrity = contentLength + 8;
|
|
const int32_t contentLengthOffset = offset;
|
|
offset += WriteScalar(dest + offset, htons(contentLength));
|
|
offset += WriteScalar(dest + offset, htonl(kStunCookie));
|
|
|
|
for (int32_t i = 0; i < 12; i++) {
|
|
dest[i + offset] = packet->transactionId[i];
|
|
}
|
|
|
|
offset += 12;
|
|
|
|
// xor mapped address attribute ipv4
|
|
offset += WriteScalar(dest + offset, htons(StunAttrib_XorMappedAddress));
|
|
offset += WriteScalar(dest + offset, htons(8));
|
|
offset += WriteScalar(dest + offset, uint8_t(0)); // reserved
|
|
offset += WriteScalar(dest + offset, packet->xorMappedAddress.family);
|
|
offset += WriteScalar(dest + offset, packet->xorMappedAddress.port);
|
|
offset += WriteScalar(dest + offset, packet->xorMappedAddress.address.ipv4);
|
|
|
|
WuSHA1Digest digest = WuSHA1(dest, offset, password, passwordLen);
|
|
|
|
offset += WriteScalar(dest + offset, htons(StunAttrib_MessageIntegrity));
|
|
offset += WriteScalar(dest + offset, htons(20));
|
|
|
|
for (int32_t i = 0; i < 20; i++) {
|
|
dest[i + offset] = digest.bytes[i];
|
|
}
|
|
|
|
offset += 20;
|
|
|
|
WriteScalar(dest + contentLengthOffset, htons(contentLengthIntegrity));
|
|
uint32_t crc = StunCRC32(dest, offset) ^ 0x5354554e;
|
|
|
|
offset += WriteScalar(dest + offset, htons(StunAttrib_Fingerprint));
|
|
offset += WriteScalar(dest + offset, htons(4));
|
|
offset += WriteScalar(dest + offset, htonl(crc));
|
|
|
|
return offset;
|
|
}
|