Wed Oct 28 11:45:37 2009

Asterisk developer's documentation


dundi-parser.c

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

Generated on Wed Oct 28 11:45:37 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6