Пример #1
0
int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
{
	char *user_s;
	int user_len, i, j;
	char name[MAX_DOMAIN_SIZE];
	char apex[MAX_COMPONENT_SIZE + 1];
	char separator[MAX_COMPONENT_SIZE + 1];
	int sdl = 0;    /* subdomain location: infrastructure enum offset */
	int cc_len;
	struct rdata* head;

	char string[17];

	str *suffix, *service;

	suffix = (str*)_suffix;
	service = (str*)_service;

	if (parse_sip_msg_uri(_msg) < 0) {
		LM_ERR("Parsing of R-URI failed\n");
		return -1;
	}

	if (is_e164(&(_msg->parsed_uri.user)) == -1) {
		LM_ERR("R-URI user is not an E164 number\n");
		return -1;
	}

	user_s = _msg->parsed_uri.user.s;
	user_len = _msg->parsed_uri.user.len;

	/* make sure we don't run out of space in strings */
	if (( 2*user_len + MAX_COMPONENT_SIZE + MAX_COMPONENT_SIZE + 4) > MAX_DOMAIN_SIZE) {
		LM_ERR("Strings too long\n");
		return -1;
	}
	if ( i_branchlabel.len > MAX_COMPONENT_SIZE ) {
		LM_ERR("i_branchlabel too long\n");
		return -1;
	}
	if ( suffix->len > MAX_COMPONENT_SIZE ) {
		LM_ERR("Suffix too long\n");
		return -1;
	}


	memcpy(&(string[0]), user_s, user_len);
	string[user_len] = (char)0;

	/* Set up parameters as for user-enum */
	memcpy(apex,  suffix->s , suffix->len);
	apex[suffix->len] = (char)0;
	sdl = 0;		/* where to insert i-enum separator */
	separator[0] = 0;	/* don't insert anything */

	cc_len = cclen(string + 1);

	if (!strncasecmp(i_bl_alg.s,"ebl",i_bl_alg.len)) {
		sdl = cc_len; /* default */

		j = 0;
		memcpy(name, i_branchlabel.s, i_branchlabel.len);
		j += i_branchlabel.len;
		name[j++] = '.';

		for (i = cc_len ; i > 0; i--) {
			name[j++] = user_s[i];
			name[j++] = '.';
		}
		memcpy(name + j, suffix->s, suffix->len + 1);

		LM_DBG("Looking for EBL record for %s.\n", name); 
		head = get_record(name, T_EBL);
		if (head == 0) {
			LM_DBG("No EBL found for %s. Defaulting to user ENUM.\n",name);
		} else {
		    	struct ebl_rdata* ebl;
			ebl = (struct ebl_rdata *) head->rdata;

			LM_DBG("EBL record for %s is %d / %.*s / %.*s.\n",
			       name, ebl->position, (int)ebl->separator_len,
			       ebl->separator,(int)ebl->apex_len, ebl->apex);

			if ((ebl->apex_len > MAX_COMPONENT_SIZE) || (ebl->separator_len > MAX_COMPONENT_SIZE)) {
				LM_ERR("EBL strings too long\n"); 
				return -1;
			}

			if (ebl->position > 15)  {
				LM_ERR("EBL position too large (%d)\n",
				       ebl->position); 
				return -1;
			}

			sdl = ebl->position;

			memcpy(separator, ebl->separator, ebl->separator_len);
			separator[ebl->separator_len] = 0;

			memcpy(apex, ebl->apex, ebl->apex_len);
			apex[ebl->apex_len] = 0;
			free_rdata_list(head);
		}
	} else if (!strncasecmp(i_bl_alg.s,"txt",i_bl_alg.len)) {
		sdl = cc_len; /* default */
		memcpy(separator, i_branchlabel.s, i_branchlabel.len);
		separator[i_branchlabel.len] = 0;
		/* no change to apex */

		j = 0;
		memcpy(name, i_branchlabel.s, i_branchlabel.len);
		j += i_branchlabel.len;
		name[j++] = '.';

		for (i = cc_len ; i > 0; i--) {
			name[j++] = user_s[i];
			name[j++] = '.';
		}
		memcpy(name + j, suffix->s, suffix->len + 1);

		head = get_record(name, T_TXT);
		if (head == 0) {
			LM_DBG("TXT found for %s. Defaulting to %d\n",
			       name, cc_len);
		} else {
			sdl = atoi(((struct txt_rdata*)head->rdata)->txt);
			LM_DBG("TXT record for %s is %d.\n", name, sdl);

			if ((sdl < 0) || (sdl > 10)) {
				LM_ERR("Sdl %d out of bounds. Set back to cc_len.\n", sdl);
				sdl = cc_len;
			}
			free_rdata_list(head);
		}
	} else {	/* defaults to CC */
		sdl = cc_len;
		memcpy(separator, i_branchlabel.s, i_branchlabel.len);
		separator[i_branchlabel.len] = 0;
		/* no change to apex */
	}

	j = 0;
	sdl++; /* to avoid comparing i to (sdl+1) */
	for (i = user_len - 1; i > 0; i--) {
		name[j] = user_s[i];
		name[j + 1] = '.';
		j = j + 2;
		if (separator[0] && (i == sdl)) { /* insert the I-ENUM separator here? */
			strcpy(name + j, separator);  /* we've checked string sizes. */
			j += strlen(separator);
			name[j++] = '.';
		}
	}

	memcpy(name + j, apex, strlen(apex)+1);

	return do_query(_msg, string, name, service);
}
Пример #2
0
/* ENUM lookup */
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options, unsigned int record, struct enum_context **argcontext)
{
	struct enum_context *context;
	char tmp[512];
	char domain[256];
	char left[128];
	char middle[128];
	char naptrinput[128];
	char apex[128] = "";
	int ret = -1;
	/* for ISN rewrite */
	char *p1 = NULL;
	char *p2 = NULL;
	char *p3 = NULL;
	int k = 0;
	int i = 0;
	int z = 0;
	int spaceleft = 0;
	struct timeval time_start, time_end;

	if (ast_strlen_zero(suffix)) {
		ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
		return -1;
	}

	ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);

