~ubuntu-branches/debian/sid/kamailio/sid

« back to all changes in this revision

Viewing changes to ser_stun.c

  • Committer: Package Import Robot
  • Author(s): Victor Seva
  • Date: 2014-01-06 11:47:13 UTC
  • mfrom: (1.1.5)
  • Revision ID: package-import@ubuntu.com-20140106114713-t8xidp4arzrnyeya
Tags: 4.1.1-1
* New upstream release
* debian/patches:
  - add upstream fixes
* Added tls outbound websocket autheph dnssec modules
  - openssl exception added to their license
* removing sparc and ia64 from supported archs
  for mono module (Closes: #728915)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * $Id$
3
 
 *
4
 
 * Copyright (C) 2001-2003 FhG Fokus
5
 
 *
6
 
 * This file is part of ser, a free SIP server.
7
 
 *
8
 
 * ser is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version
12
 
 *
13
 
 * For a license to use the ser software under conditions
14
 
 * other than those described here, or to purchase support for this
15
 
 * software, please contact iptel.org by e-mail at the following addresses:
16
 
 *    info@iptel.org
17
 
 *
18
 
 * ser is distributed in the hope that it will be useful,
19
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 
 * GNU General Public License for more details.
22
 
 *
23
 
 * You should have received a copy of the GNU General Public License 
24
 
 * along with this program; if not, write to the Free Software 
25
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 
 *
27
 
 * History
28
 
 * --------
29
 
 *  2006-10-13  created (vlada)
30
 
 *  2006-12-14  fixed calculation of body length (vlada) 
31
 
 */
32
 
 
33
 
/*!
34
 
 * \file
35
 
 * \brief SIP-router core :: 
36
 
 * \ingroup core
37
 
 * Module: \ref core
38
 
 */
39
 
 
40
 
#ifdef USE_STUN 
41
 
 
42
 
#include <arpa/inet.h>
43
 
#include <openssl/sha.h>
44
 
#include "ser_stun.h"
45
 
#include "forward.h"
46
 
 
47
 
/*
48
 
 * ****************************************************************************
49
 
 *                     Declaration of functions                               *
50
 
 * ****************************************************************************
51
 
 */
52
 
int stun_parse_header(struct stun_msg* req, USHORT_T* error_code);
53
 
int stun_parse_body(
54
 
                                struct stun_msg* req,
55
 
                                struct stun_unknown_att** unknown,
56
 
                                USHORT_T* error_code);
57
 
void stun_delete_unknown_attrs(struct stun_unknown_att* unknown);
58
 
struct stun_unknown_att* stun_alloc_unknown_attr(USHORT_T type);
59
 
int stun_add_address_attr(struct stun_msg* res, 
60
 
                                                UINT_T          af,
61
 
                                                USHORT_T        port,
62
 
                                                UINT_T*         ip_addr,
63
 
                                                USHORT_T        type,
64
 
                                                int do_xor);
65
 
int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown);
66
 
int add_error_code(struct stun_msg* res, USHORT_T error_code);
67
 
int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad);
68
 
int reallock_buffer(struct stun_buffer* buffer, UINT_T len);
69
 
int buf_copy(struct stun_buffer* msg, void* source, UINT_T len);
70
 
void clean_memory(struct stun_msg* req,
71
 
                                struct stun_msg* res,   struct stun_unknown_att* unknown);
72
 
int stun_create_response(
73
 
                                                struct stun_msg* req,
74
 
                                                struct stun_msg* res,
75
 
                                                struct receive_info* ri,
76
 
                                                struct stun_unknown_att* unknown, 
77
 
                                                UINT_T error_code);
78
 
int stun_add_common_integer_attr(struct stun_msg* res, USHORT_T type, UINT_T value);
79
 
int stun_add_common_text_attr(struct stun_msg* res, USHORT_T type, char* value, 
80
 
                                                        USHORT_T pad);
81
 
 
82
 
 
83
 
/*
84
 
 * ****************************************************************************
85
 
 *                      Definition of functions                               *
86
 
 * ****************************************************************************
87
 
 */
88
 
 
89
 
/* 
90
 
 * stun_process_msg(): 
91
 
 *                      buf - incoming message
92
 
 *                      len - length of incoming message
93
 
 *                      ri  - information about socket that received a message and 
94
 
 *                also information about sender (its IP, port, protocol)
95
 
 * 
96
 
 * This function ensures processing of incoming message. It's common for both
97
 
 * TCP and UDP protocol. There is no other function as an interface.
98
 
 * 
99
 
 * Return value:        0       if there is no environment error
100
 
 *                                      -1      if there is some enviroment error such as insufficiency
101
 
 *                                              of memory
102
 
 * 
103
 
 */
104
 
int stun_process_msg(char* buf, unsigned len, struct receive_info* ri)
105
 
