-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathWuStun.cpp
134 lines (107 loc) · 4.29 KB
/
WuStun.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#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;
}