00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "asterisk.h"
00026
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211528 $")
00028
00029 #include <sys/types.h>
00030 #include <sys/socket.h>
00031 #include <string.h>
00032 #include <netinet/in.h>
00033 #include <arpa/inet.h>
00034 #include <unistd.h>
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037
00038 #include "asterisk/frame.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/dundi.h"
00041 #include "dundi-parser.h"
00042 #include "asterisk/dundi.h"
00043
00044 static void internaloutput(const char *str)
00045 {
00046 fputs(str, stdout);
00047 }
00048
00049 static void internalerror(const char *str)
00050 {
00051 fprintf(stderr, "WARNING: %s", str);
00052 }
00053
00054 static void (*outputf)(const char *str) = internaloutput;
00055 static void (*errorf)(const char *str) = internalerror;
00056
00057 char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid)
00058 {
00059 int x;
00060 char *os = s;
00061 if (maxlen < 18) {
00062 if (s && (maxlen > 0))
00063 *s = '\0';
00064 } else {
00065 for (x=0;x<5;x++) {
00066 sprintf(s, "%02x:", eid->eid[x]);
00067 s += 3;
00068 }
00069 sprintf(s, "%02x", eid->eid[5]);
00070 }
00071 return os;
00072 }
00073
00074 char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
00075 {
00076 int x;
00077 char *os = s;
00078 if (maxlen < 13) {
00079 if (s && (maxlen > 0))
00080 *s = '\0';
00081 } else {
00082 for (x=0;x<6;x++) {
00083 sprintf(s, "%02X", eid->eid[x]);
00084 s += 2;
00085 }
00086 }
00087 return os;
00088 }
00089
00090 int dundi_str_to_eid(dundi_eid *eid, char *s)
00091 {
00092 unsigned int eid_int[6];
00093 int x;
00094 if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
00095 &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
00096 return -1;
00097 for (x=0;x<6;x++)
00098 eid->eid[x] = eid_int[x];
00099 return 0;
00100 }
00101
00102 int dundi_str_short_to_eid(dundi_eid *eid, char *s)
00103 {
00104 unsigned int eid_int[6];
00105 int x;
00106 if (sscanf(s, "%2x%2x%2x%2x%2x%2x", &eid_int[0], &eid_int[1], &eid_int[2],
00107 &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
00108 return -1;
00109 for (x=0;x<6;x++)
00110 eid->eid[x] = eid_int[x];
00111 return 0;
00112 }
00113
00114 int dundi_eid_zero(dundi_eid *eid)
00115 {
00116 int x;
00117 for (x=0;x<sizeof(eid->eid) / sizeof(eid->eid[0]);x++)
00118 if (eid->eid[x]) return 0;
00119 return 1;
00120 }
00121
00122 int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2)
00123 {
00124 return memcmp(eid1, eid2, sizeof(dundi_eid));
00125 }
00126
00127 static void dump_string(char *output, int maxlen, void *value, int len)
00128 {
00129 maxlen--;
00130 if (maxlen > len)
00131 maxlen = len;
00132 strncpy(output, value, maxlen);
00133 output[maxlen] = '\0';
00134 }
00135
00136 static void dump_cbypass(char *output, int maxlen, void *value, int len)
00137 {
00138 maxlen--;
00139 strncpy(output, "Bypass Caches", maxlen);
00140 output[maxlen] = '\0';
00141 }
00142
00143 static void dump_eid(char *output, int maxlen, void *value, int len)
00144 {
00145 if (len == 6)
00146 dundi_eid_to_str(output, maxlen, (dundi_eid *)value);
00147 else
00148 snprintf(output, maxlen, "Invalid EID len %d", len);
00149 }
00150
00151 char *dundi_hint2str(char *buf, int bufsiz, int flags)
00152 {
00153 strcpy(buf, "");
00154 buf[bufsiz-1] = '\0';
00155 if (flags & DUNDI_HINT_TTL_EXPIRED) {
00156 strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1);
00157 }
00158 if (flags & DUNDI_HINT_DONT_ASK) {
00159 strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1);
00160 }
00161 if (flags & DUNDI_HINT_UNAFFECTED) {
00162 strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1);
00163 }
00164
00165 if (ast_strlen_zero(buf))
00166 strcpy(buf, "NONE|");
00167 buf[strlen(buf)-1] = '\0';
00168 return buf;
00169 }
00170
00171 static void dump_hint(char *output, int maxlen, void *value, int len)
00172 {
00173 unsigned short flags;
00174 char tmp[512];
00175 char tmp2[256];
00176 if (len < 2) {
00177 strncpy(output, "<invalid contents>", maxlen);
00178 return;
00179 }
00180 memcpy(&flags, value, sizeof(flags));
00181 flags = ntohs(flags);
00182 memset(tmp, 0, sizeof(tmp));
00183 dundi_hint2str(tmp2, sizeof(tmp2), flags);
00184 snprintf(tmp, sizeof(tmp), "[%s] ", tmp2);
00185 memcpy(tmp + strlen(tmp), value + 2, len - 2);
00186 strncpy(output, tmp, maxlen - 1);
00187 }
00188
00189 static void dump_cause(char *output, int maxlen, void *value, int len)
00190 {
00191 static char *causes[] = {
00192 "SUCCESS",
00193 "GENERAL",
00194 "DYNAMIC",
00195 "NOAUTH" ,
00196 };
00197 char tmp[256];
00198 char tmp2[256];
00199 int mlen;
00200 unsigned char cause;
00201 if (len < 1) {
00202 strncpy(output, "<invalid contents>", maxlen);
00203 return;
00204 }
00205 cause = *((unsigned char *)value);
00206 memset(tmp2, 0, sizeof(tmp2));
00207 mlen = len - 1;
00208 if (mlen > 255)
00209 mlen = 255;
00210 memcpy(tmp2, value + 1, mlen);
00211 if (cause < sizeof(causes) / sizeof(causes[0])) {
00212 if (len > 1)
00213 snprintf(tmp, sizeof(tmp), "%s: %s", causes[cause], tmp2);
00214 else
00215 snprintf(tmp, sizeof(tmp), "%s", causes[cause]);
00216 } else {
00217 if (len > 1)
00218 snprintf(tmp, sizeof(tmp), "%d: %s", cause, tmp2);
00219 else
00220 snprintf(tmp, sizeof(tmp), "%d", cause);
00221 }
00222
00223 strncpy(output,tmp, maxlen);
00224 output[maxlen] = '\0';
00225 }
00226
00227 static void dump_int(char *output, int maxlen, void *value, int len)
00228 {
00229 if (len == (int)sizeof(unsigned int))
00230 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
00231 else
00232 snprintf(output, maxlen, "Invalid INT");
00233 }
00234
00235 static void dump_short(char *output, int maxlen, void *value, int len)
00236 {
00237 if (len == (int)sizeof(unsigned short))
00238 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
00239 else
00240 snprintf(output, maxlen, "Invalid SHORT");
00241 }
00242
00243 static void dump_byte(char *output, int maxlen, void *value, int len)
00244 {
00245 if (len == (int)sizeof(unsigned char))
00246 snprintf(output, maxlen, "%d", *((unsigned char *)value));
00247 else
00248 snprintf(output, maxlen, "Invalid BYTE");
00249 }
00250
00251 static char *proto2str(int proto, char *buf, int bufsiz)
00252 {
00253 switch(proto) {
00254 case DUNDI_PROTO_NONE:
00255 strncpy(buf, "None", bufsiz - 1);
00256 break;
00257 case DUNDI_PROTO_IAX:
00258 strncpy(buf, "IAX", bufsiz - 1);
00259 break;
00260 case DUNDI_PROTO_SIP:
00261 strncpy(buf, "SIP", bufsiz - 1);
00262 break;
00263 case DUNDI_PROTO_H323:
00264 strncpy(buf, "H.323", bufsiz - 1);
00265 break;
00266 default:
00267 snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
00268 }
00269 buf[bufsiz-1] = '\0';
00270 return buf;
00271 }
00272
00273 char *dundi_flags2str(char *buf, int bufsiz, int flags)
00274 {
00275 strcpy(buf, "");
00276 buf[bufsiz-1] = '\0';
00277 if (flags & DUNDI_FLAG_EXISTS) {
00278 strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
00279 }
00280 if (flags & DUNDI_FLAG_MATCHMORE) {
00281 strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
00282 }
00283 if (flags & DUNDI_FLAG_CANMATCH) {
00284 strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
00285 }
00286 if (flags & DUNDI_FLAG_IGNOREPAT) {
00287 strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
00288 }
00289 if (flags & DUNDI_FLAG_RESIDENTIAL) {
00290 strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
00291 }
00292 if (flags & DUNDI_FLAG_COMMERCIAL) {
00293 strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
00294 }
00295 if (flags & DUNDI_FLAG_MOBILE) {
00296 strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
00297 }
00298 if (flags & DUNDI_FLAG_NOUNSOLICITED) {
00299 strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
00300 }
00301 if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
00302 strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
00303 }
00304
00305 if (ast_strlen_zero(buf))
00306 strcpy(buf, "NONE|");
00307 buf[strlen(buf)-1] = '\0';
00308 return buf;
00309 }
00310
00311 static void dump_answer(char *output, int maxlen, void *value, int len)
00312 {
00313 struct dundi_answer *answer;
00314 char proto[40];
00315 char flags[40];
00316 char eid_str[40];
00317 char tmp[512]="";
00318 if (len >= 10) {
00319 answer = (struct dundi_answer *)(value);
00320 memcpy(tmp, answer->data, (len >= 500) ? 500 : len - 10);
00321 dundi_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
00322 snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]",
00323 dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)),
00324 ntohs(answer->weight),
00325 proto2str(answer->protocol, proto, sizeof(proto)),
00326 tmp, eid_str);
00327 } else
00328 strncpy(output, "Invalid Answer", maxlen - 1);
00329 }
00330
00331 static void dump_encrypted(char *output, int maxlen, void *value, int len)
00332 {
00333 char iv[33];
00334 int x;
00335 if ((len > 16) && !(len % 16)) {
00336
00337 for (x=0;x<16;x++) {
00338 snprintf(iv + (x << 1), 3, "%02x", ((unsigned char *)value)[x]);
00339 }
00340 snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
00341 } else
00342 snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
00343 }
00344
00345 static void dump_raw(char *output, int maxlen, void *value, int len)
00346 {
00347 int x;
00348 unsigned char *u = value;
00349 output[maxlen - 1] = '\0';
00350 strcpy(output, "[ ");
00351 for (x=0;x<len;x++) {
00352 snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", u[x]);
00353 }
00354 strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
00355 }
00356
00357 static struct dundi_ie {
00358 int ie;
00359 char *name;
00360 void (*dump)(char *output, int maxlen, void *value, int len);
00361 } ies[] = {
00362 { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
00363 { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
00364 { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
00365 { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
00366 { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
00367 { DUNDI_IE_TTL, "TTL", dump_short },
00368 { DUNDI_IE_VERSION, "VERSION", dump_short },
00369 { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
00370 { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
00371 { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
00372 { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
00373 { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
00374 { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
00375 { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
00376 { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
00377 { DUNDI_IE_HINT, "HINT", dump_hint },
00378 { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
00379 { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
00380 { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
00381 { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
00382 { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
00383 { DUNDI_IE_EMAIL, "EMAIL", dump_string },
00384 { DUNDI_IE_PHONE, "PHONE", dump_string },
00385 { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
00386 { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
00387 };
00388
00389 const char *dundi_ie2str(int ie)
00390 {
00391 int x;
00392 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00393 if (ies[x].ie == ie)
00394 return ies[x].name;
00395 }
00396 return "Unknown IE";
00397 }
00398
00399 static void dump_ies(unsigned char *iedata, int spaces, int len)
00400 {
00401 int ielen;
00402 int ie;
00403 int x;
00404 int found;
00405 char interp[1024];
00406 char tmp[1024];
00407 if (len < 2)
00408 return;
00409 while(len >= 2) {
00410 ie = iedata[0];
00411 ielen = iedata[1];
00412
00413 if (ie == DUNDI_IE_ENCDATA)
00414 ielen = len - 2;
00415 if (ielen + 2> len) {
00416 snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
00417 outputf(tmp);
00418 return;
00419 }
00420 found = 0;
00421 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00422 if (ies[x].ie == ie) {
00423 if (ies[x].dump) {
00424 ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00425 snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp);
00426 outputf(tmp);
00427 } else {
00428 if (ielen)
00429 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00430 else
00431 strcpy(interp, "Present");
00432 snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp);
00433 outputf(tmp);
00434 }
00435 found++;
00436 }
00437 }
00438 if (!found) {
00439 snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie);
00440 outputf(tmp);
00441 }
00442 iedata += (2 + ielen);
00443 len -= (2 + ielen);
00444 }
00445 outputf("\n");
00446 }
00447
00448 void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00449 {
00450 char *pref[] = {
00451 "Tx",
00452 "Rx",
00453 " ETx",
00454 " Erx" };
00455 char *commands[] = {
00456 "ACK ",
00457 "DPDISCOVER ",
00458 "DPRESPONSE ",
00459 "EIDQUERY ",
00460 "EIDRESPONSE ",
00461 "PRECACHERQ ",
00462 "PRECACHERP ",
00463 "INVALID ",
00464 "UNKNOWN CMD ",
00465 "NULL ",
00466 "REQREQ ",
00467 "REGRESPONSE ",
00468 "CANCEL ",
00469 "ENCRYPT ",
00470 "ENCREJ " };
00471 char class2[20];
00472 char *class;
00473 char subclass2[20];
00474 char *subclass;
00475 char tmp[256];
00476 char retries[20];
00477 if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS)
00478 strcpy(retries, "Yes");
00479 else
00480 strcpy(retries, "No");
00481 if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) {
00482
00483 return;
00484 }
00485 if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
00486 snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
00487 class = class2;
00488 } else {
00489 class = commands[(int)(fhi->cmdresp & 0x3f)];
00490 }
00491 snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags);
00492 subclass = subclass2;
00493 snprintf(tmp, (int)sizeof(tmp),
00494 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
00495 pref[rx],
00496 retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
00497 outputf(tmp);
00498 snprintf(tmp, (int)sizeof(tmp),
00499 "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "",
00500 subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
00501 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00502 fhi->cmdresp & 0x80 ? " (Final)" : "");
00503 outputf(tmp);
00504 dump_ies(fhi->ies, rx > 1, datalen);
00505 }
00506
00507 int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
00508 {
00509 char tmp[256];
00510 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00511 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);
00512 errorf(tmp);
00513 return -1;
00514 }
00515 ied->buf[ied->pos++] = ie;
00516 ied->buf[ied->pos++] = datalen;
00517 memcpy(ied->buf + ied->pos, data, datalen);
00518 ied->pos += datalen;
00519 return 0;
00520 }
00521
00522 int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
00523 {
00524 char tmp[256];
00525 int datalen = data ? strlen(data) + 1 : 1;
00526 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00527 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);
00528 errorf(tmp);
00529 return -1;
00530 }
00531 ied->buf[ied->pos++] = ie;
00532 ied->buf[ied->pos++] = datalen;
00533 ied->buf[ied->pos++] = cause;
00534 memcpy(ied->buf + ied->pos, data, datalen-1);
00535 ied->pos += datalen-1;
00536 return 0;
00537 }
00538
00539 int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
00540 {
00541 char tmp[256];
00542 int datalen = data ? strlen(data) + 2 : 2;
00543 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00544 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);
00545 errorf(tmp);
00546 return -1;
00547 }
00548 ied->buf[ied->pos++] = ie;
00549 ied->buf[ied->pos++] = datalen;
00550 flags = htons(flags);
00551 memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
00552 ied->pos += 2;
00553 memcpy(ied->buf + ied->pos, data, datalen-1);
00554 ied->pos += datalen-2;
00555 return 0;
00556 }
00557
00558 int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
00559 {
00560 char tmp[256];
00561 datalen += 16;
00562 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00563 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);
00564 errorf(tmp);
00565 return -1;
00566 }
00567 ied->buf[ied->pos++] = ie;
00568 ied->buf[ied->pos++] = datalen;
00569 memcpy(ied->buf + ied->pos, iv, 16);
00570 ied->pos += 16;
00571 if (data) {
00572 memcpy(ied->buf + ied->pos, data, datalen-16);
00573 ied->pos += datalen-16;
00574 }
00575 return 0;
00576 }
00577
00578 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)
00579 {
00580 char tmp[256];
00581 int datalen = data ? strlen(data) + 11 : 11;
00582 int x;
00583 unsigned short myw;
00584 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00585 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);
00586 errorf(tmp);
00587 return -1;
00588 }
00589 ied->buf[ied->pos++] = ie;
00590 ied->buf[ied->pos++] = datalen;
00591 for (x=0;x<6;x++)
00592 ied->buf[ied->pos++] = eid->eid[x];
00593 ied->buf[ied->pos++] = protocol;
00594 myw = htons(flags);
00595 memcpy(ied->buf + ied->pos, &myw, 2);
00596 ied->pos += 2;
00597 myw = htons(weight);
00598 memcpy(ied->buf + ied->pos, &myw, 2);
00599 ied->pos += 2;
00600 memcpy(ied->buf + ied->pos, data, datalen-11);
00601 ied->pos += datalen-11;
00602 return 0;
00603 }
00604
00605 int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
00606 {
00607 return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00608 }
00609
00610 int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
00611 {
00612 unsigned int newval;
00613 newval = htonl(value);
00614 return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00615 }
00616
00617 int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
00618 {
00619 unsigned short newval;
00620 newval = htons(value);
00621 return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00622 }
00623
00624 int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
00625 {
00626 return dundi_ie_append_raw(ied, ie, str, strlen(str));
00627 }
00628
00629 int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
00630 {
00631 return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
00632 }
00633
00634 int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
00635 {
00636 return dundi_ie_append_raw(ied, ie, &dat, 1);
00637 }
00638
00639 int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
00640 {
00641 return dundi_ie_append_raw(ied, ie, NULL, 0);
00642 }
00643
00644 void dundi_set_output(void (*func)(const char *))
00645 {
00646 outputf = func;
00647 }
00648
00649 void dundi_set_error(void (*func)(const char *))
00650 {
00651 errorf = func;
00652 }
00653
00654 int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
00655 {
00656
00657 int len;
00658 int ie;
00659 char tmp[256];
00660 memset(ies, 0, (int)sizeof(struct dundi_ies));
00661 ies->ttl = -1;
00662 ies->expiration = -1;
00663 ies->unknowncmd = -1;
00664 ies->cause = -1;
00665 while(datalen >= 2) {
00666 ie = data[0];
00667 len = data[1];
00668 if (len > datalen - 2) {
00669 errorf("Information element length exceeds message size\n");
00670 return -1;
00671 }
00672 switch(ie) {
00673 case DUNDI_IE_EID:
00674 case DUNDI_IE_EID_DIRECT:
00675 if (len != (int)sizeof(dundi_eid)) {
00676 errorf("Improper entity identifer, expecting 6 bytes!\n");
00677 } else if (ies->eidcount < DUNDI_MAX_STACK) {
00678 ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
00679 ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
00680 ies->eidcount++;
00681 } else
00682 errorf("Too many entities in stack!\n");
00683 break;
00684 case DUNDI_IE_REQEID:
00685 if (len != (int)sizeof(dundi_eid)) {
00686 errorf("Improper requested entity identifer, expecting 6 bytes!\n");
00687 } else
00688 ies->reqeid = (dundi_eid *)(data + 2);
00689 break;
00690 case DUNDI_IE_CALLED_CONTEXT:
00691 ies->called_context = (char *)data + 2;
00692 break;
00693 case DUNDI_IE_CALLED_NUMBER:
00694 ies->called_number = (char *)data + 2;
00695 break;
00696 case DUNDI_IE_ANSWER:
00697 if (len < sizeof(struct dundi_answer)) {
00698 snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
00699 errorf(tmp);
00700 } else {
00701 if (ies->anscount < DUNDI_MAX_ANSWERS)
00702 ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
00703 else
00704 errorf("Ignoring extra answers!\n");
00705 }
00706 break;
00707 case DUNDI_IE_TTL:
00708 if (len != (int)sizeof(unsigned short)) {
00709 snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00710 errorf(tmp);
00711 } else
00712 ies->ttl = ntohs(*((unsigned short *)(data + 2)));
00713 break;
00714 case DUNDI_IE_VERSION:
00715 if (len != (int)sizeof(unsigned short)) {
00716 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00717 errorf(tmp);
00718 } else
00719 ies->version = ntohs(*((unsigned short *)(data + 2)));
00720 break;
00721 case DUNDI_IE_EXPIRATION:
00722 if (len != (int)sizeof(unsigned short)) {
00723 snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00724 errorf(tmp);
00725 } else
00726 ies->expiration = ntohs(*((unsigned short *)(data + 2)));
00727 break;
00728 case DUNDI_IE_KEYCRC32:
00729 if (len != (int)sizeof(unsigned int)) {
00730 snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00731 errorf(tmp);
00732 } else
00733 ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
00734 break;
00735 case DUNDI_IE_UNKNOWN:
00736 if (len == 1)
00737 ies->unknowncmd = data[2];
00738 else {
00739 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00740 errorf(tmp);
00741 }
00742 break;
00743 case DUNDI_IE_CAUSE:
00744 if (len >= 1) {
00745 ies->cause = data[2];
00746 ies->causestr = (char *)data + 3;
00747 } else {
00748 snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
00749 errorf(tmp);
00750 }
00751 break;
00752 case DUNDI_IE_HINT:
00753 if (len >= 2) {
00754 ies->hint = (struct dundi_hint *)(data + 2);
00755 } else {
00756 snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
00757 errorf(tmp);
00758 }
00759 break;
00760 case DUNDI_IE_DEPARTMENT:
00761 ies->q_dept = (char *)data + 2;
00762 break;
00763 case DUNDI_IE_ORGANIZATION:
00764 ies->q_org = (char *)data + 2;
00765 break;
00766 case DUNDI_IE_LOCALITY:
00767 ies->q_locality = (char *)data + 2;
00768 break;
00769 case DUNDI_IE_STATE_PROV:
00770 ies->q_stateprov = (char *)data + 2;
00771 break;
00772 case DUNDI_IE_COUNTRY:
00773 ies->q_country = (char *)data + 2;
00774 break;
00775 case DUNDI_IE_EMAIL:
00776 ies->q_email = (char *)data + 2;
00777 break;
00778 case DUNDI_IE_PHONE:
00779 ies->q_phone = (char *)data + 2;
00780 break;
00781 case DUNDI_IE_IPADDR:
00782 ies->q_ipaddr = (char *)data + 2;
00783 break;
00784 case DUNDI_IE_ENCDATA:
00785
00786
00787 len = datalen - 2;
00788 if ((len > 16) && !(len % 16)) {
00789 ies->encblock = (struct dundi_encblock *)(data + 2);
00790 ies->enclen = len - 16;
00791 } else {
00792 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
00793 errorf(tmp);
00794 }
00795 break;
00796 case DUNDI_IE_SHAREDKEY:
00797 if (len == 128) {
00798 ies->encsharedkey = (unsigned char *)(data + 2);
00799 } else {
00800 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
00801 errorf(tmp);
00802 }
00803 break;
00804 case DUNDI_IE_SIGNATURE:
00805 if (len == 128) {
00806 ies->encsig = (unsigned char *)(data + 2);
00807 } else {
00808 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
00809 errorf(tmp);
00810 }
00811 break;
00812 case DUNDI_IE_CACHEBYPASS:
00813 ies->cbypass = 1;
00814 break;
00815 default:
00816 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
00817 outputf(tmp);
00818 }
00819
00820 data[0] = 0;
00821 datalen -= (len + 2);
00822 data += (len + 2);
00823 }
00824
00825 *data = '\0';
00826 if (datalen) {
00827 errorf("Invalid information element contents, strange boundary\n");
00828 return -1;
00829 }
00830 return 0;
00831 }