{
106
 
        struct stun_msg                         msg_req;
107
 
        struct stun_msg                         msg_res;
108
 
        struct dest_info                        dst;
109
 
        struct stun_unknown_att*        unknown;
110
 
        USHORT_T                                        error_code;
111
 
         
112
 
        memset(&msg_req, 0, sizeof(msg_req));
113
 
        memset(&msg_res, 0, sizeof(msg_res));
114
 
        
115
 
        msg_req.msg.buf.s = buf;
116
 
        msg_req.msg.buf.len = len;      
117
 
        unknown = NULL;
118
 
        error_code = RESPONSE_OK;
119
 
        
120
 
        if (stun_parse_header(&msg_req, &error_code) != 0) {
121
 
                goto error;
122
 
        }
123
 
        
124
 
        if (error_code == RESPONSE_OK) {
125
 
                if (stun_parse_body(&msg_req, &unknown, &error_code) != 0) {
126
 
                        goto error;
127
 
                }
128
 
        }
129
 
        
130
 
        if (stun_create_response(&msg_req, &msg_res, ri,  
131
 
                                                        unknown, error_code) != 0) {
132
 
                goto error;
133
 
        }
134
 
        
135
 
        init_dst_from_rcv(&dst, ri);
136
 
 
137
 
#ifdef EXTRA_DEBUG      
138
 
        struct ip_addr ip;
139
 
        su2ip_addr(&ip, &dst.to);
140
 
        LOG(L_DBG, "DEBUG: stun_process_msg: decoded request from (%s:%d)\n", ip_addr2a(&ip), 
141
 
                su_getport(&dst.to));
142
 
#endif
143
 
        
144
 
        /* send STUN response */
145
 
        if (msg_send(&dst, msg_res.msg.buf.s, msg_res.msg.buf.len) != 0) {
146
 
                goto error;
147
 
        }
148
 
        
149
 
#ifdef EXTRA_DEBUG
150
 
        LOG(L_DBG, "DEBUG: stun_process_msg: send response\n");
151
 
#endif
152
 
        clean_memory(&msg_req, &msg_res, unknown);
153
 
        return 0;
154
 
        
155
 
error:
156
 
#ifdef EXTRA_DEBUG
157
 
        LOG(L_DBG, "DEBUG: stun_process_msg: failed to decode request\n");
158
 
#endif
159
 
        clean_memory(&msg_req, &msg_res, unknown);
160
 
        return FATAL_ERROR;
161
 
}
162
 
 
163
 
/*
164
 
 * stun_parse_header():
165
 
 *                      - req: request from host that should be processed
166
 
 *                      - error_code: indication of any protocol error
167
 
 * 
168
 
 * This function ensures parsing of incoming header.
169
 
 * 
170
 
 * Return value:        0       if there is no environment error
171
 
 *                                      -1      if there is some enviroment error such as insufficiency
172
 
 *                                              of memory
173
 
 */
174
 
 
175
 
int stun_parse_header(struct stun_msg* req, USHORT_T* error_code)
176
 
{
177
 
        
178
 
        if (sizeof(req->hdr) > req->msg.buf.len) {
179
 
                /* the received message does not contain whole header */
180
 
                LOG(L_INFO, "INFO: stun_parse_header: incomplete header of STUN message\n");
181
 
                /* Any better solution? IMHO it's not possible to send error response
182
 
                 * because the transaction ID is not available.
183
 
                 */
184
 
                return FATAL_ERROR;
185
 
        }
186
 
        
187
 
        memcpy(&req->hdr, req->msg.buf.s, sizeof(struct stun_hdr));
188
 
        req->hdr.type = ntohs(req->hdr.type);
189
 
        
190
 
        /* the SER supports only Binding Request right now */ 
191
 
        if (req->hdr.type != BINDING_REQUEST) {
192
 
                LOG(L_INFO, "INFO: stun_parse_header: unsupported type of STUN message: %x\n", 
193
 
                                        req->hdr.type);
194
 
                /* resending of same message is not welcome */
195
 
                *error_code = GLOBAL_FAILURE_ERR;
196
 
        }
197
 
        
198
 
        req->hdr.len = ntohs(req->hdr.len);
199
 
        
200
 
        /* check if there is correct magic cookie */
201
 
        req->old = (req->hdr.id.magic_cookie == htonl(MAGIC_COOKIE)) ? 0 : 1;
202
 
 
203
 
#ifdef EXTRA_DEBUG
204
 
        LOG(L_DBG, "DEBUG: stun_parse_header: request is old: %i\n", req->old);
205
 
#endif
206
 
        return 0;
207
 
}
208
 
 
209
 
/*
210
 
 * stun_parse_body():
211
 
 *                      - req: request from host that should be processed
212
 
 *                      - unknown: this is a link list header of attributes 
213
 
 *                                         that are unknown to SER; defaul value is NULL
214
 
 *                      - error_code: indication of any protocol error
215
 
 * 
216
 
 * Return value:        0       if there is no environment error
217
 
 *                                      -1      if there is some enviroment error such as insufficiency
218
 
 *                                              of memory
219
 
 */
220
 
int stun_parse_body(
221
 
                                struct stun_msg* req,
222
 
                                struct stun_unknown_att** unknown,
223
 
                                USHORT_T* error_code)
224
 
