1 /*
2 * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
3 * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
4 *
5 * The initial version of this code was written by Dragos Vingarzan
6 * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
7 * Fruanhofer Institute. It was and still is maintained in a separate
8 * branch of the original SER. We are therefore migrating it to
9 * Kamailio/SR and look forward to maintaining it from here on out.
10 * 2011/2012 Smile Communications, Pty. Ltd.
11 * ported/maintained/improved by
12 * Jason Penton (jason(dot)penton(at)smilecoms.com and
13 * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
14 * effort to add full IMS support to Kamailio/SR using a new and
15 * improved architecture
16 *
17 * NB: Alot of this code was originally part of OpenIMSCore,
18 * FhG Fokus.
19 * Copyright (C) 2004-2006 FhG Fokus
20 * Thanks for great work! This is an effort to
21 * break apart the various CSCF functions into logically separate
22 * components. We hope this will drive wider use. We also feel
23 * that in this way the architecture is more complete and thereby easier
24 * to manage in the Kamailio/SR environment
25 *
26 * This file is part of Kamailio, a free SIP server.
27 *
28 * Kamailio is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * (at your option) any later version
32 *
33 * Kamailio is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
41 *
42 */
43
44 #include "diameter.h"
45 #include "diameter_api.h"
46
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include <netinet/in.h>
51
52 #include "utils.h"
53 #include "globals.h"
54
55 #include "config.h"
56 #include "peermanager.h"
57 #include "diameter_epc_code_cmd.h"
58
59 extern dp_config *config; /**< Configuration for this diameter peer */
60
61
62 /**
63 * This function encodes a AAAMessage to its network representation (encoder).
64 * From a AAAMessage structure, a buffer to be send is built.
65 * @param msg - the message to encode
66 * @returns 1 on success, -1 on error
67 * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
68 */
AAABuildMsgBuffer(AAAMessage * msg)69 AAAReturnCode AAABuildMsgBuffer( AAAMessage *msg )
70 {
71 unsigned char *p;
72 AAA_AVP *avp;
73
74 /* first let's comput the length of the buffer */
75 msg->buf.len = AAA_MSG_HDR_SIZE; /* AAA message header size */
76 /* count and add the avps */
77 for(avp=msg->avpList.head;avp;avp=avp->next) {
78 msg->buf.len += AVP_HDR_SIZE(avp->flags)+ to_32x_len( avp->data.len );
79 //LM_DBG("AVP code: %d, data %.*s\n", avp->code, avp->data.len, avp->data.s);
80 }
81
82 LM_DBG("AAABuildMsgBuffer(): len=%d\n",msg->buf.len);
83 /* allocate some memory */
84 msg->buf.s = (char*)shm_malloc( msg->buf.len );
85 if (!msg->buf.s) {
86 LM_ERR("AAABuildMsgBuffer: no more free memory!\n");
87 goto error;
88 }
89 memset(msg->buf.s, 0, msg->buf.len);
90
91 /* fill in the buffer */
92 p = (unsigned char*)msg->buf.s;
93 /* DIAMETER HEADER */
94 /* message length */
95 ((unsigned int*)p)[0] =htonl(msg->buf.len);
96 /* Diameter Version */
97 *p = 1;
98 p += VER_SIZE + MESSAGE_LENGTH_SIZE;
99 /* command code */
100 ((unsigned int*)p)[0] = htonl(msg->commandCode);
101 /* flags */
102 *p = (unsigned char)msg->flags;
103 p += FLAGS_SIZE + COMMAND_CODE_SIZE;
104 /* application-ID */
105 ((unsigned int*)p)[0] = htonl(msg->applicationId);
106 p += APPLICATION_ID_SIZE;
107 /* hop by hop id */
108 ((unsigned int*)p)[0] = htonl(msg->hopbyhopId);
109 p += HOP_BY_HOP_IDENTIFIER_SIZE;
110 /* end to end id */
111 ((unsigned int*)p)[0] = htonl(msg->endtoendId);
112 p += END_TO_END_IDENTIFIER_SIZE;
113
114 /* AVPS */
115 for(avp=msg->avpList.head;avp;avp=avp->next) {
116 /* AVP HEADER */
117 /* avp code */
118 set_4bytes(p,avp->code);
119 p +=4;
120 /* flags */
121 (*p++) = (unsigned char)avp->flags;
122 /* avp length */
123 set_3bytes(p, (AVP_HDR_SIZE(avp->flags)+avp->data.len) );
124 p += 3;
125 /* vendor id */
126 if ((avp->flags&0x80)!=0) {
127 set_4bytes(p,avp->vendorId);
128 p +=4;
129 }
130 /* data */
131 memcpy( p, avp->data.s, avp->data.len);
132 p += to_32x_len( avp->data.len );
133 }
134
135 if ((char*)p-msg->buf.s!=msg->buf.len) {
136 LM_ERR("BUG: build_buf_from_msg: mismatch between len and buf!\n");
137 shm_free( msg->buf.s );
138 msg->buf.s = 0;
139 msg->buf.len = 0;
140 goto error;
141 }
142
143 return 1;
144 error:
145 return -1;
146 }
147
148
149
150
151 /**
152 * Allocates a new AAAMessage.
153 * @param commandCode - the command code for this message
154 * @param applicationId - application id to be set
155 * @param sessionId - session id to be set
156 * @param request - if you want to create a response, put the request here. If you want a
157 * request, call with NULL
158 * @returns the AAAMessage* or NULL on error
159 * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
160 */
AAANewMessage(AAACommandCode commandCode,AAAApplicationId applicationId,AAASession * session,AAAMessage * request)161 AAAMessage *AAANewMessage(
162 AAACommandCode commandCode,
163 AAAApplicationId applicationId,
164 AAASession *session,
165 AAAMessage *request)
166 {
167 AAAMessage *msg;
168 AAA_AVP *avp;
169 AAA_AVP *avp_t;
170 str *sessionId=0;
171 #if 0
172 unsigned int code;
173 #endif
174 // str dest_host={"?",1};
175 str dest_realm={"?",1};
176
177 msg = 0;
178 if (!session||!session->id.s) {
179 if (request){
180 /* copy old session id from AVP */
181 if (request->sessionId)
182 sessionId = &(request->sessionId->data);
183 }else{
184 if (commandCode!=Code_DW)
185 LM_DBG("AAANewMessage: param session received null and it's a request!!\n");
186 }
187 }else{
188 sessionId = &(session->id);
189 }
190
191 /* allocated a new AAAMessage structure and set it to 0 */
192 msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage));
193 if (!msg) {
194 LM_ERR("AAANewMessage: no more free memory!!\n");
195 goto error;
196 }
197 memset(msg,0,sizeof(AAAMessage));
198
199 /* command code */
200 msg->commandCode = commandCode;
201 /* application ID */
202 msg->applicationId = applicationId;
203
204 /*add session ID */
205 if (sessionId){
206 avp = AAACreateAVP( 263, 0, 0, sessionId->s, sessionId->len,
207 AVP_DUPLICATE_DATA);
208 if ( !avp || AAAAddAVPToMessage(msg,avp,0)!=AAA_ERR_SUCCESS) {
209 LM_ERR("AAANewMessage: cannot create/add Session-Id avp\n");
210 if (avp) AAAFreeAVP( &avp );
211 goto error;
212 }
213 msg->sessionId = avp;
214 }
215
216 /* add origin host AVP */
217 /* changed by cristian to comply with rfc3588:
218 * 6.3. Origin-Host AVP
219 *
220 * The Origin-Host AVP (AVP Code 264) is of type
221 * DiameterIdentity... */
222 avp = AAACreateAVP( 264, 0, 0, config->fqdn.s, config->fqdn.len,
223 AVP_DUPLICATE_DATA);
224 if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
225 LM_ERR("AAANewMessage: cannot create/add Origin-Host avp\n");
226 if (avp) AAAFreeAVP( &avp );
227 goto error;
228 }
229 msg->orig_host = avp;
230 /* add origin realm AVP */
231 avp = AAACreateAVP( 296, 0, 0, config->realm.s, config->realm.len,
232 AVP_DUPLICATE_DATA);
233 if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
234 LM_ERR("AAANewMessage: cannot create/add Origin-Realm avp\n");
235 if (avp) AAAFreeAVP( &avp );
236 goto error;
237 }
238 msg->orig_realm = avp;
239
240 if (!request) {
241 /* it's a new request -> set the flag */
242 msg->flags = 0x80;
243 } else {
244 /* link the incoming peer to the answer */
245 msg->in_peer = request->in_peer;
246 /* set the P flag as in request */
247 msg->flags |= request->flags&0x40;
248 /**/
249 msg->endtoendId = request->endtoendId;
250 msg->hopbyhopId = request->hopbyhopId;
251
252
253 //TODO: aon:move this information in the AAASession structure, do not add these fields for
254
255 if (msg->commandCode==Code_CE||msg->commandCode==Code_DP||msg->commandCode==Code_DW ||
256 msg->commandCode==Diameter_CCR || msg->commandCode==Diameter_RAR){
257 // Don't add Destination Host/Realm because some stacks are way to picky and will just refuse it
258 }else{
259
260 /* Mirror the old originhost/realm to destinationhost/realm*/
261 //avp = AAAFindMatchingAVP(request,0,AVP_Origin_Host,0,0);
262 //if (avp) dest_host = avp->data;
263 /* add destination host and destination realm */
264 //avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0,
265 // dest_host.s,dest_host.len,AVP_DUPLICATE_DATA);
266 //if (!avp) {
267 // LM_ERR("ERR:AAANewMessage: Failed creating Destination Host avp\n");
268 // goto error;
269 // }
270 // if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
271 // LM_ERR("ERR:AAANewMessage: Failed adding Destination Host avp to message\n");
272 // AAAFreeAVP(&avp);
273 // goto error;
274 // }
275
276 avp = AAAFindMatchingAVP(request,0,AVP_Origin_Realm,0,0);
277 if (avp) dest_realm = avp->data;
278 avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0,
279 dest_realm.s,dest_realm.len,AVP_DUPLICATE_DATA);
280 if (!avp) {
281 LM_ERR("ERR:AAANewMessage: Failed creating Destination Realm avp\n");
282 goto error;
283 }
284 if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
285 LM_ERR("ERR:AAANewMessage: Failed adding Destination Realm avp to message\n");
286 AAAFreeAVP(&avp);
287 goto error;
288 }
289 }
290
291 msg->res_code=0;
292 /* mirror all the proxy-info avp in the same order */
293 avp_t = request->avpList.head;
294 while ( (avp_t=AAAFindMatchingAVP
295 (request,avp_t,284,0,AAA_FORWARD_SEARCH))!=0 ) {
296 if ( (avp=AAACloneAVP(avp_t,1))==0 || AAAAddAVPToMessage( msg, avp,
297 msg->avpList.tail)!=AAA_ERR_SUCCESS )
298 goto error;
299 }
300 }
301
302 return msg;
303 error:
304 LM_ERR("AAANewMessage: failed to create a new AAA message!\n");
305 AAAFreeMessage(&msg);
306 return 0;
307 }
308
309 /**
310 * Create a Diameter Request.
311 * @param app_id - application id to be set
312 * @param command_code - the command code for this message
313 * @param flags - flags to be set
314 * @param sessId - session id to be set
315 * @returns the AAAMessage* or NULL on error
316 */
AAACreateRequest(AAAApplicationId app_id,AAACommandCode command_code,AAAMsgFlag flags,AAASession * session)317 AAAMessage *AAACreateRequest(AAAApplicationId app_id,
318 AAACommandCode command_code,
319 AAAMsgFlag flags,
320 AAASession *session)
321 {
322 AAAMessage *msg;
323 AAA_AVP *avp;
324
325 msg = AAANewMessage(command_code,app_id,session,0);
326 if (!msg) return 0;
327 msg->hopbyhopId = next_hopbyhop();
328 msg->endtoendId = next_endtoend();
329 msg->flags |= flags;
330
331 if(session){
332 /* add destination host and destination realm */
333 /*if(session->dest_host.s){//TODO: check spec about removing this across the board (jason)
334 avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0,
335 session->dest_host.s,session->dest_host.len,AVP_DUPLICATE_DATA);
336 if (!avp) {
337 LM_ERR("ERR:AAACreateRequest: Failed creating Destination Host avp\n");
338 goto error;
339 }
340 if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
341 LM_ERR("ERR:AAACreateRequest: Failed adding Destination Host avp to message\n");
342 AAAFreeAVP(&avp);
343 goto error;
344 }
345 }*/
346
347 if(session->dest_realm.s){
348 avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0,
349 session->dest_realm.s,session->dest_realm.len,AVP_DUPLICATE_DATA);
350 if (!avp) {
351 LM_ERR("ERR:AAACreateRequest: Failed creating Destination Realm avp\n");
352 goto error;
353 }
354 if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
355 LM_ERR("ERR:AAACreateRequest: Failed adding Destination Realm avp to message\n");
356 AAAFreeAVP(&avp);
357 goto error;
358 }
359 }
360 }
361
362 return msg;
363 error:
364 AAAFreeMessage(&msg);
365 return NULL;
366 }
367
368 /**
369 * Create a Diameter Response to a given Request.
370 * @param request - the request that this response is for
371 * @returns the AAAMessage* or NULL on error
372 */
AAACreateResponse(AAAMessage * request)373 AAAMessage *AAACreateResponse(AAAMessage *request)
374 {
375 AAAMessage *msg;
376 msg = AAANewMessage(request->commandCode,request->applicationId,0,request);
377
378 return msg;
379 }
380
381
382 /**
383 * Frees a AVP List and all the members
384 * @param avpList - list to be freed
385 * @returns AAA_ERR_SUCCESS
386 */
AAAFreeAVPList(AAA_AVP_LIST * avpList)387 AAAReturnCode AAAFreeAVPList(AAA_AVP_LIST *avpList)
388 {
389 AAA_AVP *avp_t;
390 AAA_AVP *avp;
391 /* free the avp list */
392 avp = avpList->head;
393 while (avp) {
394 avp_t = avp;
395 avp = avp->next;
396 /*free the avp*/
397 AAAFreeAVP(&avp_t);
398 }
399 avpList->head = 0;
400 avpList->tail = 0;
401 return AAA_ERR_SUCCESS;
402 }
403
404 /**
405 * Frees completely a message allocated through AAANewMessage()
406 * @param msg - pointer to the pointer containing the message.
407 * @returns AAA_ERR_SUCCESS
408 */
AAAFreeMessage(AAAMessage ** msg)409 AAAReturnCode AAAFreeMessage(AAAMessage **msg)
410 {
411 LM_DBG("AAAFreeMessage: Freeing message (%p) %d\n",*msg,(*msg)->commandCode);
412 /* param check */
413 if (!msg || !(*msg))
414 goto done;
415
416 /* free the avp list */
417 AAAFreeAVPList(&((*msg)->avpList));
418
419 /* free the buffer (if any) */
420 if ( (*msg)->buf.s )
421 shm_free( (*msg)->buf.s );
422
423 /* free the AAA msg */
424 shm_free(*msg);
425 *msg = 0;
426
427 done:
428 return AAA_ERR_SUCCESS;
429 }
430
431 /**
432 * Sets the proper result_code into the Result-Code AVP; ths avp must already
433 * exists into the reply messge.
434 * @param message - the message to set the Result-Code to
435 * @param resultCode - code to set as result
436 * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
437 */
AAASetMessageResultCode(AAAMessage * message,AAAResultCode resultCode)438 AAAReturnCode AAASetMessageResultCode(
439 AAAMessage *message,
440 AAAResultCode resultCode)
441 {
442 if ( !is_req(message) && message->res_code) {
443 *((unsigned int*)(message->res_code->data.s)) = htonl(resultCode);
444 return AAA_ERR_SUCCESS;
445 }
446 return AAA_ERR_FAILURE;
447 }
448
449
450
451 /**
452 * This function convert message from the network format to the AAAMessage structure (decoder).
453 * @param source - the source char buffer
454 * @param sourceLen - the length of the input buffer
455 * @param attach_buf - whether to attach the input buffer to the message
456 * @returns the AAAMessage* or NULL on error
457 * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
458 */
AAATranslateMessage(unsigned char * source,unsigned int sourceLen,int attach_buf)459 AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen,
460 int attach_buf)
461 {
462 unsigned char *ptr;
463 AAAMessage *msg = 0;
464 unsigned char version;
465 unsigned int msg_len;
466 AAA_AVP *avp;
467 unsigned int avp_code;
468 unsigned char avp_flags;
469 unsigned int avp_len;
470 unsigned int avp_vendorID;
471 unsigned int avp_data_len;
472
473 /* check the params */
474 if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) {
475 LM_ERR("AAATranslateMessage: invalid buffered received!\n");
476 goto error;
477 }
478
479 /* inits */
480 msg = 0;
481 avp = 0;
482 ptr = source;
483
484 /* alloc a new message structure */
485 msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage));
486 if (!msg) {
487 LM_ERR("AAATranslateMessage: no more free memory!!\n");
488 goto error;
489 }
490 memset(msg,0,sizeof(AAAMessage));
491
492 /* get the version */
493 version = (unsigned char)*ptr;
494 ptr += VER_SIZE;
495 if (version!=1) {
496 LM_ERR("AAATranslateMessage: invalid version [%d]in "
497 "AAA msg\n",version);
498 goto error;
499 }
500
501 /* message length */
502 msg_len = get_3bytes( ptr );
503 ptr += MESSAGE_LENGTH_SIZE;
504 if (msg_len>sourceLen) {
505 LM_ERR("AAATranslateMessage: AAA message len [%d] bigger then"
506 " buffer len [%d]\n",msg_len,sourceLen);
507 goto error;
508 }
509
510 /* command flags */
511 msg->flags = *ptr;
512 ptr += FLAGS_SIZE;
513
514 /* command code */
515 msg->commandCode = get_3bytes( ptr );
516 ptr += COMMAND_CODE_SIZE;
517
518 /* application-Id */
519 msg->applicationId = get_4bytes( ptr );
520 ptr += APPLICATION_ID_SIZE;
521
522 /* Hop-by-Hop-Id */
523 msg->hopbyhopId = ntohl(*((unsigned int*)ptr));
524 ptr += HOP_BY_HOP_IDENTIFIER_SIZE;
525
526 /* End-to-End-Id */
527 msg->endtoendId = ntohl(*((unsigned int*)ptr));
528 ptr += END_TO_END_IDENTIFIER_SIZE;
529
530 /* start decoding the AVPS */
531 while (ptr < source+msg_len) {
532 if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){
533 LM_ERR("AAATranslateMessage: source buffer to short!! "
534 "Cannot read the whole AVP header!\n");
535 goto error;
536 }
537 /* avp code */
538 avp_code = get_4bytes( ptr );
539 ptr += AVP_CODE_SIZE;
540 /* avp flags */
541 avp_flags = (unsigned char)*ptr;
542 ptr += AVP_FLAGS_SIZE;
543 /* avp length */
544 avp_len = get_3bytes( ptr );
545 ptr += AVP_LENGTH_SIZE;
546 if (avp_len<1) {
547 LM_ERR("AAATranslateMessage: invalid AVP len [%d]\n",
548 avp_len);
549 goto error;
550 }
551 /* avp vendor-ID */
552 avp_vendorID = 0;
553 if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) {
554 avp_vendorID = get_4bytes( ptr );
555 ptr += AVP_VENDOR_ID_SIZE;
556 }
557 /* data length */
558 avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags);
559 /*check the data length */
560 if ( source+msg_len<ptr+avp_data_len) {
561 LM_ERR("AAATranslateMessage: source buffer to short!! "
562 "Cannot read a whole data for AVP!\n");
563 goto error;
564 }
565
566 /* create the AVP */
567 avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, (char*) ptr,
568 avp_data_len, AVP_DONT_FREE_DATA);
569 if (!avp)
570 goto error;
571
572 /* link the avp into aaa message to the end */
573 AAAAddAVPToMessage( msg, avp, msg->avpList.tail);
574
575 ptr += to_32x_len( avp_data_len );
576 }
577
578 /* link the buffer to the message */
579 if (attach_buf) {
580 msg->buf.s = (char*) source;
581 msg->buf.len = msg_len;
582 }
583
584 msg->sessionId = AAAFindMatchingAVP(msg,0,AVP_Session_Id,0,0);
585
586 //AAAPrintMessage( msg );
587 return msg;
588 error:
589 LM_ERR("AAATranslateMessage: message conversion dropped!!\n");
590 AAAFreeMessage(&msg);
591 return 0;
592 }
593
594
595
596 /**
597 * print as debug all info contained by an aaa message + AVPs
598 * @param msg - the AAAMessage to print
599 * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
600 */
AAAPrintMessage(AAAMessage * msg)601 void AAAPrintMessage( AAAMessage *msg)
602 {
603 char buf[1024];
604 AAA_AVP *avp;
605
606 /* print msg info */
607 LM_DBG("AAA_MESSAGE - %p\n",msg);
608 LM_DBG("\tCode = %u\n",msg->commandCode);
609 LM_DBG("\tFlags = %x\n",msg->flags);
610
611 /*print the AVPs */
612 avp = msg->avpList.head;
613 while (avp) {
614 AAAConvertAVPToString(avp,buf,1024);
615 LM_DBG("\n%s\n",buf);
616 avp=avp->next;
617 }
618 }
619
620
621
622