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 ( ) ;
}