From fa8ea94c177025426ad5429a3737e0b8aae6363f Mon Sep 17 00:00:00 2001 From: kpfleming Date: Wed, 14 Sep 2005 01:36:15 +0000 Subject: extensive ENUM support update, including ENUMLOOKUP() dialplan function (issue #5201 with mods) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6579 f38db490-d61c-443f-a65b-d21fe96a405b --- enum.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 218 insertions(+), 57 deletions(-) (limited to 'enum.c') diff --git a/enum.c b/enum.c index 45370e0b7..6f475fef7 100755 --- a/enum.c +++ b/enum.c @@ -87,9 +87,12 @@ static int parse_ie(char *data, int maxdatalen, char *src, int srclen) /*--- parse_naptr: Parse DNS NAPTR record used in ENUM ---*/ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *answer, int len, char *naptrinput) { + + char tech_return[80]; char *oanswer = answer; char flags[512] = ""; char services[512] = ""; + unsigned char *p; char regexp[512] = ""; char repl[512] = ""; char temp[512] = ""; @@ -102,9 +105,10 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a regex_t preg; regmatch_t pmatch[9]; + tech_return[0] = '\0'; dst[0] = '\0'; - + if (len < sizeof(struct naptr)) { ast_log(LOG_WARNING, "NAPTR record length too short\n"); return -1; @@ -113,29 +117,30 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a len -= sizeof(struct naptr); if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) { ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n"); - return -1; - } else { - answer += res; - len -= res; + return -1; + } else { + answer += res; + len -= res; } if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) { ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n"); - return -1; - } else { - answer += res; - len -= res; + return -1; + } else { + answer += res; + len -= res; } if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) { ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n"); - return -1; - } else { - answer += res; - len -= res; + return -1; + } else { + answer += res; + len -= res; } + if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) { ast_log(LOG_WARNING, "Failed to expand hostname\n"); return -1; - } + } if (option_debug > 2) /* Advanced NAPTR debugging */ ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n", @@ -146,29 +151,27 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a return -1; } - if ((!strncasecmp(services, "e2u+sip", 7)) || - (!strncasecmp(services, "sip+e2u", 7))) { - ast_copy_string(tech, "sip", techsize); - } else if ((!strncasecmp(services, "e2u+h323", 8)) || - (!strncasecmp(services, "h323+e2u", 8))) { - ast_copy_string(tech, "h323", techsize); - } else if ((!strncasecmp(services, "e2u+x-iax2", 10)) || - (!strncasecmp(services, "e2u+iax2", 8)) || - (!strncasecmp(services, "iax2+e2u", 8))) { - ast_copy_string(tech, "iax2", techsize); - } else if ((!strncasecmp(services, "e2u+x-iax", 9)) || - (!strncasecmp(services, "e2u+iax", 7)) || - (!strncasecmp(services, "iax+e2u", 7))) { - ast_copy_string(tech, "iax", techsize); - } else if ((!strncasecmp(services, "e2u+tel", 7)) || - (!strncasecmp(services, "tel+e2u", 7))) { - ast_copy_string(tech, "tel", techsize); - } else if (!strncasecmp(services, "e2u+voice:", 10)) { - ast_copy_string(tech, services+10, techsize); + p = strstr(services, "e2u+"); + if(p == NULL) + p = strstr(services, "E2U+"); + if(p){ + p = p + 4; + if(strchr(p, ':')){ + p = strchr(p, ':') + 1; + } + ast_copy_string(tech_return, p, sizeof(tech_return)); } else { - ast_log(LOG_DEBUG, - "Services must be e2u+${tech}, ${tech}+e2u, or e2u+voice: where $tech is from (sip, h323, tel, iax, iax2). \n"); - return 0; + + p = strstr(services, "+e2u"); + if(p == NULL) + p = strstr(services, "+E2U"); + if(p){ + *p = 0; + p = strchr(services, ':'); + if(p) + *p = 0; + ast_copy_string(tech_return, services, sizeof(tech_return)); + } } /* DEDBUGGING STUB @@ -179,7 +182,7 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a if (regexp_len < 7) { ast_log(LOG_WARNING, "Regex too short to be meaningful.\n"); return -1; - } + } delim = regexp[0]; @@ -197,6 +200,7 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a #if 0 printf("Pattern: %s\n", pattern); printf("Subst: %s\n", subst); + printf("Input: %s\n", naptrinput); #endif /* @@ -221,8 +225,8 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a } regfree(&preg); - d = temp; - d_len--; + d = temp; + d_len--; while( *subst && (d_len > 0) ) { if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) { backref = subst[1]-'0'; @@ -246,9 +250,35 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a *d = 0; ast_copy_string(dst, temp, dstsize); dst[dstsize - 1] = '\0'; - return 0; + + if(*tech != '\0'){ /* check if it is requested NAPTR */ + if(!strncasecmp(tech, "ALL", techsize)){ + return 1; /* return or count any RR */ + } + if(!strncasecmp(tech_return, tech, sizeof(tech_return)txt */ ast_copy_string(c->txt, answer, len < c->txtlen ? len : (c->txtlen)); - + /* just to be safe, let's make sure c->txt is null terminated */ c->txt[(c->txtlen)-1] = '\0'; @@ -298,45 +332,122 @@ static int txt_callback(void *context, char *answer, int len, char *fullanswer) static int enum_callback(void *context, char *answer, int len, char *fullanswer) { struct enum_context *c = (struct enum_context *)context; + void *p = NULL; + int res; - if (parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput)) { + res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput); + + if(res < 0){ ast_log(LOG_WARNING, "Failed to parse naptr :(\n"); return -1; + } else if(res > 0 && !ast_strlen_zero(c->dst)){ /* ok, we got needed NAPTR */ + if(c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */ + c->position++; + snprintf(c->dst, c->dstlen, "%d", c->position); + } else { + p = realloc(c->naptr_rrs, sizeof(struct enum_naptr_rr)*(c->naptr_rrs_count+1)); + if(p){ + c->naptr_rrs = (struct enum_naptr_rr*)p; + memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(struct naptr)); + /* printf("order=%d, pref=%d\n", ntohs(c->naptr_rrs[c->naptr_rrs_count].naptr.order), ntohs(c->naptr_rrs[c->naptr_rrs_count].naptr.pref)); */ + c->naptr_rrs[c->naptr_rrs_count].result = strdup(c->dst); + c->naptr_rrs[c->naptr_rrs_count].tech = strdup(c->tech); + c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count; + c->naptr_rrs_count++; + } + c->dst[0] = 0; + } + return 0; } - if (!ast_strlen_zero(c->dst)) - return 1; + if(c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */ + snprintf(c->dst, c->dstlen, "%d", c->position); + } return 0; } /*--- ast_get_enum: ENUM lookup */ -int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen) +int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options) { struct enum_context context; char tmp[259 + 512]; - char naptrinput[512] = "+"; + char naptrinput[512]; int pos = strlen(number) - 1; int newpos = 0; int ret = -1; struct enum_search *s = NULL; int version = -1; - - strncat(naptrinput, number, sizeof(naptrinput) - 2); + /* for ISN rewrite */ + char *p1 = NULL; + char *p2 = NULL; + int k = 0; + int i = 0; + int z = 0; + + if(number[0] == 'n'){ + strncpy(naptrinput, number+1, sizeof(naptrinput)); + } else { + strncpy(naptrinput, number, sizeof(naptrinput)); + } context.naptrinput = naptrinput; /* The number */ context.dst = dst; /* Return string */ context.dstlen = dstlen; - context.tech = tech; /* Return string */ + context.tech = tech; context.techlen = techlen; + context.options = 0; + context.position = 1; + context.naptr_rrs = NULL; + context.naptr_rrs_count = 0; + + if(options != NULL){ + if(*options == 'c'){ + context.options = ENUMLOOKUP_OPTIONS_COUNT; + context.position = 0; + } else { + context.position = atoi(options); + if(context.position < 1) + context.position = 1; + } + } if (pos > 128) pos = 128; - while(pos >= 0) { - tmp[newpos++] = number[pos--]; - tmp[newpos++] = '.'; + + /* ISN rewrite */ + p1 = strchr(number, '*'); + + if(number[0] == 'n'){ /* do not perform ISN rewrite ('n' is testing flag) */ + p1 = NULL; + k = 1; /* strip 'n' from number */ + } + + if(p1 != NULL){ + p2 = p1+1; + while(p1 > number){ + p1--; + tmp[newpos++] = *p1; + tmp[newpos++] = '.'; + } + if(*p2){ + while(*p2 && newpos < 128){ + tmp[newpos++] = *p2; + p2++; + } + tmp[newpos++] = '.'; + } + + } else { + while(pos >= k) { + if(isdigit(number[pos])){ + tmp[newpos++] = number[pos]; + tmp[newpos++] = '.'; + } + pos--; + } } - + if (chan && ast_autoservice_start(chan) < 0) return -1; @@ -349,7 +460,9 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds } else { s = s->next; } - if (s) { + if(suffix != NULL){ + strncpy(tmp + newpos, suffix, sizeof(tmp) - newpos - 1); + } else if (s) { strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1); } ast_mutex_unlock(&enumlock); @@ -358,17 +471,65 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback); if (ret > 0) break; + if(suffix != NULL) + break; } if (ret < 0) { ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno)); ret = 0; } + + if(context.naptr_rrs_count >= context.position && ! (context.options & ENUMLOOKUP_OPTIONS_COUNT)){ + /* sort array by NAPTR order/preference */ + for(k=0; k context.naptr_rrs[i].sort_pos) + || (ntohs(context.naptr_rrs[k].naptr.order) > ntohs(context.naptr_rrs[i].naptr.order) + && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){ + z = context.naptr_rrs[k].sort_pos; + context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos; + context.naptr_rrs[i].sort_pos = z; + continue; + } + if(ntohs(context.naptr_rrs[k].naptr.order) == ntohs(context.naptr_rrs[i].naptr.order)){ + if((ntohs(context.naptr_rrs[k].naptr.pref) < ntohs(context.naptr_rrs[i].naptr.pref) + && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos) + || (ntohs(context.naptr_rrs[k].naptr.pref) > ntohs(context.naptr_rrs[i].naptr.pref) + && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){ + z = context.naptr_rrs[k].sort_pos; + context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos; + context.naptr_rrs[i].sort_pos = z; + } + } + } + } + for(k=0; k