1
/* $Id: stun.c 4537 2013-06-19 06:47:43Z riza $ */
3
* Copyright (C) 2008-2011 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
22
#define THIS_FILE "stun.c"
24
static pj_stun_msg* create1(pj_pool_t*);
25
static int verify1(pj_stun_msg*);
26
static int verify2(pj_stun_msg*);
27
static int verify5(pj_stun_msg*);
34
pj_stun_msg* (*create)(pj_pool_t*);
35
pj_status_t expected_status;
36
int (*verify)(pj_stun_msg*);
40
"Invalid message type",
41
"\x11\x01\x00\x00\x21\x12\xa4\x42"
42
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
45
PJNATH_EINSTUNMSGTYPE,
49
"Short message (1) (partial header)",
57
"Short message (2) (partial header)",
58
"\x00\x01\x00\x00\x21\x12\xa4\x42"
59
"\x00\x00\x00\x00\x00\x00\x00\x00",
66
"Short message (3), (missing attribute)",
67
"\x00\x01\x00\x08\x21\x12\xa4\x42"
68
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
75
"Short message (4), (partial attribute header)",
76
"\x00\x01\x00\x08\x21\x12\xa4\x42"
77
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
85
"Short message (5), (partial attribute header)",
86
"\x00\x01\x00\x08\x21\x12\xa4\x42"
87
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
95
"Short message (6), (partial attribute header)",
96
"\x00\x01\x00\x08\x21\x12\xa4\x42"
97
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
101
PJNATH_EINSTUNMSGLEN,
105
"Short message (7), (partial attribute body)",
106
"\x00\x01\x00\x08\x21\x12\xa4\x42"
107
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
108
"\x80\x28\x00\x04\x00\x00\x00",
111
PJNATH_EINSTUNMSGLEN,
115
"Message length in header is too long",
116
"\x00\x01\xff\xff\x21\x12\xa4\x42"
117
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
118
"\x80\x28\x00\x04\x00\x00\x00",
121
PJNATH_EINSTUNMSGLEN,
125
"Message length in header is shorter",
126
"\x00\x01\x00\x04\x21\x12\xa4\x42"
127
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
128
"\x80\x28\x00\x04\x00\x00\x00\x00",
131
PJNATH_EINSTUNMSGLEN,
136
"\x00\x01\x00\x08\x00\x12\xa4\x42"
137
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
138
"\x80\x28\x00\x04\x00\x00\x00\x00",
145
"Character beyond message",
146
"\x00\x01\x00\x08\x21\x12\xa4\x42"
147
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
148
"\x80\x28\x00\x04\x00\x00\x00\x00\x0a",
151
PJNATH_EINSTUNMSGLEN,
155
"Respond unknown mandatory attribute with 420 and "
156
"UNKNOWN-ATTRIBUTES attribute",
164
"Unknown but non-mandatory should be okay",
165
"\x00\x01\x00\x08\x21\x12\xa4\x42"
166
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
167
"\x80\xff\x00\x03\x00\x00\x00\x00",
174
"String attr length larger than message",
175
"\x00\x01\x00\x08\x00\x12\xa4\x42"
176
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
177
"\x00\x06\x00\xff\x00\x00\x00\x00",
180
PJNATH_ESTUNINATTRLEN,
184
"Attribute other than FINGERPRINT after MESSAGE-INTEGRITY is allowed",
185
"\x00\x01\x00\x20\x21\x12\xa4\x42"
186
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
187
"\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
188
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
189
"\x80\x24\x00\x04\x00\x00\x00\x00", // REFRESH-INTERVAL
196
"Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed",
197
"\x00\x01\x00\x28\x21\x12\xa4\x42"
198
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
199
"\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
200
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
201
"\x80\x24\x00\x04\x00\x00\x00\x00" // REFRESH-INTERVAL
202
"\x80\x28\x00\x04\xc7\xde\xdd\x65", // FINGERPRINT
209
"Attribute past FINGERPRINT is not allowed",
210
"\x00\x01\x00\x10\x21\x12\xa4\x42"
211
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
212
"\x80\x28\x00\x04\x00\x00\x00\x00"
213
"\x80\x24\x00\x04\x00\x00\x00\x00",
216
PJNATH_ESTUNFINGERPOS,
221
static const char *err(pj_status_t status)
223
static char errmsg[PJ_ERR_MSG_SIZE];
224
pj_strerror(status, errmsg, sizeof(errmsg));
228
static const pj_str_t USERNAME = {"user", 4};
229
static const pj_str_t PASSWORD = {"password", 8};
231
static int decode_test(void)
237
pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL);
239
PJ_LOG(3,(THIS_FILE, " STUN decode test"));
241
for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
242
struct test *t = &tests[i];
243
pj_stun_msg *msg, *msg2;
244
pj_uint8_t buf[1500];
249
PJ_LOG(3,(THIS_FILE, " %s", t->title));
252
status = pj_stun_msg_decode(pool, (pj_uint8_t*)t->pdu, t->pdu_len,
253
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
256
/* Check expected decode result */
257
if (t->expected_status != status) {
258
PJ_LOG(1,(THIS_FILE, " expecting status %d, got %d",
259
t->expected_status, status));
265
msg = t->create(pool);
269
if (status != PJ_SUCCESS)
272
/* Try to encode message */
273
pj_stun_create_key(pool, &key, NULL, &USERNAME, PJ_STUN_PASSWD_PLAIN, &PASSWORD);
274
status = pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
275
if (status != PJ_SUCCESS) {
276
PJ_LOG(1,(THIS_FILE, " encode error: %s", err(status)));
281
/* Try to decode it once more */
282
status = pj_stun_msg_decode(pool, buf, len,
283
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
285
if (status != PJ_SUCCESS) {
286
PJ_LOG(1,(THIS_FILE, " subsequent decoding failed: %s", err(status)));
301
pj_pool_release(pool);
303
PJ_LOG(3,(THIS_FILE, "...success!"));
307
/* Create 420 response */
308
static pj_stun_msg* create1(pj_pool_t *pool)
310
char *pdu = "\x00\x01\x00\x08\x21\x12\xa4\x42"
311
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
312
"\x00\xff\x00\x04\x00\x00\x00\x00";
313
unsigned pdu_len = 28;
314
pj_stun_msg *msg, *res;
317
status = pj_stun_msg_decode(pool, (pj_uint8_t*)pdu, pdu_len,
318
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
320
pj_assert(status != PJ_SUCCESS);
321
pj_assert(res != NULL);
326
/* Error response MUST have ERROR-CODE attribute */
327
/* 420 response MUST contain UNKNOWN-ATTRIBUTES */
328
static int verify1(pj_stun_msg *msg)
330
pj_stun_errcode_attr *aerr;
331
pj_stun_unknown_attr *aunk;
333
if (!PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) {
334
PJ_LOG(1,(THIS_FILE, " expecting error message"));
338
aerr = (pj_stun_errcode_attr*)
339
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
341
PJ_LOG(1,(THIS_FILE, " missing ERROR-CODE attribute"));
345
if (aerr->err_code != 420) {
346
PJ_LOG(1,(THIS_FILE, " expecting 420 error"));
350
aunk = (pj_stun_unknown_attr*)
351
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
353
PJ_LOG(1,(THIS_FILE, " missing UNKNOWN-ATTRIBUTE attribute"));
357
if (aunk->attr_count != 1) {
358
PJ_LOG(1,(THIS_FILE, " expecting one unknown attribute"));
362
if (aunk->attrs[0] != 0xff) {
363
PJ_LOG(1,(THIS_FILE, " expecting 0xff as unknown attribute"));
370
/* Attribute count should be zero since unknown attribute is not parsed */
371
static int verify2(pj_stun_msg *msg)
373
pj_stun_binary_attr *bin_attr;
375
if (msg->attr_count != 1) {
376
PJ_LOG(1,(THIS_FILE, " expecting one attribute count"));
380
bin_attr = (pj_stun_binary_attr*)msg->attr[0];
381
if (bin_attr->hdr.type != 0x80ff) {
382
PJ_LOG(1,(THIS_FILE, " expecting attribute type 0x80ff"));
385
if (bin_attr->hdr.length != 3) {
386
PJ_LOG(1,(THIS_FILE, " expecting attribute length = 4"));
389
if (bin_attr->magic != PJ_STUN_MAGIC) {
390
PJ_LOG(1,(THIS_FILE, " expecting PJ_STUN_MAGIC for unknown attr"));
393
if (bin_attr->length != 3) {
394
PJ_LOG(1,(THIS_FILE, " expecting data length 4"));
402
/* Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed */
403
static int verify5(pj_stun_msg *msg)
405
if (msg->attr_count != 3) {
406
PJ_LOG(1,(THIS_FILE, " expecting 3 attribute count"));
410
if (msg->attr[0]->type != PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
411
PJ_LOG(1,(THIS_FILE, " expecting MESSAGE-INTEGRITY"));
414
if (msg->attr[1]->type != PJ_STUN_ATTR_REFRESH_INTERVAL) {
415
PJ_LOG(1,(THIS_FILE, " expecting REFRESH-INTERVAL"));
418
if (msg->attr[2]->type != PJ_STUN_ATTR_FINGERPRINT) {
419
PJ_LOG(1,(THIS_FILE, " expecting FINGERPRINT"));
427
static int decode_verify(void)
429
/* Decode all attribute types */
434
* Test vectors, from:
435
* http://tools.ietf.org/html/draft-denis-behave-rfc3489bis-test-vectors-02
437
typedef struct test_vector test_vector;
439
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
440
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
441
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v);
445
USE_MESSAGE_INTEGRITY = 1,
449
static struct test_vector
460
pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
464
PJ_STUN_BINDING_REQUEST,
465
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
466
"\x00\x01\x00\x44\x21\x12\xa4\x42\xb7\xe7"
467
"\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
468
"\x00\x24\x00\x04\x6e\x00\x01\xff\x80\x29"
469
"\x00\x08\x93\x2f\xf9\xb1\x51\x26\x3b\x36"
470
"\x00\x06\x00\x09\x65\x76\x74\x6a\x3a\x68"
471
"\x36\x76\x59\x20\x20\x20\x00\x08\x00\x14"
472
"\x62\x4e\xeb\xdc\x3c\xc9\x2d\xd8\x4b\x74"
473
"\xbf\x85\xd1\xc0\xf5\xde\x36\x87\xbd\x33"
474
"\x80\x28\x00\x04\xad\x8a\x85\xff",
476
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
478
"VOkJxbRl1RmTxUk/WvJxBt",
483
/* disabled: see http://trac.pjsip.org/repos/ticket/960
486
PJ_STUN_BINDING_RESPONSE,
487
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
490
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
492
"\x74\x65\x73\x74\x20\x76\x65\x63\x74\x6f\x72\x20"
494
"\x00\x01\xa1\x47\xe1\x12\xa6\x43"
496
"\x2b\x91\xf5\x99\xfd\x9e\x90\xc3\x8c\x74\x89\xf9"
497
"\x2a\xf9\xba\x53\xf0\x6b\xe7\xd7"
501
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
503
"VOkJxbRl1RmTxUk/WvJxBt",
510
/* disabled: see http://trac.pjsip.org/repos/ticket/960
511
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
514
PJ_STUN_BINDING_RESPONSE,
515
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
516
"\x01\x01\x00\x48" // Response type and message length
517
"\x21\x12\xa4\x42" // Message cookie
518
"\xb7\xe7\xa7\x01" // }
519
"\xbc\x34\xd6\x86" // } Transaction ID
520
"\xfa\x87\xdf\xae" // }
522
"\x80\x22\x00\x0b" // SOFTWARE, length=11
526
"\x00\x20\x00\x14" // XOR-MAPPED-ADDRESS
532
"\x00\x08\x00\x14" // MESSAGE-INTEGRITY attribute header
533
"\xa3\x82\x95\x4e" // }
534
"\x4b\xe6\x7b\xf1" // }
535
"\x17\x84\xc9\x7c" // } HMAC-SHA1 fingerprint
536
"\x82\x92\xc2\x75" // }
537
"\xbf\xe3\xed\x41" // }
538
"\x80\x28\x00\x04" // FINGERPRINT attribute header
539
"\xc8\xfb\x0b\x4c" // CRC32 fingerprint
542
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
544
"VOkJxbRl1RmTxUk/WvJxBt",
554
static char* print_binary(const pj_uint8_t *data, unsigned data_len)
556
static char buf[1500];
557
unsigned length = sizeof(buf);
561
for (i=0; i<data_len;) {
564
pj_ansi_snprintf(p, 1500-(p-buf),
566
i, (i+20 < data_len) ? i+20 : data_len);
569
for (j=0; j<20 && i<data_len && p<(buf+length-10); ++j, ++i) {
570
pj_ansi_sprintf(p, "%02x ", (*data) & 0xFF);
575
pj_ansi_sprintf(p, "\n");
582
static int cmp_buf(const pj_uint8_t *s1, const pj_uint8_t *s2, unsigned len)
585
for (i=0; i<len; ++i) {
593
static int fingerprint_test_vector()
600
/* To avoid function not referenced warnings */
601
(void)create_msgint2;
602
(void)create_msgint3;
604
PJ_LOG(3,(THIS_FILE, " draft-denis-behave-rfc3489bis-test-vectors-02"));
606
pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
608
for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) {
609
struct test_vector *v;
610
pj_stun_msg *ref_msg, *msg;
611
pj_size_t parsed_len;
614
pj_uint8_t buf[1500];
618
PJ_LOG(3,(THIS_FILE, " Running test %d/%d", i,
619
PJ_ARRAY_SIZE(test_vectors)));
621
v = &test_vectors[i];
623
/* Print reference message */
624
PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
625
print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));
627
/* Try to parse the reference message first */
628
status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
629
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
630
&ref_msg, &parsed_len, NULL);
631
if (status != PJ_SUCCESS) {
632
PJ_LOG(1,(THIS_FILE, " Error decoding reference message"));
637
if (parsed_len != v->pdu_len) {
638
PJ_LOG(1,(THIS_FILE, " Parsed len error"));
643
/* Print the reference message */
644
pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
645
PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));
647
/* Create our message */
648
msg = v->create(pool, v);
650
PJ_LOG(1,(THIS_FILE, " Error creating stun message"));
656
if (v->options & USE_MESSAGE_INTEGRITY) {
659
pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm),
660
pj_cstr(&s1, v->username),
661
PJ_STUN_PASSWD_PLAIN,
662
pj_cstr(&s2, v->password));
663
pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
666
pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
669
/* Print our raw message */
670
PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
671
print_binary((pj_uint8_t*)buf, (unsigned)len)));
673
/* Print our message */
674
pj_stun_msg_dump(msg, print, sizeof(print), NULL);
675
PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));
677
/* Compare message length */
678
if (len != v->pdu_len) {
679
PJ_LOG(1,(THIS_FILE, " Message length mismatch"));
684
pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, (unsigned)len);
685
if (pos != (unsigned)-1) {
686
PJ_LOG(1,(THIS_FILE, " Message mismatch at byte %d", pos));
691
/* Authenticate the request/response */
692
if (v->options & USE_MESSAGE_INTEGRITY) {
693
if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
694
pj_stun_auth_cred cred;
697
pj_bzero(&cred, sizeof(cred));
698
cred.type = PJ_STUN_AUTH_CRED_STATIC;
699
cred.data.static_cred.realm = pj_str(v->realm);
700
cred.data.static_cred.username = pj_str(v->username);
701
cred.data.static_cred.data = pj_str(v->password);
702
cred.data.static_cred.nonce = pj_str(v->nonce);
704
status = pj_stun_authenticate_request(buf, (unsigned)len, msg,
705
&cred, pool, NULL, NULL);
706
if (status != PJ_SUCCESS) {
707
char errmsg[PJ_ERR_MSG_SIZE];
708
pj_strerror(status, errmsg, sizeof(errmsg));
710
" Request authentication failed: %s",
716
} else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
718
status = pj_stun_authenticate_response(buf, (unsigned)len,
720
if (status != PJ_SUCCESS) {
721
char errmsg[PJ_ERR_MSG_SIZE];
722
pj_strerror(status, errmsg, sizeof(errmsg));
724
" Response authentication failed: %s",
735
pj_pool_release(pool);
739
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v)
746
status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
747
(pj_uint8_t*)v->tsx_id, &msg);
748
if (status != PJ_SUCCESS)
751
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY,
753
if (status != PJ_SUCCESS)
756
u64.u32.hi = 0x932ff9b1;
757
u64.u32.lo = 0x51263b36;
758
status = pj_stun_msg_add_uint64_attr(pool, msg,
759
PJ_STUN_ATTR_ICE_CONTROLLED, &u64);
760
if (status != PJ_SUCCESS)
763
status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME,
764
pj_cstr(&s1, v->username));
765
if (status != PJ_SUCCESS)
768
status = pj_stun_msg_add_msgint_attr(pool, msg);
769
if (status != PJ_SUCCESS)
772
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
773
if (status != PJ_SUCCESS)
779
app_perror(" error: create_msgint1()", status);
783
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
786
pj_sockaddr_in mapped_addr;
790
status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
791
(pj_uint8_t*)v->tsx_id, &msg);
792
if (status != PJ_SUCCESS)
795
status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
796
pj_cstr(&s1, "test vector"));
797
if (status != PJ_SUCCESS)
800
status = pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "192.0.2.1"),
802
if (status != PJ_SUCCESS)
805
status = pj_stun_msg_add_sockaddr_attr(pool, msg,
806
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
807
PJ_TRUE, &mapped_addr,
808
sizeof(pj_sockaddr_in));
809
if (status != PJ_SUCCESS)
812
status = pj_stun_msg_add_msgint_attr(pool, msg);
813
if (status != PJ_SUCCESS)
816
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
817
if (status != PJ_SUCCESS)
823
app_perror(" error: create_msgint2()", status);
828
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
831
pj_sockaddr mapped_addr;
835
status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
836
(pj_uint8_t*)v->tsx_id, &msg);
837
if (status != PJ_SUCCESS)
840
status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
841
pj_cstr(&s1, "test vector"));
842
if (status != PJ_SUCCESS)
845
status = pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
846
pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
848
if (status != PJ_SUCCESS)
851
status = pj_stun_msg_add_sockaddr_attr(pool, msg,
852
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
853
PJ_TRUE, &mapped_addr,
854
sizeof(pj_sockaddr));
855
if (status != PJ_SUCCESS)
858
status = pj_stun_msg_add_msgint_attr(pool, msg);
859
if (status != PJ_SUCCESS)
862
status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
863
if (status != PJ_SUCCESS)
869
app_perror(" error: create_msgint3()", status);
874
/* Compare two messages */
875
static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
879
if (msg1->hdr.type != msg2->hdr.type)
881
if (msg1->hdr.length != msg2->hdr.length)
883
if (msg1->hdr.magic != msg2->hdr.magic)
885
if (pj_memcmp(msg1->hdr.tsx_id, msg2->hdr.tsx_id, sizeof(msg1->hdr.tsx_id)))
887
if (msg1->attr_count != msg2->attr_count)
890
for (i=0; i<msg1->attr_count; ++i) {
891
const pj_stun_attr_hdr *a1 = msg1->attr[i];
892
const pj_stun_attr_hdr *a2 = msg2->attr[i];
894
if (a1->type != a2->type)
896
if (a1->length != a2->length)
903
/* Decode and authenticate message with unknown non-mandatory attribute */
904
static int handle_unknown_non_mandatory(void)
906
pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL);
907
pj_stun_msg *msg0, *msg1, *msg2;
908
pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6};
909
pj_uint8_t packet[500];
910
pj_stun_auth_cred cred;
914
PJ_LOG(3,(THIS_FILE, " handling unknown non-mandatory attr"));
916
PJ_LOG(3,(THIS_FILE, " encoding"));
917
rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0);
918
rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME);
919
rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data));
920
rc += pj_stun_msg_add_msgint_attr(pool, msg0);
921
rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len);
928
for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]);
933
PJ_LOG(3,(THIS_FILE, " decoding"));
934
rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
937
rc += cmp_msg(msg0, msg1);
939
pj_bzero(&cred, sizeof(cred));
940
cred.type = PJ_STUN_AUTH_CRED_STATIC;
941
cred.data.static_cred.username = USERNAME;
942
cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
943
cred.data.static_cred.data = PASSWORD;
945
PJ_LOG(3,(THIS_FILE, " authenticating"));
946
rc += pj_stun_authenticate_request(packet, (unsigned)len, msg1, &cred, pool,
949
PJ_LOG(3,(THIS_FILE, " clone"));
950
msg2 = pj_stun_msg_clone(pool, msg1);
951
rc += cmp_msg(msg0, msg2);
953
pj_pool_release(pool);
955
return rc==0 ? 0 : -4410;
963
pad = pj_stun_set_padding_char(32);
969
rc = decode_verify();
973
rc = fingerprint_test_vector();
977
rc = handle_unknown_non_mandatory();
982
pj_stun_set_padding_char(pad);