Asterisk - The Open Source Telephony Project  21.4.1
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 
82 int dundi_eid_zero(dundi_eid *eid)
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  case DUNDI_PROTO_PJSIP:
240  strncpy(buf, "PJSIP", bufsiz - 1);
241  default:
242  snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
243  }
244  buf[bufsiz-1] = '\0';
245  return buf;
246 }
247 
248 char *dundi_flags2str(char *buf, int bufsiz, int flags)
249 {
250  strcpy(buf, "");
251  buf[bufsiz-1] = '\0';
252  if (flags & DUNDI_FLAG_EXISTS) {
253  strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
254  }
255  if (flags & DUNDI_FLAG_MATCHMORE) {
256  strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
257  }
258  if (flags & DUNDI_FLAG_CANMATCH) {
259  strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
260  }
261  if (flags & DUNDI_FLAG_IGNOREPAT) {
262  strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
263  }
264  if (flags & DUNDI_FLAG_RESIDENTIAL) {
265  strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
266  }
267  if (flags & DUNDI_FLAG_COMMERCIAL) {
268  strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
269  }
270  if (flags & DUNDI_FLAG_MOBILE) {
271  strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
272  }
273  if (flags & DUNDI_FLAG_NOUNSOLICITED) {
274  strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
275  }
276  if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
277  strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
278  }
279  /* Get rid of trailing | */
280  if (ast_strlen_zero(buf))
281  strcpy(buf, "NONE|");
282  buf[strlen(buf)-1] = '\0';
283  return buf;
284 }
285 
286 static void dump_answer(char *output, int maxlen, void *value, int len)
287 {
288  struct dundi_answer *answer;
289  char proto[40];
290  char flags[40];
291  char eid_str[40];
292  char tmp[512]="";
293  int datalen;
294 
295  if (len < sizeof(*answer)) {
296  snprintf(output, maxlen, "Invalid Answer");
297  return;
298  }
299 
300  answer = (struct dundi_answer *)(value);
301 
302  datalen = len - offsetof(struct dundi_answer, data);
303  if (datalen > sizeof(tmp) - 1)
304  datalen = sizeof(tmp) - 1;
305 
306  memcpy(tmp, answer->data, datalen);
307  tmp[datalen] = '\0';
308 
309  ast_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
310  snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]",
311  dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)),
312  ntohs(answer->weight),
313  proto2str(answer->protocol, proto, sizeof(proto)),
314  tmp, eid_str);
315 }
316 
317 static void dump_encrypted(char *output, int maxlen, void *value, int len)
318 {
319  char iv[33];
320  int x;
321  if ((len > 16) && !(len % 16)) {
322  /* Build up IV */
323  for (x=0;x<16;x++) {
324  snprintf(iv + (x << 1), 3, "%02hhx", ((unsigned char *)value)[x]);
325  }
326  snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
327  } else
328  snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
329 }
330 
331 static void dump_raw(char *output, int maxlen, void *value, int len)
332 {
333  int x;
334  unsigned char *u = value;
335  output[maxlen - 1] = '\0';
336  strcpy(output, "[ ");
337  for (x=0;x<len;x++) {
338  snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02hhx ", u[x]);
339  }
340  strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
341 }
342 
343 static struct dundi_ie {
344  int ie;
345  char *name;
346  void (*dump)(char *output, int maxlen, void *value, int len);
347 } infoelts[] = {
348  { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
349  { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
350  { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
351  { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
352  { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
353  { DUNDI_IE_TTL, "TTL", dump_short },
354  { DUNDI_IE_VERSION, "VERSION", dump_short },
355  { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
356  { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
357  { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
358  { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
359  { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
360  { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
361  { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
362  { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
363  { DUNDI_IE_HINT, "HINT", dump_hint },
364  { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
365  { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
366  { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
367  { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
368  { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
369  { DUNDI_IE_EMAIL, "EMAIL", dump_string },
370  { DUNDI_IE_PHONE, "PHONE", dump_string },
371  { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
372  { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
373 };
374 
375 const char *dundi_ie2str(int ie)
376 {
377  int x;
378  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
379  if (infoelts[x].ie == ie)
380  return infoelts[x].name;
381  }
382  return "Unknown IE";
383 }
384 
385 static void dump_ies(unsigned char *iedata, int spaces, int len)
386 {
387  int ielen;
388  int ie;
389  int x;
390  int found;
391  char interp[1024];
392  char tmp[1051];
393  if (len < 2)
394  return;
395  while(len >= 2) {
396  ie = iedata[0];
397  ielen = iedata[1];
398  /* Encrypted data is the remainder */
399  if (ie == DUNDI_IE_ENCDATA)
400  ielen = len - 2;
401  if (ielen + 2> len) {
402  snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
403  outputf(tmp);
404  return;
405  }
406  found = 0;
407  for (x = 0; x < ARRAY_LEN(infoelts); x++) {
408  if (infoelts[x].ie == ie) {
409  if (infoelts[x].dump) {
410  infoelts[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
411  snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), infoelts[x].name, interp);
412  outputf(tmp);
413  } else {
414  if (ielen)
415  snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
416  else
417  strcpy(interp, "Present");
418  snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), infoelts[x].name, interp);
419  outputf(tmp);
420  }
421  found++;
422  }
423  }
424  if (!found) {
425  snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie);
426  outputf(tmp);
427  }
428  iedata += (2 + ielen);
429  len -= (2 + ielen);
430  }
431  outputf("\n");
432 }
433 
434 void dundi_showframe(struct dundi_hdr *fhi, int rx, struct ast_sockaddr *sin, int datalen)
435 {
436  char *pref[] = {
437  "Tx",
438  "Rx",
439  " ETx",
440  " Erx" };
441  char *commands[] = {
442  "ACK ",
443  "DPDISCOVER ",
444  "DPRESPONSE ",
445  "EIDQUERY ",
446  "EIDRESPONSE ",
447  "PRECACHERQ ",
448  "PRECACHERP ",
449  "INVALID ",
450  "UNKNOWN CMD ",
451  "NULL ",
452  "REGREQ ",
453  "REGRESPONSE ",
454  "CANCEL ",
455  "ENCRYPT ",
456  "ENCREJ " };
457  char class2[20];
458  char *class;
459  char subclass2[20];
460  char *subclass;
461  char tmp[256];
462  if ((fhi->cmdresp & 0x3f) >= ARRAY_LEN(commands)) {
463  snprintf(class2, sizeof(class2), "(%d?)", fhi->cmdresp & 0x3f);
464  class = class2;
465  } else {
466  class = commands[fhi->cmdresp & 0x3f];
467  }
468  snprintf(subclass2, sizeof(subclass2), "%02hhx", (unsigned char)fhi->cmdflags);
469  subclass = subclass2;
470  snprintf(tmp, sizeof(tmp),
471  "%s-Frame -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
472  pref[rx],
473  fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
474  outputf(tmp);
475 
476  snprintf(tmp, (int)sizeof(tmp),
477  "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s]%s\n", (rx > 1) ? " " : "",
478  subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
480  fhi->cmdresp & 0x80 ? " (Final)" : "");
481 
482  outputf(tmp);
483  dump_ies(fhi->ies, rx > 1, datalen);
484 }
485 
486 int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
487 {
488  char tmp[256];
489  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
490  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);
491  errorf(tmp);
492  return -1;
493  }
494  ied->buf[ied->pos++] = ie;
495  ied->buf[ied->pos++] = datalen;
496  memcpy(ied->buf + ied->pos, data, datalen);
497  ied->pos += datalen;
498  return 0;
499 }
500 
501 int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
502 {
503  char tmp[256];
504  int datalen = data ? strlen(data) + 1 : 1;
505  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
506  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);
507  errorf(tmp);
508  return -1;
509  }
510  ied->buf[ied->pos++] = ie;
511  ied->buf[ied->pos++] = datalen;
512  ied->buf[ied->pos++] = cause;
513  if (data) {
514  memcpy(ied->buf + ied->pos, data, datalen-1);
515  ied->pos += datalen-1;
516  }
517  return 0;
518 }
519 
520 int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
521 {
522  char tmp[256];
523  int datalen = data ? strlen(data) + 2 : 2;
524  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
525  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);
526  errorf(tmp);
527  return -1;
528  }
529  ied->buf[ied->pos++] = ie;
530  ied->buf[ied->pos++] = datalen;
531  flags = htons(flags);
532  memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
533  ied->pos += 2;
534  if (data) {
535  memcpy(ied->buf + ied->pos, data, datalen-2);
536  ied->pos += datalen-2;
537  }
538  return 0;
539 }
540 
541 int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
542 {
543  char tmp[256];
544  datalen += 16;
545  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
546  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);
547  errorf(tmp);
548  return -1;
549  }
550  ied->buf[ied->pos++] = ie;
551  ied->buf[ied->pos++] = datalen;
552  memcpy(ied->buf + ied->pos, iv, 16);
553  ied->pos += 16;
554  if (data) {
555  memcpy(ied->buf + ied->pos, data, datalen-16);
556  ied->pos += datalen-16;
557  }
558  return 0;
559 }
560 
561 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)
562 {
563  char tmp[256];
564  int datalen = data ? strlen(data) + 11 : 11;
565  int x;
566  unsigned short myw;
567  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
568  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);
569  errorf(tmp);
570  return -1;
571  }
572  ied->buf[ied->pos++] = ie;
573  ied->buf[ied->pos++] = datalen;
574  for (x=0;x<6;x++)
575  ied->buf[ied->pos++] = eid->eid[x];
576  ied->buf[ied->pos++] = protocol;
577  myw = htons(flags);
578  memcpy(ied->buf + ied->pos, &myw, 2);
579  ied->pos += 2;
580  myw = htons(weight);
581  memcpy(ied->buf + ied->pos, &myw, 2);
582  ied->pos += 2;
583  memcpy(ied->buf + ied->pos, data, datalen-11);
584  ied->pos += datalen-11;
585  return 0;
586 }
587 
588 int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
589 {
590  return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
591 }
592 
593 int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
594 {
595  unsigned int newval;
596  newval = htonl(value);
597  return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
598 }
599 
600 int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
601 {
602  unsigned short newval;
603  newval = htons(value);
604  return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
605 }
606 
607 int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
608 {
609  return dundi_ie_append_raw(ied, ie, str, strlen(str));
610 }
611 
612 int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
613 {
614  return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
615 }
616 
617 int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
618 {
619  return dundi_ie_append_raw(ied, ie, &dat, 1);
620 }
621 
622 int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
623 {
624  return dundi_ie_append_raw(ied, ie, NULL, 0);
625 }
626 
627 void dundi_set_output(void (*func)(const char *))
628 {
629  outputf = func;
630 }
631 
632 void dundi_set_error(void (*func)(const char *))
633 {
634  errorf = func;
635 }
636 
637 int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
638 {
639  /* Parse data into information elements */
640  int len;
641  int ie;
642  char tmp[256];
643  memset(ies, 0, (int)sizeof(struct dundi_ies));
644  ies->ttl = -1;
645  ies->expiration = -1;
646  ies->unknowncmd = -1;
647  ies->cause = -1;
648  while(datalen >= 2) {
649  ie = data[0];
650  len = data[1];
651  if (len > datalen - 2) {
652  errorf("Information element length exceeds message size\n");
653  return -1;
654  }
655  switch(ie) {
656  case DUNDI_IE_EID:
657  case DUNDI_IE_EID_DIRECT:
658  if (len != (int)sizeof(dundi_eid)) {
659  errorf("Improper entity identifer, expecting 6 bytes!\n");
660  } else if (ies->eidcount < DUNDI_MAX_STACK) {
661  ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
662  ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
663  ies->eidcount++;
664  } else
665  errorf("Too many entities in stack!\n");
666  break;
667  case DUNDI_IE_REQEID:
668  if (len != (int)sizeof(dundi_eid)) {
669  errorf("Improper requested entity identifer, expecting 6 bytes!\n");
670  } else
671  ies->reqeid = (dundi_eid *)(data + 2);
672  break;
674  ies->called_context = (char *)data + 2;
675  break;
677  ies->called_number = (char *)data + 2;
678  break;
679  case DUNDI_IE_ANSWER:
680  if (len < sizeof(struct dundi_answer)) {
681  snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
682  errorf(tmp);
683  } else {
684  if (ies->anscount < DUNDI_MAX_ANSWERS)
685  ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
686  else
687  errorf("Ignoring extra answers!\n");
688  }
689  break;
690  case DUNDI_IE_TTL:
691  if (len != (int)sizeof(unsigned short)) {
692  snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
693  errorf(tmp);
694  } else
695  ies->ttl = ntohs(*((unsigned short *)(data + 2)));
696  break;
697  case DUNDI_IE_VERSION:
698  if (len != (int)sizeof(unsigned short)) {
699  snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
700  errorf(tmp);
701  } else
702  ies->version = ntohs(*((unsigned short *)(data + 2)));
703  break;
704  case DUNDI_IE_EXPIRATION:
705  if (len != (int)sizeof(unsigned short)) {
706  snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
707  errorf(tmp);
708  } else
709  ies->expiration = ntohs(*((unsigned short *)(data + 2)));
710  break;
711  case DUNDI_IE_KEYCRC32:
712  if (len != (int)sizeof(unsigned int)) {
713  snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
714  errorf(tmp);
715  } else
716  ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
717  break;
718  case DUNDI_IE_UNKNOWN:
719  if (len == 1)
720  ies->unknowncmd = data[2];
721  else {
722  snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
723  errorf(tmp);
724  }
725  break;
726  case DUNDI_IE_CAUSE:
727  if (len >= 1) {
728  ies->cause = data[2];
729  ies->causestr = (char *)data + 3;
730  } else {
731  snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
732  errorf(tmp);
733  }
734  break;
735  case DUNDI_IE_HINT:
736  if (len >= 2) {
737  ies->hint = (struct dundi_hint *)(data + 2);
738  } else {
739  snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
740  errorf(tmp);
741  }
742  break;
743  case DUNDI_IE_DEPARTMENT:
744  ies->q_dept = (char *)data + 2;
745  break;
747  ies->q_org = (char *)data + 2;
748  break;
749  case DUNDI_IE_LOCALITY:
750  ies->q_locality = (char *)data + 2;
751  break;
752  case DUNDI_IE_STATE_PROV:
753  ies->q_stateprov = (char *)data + 2;
754  break;
755  case DUNDI_IE_COUNTRY:
756  ies->q_country = (char *)data + 2;
757  break;
758  case DUNDI_IE_EMAIL:
759  ies->q_email = (char *)data + 2;
760  break;
761  case DUNDI_IE_PHONE:
762  ies->q_phone = (char *)data + 2;
763  break;
764  case DUNDI_IE_IPADDR:
765  ies->q_ipaddr = (char *)data + 2;
766  break;
767  case DUNDI_IE_ENCDATA:
768  /* Recalculate len as the remainder of the message, regardless of
769  theoretical length */
770  len = datalen - 2;
771  if ((len > 16) && !(len % 16)) {
772  ies->encblock = (struct dundi_encblock *)(data + 2);
773  ies->enclen = len - 16;
774  } else {
775  snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
776  errorf(tmp);
777  }
778  break;
779  case DUNDI_IE_SHAREDKEY:
780  if (len == 128) {
781  ies->encsharedkey = (unsigned char *)(data + 2);
782  } else {
783  snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
784  errorf(tmp);
785  }
786  break;
787  case DUNDI_IE_SIGNATURE:
788  if (len == 128) {
789  ies->encsig = (unsigned char *)(data + 2);
790  } else {
791  snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
792  errorf(tmp);
793  }
794  break;
796  ies->cbypass = 1;
797  break;
798  default:
799  snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
800  outputf(tmp);
801  }
802  /* Overwrite information element with 0, to null terminate previous portion */
803  data[0] = 0;
804  datalen -= (len + 2);
805  data += (len + 2);
806  }
807  /* Null-terminate last field */
808  *data = '\0';
809  if (datalen) {
810  errorf("Invalid information element contents, strange boundary\n");
811  return -1;
812  }
813  return 0;
814 }
#define DUNDI_IE_EXPIRATION
Definition: dundi.h:191
#define DUNDI_IE_EID_DIRECT
Definition: dundi.h:187
Asterisk main include file. File version handling, generic pbx functions.
Distributed Universal Number Discovery (DUNDi) See also.
#define DUNDI_IE_IPADDR
Definition: dundi.h:208
#define DUNDI_IE_CACHEBYPASS
Definition: dundi.h:209
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2839
#define DUNDI_IE_SHAREDKEY
Definition: dundi.h:196
#define DUNDI_IE_CAUSE
Definition: dundi.h:193
#define DUNDI_IE_EMAIL
Definition: dundi.h:206
#define DUNDI_IE_REQEID
Definition: dundi.h:194
#define DUNDI_FLAG_RETRANS
Definition: dundi.h:50
unsigned char cmdresp
Definition: dundi.h:39
#define DUNDI_IE_VERSION
Definition: dundi.h:190
unsigned char oseqno
Definition: dundi.h:38
#define DUNDI_IE_DEPARTMENT
Definition: dundi.h:201
#define DUNDI_FLAG_RESERVED
Definition: dundi.h:51
Socket address structure.
Definition: netsock2.h:97
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:813
Utility functions.
unsigned char data[0]
Definition: dundi.h:114
#define DUNDI_IE_LOCALITY
Definition: dundi.h:203
#define DUNDI_IE_UNKNOWN
Definition: dundi.h:192
unsigned short flags
Definition: dundi.h:107
#define DUNDI_IE_KEYCRC32
Definition: dundi.h:198
#define DUNDI_IE_SIGNATURE
Definition: dundi.h:197
unsigned char protocol
Definition: dundi.h:106
unsigned char cmdflags
Definition: dundi.h:40
Asterisk internal frame definitions.
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3738
#define DUNDI_IE_PHONE
Definition: dundi.h:207
#define DUNDI_IE_EID
Definition: dundi.h:184
unsigned short flags
Definition: dundi.h:113
#define DUNDI_IE_CALLED_CONTEXT
Definition: dundi.h:185
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define DUNDI_IE_ORGANIZATION
Definition: dundi.h:202
#define DUNDI_IE_HINT
Definition: dundi.h:199
unsigned short weight
Definition: dundi.h:108
unsigned short strans
Definition: dundi.h:35
unsigned int flags
#define DUNDI_IE_CALLED_NUMBER
Definition: dundi.h:186
char desc[0]
Definition: dundi.h:138
#define DUNDI_IE_STATE_PROV
Definition: dundi.h:204
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
unsigned char causecode
Definition: dundi.h:137
dundi_eid eid
Definition: dundi.h:105
#define DUNDI_IE_COUNTRY
Definition: dundi.h:205
unsigned short dtrans
Definition: dundi.h:36
#define DUNDI_IE_ENCDATA
Definition: dundi.h:195
#define DUNDI_IE_ANSWER
Definition: dundi.h:188
unsigned char data[0]
Definition: dundi.h:109
unsigned char iseqno
Definition: dundi.h:37
#define DUNDI_IE_TTL
Definition: dundi.h:189