Bug Summary

File:root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.cpp
Warning:line 1481, column 14
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name stun_codec.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D _FILE_OFFSET_BITS=64 -D CHROMIUM_BUILD -D USE_LIBJPEG_TURBO=1 -D USE_NSS=1 -D ENABLE_ONE_CLICK_SIGNIN -D GTK_DISABLE_SINGLE_INCLUDES=1 -D _ISOC99_SOURCE=1 -D ENABLE_REMOTING=1 -D ENABLE_WEBRTC=1 -D ENABLE_CONFIGURATION_POLICY -D ENABLE_INPUT_SPEECH -D ENABLE_NOTIFICATIONS -D ENABLE_GPU=1 -D ENABLE_EGLIMAGE=1 -D USE_SKIA=1 -D ENABLE_TASK_MANAGER=1 -D ENABLE_WEB_INTENTS=1 -D ENABLE_EXTENSIONS=1 -D ENABLE_PLUGIN_INSTALLATION=1 -D ENABLE_PROTECTOR_SERVICE=1 -D ENABLE_SESSION_SERVICE=1 -D ENABLE_THEMES=1 -D ENABLE_BACKGROUND=1 -D ENABLE_AUTOMATION=1 -D ENABLE_PRINTING=1 -D ENABLE_CAPTIVE_PORTAL_DETECTION=1 -D SANITY_CHECKS -D USE_TURN -D USE_ICE -D USE_RFC_3489_BACKWARDS_COMPATIBLE -D USE_STUND_0_96 -D USE_STUN_PEDANTIC -D NR_SOCKET_IS_VOID_PTR -D restrict= -D R_PLATFORM_INT_TYPES=<stdint.h> -D R_DEFINED_INT2=int16_t -D R_DEFINED_UINT2=uint16_t -D R_DEFINED_INT4=int32_t -D R_DEFINED_UINT4=uint32_t -D R_DEFINED_INT8=int64_t -D R_DEFINED_UINT8=uint64_t -D LINUX -D HAVE_LIBM=1 -D HAVE_STRDUP=1 -D HAVE_STRLCPY=1 -D HAVE_SYS_TIME_H=1 -D HAVE_VFPRINTF=1 -D NEW_STDIORETSIGTYPE=void -D TIME_WITH_SYS_TIME_H=1 -D __UNUSED__=__attribute__((unused)) -D DYNAMIC_ANNOTATIONS_ENABLED=1 -D WTF_USE_DYNAMIC_ANNOTATIONS=1 -D _DEBUG -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media/webrtc/transport/third_party/nICEr/nicer_nicer -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/event -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/log -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/registry -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/share -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/util -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/util/libekr -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/port/generic/include -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/crypto -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/net -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/util -I /root/firefox-clang/dom/media/webrtc/transport/third_party/nrappkit/src/port/linux/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-parentheses -Wno-format -Wno-format-security -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.cpp
1/*
2Copyright (c) 2007, Adobe Systems, Incorporated
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9* Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12* Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16* Neither the name of Adobe Systems, Network Resonance nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32
33#include <errno(*__errno_location ()).h>
34#include <csi_platform.h>
35
36#ifdef WIN32
37#include <winsock2.h>
38#include <stdlib.h>
39#include <io.h>
40#include <time.h>
41#else /* UNIX */
42#include <string.h>
43#endif /* end UNIX */
44#include <assert.h>
45#include <sstream>
46#include <stddef.h>
47
48#include "nr_api.h"
49#include "stun.h"
50#include "byteorder.h"
51#include "r_crc32.h"
52#include "nr_crypto.h"
53
54#define NR_STUN_IPV4_FAMILY0x01 0x01
55#define NR_STUN_IPV6_FAMILY0x02 0x02
56
57#define SKIP_ATTRIBUTE_DECODE-1 -1
58
59static int nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info);
60
61static int nr_stun_fix_attribute_ordering(nr_stun_message *msg);
62
63static int nr_stun_encode_htons(UINT2 data, size_t buflen, UCHAR *buf, size_t *offset);
64static int nr_stun_encode_htonl(UINT4 data, size_t buflen, UCHAR *buf, size_t *offset);
65static int nr_stun_encode_htonll(UINT8 data, size_t buflen, UCHAR *buf, size_t *offset);
66static int nr_stun_encode(UCHAR *data, size_t length, size_t buflen, UCHAR *buf, size_t *offset);
67
68static int nr_stun_decode_htons(UCHAR *buf, size_t buflen, size_t *offset, UINT2 *data);
69static int nr_stun_decode_htonl(UCHAR *buf, size_t buflen, size_t *offset, UINT4 *data);
70static int nr_stun_decode_htonll(UCHAR *buf, size_t buflen, size_t *offset, UINT8 *data);
71static int nr_stun_decode(size_t length, UCHAR *buf, size_t buflen, size_t *offset, UCHAR *data);
72
73static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, size_t len, void *data, size_t max_bytes, size_t max_chars);
74
75static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
76static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
77static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
78static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
79static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
80static int
81nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data);
82
83
84int
85nr_stun_encode_htons(UINT2 data, size_t buflen, UCHAR *buf, size_t *offset)
86{
87 UINT2 d = htons(data)__bswap_16 (data);
88
89 if (*offset + sizeof(d) >= buflen) {
90 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %zd >= %d", *offset, sizeof(d), buflen);
91 return R_BAD_DATA7;
92 }
93
94 memcpy(&buf[*offset], &d, sizeof(d));
95 *offset += sizeof(d);
96
97 return 0;
98}
99
100int
101nr_stun_encode_htonl(UINT4 data, size_t buflen, UCHAR *buf, size_t *offset)
102{
103 UINT4 d = htonl(data)__bswap_32 (data);
104
105 if (*offset + sizeof(d) > buflen) {
106 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
107 return R_BAD_DATA7;
108 }
109
110 memcpy(&buf[*offset], &d, sizeof(d));
111 *offset += sizeof(d);
112
113 return 0;
114}
115
116int
117nr_stun_encode_htonll(UINT8 data, size_t buflen, UCHAR *buf, size_t *offset)
118{
119 UINT8 d = nr_htonll(data);
120
121 if (*offset + sizeof(d) > buflen) {
122 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
123 return R_BAD_DATA7;
124 }
125
126 memcpy(&buf[*offset], &d, sizeof(d));
127 *offset += sizeof(d);
128
129 return 0;
130}
131
132int
133nr_stun_encode(UCHAR *data, size_t length, size_t buflen, UCHAR *buf, size_t *offset)
134{
135 if (*offset + length > buflen) {
136 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
137 return R_BAD_DATA7;
138 }
139
140 memcpy(&buf[*offset], data, length);
141 *offset += length;
142
143 return 0;
144}
145
146
147int
148nr_stun_decode_htons(UCHAR *buf, size_t buflen, size_t *offset, UINT2 *data)
149{
150 UINT2 d;
151
152 if (*offset + sizeof(d) > buflen) {
153 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
154 return R_BAD_DATA7;
155 }
156
157 memcpy(&d, &buf[*offset], sizeof(d));
158 *offset += sizeof(d);
159 *data = htons(d)__bswap_16 (d);
160
161 return 0;
162}
163
164int
165nr_stun_decode_htonl(UCHAR *buf, size_t buflen, size_t *offset, UINT4 *data)
166{
167 UINT4 d;
168
169 if (*offset + sizeof(d) > buflen) {
170 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
171 return R_BAD_DATA7;
172 }
173
174 memcpy(&d, &buf[*offset], sizeof(d));
175 *offset += sizeof(d);
176 *data = htonl(d)__bswap_32 (d);
177
178 return 0;
179}
180
181int
182nr_stun_decode_htonll(UCHAR *buf, size_t buflen, size_t *offset, UINT8 *data)
183{
184 UINT8 d;
185
186 if (*offset + sizeof(d) > buflen) {
187 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
188 return R_BAD_DATA7;
189 }
190
191 memcpy(&d, &buf[*offset], sizeof(d));
192 *offset += sizeof(d);
193 *data = nr_htonll(d);
194
195 return 0;
196}
197
198int
199nr_stun_decode(size_t length, UCHAR *buf, size_t buflen, size_t *offset, UCHAR *data)
200{
201 if (*offset + length > buflen) {
202 r_log(NR_LOG_STUN, LOG_WARNING4, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
203 return R_BAD_DATA7;
204 }
205
206 memcpy(data, &buf[*offset], length);
207 *offset += length;
208
209 return 0;
210}
211
212/**
213 * The argument must be a non-null pointer to a zero-terminated string.
214 *
215 * If the argument is valid UTF-8, returns the number of code points in the
216 * string excluding the zero-terminator.
217 *
218 * If the argument is invalid UTF-8, returns a lower bound for the number of
219 * code points in the string. (If UTF-8 error handling was performed on the
220 * string, new REPLACEMENT CHARACTER code points could be introduced in
221 * a way that would increase the total number of code points compared to
222 * what this function counts.)
223 */
224size_t
225nr_count_utf8_code_points_without_validation(const char *s) {
226 size_t nchars = 0;
227 char c;
228 while ((c = *s)) {
229 if ((c & 0xC0) != 0x80) {
230 ++nchars;
231 }
232 ++s;
233 }
234 return nchars;
235}
236
237int
238nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, size_t len, void *data, size_t max_bytes, size_t max_chars)
239{
240 int _status;
241 char *s = (char*)data;
242 size_t nchars;
243
244 if (len > max_bytes) {
245 r_log(NR_LOG_STUN, LOG_WARNING4, "%s is too large: %d bytes", attr_info->name, len);
246 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
247 }
248
249 nchars = nr_count_utf8_code_points_without_validation(s);
250 if (nchars > max_chars) {
251 r_log(NR_LOG_STUN, LOG_WARNING4, "%s is too large: %zd characters", attr_info->name, nchars);
252 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
253 }
254
255 _status = 0;
256 abort:
257 return _status;
258}
259
260int
261nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
262{
263 int r,_status;
264 nr_stun_attr_error_code *ec = (nr_stun_attr_error_code*)data;
265
266 if (ec->number < 300 || ec->number > 699)
267 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
268
269 if ((r=nr_stun_attr_string_illegal(attr_info, strlen(ec->reason), ec->reason, NR_STUN_MAX_ERROR_CODE_REASON_BYTES763, NR_STUN_MAX_ERROR_CODE_REASON_CHARS128)))
270 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
271
272 _status = 0;
273 abort:
274 return _status;
275}
276
277int
278nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
279{
280 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_NONCE_BYTES763, NR_STUN_MAX_NONCE_CHARS128);
281}
282
283int
284nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
285{
286 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_REALM_BYTES763, NR_STUN_MAX_REALM_CHARS128);
287}
288
289int
290nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
291{
292 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_SERVER_BYTES763, NR_STUN_MAX_SERVER_CHARS128);
293}
294
295int
296nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
297{
298 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_USERNAME_BYTES513, -1);
299}
300
301static int
302nr_stun_attr_codec_UCHAR_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
303{
304 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %u", msg, attr_info->name, *(UCHAR*)data);
305 return 0;
306}
307
308static int
309nr_stun_attr_codec_UCHAR_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
310{
311 int start = offset;
312 UINT4 tmp = *((UCHAR *)data);
313 tmp <<= 24;
314
315 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
316 || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset)
317 || nr_stun_encode_htonl(tmp , buflen, buf, &offset))
318 return R_FAILED10;
319
320 *attrlen = offset - start;
321
322 return 0;
323}
324
325static int
326nr_stun_attr_codec_UCHAR_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
327{
328 UINT4 tmp;
329
330 if (attrlen != sizeof(UINT4)) {
331 r_log(NR_LOG_STUN, LOG_WARNING4, "Integer is illegal size: %d", attrlen);
332 return R_FAILED10;
333 }
334
335 if (nr_stun_decode_htonl(buf, buflen, &offset, &tmp))
336 return R_FAILED10;
337
338 *((UCHAR *)data) = (tmp >> 24) & 0xff;
339
340 return 0;
341}
342
343nr_stun_attr_codec nr_stun_attr_codec_UCHAR = {
344 "UCHAR",
345 nr_stun_attr_codec_UCHAR_print,
346 nr_stun_attr_codec_UCHAR_encode,
347 nr_stun_attr_codec_UCHAR_decode
348};
349
350static int
351nr_stun_attr_codec_UINT4_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
352{
353 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %u", msg, attr_info->name, *(UINT4*)data);
354 return 0;
355}
356
357static int
358nr_stun_attr_codec_UINT4_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
359{
360 int start = offset;
361
362 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
363 || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset)
364 || nr_stun_encode_htonl(*(UINT4*)data , buflen, buf, &offset))
365 return R_FAILED10;
366
367 *attrlen = offset - start;
368
369 return 0;
370}
371
372static int
373nr_stun_attr_codec_UINT4_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
374{
375 if (attrlen != sizeof(UINT4)) {
376 r_log(NR_LOG_STUN, LOG_WARNING4, "Integer is illegal size: %d", attrlen);
377 return R_FAILED10;
378 }
379
380 if (nr_stun_decode_htonl(buf, buflen, &offset, (UINT4*)data))
381 return R_FAILED10;
382
383 return 0;
384}
385
386nr_stun_attr_codec nr_stun_attr_codec_UINT4 = {
387 "UINT4",
388 nr_stun_attr_codec_UINT4_print,
389 nr_stun_attr_codec_UINT4_encode,
390 nr_stun_attr_codec_UINT4_decode
391};
392
393static int
394nr_stun_attr_codec_UINT8_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
395{
396 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %llu", msg, attr_info->name, *(UINT8*)data);
397 return 0;
398}
399
400static int
401nr_stun_attr_codec_UINT8_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
402{
403 int start = offset;
404
405 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
406 || nr_stun_encode_htons(sizeof(UINT8) , buflen, buf, &offset)
407 || nr_stun_encode_htonll(*(UINT8*)data , buflen, buf, &offset))
408 return R_FAILED10;
409
410 *attrlen = offset - start;
411
412 return 0;
413}
414
415static int
416nr_stun_attr_codec_UINT8_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
417{
418 if (attrlen != sizeof(UINT8)) {
419 r_log(NR_LOG_STUN, LOG_WARNING4, "Integer is illegal size: %d", attrlen);
420 return R_FAILED10;
421 }
422
423 if (nr_stun_decode_htonll(buf, buflen, &offset, (UINT8*)data))
424 return R_FAILED10;
425
426 return 0;
427}
428
429nr_stun_attr_codec nr_stun_attr_codec_UINT8 = {
430 "UINT8",
431 nr_stun_attr_codec_UINT8_print,
432 nr_stun_attr_codec_UINT8_encode,
433 nr_stun_attr_codec_UINT8_decode
434};
435
436static int
437nr_stun_attr_codec_addr_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
438{
439 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %s", msg, attr_info->name, ((nr_transport_addr*)data)->as_string);
440 return 0;
441}
442
443static int
444nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
445{
446 int r,_status;
447 int start = offset;
448 nr_transport_addr *addr = (nr_transport_addr*)data;
449 UCHAR pad = '\0';
450 UCHAR family;
451
452 if ((r=nr_stun_encode_htons(attr_info->type, buflen, buf, &offset)))
453 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
454
455 switch (addr->ip_version) {
456 case NR_IPV44:
457 family = NR_STUN_IPV4_FAMILY0x01;
458 if (nr_stun_encode_htons(8 , buflen, buf, &offset)
459 || nr_stun_encode(&pad, 1 , buflen, buf, &offset)
460 || nr_stun_encode(&family, 1 , buflen, buf, &offset)
461 || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port)__bswap_16 (addr->u.addr4.sin_port), buflen, buf, &offset)
462 || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr)__bswap_32 (addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset))
463 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
464 break;
465
466 case NR_IPV66:
467 family = NR_STUN_IPV6_FAMILY0x02;
468 if (nr_stun_encode_htons(20 , buflen, buf, &offset)
469 || nr_stun_encode(&pad, 1 , buflen, buf, &offset)
470 || nr_stun_encode(&family, 1 , buflen, buf, &offset)
471 || nr_stun_encode_htons(ntohs(addr->u.addr6.sin6_port)__bswap_16 (addr->u.addr6.sin6_port), buflen, buf, &offset)
472 || nr_stun_encode(addr->u.addr6.sin6_addr.s6_addr__in6_u.__u6_addr8, 16, buflen, buf, &offset))
473 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
474 break;
475
476 default:
477 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
478 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
479 break;
480 }
481
482 *attrlen = offset - start;
483
484 _status = 0;
485 abort:
486 return _status;
487}
488
489static int
490nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
491{
492 int _status;
493 UCHAR pad;
494 UCHAR family;
495 UINT2 port;
496 UINT4 addr4;
497 struct in6_addr addr6;
498 nr_transport_addr *result = (nr_transport_addr*)data;
499
500 if (nr_stun_decode(1, buf, buflen, &offset, &pad)
501 || nr_stun_decode(1, buf, buflen, &offset, &family))
502 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
503
504 switch (family) {
505 case NR_STUN_IPV4_FAMILY0x01:
506 if (attrlen != 8) {
507 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal attribute length: %d", attrlen);
508 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
509 }
510
511 if (nr_stun_decode_htons(buf, buflen, &offset, &port)
512 || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
513 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
514
515 if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDPIPPROTO_UDP, result))
516 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
517 break;
518
519 case NR_STUN_IPV6_FAMILY0x02:
520 if (attrlen != 20) {
521 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal attribute length: %d", attrlen);
522 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
523 }
524
525 if (nr_stun_decode_htons(buf, buflen, &offset, &port)
526 || nr_stun_decode(16, buf, buflen, &offset, addr6.s6_addr__in6_u.__u6_addr8))
527 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
528
529 if (nr_ip6_port_to_transport_addr(&addr6, port, IPPROTO_UDPIPPROTO_UDP, result))
530 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
531 break;
532
533 default:
534 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal address family: %d", family);
535 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
536 break;
537 }
538
539 _status = 0;
540 abort:
541 return _status;
542}
543
544nr_stun_attr_codec nr_stun_attr_codec_addr = {
545 "addr",
546 nr_stun_attr_codec_addr_print,
547 nr_stun_attr_codec_addr_encode,
548 nr_stun_attr_codec_addr_decode
549};
550
551static int
552nr_stun_attr_codec_data_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
553{
554 nr_stun_attr_data *d = (nr_stun_attr_data*)data;
555 r_dump(NR_LOG_STUN, LOG_DEBUG7, attr_info->name, (char*)d->data, d->length);
556 return 0;
557}
558
559static int
560nr_stun_attr_codec_data_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
561{
562 nr_stun_attr_data *d = (nr_stun_attr_data*)data;
563 int start = offset;
564
565 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
566 || nr_stun_encode_htons(d->length , buflen, buf, &offset)
567 || nr_stun_encode(d->data, d->length , buflen, buf, &offset))
568 return R_FAILED10;
569
570 *attrlen = offset - start;
571
572 return 0;
573}
574
575static int
576nr_stun_attr_codec_data_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
577{
578 int _status;
579 nr_stun_attr_data *result = (nr_stun_attr_data*)data;
580
581 /* -1 because it is going to be null terminated just to be safe */
582 if (attrlen >= (sizeof(result->data) - 1)) {
583 r_log(NR_LOG_STUN, LOG_WARNING4, "Too much data: %d bytes", attrlen);
584 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
585 }
586
587 if (nr_stun_decode(attrlen, buf, buflen, &offset, result->data))
588 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
589
590 result->length = attrlen;
591 result->data[attrlen] = '\0'; /* just to be nice */
592
593 _status=0;
594 abort:
595 return _status;
596}
597
598nr_stun_attr_codec nr_stun_attr_codec_data = {
599 "data",
600 nr_stun_attr_codec_data_print,
601 nr_stun_attr_codec_data_encode,
602 nr_stun_attr_codec_data_decode
603};
604
605static int
606nr_stun_attr_codec_error_code_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
607{
608 nr_stun_attr_error_code *error_code = (nr_stun_attr_error_code*)data;
609 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %d %s",
610 msg, attr_info->name, error_code->number,
611 error_code->reason);
612 return 0;
613}
614
615static int
616nr_stun_attr_codec_error_code_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
617{
618 nr_stun_attr_error_code *error_code = (nr_stun_attr_error_code*)data;
619 int start = offset;
620 int length = strlen(error_code->reason);
621 UCHAR pad[2] = { 0 };
622 UCHAR err_class = error_code->number / 100;
623 UCHAR err_number = error_code->number % 100;
624
625 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
626 || nr_stun_encode_htons(4 + length , buflen, buf, &offset)
627 || nr_stun_encode(pad, 2 , buflen, buf, &offset)
628 || nr_stun_encode(&err_class, 1 , buflen, buf, &offset)
629 || nr_stun_encode(&err_number, 1 , buflen, buf, &offset)
630 || nr_stun_encode((UCHAR*)error_code->reason, length, buflen, buf, &offset))
631 return R_FAILED10;
632
633 *attrlen = offset - start;
634
635 return 0;
636}
637
638static int
639nr_stun_attr_codec_error_code_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
640{
641 int _status;
642 nr_stun_attr_error_code *result = (nr_stun_attr_error_code*)data;
643 UCHAR pad[2];
644 UCHAR err_class;
645 UCHAR err_number;
646 size_t size_reason;
647
648 if (nr_stun_decode(2, buf, buflen, &offset, pad)
649 || nr_stun_decode(1, buf, buflen, &offset, &err_class)
650 || nr_stun_decode(1, buf, buflen, &offset, &err_number))
651 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
652
653 result->number = (err_class * 100) + err_number;
654
655 size_reason = attrlen - 4;
656
657 /* -1 because the string will be null terminated */
658 if (size_reason > (sizeof(result->reason) - 1)) {
659 r_log(NR_LOG_STUN, LOG_WARNING4, "Reason is too large, truncating");
660 /* don't fail, but instead truncate the reason */
661 size_reason = sizeof(result->reason) - 1;
662 }
663
664 if (nr_stun_decode(size_reason, buf, buflen, &offset, (UCHAR*)result->reason))
665 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
666 result->reason[size_reason] = '\0';
667
668 _status=0;
669 abort:
670 return _status;
671}
672
673nr_stun_attr_codec nr_stun_attr_codec_error_code = {
674 "error_code",
675 nr_stun_attr_codec_error_code_print,
676 nr_stun_attr_codec_error_code_encode,
677 nr_stun_attr_codec_error_code_decode
678};
679
680static int
681nr_stun_attr_codec_fingerprint_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
682{
683 nr_stun_attr_fingerprint *fingerprint = (nr_stun_attr_fingerprint*)data;
684 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %08x", msg, attr_info->name, fingerprint->checksum);
685 return 0;
686}
687
688static int
689nr_stun_attr_codec_fingerprint_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
690{
691 UINT4 checksum;
692 nr_stun_attr_fingerprint *fingerprint = (nr_stun_attr_fingerprint*)data;
693 nr_stun_message_header *header = (nr_stun_message_header*)buf;
694
695 /* the length must include the FINGERPRINT attribute when computing
696 * the fingerprint */
697 header->length = ntohs(header->length)__bswap_16 (header->length);
698 header->length += 8; /* Fingerprint */
699 header->length = htons(header->length)__bswap_16 (header->length);
700
701 if (r_crc32((char*)buf, offset, &checksum)) {
702 r_log(NR_LOG_STUN, LOG_WARNING4, "Unable to compute fingerprint");
703 return R_FAILED10;
704 }
705
706 fingerprint->checksum = checksum ^ 0x5354554e;
707
708 r_log(NR_LOG_STUN, LOG_DEBUG7, "Computed FINGERPRINT %08x", fingerprint->checksum);
709
710 fingerprint->valid = 1;
711 return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen);
712}
713
714static int
715nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
716{
717 int r,_status;
718 nr_stun_attr_fingerprint *fingerprint = (nr_stun_attr_fingerprint*)data;
719 nr_stun_message_header *header = (nr_stun_message_header*)buf;
720 size_t length;
721 UINT4 checksum;
722
723 if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum)))
724 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
725
726 offset -= 4; /* rewind to before the length and type fields */
727
728 /* the length must include the FINGERPRINT attribute when computing
729 * the fingerprint */
730 length = offset; /* right before FINGERPRINT */
731 length -= sizeof(*header); /* remove header length */
732 length += 8; /* add length of Fingerprint */
733 header->length = htons(length)__bswap_16 (length);
734
735 /* make sure FINGERPRINT is final attribute in message */
736 if (length + sizeof(*header) != buflen) {
737 r_log(NR_LOG_STUN, LOG_WARNING4, "Fingerprint is not final attribute in message");
738 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
739 }
740
741 if (r_crc32((char*)buf, offset, &checksum)) {
742 r_log(NR_LOG_STUN, LOG_WARNING4, "Unable to compute fingerprint");
743 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
744 }
745
746 fingerprint->valid = (fingerprint->checksum == (checksum ^ 0x5354554e));
747
748 r_log(NR_LOG_STUN, LOG_DEBUG7, "Computed FINGERPRINT %08x", (checksum ^ 0x5354554e));
749 if (! fingerprint->valid)
750 r_log(NR_LOG_STUN, LOG_WARNING4, "Invalid FINGERPRINT %08x", fingerprint->checksum);
751
752 _status=0;
753 abort:
754 return _status;
755}
756
757nr_stun_attr_codec nr_stun_attr_codec_fingerprint = {
758 "fingerprint",
759 nr_stun_attr_codec_fingerprint_print,
760 nr_stun_attr_codec_fingerprint_encode,
761 nr_stun_attr_codec_fingerprint_decode
762};
763
764static int
765nr_stun_attr_codec_flag_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
766{
767 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: on", msg, attr_info->name);
768 return 0;
769}
770
771static int
772nr_stun_attr_codec_flag_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
773{
774 int start = offset;
775
776 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
777 || nr_stun_encode_htons(0 , buflen, buf, &offset))
778 return R_FAILED10;
779
780 *attrlen = offset - start;
781
782 return 0;
783}
784
785static int
786nr_stun_attr_codec_flag_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
787{
788 if (attrlen != 0) {
789 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal flag length: %d", attrlen);
790 return R_FAILED10;
791 }
792
793 return 0;
794}
795
796nr_stun_attr_codec nr_stun_attr_codec_flag = {
797 "flag",
798 nr_stun_attr_codec_flag_print,
799 nr_stun_attr_codec_flag_encode,
800 nr_stun_attr_codec_flag_decode
801};
802
803static int
804nr_stun_attr_codec_message_integrity_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
805{
806 nr_stun_attr_message_integrity *integrity = (nr_stun_attr_message_integrity*)data;
807 r_dump(NR_LOG_STUN, LOG_DEBUG7, attr_info->name, (char*)integrity->hash, sizeof(integrity->hash));
808 return 0;
809}
810
811static int
812nr_stun_compute_message_integrity(UCHAR *buf, int offset, UCHAR *password, int passwordlen, UCHAR *computedHMAC)
813{
814 int r,_status;
815 UINT2 hold;
816 UINT2 length;
817 nr_stun_message_header *header;
818
819 r_log(NR_LOG_STUN, LOG_DEBUG7, "Computing MESSAGE-INTEGRITY");
820
821 header = (nr_stun_message_header*)buf;
822 hold = header->length;
823
824 /* adjust the length of the message */
825 length = offset;
826 length -= sizeof(*header);
827 length += 24; /* for MESSAGE-INTEGRITY attribute */
828 header->length = htons(length)__bswap_16 (length);
829
830 if ((r=nr_crypto_hmac_sha1((UCHAR*)password, passwordlen,nr_crypto_vtbl->hmac_sha1((UCHAR*)password,passwordlen,buf
,offset,computedHMAC)
831 buf, offset, computedHMAC)nr_crypto_vtbl->hmac_sha1((UCHAR*)password,passwordlen,buf
,offset,computedHMAC)
))
832 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
833
834 r_dump(NR_LOG_STUN, LOG_DEBUG7, "Computed MESSAGE-INTEGRITY ", (char*)computedHMAC, 20);
835
836 _status=0;
837 abort:
838 header->length = hold;
839 return _status;
840}
841
842static int
843nr_stun_attr_codec_message_integrity_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
844{
845 int start = offset;
846 nr_stun_attr_message_integrity *integrity = (nr_stun_attr_message_integrity*)data;
847
848 if (nr_stun_compute_message_integrity(buf, offset, integrity->password, integrity->passwordlen, integrity->hash))
849 return R_FAILED10;
850
851 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
852 || nr_stun_encode_htons(sizeof(integrity->hash) , buflen, buf, &offset)
853 || nr_stun_encode(integrity->hash, sizeof(integrity->hash) , buflen, buf, &offset))
854 return R_FAILED10;
855
856 *attrlen = offset - start;
857
858 return 0;
859}
860
861static int
862nr_stun_attr_codec_message_integrity_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
863{
864 int _status;
865 int start;
866 nr_stun_attr_message_integrity *result = (nr_stun_attr_message_integrity*)data;
867 UCHAR computedHMAC[20];
868
869 result->valid = 0;
870
871 if (attrlen != 20) {
872 r_log(NR_LOG_STUN, LOG_WARNING4, "%s must be 20 bytes, not %d", attr_info->name, attrlen);
873 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
874 }
875
876 start = offset - 4; /* rewind to before the length and type fields */
877 if (start < 0)
878 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
879
880 if (nr_stun_decode(attrlen, buf, buflen, &offset, result->hash))
881 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
882
883 if (result->unknown_user) {
884 result->valid = 0;
885 }
886 else {
887 if (nr_stun_compute_message_integrity(buf, start, result->password, result->passwordlen, computedHMAC))
888 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
889
890 assert(sizeof(computedHMAC) == sizeof(result->hash))(static_cast <bool> (sizeof(computedHMAC) == sizeof(result
->hash)) ? void (0) : __assert_fail ("sizeof(computedHMAC) == sizeof(result->hash)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
891
892 result->valid = (memcmp(computedHMAC, result->hash, 20) == 0);
893 }
894
895 _status=0;
896 abort:
897 return _status;
898}
899
900nr_stun_attr_codec nr_stun_attr_codec_message_integrity = {
901 "message_integrity",
902 nr_stun_attr_codec_message_integrity_print,
903 nr_stun_attr_codec_message_integrity_encode,
904 nr_stun_attr_codec_message_integrity_decode
905};
906
907static int
908nr_stun_attr_codec_noop_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
909{
910 return SKIP_ATTRIBUTE_DECODE-1;
911}
912
913nr_stun_attr_codec nr_stun_attr_codec_noop = {
914 "NOOP",
915 0, /* ignore, never print these attributes */
916 0, /* ignore, never encode these attributes */
917 nr_stun_attr_codec_noop_decode
918};
919
920static int
921nr_stun_attr_codec_quoted_string_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
922{
923 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %s",
924 msg, attr_info->name, (char*)data);
925 return 0;
926}
927
928static int
929nr_stun_attr_codec_quoted_string_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
930{
931//TODO: !nn! syntax check, conversion if not quoted already?
932//We'll just restrict this in the API -- EKR
933 return nr_stun_attr_codec_string.encode(attr_info, data, offset, buflen, buf, attrlen);
934}
935
936static int
937nr_stun_attr_codec_quoted_string_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
938{
939//TODO: !nn! I don't see any need to unquote this but we may
940//find one later -- EKR
941 return nr_stun_attr_codec_string.decode(attr_info, attrlen, buf, offset, buflen, data);
942}
943
944nr_stun_attr_codec nr_stun_attr_codec_quoted_string = {
945 "quoted_string",
946 nr_stun_attr_codec_quoted_string_print,
947 nr_stun_attr_codec_quoted_string_encode,
948 nr_stun_attr_codec_quoted_string_decode
949};
950
951static int
952nr_stun_attr_codec_string_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
953{
954 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %s",
955 msg, attr_info->name, (char*)data);
956 return 0;
957}
958
959static int
960nr_stun_attr_codec_string_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
961{
962 int start = offset;
963 char *str = (char*)data;
964 int length = strlen(str);
965
966 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
967 || nr_stun_encode_htons(length , buflen, buf, &offset)
968 || nr_stun_encode((UCHAR*)str, length , buflen, buf, &offset))
969 return R_FAILED10;
970
971 *attrlen = offset - start;
972
973 return 0;
974}
975
976static int
977nr_stun_attr_codec_string_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
978{
979 int _status;
980 char *result = (char*)data;
981
982 /* actual enforcement of the specific string size happens elsewhere */
983 if (attrlen >= NR_STUN_MAX_STRING_SIZE763) {
984 r_log(NR_LOG_STUN, LOG_WARNING4, "String is too large: %d bytes", attrlen);
985 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
986 }
987
988 if (nr_stun_decode(attrlen, buf, buflen, &offset, (UCHAR*)result))
989 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
990 result[attrlen] = '\0'; /* just to be nice */
991
992 if (strlen(result) != attrlen) {
993 /* stund 0.96 sends a final null in the Server attribute, so
994 * only error if the null appears anywhere else in a string */
995 if (strlen(result) != attrlen-1) {
996 r_log(NR_LOG_STUN, LOG_WARNING4, "Error in string: %zd/%d", strlen(result), attrlen);
997 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
998 }
999 }
1000
1001 _status = 0;
1002 abort:
1003 return _status;
1004}
1005
1006nr_stun_attr_codec nr_stun_attr_codec_string = {
1007 "string",
1008 nr_stun_attr_codec_string_print,
1009 nr_stun_attr_codec_string_encode,
1010 nr_stun_attr_codec_string_decode
1011};
1012
1013static int
1014nr_stun_attr_codec_unknown_attributes_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
1015{
1016 nr_stun_attr_unknown_attributes *unknown_attributes = (nr_stun_attr_unknown_attributes*)data;
1017 std::ostringstream oss;
1018
1019 oss << msg << " " << attr_info->name << ":";
1020 for (int i = 0; i < unknown_attributes->num_attributes; ++i) {
1021 char type[9];
1022 snprintf(type, sizeof(type), "%s 0x%04x", ((i>0)?",":""), unknown_attributes->attribute[i]);
1023 oss << type;
1024 }
1025
1026 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s", oss.str().c_str());
1027 return 0;
1028}
1029
1030static int
1031nr_stun_attr_codec_unknown_attributes_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
1032{
1033 int _status;
1034 int start = offset;
1035 nr_stun_attr_unknown_attributes *unknown_attributes = (nr_stun_attr_unknown_attributes*)data;
1036 int length = (2 * unknown_attributes->num_attributes);
1037 int i;
1038
1039 if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES16) {
1040 r_log(NR_LOG_STUN, LOG_WARNING4, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes);
1041 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1042 }
1043
1044 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
1045 || nr_stun_encode_htons(length , buflen, buf, &offset))
1046 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1047
1048 for (i = 0; i < unknown_attributes->num_attributes; ++i) {
1049 if (nr_stun_encode_htons(unknown_attributes->attribute[i], buflen, buf, &offset))
1050 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1051 }
1052
1053 *attrlen = offset - start;
1054
1055 _status = 0;
1056 abort:
1057 return _status;
1058}
1059
1060static int
1061nr_stun_attr_codec_unknown_attributes_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
1062{
1063 int _status;
1064 nr_stun_attr_unknown_attributes *unknown_attributes = (nr_stun_attr_unknown_attributes*)data;
1065 int i;
1066 UINT2 *a;
1067
1068 if ((attrlen % 4) != 0) {
1069 r_log(NR_LOG_STUN, LOG_WARNING4, "Attribute is illegal size: %d", attrlen);
1070 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1071 }
1072
1073 unknown_attributes->num_attributes = attrlen / 2;
1074
1075 if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES16) {
1076 r_log(NR_LOG_STUN, LOG_WARNING4, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes);
1077 ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1078 }
1079
1080 for (i = 0; i < unknown_attributes->num_attributes; ++i) {
1081 a = &(unknown_attributes->attribute[i]);
1082 if (nr_stun_decode_htons(buf, buflen, &offset, a))
1083 return R_FAILED10;
1084 }
1085
1086 _status = 0;
1087 abort:
1088 return _status;
1089}
1090
1091nr_stun_attr_codec nr_stun_attr_codec_unknown_attributes = {
1092 "unknown_attributes",
1093 nr_stun_attr_codec_unknown_attributes_print,
1094 nr_stun_attr_codec_unknown_attributes_encode,
1095 nr_stun_attr_codec_unknown_attributes_decode
1096};
1097
1098static int
1099nr_stun_attr_codec_xor_mapped_address_print(nr_stun_attr_info *attr_info, const char *msg, void *data)
1100{
1101 nr_stun_attr_xor_mapped_address *xor_mapped_address = (nr_stun_attr_xor_mapped_address*)data;
1102 r_log(NR_LOG_STUN, LOG_DEBUG7, "%s %s: %s (unmasked) %s (masked)",
1103 msg, attr_info->name,
1104 xor_mapped_address->unmasked.as_string,
1105 xor_mapped_address->masked.as_string);
1106 return 0;
1107}
1108
1109static int
1110nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
1111{
1112 nr_stun_attr_xor_mapped_address *xor_mapped_address = (nr_stun_attr_xor_mapped_address*)data;
1113 nr_stun_message_header *header = (nr_stun_message_header*)buf;
1114 UINT4 magic_cookie;
1115
1116 r_log(NR_LOG_STUN, LOG_DEBUG7, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
1117
1118 /* this needs to be the magic cookie in the header and not
1119 * the MAGIC_COOKIE constant because if we're talking to
1120 * older servers (that don't have a magic cookie) they use
1121 * message ID for this */
1122 magic_cookie = ntohl(header->magic_cookie)__bswap_32 (header->magic_cookie);
1123
1124 nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
1125
1126 r_log(NR_LOG_STUN, LOG_DEBUG7, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
1127
1128 if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
1129 return R_FAILED10;
1130
1131 return 0;
1132}
1133
1134static int
1135nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
1136{
1137 int r,_status;
1138 nr_stun_attr_xor_mapped_address *xor_mapped_address = (nr_stun_attr_xor_mapped_address*)data;
1139 nr_stun_message_header *header = (nr_stun_message_header*)buf;
1140 UINT4 magic_cookie;
1141
1142 if ((r=nr_stun_attr_codec_addr.decode(attr_info, attrlen, buf, offset, buflen, &xor_mapped_address->masked)))
1143 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1144
1145 r_log(NR_LOG_STUN, LOG_DEBUG7, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
1146
1147 /* this needs to be the magic cookie in the header and not
1148 * the MAGIC_COOKIE constant because if we're talking to
1149 * older servers (that don't have a magic cookie) they use
1150 * message ID for this */
1151 magic_cookie = ntohl(header->magic_cookie)__bswap_32 (header->magic_cookie);
1152
1153 nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
1154
1155 r_log(NR_LOG_STUN, LOG_DEBUG7, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
1156
1157 _status = 0;
1158 abort:
1159 return _status;
1160}
1161
1162nr_stun_attr_codec nr_stun_attr_codec_xor_mapped_address = {
1163 "xor_mapped_address",
1164 nr_stun_attr_codec_xor_mapped_address_print,
1165 nr_stun_attr_codec_xor_mapped_address_encode,
1166 nr_stun_attr_codec_xor_mapped_address_decode
1167};
1168
1169nr_stun_attr_codec nr_stun_attr_codec_old_xor_mapped_address = {
1170 "xor_mapped_address",
1171 nr_stun_attr_codec_xor_mapped_address_print,
1172 0, /* never encode this type */
1173 nr_stun_attr_codec_xor_mapped_address_decode
1174};
1175
1176nr_stun_attr_codec nr_stun_attr_codec_xor_peer_address = {
1177 "xor_peer_address",
1178 nr_stun_attr_codec_xor_mapped_address_print,
1179 nr_stun_attr_codec_xor_mapped_address_encode,
1180 nr_stun_attr_codec_xor_mapped_address_decode
1181};
1182
1183#define NR_ADD_STUN_ATTRIBUTE(type, name, codec, illegal){ (type), (name), &(codec), illegal }, \
1184 { (type), (name), &(codec), illegal },
1185
1186#define NR_ADD_STUN_ATTRIBUTE_IGNORE(type, name){ (type), (name), &nr_stun_attr_codec_noop, 0 }, \
1187 { (type), (name), &nr_stun_attr_codec_noop, 0 },
1188
1189
1190static nr_stun_attr_info attrs[] = {
1191 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ALTERNATE_SERVER, "ALTERNATE-SERVER", nr_stun_attr_codec_addr, 0){ (0x8023), ("ALTERNATE-SERVER"), &(nr_stun_attr_codec_addr
), 0 },
1192#ifdef USE_STUND_0_961
1193 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_CHANGE_REQUEST, "CHANGE-REQUEST", nr_stun_attr_codec_UINT4, 0){ (0x0003), ("CHANGE-REQUEST"), &(nr_stun_attr_codec_UINT4
), 0 },
1194#endif
1195 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ERROR_CODE, "ERROR-CODE", nr_stun_attr_codec_error_code, nr_stun_attr_error_code_illegal){ (0x0009), ("ERROR-CODE"), &(nr_stun_attr_codec_error_code
), nr_stun_attr_error_code_illegal },
1196 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_FINGERPRINT, "FINGERPRINT", nr_stun_attr_codec_fingerprint, 0){ (0x8028), ("FINGERPRINT"), &(nr_stun_attr_codec_fingerprint
), 0 },
1197 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MAPPED_ADDRESS, "MAPPED-ADDRESS", nr_stun_attr_codec_addr, 0){ (0x0001), ("MAPPED-ADDRESS"), &(nr_stun_attr_codec_addr
), 0 },
1198 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY", nr_stun_attr_codec_message_integrity, 0){ (0x0008), ("MESSAGE-INTEGRITY"), &(nr_stun_attr_codec_message_integrity
), 0 },
1199 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_NONCE, "NONCE", nr_stun_attr_codec_quoted_string, nr_stun_attr_nonce_illegal){ (0x0015), ("NONCE"), &(nr_stun_attr_codec_quoted_string
), nr_stun_attr_nonce_illegal },
1200 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REALM, "REALM", nr_stun_attr_codec_quoted_string, nr_stun_attr_realm_illegal){ (0x0014), ("REALM"), &(nr_stun_attr_codec_quoted_string
), nr_stun_attr_realm_illegal },
1201 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_SERVER, "SERVER", nr_stun_attr_codec_string, nr_stun_attr_server_illegal){ (0x8022), ("SERVER"), &(nr_stun_attr_codec_string), nr_stun_attr_server_illegal
},
1202 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_UNKNOWN_ATTRIBUTES, "UNKNOWN-ATTRIBUTES", nr_stun_attr_codec_unknown_attributes, 0){ (0x000A), ("UNKNOWN-ATTRIBUTES"), &(nr_stun_attr_codec_unknown_attributes
), 0 },
1203 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USERNAME, "USERNAME", nr_stun_attr_codec_string, nr_stun_attr_username_illegal){ (0x0006), ("USERNAME"), &(nr_stun_attr_codec_string), nr_stun_attr_username_illegal
},
1204 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_MAPPED_ADDRESS, "XOR-MAPPED-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0){ (0x0020), ("XOR-MAPPED-ADDRESS"), &(nr_stun_attr_codec_xor_mapped_address
), 0 },
1205
1206#ifdef USE_ICE1
1207 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLED, "ICE-CONTROLLED", nr_stun_attr_codec_UINT8, 0){ (0x8029), ("ICE-CONTROLLED"), &(nr_stun_attr_codec_UINT8
), 0 },
1208 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLING, "ICE-CONTROLLING", nr_stun_attr_codec_UINT8, 0){ (0x802A), ("ICE-CONTROLLING"), &(nr_stun_attr_codec_UINT8
), 0 },
1209 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_PRIORITY, "PRIORITY", nr_stun_attr_codec_UINT4, 0){ (0x0024), ("PRIORITY"), &(nr_stun_attr_codec_UINT4), 0 }
,
1210 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USE_CANDIDATE, "USE-CANDIDATE", nr_stun_attr_codec_flag, 0){ (0x0025), ("USE-CANDIDATE"), &(nr_stun_attr_codec_flag)
, 0 },
1211#endif
1212
1213#ifdef USE_TURN1
1214 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_DATA, "DATA", nr_stun_attr_codec_data, 0){ (0x0013), ("DATA"), &(nr_stun_attr_codec_data), 0 },
1215 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_LIFETIME, "LIFETIME", nr_stun_attr_codec_UINT4, 0){ (0x000d), ("LIFETIME"), &(nr_stun_attr_codec_UINT4), 0 }
,
1216 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_RELAY_ADDRESS, "XOR-RELAY-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0){ (0x0016), ("XOR-RELAY-ADDRESS"), &(nr_stun_attr_codec_xor_mapped_address
), 0 },
1217 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_PEER_ADDRESS, "XOR-PEER-ADDRESS", nr_stun_attr_codec_xor_peer_address, 0){ (0x0012), ("XOR-PEER-ADDRESS"), &(nr_stun_attr_codec_xor_peer_address
), 0 },
1218 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REQUESTED_TRANSPORT, "REQUESTED-TRANSPORT", nr_stun_attr_codec_UCHAR, 0){ (0x0019), ("REQUESTED-TRANSPORT"), &(nr_stun_attr_codec_UCHAR
), 0 },
1219 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_BANDWIDTH, "BANDWIDTH", nr_stun_attr_codec_UINT4, 0){ (0x0010), ("BANDWIDTH"), &(nr_stun_attr_codec_UINT4), 0
},
1220#endif /* USE_TURN */
1221
1222 /* for backwards compatibilty */
1223 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS, "Old XOR-MAPPED-ADDRESS", nr_stun_attr_codec_old_xor_mapped_address, 0){ (0x8020), ("Old XOR-MAPPED-ADDRESS"), &(nr_stun_attr_codec_old_xor_mapped_address
), 0 },
1224#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE1
1225 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_RESPONSE_ADDRESS, "RESPONSE-ADDRESS"){ (0x0002), ("RESPONSE-ADDRESS"), &nr_stun_attr_codec_noop
, 0 },
1226 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_SOURCE_ADDRESS, "SOURCE-ADDRESS"){ (0x0004), ("SOURCE-ADDRESS"), &nr_stun_attr_codec_noop,
0 },
1227 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_CHANGED_ADDRESS, "CHANGED-ADDRESS"){ (0x0005), ("CHANGED-ADDRESS"), &nr_stun_attr_codec_noop
, 0 },
1228 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_PASSWORD, "PASSWORD"){ (0x0007), ("PASSWORD"), &nr_stun_attr_codec_noop, 0 },
1229#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
1230};
1231
1232
1233int
1234nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info)
1235{
1236 int _status;
1237 size_t i;
1238
1239 *info = 0;
1240 for (i = 0; i < sizeof(attrs)/sizeof(*attrs); ++i) {
1241 if (type == attrs[i].type) {
1242 *info = &attrs[i];
1243 break;
1244 }
1245 }
1246
1247 if (*info == 0)
1248 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1249
1250 _status=0;
1251 abort:
1252 return(_status);
1253}
1254
1255int
1256nr_stun_fix_attribute_ordering(nr_stun_message *msg)
1257{
1258 nr_stun_message_attribute *message_integrity;
1259 nr_stun_message_attribute *fingerprint;
1260
1261 /* 2nd to the last */
1262 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY0x0008, &message_integrity)) {
1263 TAILQ_REMOVE(&msg->attributes, message_integrity, entry)do { if (((((message_integrity))->entry.tqe_next)) != __null
) (((message_integrity))->entry.tqe_next)->entry.tqe_prev
= (message_integrity)->entry.tqe_prev; else { (&msg->
attributes)->tqh_last = (message_integrity)->entry.tqe_prev
; ; } *(message_integrity)->entry.tqe_prev = (((message_integrity
))->entry.tqe_next); ; ; ; } while (0)
;
1264 TAILQ_INSERT_TAIL(&msg->attributes, message_integrity, entry)do { (((message_integrity))->entry.tqe_next) = __null; (message_integrity
)->entry.tqe_prev = (&msg->attributes)->tqh_last
; *(&msg->attributes)->tqh_last = (message_integrity
); (&msg->attributes)->tqh_last = &(((message_integrity
))->entry.tqe_next); ; ; } while (0)
;
1265 }
1266
1267 /* last */
1268 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT0x8028, &fingerprint)) {
1269 TAILQ_REMOVE(&msg->attributes, fingerprint, entry)do { if (((((fingerprint))->entry.tqe_next)) != __null) ((
(fingerprint))->entry.tqe_next)->entry.tqe_prev = (fingerprint
)->entry.tqe_prev; else { (&msg->attributes)->tqh_last
= (fingerprint)->entry.tqe_prev; ; } *(fingerprint)->entry
.tqe_prev = (((fingerprint))->entry.tqe_next); ; ; ; } while
(0)
;
1270 TAILQ_INSERT_TAIL(&msg->attributes, fingerprint, entry)do { (((fingerprint))->entry.tqe_next) = __null; (fingerprint
)->entry.tqe_prev = (&msg->attributes)->tqh_last
; *(&msg->attributes)->tqh_last = (fingerprint); (&
msg->attributes)->tqh_last = &(((fingerprint))->
entry.tqe_next); ; ; } while (0)
;
1271 }
1272
1273 return 0;
1274}
1275
1276// Since this sanity check is only a collection of assert statements and those
1277// assert statements are compiled out in non-debug builds, undef SANITY_CHECKS
1278// so we can avoid the warning that padding_bytes is never used in opt builds.
1279#ifdef NDEBUG
1280#undef SANITY_CHECKS1
1281#endif
1282
1283#ifdef SANITY_CHECKS1
1284static void sanity_check_encoding_stuff(nr_stun_message *msg)
1285{
1286 nr_stun_message_attribute *attr = 0;
1287 int padding_bytes;
1288 int l;
1289
1290 r_log(NR_LOG_STUN, LOG_DEBUG7, "Starting to sanity check encoding");
1291
1292 l = 0;
1293 TAILQ_FOREACH(attr, &msg->attributes, entry)for ((attr) = (((&msg->attributes))->tqh_first); (attr
); (attr) = (((attr))->entry.tqe_next))
{
1294 padding_bytes = 0;
1295 if ((attr->length % 4) != 0) {
1296 padding_bytes = 4 - (attr->length % 4);
1297 }
1298 assert(attr->length == (attr->encoding_length - (4 + padding_bytes)))(static_cast <bool> (attr->length == (attr->encoding_length
- (4 + padding_bytes))) ? void (0) : __assert_fail ("attr->length == (attr->encoding_length - (4 + padding_bytes))"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1299 assert(((void*)attr->encoding) == (msg->buffer + 20 + l))(static_cast <bool> (((void*)attr->encoding) == (msg
->buffer + 20 + l)) ? void (0) : __assert_fail ("((void*)attr->encoding) == (msg->buffer + 20 + l)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1300 l += attr->encoding_length;
1301 assert((l % 4) == 0)(static_cast <bool> ((l % 4) == 0) ? void (0) : __assert_fail
("(l % 4) == 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1302 }
1303 assert(l == msg->header.length)(static_cast <bool> (l == msg->header.length) ? void
(0) : __assert_fail ("l == msg->header.length", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1304}
1305#endif /* SANITY_CHECKS */
1306
1307
1308int
1309nr_stun_encode_message(nr_stun_message *msg)
1310{
1311 int r,_status;
1312 size_t length_offset;
1313 size_t length_offset_hold;
1314 nr_stun_attr_info *attr_info;
1315 nr_stun_message_attribute *attr;
1316 int padding_bytes;
1317
1318 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoding STUN message");
1319
1320 nr_stun_fix_attribute_ordering(msg);
1321
1322 msg->name = nr_stun_msg_type(msg->header.type);
1323 msg->length = 0;
1324 msg->header.length = 0;
1325
1326 if ((r=nr_stun_encode_htons(msg->header.type, sizeof(msg->buffer), msg->buffer, &msg->length)))
1327 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1328 if (msg->name)
1329 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded MsgType: %s", msg->name);
1330 else
1331 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded MsgType: 0x%03x", msg->header.type);
1332
1333 /* grab the offset to be used later to re-write the header length field */
1334 length_offset_hold = msg->length;
1335
1336 if ((r=nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &msg->length)))
1337 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1338
1339 if ((r=nr_stun_encode_htonl(msg->header.magic_cookie, sizeof(msg->buffer), msg->buffer, &msg->length)))
1340 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1341 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded Cookie: %08x", msg->header.magic_cookie);
1342
1343 if ((r=nr_stun_encode((UCHAR*)(&msg->header.id), sizeof(msg->header.id), sizeof(msg->buffer), msg->buffer, &msg->length)))
1344 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1345 r_dump(NR_LOG_STUN, LOG_DEBUG7, "Encoded ID", (const char*)&msg->header.id, sizeof(msg->header.id));
1346
1347 TAILQ_FOREACH(attr, &msg->attributes, entry)for ((attr) = (((&msg->attributes))->tqh_first); (attr
); (attr) = (((attr))->entry.tqe_next))
{
1348 if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
1349 r_log(NR_LOG_STUN, LOG_WARNING4, "Unrecognized attribute: 0x%04x", attr->type);
1350 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1351 }
1352
1353 attr->name = attr_info->name;
1354 attr->type_name = attr_info->codec->name;
1355 attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[msg->length];
1356
1357 if (attr_info->codec->encode != 0) {
1358 if ((r=attr_info->codec->encode(attr_info, &attr->u, msg->length, sizeof(msg->buffer), msg->buffer, &attr->encoding_length))) {
1359 r_log(NR_LOG_STUN, LOG_WARNING4, "Unable to encode %s", attr_info->name);
1360 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1361 }
1362
1363 msg->length += attr->encoding_length;
1364 attr->length = attr->encoding_length - 4; /* -4 for type and length fields */
1365
1366 if (attr_info->illegal) {
1367 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u)))
1368 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1369 }
1370
1371 attr_info->codec->print(attr_info, "Encoded", &attr->u);
1372
1373 if ((attr->length % 4) == 0) {
1374 padding_bytes = 0;
1375 }
1376 else {
1377 padding_bytes = 4 - (attr->length % 4);
1378 nr_stun_encode((UCHAR*)"\0\0\0\0", padding_bytes, sizeof(msg->buffer), msg->buffer, &msg->length);
1379 attr->encoding_length += padding_bytes;
1380 }
1381
1382 msg->header.length += attr->encoding_length;
1383 length_offset = length_offset_hold;
1384 (void)nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &length_offset);
1385 }
1386 else {
1387 r_log(NR_LOG_STUN, LOG_WARNING4, "Missing encode function for attribute: %s", attr_info->name);
1388 }
1389 }
1390
1391 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded Length: %d", msg->header.length);
1392
1393 assert(msg->length < NR_STUN_MAX_MESSAGE_SIZE)(static_cast <bool> (msg->length < 2048) ? void (
0) : __assert_fail ("msg->length < NR_STUN_MAX_MESSAGE_SIZE"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1394
1395#ifdef SANITY_CHECKS1
1396 sanity_check_encoding_stuff(msg);
1397#endif /* SANITY_CHECKS */
1398
1399 _status=0;
1400abort:
1401 return _status;
1402}
1403
1404int
1405nr_stun_decode_message(nr_stun_message *msg, int (*get_password)(void *arg, nr_stun_message *msg, Data **password), void *arg)
1406{
1407 int r,_status;
1408 int offset;
1409 int size;
1410 int padding_bytes;
1411 nr_stun_message_attribute *attr;
1412 nr_stun_attr_info *attr_info;
1413 Data *password;
1414
1415 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsing STUN message of %d bytes", msg->length);
1416
1417 if (!TAILQ_EMPTY(&msg->attributes)((&msg->attributes)->tqh_first == __null))
1418 ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1419
1420 if (sizeof(nr_stun_message_header) > msg->length) {
1421 r_log(NR_LOG_STUN, LOG_WARNING4, "Message too small");
1422 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1423 }
1424
1425 memcpy(&msg->header, msg->buffer, sizeof(msg->header));
1426 msg->header.type = ntohs(msg->header.type)__bswap_16 (msg->header.type);
1427 msg->header.length = ntohs(msg->header.length)__bswap_16 (msg->header.length);
1428 msg->header.magic_cookie = ntohl(msg->header.magic_cookie)__bswap_32 (msg->header.magic_cookie);
1429
1430 msg->name = nr_stun_msg_type(msg->header.type);
1431
1432 if (msg->name)
1433 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed MsgType: %s", msg->name);
1434 else
1435 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed MsgType: 0x%03x", msg->header.type);
1436 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed Length: %d", msg->header.length);
1437 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed Cookie: %08x", msg->header.magic_cookie);
1438 r_dump(NR_LOG_STUN, LOG_DEBUG7, "Parsed ID", (const char*)&msg->header.id, sizeof(msg->header.id));
1439
1440 if (msg->header.length + sizeof(msg->header) != msg->length) {
1441 r_log(NR_LOG_STUN, LOG_WARNING4, "Inconsistent message header length: %d/%d",
1442 msg->header.length, msg->length);
1443 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1444 }
1445
1446 size = msg->header.length;
1447
1448 if ((size % 4) != 0) {
1449 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal message size: %d", msg->header.length);
1450 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1451 }
1452
1453 offset = sizeof(msg->header);
1454
1455 while (size > 0) {
1456 r_log(NR_LOG_STUN, LOG_DEBUG7, "size = %d", size);
1457
1458 if (size < 4) {
1459 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal message length: %d", size);
1460 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1461 }
1462
1463 if ((r=nr_stun_message_attribute_create(msg, &attr)))
1464 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1465
1466 attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[offset];
1467 attr->type = ntohs(attr->encoding->type)__bswap_16 (attr->encoding->type);
1468 attr->length = ntohs(attr->encoding->length)__bswap_16 (attr->encoding->length);
1469 attr->encoding_length = attr->length + 4;
1470
1471 if ((attr->length % 4) != 0) {
1472 padding_bytes = 4 - (attr->length % 4);
1473 attr->encoding_length += padding_bytes;
1474 }
1475
1476 if ((attr->encoding_length) > (size_t)size) {
1477 r_log(NR_LOG_STUN, LOG_WARNING4, "Attribute length larger than remaining message size: %d/%d", attr->encoding_length, size);
1478 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1479 }
1480
1481 if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
1482 if (attr->type <= 0x7FFF)
1483 ++msg->comprehension_required_unknown_attributes;
1484 else
1485 ++msg->comprehension_optional_unknown_attributes;
1486 r_log(NR_LOG_STUN, LOG_INFO6, "Unrecognized attribute: 0x%04x", attr->type);
1487 }
1488 else {
1489 attr_info->name = attr_info->name;
1490 attr->type_name = attr_info->codec->name;
1491
1492 if (attr->type == NR_STUN_ATTR_MESSAGE_INTEGRITY0x0008) {
1493 if (get_password && get_password(arg, msg, &password) == 0) {
1494 if (password->len > sizeof(attr->u.message_integrity.password)) {
1495 r_log(NR_LOG_STUN, LOG_WARNING4, "Password too long: %d bytes", password->len);
1496 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1497 }
1498
1499 memcpy(attr->u.message_integrity.password, password->data, password->len);
1500 attr->u.message_integrity.passwordlen = password->len;
1501 }
1502 else {
1503 /* set to user "not found" */
1504 attr->u.message_integrity.unknown_user = 1;
1505 }
1506 }
1507 else if (attr->type == NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS0x8020) {
1508 attr->type = NR_STUN_ATTR_XOR_MAPPED_ADDRESS0x0020;
1509 r_log(NR_LOG_STUN, LOG_INFO6, "Translating obsolete XOR-MAPPED-ADDRESS type");
1510 }
1511
1512 if ((r=attr_info->codec->decode(attr_info, attr->length, msg->buffer, offset+4, msg->length, &attr->u))) {
1513 if (r == SKIP_ATTRIBUTE_DECODE-1) {
1514 r_log(NR_LOG_STUN, LOG_INFO6, "Skipping %s", attr_info->name);
1515 }
1516 else {
1517 r_log(NR_LOG_STUN, LOG_WARNING4, "Unable to parse %s", attr_info->name);
1518 }
1519
1520 attr->invalid = 1;
1521 }
1522 else {
1523 attr_info->codec->print(attr_info, "Parsed", &attr->u);
1524
1525#ifdef USE_STUN_PEDANTIC1
1526 r_log(NR_LOG_STUN, LOG_DEBUG7, "Before pedantic attr_info checks");
1527 if (attr_info->illegal) {
1528 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u))) {
1529 r_log(NR_LOG_STUN, LOG_WARNING4, "Failed pedantic attr_info checks");
1530 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1531 }
1532 }
1533 r_log(NR_LOG_STUN, LOG_DEBUG7, "After pedantic attr_info checks");
1534#endif /* USE_STUN_PEDANTIC */
1535 }
1536 }
1537
1538 offset += attr->encoding_length;
1539 size -= attr->encoding_length;
1540 }
1541
1542#ifdef SANITY_CHECKS1
1543 sanity_check_encoding_stuff(msg);
1544#endif /* SANITY_CHECKS */
1545
1546 _status=0;
1547 abort:
1548 return _status;
1549}
1550