mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	extensive ENUM support update, including ENUMLOOKUP() dialplan function (issue #5201 with mods)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6579 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		
							
								
								
									
										273
									
								
								enum.c
									
									
									
									
									
								
							
							
						
						
									
										273
									
								
								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)<techsize?sizeof(tech_return):techsize)){ | ||||
|                        ast_copy_string(tech, tech_return, techsize); | ||||
|                        return 1; /* we got out RR */ | ||||
|                } else { /* go to the next RR in the DNS answer */ | ||||
|                        return 0; | ||||
|                } | ||||
|        } | ||||
|  | ||||
|        /* tech was not specified, return first parsed RR */ | ||||
|        ast_copy_string(tech, tech_return, techsize); | ||||
|  | ||||
|        return 1; | ||||
| } | ||||
|  | ||||
| /* do not return requested value, just count RRs and return thei number in dst */ | ||||
| #define ENUMLOOKUP_OPTIONS_COUNT       1 | ||||
|  | ||||
| struct enum_naptr_rr { | ||||
|        struct naptr naptr; /* order and preference of RR */ | ||||
|        char *result; /* result of naptr parsing,e.g.: tel:+5553 */ | ||||
|        char *tech; /* Technology (from URL scheme) */ | ||||
|        int sort_pos; /* sort position */ | ||||
| }; | ||||
|  | ||||
| struct enum_context { | ||||
| 	char *dst;	/* Destination part of URL from ENUM */ | ||||
| 	int dstlen;	/* Length */ | ||||
| @@ -257,6 +287,10 @@ struct enum_context { | ||||
| 	char *txt;	/* TXT record in TXT lookup */ | ||||
| 	int txtlen;	/* Length */ | ||||
| 	char *naptrinput;	/* The number to lookup */ | ||||
|        int position; /* used as counter for RRs or specifies position of required RR */ | ||||
|        int options; /* options , see ENUMLOOKUP_OPTIONS_* defined above */ | ||||
|        struct enum_naptr_rr *naptr_rrs; /* array of parsed NAPTR RRs */ | ||||
|        int naptr_rrs_count; /* Size of array naptr_rrs */ | ||||
| }; | ||||
|  | ||||
| /*--- txt_callback: Callback for TXT record lookup */ | ||||
| @@ -278,7 +312,7 @@ static int txt_callback(void *context, char *answer, int len, char *fullanswer) | ||||
| 	len -= 1; | ||||
|  | ||||
| 	/* answer is not null-terminated, but should be */ | ||||
| 	/* this is safe to do, as answer has extra bytes on the end we can  | ||||
|        /* this is safe to do, as answer has extra bytes on the end we can | ||||
|            safely overwrite with a null */ | ||||
| 	answer[len] = '\0'; | ||||
| 	/* now increment len so that len includes the null, so that we can | ||||
| @@ -287,7 +321,7 @@ static int txt_callback(void *context, char *answer, int len, char *fullanswer) | ||||
|  | ||||
| 	/* finally, copy the answer into c->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; | ||||
|        /* for ISN rewrite */ | ||||
|        char *p1 = NULL; | ||||
|        char *p2 = NULL; | ||||
|        int k = 0; | ||||
|        int i = 0; | ||||
|        int z = 0; | ||||
|  | ||||
| 	strncat(naptrinput, number, sizeof(naptrinput) - 2); | ||||
|        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_count; k++){ | ||||
|                        for(i=0; i<context.naptr_rrs_count; i++){ | ||||
|                                /* use order first and then preference to compare */ | ||||
|                                if((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) | ||||
|                                        || (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<context.naptr_rrs_count; k++){ | ||||
|                        if(context.naptr_rrs[k].sort_pos == context.position-1){ | ||||
|                                ast_copy_string(context.dst, context.naptr_rrs[k].result, dstlen); | ||||
|                                ast_copy_string(context.tech, context.naptr_rrs[k].tech, techlen); | ||||
|                                break; | ||||
|                        } | ||||
|                } | ||||
|        } else if( !(context.options & ENUMLOOKUP_OPTIONS_COUNT) ) { | ||||
|                context.dst[0] = 0; | ||||
|        } | ||||
|  | ||||
| 	if (chan) | ||||
| 		ret |= ast_autoservice_stop(chan); | ||||
|  | ||||
|        for(k=0; k<context.naptr_rrs_count; k++){ | ||||
|                free(context.naptr_rrs[k].result); | ||||
|                free(context.naptr_rrs[k].tech); | ||||
|        } | ||||
|  | ||||
|        free(context.naptr_rrs); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /*--- ast_get_txt: Get TXT record from DNS.  | ||||
| /*--- ast_get_txt: Get TXT record from DNS. | ||||
| 	Really has nothing to do with enum, but anyway... | ||||
|  */ | ||||
| int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen) | ||||
| @@ -398,7 +559,7 @@ int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dst | ||||
| 		tmp[newpos++] = number[pos--]; | ||||
| 		tmp[newpos++] = '.'; | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if (chan && ast_autoservice_start(chan) < 0) | ||||
| 		return -1; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user