/*
  We don't need that any more, that "n" preceding the number has been replaced by a flag
  in the options paramter.
	ast_copy_string(naptrinput, number, sizeof(naptrinput));
*/
/*
 * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
 * We need to preserve that as the regex inside NAPTRs expect the +.
 *
 * But for the domain generation, the '+' is a nuissance, so we get rid of it.
*/
	ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
	if (number[0] == '+') {
		number++;
	}

	if (!(context = ast_calloc(1, sizeof(*context)))) {
		return -1;
	}

	if ((p3 = strchr(naptrinput, '*'))) {
		*p3='\0';
	}

	context->naptrinput = naptrinput;	/* The number */
	context->dst = dst;			/* Return string */
	context->dstlen = dstlen;
	context->tech = tech;
	context->techlen = techlen;
	context->options = 0;
	context->position = record > 0 ? record : 1;
	context->count = 0;
	context->naptr_rrs = NULL;
	context->naptr_rrs_count = 0;

	/*
	 * Process options:
	 *
	 *	c	Return count, not URI
	 *	i	Use infrastructure ENUM
	 *	s	Do ISN transformation
	 *	d	Direct DNS query: no reversing.
	 *
	 */
	if (options != NULL) {
		if (strchr(options,'s')) {
			context->options |= ENUMLOOKUP_OPTIONS_ISN;
		} else if (strchr(options,'i')) {
			context->options |= ENUMLOOKUP_OPTIONS_IENUM;
		} else if (strchr(options,'d')) {
			context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
		}
		if (strchr(options,'c')) {
			context->options |= ENUMLOOKUP_OPTIONS_COUNT;
		}
		if (strchr(number,'*')) {
			context->options |= ENUMLOOKUP_OPTIONS_ISN;
		}
	}
	ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
	ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
			number, tech, suffix, context->options, context->position);

	/*
	 * This code does more than simple RFC3261 ENUM. All these rewriting
	 * schemes have in common that they build the FQDN for the NAPTR lookup
	 * by concatenating
	 *    - a number which needs be flipped and "."-seperated 	(left)
	 *    - some fixed string					(middle)
	 *    - an Apex.						(apex)
	 *
	 * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
	 * ISN:  number = "middle*left", apex=from args
	 * I-ENUM: EBL parameters build the split, can change apex
	 * Direct: left="", middle=argument, apex=from args
	 *
	 */

	/* default: the whole number will be flipped, no middle domain component */
	ast_copy_string(left, number, sizeof(left));
	middle[0] = '\0';
	/*
	 * I-ENUM can change the apex, thus we copy it
	 */
	ast_copy_string(apex, suffix, sizeof(apex));
	/* ISN rewrite */
	if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
		*p1++ = '\0';
		ast_copy_string(left, number, sizeof(left));
		ast_copy_string(middle, p1, sizeof(middle) - 1);
		strcat(middle, ".");
		ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
	/* Direct DNS lookup rewrite */
	} else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
		left[0] = 0; /* nothing to flip around */
		ast_copy_string(middle, number, sizeof(middle) - 1);
		strcat(middle, ".");
		ast_debug(2, "DIRECT ENUM:  middle='%s'\n", middle);
	/* Infrastructure ENUM rewrite */
	} else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
		int sdl = 0;
		char cc[8];
		char sep[256], n_apex[256];
		int cc_len = cclen(number);
		sdl = cc_len;
		ast_mutex_lock(&enumlock);
		ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
		ast_mutex_unlock(&enumlock);

		switch (ebl_alg) {
		case ENUMLOOKUP_BLR_EBL:
			ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
			sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);

			if (sdl >= 0) {
				ast_copy_string(apex, n_apex, sizeof(apex));
				ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
			} else {
				sdl = cc_len;
			}
			break;
		case ENUMLOOKUP_BLR_TXT:
			ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
			sdl = blr_txt(cc, suffix);

			if (sdl < 0) {
				sdl = cc_len;
			}
			break;

		case ENUMLOOKUP_BLR_CC:	/* BLR is at the country-code level */
		default:
			sdl = cc_len;
			break;
		}

		if (sdl > strlen(number)) {	/* Number too short for this sdl? */
			ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
			ast_free(context);
			return 0;
		}
		ast_copy_string(left, number + sdl, sizeof(left));

		ast_mutex_lock(&enumlock);
		ast_copy_string(middle, sep, sizeof(middle) - 1);
		strcat(middle, ".");
		ast_mutex_unlock(&enumlock);

		/* check the space we need for middle */
		if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
			ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
			ast_free(context);
			return -1;
		}

		p1 = middle + strlen(middle);
		for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
			if (isdigit(*p2)) {
				*p1++ = *p2;
				*p1++ = '.';
			}
		}
		*p1 = '\0';

		ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
	}

	if (strlen(left) * 2 + 2 > sizeof(domain)) {
		ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
		ast_free(context);
		return -1;
	}

	/* flip left into domain */
	p1 = domain;
	for (p2 = left + strlen(left); p2 >= left; p2--) {
		if (isdigit(*p2)) {
			*p1++ = *p2;
			*p1++ = '.';
		}
	}
	*p1 = '\0';

	if (chan && ast_autoservice_start(chan) < 0) {
		ast_free(context);
		return -1;
	}

	spaceleft = sizeof(tmp) - 2;
	ast_copy_string(tmp, domain, spaceleft);
	spaceleft -= strlen(domain);

	if (*middle) {
		strncat(tmp, middle, spaceleft);
		spaceleft -= strlen(middle);
	}

	strncat(tmp,apex,spaceleft);
	time_start = ast_tvnow();
	ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
	time_end = ast_tvnow();

	ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
			(ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));

	if (ret < 0) {
		ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
		context->naptr_rrs_count = -1;
		strcpy(dst, "0");
		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;
	} else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
		snprintf(context->dst, context->dstlen, "%d", context->naptr_rrs_count + context->count);
	}

	if (chan) {
		ret |= ast_autoservice_stop(chan);
	}

	if (!argcontext) {
		for (k = 0; k < context->naptr_rrs_count; k++) {
			ast_free(context->naptr_rrs[k].result);
			ast_free(context->naptr_rrs[k].tech);
		}
		ast_free(context->naptr_rrs);
		ast_free(context);
	} else {
		*argcontext = context;
	}

	return ret;
}