{
225
 
        int not_parsed;
226
 
        struct stun_attr attr;
227
 
        USHORT_T attr_size;
228
 
        UINT_T padded_len;
229
 
        struct stun_unknown_att*        tmp_unknown;
230
 
        struct stun_unknown_att*        body;
231
 
        char*   buf;
232
 
        
233
 
        attr_size = sizeof(struct stun_attr);
234
 
        buf = &req->msg.buf.s[sizeof(struct stun_hdr)];
235
 
        
236
 
        /* 
237
 
         * Mark the body lenght as unparsed.
238
 
         */
239
 
        not_parsed = req->msg.buf.len - sizeof(struct stun_hdr);
240
 
        
241
 
        if (not_parsed != req->hdr.len) {
242
 
#ifdef EXTRA_DEBUG
243
 
                LOG(L_DBG, "DEBUG: stun_parse_body: body too short to be valid\n");
244
 
#endif
245
 
                *error_code = BAD_REQUEST_ERR;
246
 
                return 0; 
247
 
        }
248
 
        
249
 
        tmp_unknown = *unknown;
250
 
        body = NULL;
251
 
        
252
 
        while (not_parsed > 0 && *error_code == RESPONSE_OK) {
253
 
                memset(&attr, 0, attr_size);
254
 
                
255
 
                /* check if there are 4 bytes for attribute type and its value */
256
 
                if (not_parsed < 4) {
257
 
#ifdef EXTRA_DEBUG
258
 
                        LOG(L_DBG, "DEBUG: stun_parse_body: attribute header short to be valid\n");
259
 
#endif
260
 
                        *error_code = BAD_REQUEST_ERR;
261
 
                        continue;
262
 
                }
263
 
                
264
 
                memcpy(&attr, buf, attr_size);
265
 
                
266
 
                buf += attr_size;
267
 
                not_parsed -= attr_size;
268
 
                
269
 
                /* check if there is enought unparsed space for attribute's value */
270
 
                if (not_parsed < ntohs(attr.len)) {
271
 
#ifdef EXTRA_DEBUG
272
 
                        LOG(L_DBG, "DEBUG: stun_parse_body: remaining message is shorter then attribute length\n");
273
 
#endif
274
 
                        *error_code = BAD_REQUEST_ERR;
275
 
                        continue;
276
 
                }
277
 
                
278
 
                /* check if the attribute is known to the server */
279
 
                switch (ntohs(attr.type)) {                     
280
 
                        case REALM_ATTR:
281
 
                        case NONCE_ATTR:
282
 
                        case MAPPED_ADDRESS_ATTR:
283
 
                        case XOR_MAPPED_ADDRESS_ATTR:
284
 
                        case ALTERNATE_SERVER_ATTR:
285
 
                        case RESPONSE_ADDRESS_ATTR:
286
 
                        case SOURCE_ADDRESS_ATTR:
287
 
                        case REFLECTED_FROM_ATTR:               
288
 
                        case CHANGE_REQUEST_ATTR:
289
 
                        case CHANGED_ADDRESS_ATTR:
290
 
                                padded_len = ntohs(attr.len);
291
 
#ifdef EXTRA_DEBUG
292
 
                                LOG(L_DBG, "DEBUG: stun_parse_body: known attributes\n");
293
 
#endif
294
 
                                break;
295
 
                        
296
 
                        /* following attributes must be padded to 4 bytes */
297
 
                        case USERNAME_ATTR:
298
 
                        case ERROR_CODE_ATTR:
299
 
                        case UNKNOWN_ATTRIBUTES_ATTR:
300
 
                        case SOFTWARE_ATTR:
301
 
                                padded_len = PADDED_TO_FOUR(ntohs(attr.len));
302
 
#ifdef EXTRA_DEBUG
303
 
                                LOG(L_DBG, "DEBUG: stun_parse_body: padded to four\n");
304
 
#endif
305
 
                                break;
306
 
 
307
 
                        /* MESSAGE_INTEGRITY must be padded to sixty four bytes*/
308
 
                        case MESSAGE_INTEGRITY_ATTR:
309
 
#ifdef EXTRA_DEBUG
310
 
                                LOG(L_DBG, "DEBUG: stun_parse_body: message integrity attribute found\n");
311
 
#endif
312
 
                                padded_len = PADDED_TO_SIXTYFOUR(ntohs(attr.len));
313
 
                                break;
314
 
                        
315
 
                        case FINGERPRINT_ATTR:
316
 
#ifdef EXTRA_DEBUG
317
 
                                LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint attribute found\n");
318
 
#endif
319
 
                                padded_len = SHA_DIGEST_LENGTH;
320
 
 
321
 
                                if (not_parsed > SHA_DIGEST_LENGTH) {
322
 
#ifdef EXTRA_DEBUG
323
 
                                        LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is not the last attribute\n");
324
 
#endif
325
 
                                        /* fingerprint must be last parameter in request */
326
 
                                        *error_code = BAD_REQUEST_ERR;
327
 
                                        continue;
328
 
                                }
329
 
                                break;
330
 
                        
331
 
                        default:
332
 
                                /* 
333
 
                                 * the attribute is uknnown to the server
334
 
                                 * let see if it's necessary to generate error response 
335
 
                                 */
336
 
#ifdef EXTRA_DEBUG
337
 
                                LOG(L_DBG, "DEBUG: low endian: attr - 0x%x   const - 0x%x\n", ntohs(attr.type), MANDATORY_ATTR);
338
 
                    LOG(L_DBG, "DEBUG: big endian: attr - 0x%x   const - 0x%x\n", attr.type, htons(MANDATORY_ATTR));
339
 
#endif
340
 
                                if (ntohs(attr.type) <= MANDATORY_ATTR) {
341
 
#ifdef EXTRA_DEBUG
342
 
                                LOG(L_DBG, "DEBUG: stun_parse_body: mandatory unknown attribute found - 0x%x\n", ntohs(attr.type));
343
 
#endif          
344
 
                                        tmp_unknown = stun_alloc_unknown_attr(attr.type);
345
 
                                        if (tmp_unknown == NULL) {
346
 
                                                return FATAL_ERROR;
347
 
                                        }
348
 
                                        if (*unknown == NULL) {
349
 
                                                *unknown = body = tmp_unknown;
350
 
                                        }
351
 
                                        else { 
352
 
                                                body->next = tmp_unknown;
353
 
                                                body = body->next;
354
 
                                        }
355
 
                                }
356
 
#ifdef EXTRA_DEBUG
357
 
        else {
358
 
                                  LOG(L_DBG, "DEBUG: stun_parse_body: optional unknown attribute found - 0x%x\n", ntohs(attr.type));
359
 
        }
360
 
#endif
361
 
                                padded_len = ntohs(attr.len);
362
 
                                break;
363
 
                }
364
 
                
365
 
                /* check if there is enough unparsed space for the padded attribute
366
 
                   (the padded length might be greater then the attribute length)
367
 
                 */
368
 
                if (not_parsed < padded_len) {
369
 
                        break;
370
 
                }
371
 
                buf += padded_len;
372
 
                not_parsed -= padded_len;
373
 
        }  /* while */
374
 
        
375
 
        /*
376
 
         * The unknown attribute error code must set after parsing of whole body
377
 
         * because it's necessary to obtain all of unknown attributes! 
378
 
         */
379
 
        if (*error_code == RESPONSE_OK && *unknown != NULL) {
380
 
                *error_code = UNKNOWN_ATTRIBUTE_ERR;
381
 
        } 
382
 
        
383
 
        return 0;
384
 
}
385
 
 
386
 
