Asterisk - The Open Source Telephony Project  GIT-master-0190e70
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 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 
35 #include "asterisk/frame.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/dundi.h"
38 #include "dundi-parser.h"
39 
40 
41 static void internaloutput(const char *str)
42 {
43  fputs(str, stdout);
44 }
45 
46 static void internalerror(const char *str)
47 {
48  fprintf(stderr, "WARNING: %s", str);
49 }
50 
51 static void (*outputf)(const char *str) = internaloutput;
52 static void (*errorf)(const char *str) = internalerror;
53 
54 char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
55 {
56  int x;
57  char *os = s;
58  if (maxlen < 13) {
59  if (s && (maxlen > 0))
60  *s = '\0';
61  } else {
62  for (x=0;x<6;x++) {
63  sprintf(s, "%02hhX", (unsigned char)eid->eid[x]);
64  s += 2;
65  }
66  }
67  return os;
68 }
69 
70 int dundi_str_short_to_eid(dundi_eid *eid, const char *s)
71 {
72  unsigned int eid_int[6];
73  int x;
74  if (sscanf(s, "%2x%2x%2x%2x%2x%2x", &eid_int[0], &eid_int[1], &eid_int[2],
75  &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
76  return -1;
77  for (x = 0; x < 6; x++)
78  eid->eid[x] = eid_int[x];
79  return 0;
80 }
81 
83 {
84  int x;
85  for (x = 0; x < ARRAY_LEN(eid->eid); x++)
86  if (eid->eid[x]) return 0;
87  return 1;
88 }
89 
90 static void dump_string(char *output, int maxlen, void *value, int len)
91 {
92  if (maxlen > len + 1)
93  maxlen = len + 1;
94 
95  snprintf(output, maxlen, "%s", (char *) value);
96 }
97 
98 static void dump_cbypass(char *output, int maxlen, void *value, int len)
99 {
100  snprintf(output, maxlen, "Bypass Caches");
101 }
102 
103 static void dump_eid(char *output, int maxlen, void *value, int len)
104 {
105  if (len == 6)
106  ast_eid_to_str(output, maxlen, (dundi_eid *)value);
107  else
108  snprintf(output, maxlen, "Invalid EID len %d", len);
109 }
110 
111 char *dundi_hint2str(char *buf, int bufsiz, int flags)
112 {
113  strcpy(buf, "");
114  buf[bufsiz-1] = '\0';
115  if (flags & DUNDI_HINT_TTL_EXPIRED) {
116  strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1);
117  }
118  if (flags & DUNDI_HINT_DONT_ASK) {
119  strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1);
120  }
121  if (flags & DUNDI_HINT_UNAFFECTED) {
122  strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1);
123  }
124  /* Get rid of trailing | */
125  if (ast_strlen_zero(buf))
126  strcpy(buf, "NONE|");
127  buf[strlen(buf)-1] = '\0';
128  return buf;
129 }
130 
131 static void dump_hint(char *output, int maxlen, void *value, int len)
132 {
133  char tmp2[256];
134  char tmp3[256];
135  int datalen;
136  struct dundi_hint *hint;
137  if (len < sizeof(*hint)) {
138  snprintf(output, maxlen, "<invalid contents>");
139  return;
140  }
141 
142  hint = (struct dundi_hint *) value;;
143 
144  datalen = len - offsetof(struct dundi_hint, data);
145  if (datalen > sizeof(tmp3) - 1)
146  datalen = sizeof(tmp3) - 1;
147 
148  memcpy(tmp3, hint->data, datalen);
149  tmp3[datalen] = '\0';
150 
151  dundi_hint2str(tmp2, sizeof(tmp2), ntohs(hint->flags));
152 
153  if (ast_strlen_zero(tmp3))
154  snprintf(output, maxlen, "[%s]", tmp2);
155  else
156  snprintf(output, maxlen, "[%s] %s", tmp2, tmp3);
157 }
158 
159 static void dump_cause(char *output, int maxlen, void *value, int len)
160 {
161  static const char * const causes[] = {
162  "SUCCESS",
163  "GENERAL",
164  "DYNAMIC",
165  "NOAUTH" ,
166  };
167  char tmp2[256];
168  struct dundi_cause *cause;
169  int datalen;
170  int causecode;
171 
172  if (len < sizeof(*cause)) {
173  snprintf(output, maxlen, "<invalid contents>");
174  return;
175  }
176 
177  cause = (struct dundi_cause*) value;
178  causecode = cause->causecode;
179 
180  datalen = len - offsetof(struct dundi_cause, desc);
181  if (datalen > sizeof(tmp2) - 1)
182  datalen = sizeof(tmp2) - 1;
183 
184  memcpy(tmp2, cause->desc, datalen);
185  tmp2[datalen] = '\0';
186 
187  if (causecode < ARRAY_LEN(causes)) {
188  if (ast_strlen_zero(tmp2))
189  snprintf(output, maxlen, "%s", causes[causecode]);
190  else
191  snprintf(output, maxlen, "%s: %s", causes[causecode], tmp2);
192  } else {
193  if (ast_strlen_zero(tmp2))
194  snprintf(output, maxlen, "%d", causecode);
195  else
196  snprintf(output, maxlen, "%d: %s", causecode, tmp2);
197  }
198 }
199 
200 static void dump_int(char *output, int maxlen, void *value, int len)
201 {
202  if (len == (int)sizeof(unsigned int))
203  snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
204  else
205  ast_copy_string(output, "Invalid INT", maxlen);
206 }
207 
208 static void dump_short(char *output, int maxlen, void *value, int len)
209 {
210  if (len == (int)sizeof(unsigned short))
211  snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
212  else
213  ast_copy_string(output, "Invalid SHORT", maxlen);
214 }
215 
216 static void dump_byte(char *output, int maxlen, void *value, int len)
217 {
218  if (len == (int)sizeof(unsigned char))
219  snprintf(output, maxlen, "%d", *((unsigned char *)value));
220  else
221  ast_copy_string(output, "Invalid BYTE", maxlen);
222 }
223 
224 static char *proto2str(int proto, char *buf, int bufsiz)
225 {
226  switch(proto) {
227  case DUNDI_PROTO_NONE:
228  strncpy(buf, "None", bufsiz - 1);
229  break;
230  case DUNDI_PROTO_IAX:
231  strncpy(buf, "IAX", bufsiz - 1);
232  break;
233  case DUNDI_PROTO_SIP:
234  strncpy(buf, "SIP", bufsiz - 1);
235  break;
236  case DUNDI_PROTO_H323:
237  strncpy(buf, "H.323", bufsiz - 1);
238  break;
239  default:
240  snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
241  }
242  buf[bufsiz-1] = '\0';
243  return buf;
244 }
245 
246 char *dundi_flags2str(char *buf, int bufsiz, int flags)
247 {
248  strcpy(buf, "");
249  buf[bufsiz-1] = '\0';
250  if (flags & DUNDI_FLAG_EXISTS) {
251  strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
252  }
253  if (flags & DUNDI_FLAG_MATCHMORE) {
254  strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
255  }
256  if (flags & DUNDI_FLAG_CANMATCH) {
257  strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
258  }
259  if (flags & DUNDI_FLAG_IGNOREPAT) {
260  strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
261  }
262  if (flags & DUNDI_FLAG_RESIDENTIAL) {
263  strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
264  }
265  if (flags & DUNDI_FLAG_COMMERCIAL) {
266  strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
267  }
268  if (flags & DUNDI_FLAG_MOBILE) {
269  strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
270  }
271  if (flags & DUNDI_FLAG_NOUNSOLICITED) {
272  strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
273  }
274  if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
275  strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
276  }
277  /* Get rid of trailing | */
278  if (ast_strlen_zero(buf))
279  strcpy(buf, "NONE|");
280  buf[strlen(buf)-1] = '\0';
281  return buf;
282 }
283 
284 static void dump_answer(char *output, int maxlen, void *value, int len)
285 {
286  struct dundi_answer *answer;
287  char proto[40];
288  char flags[40];
289  char eid_str[40];
290  char tmp[512]="";
291  int datalen;
292 
293  if (len < sizeof(*answer)) {
294  snprintf(output, maxlen, "Invalid Answer");
295  return;
296  }
297 
298  answer = (struct dundi_answer *)(value);
299 
300  datalen = len - offsetof(struct dundi_answer, data);
301  if (datalen > sizeof(tmp) - 1)
302  datalen = sizeof(tmp) - 1;
303 
304  memcpy(tmp, answer->data, datalen);
305  tmp[datalen] = '\0';
306 
307  ast_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
308  snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]",
309  dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)),
310  ntohs(answer->weight),
311  proto2str(answer->protocol, proto, sizeof(proto)),
312  tmp, eid_str);
313 }
314 
315 static void dump_encrypted(char *output, int maxlen, void *value, int len)
316 {
317  char iv[33];
318  int x;
319  if ((len > 16) && !(len % 16)) {
320  /* Build up IV */
321  for (x=0;x<16;x++) {
322  snprintf(iv + (x << 1), 3, "%02hhx", ((unsigned char *)value)[x]);
323  }
324  snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
325  } else
326  snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
327 }
328 
329 static void dump_raw(char *output, int maxlen, void *value, int len)
330 {
331  int x;
332  unsigned char *u = value;
333  output[maxlen - 1] = '\0';
334  strcpy(output, "[ ");
335  for (x=0;x<len;x++) {
336  snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02hhx ", u[x]);
337  }
338  strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
339 }
340 
341 static struct dundi_ie {
342  int ie;
343  char *name;
344  void (*dump)(char *output, int maxlen, void *value, int len);
345 } infoelts[] = {
346  { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
347  { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
348  { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
349  { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
350  { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
351  { DUNDI_IE_TTL, "TTL", dump_short },
352  { DUNDI_IE_VERSION, "VERSION", dump_short },
353  { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
354  { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
355  { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
356  { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
357  { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
358  { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
359  { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
360  { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
361  { DUNDI_IE_HINT, "HINT", dump_hint },
362  { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
363  { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
364  { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
365  { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
366  { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
367  { DUNDI_IE_EMAIL, "EMAIL", dump_string },
368  { DUNDI_IE_PHONE, "PHONE", dump_string },
369  { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
370  { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
371 };
372 
373 const char *dundi_ie2str(int ie)
374 {
375  int x;
376  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
377  if (infoelts[x].ie == ie)
378  return infoelts[x].name;
379  }
380  return "Unknown IE";
381 }
382 
383 static void dump_ies(unsigned char *iedata, int spaces, int len)
384 {
385  int ielen;
386  int ie;
387  int x;
388  int found;
389  char interp[1024];
390  char tmp[1051];
391  if (len < 2)
392  return;
393  while(len >= 2) {
394  ie = iedata[0];
395  ielen = iedata[1];
396  /* Encrypted data is the remainder */
397  if (ie == DUNDI_IE_ENCDATA)
398  ielen = len - 2;
399  if (ielen + 2> len) {
400  snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
401  outputf(tmp);
402  return;
403  }
404  found = 0;
405  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
406  if (infoelts[x].ie == ie) {
407  if (infoelts[x].dump) {
408  infoelts[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
409  snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), infoelts[x].name, interp);
410  outputf(tmp);
411  } else {
412  if (ielen)
413  snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
414  else
415  strcpy(interp, "Present");
416  snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), infoelts[x].name, interp);
417  outputf(tmp);
418  }
419  found++;
420  }
421  }
422  if (!found) {
423  snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie);
424  outputf(tmp);
425  }
426  iedata += (2 + ielen);
427  len -= (2 + ielen);
428  }
429  outputf("\n");
430 }
431 
432 void dundi_showframe(struct dundi_hdr *fhi, int rx, struct ast_sockaddr *sin, int datalen)
433 {
434  char *pref[] = {
435  "Tx",
436  "Rx",
437  " ETx",
438  " Erx" };
439  char *commands[] = {
440  "ACK ",
441  "DPDISCOVER ",
442  "DPRESPONSE ",
443  "EIDQUERY ",
444  "EIDRESPONSE ",
445  "PRECACHERQ ",
446  "PRECACHERP ",
447  "INVALID ",
448  "UNKNOWN CMD ",
449  "NULL ",
450  "REGREQ ",
451  "REGRESPONSE ",
452  "CANCEL ",
453  "ENCRYPT ",
454  "ENCREJ " };
455  char class2[20];
456  char *class;
457  char subclass2[20];
458  char *subclass;
459  char tmp[256];
460  if ((fhi->cmdresp & 0x3f) >= ARRAY_LEN(commands)) {
461  snprintf(class2, sizeof(class2), "(%d?)", fhi->cmdresp & 0x3f);
462  class = class2;
463  } else {
464  class = commands[fhi->cmdresp & 0x3f];
465  }
466  snprintf(subclass2, sizeof(subclass2), "%02hhx", (unsigned char)fhi->cmdflags);
467  subclass = subclass2;
468  snprintf(tmp, sizeof(tmp),
469  "%s-Frame -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
470  pref[rx],
471  fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
472  outputf(tmp);
473 
474  snprintf(tmp, (int)sizeof(tmp),
475  "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s]%s\n", (rx > 1) ? " " : "",
476  subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
478  fhi->cmdresp & 0x80 ? " (Final)" : "");
479 
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:41
#define DUNDI_IE_EXPIRATION
Definition: dundi.h:189
static void dump_hint(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:131
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)
Convert an EID to a string.
Definition: main/utils.c:2458
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static void dump_eid(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:103
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:284
#define DUNDI_IE_SHAREDKEY
Definition: dundi.h:194
char * causestr
Definition: dundi-parser.h:45
char * q_locality
Definition: dundi-parser.h:39
static int tmp()
Definition: bt_open.c:389
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:54
#define DUNDI_IE_CAUSE
Definition: dundi.h:191
static const char desc[]
Definition: cdr_mysql.c:73
#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:147
int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
Definition: dundi-parser.c:518
#define NULL
Definition: resample.c:96
char * q_country
Definition: dundi-parser.h:41
#define DUNDI_IE_VERSION
Definition: dundi.h:188
int value
Definition: syslog.c:37
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:329
Socket address structure.
Definition: netsock2.h:97
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:726
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[]
#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
char * q_ipaddr
Definition: dundi-parser.h:44
Asterisk internal frame definitions.
unsigned long keycrc32
Definition: dundi-parser.h:48
static void internalerror(const char *str)
Definition: dundi-parser.c:46
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3706
#define DUNDI_IE_PHONE
Definition: dundi.h:205
static void dump_encrypted(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:315
#define DUNDI_IE_EID
Definition: dundi.h:182
static void dump_cause(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:159
static const struct causes_map causes[]
Definition: channel.c:132
unsigned char ies[0]
Definition: dundi.h:41
static void dump_byte(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:216
static int answer(void *data)
Definition: chan_pjsip.c:680
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
unsigned char eid[6]
Definition: utils.h:727
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
char weight
static void dump_ies(unsigned char *iedata, int spaces, int len)
Definition: dundi-parser.c:383
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:208
#define DUNDI_IE_CALLED_CONTEXT
Definition: dundi.h:183
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
unsigned char * encsig
Definition: dundi-parser.h:47
#define DUNDI_IE_ORGANIZATION
Definition: dundi.h:200
static void(* outputf)(const char *str)
Definition: dundi-parser.c:51
#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
#define ast_strlen_zero(a)
Definition: muted.c:73
unsigned short weight
Definition: dundi.h:106
char * called_context
Definition: dundi-parser.h:26
unsigned short strans
Definition: dundi.h:35
unsigned int flags
void dundi_showframe(struct dundi_hdr *fhi, int rx, struct ast_sockaddr *sin, int datalen)
Definition: dundi-parser.c:432
#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:224
char * q_dept
Definition: dundi-parser.h:37
static void dump_cbypass(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:98
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:401
int dundi_eid_zero(dundi_eid *eid)
Definition: dundi-parser.c:82
unsigned char causecode
Definition: dundi.h:135
char * name
Definition: dundi-parser.c:343
dundi_eid eid
Definition: dundi.h:103
char * q_phone
Definition: dundi-parser.h:43
void(* dump)(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:344
#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:200
int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
Definition: dundi-parser.c:615
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
static void(* errorf)(const char *str)
Definition: dundi-parser.c:52
int dundi_str_short_to_eid(dundi_eid *eid, const char *s)
Definition: dundi-parser.c:70
const char * dundi_ie2str(int ie)
Definition: dundi-parser.c:373
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:246
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:111
static void dump_string(char *output, int maxlen, void *value, int len)
Definition: dundi-parser.c:90
unsigned char iseqno
Definition: dundi.h:37
#define DUNDI_IE_TTL
Definition: dundi.h:187