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 <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <string.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <unistd.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
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, "%x:%x:%x:%x:%x:%x", &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 char iabuf[INET_ADDRSTRLEN];
00478 if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS)
00479 strcpy(retries, "Yes");
00480 else
00481 strcpy(retries, "No");
00482 if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) {
00483
00484 return;
00485 }
00486 if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
00487 snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
00488 class = class2;
00489 } else {
00490 class = commands[(int)(fhi->cmdresp & 0x3f)];
00491 }
00492 snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags);
00493 subclass = subclass2;
00494 snprintf(tmp, (int)sizeof(tmp),
00495 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
00496 pref[rx],
00497 retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
00498 outputf(tmp);
00499 snprintf(tmp, (int)sizeof(tmp),
00500 "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "",
00501 subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
00502 ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port),
00503 fhi->cmdresp & 0x80 ? " (Final)" : "");
00504 outputf(tmp);
00505 dump_ies(fhi->ies, rx > 1, datalen);
00506 }
00507
00508 int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
00509 {
00510 char tmp[256];
00511 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00512 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);
00513 errorf(tmp);
00514 return -1;
00515 }
00516 ied->buf[ied->pos++] = ie;
00517 ied->buf[ied->pos++] = datalen;
00518 memcpy(ied->buf + ied->pos, data, datalen);
00519 ied->pos += datalen;
00520 return 0;
00521 }
00522
00523 int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
00524 {
00525 char tmp[256];
00526 int datalen = data ? strlen(data) + 1 : 1;
00527 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00528 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);
00529 errorf(tmp);
00530 return -1;
00531 }
00532 ied->buf[ied->pos++] = ie;
00533 ied->buf[ied->pos++] = datalen;
00534 ied->buf[ied->pos++] = cause;
00535 memcpy(ied->buf + ied->pos, data, datalen-1);
00536 ied->pos += datalen-1;
00537 return 0;
00538 }
00539
00540 int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
00541 {
00542 char tmp[256];
00543 int datalen = data ? strlen(data) + 2 : 2;
00544 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00545 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);
00546 errorf(tmp);
00547 return -1;
00548 }
00549 ied->buf[ied->pos++] = ie;
00550 ied->buf[ied->pos++] = datalen;
00551 flags = htons(flags);
00552 memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
00553 ied->pos += 2;
00554 memcpy(ied->buf + ied->pos, data, datalen-1);
00555 ied->pos += datalen-2;
00556 return 0;
00557 }
00558
00559 int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
00560 {
00561 char tmp[256];
00562 datalen += 16;
00563 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00564 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);
00565 errorf(tmp);
00566 return -1;
00567 }
00568 ied->buf[ied->pos++] = ie;
00569 ied->buf[ied->pos++] = datalen;
00570 memcpy(ied->buf + ied->pos, iv, 16);
00571 ied->pos += 16;
00572 if (data) {
00573 memcpy(ied->buf + ied->pos, data, datalen-16);
00574 ied->pos += datalen-16;
00575 }
00576 return 0;
00577 }
00578
00579 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)
00580 {
00581 char tmp[256];
00582 int datalen = data ? strlen(data) + 11 : 11;
00583 int x;
00584 unsigned short myw;
00585 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00586 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);
00587 errorf(tmp);
00588 return -1;
00589 }
00590 ied->buf[ied->pos++] = ie;
00591 ied->buf[ied->pos++] = datalen;
00592 for (x=0;x<6;x++)
00593 ied->buf[ied->pos++] = eid->eid[x];
00594 ied->buf[ied->pos++] = protocol;
00595 myw = htons(flags);
00596 memcpy(ied->buf + ied->pos, &myw, 2);
00597 ied->pos += 2;
00598 myw = htons(weight);
00599 memcpy(ied->buf + ied->pos, &myw, 2);
00600 ied->pos += 2;
00601 memcpy(ied->buf + ied->pos, data, datalen-11);
00602 ied->pos += datalen-11;
00603 return 0;
00604 }
00605
00606 int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
00607 {
00608 return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00609 }
00610
00611 int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
00612 {
00613 unsigned int newval;
00614 newval = htonl(value);
00615 return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00616 }
00617
00618 int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
00619 {
00620 unsigned short newval;
00621 newval = htons(value);
00622 return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00623 }
00624
00625 int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
00626 {
00627 return dundi_ie_append_raw(ied, ie, str, strlen(str));
00628 }
00629
00630 int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
00631 {
00632 return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
00633 }
00634
00635 int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
00636 {
00637 return dundi_ie_append_raw(ied, ie, &dat, 1);
00638 }
00639
00640 int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
00641 {
00642 return dundi_ie_append_raw(ied, ie, NULL, 0);
00643 }
00644
00645 void dundi_set_output(void (*func)(const char *))
00646 {
00647 outputf = func;
00648 }
00649
00650 void dundi_set_error(void (*func)(const char *))
00651 {
00652 errorf = func;
00653 }
00654
00655 int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
00656 {
00657
00658 int len;
00659 int ie;
00660 char tmp[256];
00661 memset(ies, 0, (int)sizeof(struct dundi_ies));
00662 ies->ttl = -1;
00663 ies->expiration = -1;
00664 ies->unknowncmd = -1;
00665 ies->cause = -1;
00666 while(datalen >= 2) {
00667 ie = data[0];
00668 len = data[1];
00669 if (len > datalen - 2) {
00670 errorf("Information element length exceeds message size\n");
00671 return -1;
00672 }
00673 switch(ie) {
00674 case DUNDI_IE_EID:
00675 case DUNDI_IE_EID_DIRECT:
00676 if (len != (int)sizeof(dundi_eid)) {
00677 errorf("Improper entity identifer, expecting 6 bytes!\n");
00678 } else if (ies->eidcount < DUNDI_MAX_STACK) {
00679 ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
00680 ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
00681 ies->eidcount++;
00682 } else
00683 errorf("Too many entities in stack!\n");
00684 break;
00685 case DUNDI_IE_REQEID:
00686 if (len != (int)sizeof(dundi_eid)) {
00687 errorf("Improper requested entity identifer, expecting 6 bytes!\n");
00688 } else
00689 ies->reqeid = (dundi_eid *)(data + 2);
00690 break;
00691 case DUNDI_IE_CALLED_CONTEXT:
00692 ies->called_context = (char *)data + 2;
00693 break;
00694 case DUNDI_IE_CALLED_NUMBER:
00695 ies->called_number = (char *)data + 2;
00696 break;
00697 case DUNDI_IE_ANSWER:
00698 if (len < sizeof(struct dundi_answer)) {
00699 snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
00700 errorf(tmp);
00701 } else {
00702 if (ies->anscount < DUNDI_MAX_ANSWERS)
00703 ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
00704 else
00705 errorf("Ignoring extra answers!\n");
00706 }
00707 break;
00708 case DUNDI_IE_TTL:
00709 if (len != (int)sizeof(unsigned short)) {
00710 snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00711 errorf(tmp);
00712 } else
00713 ies->ttl = ntohs(*((unsigned short *)(data + 2)));
00714 break;
00715 case DUNDI_IE_VERSION:
00716 if (len != (int)sizeof(unsigned short)) {
00717 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00718 errorf(tmp);
00719 } else
00720 ies->version = ntohs(*((unsigned short *)(data + 2)));
00721 break;
00722 case DUNDI_IE_EXPIRATION:
00723 if (len != (int)sizeof(unsigned short)) {
00724 snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00725 errorf(tmp);
00726 } else
00727 ies->expiration = ntohs(*((unsigned short *)(data + 2)));
00728 break;
00729 case DUNDI_IE_KEYCRC32:
00730 if (len != (int)sizeof(unsigned int)) {
00731 snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00732 errorf(tmp);
00733 } else
00734 ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
00735 break;
00736 case DUNDI_IE_UNKNOWN:
00737 if (len == 1)
00738 ies->unknowncmd = data[2];
00739 else {
00740 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00741 errorf(tmp);
00742 }
00743 break;
00744 case DUNDI_IE_CAUSE:
00745 if (len >= 1) {
00746 ies->cause = data[2];
00747 ies->causestr = (char *)data + 3;
00748 } else {
00749 snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
00750 errorf(tmp);
00751 }
00752 break;
00753 case DUNDI_IE_HINT:
00754 if (len >= 2) {
00755 ies->hint = (struct dundi_hint *)(data + 2);
00756 } else {
00757 snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
00758 errorf(tmp);
00759 }
00760 break;
00761 case DUNDI_IE_DEPARTMENT:
00762 ies->q_dept = (char *)data + 2;
00763 break;
00764 case DUNDI_IE_ORGANIZATION:
00765 ies->q_org = (char *)data + 2;
00766 break;
00767 case DUNDI_IE_LOCALITY:
00768 ies->q_locality = (char *)data + 2;
00769 break;
00770 case DUNDI_IE_STATE_PROV:
00771 ies->q_stateprov = (char *)data + 2;
00772 break;
00773 case DUNDI_IE_COUNTRY:
00774 ies->q_country = (char *)data + 2;
00775 break;
00776 case DUNDI_IE_EMAIL:
00777 ies->q_email = (char *)data + 2;
00778 break;
00779 case DUNDI_IE_PHONE:
00780 ies->q_phone = (char *)data + 2;
00781 break;
00782 case DUNDI_IE_IPADDR:
00783 ies->q_ipaddr = (char *)data + 2;
00784 break;
00785 case DUNDI_IE_ENCDATA:
00786
00787
00788 len = datalen - 2;
00789 if ((len > 16) && !(len % 16)) {
00790 ies->encblock = (struct dundi_encblock *)(data + 2);
00791 ies->enclen = len - 16;
00792 } else {
00793 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
00794 errorf(tmp);
00795 }
00796 break;
00797 case DUNDI_IE_SHAREDKEY:
00798 if (len == 128) {
00799 ies->encsharedkey = (unsigned char *)(data + 2);
00800 } else {
00801 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
00802 errorf(tmp);
00803 }
00804 break;
00805 case DUNDI_IE_SIGNATURE:
00806 if (len == 128) {
00807 ies->encsig = (unsigned char *)(data + 2);
00808 } else {
00809 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
00810 errorf(tmp);
00811 }
00812 break;
00813 case DUNDI_IE_CACHEBYPASS:
00814 ies->cbypass = 1;
00815 break;
00816 default:
00817 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
00818 outputf(tmp);
00819 }
00820
00821 data[0] = 0;
00822 datalen -= (len + 2);
00823 data += (len + 2);
00824 }
00825
00826 *data = '\0';
00827 if (datalen) {
00828 errorf("Invalid information element contents, strange boundary\n");
00829 return -1;
00830 }
00831 return 0;
00832 }