Merge pull request #1707 from dunst0/fix/ims_diameter_server
[sip-router] / src / modules / ims_diameter_server / avp_helper.c
1 /*
2  *
3  * Copyright (C) 2016-2017 ng-voice GmbH, Carsten Bock, carsten@ng-voice.com
4  *
5  * This file is part of Kamailio, a free SIP server.
6  *
7  * Kamailio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version
11  *
12  * Kamailio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License 
18  * along with this program; if not, write to the Free Software 
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  * 
21  */
22
23 #include "../cdp/cdp_load.h"
24 #include "../cdp_avp/cdp_avp_mod.h"
25 #include "avp_helper.h"
26 #include "ims_diameter_server.h"
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <time.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include "cJSON.h"
35
36 #include "../../core/dprint.h"
37 #include "../../core/mem/mem.h"
38 #include "../../core/ut.h" 
39 #include "../../core/trim.h" 
40 #include "../../core/pvapi.h"
41 #include "../../core/dset.h"
42 #include "../../core/basex.h"
43
44 #define STRSIZE 8*1024
45 #define HEXDUMP "hexdump"
46
47 // ID of current message
48 static unsigned int current_msg_id = 0;
49 static unsigned int current_msg_id_repl = 0;
50
51 cJSON * avp2json(AAA_AVP *avp_t) {
52         int l, i;
53         AAA_AVP *avp_it;        
54         char dest[STRSIZE];
55
56         cJSON * avp, * array;
57
58         avp=cJSON_CreateObject();
59         LM_DBG("AVP(%p < %p >%p);code=%u,"
60                 "flags=%x;\nDataType=%u;VendorID=%u;DataLen=%u;\n",
61                 avp_t->prev,avp_t,avp_t->next,avp_t->code,avp_t->flags,
62                 avp_t->type,avp_t->vendorId,avp_t->data.len);
63         cJSON_AddNumberToObject(avp,"avpCode", avp_t->code);
64         cJSON_AddNumberToObject(avp,"vendorId", avp_t->vendorId);
65         cJSON_AddNumberToObject(avp,"DataType", avp_t->type);
66         cJSON_AddNumberToObject(avp,"Flags",    avp_t->flags);
67         memset(dest, 0, STRSIZE);
68         switch(avp_t->type) {
69                 case AAA_AVP_STRING_TYPE:
70                         snprintf(dest, STRSIZE, "%.*s", avp_t->data.len, avp_t->data.s);
71                         cJSON_AddStringToObject(avp, "string", dest);
72                         break;
73                 case AAA_AVP_INTEGER32_TYPE:
74                         cJSON_AddNumberToObject(avp,"int32", htonl(*((unsigned int*)avp_t->data.s)));
75                         break;
76                 case AAA_AVP_INTEGER64_TYPE:
77                         cJSON_AddNumberToObject(avp,"int64", htonl(*((unsigned int*)avp_t->data.s)));
78                         break;
79                 case AAA_AVP_ADDRESS_TYPE:
80                         i = 1;
81                         switch (avp_t->data.len) {
82                                 case 4: i=i*0;
83                                 case 6: i=i*2;
84                                         snprintf(dest, STRSIZE,"%d.%d.%d.%d",
85                                                         (unsigned char)avp_t->data.s[i+0],
86                                                         (unsigned char)avp_t->data.s[i+1],
87                                                         (unsigned char)avp_t->data.s[i+2],
88                                                         (unsigned char)avp_t->data.s[i+3]);
89                                         cJSON_AddStringToObject(avp, "address", dest);
90                                         break;
91                                 case 16: i=i*0;
92                                 case 18: i=i*2;
93                                         snprintf(dest, STRSIZE, "%x.%x.%x.%x.%x.%x.%x.%x",
94                                                         ((avp_t->data.s[i+0]<<8)+avp_t->data.s[i+1]),
95                                                         ((avp_t->data.s[i+2]<<8)+avp_t->data.s[i+3]),
96                                                         ((avp_t->data.s[i+4]<<8)+avp_t->data.s[i+5]),
97                                                         ((avp_t->data.s[i+6]<<8)+avp_t->data.s[i+7]),
98                                                         ((avp_t->data.s[i+8]<<8)+avp_t->data.s[i+9]),
99                                                         ((avp_t->data.s[i+10]<<8)+avp_t->data.s[i+11]),
100                                                         ((avp_t->data.s[i+12]<<8)+avp_t->data.s[i+13]),
101                                                         ((avp_t->data.s[i+14]<<8)+avp_t->data.s[i+15]));
102                                         cJSON_AddStringToObject(avp, "address", dest);
103                                         break;
104                         }
105                         break;
106                 case AAA_AVP_TIME_TYPE:
107                 default:
108                         LM_WARN("AAAConvertAVPToString: don't know how to print"
109                                         " this data type [%d] -> tryng hexa\n",avp_t->type);
110                 case AAA_AVP_DATA_TYPE:
111                         l = 0;
112                         for (i=0; i < avp_t->data.len; i++) {
113                                 l+=snprintf(dest+l,STRSIZE-l-1,"%02x", ((unsigned char*)avp_t->data.s)[i]);
114                         }
115                         cJSON_AddStringToObject(avp, "data", dest);
116                         if (avp_t->data.len == 4) {
117                                 cJSON_AddNumberToObject(avp,"int32", htonl(*((unsigned int*)avp_t->data.s)));
118                         }
119                         if (avp_t->data.len > 4) {
120                                 memset(dest, 0, STRSIZE);
121                                 l = snprintf(dest, STRSIZE, "%.*s", avp_t->data.len, avp_t->data.s);
122                                 LM_DBG("%.*s (%i/%i)\n", l, dest, l, (int)strlen(dest));
123                                 if (strlen(dest) > 0) {
124                                         cJSON_AddStringToObject(avp, "string", dest);
125                                 } else {
126                                         AAA_AVP_LIST list;
127                                         list = cdp_avp->cdp->AAAUngroupAVPS(avp_t->data);
128                                         array = cJSON_CreateArray();
129                                         avp_it = list.head;
130                                         while(avp_it) {
131                                                 LM_DBG("  AVP(%p < %p >%p);code=%u,"
132                                                         "flags=%x;\nDataType=%u;VendorID=%u;DataLen=%u;\n",
133                                                         avp_it->prev,avp_it,avp_it->next,avp_it->code,avp_it->flags,
134                                                         avp_it->type,avp_it->vendorId,avp_it->data.len);
135
136                                                 cJSON_AddItemToArray(array, avp2json(avp_it));
137
138                                                 avp_it = avp_it->next;
139                                         }
140                                         cJSON_AddItemToObject(avp, "list", array);
141                                         cdpb.AAAFreeAVPList(&list);
142                                 }
143                         }
144         }
145         return avp;
146 }
147
148 int AAAmsg2json(AAAMessage * request, str * dest) {
149         cJSON *root;
150         AAA_AVP *avp_t;
151         root=cJSON_CreateArray();
152
153         avp_t=request->avpList.head;
154         while(avp_t) {
155                 cJSON_AddItemToArray(root, avp2json(avp_t));
156                 avp_t = avp_t->next;
157         }
158
159         char * out = cJSON_Print(root);
160         cJSON_Delete(root);
161
162         if (dest->s) {
163                 pkg_free(dest->s);
164         }
165
166         dest->len = strlen(out);
167         dest->s = pkg_malloc(dest->len);
168         if (dest->s) {
169                 memcpy(dest->s, out, dest->len);
170                 free(out);
171         } else {
172                 LM_WARN("Failed to allocate %d bytes for the JSON\n", dest->len);
173                 free(out);
174                 return -1;
175         }
176         return 1;
177 }
178
179
180 int pv_get_request(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
181         if (msg->id != current_msg_id) {
182                 current_msg_id = msg->id;
183                 AAAmsg2json(request, &requestjson);
184         }
185         return pv_get_strval(msg, param, res, &requestjson);
186 }
187
188
189 /**
190  * Create and add an AVP to a Diameter message.
191  * @param m - Diameter message to add to
192  * @param d - the payload data
193  * @param len - length of the payload data
194  * @param avp_code - the code of the AVP
195  * @param flags - flags for the AVP
196  * @param vendorid - the value of the vendor id or 0 if none
197  * @param data_do - what to do with the data when done
198  * @param func - the name of the calling function, for debugging purposes
199  * @returns 1 on success or 0 on failure
200  */
201 int diameterserver_add_avp(AAAMessage *m, char *d, int len, int avp_code, int flags, int vendorid, int data_do, const char *func) {
202     AAA_AVP *avp;
203         if(m==NULL) {
204                 LM_ERR("invalid diamemter message parameter\n");
205                 return 0;
206         }
207     if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
208     avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
209     if (!avp) {
210         LM_ERR("%s: Failed creating avp\n", func);
211         return 0;
212     }
213     if (cdpb.AAAAddAVPToMessage(m, avp, m->avpList.tail) != AAA_ERR_SUCCESS) {
214         LM_ERR("%s: Failed adding avp to message\n", func);
215        cdpb.AAAFreeAVP(&avp);
216         return 0;
217     }
218     return 1;
219 }
220
221
222 /**
223  * Create and add an AVP to a list of AVPs.
224  * @param list - the AVP list to add to
225  * @param d - the payload data
226  * @param len - length of the payload data
227  * @param avp_code - the code of the AVP
228  * @param flags - flags for the AVP
229  * @param vendorid - the value of the vendor id or 0 if none
230  * @param data_do - what to do with the data when done
231  * @param func - the name of the calling function, for debugging purposes
232  * @returns 1 on success or 0 on failure
233  */
234 int diameterserver_add_avp_list(AAA_AVP_LIST *list, char *d, int len, int avp_code,
235         int flags, int vendorid, int data_do, const char *func) {
236     AAA_AVP *avp;
237     if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
238     avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
239     if (!avp) {
240         LM_ERR("%s: Failed creating avp\n", func);
241         return 0;
242     }
243     if (list->tail) {
244         avp->prev = list->tail;
245         avp->next = 0;
246         list->tail->next = avp;
247         list->tail = avp;
248     } else {
249         list->head = avp;
250         list->tail = avp;
251         avp->next = 0;
252         avp->prev = 0;
253     }
254
255     return 1;
256 }
257
258 unsigned int parse_hex_half_digit(const char * str) {
259   if (*str>='0' && *str<='9') {
260     return (*str)-'0';
261   } else if (*str>='A' && *str<='F') {
262     return 10+(*str)-'A';
263   } else if (*str>='a' && *str<='f') {
264     return 10+(*str)-'a';
265   }
266   return 0;
267   
268 }
269
270 char* parse_hexdump(const char * hexdump) {
271   const char *src = hexdump;
272   char *hexdump_copy = strdup(hexdump);
273   unsigned char *dst = (unsigned char*)hexdump_copy;
274   while (*src) {
275     unsigned h=parse_hex_half_digit(src++);
276     h=h<<4;
277     if (!*src) {
278       return hexdump_copy;
279     }
280     h+=parse_hex_half_digit(src++);
281     *dst++ = (unsigned char) h;
282   }
283   return hexdump_copy;
284 }
285
286 void parselist(AAAMessage *response, AAA_AVP_LIST *list, cJSON * item, int level) {
287         int flags;
288         char x[4];
289         AAA_AVP_LIST avp_list;
290         str avp_list_s;
291
292         LM_DBG("------------------------------------------------------------------\n");
293         LM_DBG("%i) Item %s (%i / %s)\n", level, item->string, item->valueint, item->valuestring);
294         // LM_ERR("Got JSON:\n%s\n",  cJSON_Print(item));
295
296         if (cJSON_GetObjectItem(item,"avpCode")) {
297                 LM_DBG("%i) avp-Code: %i\n", level, cJSON_GetObjectItem(item,"avpCode")->valueint);
298         }
299         if (cJSON_GetObjectItem(item,"vendorId")) {
300                 LM_DBG("%i) vendorId: %i\n", level, cJSON_GetObjectItem(item,"vendorId")->valueint);
301         }
302         flags = 0;
303         if (cJSON_GetObjectItem(item,"Flags")) {
304                 LM_DBG("%i) Flags: %i\n", level, cJSON_GetObjectItem(item,"Flags")->valueint);
305                 flags = cJSON_GetObjectItem(item,"Flags")->valueint;
306         }
307         if (cJSON_GetObjectItem(item,"string")) {
308                 LM_DBG("%i) String: %s\n", level, cJSON_GetObjectItem(item,"string")->valuestring);
309         }
310         if (cJSON_GetObjectItem(item,HEXDUMP)) {
311                 LM_DBG("%i) String: %s\n", level, cJSON_GetObjectItem(item,HEXDUMP)->valuestring);
312         }
313         if (cJSON_GetObjectItem(item,"int32")) {
314                 LM_DBG("%i) Integer: %i\n", level, cJSON_GetObjectItem(item,"int32")->valueint);
315         }
316
317         if (!cJSON_GetObjectItem(item,"avpCode")) {
318                 LM_WARN("mandatory field missing: avpCode\n");
319                 return;
320         }
321         if (!cJSON_GetObjectItem(item,"vendorId")) {
322                 LM_WARN("mandatory field missing: vendorId (avpCode %i)\n", cJSON_GetObjectItem(item,"avpCode")->valueint);
323                 return;
324         }
325
326         if ((response == 0) && (list == 0)) {
327                 LM_WARN("No response nor list provided?!? (%i:%i)\n", cJSON_GetObjectItem(item,"avpCode")->valueint,
328                         cJSON_GetObjectItem(item,"vendorId")->valueint);
329                 return;
330         }
331
332         if (cJSON_GetObjectItem(item,"list")) {
333                 LM_DBG("%i) It has a list...\n", level);
334                 int i;
335                 avp_list.head = 0;
336                 avp_list.tail = 0;
337
338                 for (i = 0 ; i < cJSON_GetArraySize(cJSON_GetObjectItem(item,"list")) ; i++) {
339                         cJSON * subitem = cJSON_GetArrayItem(cJSON_GetObjectItem(item,"list"), i);
340                         parselist(0, &avp_list, subitem, level + 1);
341                 }
342                 avp_list_s = cdpb.AAAGroupAVPS(avp_list);
343                 cdpb.AAAFreeAVPList(&avp_list);
344
345                 if(list) {
346                         diameterserver_add_avp_list(list, avp_list_s.s, avp_list_s.len,
347                                         cJSON_GetObjectItem(item, "avpCode")->valueint, flags,
348                                         cJSON_GetObjectItem(item, "vendorId")->valueint, AVP_FREE_DATA,
349                                         __FUNCTION__);
350                 } else {
351                         diameterserver_add_avp(response, avp_list_s.s, avp_list_s.len,
352                                         cJSON_GetObjectItem(item, "avpCode")->valueint, flags,
353                                         cJSON_GetObjectItem(item, "vendorId")->valueint, AVP_FREE_DATA,
354                                         __FUNCTION__);
355                 }
356         } else if (cJSON_GetObjectItem(item,"int32")) {
357                 set_4bytes(x, cJSON_GetObjectItem(item,"int32")->valueint);
358                 if (list) {
359                         diameterserver_add_avp_list(list, x, 4, cJSON_GetObjectItem(item,"avpCode")->valueint, flags,
360                           cJSON_GetObjectItem(item,"vendorId")->valueint, AVP_DUPLICATE_DATA, __FUNCTION__);
361                 } else {
362                         diameterserver_add_avp(response, x, 4, cJSON_GetObjectItem(item,"avpCode")->valueint, flags,
363                           cJSON_GetObjectItem(item,"vendorId")->valueint, AVP_DUPLICATE_DATA, __FUNCTION__);
364                 }
365         } else if (cJSON_GetObjectItem(item,"string")) {
366                 if (list) {
367                         diameterserver_add_avp_list(list, cJSON_GetObjectItem(item,"string")->valuestring,
368                          strlen(cJSON_GetObjectItem(item,"string")->valuestring), cJSON_GetObjectItem(item,"avpCode")->valueint, flags,
369                          cJSON_GetObjectItem(item,"vendorId")->valueint, AVP_DUPLICATE_DATA, __FUNCTION__);
370                 } else {
371                         diameterserver_add_avp(response, cJSON_GetObjectItem(item,"string")->valuestring,
372                          strlen(cJSON_GetObjectItem(item,"string")->valuestring), cJSON_GetObjectItem(item,"avpCode")->valueint, flags,
373                          cJSON_GetObjectItem(item,"vendorId")->valueint, AVP_DUPLICATE_DATA, __FUNCTION__);
374                 }
375         } else if (cJSON_GetObjectItem(item,HEXDUMP)) {
376                 char * binary_form = parse_hexdump(cJSON_GetObjectItem(item,HEXDUMP)->valuestring);
377                 if (list) {
378                         diameterserver_add_avp_list(list, binary_form,
379                          strlen(cJSON_GetObjectItem(item,HEXDUMP)->valuestring) / 2, cJSON_GetObjectItem(item,"avpCode")->valueint, flags,
380                          cJSON_GetObjectItem(item,"vendorId")->valueint, AVP_DUPLICATE_DATA, __FUNCTION__);
381                 } else {
382                         diameterserver_add_avp(response, binary_form,
383                          strlen(cJSON_GetObjectItem(item,HEXDUMP)->valuestring) / 2, cJSON_GetObjectItem(item,"avpCode")->valueint, flags,
384                          cJSON_GetObjectItem(item,"vendorId")->valueint, AVP_DUPLICATE_DATA, __FUNCTION__);
385                 }
386                 free(binary_form);
387         } else {
388                 LM_WARN("Not a string, int32, list, hexdump? Invalid field definition... (%i:%i)\n",
389                         cJSON_GetObjectItem(item,"avpCode")->valueint, cJSON_GetObjectItem(item,"vendorId")->valueint);
390         }
391 }
392
393 int addAVPsfromJSON(AAAMessage *response, str * json) {
394         if (json == NULL) {
395                 json = &responsejson;
396         }
397         if (json->len <= 0) {
398                 LM_WARN("No JSON Response\n");
399                 return 0;
400         }
401         cJSON * root = cJSON_Parse(json->s);
402         if (root) {
403                 int i;
404                 for (i = 0 ; i < cJSON_GetArraySize(root) ; i++) {
405                         cJSON * subitem = cJSON_GetArrayItem(root, i);
406                         parselist(response, 0, subitem, 1);
407                 }
408                 // parselist(root, 0);
409                 cJSON_Delete(root);
410                 return 1;
411         }
412         return 0;
413 }
414
415 int pv_get_command(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
416         return pv_get_uintval(msg, param, res, request->commandCode);
417 }
418
419
420 int pv_get_application(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
421         return pv_get_uintval(msg, param, res, request->applicationId);
422 }
423
424 int pv_get_response(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
425         if ((msg->id != current_msg_id_repl) || (responsejson.len < 0)) {
426                 return pv_get_null(msg, param, res);
427         }
428         return pv_get_strval(msg, param, res, &responsejson);
429 }
430
431 int pv_set_response(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
432         if (val == NULL)
433                 return 0;
434         if (val->flags&PV_VAL_STR) {
435                 LM_DBG("Setting response to \"%.*s\" (String)\n", val->rs.len, val->rs.s);
436                 responsejson.s = val->rs.s;
437                 responsejson.len = val->rs.len;
438                 current_msg_id_repl = msg->id;
439                 return 0;
440         }
441         return 0;
442 }
443