/*
387
 
 * stun_create_response():
388
 
 *                      - req: original request from host
389
 
 *                      - res: this will represent response to host
390
 
 *                      - ri: information about request, necessary because of IP 
391
 
 *                                address and port 
392
 
 *                      - unknown: link list of unknown attributes
393
 
 *                      - error_code: indication of any protocol error
394
 
 * 
395
 
 * The function stun_create_response ensures creating response to a host.
396
 
 * The type of response depends on value of error_code parameter.
397
 
 * 
398
 
 * Return value:        0       if there is no environment error
399
 
 *                                      -1      if there is some enviroment error such as insufficiency
400
 
 *                                              of memory  
401
 
 */
402
 
 
403
 
int stun_create_response(
404
 
                                                struct stun_msg* req,
405
 
                                                struct stun_msg* res,
406
 
                                                struct receive_info* ri,
407
 
                                                struct stun_unknown_att* unknown, 
408
 
                                                UINT_T error_code)
409
 
{
410
 
        /*
411
 
         * Alloc some space for response.
412
 
         * Optimalization? - maybe it would be better to use biggish static array.
413
 
         */
414
 
        res->msg.buf.s = (char *) pkg_malloc(sizeof(char)*STUN_MSG_LEN);
415
 
        if (res->msg.buf.s == NULL) {
416
 
                LOG(L_ERR, "ERROR: STUN: out of memory\n");
417
 
                return FATAL_ERROR;
418
 
        }
419
 
        
420
 
        memset(res->msg.buf.s, 0, sizeof(char)*STUN_MSG_LEN); 
421
 
        res->msg.buf.len = 0;
422
 
        res->msg.empty = STUN_MSG_LEN;
423
 
        
424
 
        /* use magic cookie and transaction ID from request */
425
 
        memcpy(&res->hdr.id, &req->hdr.id, sizeof(struct transaction_id));
426
 
        /* the correct body length will be added ASAP it will be known */ 
427
 
        res->hdr.len = htons(0);
428
 
        
429
 
        if (error_code == RESPONSE_OK) {
430
 
#ifdef EXTRA_DEBUG
431
 
                LOG(L_DBG, "DEBUG: stun_create_response: creating normal response\n");
432
 
#endif
433
 
                res->hdr.type = htons(BINDING_RESPONSE);
434
 
                
435
 
                /* copy header into msg buffer */
436
 
                if (buf_copy(&res->msg, (void *) &res->hdr, 
437
 
                                        sizeof(struct stun_hdr)) != 0) {
438
 
#ifdef EXTRA_DEBUG
439
 
                        LOG(L_DBG, "DEBUG: stun_create_response: failed to copy buffer\n");
440
 
#endif
441
 
                        return FATAL_ERROR;
442
 
                }
443
 
 
444
 
                /* 
445
 
                 * If the SER received message in old format, then the body will 
446
 
                 * contain MAPPED-ADDRESS attribute instead of XOR-MAPPED-ADDRESS
447
 
                 * attribute.
448
 
                 */             
449
 
                if (req->old == 0) {
450
 
                        if (stun_add_address_attr(res, ri->src_ip.af, ri->src_port, 
451
 
                                                  ri->src_ip.u.addr32, XOR_MAPPED_ADDRESS_ATTR, 
452
 
                                                  XOR) != 0) {
453
 
#ifdef EXTRA_DEBUG
454
 
                                LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
455
 
#endif
456
 
                                return FATAL_ERROR;
457
 
                        }
458
 
                }
459
 
                else {
460
 
                        if (stun_add_address_attr(res, ri->src_ip.af, ri->src_port, 
461
 
                                                ri->src_ip.u.addr32, MAPPED_ADDRESS_ATTR, !XOR) != 0) {
462
 
#ifdef EXTRA_DEBUG
463
 
                                LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
464
 
#endif
465
 
                                return FATAL_ERROR;
466
 
                        }
467
 
                }
468
 
        }
469
 
        else {
470
 
#ifdef EXTRA_DEBUG
471
 
                LOG(L_DBG, "DEBUG: stun_create_response: creating error response\n");
472
 
#endif
473
 
                res->hdr.type = htons(BINDING_ERROR_RESPONSE);
474
 
                
475
 
                if (buf_copy(&res->msg, (void *) &res->hdr, 
476
 
                                                                sizeof(struct stun_hdr)) != 0) {
477
 
#ifdef EXTRA_DEBUG
478
 
                        LOG(L_DBG, "DEBUG: stun_create_response: failed to copy buffer\n");
479
 
#endif
480
 
                        return FATAL_ERROR;
481
 
                }
482
 
                
483
 
                if (add_error_code(res, error_code) != 0) {
484
 
#ifdef EXTRA_DEBUG
485
 
                        LOG(L_DBG, "DEBUG: stun_create_response: failed to add error code\n");
486
 
#endif
487
 
                        return FATAL_ERROR;
488
 
                }
489
 
                
490
 
                if (unknown != NULL) {
491
 
                        if (add_unknown_attr(res, unknown) != 0) {
492
 
#ifdef EXTRA_DEBUG
493
 
                                LOG(L_DBG, "DEBUG: stun_create_response: failed to add unknown attribute\n");
494
 
#endif
495
 
                                return FATAL_ERROR;
496
 
                        }
497
 
                } 
498
 
        }
499
 
        
500
 
        if (req->old == 0) {
501
 
                /* 
502
 
                 * add optional information about server; attribute SOFTWARE is part of 
503
 
                 * rfc5389.txt
504
 
                 * */
505
 
                if (stun_add_common_text_attr(res, SOFTWARE_ATTR, SERVER_HDR, PAD4)!=0) {
506
 
#ifdef EXTRA_DEBUG
507
 
                        LOG(L_DBG, "DEBUG: stun_create_response: failed to add common text attribute\n");
508
 
#endif
509
 
                        return FATAL_ERROR;
510
 
                }
511
 
        }       
512
 
        
513
 
        res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
514
 
        memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
515
 
               sizeof(USHORT_T));
