2003-04-29 04:26:41 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk -- An open source telephony toolkit.
2003-04-29 04:26:41 +00:00
*
2006-02-14 22:18:13 +00:00
* Copyright (C) 1999 - 2006, Digium, Inc.
2003-04-29 04:26:41 +00:00
*
2005-09-14 20:46:50 +00:00
* Mark Spencer <markster@digium.com>
2003-05-01 04:29:25 +00:00
*
* Funding provided by nic.at
*
2005-09-14 20:46:50 +00:00
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \brief ENUM Support for Asterisk
2003-04-29 04:26:41 +00:00
*
2005-12-30 21:18:06 +00:00
* \author Mark Spencer <markster@digium.com>
*
* \arg Funding provided by nic.at
2006-04-05 06:43:14 +00:00
*
* \par Enum standards
*
* - NAPTR records: http://ietf.nri.reston.va.us/rfc/rfc2915.txt
* - DNS SRV records: http://www.ietf.org/rfc/rfc2782.txt
* - ENUM http://www.ietf.org/rfc/rfc3761.txt
* - ENUM for H.323: http://www.ietf.org/rfc/rfc3762.txt
* - ENUM SIP: http://www.ietf.org/rfc/rfc3764.txt
* - IANA ENUM Services: http://www.iana.org/assignments/enum-services
*
2006-04-05 13:53:06 +00:00
* \par Possible improvement
* \todo Implement a caching mechanism for multile enum lookups
* - See http://bugs.digium.com/view.php?id=6739
2003-04-29 04:26:41 +00:00
*/
2006-06-07 18:54:56 +00:00
#include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , "$Revision$" )
2003-05-16 23:33:41 +00:00
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
2003-10-27 20:00:41 +00:00
#if __APPLE_CC__ >= 1495
#include <arpa/nameser_compat.h>
#endif
2003-04-29 04:26:41 +00:00
#include <resolv.h>
2003-09-27 00:22:46 +00:00
#include <stdlib.h>
#include <string.h>
2003-08-14 21:33:49 +00:00
#include <ctype.h>
#include <regex.h>
2003-09-27 00:22:46 +00:00
#include <unistd.h>
#include <errno.h>
2003-04-29 04:26:41 +00:00
2005-04-21 06:02:45 +00:00
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/enum.h"
#include "asterisk/dns.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
2003-04-29 04:26:41 +00:00
2003-10-26 18:50:49 +00:00
#ifdef __APPLE__
#undef T_NAPTR
#define T_NAPTR 35
#endif
2004-05-16 18:12:16 +00:00
#ifdef __APPLE__
#undef T_TXT
#define T_TXT 16
#endif
2006-04-04 19:48:42 +00:00
#define TOPLEV "e164.arpa." /*!< The IETF Enum standard root, managed by the ITU */
2003-04-29 04:26:41 +00:00
2005-03-02 05:17:13 +00:00
/* Linked list from config file */
2003-05-01 04:29:25 +00:00
static struct enum_search {
2005-08-11 18:05:25 +00:00
char toplev [ 512 ];
2003-05-01 04:29:25 +00:00
struct enum_search * next ;
} * toplevs ;
2006-12-27 22:06:56 +00:00
static int enumver ;
2003-05-01 04:29:25 +00:00
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( enumlock );
2003-04-29 04:26:41 +00:00
struct naptr {
unsigned short order ;
unsigned short pref ;
2008-11-29 16:58:29 +00:00
} __attribute__ (( __packed__ ));
2003-04-29 04:26:41 +00:00
2006-01-20 00:18:42 +00:00
/*! \brief Parse NAPTR record information elements */
2006-07-07 06:55:48 +00:00
static unsigned int parse_ie ( char * data , unsigned int maxdatalen , unsigned char * src , unsigned int srclen )
2003-04-29 04:26:41 +00:00
{
2006-05-18 19:39:39 +00:00
unsigned int len , olen ;
2005-03-02 05:17:13 +00:00
2006-05-18 19:39:39 +00:00
len = olen = ( unsigned int ) src [ 0 ];
2003-04-29 04:26:41 +00:00
src ++ ;
srclen -- ;
2006-05-18 19:39:39 +00:00
if ( len > srclen ) {
2006-04-05 06:52:41 +00:00
ast_log ( LOG_WARNING , "ENUM parsing failed: Wanted %d characters, got %d \n " , len , srclen );
2003-04-29 04:26:41 +00:00
return - 1 ;
}
2006-05-18 19:39:39 +00:00
2003-04-29 04:26:41 +00:00
if ( len > maxdatalen )
len = maxdatalen ;
memcpy ( data , src , len );
2006-05-18 19:39:39 +00:00
2003-04-29 04:26:41 +00:00
return olen + 1 ;
}
2006-01-20 00:18:42 +00:00
/*! \brief Parse DNS NAPTR record used in ENUM ---*/
2006-07-07 06:55:48 +00:00
static int parse_naptr ( char * dst , int dstsize , char * tech , int techsize , unsigned char * answer , int len , char * naptrinput )
2003-04-29 04:26:41 +00:00
{
2005-09-23 02:40:38 +00:00
char tech_return [ 80 ];
2006-07-07 06:55:48 +00:00
unsigned char * oanswer = answer ;
2005-08-11 18:05:25 +00:00
char flags [ 512 ] = "" ;
char services [ 512 ] = "" ;
2005-09-23 02:40:38 +00:00
char * p ;
2005-08-11 18:05:25 +00:00
char regexp [ 512 ] = "" ;
char repl [ 512 ] = "" ;
2009-03-06 17:19:55 +00:00
char tempdst [ 512 ] = "" ;
char errbuff [ 512 ] = "" ;
2005-08-07 06:34:26 +00:00
char delim ;
char * delim2 ;
char * pattern , * subst , * d ;
2003-04-29 04:26:41 +00:00
int res ;
2009-03-06 17:19:55 +00:00
int regexp_len , rc ;
int size , matchindex ; /* size is the size of the backreference sub. */
int d_len = sizeof ( tempdst ) - 1 ;
static const int max_bt = 10 ; /* max num of regexp backreference allowed, must remain 10 to guarantee a valid backreference index */
2003-08-14 21:33:49 +00:00
regex_t preg ;
2009-03-06 17:19:55 +00:00
regmatch_t pmatch [ max_bt ];
2003-08-14 21:33:49 +00:00
2005-09-23 02:40:38 +00:00
tech_return [ 0 ] = '\0' ;
2003-11-08 23:06:59 +00:00
2004-07-14 07:44:19 +00:00
dst [ 0 ] = '\0' ;
2005-09-14 01:36:15 +00:00
2003-04-29 04:26:41 +00:00
if ( len < sizeof ( struct naptr )) {
2005-03-02 05:17:13 +00:00
ast_log ( LOG_WARNING , "NAPTR record length too short \n " );
2003-04-29 04:26:41 +00:00
return - 1 ;
}
answer += sizeof ( struct naptr );
len -= sizeof ( struct naptr );
if (( res = parse_ie ( flags , sizeof ( flags ) - 1 , answer , len )) < 0 ) {
2005-03-02 05:17:13 +00:00
ast_log ( LOG_WARNING , "Failed to get flags from NAPTR record \n " );
2005-09-23 02:40:38 +00:00
return - 1 ;
} else {
answer += res ;
len -= res ;
2005-03-02 05:17:13 +00:00
}
2003-04-29 04:26:41 +00:00
if (( res = parse_ie ( services , sizeof ( services ) - 1 , answer , len )) < 0 ) {
2005-03-02 05:17:13 +00:00
ast_log ( LOG_WARNING , "Failed to get services from NAPTR record \n " );
2005-09-23 02:40:38 +00:00
return - 1 ;
} else {
answer += res ;
len -= res ;
2005-03-02 05:17:13 +00:00
}
if (( res = parse_ie ( regexp , sizeof ( regexp ) - 1 , answer , len )) < 0 ) {
ast_log ( LOG_WARNING , "Failed to get regexp from NAPTR record \n " );
2005-09-23 02:40:38 +00:00
return - 1 ;
} else {
answer += res ;
len -= res ;
2005-03-02 05:17:13 +00:00
}
2005-09-14 01:36:15 +00:00
2006-07-07 06:55:48 +00:00
if (( res = dn_expand ( oanswer , answer + len , answer , repl , sizeof ( repl ) - 1 )) < 0 ) {
2003-04-29 04:26:41 +00:00
ast_log ( LOG_WARNING , "Failed to expand hostname \n " );
return - 1 ;
2005-09-23 02:40:38 +00:00
}
2003-08-14 21:33:49 +00:00
2005-03-02 05:17:13 +00:00
if ( option_debug > 2 ) /* Advanced NAPTR debugging */
ast_log ( LOG_DEBUG , "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s' \n " ,
naptrinput , flags , services , regexp , repl );
2003-08-14 21:33:49 +00:00
if ( tolower ( flags [ 0 ]) != 'u' ) {
2005-03-02 05:17:13 +00:00
ast_log ( LOG_WARNING , "NAPTR Flag must be 'U' or 'u'. \n " );
2003-08-14 21:33:49 +00:00
return - 1 ;
}
2005-09-23 02:40:38 +00:00
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 ));
2003-10-04 21:58:16 +00:00
} else {
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
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 ));
}
2003-08-14 21:33:49 +00:00
}
regexp_len = strlen ( regexp );
if ( regexp_len < 7 ) {
ast_log ( LOG_WARNING , "Regex too short to be meaningful. \n " );
return - 1 ;
2005-09-23 02:40:38 +00:00
}
2003-08-14 21:33:49 +00:00
2009-03-06 17:19:55 +00:00
/* this takes the first character of the regexp (which is a delimiter)
* and uses that character to find the index of the second delimiter */
2003-08-14 21:33:49 +00:00
delim = regexp [ 0 ];
delim2 = strchr ( regexp + 1 , delim );
2009-03-06 17:19:55 +00:00
if (( delim2 == NULL ) || ( regexp [ regexp_len - 1 ] != delim )) { /* is the second delimiter found, and is the end of the regexp a delimiter */
ast_log ( LOG_WARNING , "Regex delimiter error (on \" %s \" ). \n " , regexp );
return - 1 ;
} else if ( strchr (( delim2 + 1 ), delim ) == NULL ) { /* if the second delimiter is found, make sure there is a third instance. this could be the end one instead of the middle */
ast_log ( LOG_WARNING , "Regex delimiter error (on \" %s \" ). \n " , regexp );
2003-08-14 21:33:49 +00:00
return - 1 ;
}
2009-03-06 17:19:55 +00:00
pattern = regexp + 1 ; /* pattern is the regex without the begining and ending delimiter */
* delim2 = 0 ; /* zero out the middle delimiter */
subst = delim2 + 1 ; /* dst substring is everything after the second delimiter. */
regexp [ regexp_len - 1 ] = 0 ; /* zero out the last delimiter */
2003-08-14 21:33:49 +00:00
/*
* now do the regex wizardry.
*/
if ( regcomp ( & preg , pattern , REG_EXTENDED | REG_NEWLINE )) {
2009-03-06 17:19:55 +00:00
ast_log ( LOG_WARNING , "NAPTR Regex compilation error (regex = \" %s \" ). \n " , regexp );
2003-08-14 21:33:49 +00:00
return - 1 ;
}
2009-03-06 17:19:55 +00:00
if ( preg . re_nsub > ARRAY_LEN ( pmatch )) {
2005-03-02 05:17:13 +00:00
ast_log ( LOG_WARNING , "NAPTR Regex compilation error: too many subs. \n " );
2003-08-14 21:33:49 +00:00
regfree ( & preg );
return - 1 ;
}
2009-03-06 17:19:55 +00:00
/* pmatch is an array containing the substring indexes for the regex backreference sub.
* max_bt is the maximum number of backreferences allowed to be stored in pmatch */
if (( rc = regexec ( & preg , ( char * ) naptrinput , max_bt , pmatch , 0 ))) {
regerror ( rc , & preg , errbuff , sizeof ( errbuff ));
ast_log ( LOG_WARNING , "NAPTR Regex match failed. Reason: %s \n " , errbuff );
2003-08-14 21:33:49 +00:00
regfree ( & preg );
return - 1 ;
}
regfree ( & preg );
2009-03-06 17:19:55 +00:00
d = tempdst ;
2005-09-23 02:40:38 +00:00
d_len -- ;
2009-03-06 17:19:55 +00:00
/* perform the backreference sub. Search the subst for backreferences,
* when a backreference is found, retrieve the backreferences number.
* use the backreference number as an index for pmatch to retrieve the
* beginning and ending indexes of the substring to insert as the backreference.
* if no backreference is found, continue copying the subst into tempdst */
2005-09-23 02:40:38 +00:00
while ( * subst && ( d_len > 0 )) {
2009-03-06 17:19:55 +00:00
if (( subst [ 0 ] == '\\' ) && isdigit ( subst [ 1 ])) { /* is this character the beginning of a backreference */
matchindex = ( int ) ( subst [ 1 ] - '0' );
if ( matchindex >= ARRAY_LEN ( pmatch )) {
ast_log ( LOG_WARNING , "Error during regex substitution. Invalid pmatch index. \n " );
return - 1 ;
}
/* pmatch len is 10. we are garanteed a single char 0-9 is a valid index */
size = pmatch [ matchindex ]. rm_eo - pmatch [ matchindex ]. rm_so ;
2003-08-14 21:33:49 +00:00
if ( size > d_len ) {
2005-03-02 05:17:13 +00:00
ast_log ( LOG_WARNING , "Not enough space during NAPTR regex substitution. \n " );
2003-08-14 21:33:49 +00:00
return - 1 ;
2009-03-06 17:19:55 +00:00
}
/* are the pmatch indexes valid for the input length */
if (( strlen (( char * ) naptrinput ) >= pmatch [ matchindex ]. rm_eo ) && ( pmatch [ matchindex ]. rm_so <= pmatch [ matchindex ]. rm_eo )) {
memcpy ( d , ( naptrinput + ( int ) pmatch [ matchindex ]. rm_so ), size ); /* copy input substring into backreference marker */
d_len -= size ;
subst += 2 ; /* skip over backreference characters to next valid character */
d += size ;
} else {
ast_log ( LOG_WARNING , "Error during regex substitution. Invalid backreference index. \n " );
return - 1 ;
}
2003-08-14 21:33:49 +00:00
} else if ( isprint ( * subst )) {
* d ++ = * subst ++ ;
d_len -- ;
} else {
ast_log ( LOG_WARNING , "Error during regex substitution. \n " );
return - 1 ;
2003-04-29 04:26:41 +00:00
}
2003-08-14 21:33:49 +00:00
}
* d = 0 ;
2009-03-06 17:19:55 +00:00
ast_copy_string (( char * ) dst , tempdst , dstsize );
2004-07-14 07:44:19 +00:00
dst [ dstsize - 1 ] = '\0' ;
2005-09-23 02:40:38 +00:00
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 ;
}
}
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
/* tech was not specified, return first parsed RR */
ast_copy_string ( tech , tech_return , techsize );
return 1 ;
2003-04-29 04:26:41 +00:00
}
2005-09-14 01:36:15 +00:00
/* do not return requested value, just count RRs and return thei number in dst */
#define ENUMLOOKUP_OPTIONS_COUNT 1
struct enum_naptr_rr {
2005-09-23 02:40:38 +00:00
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 */
2005-09-14 01:36:15 +00:00
};
2003-09-27 00:22:46 +00:00
struct enum_context {
2005-03-02 05:17:13 +00:00
char * dst ; /* Destination part of URL from ENUM */
int dstlen ; /* Length */
char * tech ; /* Technology (from URL scheme) */
int techlen ; /* Length */
char * txt ; /* TXT record in TXT lookup */
int txtlen ; /* Length */
char * naptrinput ; /* The number to lookup */
2005-09-23 02:40:38 +00:00
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 */
2003-09-27 00:22:46 +00:00
};
2006-01-20 00:18:42 +00:00
/*! \brief Callback for TXT record lookup */
2006-07-07 06:55:48 +00:00
static int txt_callback ( void * context , unsigned char * answer , int len , unsigned char * fullanswer )
2004-05-16 18:12:16 +00:00
{
struct enum_context * c = ( struct enum_context * ) context ;
2005-03-02 05:17:13 +00:00
if ( answer == NULL ) {
2004-05-16 18:12:16 +00:00
c -> txt = NULL ;
c -> txtlen = 0 ;
return 0 ;
}
2005-03-12 06:56:22 +00:00
/* skip over first byte, as for some reason it's a vertical tab character */
answer += 1 ;
len -= 1 ;
/* answer is not null-terminated, but should be */
2006-07-13 20:14:27 +00:00
/* this is safe to do, as answer has extra bytes on the end we can
* safely overwrite with a null */
2005-03-12 16:58:04 +00:00
answer [ len ] = '\0' ;
2005-03-12 06:56:22 +00:00
/* now increment len so that len includes the null, so that we can
2006-07-13 20:14:27 +00:00
* compare apples to apples */
2005-03-12 06:56:22 +00:00
len += 1 ;
/* finally, copy the answer into c->txt */
2006-07-07 06:55:48 +00:00
ast_copy_string ( c -> txt , ( const char * ) answer , len < c -> txtlen ? len : ( c -> txtlen ));
2005-09-14 01:36:15 +00:00
2005-03-12 06:56:22 +00:00
/* just to be safe, let's make sure c->txt is null terminated */
2005-03-12 16:58:04 +00:00
c -> txt [( c -> txtlen ) - 1 ] = '\0' ;
2005-03-12 06:56:22 +00:00
2005-03-02 05:17:13 +00:00
return 1 ;
2004-05-16 18:12:16 +00:00
}
2006-01-20 00:18:42 +00:00
/*! \brief Callback from ENUM lookup function */
2006-07-07 06:55:48 +00:00
static int enum_callback ( void * context , unsigned char * answer , int len , unsigned char * fullanswer )
2003-04-29 04:26:41 +00:00
{
2006-07-13 20:14:27 +00:00
struct enum_context * c = context ;
void * p = NULL ;
int res ;
2003-09-27 00:22:46 +00:00
2006-07-13 20:14:27 +00:00
res = parse_naptr ( c -> dst , c -> dstlen , c -> tech , c -> techlen , answer , len , c -> naptrinput );
2005-09-14 01:36:15 +00:00
2006-07-13 20:14:27 +00:00
if ( res < 0 ) {
2003-09-27 00:22:46 +00:00
ast_log ( LOG_WARNING , "Failed to parse naptr :( \n " );
2004-03-03 03:12:59 +00:00
return - 1 ;
2006-07-13 20:14:27 +00:00
} 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 {
if (( p = ast_realloc ( c -> naptr_rrs , sizeof ( * c -> naptr_rrs ) * ( c -> naptr_rrs_count + 1 )))) {
c -> naptr_rrs = p ;
memcpy ( & c -> naptr_rrs [ c -> naptr_rrs_count ]. naptr , answer , sizeof ( c -> naptr_rrs -> naptr ));
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 ;
2004-03-03 03:12:59 +00:00
}
2003-09-27 00:22:46 +00:00
2006-07-13 20:14:27 +00:00
if ( c -> options & ENUMLOOKUP_OPTIONS_COUNT ) { /* counting RRs */
snprintf ( c -> dst , c -> dstlen , "%d" , c -> position );
}
2003-09-27 00:22:46 +00:00
2003-04-29 04:26:41 +00:00
return 0 ;
}
2006-01-20 00:18:42 +00:00
/*! \brief ENUM lookup */
2006-10-31 10:56:20 +00:00
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 )
2003-04-29 04:26:41 +00:00
{
2003-09-27 00:22:46 +00:00
struct enum_context context ;
2005-08-11 18:05:25 +00:00
char tmp [ 259 + 512 ];
2005-09-23 02:40:38 +00:00
char naptrinput [ 512 ];
2003-04-29 04:26:41 +00:00
int pos = strlen ( number ) - 1 ;
2003-09-27 00:22:46 +00:00
int newpos = 0 ;
2003-04-29 04:26:41 +00:00
int ret = - 1 ;
2003-05-01 04:29:25 +00:00
struct enum_search * s = NULL ;
int version = - 1 ;
2005-09-23 02:40:38 +00:00
/* for ISN rewrite */
char * p1 = NULL ;
char * p2 = NULL ;
int k = 0 ;
int i = 0 ;
int z = 0 ;
2006-04-21 17:47:44 +00:00
ast_copy_string ( naptrinput , number [ 0 ] == 'n' ? number + 1 : number , sizeof ( naptrinput ));
2003-08-14 21:33:49 +00:00
2005-03-02 05:17:13 +00:00
context . naptrinput = naptrinput ; /* The number */
context . dst = dst ; /* Return string */
2003-09-27 00:22:46 +00:00
context . dstlen = dstlen ;
2005-09-23 02:40:38 +00:00
context . tech = tech ;
2003-09-27 00:22:46 +00:00
context . techlen = techlen ;
2005-09-23 02:40:38 +00:00
context . options = 0 ;
2009-03-06 17:19:55 +00:00
context . position = record > 0 ? record : 1 ;
2005-09-23 02:40:38 +00:00
context . naptr_rrs = NULL ;
context . naptr_rrs_count = 0 ;
2006-04-04 19:48:42 +00:00
if ( options != NULL ) {
if ( * options == 'c' ) {
2005-09-23 02:40:38 +00:00
context . options = ENUMLOOKUP_OPTIONS_COUNT ;
context . position = 0 ;
}
}
2003-09-27 00:22:46 +00:00
2006-10-31 10:56:20 +00:00
ast_log ( LOG_DEBUG , "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d' \n " ,
number , tech , suffix , context . options , context . position );
2003-04-29 04:26:41 +00:00
if ( pos > 128 )
pos = 128 ;
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
/* ISN rewrite */
p1 = strchr ( number , '*' );
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
if ( number [ 0 ] == 'n' ) { /* do not perform ISN rewrite ('n' is testing flag) */
p1 = NULL ;
k = 1 ; /* strip 'n' from number */
}
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
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 ++ ] = '.' ;
}
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
} else {
while ( pos >= k ) {
if ( isdigit ( number [ pos ])) {
tmp [ newpos ++ ] = number [ pos ];
tmp [ newpos ++ ] = '.' ;
}
pos -- ;
}
2003-04-29 04:26:41 +00:00
}
2005-09-14 01:36:15 +00:00
2003-09-27 00:22:46 +00:00
if ( chan && ast_autoservice_start ( chan ) < 0 )
return - 1 ;
2006-10-31 10:56:20 +00:00
if ( suffix ) {
ast_copy_string ( tmp + newpos , suffix , sizeof ( tmp ) - newpos );
2003-09-27 00:22:46 +00:00
ret = ast_search_dns ( & context , tmp , C_IN , T_NAPTR , enum_callback );
2006-10-31 10:56:20 +00:00
ast_log ( LOG_DEBUG , "ast_get_enum: ast_search_dns(%s) returned %d \n " , tmp , ret );
} else {
ret = - 1 ; /* this is actually dead code since the demise of app_enum.c */
for (;;) {
ast_mutex_lock ( & enumlock );
if ( version != enumver ) {
/* Ooh, a reload... */
s = toplevs ;
version = enumver ;
} else {
s = s -> next ;
}
ast_mutex_unlock ( & enumlock );
if ( ! s )
break ;
ast_copy_string ( tmp + newpos , s -> toplev , sizeof ( tmp ) - newpos );
ret = ast_search_dns ( & context , tmp , C_IN , T_NAPTR , enum_callback );
ast_log ( LOG_DEBUG , "ast_get_enum: ast_search_dns(%s) returned %d \n " , tmp , ret );
if ( ret > 0 )
break ;
}
2003-05-01 04:29:25 +00:00
}
2006-10-31 10:56:20 +00:00
2003-09-27 00:22:46 +00:00
if ( ret < 0 ) {
2003-04-29 04:26:41 +00:00
ast_log ( LOG_DEBUG , "No such number found: %s (%s) \n " , tmp , strerror ( errno ));
2006-02-14 22:18:13 +00:00
strcpy ( dst , "0" );
2003-04-29 04:26:41 +00:00
ret = 0 ;
}
2005-09-14 01:36:15 +00:00
2006-04-04 19:48:42 +00:00
if ( context . naptr_rrs_count >= context . position && ! ( context . options & ENUMLOOKUP_OPTIONS_COUNT )) {
/* sort array by NAPTR order/preference */
2006-07-13 20:14:27 +00:00
for ( k = 0 ; k < context . naptr_rrs_count ; k ++ ) {
for ( i = 0 ; i < context . naptr_rrs_count ; i ++ ) {
2006-04-04 19:48:42 +00:00
/* 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 ;
}
}
}
}
2006-07-13 20:14:27 +00:00
for ( k = 0 ; k < context . naptr_rrs_count ; k ++ ) {
2006-04-04 19:48:42 +00:00
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 ;
}
2003-04-29 04:26:41 +00:00
if ( chan )
ret |= ast_autoservice_stop ( chan );
2005-09-14 01:36:15 +00:00
2006-07-13 20:14:27 +00:00
for ( k = 0 ; k < context . naptr_rrs_count ; k ++ ) {
2005-09-23 02:40:38 +00:00
free ( context . naptr_rrs [ k ]. result );
free ( context . naptr_rrs [ k ]. tech );
}
2005-09-14 01:36:15 +00:00
2005-09-23 02:40:38 +00:00
free ( context . naptr_rrs );
2005-09-14 01:36:15 +00:00
2004-05-16 18:12:16 +00:00
return ret ;
}
2006-01-20 00:18:42 +00:00
/*! \brief Get TXT record from DNS.
2005-03-02 05:17:13 +00:00
Really has nothing to do with enum, but anyway...
*/
2004-05-16 18:12:16 +00:00
int ast_get_txt ( struct ast_channel * chan , const char * number , char * dst , int dstlen , char * tech , int techlen , char * txt , int txtlen )
{
struct enum_context context ;
2005-08-11 18:05:25 +00:00
char tmp [ 259 + 512 ];
char naptrinput [ 512 ] = "+" ;
2004-05-16 18:12:16 +00:00
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 );
context . naptrinput = naptrinput ;
context . dst = dst ;
context . dstlen = dstlen ;
context . tech = tech ;
context . techlen = techlen ;
context . txt = txt ;
context . txtlen = txtlen ;
if ( pos > 128 )
pos = 128 ;
2005-09-23 02:40:38 +00:00
while ( pos >= 0 ) {
2004-05-16 18:12:16 +00:00
tmp [ newpos ++ ] = number [ pos -- ];
tmp [ newpos ++ ] = '.' ;
}
2005-09-14 01:36:15 +00:00
2004-05-16 18:12:16 +00:00
if ( chan && ast_autoservice_start ( chan ) < 0 )
return - 1 ;
2005-09-23 02:40:38 +00:00
for (;;) {
2004-05-16 18:12:16 +00:00
ast_mutex_lock ( & enumlock );
if ( version != enumver ) {
/* Ooh, a reload... */
s = toplevs ;
version = enumver ;
} else {
s = s -> next ;
}
if ( s ) {
2006-04-21 17:47:44 +00:00
ast_copy_string ( tmp + newpos , s -> toplev , sizeof ( tmp ) - newpos );
2004-05-16 18:12:16 +00:00
}
ast_mutex_unlock ( & enumlock );
if ( ! s )
break ;
2005-03-02 05:17:13 +00:00
2004-05-16 18:12:16 +00:00
ret = ast_search_dns ( & context , tmp , C_IN , T_TXT , txt_callback );
if ( ret > 0 )
break ;
}
if ( ret < 0 ) {
2006-04-04 19:48:42 +00:00
if ( option_debug > 1 )
ast_log ( LOG_DEBUG , "No such number found in ENUM: %s (%s) \n " , tmp , strerror ( errno ));
2004-05-16 18:12:16 +00:00
ret = 0 ;
}
if ( chan )
ret |= ast_autoservice_stop ( chan );
2003-04-29 04:26:41 +00:00
return ret ;
}
2003-05-01 04:29:25 +00:00
2006-04-04 19:48:42 +00:00
/*! \brief Add enum tree to linked list */
2003-05-01 04:29:25 +00:00
static struct enum_search * enum_newtoplev ( char * s )
{
struct enum_search * tmp ;
2005-03-02 05:17:13 +00:00
2006-02-09 02:08:04 +00:00
if (( tmp = ast_calloc ( 1 , sizeof ( * tmp )))) {
2005-07-10 22:56:21 +00:00
ast_copy_string ( tmp -> toplev , s , sizeof ( tmp -> toplev ));
2003-05-01 04:29:25 +00:00
}
return tmp ;
}
2006-01-20 00:18:42 +00:00
/*! \brief Initialize the ENUM support subsystem */
2003-05-01 04:29:25 +00:00
int ast_enum_init ( void )
{
struct ast_config * cfg ;
struct enum_search * s , * sl ;
struct ast_variable * v ;
/* Destroy existing list */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & enumlock );
2003-05-01 04:29:25 +00:00
s = toplevs ;
while ( s ) {
sl = s ;
s = s -> next ;
free ( sl );
}
toplevs = NULL ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( "enum.conf" );
2003-05-01 04:29:25 +00:00
if ( cfg ) {
sl = NULL ;
v = ast_variable_browse ( cfg , "general" );
while ( v ) {
if ( ! strcasecmp ( v -> name , "search" )) {
s = enum_newtoplev ( v -> value );
if ( s ) {
if ( sl )
sl -> next = s ;
else
toplevs = s ;
sl = s ;
}
}
v = v -> next ;
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg );
2003-05-01 04:29:25 +00:00
} else {
toplevs = enum_newtoplev ( TOPLEV );
}
enumver ++ ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & enumlock );
2003-05-01 04:29:25 +00:00
return 0 ;
}
int ast_enum_reload ( void )
{
return ast_enum_init ();
}