1
/* $Id: stun.c 2938 2009-10-11 05:06:43Z bennylp $ */
3
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
* Additional permission under GNU GPL version 3 section 7:
22
* If you modify this program, or any covered work, by linking or
23
* combining it with the OpenSSL project's OpenSSL library (or a
24
* modified version of that library), containing parts covered by the
25
* terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
26
* grants you additional permission to convey the resulting work.
27
* Corresponding Source for a non-source form of such a combination
28
* shall include the source code for the parts of OpenSSL used as well
29
* as that of the covered work.
33
#define THIS_FILE "stun.c"
35
static pj_stun_msg* create1(pj_pool_t*);
36
static int verify1(pj_stun_msg*);
37
static int verify2(pj_stun_msg*);
38
static int verify5(pj_stun_msg*);
45
pj_stun_msg* (*create)(pj_pool_t*);
46
pj_status_t expected_status;
47
int (*verify)(pj_stun_msg*);
51
"Invalid message type",
52
"\x11\x01\x00\x00\x21\x12\xa4\x42"
53
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
56
PJNATH_EINSTUNMSGTYPE,
60
"Short message (1) (partial header)",
68
"Short message (2) (partial header)",
69
"\x00\x01\x00\x00\x21\x12\xa4\x42"
70
"\x00\x00\x00\x00\x00\x00\x00\x00",
77
"Short message (3), (missing attribute)",
78
"\x00\x01\x00\x08\x21\x12\xa4\x42"
79
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
86
"Short message (4), (partial attribute header)",
87
"\x00\x01\x00\x08\x21\x12\xa4\x42"
88
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
96
"Short message (5), (partial attribute header)",
97
"\x00\x01\x00\x08\x21\x12\xa4\x42"
98
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
102
PJNATH_EINSTUNMSGLEN,
106
"Short message (6), (partial attribute header)",
107
"\x00\x01\x00\x08\x21\x12\xa4\x42"
108
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
112
PJNATH_EINSTUNMSGLEN,
116
"Short message (7), (partial attribute body)",
117
"\x00\x01\x00\x08\x21\x12\xa4\x42"
118
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
119
"\x80\x28\x00\x04\x00\x00\x00",
122
PJNATH_EINSTUNMSGLEN,
126
"Message length in header is too long",
127
"\x00\x01\xff\xff\x21\x12\xa4\x42"
128
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
129
"\x80\x28\x00\x04\x00\x00\x00",
132
PJNATH_EINSTUNMSGLEN,
136
"Message length in header is shorter",
137
"\x00\x01\x00\x04\x21\x12\xa4\x42"
138
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
139
"\x80\x28\x00\x04\x00\x00\x00\x00",
142
PJNATH_EINSTUNMSGLEN,
147
"\x00\x01\x00\x08\x00\x12\xa4\x42"
148
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
149
"\x80\x28\x00\x04\x00\x00\x00\x00",
156
"Character beyond message",
157
"\x00\x01\x00\x08\x21\x12\xa4\x42"
158
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
159
"\x80\x28\x00\x04\x00\x00\x00\x00\x0a",
162
PJNATH_EINSTUNMSGLEN,
166
"Respond unknown mandatory attribute with 420 and "
167
"UNKNOWN-ATTRIBUTES attribute",
175
"Unknown but non-mandatory should be okay",
176
"\x00\x01\x00\x08\x21\x12\xa4\x42"
177
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
178
"\x80\xff\x00\x03\x00\x00\x00\x00",
185
"String attr length larger than message",
186
"\x00\x01\x00\x08\x00\x12\xa4\x42"
187
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
188
"\x00\x06\x00\xff\x00\x00\x00\x00",
191
PJNATH_ESTUNINATTRLEN,
195
"Attribute other than FINGERPRINT after MESSAGE-INTEGRITY is allowed",
196
"\x00\x01\x00\x20\x21\x12\xa4\x42"
197
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
198
"\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
199
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
200
"\x80\x24\x00\x04\x00\x00\x00\x00", // REFRESH-INTERVAL
207
"Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed",
208
"\x00\x01\x00\x28\x21\x12\xa4\x42"
209
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
210
"\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
211
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
212
"\x80\x24\x00\x04\x00\x00\x00\x00" // REFRESH-INTERVAL
213
"\x80\x28\x00\x04\xc7\xde\xdd\x65", // FINGERPRINT
220
"Attribute past FINGERPRINT is not allowed",
221
"\x00\x01\x00\x10\x21\x12\xa4\x42"
222
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
223
"\x80\x28\x00\x04\x00\x00\x00\x00"
224
"\x80\x24\x00\x04\x00\x00\x00\x00",
227
PJNATH_ESTUNFINGERPOS,
232
static const char *err(pj_status_t status)
234
static char errmsg[PJ_ERR_MSG_SIZE];
235
pj_strerror(status, errmsg, sizeof(errmsg));
239
static const pj_str_t USERNAME = {"user", 4};
240
static const pj_str_t PASSWORD = {"password", 8};
242
static int decode_test(void)
248
pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL);
250
PJ_LOG(3,(THIS_FILE, " STUN decode test"));
252
for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
253
struct test *t = &tests[i];
254
pj_stun_msg *msg, *msg2;
255
pj_uint8_t buf[1500];
260
PJ_LOG(3,(THIS_FILE, " %s", t->title));
263
status = pj_stun_msg_decode(pool, (pj_uint8_t*)t->pdu, t->pdu_len,
264
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
267
/* Check expected decode result */
268
if (t->expected_status != status) {
269
PJ_LOG(1,(THIS_FILE, " expecting status %d, got %d",
270
t->expected_status, status));
276
msg = t->create(pool);
280
if (status != PJ_SUCCESS)
283
/* Try to encode message */
284
pj_stun_create_key(pool, &key, NULL, &USERNAME, PJ_STUN_PASSWD_PLAIN, &PASSWORD);
285
status = pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
286
if (status != PJ_SUCCESS) {
287
PJ_LOG(1,(THIS_FILE, " encode error: %s", err(status)));
292
/* Try to decode it once more */
293
status = pj_stun_msg_decode(pool, buf, len,
294
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
296
if (status != PJ_SUCCESS) {
297
PJ_LOG(1,(THIS_FILE, " subsequent decoding failed: %s", err(status)));
312
pj_pool_release(pool);
314
PJ_LOG(3,(THIS_FILE, "...success!"));
318
/* Create 420 response */
319
static pj_stun_msg* create1(pj_pool_t *pool)
321
char *pdu = "\x00\x01\x00\x08\x21\x12\xa4\x42"
322
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
323
"\x00\xff\x00\x04\x00\x00\x00\x00";
324
unsigned pdu_len = 28;
325
pj_stun_msg *msg, *res;
328
status = pj_stun_msg_decode(pool, (pj_uint8_t*)pdu, pdu_len,
329
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
331
pj_assert(status != PJ_SUCCESS);
332
pj_assert(res != NULL);
337
/* Error response MUST have ERROR-CODE attribute */
338
/* 420 response MUST contain UNKNOWN-ATTRIBUTES */
339
static int verify1(pj_stun_msg *msg)
341
pj_stun_errcode_attr *aerr;
342
pj_stun_unknown_attr *aunk;
344
if (!PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) {
345
PJ_LOG(1,(THIS_FILE, " expecting error message"));
349
aerr = (pj_stun_errcode_attr*)
350
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
352
PJ_LOG(1,(THIS_FILE, " missing ERROR-CODE attribute"));
356
if (aerr->err_code != 420) {
357
PJ_LOG(1,(THIS_FILE, " expecting 420 error"));
361
aunk = (pj_stun_unknown_attr*)
362
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
364
PJ_LOG(1,(THIS_FILE, " missing UNKNOWN-ATTRIBUTE attribute"));
368
if (aunk->attr_count != 1) {
369
PJ_LOG(1,(THIS_FILE, " expecting one unknown attribute"));
373
if (aunk->attrs[0] != 0xff) {
374
PJ_LOG(1,(THIS_FILE, " expecting 0xff as unknown attribute"));
381
/* Attribute count should be zero since unknown attribute is not parsed */
382
static int verify2(pj_stun_msg *msg)
384
pj_stun_binary_attr *bin_attr;
386
if (msg->attr_count != 1) {
387
PJ_LOG(1,(THIS_FILE, " expecting one attribute count"));
391
bin_attr = (pj_stun_binary_attr*)msg->attr[0];
392
if (bin_attr->hdr.type != 0x80ff) {
393
PJ_LOG(1,(THIS_FILE, " expecting attribute type 0x80ff"));
396
if (bin_attr->hdr.length != 3) {
397
PJ_LOG(1,(THIS_FILE, " expecting attribute length = 4"));
400
if (bin_attr->magic != PJ_STUN_MAGIC) {
401
PJ_LOG(1,(THIS_FILE, " expecting PJ_STUN_MAGIC for unknown attr"));
404
if (bin_attr->length != 3) {
405
PJ_LOG(1,(THIS_FILE, " expecting data length 4"));
413
/* Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed */
414
static int verify5(pj_stun_msg *msg)
416
if (msg->attr_count != 3) {
417
PJ_LOG(1,(THIS_FILE, " expecting 3 attribute count"));
421
if (msg->attr[0]->type != PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
422
PJ_LOG(1,(THIS_FILE, " expecting MESSAGE-INTEGRITY"));
425
if (msg->attr[1]->type != PJ_STUN_ATTR_REFRESH_INTERVAL) {
426
PJ_LOG(1,(THIS_FILE, " expecting REFRESH-INTERVAL"));
429
if (msg->attr[2]->type != PJ_STUN_ATTR_FINGERPRINT) {
430
PJ_LOG(1,(THIS_FILE, " expecting FINGERPRINT"));
438
static int decode_verify(void)
440
/* Decode all attribute types */
445
* Test vectors, from:
446
* http://tools.ietf.org/html/draft-denis-behave-rfc3489bis-test-vectors-02
448
typedef struct test_vector test_vector;
450
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
451
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
452
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v);
456
USE_MESSAGE_INTEGRITY = 1,
460
static struct test_vector
471
pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
475
PJ_STUN_BINDING_REQUEST,
476
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
477
"\x00\x01\x00\x44\x21\x12\xa4\x42\xb7\xe7"
478
"\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
479
"\x00\x24\x00\x04\x6e\x00\x01\xff\x80\x29"
480
"\x00\x08\x93\x2f\xf9\xb1\x51\x26\x3b\x36"
481
"\x00\x06\x00\x09\x65\x76\x74\x6a\x3a\x68"
482
"\x36\x76\x59\x20\x20\x20\x00\x08\x00\x14"
483
"\x62\x4e\xeb\xdc\x3c\xc9\x2d\xd8\x4b\x74"
484
"\xbf\x85\xd1\xc0\xf5\xde\x36\x87\xbd\x33"
485
"\x80\x28\x00\x04\xad\x8a\x85\xff",
487
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
489
"VOkJxbRl1RmTxUk/WvJxBt",
494
/* disabled: see http://trac.pjsip.org/repos/ticket/960
497
PJ_STUN_BINDING_RESPONSE,
498
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
501
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
503
"\x74\x65\x73\x74\x20\x76\x65\x63\x74\x6f\x72\x20"
505
"\x00\x01\xa1\x47\xe1\x12\xa6\x43"
507
"\x2b\x91\xf5\x99\xfd\x9e\x90\xc3\x8c\x74\x89\xf9"
508
"\x2a\xf9\xba\x53\xf0\x6b\xe7\xd7"
512
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
514
"VOkJxbRl1RmTxUk/WvJxBt",
521
/* disabled: see http://trac.pjsip.org/repos/ticket/960
522
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
525
PJ_STUN_BINDING_RESPONSE,
526
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
527
"\x01\x01\x00\x48" // Response type and message length
528
"\x21\x12\xa4\x42" // Message cookie
529
"\xb7\xe7\xa7\x01" // }
530
"\xbc\x34\xd6\x86" // } Transaction ID
531
"\xfa\x87\xdf\xae" // }
533
"\x80\x22\x00\x0b" // SOFTWARE, length=11
537
"\x00\x20\x00\x14" // XOR-MAPPED-ADDRESS
543
"\x00\x08\x00\x14" // MESSAGE-INTEGRITY attribute header
544
"\xa3\x82\x95\x4e" // }
545
"\x4b\xe6\x7b\xf1" // }
546
"\x17\x84\xc9\x7c" // } HMAC-SHA1 fingerprint
547
"\x82\x92\xc2\x75" // }
548
"\xbf\xe3\xed\x41" // }
549
"\x80\x28\x00\x04" // FINGERPRINT attribute header
550
"\xc8\xfb\x0b\x4c" // CRC32 fingerprint
553
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
555
"VOkJxbRl1RmTxUk/WvJxBt",
565
static char* print_binary(const pj_uint8_t *data, unsigned data_len)
567
static char buf[1500];
568
unsigned length = sizeof(buf);
572
for (i=0; i<data_len;) {
575
pj_ansi_snprintf(p, 1500-(p-buf),
577
i, (i+20 < data_len) ? i+20 : data_len);
580
for (j=0; j<20 && i<data_len && p<(buf+length-10); ++j, ++i) {
581
pj_ansi_sprintf(p, "%02x ", (*data) & 0xFF);
586
pj_ansi_sprintf(p, "\n");
593
static int cmp_buf(const pj_uint8_t *s1, const pj_uint8_t *s2, unsigned len)
596
for (i=0; i<len; ++i) {
604
static int fingerprint_test_vector()
611
/* To avoid function not referenced warnings */
612
(void)create_msgint2;
613
(void)create_msgint3;
615
PJ_LOG(3,(THIS_FILE, " draft-denis-behave-rfc3489bis-test-vectors-02"));
617
pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
619
for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) {
620
struct test_vector *v;
621
pj_stun_msg *ref_msg, *msg;
622
pj_size_t parsed_len;
625
pj_uint8_t buf[1500];
629
PJ_LOG(3,(THIS_FILE, " Running test %d/%d", i,
630
PJ_ARRAY_SIZE(test_vectors)));
632
v = &test_vectors[i];
634
/* Print reference message */
635
PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
636
print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));
638
/* Try to parse the reference message first */
639
status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
640
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
641
&ref_msg, &parsed_len, NULL);
642
if (status != PJ_SUCCESS) {
643
PJ_LOG(1,(THIS_FILE, " Error decoding reference message"));
648
if (parsed_len != v->pdu_len) {
649
PJ_LOG(1,(THIS_FILE, " Parsed len error"));
654
/* Print the reference message */
655
pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
656
PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));
658
/* Create our message */
659
msg = v->create(pool, v);
661
PJ_LOG(1,(THIS_FILE, " Error creating stun message"));
667
if (v->options & USE_MESSAGE_INTEGRITY) {
670
pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm),
671
pj_cstr(&s1, v->username),
672
PJ_STUN_PASSWD_PLAIN,
673
pj_cstr(&s2, v->password));
674
pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
677
pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
680
/* Print our raw message */
681
PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
682
print_binary((pj_uint8_t*)buf, len)));
684
/* Print our message */
685
pj_stun_msg_dump(msg, print, sizeof(print), NULL);
686
PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));
688
/* Compare message length */
689
if (len != v->pdu_len) {
690
PJ_LOG(1,(THIS_FILE, " Message length mismatch"));
695
pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, len);
696
if (pos != (unsigned)-1) {
697
PJ_LOG(1,(THIS_FILE, " Message mismatch at byte %d", pos));
702
/* Authenticate the request/response */
703
if (v->options & USE_MESSAGE_INTEGRITY) {
704
if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
705
pj_stun_auth_cred cred;
708
pj_bzero(&cred, sizeof(cred));
709
cred.type = PJ_STUN_AUTH_CRED_STATIC;
710
cred.data.static_cred.realm = pj_str(v->realm);
711
cred.data.static_cred.username = pj_str(v->username);
712
cred.data.static_cred.data = pj_str(v->password);
713
cred.data.static_cred.nonce = pj_str(v->nonce);
715
status = pj_stun_authenticate_request(buf, len, msg,
716
&cred, pool, NULL, NULL);
717
if (status != PJ_SUCCESS) {
718
char errmsg[PJ_ERR_MSG_SIZE];
719
pj_strerror(status, errmsg, sizeof(errmsg));
721
" Request authentication failed: %s",
727
} else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
729
status = pj_stun_authenticate_response(buf, len, msg, &key);
730
if (status != PJ_SUCCESS) {
731
char errmsg[PJ_ERR_MSG_SIZE];
732
pj_strerror(status, errmsg, sizeof(errmsg));
734
" Response authentication failed: %s",
745
pj_pool_release(pool);
749
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v)
756
status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
757
(pj_uint8_t*)v->tsx_id, &msg);
758
if (status != PJ_SUCCESS)
761
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY,
763
if (status != PJ_SUCCESS)
766
u64.u32.hi = 0x932ff9b1;
767
u64.u32.lo = 0x51263b36;
768
status = pj_stun_msg_add_uint64_attr(pool, msg,
769
PJ_STUN_ATTR_ICE_CONTROLLED, &u64);
770
if (status != PJ_SUCCESS)
773
status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME,
774
pj_cstr(&s1, v->username));
775
if (status != PJ_SUCCESS)
778
status = pj_stun_msg_add_msgint_attr(pool, msg);
779
if (status != PJ_SUCCESS)
782
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
783
if (status != PJ_SUCCESS)
789
app_perror(" error: create_msgint1()", status);
793
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
796
pj_sockaddr_in mapped_addr;
800
status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
801
(pj_uint8_t*)v->tsx_id, &msg);
802
if (status != PJ_SUCCESS)
805
status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
806
pj_cstr(&s1, "test vector"));
807
if (status != PJ_SUCCESS)
810
status = pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "192.0.2.1"),
812
if (status != PJ_SUCCESS)
815
status = pj_stun_msg_add_sockaddr_attr(pool, msg,
816
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
817
PJ_TRUE, &mapped_addr,
818
sizeof(pj_sockaddr_in));
819
if (status != PJ_SUCCESS)
822
status = pj_stun_msg_add_msgint_attr(pool, msg);
823
if (status != PJ_SUCCESS)
826
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
827
if (status != PJ_SUCCESS)
833
app_perror(" error: create_msgint2()", status);
838
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
841
pj_sockaddr mapped_addr;
845
status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
846
(pj_uint8_t*)v->tsx_id, &msg);
847
if (status != PJ_SUCCESS)
850
status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
851
pj_cstr(&s1, "test vector"));
852
if (status != PJ_SUCCESS)
855
status = pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
856
pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
858
if (status != PJ_SUCCESS)
861
status = pj_stun_msg_add_sockaddr_attr(pool, msg,
862
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
863
PJ_TRUE, &mapped_addr,
864
sizeof(pj_sockaddr));
865
if (status != PJ_SUCCESS)
868
status = pj_stun_msg_add_msgint_attr(pool, msg);
869
if (status != PJ_SUCCESS)
872
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
873
if (status != PJ_SUCCESS)
879
app_perror(" error: create_msgint3()", status);
884
/* Compare two messages */
885
static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
889
if (msg1->hdr.type != msg2->hdr.type)
891
if (msg1->hdr.length != msg2->hdr.length)
893
if (msg1->hdr.magic != msg2->hdr.magic)
895
if (pj_memcmp(msg1->hdr.tsx_id, msg2->hdr.tsx_id, sizeof(msg1->hdr.tsx_id)))
897
if (msg1->attr_count != msg2->attr_count)
900
for (i=0; i<msg1->attr_count; ++i) {
901
const pj_stun_attr_hdr *a1 = msg1->attr[i];
902
const pj_stun_attr_hdr *a2 = msg2->attr[i];
904
if (a1->type != a2->type)
906
if (a1->length != a2->length)
913
/* Decode and authenticate message with unknown non-mandatory attribute */
914
static int handle_unknown_non_mandatory(void)
916
pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL);
917
pj_stun_msg *msg0, *msg1, *msg2;
918
pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6};
919
pj_uint8_t packet[500];
920
pj_stun_auth_cred cred;
924
PJ_LOG(3,(THIS_FILE, " handling unknown non-mandatory attr"));
926
PJ_LOG(3,(THIS_FILE, " encoding"));
927
rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0);
928
rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME);
929
rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data));
930
rc += pj_stun_msg_add_msgint_attr(pool, msg0);
931
rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len);
938
for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]);
943
PJ_LOG(3,(THIS_FILE, " decoding"));
944
rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
947
rc += cmp_msg(msg0, msg1);
949
pj_bzero(&cred, sizeof(cred));
950
cred.type = PJ_STUN_AUTH_CRED_STATIC;
951
cred.data.static_cred.username = USERNAME;
952
cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
953
cred.data.static_cred.data = PASSWORD;
955
PJ_LOG(3,(THIS_FILE, " authenticating"));
956
rc += pj_stun_authenticate_request(packet, len, msg1, &cred, pool, NULL, NULL);
958
PJ_LOG(3,(THIS_FILE, " clone"));
959
msg2 = pj_stun_msg_clone(pool, msg1);
960
rc += cmp_msg(msg0, msg2);
962
pj_pool_release(pool);
964
return rc==0 ? 0 : -4410;
972
pad = pj_stun_set_padding_char(32);
978
rc = decode_verify();
982
rc = fingerprint_test_vector();
986
rc = handle_unknown_non_mandatory();
991
pj_stun_set_padding_char(pad);