blob: 5dc3da9c07f4c90dfb63ddfa9006f64da75fe048 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file stun/attr.c STUN Attributes
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <re_types.h>
7#include <re_mem.h>
8#include <re_mbuf.h>
9#include <re_sa.h>
10#include <re_list.h>
11#include <re_fmt.h>
12#include <re_sys.h>
13#include <re_stun.h>
14#include "stun.h"
15
16
17static int str_decode(struct mbuf *mb, char **str, size_t len)
18{
19 if (mbuf_get_left(mb) < len)
20 return EBADMSG;
21
22 return mbuf_strdup(mb, str, len);
23}
24
25
26static void destructor(void *arg)
27{
28 struct stun_attr *attr = arg;
29
30 switch (attr->type) {
31
32 case STUN_ATTR_USERNAME:
33 case STUN_ATTR_REALM:
34 case STUN_ATTR_NONCE:
35 case STUN_ATTR_SOFTWARE:
36 mem_deref(attr->v.str);
37 break;
38
39 case STUN_ATTR_ERR_CODE:
40 mem_deref(attr->v.err_code.reason);
41 break;
42
43 case STUN_ATTR_DATA:
44 case STUN_ATTR_PADDING:
45 mem_deref(attr->v.mb.buf);
46 break;
47 }
48
49 list_unlink(&attr->le);
50}
51
52
53int stun_attr_encode(struct mbuf *mb, uint16_t type, const void *v,
54 const uint8_t *tid, uint8_t padding)
55{
56 const struct stun_change_req *ch_req = v;
57 const struct stun_errcode *err_code = v;
58 const struct stun_unknown_attr *ua = v;
59 const uint32_t *num32 = v;
60 const uint16_t *num16 = v;
61 const uint8_t *num8 = v;
62 const struct mbuf *mbd = v;
63 size_t start, len;
64 uint32_t i, n;
65 int err = 0;
66
67 if (!mb || !v)
68 return EINVAL;
69
70 mb->pos += 4;
71 start = mb->pos;
72
73 switch (type) {
74
75 case STUN_ATTR_MAPPED_ADDR:
76 case STUN_ATTR_ALT_SERVER:
77 case STUN_ATTR_RESP_ORIGIN:
78 case STUN_ATTR_OTHER_ADDR:
79 tid = NULL;
80 /*@fallthrough@*/
81 case STUN_ATTR_XOR_PEER_ADDR:
82 case STUN_ATTR_XOR_RELAY_ADDR:
83 case STUN_ATTR_XOR_MAPPED_ADDR:
84 err |= stun_addr_encode(mb, v, tid);
85 break;
86
87 case STUN_ATTR_CHANGE_REQ:
88 n = (uint32_t)ch_req->ip << 2 | (uint32_t)ch_req->port << 1;
89 err |= mbuf_write_u32(mb, htonl(n));
90 break;
91
92 case STUN_ATTR_USERNAME:
93 case STUN_ATTR_REALM:
94 case STUN_ATTR_NONCE:
95 case STUN_ATTR_SOFTWARE:
96 err |= mbuf_write_str(mb, v);
97 break;
98
99 case STUN_ATTR_MSG_INTEGRITY:
100 err |= mbuf_write_mem(mb, v, 20);
101 break;
102
103 case STUN_ATTR_ERR_CODE:
104 err |= mbuf_write_u16(mb, 0x00);
105 err |= mbuf_write_u8(mb, err_code->code/100);
106 err |= mbuf_write_u8(mb, err_code->code%100);
107 err |= mbuf_write_str(mb, err_code->reason);
108 break;
109
110 case STUN_ATTR_UNKNOWN_ATTR:
111 for (i=0; i<ua->typec; i++)
112 err |= mbuf_write_u16(mb, htons(ua->typev[i]));
113 break;
114
115 case STUN_ATTR_CHANNEL_NUMBER:
116 case STUN_ATTR_RESP_PORT:
117 err |= mbuf_write_u16(mb, htons(*num16));
118 err |= mbuf_write_u16(mb, 0x0000);
119 break;
120
121 case STUN_ATTR_LIFETIME:
122 case STUN_ATTR_PRIORITY:
123 case STUN_ATTR_FINGERPRINT:
124 err |= mbuf_write_u32(mb, htonl(*num32));
125 break;
126
127 case STUN_ATTR_DATA:
128 case STUN_ATTR_PADDING:
129 if (mb == mbd) {
130 mb->pos = mb->end;
131 break;
132 }
133 err |= mbuf_write_mem(mb, mbuf_buf(mbd), mbuf_get_left(mbd));
134 break;
135
136 case STUN_ATTR_REQ_ADDR_FAMILY:
137 case STUN_ATTR_REQ_TRANSPORT:
138 err |= mbuf_write_u8(mb, *num8);
139 err |= mbuf_write_u8(mb, 0x00);
140 err |= mbuf_write_u16(mb, 0x0000);
141 break;
142
143 case STUN_ATTR_EVEN_PORT:
144 err |= mbuf_write_u8(mb, ((struct stun_even_port *)v)->r << 7);
145 break;
146
147 case STUN_ATTR_DONT_FRAGMENT:
148 case STUN_ATTR_USE_CAND:
149 /* no value */
150 break;
151
152 case STUN_ATTR_RSV_TOKEN:
153 case STUN_ATTR_CONTROLLED:
154 case STUN_ATTR_CONTROLLING:
155 err |= mbuf_write_u64(mb, sys_htonll(*(uint64_t *)v));
156 break;
157
158 default:
159 err = EINVAL;
160 break;
161 }
162
163 /* header */
164 len = mb->pos - start;
165
166 mb->pos = start - 4;
167 err |= mbuf_write_u16(mb, htons(type));
168 err |= mbuf_write_u16(mb, htons(len));
169 mb->pos += len;
170
171 /* padding */
172 while ((mb->pos - start) & 0x03)
173 err |= mbuf_write_u8(mb, padding);
174
175 return err;
176}
177
178
179int stun_attr_decode(struct stun_attr **attrp, struct mbuf *mb,
180 const uint8_t *tid, struct stun_unknown_attr *ua)
181{
182 struct stun_attr *attr;
183 size_t start, len;
184 uint32_t i, n;
185 int err = 0;
186
187 if (!mb || !attrp)
188 return EINVAL;
189
190 if (mbuf_get_left(mb) < 4)
191 return EBADMSG;
192
193 attr = mem_zalloc(sizeof(*attr), destructor);
194 if (!attr)
195 return ENOMEM;
196
197 attr->type = ntohs(mbuf_read_u16(mb));
198 len = ntohs(mbuf_read_u16(mb));
199
200 if (mbuf_get_left(mb) < len)
201 goto badmsg;
202
203 start = mb->pos;
204
205 switch (attr->type) {
206
207 case STUN_ATTR_MAPPED_ADDR:
208 case STUN_ATTR_ALT_SERVER:
209 case STUN_ATTR_RESP_ORIGIN:
210 case STUN_ATTR_OTHER_ADDR:
211 tid = NULL;
212 /*@fallthrough@*/
213 case STUN_ATTR_XOR_PEER_ADDR:
214 case STUN_ATTR_XOR_RELAY_ADDR:
215 case STUN_ATTR_XOR_MAPPED_ADDR:
216 err = stun_addr_decode(mb, &attr->v.sa, tid);
217 break;
218
219 case STUN_ATTR_CHANGE_REQ:
220 if (len != 4)
221 goto badmsg;
222
223 n = ntohl(mbuf_read_u32(mb));
224 attr->v.change_req.ip = (n >> 2) & 0x1;
225 attr->v.change_req.port = (n >> 1) & 0x1;
226 break;
227
228 case STUN_ATTR_USERNAME:
229 case STUN_ATTR_REALM:
230 case STUN_ATTR_NONCE:
231 case STUN_ATTR_SOFTWARE:
232 err = str_decode(mb, &attr->v.str, len);
233 break;
234
235 case STUN_ATTR_MSG_INTEGRITY:
236 if (len != 20)
237 goto badmsg;
238
239 err = mbuf_read_mem(mb, attr->v.msg_integrity, 20);
240 break;
241
242 case STUN_ATTR_ERR_CODE:
243 if (len < 4)
244 goto badmsg;
245
246 mb->pos += 2;
247 attr->v.err_code.code = (mbuf_read_u8(mb) & 0x7) * 100;
248 attr->v.err_code.code += mbuf_read_u8(mb);
249 err = str_decode(mb, &attr->v.err_code.reason, len - 4);
250 break;
251
252 case STUN_ATTR_UNKNOWN_ATTR:
253 for (i=0; i<len/2; i++) {
254 uint16_t type = ntohs(mbuf_read_u16(mb));
255
256 if (i >= ARRAY_SIZE(attr->v.unknown_attr.typev))
257 continue;
258
259 attr->v.unknown_attr.typev[i] = type;
260 attr->v.unknown_attr.typec++;
261 }
262 break;
263
264 case STUN_ATTR_CHANNEL_NUMBER:
265 case STUN_ATTR_RESP_PORT:
266 if (len < 2)
267 goto badmsg;
268
269 attr->v.uint16 = ntohs(mbuf_read_u16(mb));
270 break;
271
272 case STUN_ATTR_LIFETIME:
273 case STUN_ATTR_PRIORITY:
274 case STUN_ATTR_FINGERPRINT:
275 if (len != 4)
276 goto badmsg;
277
278 attr->v.uint32 = ntohl(mbuf_read_u32(mb));
279 break;
280
281 case STUN_ATTR_DATA:
282 case STUN_ATTR_PADDING:
283 attr->v.mb.buf = mem_ref(mb->buf);
284 attr->v.mb.size = mb->size;
285 attr->v.mb.pos = mb->pos;
286 attr->v.mb.end = mb->pos + len;
287 mb->pos += len;
288 break;
289
290 case STUN_ATTR_REQ_ADDR_FAMILY:
291 case STUN_ATTR_REQ_TRANSPORT:
292 if (len < 1)
293 goto badmsg;
294
295 attr->v.uint8 = mbuf_read_u8(mb);
296 break;
297
298 case STUN_ATTR_EVEN_PORT:
299 if (len < 1)
300 goto badmsg;
301
302 attr->v.even_port.r = (mbuf_read_u8(mb) >> 7) & 0x1;
303 break;
304
305 case STUN_ATTR_DONT_FRAGMENT:
306 case STUN_ATTR_USE_CAND:
307 if (len > 0)
308 goto badmsg;
309
310 /* no value */
311 break;
312
313 case STUN_ATTR_RSV_TOKEN:
314 case STUN_ATTR_CONTROLLING:
315 case STUN_ATTR_CONTROLLED:
316 if (len != 8)
317 goto badmsg;
318
319 attr->v.uint64 = sys_ntohll(mbuf_read_u64(mb));
320 break;
321
322 default:
323 mb->pos += len;
324
325 if (attr->type >= 0x8000)
326 break;
327
328 if (ua && ua->typec < ARRAY_SIZE(ua->typev))
329 ua->typev[ua->typec++] = attr->type;
330 break;
331 }
332
333 if (err)
334 goto error;
335
336 /* padding */
337 while (((mb->pos - start) & 0x03) && mbuf_get_left(mb))
338 ++mb->pos;
339
340 *attrp = attr;
341
342 return 0;
343
344 badmsg:
345 err = EBADMSG;
346 error:
347 mem_deref(attr);
348
349 return err;
350}
351
352
353/**
354 * Get the name of a STUN attribute
355 *
356 * @param type STUN attribute type
357 *
358 * @return String with attribute name
359 */
360const char *stun_attr_name(uint16_t type)
361{
362 switch (type) {
363
364 case STUN_ATTR_MAPPED_ADDR: return "MAPPED-ADDRESS";
365 case STUN_ATTR_CHANGE_REQ: return "CHANGE-REQUEST";
366 case STUN_ATTR_USERNAME: return "USERNAME";
367 case STUN_ATTR_MSG_INTEGRITY: return "MESSAGE-INTEGRITY";
368 case STUN_ATTR_ERR_CODE: return "ERROR-CODE";
369 case STUN_ATTR_UNKNOWN_ATTR: return "UNKNOWN-ATTRIBUTE";
370 case STUN_ATTR_CHANNEL_NUMBER: return "CHANNEL-NUMBER";
371 case STUN_ATTR_LIFETIME: return "LIFETIME";
372 case STUN_ATTR_XOR_PEER_ADDR: return "XOR-PEER-ADDRESS";
373 case STUN_ATTR_DATA: return "DATA";
374 case STUN_ATTR_REALM: return "REALM";
375 case STUN_ATTR_NONCE: return "NONCE";
376 case STUN_ATTR_XOR_RELAY_ADDR: return "XOR-RELAYED-ADDRESS";
377 case STUN_ATTR_REQ_ADDR_FAMILY: return "REQUESTED-ADDRESS-FAMILY";
378 case STUN_ATTR_EVEN_PORT: return "EVEN_PORT";
379 case STUN_ATTR_REQ_TRANSPORT: return "REQUESTED-TRANSPORT";
380 case STUN_ATTR_DONT_FRAGMENT: return "DONT-FRAGMENT";
381 case STUN_ATTR_XOR_MAPPED_ADDR: return "XOR-MAPPED-ADDRESS";
382 case STUN_ATTR_RSV_TOKEN: return "RESERVATION-TOKEN";
383 case STUN_ATTR_PRIORITY: return "PRIORITY";
384 case STUN_ATTR_USE_CAND: return "USE-CANDIDATE";
385 case STUN_ATTR_PADDING: return "PADDING";
386 case STUN_ATTR_RESP_PORT: return "RESPONSE-PORT";
387 case STUN_ATTR_SOFTWARE: return "SOFTWARE";
388 case STUN_ATTR_ALT_SERVER: return "ALTERNATE-SERVER";
389 case STUN_ATTR_FINGERPRINT: return "FINGERPRINT";
390 case STUN_ATTR_CONTROLLING: return "ICE-CONTROLLING";
391 case STUN_ATTR_CONTROLLED: return "ICE-CONTROLLED";
392 case STUN_ATTR_RESP_ORIGIN: return "RESPONSE-ORIGIN";
393 case STUN_ATTR_OTHER_ADDR: return "OTHER-ADDR";
394 default: return "???";
395 }
396}
397
398
399void stun_attr_dump(const struct stun_attr *a)
400{
401 uint32_t i;
402 size_t len;
403
404 if (!a)
405 return;
406
407 (void)re_printf(" %-25s", stun_attr_name(a->type));
408
409 switch (a->type) {
410
411 case STUN_ATTR_MAPPED_ADDR:
412 case STUN_ATTR_XOR_PEER_ADDR:
413 case STUN_ATTR_XOR_RELAY_ADDR:
414 case STUN_ATTR_XOR_MAPPED_ADDR:
415 case STUN_ATTR_ALT_SERVER:
416 case STUN_ATTR_RESP_ORIGIN:
417 case STUN_ATTR_OTHER_ADDR:
418 (void)re_printf("%J", &a->v.sa);
419 break;
420
421 case STUN_ATTR_CHANGE_REQ:
422 (void)re_printf("ip=%u port=%u", a->v.change_req.ip,
423 a->v.change_req.port);
424 break;
425
426 case STUN_ATTR_USERNAME:
427 case STUN_ATTR_REALM:
428 case STUN_ATTR_NONCE:
429 case STUN_ATTR_SOFTWARE:
430 (void)re_printf("%s", a->v.str);
431 break;
432
433 case STUN_ATTR_MSG_INTEGRITY:
434 (void)re_printf("%w", a->v.msg_integrity,
435 sizeof(a->v.msg_integrity));
436 break;
437
438 case STUN_ATTR_ERR_CODE:
439 (void)re_printf("%u %s", a->v.err_code.code,
440 a->v.err_code.reason);
441 break;
442
443 case STUN_ATTR_UNKNOWN_ATTR:
444 for (i=0; i<a->v.unknown_attr.typec; i++)
445 (void)re_printf("0x%04x ", a->v.unknown_attr.typev[i]);
446 break;
447
448 case STUN_ATTR_CHANNEL_NUMBER:
449 (void)re_printf("0x%04x", a->v.uint16);
450 break;
451
452 case STUN_ATTR_LIFETIME:
453 case STUN_ATTR_PRIORITY:
454 (void)re_printf("%u", a->v.uint32);
455 break;
456
457 case STUN_ATTR_DATA:
458 case STUN_ATTR_PADDING:
459 len = min(mbuf_get_left(&a->v.mb), 16);
460 (void)re_printf("%w%s (%zu bytes)", mbuf_buf(&a->v.mb), len,
461 mbuf_get_left(&a->v.mb) > 16 ? "..." : "",
462 mbuf_get_left(&a->v.mb));
463 break;
464
465 case STUN_ATTR_REQ_ADDR_FAMILY:
466 case STUN_ATTR_REQ_TRANSPORT:
467 (void)re_printf("%u", a->v.uint8);
468 break;
469
470 case STUN_ATTR_EVEN_PORT:
471 (void)re_printf("r=%u", a->v.even_port.r);
472 break;
473
474 case STUN_ATTR_DONT_FRAGMENT:
475 case STUN_ATTR_USE_CAND:
476 /* no value */
477 break;
478
479 case STUN_ATTR_RSV_TOKEN:
480 (void)re_printf("0x%016llx", a->v.rsv_token);
481 break;
482
483 case STUN_ATTR_RESP_PORT:
484 (void)re_printf("%u", a->v.uint16);
485 break;
486
487 case STUN_ATTR_FINGERPRINT:
488 (void)re_printf("0x%08x", a->v.fingerprint);
489 break;
490
491 case STUN_ATTR_CONTROLLING:
492 case STUN_ATTR_CONTROLLED:
493 (void)re_printf("%llu", a->v.uint64);
494 break;
495
496 default:
497 (void)re_printf("???");
498 break;
499 }
500
501 (void)re_printf("\n");
502}