516
 
        
517
 
        return 0;
518
 
}
519
 
 
520
 
/*
521
 
 * add_unknown_attr()
522
 
 *                      - res: response representation
523
 
 *                      - unknown: link list of unknown attributes
524
 
 * 
525
 
 * The function add_unknown_attr ensures copy of link list of unknown 
526
 
 * attributes into response buffer.
527
 
 * 
528
 
 * Return value:        0       if there is no environment error
529
 
 *                                      -1      if there is some enviroment error such as insufficiency
530
 
 *                                              of memory
531
 
 * 
532
 
 */
533
 
int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown)
534
 
{
535
 
        struct stun_attr attr;
536
 
        struct stun_unknown_att* tmp_unknown;
537
 
        UINT_T          counter;
538
 
        USHORT_T        orig_len;
539
 
 
540
 
        counter = 0;
541
 
        orig_len = res->msg.buf.len;
542
 
        tmp_unknown = unknown;
543
 
        
544
 
        attr.type = htons(UNKNOWN_ATTRIBUTES_ATTR);
545
 
        attr.len = htons(0);
546
 
        
547
 
        if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
548
 
#ifdef EXTRA_DEBUG
549
 
                LOG(L_DBG, "DEBUG: add_unknown_attr: failed to copy buffer\n");
550
 
#endif
551
 
                return FATAL_ERROR;
552
 
        }
553
 
        
554
 
        while (tmp_unknown != NULL) {
555
 
                if (buf_copy(&res->msg, (void *)&tmp_unknown->type, 
556
 
                                                                sizeof(USHORT_T)) != 0) {
557
 
#ifdef EXTRA_DEBUG
558
 
                        LOG(L_DBG, "DEBUG: add_unknown_attr: failed to copy unknown attribute\n");
559
 
#endif
560
 
                        return FATAL_ERROR;
561
 
                }
562
 
                tmp_unknown = tmp_unknown->next;
563
 
                ++counter;
564
 
        }
565
 
        
566
 
        attr.len = htons(res->msg.buf.len - orig_len);
567
 
        memcpy(&res->msg.buf.s[orig_len], (void *)&attr, sizeof(struct stun_attr));
568
 
        
569
 
        /* check if there is an odd number of unknown attributes and if yes, 
570
 
         * repeat one of them because of padding to 32
571
 
         */
572
 
        if (counter/2 != 0 && unknown != NULL) {
573
 
                if (buf_copy(&res->msg, (void *)&unknown->type, sizeof(USHORT_T))!=0) {
574
 
#ifdef EXTRA_DEBUG
575
 
                        LOG(L_DBG, "DEBUG: add_unknown_attr: failed to padd\n");
576
 
#endif
577
 
                        return FATAL_ERROR;
578
 
                }
579
 
        }       
580
 
        
581
 
        return 0;
582
 
}
583
 
 
584
 
/*
585
 
 * add_error_code()
586
 
 *                      - res: response representation
587
 
 *                      - error_code: value of error type
588
 
 * 
589
 
 * The function add_error_code ensures copy of link list of unknown 
590
 
 * attributes into response buffer.
591
 
 * 
592
 
 * Return value:        0       if there is no environment error
593
 
 *                                      -1      if there is some enviroment error such as insufficiency
594
 
 *                                              of memory
595
 
 */
596
 
int add_error_code(struct stun_msg* res, USHORT_T error_code)
597
 
