Bug Summary

File:root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.cpp
Warning:line 1460, 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_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-10-17-231001-351276-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 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 },
1193 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_FINGERPRINT, "FINGERPRINT", nr_stun_attr_codec_fingerprint, 0){ (0x8028), ("FINGERPRINT"), &(nr_stun_attr_codec_fingerprint
), 0 },
1194 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 },
1195 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 },
1196 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 },
1197 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 },
1198 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
},
1199 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 },
1200 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
},
1201 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 },
1202
1203#ifdef USE_ICE1
1204 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 },
1205 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 },
1206 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_PRIORITY, "PRIORITY", nr_stun_attr_codec_UINT4, 0){ (0x0024), ("PRIORITY"), &(nr_stun_attr_codec_UINT4), 0 }
,
1207 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 },
1208#endif
1209
1210#ifdef USE_TURN1
1211 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_DATA, "DATA", nr_stun_attr_codec_data, 0){ (0x0013), ("DATA"), &(nr_stun_attr_codec_data), 0 },
1212 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_LIFETIME, "LIFETIME", nr_stun_attr_codec_UINT4, 0){ (0x000d), ("LIFETIME"), &(nr_stun_attr_codec_UINT4), 0 }
,
1213 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 },
1214 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 },
1215 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 },
1216 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_BANDWIDTH, "BANDWIDTH", nr_stun_attr_codec_UINT4, 0){ (0x0010), ("BANDWIDTH"), &(nr_stun_attr_codec_UINT4), 0
},
1217#endif /* USE_TURN */
1218
1219 /* for backwards compatibilty */
1220 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 },
1221#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE1
1222 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_RESPONSE_ADDRESS, "RESPONSE-ADDRESS"){ (0x0002), ("RESPONSE-ADDRESS"), &nr_stun_attr_codec_noop
, 0 },
1223 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_SOURCE_ADDRESS, "SOURCE-ADDRESS"){ (0x0004), ("SOURCE-ADDRESS"), &nr_stun_attr_codec_noop,
0 },
1224 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_CHANGED_ADDRESS, "CHANGED-ADDRESS"){ (0x0005), ("CHANGED-ADDRESS"), &nr_stun_attr_codec_noop
, 0 },
1225 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_PASSWORD, "PASSWORD"){ (0x0007), ("PASSWORD"), &nr_stun_attr_codec_noop, 0 },
1226#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
1227};
1228
1229
1230int
1231nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info)
1232{
1233 int _status;
1234 size_t i;
1235
1236 *info = 0;
1237 for (i = 0; i < sizeof(attrs)/sizeof(*attrs); ++i) {
1238 if (type == attrs[i].type) {
1239 *info = &attrs[i];
1240 break;
1241 }
1242 }
1243
1244 if (*info == 0)
1245 ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1246
1247 _status=0;
1248 abort:
1249 return(_status);
1250}
1251
1252int
1253nr_stun_fix_attribute_ordering(nr_stun_message *msg)
1254{
1255 nr_stun_message_attribute *message_integrity;
1256 nr_stun_message_attribute *fingerprint;
1257
1258 /* 2nd to the last */
1259 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY0x0008, &message_integrity)) {
1260 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)
;
1261 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)
;
1262 }
1263
1264 /* last */
1265 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT0x8028, &fingerprint)) {
1266 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)
;
1267 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)
;
1268 }
1269
1270 return 0;
1271}
1272
1273// Since this sanity check is only a collection of assert statements and those
1274// assert statements are compiled out in non-debug builds, undef SANITY_CHECKS
1275// so we can avoid the warning that padding_bytes is never used in opt builds.
1276#ifdef NDEBUG
1277#undef SANITY_CHECKS1
1278#endif
1279
1280#ifdef SANITY_CHECKS1
1281static void sanity_check_encoding_stuff(nr_stun_message *msg)
1282{
1283 nr_stun_message_attribute *attr = 0;
1284 int padding_bytes;
1285 int l;
1286
1287 r_log(NR_LOG_STUN, LOG_DEBUG7, "Starting to sanity check encoding");
1288
1289 l = 0;
1290 TAILQ_FOREACH(attr, &msg->attributes, entry)for ((attr) = (((&msg->attributes))->tqh_first); (attr
); (attr) = (((attr))->entry.tqe_next))
{
1291 padding_bytes = 0;
1292 if ((attr->length % 4) != 0) {
1293 padding_bytes = 4 - (attr->length % 4);
1294 }
1295 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__
))
;
1296 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__
))
;
1297 l += attr->encoding_length;
1298 assert((l % 4) == 0)(static_cast <bool> ((l % 4) == 0) ? void (0) : __assert_fail
("(l % 4) == 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1299 }
1300 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__))
;
1301}
1302#endif /* SANITY_CHECKS */
1303
1304
1305int
1306nr_stun_encode_message(nr_stun_message *msg)
1307{
1308 int r,_status;
1309 size_t length_offset;
1310 size_t length_offset_hold;
1311 nr_stun_attr_info *attr_info;
1312 nr_stun_message_attribute *attr;
1313 int padding_bytes;
1314
1315 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoding STUN message");
1316
1317 nr_stun_fix_attribute_ordering(msg);
1318
1319 msg->name = nr_stun_msg_type(msg->header.type);
1320 msg->length = 0;
1321 msg->header.length = 0;
1322
1323 if ((r=nr_stun_encode_htons(msg->header.type, sizeof(msg->buffer), msg->buffer, &msg->length)))
1324 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1325 if (msg->name)
1326 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded MsgType: %s", msg->name);
1327 else
1328 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded MsgType: 0x%03x", msg->header.type);
1329
1330 /* grab the offset to be used later to re-write the header length field */
1331 length_offset_hold = msg->length;
1332
1333 if ((r=nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &msg->length)))
1334 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1335
1336 if ((r=nr_stun_encode_htonl(msg->header.magic_cookie, 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 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded Cookie: %08x", msg->header.magic_cookie);
1339
1340 if ((r=nr_stun_encode((UCHAR*)(&msg->header.id), sizeof(msg->header.id), sizeof(msg->buffer), msg->buffer, &msg->length)))
1341 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1342 r_dump(NR_LOG_STUN, LOG_DEBUG7, "Encoded ID", (const char*)&msg->header.id, sizeof(msg->header.id));
1343
1344 TAILQ_FOREACH(attr, &msg->attributes, entry)for ((attr) = (((&msg->attributes))->tqh_first); (attr
); (attr) = (((attr))->entry.tqe_next))
{
1345 if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
1346 r_log(NR_LOG_STUN, LOG_WARNING4, "Unrecognized attribute: 0x%04x", attr->type);
1347 ABORT(R_INTERNAL)do { int _r=3; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1348 }
1349
1350 attr->name = attr_info->name;
1351 attr->type_name = attr_info->codec->name;
1352 attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[msg->length];
1353
1354 if (attr_info->codec->encode != 0) {
1355 if ((r=attr_info->codec->encode(attr_info, &attr->u, msg->length, sizeof(msg->buffer), msg->buffer, &attr->encoding_length))) {
1356 r_log(NR_LOG_STUN, LOG_WARNING4, "Unable to encode %s", attr_info->name);
1357 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1358 }
1359
1360 msg->length += attr->encoding_length;
1361 attr->length = attr->encoding_length - 4; /* -4 for type and length fields */
1362
1363 if (attr_info->illegal) {
1364 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u)))
1365 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1366 }
1367
1368 attr_info->codec->print(attr_info, "Encoded", &attr->u);
1369
1370 if ((attr->length % 4) == 0) {
1371 padding_bytes = 0;
1372 }
1373 else {
1374 padding_bytes = 4 - (attr->length % 4);
1375 nr_stun_encode((UCHAR*)"\0\0\0\0", padding_bytes, sizeof(msg->buffer), msg->buffer, &msg->length);
1376 attr->encoding_length += padding_bytes;
1377 }
1378
1379 msg->header.length += attr->encoding_length;
1380 length_offset = length_offset_hold;
1381 (void)nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &length_offset);
1382 }
1383 else {
1384 r_log(NR_LOG_STUN, LOG_WARNING4, "Missing encode function for attribute: %s", attr_info->name);
1385 }
1386 }
1387
1388 r_log(NR_LOG_STUN, LOG_DEBUG7, "Encoded Length: %d", msg->header.length);
1389
1390 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__
))
;
1391
1392#ifdef SANITY_CHECKS1
1393 sanity_check_encoding_stuff(msg);
1394#endif /* SANITY_CHECKS */
1395
1396 _status=0;
1397abort:
1398 return _status;
1399}
1400
1401int
1402nr_stun_decode_message(nr_stun_message *msg, int (*get_password)(void *arg, nr_stun_message *msg, Data **password), void *arg)
1403{
1404 int r,_status;
1405 int offset;
1406 int size;
1407 int padding_bytes;
1408 nr_stun_message_attribute *attr;
1409 nr_stun_attr_info *attr_info;
1410 Data *password;
1411
1412 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsing STUN message of %d bytes", msg->length);
1413
1414 if (!TAILQ_EMPTY(&msg->attributes)((&msg->attributes)->tqh_first == __null))
1415 ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1416
1417 if (sizeof(nr_stun_message_header) > msg->length) {
1418 r_log(NR_LOG_STUN, LOG_WARNING4, "Message too small");
1419 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1420 }
1421
1422 memcpy(&msg->header, msg->buffer, sizeof(msg->header));
1423 msg->header.type = ntohs(msg->header.type)__bswap_16 (msg->header.type);
1424 msg->header.length = ntohs(msg->header.length)__bswap_16 (msg->header.length);
1425 msg->header.magic_cookie = ntohl(msg->header.magic_cookie)__bswap_32 (msg->header.magic_cookie);
1426
1427 msg->name = nr_stun_msg_type(msg->header.type);
1428
1429 if (msg->name)
1430 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed MsgType: %s", msg->name);
1431 else
1432 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed MsgType: 0x%03x", msg->header.type);
1433 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed Length: %d", msg->header.length);
1434 r_log(NR_LOG_STUN, LOG_DEBUG7, "Parsed Cookie: %08x", msg->header.magic_cookie);
1435 r_dump(NR_LOG_STUN, LOG_DEBUG7, "Parsed ID", (const char*)&msg->header.id, sizeof(msg->header.id));
1436
1437 if (msg->header.length + sizeof(msg->header) != msg->length) {
1438 r_log(NR_LOG_STUN, LOG_WARNING4, "Inconsistent message header length: %d/%d",
1439 msg->header.length, msg->length);
1440 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1441 }
1442
1443 size = msg->header.length;
1444
1445 if ((size % 4) != 0) {
1446 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal message size: %d", msg->header.length);
1447 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1448 }
1449
1450 offset = sizeof(msg->header);
1451
1452 while (size > 0) {
1453 r_log(NR_LOG_STUN, LOG_DEBUG7, "size = %d", size);
1454
1455 if (size < 4) {
1456 r_log(NR_LOG_STUN, LOG_WARNING4, "Illegal message length: %d", size);
1457 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1458 }
1459
1460 if ((r=nr_stun_message_attribute_create(msg, &attr)))
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r'
1461 ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1462
1463 attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[offset];
1464 attr->type = ntohs(attr->encoding->type)__bswap_16 (attr->encoding->type);
1465 attr->length = ntohs(attr->encoding->length)__bswap_16 (attr->encoding->length);
1466 attr->encoding_length = attr->length + 4;
1467
1468 if ((attr->length % 4) != 0) {
1469 padding_bytes = 4 - (attr->length % 4);
1470 attr->encoding_length += padding_bytes;
1471 }
1472
1473 if ((attr->encoding_length) > (size_t)size) {
1474 r_log(NR_LOG_STUN, LOG_WARNING4, "Attribute length larger than remaining message size: %d/%d", attr->encoding_length, size);
1475 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1476 }
1477
1478 if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
1479 if (attr->type <= 0x7FFF)
1480 ++msg->comprehension_required_unknown_attributes;
1481 else
1482 ++msg->comprehension_optional_unknown_attributes;
1483 r_log(NR_LOG_STUN, LOG_INFO6, "Unrecognized attribute: 0x%04x", attr->type);
1484 }
1485 else {
1486 attr_info->name = attr_info->name;
1487 attr->type_name = attr_info->codec->name;
1488
1489 if (attr->type == NR_STUN_ATTR_MESSAGE_INTEGRITY0x0008) {
1490 if (get_password && get_password(arg, msg, &password) == 0) {
1491 if (password->len > sizeof(attr->u.message_integrity.password)) {
1492 r_log(NR_LOG_STUN, LOG_WARNING4, "Password too long: %d bytes", password->len);
1493 ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while
(0)
;
1494 }
1495
1496 memcpy(attr->u.message_integrity.password, password->data, password->len);
1497 attr->u.message_integrity.passwordlen = password->len;
1498 }
1499 else {
1500 /* set to user "not found" */
1501 attr->u.message_integrity.unknown_user = 1;
1502 }
1503 }
1504 else if (attr->type == NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS0x8020) {
1505 attr->type = NR_STUN_ATTR_XOR_MAPPED_ADDRESS0x0020;
1506 r_log(NR_LOG_STUN, LOG_INFO6, "Translating obsolete XOR-MAPPED-ADDRESS type");
1507 }
1508
1509 if ((r=attr_info->codec->decode(attr_info, attr->length, msg->buffer, offset+4, msg->length, &attr->u))) {
1510 if (r == SKIP_ATTRIBUTE_DECODE-1) {
1511 r_log(NR_LOG_STUN, LOG_INFO6, "Skipping %s", attr_info->name);
1512 }
1513 else {
1514 r_log(NR_LOG_STUN, LOG_WARNING4, "Unable to parse %s", attr_info->name);
1515 }
1516
1517 attr->invalid = 1;
1518 }
1519 else {
1520 attr_info->codec->print(attr_info, "Parsed", &attr->u);
1521
1522#ifdef USE_STUN_PEDANTIC1
1523 r_log(NR_LOG_STUN, LOG_DEBUG7, "Before pedantic attr_info checks");
1524 if (attr_info->illegal) {
1525 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u))) {
1526 r_log(NR_LOG_STUN, LOG_WARNING4, "Failed pedantic attr_info checks");
1527 ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while(
0)
;
1528 }
1529 }
1530 r_log(NR_LOG_STUN, LOG_DEBUG7, "After pedantic attr_info checks");
1531#endif /* USE_STUN_PEDANTIC */
1532 }
1533 }
1534
1535 offset += attr->encoding_length;
1536 size -= attr->encoding_length;
1537 }
1538
1539#ifdef SANITY_CHECKS1
1540 sanity_check_encoding_stuff(msg);
1541#endif /* SANITY_CHECKS */
1542
1543 _status=0;
1544 abort:
1545 return _status;
1546}
1547