Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


dundi-parser.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Distributed Universal Number Discovery (DUNDi)
22  *
23  */
24 
25 /*** MODULEINFO
26  <support_level>extended</support_level>
27  ***/
28 
29 #include "asterisk.h"
30 
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
32 
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 
37 #include "asterisk/frame.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/dundi.h"
40 #include "dundi-parser.h"
41 
42 static void internaloutput(const char *str)
43 {
44  fputs(str, stdout);
45 }
46 
47 static void internalerror(const char *str)
48 {
49  fprintf(stderr, "WARNING: %s", str);
50 }
51 
52 static void (*outputf)(const char *str) = internaloutput;
53 static void (*errorf)(const char *str) = internalerror;
54 
55 char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
56 {
57  int x;
58  char *os = s;
59  if (maxlen < 13) {
60  if (s && (maxlen > 0))
61  *s = '\0';
62  } else {
63  for (x=0;x<6;x++) {
64  sprintf(s, "%02X", (unsigned)eid->eid[x]);
65  s += 2;
66  }
67  }
68  return os;
69 }
70 
71 int dundi_str_short_to_eid(dundi_eid *eid, const char *s)
72 {
73  unsigned int eid_int[6];
74  int x;
75  if (sscanf(s, "%2x%2x%2x%2x%2x%2x", &eid_int[0], &eid_int[1], &eid_int[2],
76  &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
77  return -1;
78  for (x = 0; x < 6; x++)
79  eid->eid[x] = eid_int[x];
80  return 0;
81 }
82 
84 {
85  int x;
86  for (x = 0; x < ARRAY_LEN(eid->eid); x++)
87  if (eid->eid[x]) return 0;
88  return 1;
89 }
90 
91 static void dump_string(char *output, int maxlen, void *value, int len)
92 {
93  if (maxlen > len + 1)
94  maxlen = len + 1;
95 
96  snprintf(output, maxlen, "%s", (char *) value);
97 }
98 
99 static void dump_cbypass(char *output, int maxlen, void *value, int len)
100 {
101  snprintf(output, maxlen, "Bypass Caches");
102 }
103 
104 static void dump_eid(char *output, int maxlen, void *value, int len)
105 {
106  if (len == 6)
107  ast_eid_to_str(output, maxlen, (dundi_eid *)value);
108  else
109  snprintf(output, maxlen, "Invalid EID len %d", len);
110 }
111 
112 char *dundi_hint2str(char *buf, int bufsiz, int flags)
113 {
114  strcpy(buf, "");
115  buf[bufsiz-1] = '\0';
116  if (flags & DUNDI_HINT_TTL_EXPIRED) {
117  strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1);
118  }
119  if (flags & DUNDI_HINT_DONT_ASK) {
120  strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1);
121  }
122  if (flags & DUNDI_HINT_UNAFFECTED) {
123  strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1);
124  }
125  /* Get rid of trailing | */
126  if (ast_strlen_zero(buf))
127  strcpy(buf, "NONE|");
128  buf[strlen(buf)-1] = '\0';
129  return buf;
130 }
131 
132 static void dump_hint(char *output, int maxlen, void *value, int len)
133 {
134  char tmp2[256];
135  char tmp3[256];
136  int datalen;
137  struct dundi_hint *hint;
138  if (len < sizeof(*hint)) {
139  snprintf(output, maxlen, "<invalid contents>");
140  return;
141  }
142 
143  hint = (struct dundi_hint *) value;;
144 
145  datalen = len - offsetof(struct dundi_hint, data);
146  if (datalen > sizeof(tmp3) - 1)
147  datalen = sizeof(tmp3) - 1;
148 
149  memcpy(tmp3, hint->data, datalen);
150  tmp3[datalen] = '\0';
151 
152  dundi_hint2str(tmp2, sizeof(tmp2), ntohs(hint->flags));
153 
154  if (ast_strlen_zero(tmp3))
155  snprintf(output, maxlen, "[%s]", tmp2);
156  else
157  snprintf(output, maxlen, "[%s] %s", tmp2, tmp3);
158 }
159 
160 static void dump_cause(char *output, int maxlen, void *value, int len)
161 {
162  static const char * const causes[] = {
163  "SUCCESS",
164  "GENERAL",
165  "DYNAMIC",
166  "NOAUTH" ,
167  };
168  char tmp2[256];
169  struct dundi_cause *cause;
170  int datalen;
171  int causecode;
172 
173  if (len < sizeof(*cause)) {
174  snprintf(output, maxlen, "<invalid contents>");
175  return;
176  }
177 
178  cause = (struct dundi_cause*) value;
179  causecode = cause->causecode;
180 
181  datalen = len - offsetof(struct dundi_cause, desc);
182  if (datalen > sizeof(tmp2) - 1)
183  datalen = sizeof(tmp2) - 1;
184 
185  memcpy(tmp2, cause->desc, datalen);
186  tmp2[datalen] = '\0';
187 
188  if (causecode < ARRAY_LEN(causes)) {
189  if (ast_strlen_zero(tmp2))
190  snprintf(output, maxlen, "%s", causes[causecode]);
191  else
192  snprintf(output, maxlen, "%s: %s", causes[causecode], tmp2);
193  } else {
194  if (ast_strlen_zero(tmp2))
195  snprintf(output, maxlen, "%d", causecode);
196  else
197  snprintf(output, maxlen, "%d: %s", causecode, tmp2);
198  }
199 }
200 
201 static void dump_int(char *output, int maxlen, void *value, int len)
202 {
203  if (len == (int)sizeof(unsigned int))
204  snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
205  else
206  ast_copy_string(output, "Invalid INT", maxlen);
207 }
208 
209 static void dump_short(char *output, int maxlen, void *value, int len)
210 {
211  if (len == (int)sizeof(unsigned short))
212  snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
213  else
214  ast_copy_string(output, "Invalid SHORT", maxlen);
215 }
216 
217 static void dump_byte(char *output, int maxlen, void *value, int len)
218 {
219  if (len == (int)sizeof(unsigned char))
220  snprintf(output, maxlen, "%d", *((unsigned char *)value));
221  else
222  ast_copy_string(output, "Invalid BYTE", maxlen);
223 }
224 
225 static char *proto2str(int proto, char *buf, int bufsiz)
226 {
227  switch(proto) {
228  case DUNDI_PROTO_NONE:
229  strncpy(buf, "None", bufsiz - 1);
230  break;
231  case DUNDI_PROTO_IAX:
232  strncpy(buf, "IAX", bufsiz - 1);
233  break;
234  case DUNDI_PROTO_SIP:
235  strncpy(buf, "SIP", bufsiz - 1);
236  break;
237  case DUNDI_PROTO_H323:
238  strncpy(buf, "H.323", bufsiz - 1);
239  break;
240  default:
241  snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
242  }
243  buf[bufsiz-1] = '\0';
244  return buf;
245 }
246 
247 char *dundi_flags2str(char *buf, int bufsiz, int flags)
248 {
249  strcpy(buf, "");
250  buf[bufsiz-1] = '\0';
251  if (flags & DUNDI_FLAG_EXISTS) {
252  strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
253  }
254  if (flags & DUNDI_FLAG_MATCHMORE) {
255  strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
256  }
257  if (flags & DUNDI_FLAG_CANMATCH) {
258  strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
259  }
260  if (flags & DUNDI_FLAG_IGNOREPAT) {
261  strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
262  }
263  if (flags & DUNDI_FLAG_RESIDENTIAL) {
264  strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
265  }
266  if (flags & DUNDI_FLAG_COMMERCIAL) {
267  strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
268  }
269  if (flags & DUNDI_FLAG_MOBILE) {
270  strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
271  }
272  if (flags & DUNDI_FLAG_NOUNSOLICITED) {
273  strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
274  }
275  if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
276  strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
277  }
278  /* Get rid of trailing | */
279  if (ast_strlen_zero(buf))
280  strcpy(buf, "NONE|");
281  buf[strlen(buf)-1] = '\0';
282  return buf;
283 }
284 
285 static void dump_answer(char *output, int maxlen, void *value, int len)
286 {
287  struct dundi_answer *answer;
288  char proto[40];
289  char flags[40];
290  char eid_str[40];
291  char tmp[512]="";
292  int datalen;
293 
294  if (len < sizeof(*answer)) {
295  snprintf(output, maxlen, "Invalid Answer");
296  return;
297  }
298 
299  answer = (struct dundi_answer *)(value);
300 
301  datalen = len - offsetof(struct dundi_answer, data);
302  if (datalen > sizeof(tmp) - 1)
303  datalen = sizeof(tmp) - 1;
304 
305  memcpy(tmp, answer->data, datalen);
306  tmp[datalen] = '\0';
307 
308  ast_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
309  snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]",
310  dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)),
311  ntohs(answer->weight),
312  proto2str(answer->protocol, proto, sizeof(proto)),
313  tmp, eid_str);
314 }
315 
316 static void dump_encrypted(char *output, int maxlen, void *value, int len)
317 {
318  char iv[33];
319  int x;
320  if ((len > 16) && !(len % 16)) {
321  /* Build up IV */
322  for (x=0;x<16;x++) {
323  snprintf(iv + (x << 1), 3, "%02x", (unsigned)((unsigned char *)value)[x]);
324  }
325  snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
326  } else
327  snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
328 }
329 
330 static void dump_raw(char *output, int maxlen, void *value, int len)
331 {
332  int x;
333  unsigned char *u = value;
334  output[maxlen - 1] = '\0';
335  strcpy(output, "[ ");
336  for (x=0;x<len;x++) {
337  snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", (unsigned)u[x]);
338  }
339  strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
340 }
341 
342 static struct dundi_ie {
343  int ie;
344  char *name;
345  void (*dump)(char *output, int maxlen, void *value, int len);
346 } infoelts[] = {
347  { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
348  { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
349  { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
350  { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
351  { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
352  { DUNDI_IE_TTL, "TTL", dump_short },
353  { DUNDI_IE_VERSION, "VERSION", dump_short },
354  { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
355  { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
356  { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
357  { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
358  { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
359  { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
360  { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
361  { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
362  { DUNDI_IE_HINT, "HINT", dump_hint },
363  { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
364  { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
365  { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
366  { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
367  { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
368  { DUNDI_IE_EMAIL, "EMAIL", dump_string },
369  { DUNDI_IE_PHONE, "PHONE", dump_string },
370  { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
371  { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
372 };
373 
374 const char *dundi_ie2str(int ie)
375 {
376  int x;
377  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
378  if (infoelts[x].ie == ie)
379  return infoelts[x].name;
380  }
381  return "Unknown IE";
382 }
383 
384 static void dump_ies(unsigned char *iedata, int spaces, int len)
385 {
386  int ielen;
387  int ie;
388  int x;
389  int found;
390  char interp[1024];
391  char tmp[1024];
392  if (len < 2)
393  return;
394  while(len >= 2) {
395  ie = iedata[0];
396  ielen = iedata[1];
397  /* Encrypted data is the remainder */
398  if (ie == DUNDI_IE_ENCDATA)
399  ielen = len - 2;
400  if (ielen + 2> len) {
401  snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
402  outputf(tmp);
403  return;
404  }
405  found = 0;
406  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
407  if (infoelts[x].ie == ie) {
408  if (infoelts[x].dump) {
409  infoelts[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
410  snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), infoelts[x].name, interp);
411  outputf(tmp);
412  } else {
413  if (ielen)
414  snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
415  else
416  strcpy(interp, "Present");
417  snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), infoelts[x].name, interp);
418  outputf(tmp);
419  }
420  found++;
421  }
422  }
423  if (!found) {
424  snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie);
425  outputf(tmp);
426  }
427  iedata += (2 + ielen);
428  len -= (2 + ielen);
429  }
430  outputf("\n");
431 }
432 
433 void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
434 {
435  char *pref[] = {
436  "Tx",
437  "Rx",
438  " ETx",
439  " Erx" };
440  char *commands[] = {
441  "ACK ",
442  "DPDISCOVER ",
443  "DPRESPONSE ",
444  "EIDQUERY ",
445  "EIDRESPONSE ",
446  "PRECACHERQ ",
447  "PRECACHERP ",
448  "INVALID ",
449  "UNKNOWN CMD ",
450  "NULL ",
451  "REQREQ ",
452  "REGRESPONSE ",
453  "CANCEL ",
454  "ENCRYPT ",
455  "ENCREJ " };
456  char class2[20];
457  char *class;
458  char subclass2[20];
459  char *subclass;
460  char tmp[256];
461  const char *retries = "Yes";
462  if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
463  snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
464  class = class2;
465  } else {
466  class = commands[(int)(fhi->cmdresp & 0x3f)];
467  }
468  snprintf(subclass2, (int)sizeof(subclass2), "%02x", (unsigned)fhi->cmdflags);
469  subclass = subclass2;
470  snprintf(tmp, (int)sizeof(tmp),
471  "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
472  pref[rx],
473  retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
474  outputf(tmp);
475  snprintf(tmp, (int)sizeof(tmp),
476  "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "",
477  subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
478  ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
479  fhi->cmdresp & 0x80 ? " (Final)" : "");
480  outputf(tmp);
481  dump_ies(fhi->ies, rx > 1, datalen);
482 }
483 
484 int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
485 {
486  char tmp[256];
487  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
488  snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
489  errorf(tmp);
490  return -1;
491  }
492  ied->buf[ied->pos++] = ie;
493  ied->buf[ied->pos++] = datalen;
494  memcpy(ied->buf + ied->pos, data, datalen);
495  ied->pos += datalen;
496  return 0;
497 }
498 
499 int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
500 {
501  char tmp[256];
502  int datalen = data ? strlen(data) + 1 : 1;
503  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
504  snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
505  errorf(tmp);
506  return -1;
507  }
508  ied->buf[ied->pos++] = ie;
509  ied->buf[ied->pos++] = datalen;
510  ied->buf[ied->pos++] = cause;
511  if (data) {
512  memcpy(ied->buf + ied->pos, data, datalen-1);
513  ied->pos += datalen-1;
514  }
515  return 0;
516 }
517 
518 int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
519 {
520  char tmp[256];
521  int datalen = data ? strlen(data) + 2 : 2;
522  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
523  snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
524  errorf(tmp);
525  return -1;
526  }
527  ied->buf[ied->pos++] = ie;
528  ied->buf[ied->pos++] = datalen;
529  flags = htons(flags);
530  memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
531  ied->pos += 2;
532  if (data) {
533  memcpy(ied->buf + ied->pos, data, datalen-2);
534  ied->pos += datalen-2;
535  }
536  return 0;
537 }
538 
539 int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
540 {
541  char tmp[256];
542  datalen += 16;
543  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
544  snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
545  errorf(tmp);
546  return -1;
547  }
548  ied->buf[ied->pos++] = ie;
549  ied->buf[ied->pos++] = datalen;
550  memcpy(ied->buf + ied->pos, iv, 16);
551  ied->pos += 16;
552  if (data) {
553  memcpy(ied->buf + ied->pos, data, datalen-16);
554  ied->pos += datalen-16;
555  }
556  return 0;
557 }
558 
559 int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *data)
560 {
561  char tmp[256];
562  int datalen = data ? strlen(data) + 11 : 11;
563  int x;
564  unsigned short myw;
565  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
566  snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
567  errorf(tmp);
568  return -1;
569  }
570  ied->buf[ied->pos++] = ie;
571  ied->buf[ied->pos++] = datalen;
572  for (x=0;x<6;x++)
573  ied->buf[ied->pos++] = eid->eid[x];
574  ied->buf[ied->pos++] = protocol;
575  myw = htons(flags);
576  memcpy(ied->buf + ied->pos, &myw, 2);
577  ied->pos += 2;
578  myw = htons(weight);
579  memcpy(ied->buf + ied->pos, &myw, 2);
580  ied->pos += 2;
581  memcpy(ied->buf + ied->pos, data, datalen-11);
582  ied->pos += datalen-11;
583  return 0;
584 }
585 
586 int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
587 {
588  return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
589 }
590 
591 int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
592 {
593  unsigned int newval;
594  newval = htonl(value);
595  return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
596 }
597 
598 int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
599 {
600  unsigned short newval;
601  newval = htons(value);
602  return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
603 }
604 
605 int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
606 {
607  return dundi_ie_append_raw(ied, ie, str, strlen(str));
608 }
609 
610 int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
611 {
612  return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
613 }
614 
615 int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
616 {
617  return dundi_ie_append_raw(ied, ie, &dat, 1);
618 }
619 
620 int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
621 {
622  return dundi_ie_append_raw(ied, ie, NULL, 0);
623 }
624 
625 void dundi_set_output(void (*func)(const char *))
626 {
627  outputf = func;
628 }
629 
630 void dundi_set_error(void (*func)(const char *))
631 {
632  errorf = func;
633 }
634 
635 int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
636 {
637  /* Parse data into information elements */
638  int len;
639  int ie;
640  char tmp[256];
641  memset(ies, 0, (int)sizeof(struct dundi_ies));
642  ies->ttl = -1;
643  ies->expiration = -1;
644  ies->unknowncmd = -1;
645  ies->cause = -1;
646  while(datalen >= 2) {
647  ie = data[0];
648  len = data[1];
649  if (len > datalen - 2) {
650  errorf("Information element length exceeds message size\n");
651  return -1;
652  }
653  switch(ie) {
654  case DUNDI_IE_EID:
655  case DUNDI_IE_EID_DIRECT:
656  if (len != (int)sizeof(dundi_eid)) {
657  errorf("Improper entity identifer, expecting 6 bytes!\n");
658  } else if (ies->eidcount < DUNDI_MAX_STACK) {
659  ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
660  ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
661  ies->eidcount++;
662  } else
663  errorf("Too many entities in stack!\n");
664  break;
665  case DUNDI_IE_REQEID:
666  if (len != (int)sizeof(dundi_eid)) {
667  errorf("Improper requested entity identifer, expecting 6 bytes!\n");
668  } else
669  ies->reqeid = (dundi_eid *)(data + 2);
670  break;
672  ies->called_context = (char *)data + 2;
673  break;
675  ies->called_number = (char *)data + 2;
676  break;
677  case DUNDI_IE_ANSWER:
678  if (len < sizeof(struct dundi_answer)) {
679  snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
680  errorf(tmp);
681  } else {
682  if (ies->anscount < DUNDI_MAX_ANSWERS)
683  ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
684  else
685  errorf("Ignoring extra answers!\n");
686  }
687  break;
688  case DUNDI_IE_TTL:
689  if (len != (int)sizeof(unsigned short)) {
690  snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
691  errorf(tmp);
692  } else
693  ies->ttl = ntohs(*((unsigned short *)(data + 2)));
694  break;
695  case DUNDI_IE_VERSION:
696  if (len != (int)sizeof(unsigned short)) {
697  snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
698  errorf(tmp);
699  } else
700  ies->version = ntohs(*((unsigned short *)(data + 2)));
701  break;
702  case DUNDI_IE_EXPIRATION:
703  if (len != (int)sizeof(unsigned short)) {
704  snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
705  errorf(tmp);
706  } else
707  ies->expiration = ntohs(*((unsigned short *)(data + 2)));
708  break;
709  case DUNDI_IE_KEYCRC32:
710  if (len != (int)sizeof(unsigned int)) {
711  snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
712  errorf(tmp);
713  } else
714  ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
715  break;
716  case DUNDI_IE_UNKNOWN:
717  if (len == 1)
718  ies->unknowncmd = data[2];
719  else {
720  snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
721  errorf(tmp);
722  }
723  break;
724  case DUNDI_IE_CAUSE:
725  if (len >= 1) {
726  ies->cause = data[2];
727  ies->causestr = (char *)data + 3;
728  } else {
729  snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
730  errorf(tmp);
731  }
732  break;
733  case DUNDI_IE_HINT:
734  if (len >= 2) {
735  ies->hint = (struct dundi_hint *)(data + 2);
736  } else {
737  snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
738  errorf(tmp);
739  }
740  break;
741  case DUNDI_IE_DEPARTMENT:
742  ies->q_dept = (char *)data + 2;
743  break;
745  ies->q_org = (char *)data + 2;
746  break;
747  case DUNDI_IE_LOCALITY:
748  ies->q_locality = (char *)data + 2;
749  break;
750  case DUNDI_IE_STATE_PROV:
751  ies->q_stateprov = (char *)data + 2;
752  break;
753  case DUNDI_IE_COUNTRY:
754  ies->q_country = (char *)data + 2;
755  break;
756  case DUNDI_IE_EMAIL:
757  ies->q_email = (char *)data + 2;
758  break;
759  case DUNDI_IE_PHONE:
760  ies->q_phone = (char *)data + 2;
761  break;
762  case DUNDI_IE_IPADDR:
763  ies->q_ipaddr = (char *)data + 2;
764  break;
765  case DUNDI_IE_ENCDATA:
766  /* Recalculate len as the remainder of the message, regardless of
767  theoretical length */
768  len = datalen - 2;
769  if ((len > 16) && !(len % 16)) {
770  ies->encblock = (struct dundi_encblock *)(data + 2);
771  ies->enclen = len - 16;
772  } else {
773  snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
774  errorf(tmp);
775  }
776  break;
777  case DUNDI_IE_SHAREDKEY:
778  if (len == 128) {
779  ies->encsharedkey = (unsigned char *)(data + 2);
780  } else {
781  snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
782  errorf(tmp);
783  }
784  break;
785  case DUNDI_IE_SIGNATURE:
786  if (len == 128) {
787  ies->encsig = (unsigned char *)(data + 2);
788  } else {
789  snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
790  errorf(tmp);
791  }
792  break;
794  ies->cbypass = 1;
795  break;
796  default:
797  snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
798  outputf(tmp);
799  }
800  /* Overwrite information element with 0, to null terminate previous portion */
801  data[0] = 0;
802  datalen -= (len + 2);
803  data += (len + 2);
804  }
805  /* Null-terminate last field */
806  *data = '\0';
807  if (datalen) {
808  errorf("Invalid information element contents, strange boundary\n");
809  return -1;
810  }
811  return 0;
812 }
static void internaloutput(const char *str)
Definition: dundi-parser.c:42
#define DUNDI_IE_EXPIRATION
Definition: dundi.h:189
static void dump_hint(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:132
dundi_eid * reqeid
Definition: dundi-parser.h:24
#define DUNDI_IE_EID_DIRECT
Definition: dundi.h:185
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
Distributed Universal Number Discovery (DUNDi) See also.
int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
Definition: dundi-parser.c:610
#define DUNDI_IE_IPADDR
Definition: dundi.h:206
#define DUNDI_IE_CACHEBYPASS
Definition: dundi.h:207
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Definition: netsock.c:222
static void dump_eid(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:104
struct dundi_answer * answers[DUNDI_MAX_ANSWERS+1]
Definition: dundi-parser.h:28
char * q_org
Definition: dundi-parser.h:38
static void dump_answer(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:285
#define DUNDI_IE_SHAREDKEY
Definition: dundi.h:194
char * causestr
Definition: dundi-parser.h:45
char * q_locality
Definition: dundi-parser.h:39
void dundi_set_error(void(*func)(const char *))
Definition: dundi-parser.c:630
int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
Definition: dundi-parser.c:586
char * dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
Definition: dundi-parser.c:55
#define DUNDI_IE_CAUSE
Definition: dundi.h:191
#define DUNDI_IE_EMAIL
Definition: dundi.h:204
#define DUNDI_IE_REQEID
Definition: dundi.h:192
#define DUNDI_FLAG_RETRANS
Definition: dundi.h:50
int eid_direct[DUNDI_MAX_STACK+1]
Definition: dundi-parser.h:23
char * called_number
Definition: dundi-parser.h:27
unsigned char cmdresp
Definition: dundi.h:39
const char * str
Definition: app_jack.c:144
int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
Definition: dundi-parser.c:518
char * q_country
Definition: dundi-parser.h:41
#define DUNDI_IE_VERSION
Definition: dundi.h:188
int value
Definition: syslog.c:39
unsigned char oseqno
Definition: dundi.h:38
#define DUNDI_IE_DEPARTMENT
Definition: dundi.h:199
dundi_eid * eids[DUNDI_MAX_STACK+1]
Definition: dundi-parser.h:22
#define DUNDI_FLAG_RESERVED
Definition: dundi.h:51
static void dump_raw(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:330
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:808
int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
Definition: dundi-parser.c:484
Utility functions.
unsigned char data[0]
Definition: dundi.h:112
unsigned char buf[8192]
Definition: dundi-parser.h:56
int eidcount
Definition: dundi-parser.h:25
static struct dundi_ie infoelts[]
void(* dump)(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:345
static void(* outputf)(const char *str)
Definition: dundi-parser.c:52
#define DUNDI_IE_LOCALITY
Definition: dundi.h:201
#define DUNDI_IE_UNKNOWN
Definition: dundi.h:190
unsigned short flags
Definition: dundi.h:105
#define DUNDI_IE_KEYCRC32
Definition: dundi.h:196
#define DUNDI_IE_SIGNATURE
Definition: dundi.h:195
unsigned char protocol
Definition: dundi.h:104
int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
Definition: dundi-parser.c:539
int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
Definition: dundi-parser.c:620
struct dundi_encblock * encblock
Definition: dundi-parser.h:49
void dundi_set_output(void(*func)(const char *))
Definition: dundi-parser.c:625
unsigned char cmdflags
Definition: dundi.h:40
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Asterisk internal frame definitions.
char * q_ipaddr
Definition: dundi-parser.h:44
int datalen
Definition: frame.h:148
unsigned long keycrc32
Definition: dundi-parser.h:48
static void internalerror(const char *str)
Definition: dundi-parser.c:47
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3046
#define DUNDI_IE_PHONE
Definition: dundi.h:205
static void dump_encrypted(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:316
static struct causes_map causes[]
Definition: channel.c:209
#define DUNDI_IE_EID
Definition: dundi.h:182
static void dump_cause(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:160
void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
Definition: dundi-parser.c:433
unsigned char ies[0]
Definition: dundi.h:41
static void dump_byte(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:217
unsigned char * encsharedkey
Definition: dundi-parser.h:46
int expiration
Definition: dundi-parser.h:33
#define DUNDI_MAX_ANSWERS
Definition: dundi-parser.h:19
char * q_stateprov
Definition: dundi-parser.h:40
static const char desc[]
Definition: cdr_radius.c:85
unsigned char eid[6]
Definition: utils.h:809
int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
Definition: dundi-parser.c:605
unsigned short flags
Definition: dundi.h:111
int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
Definition: dundi-parser.c:499
static void dump_ies(unsigned char *iedata, int spaces, int len)
Definition: dundi-parser.c:384
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static void dump_short(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:209
#define DUNDI_IE_CALLED_CONTEXT
Definition: dundi.h:183
unsigned char * encsig
Definition: dundi-parser.h:47
#define DUNDI_IE_ORGANIZATION
Definition: dundi.h:200
#define DUNDI_IE_HINT
Definition: dundi.h:197
int anscount
Definition: dundi-parser.h:30
int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
Definition: dundi-parser.c:598
unsigned short weight
Definition: dundi.h:106
static const char name[]
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:564
char * called_context
Definition: dundi-parser.h:26
unsigned short strans
Definition: dundi.h:35
unsigned int flags
Definition: frame.h:166
#define DUNDI_MAX_STACK
Definition: dundi-parser.h:18
#define DUNDI_IE_CALLED_NUMBER
Definition: dundi.h:184
static char * proto2str(int proto, char *buf, int bufsiz)
Definition: dundi-parser.c:225
char * q_dept
Definition: dundi-parser.h:37
static void dump_cbypass(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:99
char desc[0]
Definition: dundi.h:136
#define DUNDI_IE_STATE_PROV
Definition: dundi.h:202
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int dundi_eid_zero(dundi_eid *eid)
Definition: dundi-parser.c:83
unsigned char causecode
Definition: dundi.h:135
char * name
Definition: dundi-parser.c:344
dundi_eid eid
Definition: dundi.h:103
char * q_phone
Definition: dundi-parser.h:43
#define DUNDI_IE_COUNTRY
Definition: dundi.h:203
int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
Definition: dundi-parser.c:635
unsigned short dtrans
Definition: dundi.h:36
static void dump_int(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:201
int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
Definition: dundi-parser.c:615
static void(* errorf)(const char *str)
Definition: dundi-parser.c:53
int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
Definition: dundi-parser.c:591
#define DUNDI_IE_ENCDATA
Definition: dundi.h:193
struct dundi_hint * hint
Definition: dundi-parser.h:29
int unknowncmd
Definition: dundi-parser.h:34
int dundi_str_short_to_eid(dundi_eid *eid, const char *s)
Definition: dundi-parser.c:71
const char * dundi_ie2str(int ie)
Definition: dundi-parser.c:374
char * q_email
Definition: dundi-parser.h:42
#define DUNDI_IE_ANSWER
Definition: dundi.h:186
char * dundi_flags2str(char *buf, int bufsiz, int flags)
Definition: dundi-parser.c:247
int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *data)
Definition: dundi-parser.c:559
unsigned char data[0]
Definition: dundi.h:107
char * dundi_hint2str(char *buf, int bufsiz, int flags)
Definition: dundi-parser.c:112
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static void dump_string(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:91
unsigned char iseqno
Definition: dundi.h:37
#define DUNDI_IE_TTL
Definition: dundi.h:187