{
598
 
        struct stun_attr attr;
599
 
        USHORT_T        orig_len;
600
 
        USHORT_T        two_bytes;
601
 
        int                     text_pad;
602
 
        char            err[2];
603
 
        
604
 
        orig_len = res->msg.buf.len;
605
 
        text_pad = 0;
606
 
        
607
 
        /* the type and length will be copy as last one because of unknown length*/
608
 
        if (res->msg.buf.len < sizeof(struct stun_attr)) {
609
 
                if (reallock_buffer(&res->msg, sizeof(struct stun_attr)) != 0) {
610
 
#ifdef EXTRA_DEBUG
611
 
                        LOG(L_DBG, "DEBUG: add_error_code: failed to reallocate buffer\n");
612
 
#endif
613
 
                        return FATAL_ERROR;
614
 
                }
615
 
        }
616
 
        res->msg.buf.len += sizeof(struct stun_attr);
617
 
        res->msg.empty -= sizeof(struct stun_attr);
618
 
        
619
 
        /* first two bytes are empty */
620
 
        two_bytes = 0x0000;
621
 
        
622
 
        if (buf_copy(&res->msg, (void *) &two_bytes, sizeof(USHORT_T)) != 0) {
623
 
#ifdef EXTRA_DEBUG
624
 
                LOG(L_DBG, "DEBUG: add_error_code: failed to copy buffer\n");
625
 
#endif
626
 
                return FATAL_ERROR;
627
 
        }
628
 
        
629
 
        err[0] = error_code / 100;
630
 
        err[1] = error_code % 100;
631
 
        if (buf_copy(&res->msg, (void *) err, sizeof(UCHAR_T)*2) != 0) {
632
 
                return FATAL_ERROR;
633
 
        }
634
 
        
635
 
        switch (error_code) {
636
 
                case TRY_ALTERNATE_ERR:
637
 
                        text_pad = copy_str_to_buffer(res, TRY_ALTERNATE_TXT, PAD4); 
638
 
                        break;
639
 
                case BAD_REQUEST_ERR:
640
 
                        text_pad = copy_str_to_buffer(res, BAD_REQUEST_TXT, PAD4); 
641
 
                        break;
642
 
                case UNAUTHORIZED_ERR:
643
 
                        text_pad = copy_str_to_buffer(res, UNAUTHORIZED_TXT, PAD4); 
644
 
                        break;
645
 
                case UNKNOWN_ATTRIBUTE_ERR:
646
 
                        text_pad = copy_str_to_buffer(res, UNKNOWN_ATTRIBUTE_TXT, PAD4);
647
 
                        break;
648
 
                case STALE_CREDENTIALS_ERR:
649
 
                        text_pad = copy_str_to_buffer(res, STALE_CREDENTIALS_TXT, PAD4); 
650
 
                        break;
651
 
                case INTEGRITY_CHECK_ERR:
652
 
                        text_pad = copy_str_to_buffer(res, INTEGRITY_CHECK_TXT, PAD4); 
653
 
                        break;
654
 
                case MISSING_USERNAME_ERR:
655
 
                        text_pad = copy_str_to_buffer(res, MISSING_USERNAME_TXT, PAD4); 
656
 
                        break;
657
 
                case USE_TLS_ERR:
658
 
                        text_pad = copy_str_to_buffer(res, USE_TLS_TXT, PAD4); 
659
 
                        break;
660
 
                case MISSING_REALM_ERR:
661
 
                        text_pad = copy_str_to_buffer(res, MISSING_REALM_TXT, PAD4); 
662
 
                        break;
663
 
                case MISSING_NONCE_ERR:
664
 
                        text_pad = copy_str_to_buffer(res, MISSING_NONCE_TXT, PAD4); 
665
 
                        break;
666
 
                case UNKNOWN_USERNAME_ERR:
667
 
                        text_pad = copy_str_to_buffer(res, UNKNOWN_USERNAME_TXT, PAD4); 
668
 
                        break;
669
 
                case STALE_NONCE_ERR:
670
 
                        text_pad = copy_str_to_buffer(res, STALE_NONCE_TXT, PAD4);
671
 
                        break;
672
 
                case SERVER_ERROR_ERR:
673
 
                        text_pad = copy_str_to_buffer(res, SERVER_ERROR_TXT, PAD4); 
674
 
                        break;
675
 
                case GLOBAL_FAILURE_ERR:
676
 
                        text_pad = copy_str_to_buffer(res, GLOBAL_FAILURE_TXT, PAD4); 
677
 
                        break;
678
 
                default:
679
 
                        LOG(L_ERR, "ERROR: STUN: Unknown error code.\n");
680
 
                        break;
681
 
        }
682
 
        if (text_pad < 0) {
683
 
#ifdef EXTRA_DEBUG
684
 
                LOG(L_DBG, "DEBUG: add_error_code: text_pad is negative\n");
685
 
#endif
686
 
                goto error;
687
 
        }
688
 
        attr.type = htons(ERROR_CODE_ATTR);
689
 
        /* count length of "value" field -> without type and lehgth field */
690
 
        attr.len = htons(res->msg.buf.len - orig_len - 
691
 
                                         text_pad - sizeof(struct stun_attr));
692
 
        memcpy(&res->msg.buf.s[orig_len], (void *)&attr, sizeof(struct stun_attr));
693
 
        
694
 
        return 0;
695
 
 
696
 
error:
697
 
        return FATAL_ERROR;
698
 
}
699
 
 
700
 
/*
701
 
 * copy_str_to_buffer()
702
 
 *                      - res: response representation
703
 
 *                      - data: text data, in our case almost text representation of error
704
 
 *                      - pad: the size of pad (for how much bytes the string should be 
705
 
 *                                 padded
706
 
 * 
707
 
 * The function copy_str_to_buffer ensures copy of text buffer into response
708
 
 * buffer.
709
 
 * 
710
 
 * Return value:        0       if there is no environment error
711
 
 *                                      -1      if there is some enviroment error such as insufficiency
712
 
 *                                              of memory
713
 
 */
714
 
int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad)
715
 
{
716
 
        USHORT_T        pad_len;
717
 
        UINT_T          data_len;
718
 
        UCHAR_T         empty[pad];
719
 
        
720
 
        data_len = strlen(data);
721
 
        memset(&empty, 0, pad);
722
 
        
723
 
        pad_len = (pad - data_len%pad) % pad;
724
 
        
725
 
        if (buf_copy(&res->msg, (void *) data, sizeof(UCHAR_T)*data_len) != 0) {
726
 
#ifdef EXTRA_DEBUG
727
 
                LOG(L_DBG, "DEBUG: copy_str_to_buffer: failed to copy buffer\n");
728
 
#endif
729
 
                return FATAL_ERROR;
730
 
        }
731
 
        
732
 
        if (pad_len != 0) {
733
 
                if (buf_copy(&res->msg, &empty, pad_len) != 0) {
734
 
#ifdef EXTRA_DEBUG
735
 
                        LOG(L_DBG, "DEBUG: copy_str_to_buffer: failed to pad\n");
736
 
#endif
737
 
                        return FATAL_ERROR;
738
 
                }       
739
 
        }
740
 
 
741
 
        return pad_len; 
742
 
}
743
 
 
744
 
/*
745
 
 * stun_add_address_attr()
746
 
 *                      - res: response representation
747
 
 *                      - af: address family
748
 
 *                      - port: port
749
 
 *                      - ip_addr: represent both IPv4 and IPv6, the differences is in 
750
 
 *                      length  
751
 
 *                      - type: type of attribute
752
 
 *                      - do_xor: if the port should be XOR-ed or not.
753
 
 * 
754
 
 * The function stun_add_address_attr ensures copy of any IP attribute into
755
 
 * response buffer.
756
 
 * 
757
 
 * Return value:        0       if there is no environment error
758
 
 *                                      -1      if there is some enviroment error such as insufficiency
759
 
 *                                              of memory
760
 
 */
761
 
int stun_add_address_attr(struct stun_msg* res, 
762
 
                                                UINT_T          af,
763
 
                                                USHORT_T        port,
764
 
                                                UINT_T*         ip_addr,
765
 
                                                USHORT_T        type,
766
 
                                                int do_xor)
767
 
{
768
 
        struct stun_attr attr;
769
 
        int              ip_struct_len;
770
 
#ifdef USE_IPV6
771
 
        UINT_T   id[IP_ADDR];
772
 
        int i;
773
 
#endif /* USE_IPV6 */ 
774
 
        
775
 
        ip_struct_len = 0;
776
 
        attr.type = htons(type);
777
 
        res->ip_addr.port = htons((do_xor) ? (port ^ MAGIC_COOKIE_2B) : port);
778
 
        switch(af) {
779
 
                case AF_INET:
780
 
                        ip_struct_len = sizeof(struct stun_ip_addr) - 3*sizeof(UINT_T);
781
 
                        res->ip_addr.family = htons(IPV4_FAMILY);
782
 
                        memcpy(res->ip_addr.ip, ip_addr, IPV4_LEN);
783
 
                        res->ip_addr.ip[0] = (do_xor) ? 
784
 
                                res->ip_addr.ip[0] ^ htonl(MAGIC_COOKIE) : res->ip_addr.ip[0];
785
 
                        break;
786
 
#ifdef USE_IPV6
787
 
                case AF_INET6:
788
 
                        ip_struct_len = sizeof(struct stun_ip_addr);
789
 
                        res->ip_addr.family = htons(IPV6_FAMILY);
790
 
                        memcpy(&res->ip_addr.ip, ip_addr, IPV6_LEN);
791
 
                        memcpy(id, &res->hdr.id, sizeof(struct transaction_id));
792
 
                        for (i=0; i<IP_ADDR; i++) {
793
 
                                res->ip_addr.ip[i] = (do_xor) ? 
794
 
                                                        res->ip_addr.ip[i] ^ id[i] : res->ip_addr.ip[i];
795
 
                        }
796
 
                        break;
797
 
#endif /* USE_IPV6 */ 
798
 
                default:
799
 
                        break;
800
 
        }
801
 
        
802
 
        attr.len = htons(ip_struct_len);
803
 
        
804
 
        /* copy type and attribute's length */ 
805
 
        if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
806
 
                return FATAL_ERROR;
807
 
        }
808
 
        
809
 
        /* copy family, port and IP */
810
 
        if (buf_copy(&res->msg, (void *) &res->ip_addr, ip_struct_len) != 0) {
811
 
                return FATAL_ERROR;
812
 
        }
813
 
 
814
 
        return 0;
815
 
}
816
 
 
817
 
/*
818
 
 * stun_alloc_unknown_attr()
819
 
 *                      - type: type of unknown attribute
820
 
 * 
821
 
 * The function stun_alloc_unknown_attr ensures allocationg new element for
822
 
 * the link list of unknown attributes.
823
 
 * 
824
 
 * Return value: pointer to new element of link list in positive case
825
 
 *                               NULL if there is some enviroment error such as insufficiency
826
 
 *                                              of memory
827
 
 */
828
 
struct stun_unknown_att* stun_alloc_unknown_attr(USHORT_T type)
829
 
{
830
 
        struct stun_unknown_att* attr;
831
 
 
832
 
        attr = (struct stun_unknown_att *) pkg_malloc(sizeof(struct stun_unknown_att));
833
 
        if (attr == NULL) {
834
 
                LOG(L_ERR, "ERROR: STUN: out of memory\n");
835
 
                return NULL;
836
 
        }
837
 
        
838
 
        attr->type = type;
839
 
        attr->next = NULL;
840
 
        
841
 
        return attr;
842
 
}
843
 
 
844
 
/*
845
 
 * stun_delete_unknown_attrs()
846
 
 *                      - unknown: link list of unknown attributes
847
 
 * 
848
 
 * The function stun_delete_unknown_attrs ensures deleting of link list
849
 
 * 
850
 
 * Return value: none
851
 
 */
852
 
void stun_delete_unknown_attrs(struct stun_unknown_att* unknown)
853
 
{
854
 
        struct stun_unknown_att* tmp_unknown;
855
 
        
856
 
        if (unknown == NULL) {
857
 
                return;
858
 
        }
859
 
        
860
 
        while(unknown->next) {
861
 
                tmp_unknown = unknown->next;
862
 
                unknown->next = tmp_unknown->next;
863
 
                pkg_free(tmp_unknown);          
864
 
        }
865
 
        pkg_free(unknown);
866
 
}
867
 
 
868
 
/*
869
 
 * buf_copy()
870
 
 *                      - msg: buffer where the data will be copy to
871
 
 *                      - source: source data buffer
872
 
 *                      - len: number of bytes that should be copied
873
 
 * 
874
 
 * The function buf_copy copies "len" bytes from source into msg buffer
875
 
 * 
876
 
 * Return value:        0       if there is no environment error
877
 
 *                                      -1      if there is some enviroment error such as insufficiency
878
 
 *                                              of memory
879
 
 */
880
 
int buf_copy(struct stun_buffer* msg, void* source, UINT_T len)
881
 
{
882
 
        if (msg->empty < len) {
883
 
                if (reallock_buffer(msg, len) != 0) {
884
 
                        return FATAL_ERROR;
885
 
                }
886
 
        }
887
 
        
888
 
        memcpy(&msg->buf.s[msg->buf.len], source, len);
889
 
        msg->buf.len += len;
890
 
        msg->empty -= len;
891
 
        
892
 
        return 0;
893
 
}
894
 
 
895
 
/*
896
 
 * reallock_buffer()
897
 
 *                      - buffer: original buffer
898
 
 *                      - len: represents minimum of bytes that must be available after 
899
 
 *                                      reallocation
900
 
 * 
901
 
 * The function reallock_buffer reallocks buffer. New buffer's length will be 
902
 
 * original length plus bigger from len and STUN_MSG_LEN constant.
903
 
 * 
904
 
 * Return value:        0       if there is no environment error
905
 
 *                                      -1      if there is some enviroment error such as insufficiency
906
 
 *                                              of memory
907
 
 */
908
 
int reallock_buffer(struct stun_buffer* buffer, UINT_T len)
909
 
{
910
 
        char*   tmp_buf;
911
 
        UINT_T  new_len;
912
 
        
913
 
        new_len = (STUN_MSG_LEN < len) ? STUN_MSG_LEN+len : STUN_MSG_LEN;
914
 
        
915
 
        tmp_buf = (char *) pkg_realloc(buffer->buf.s, 
916
 
                                                                   buffer->buf.len + buffer->empty + new_len);
917
 
        if (tmp_buf == 0) {
918
 
                LOG(L_ERR, "ERROR: STUN: out of memory\n");
919
 
                return FATAL_ERROR;
920
 
        }
921
 
        
922
 
        buffer->buf.s = tmp_buf;
923
 
        buffer->empty += new_len;
924
 
 
925
 
        return 0;
926
 
}
927
 
 
928
 
/*
929
 
 * clean_memory()
930
 
 *                      - res: structure representing response message
931
 
 *                      - unknown: link list of unknown attributes
932
 
 * 
933
 
 * The function clean_memory should free dynamic allocated memory.
934
 
 * 
935
 
 * Return value: none
936
 
 */
937
 
void clean_memory(struct stun_msg* req,
938
 
                                struct stun_msg* res,   struct stun_unknown_att* unknown)
939
 
{
940
 
#ifdef DYN_BUF
941
 
        pkg_free(req->msg.buf.s);
942
 
#endif
943
 
 
944
 
        if (res->msg.buf.s != NULL) {
945
 
                pkg_free(res->msg.buf.s);
946
 
        }
947
 
        stun_delete_unknown_attrs(unknown);
948
 
}
949
 
 
950
 
/*
951
 
 * stun_add_common_integer_attr()
952
 
 *                      - res: structure representing response
953
 
 *                      - type: type of attribute
954
 
 *                      - value: attribute's value
955
 
 * 
956
 
 * The function stun_add_common_integer_attr copy attribute with integer value 
957
 
 * into response buffer.
958
 
 * 
959
 
 * Return value:        0       if there is no environment error
960
 
 *                                      -1      if there is some enviroment error such as insufficiency
961
 
 *                                              of memory
962
 
 */
963
 
int stun_add_common_integer_attr(struct stun_msg* res, 
964
 
                                                                 USHORT_T type, 
965
 
                                                                 UINT_T value)
966
 
{
967
 
        struct stun_attr attr;
968
 
        
969
 
        attr.type = htons(type);
970
 
        attr.len = htons(sizeof(UINT_T));
971
 
        
972
 
        if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
973
 
                return FATAL_ERROR;
974
 
        }
975
 
        
976
 
        value = htonl(value);
977
 
        if (buf_copy(&res->msg, (void *) &value, sizeof(UINT_T)) != 0) {
978
 
                return FATAL_ERROR;
979
 
        }
980
 
        
981
 
        return 0;
982
 
}
983
 
 
984
 
/*
985
 
 * stun_add_common_text_attr()
986
 
 *                      - res: structure representing response
987
 
 *                      - type: type of attribute
988
 
 *                      - value: attribute's value
989
 
 *                      - pad: size of pad
990
 
 * 
991
 
 * The function stun_add_common_text_attr copy attribute with string value 
992
 
 * into response buffer.
993
 
 * 
994
 
 * Return value:        0       if there is no environment error
995
 
 *                                      -1      if there is some enviroment error such as insufficiency
996
 
 *                                              of memory
997
 
 */
998
 
int stun_add_common_text_attr(struct stun_msg* res, 
999
 
                                                          USHORT_T type, 
1000
 
                                                          char* value, 
1001
 
                                                          USHORT_T pad)
1002
 
{
1003
 
        struct stun_attr attr;
1004
 
        
1005
 
        if (value == NULL) {
1006
 
                LOG(L_INFO, "INFO: stun_add_common_text_attr: value is NULL\n");
1007
 
                return 0;
1008
 
        }
1009
 
        
1010
 
        attr.type = htons(type);
1011
 
        attr.len = htons(strlen(value));
1012
 
        
1013
 
        if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
1014
 
                return FATAL_ERROR;
1015
 
        }
1016
 
        
1017
 
        if (copy_str_to_buffer(res, value, pad) < 0) {
1018
 
                return FATAL_ERROR;
1019
 
        }
1020
 
        
1021
 
        return 0;
1022
 
        
1023
 
}
1024
 
 
1025
 
#endif  /* USE_STUN */