[asterisk-commits] branch oej/test-this-branch r10714 - in
/team/oej/test-this-branch: ./ doc/
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Wed Feb 22 09:56:25 MST 2006
Author: oej
Date: Wed Feb 22 10:56:14 2006
New Revision: 10714
URL: http://svn.digium.com/view/asterisk?rev=10714&view=rev
Log:
Adding carrier ENUM support (patch #5526)
Modified:
team/oej/test-this-branch/README.test-this-branch
team/oej/test-this-branch/doc/enum.txt
team/oej/test-this-branch/enum.c
Modified: team/oej/test-this-branch/README.test-this-branch
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/README.test-this-branch?rev=10714&r1=10713&r2=10714&view=diff
==============================================================================
--- team/oej/test-this-branch/README.test-this-branch (original)
+++ team/oej/test-this-branch/README.test-this-branch Wed Feb 22 10:56:14 2006
@@ -19,14 +19,15 @@
- peermatch: New peer matching algorithm (no bug report yet)
- rtcp: Improved support for RTCP (#2863)
- dialplan-ami-events: Report dialplan reload in manager (#5741)
-- sipregister: A new registration architecture (#5834)
-- subscribemwi: Support for SIP subscription of MWI notification (#6390)
+- sipregister: A new registration architecture (rizzo, oej #5834)
+- subscribemwi: Support for SIP subscription of MWI notification (oej #6390)
- iptos: New IPtos support, separate audio and signalling (#6355)
And the following stand-alone patches
-- New CLI commands for global variables (#6506)
-- Additional options for the CHANNEL dialplan function
+- New CLI commands for global variables (oej, #6506)
+- Additional options for the CHANNEL dialplan function (oej)
- Manager sendtext event (ZX81, #6131)
+- Carrier ENUM support (otmar, #5526)
Coming here soon:
- metermaids: Subscription support for parking lots (#5779)
Modified: team/oej/test-this-branch/doc/enum.txt
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/doc/enum.txt?rev=10714&r1=10713&r2=10714&view=diff
==============================================================================
--- team/oej/test-this-branch/doc/enum.txt (original)
+++ team/oej/test-this-branch/doc/enum.txt Wed Feb 22 10:56:14 2006
@@ -25,6 +25,14 @@
actually create channels ("dial") results given by the ENUMLOOKUP
function is then up to the administrator to implement in a way that
best suits their environment.
+
+This function uses the enum.conf configuration file. You can turn
+on verbose output by setting verbose to an integer > 0, e.g.
+
+; enum.conf
+[general]
+verbose => 10
+
Function: ENUMLOOKUP(<number>[,pointer_type[,options[,zone_suffix]]])
@@ -125,7 +133,7 @@
Example 8: Look up the ISN mapping in freenum.org alpha test zone
-exten => 100,1,Set(foo=${ENUMLOOKUP(1234*256,,,freenum.org)})
+exten => 100,1,Set(foo=${ENUMLOOKUP(1234*256,,i,freenum.org)})
returns: ${foo}="1234 at 204.91.156.10" [note: this result is subject
to change as it is "live" DNS]
@@ -217,9 +225,45 @@
the form ABC*DEF (where ABC and DEF are at least one numeric digit)
then perform an ISN-style lookup where the lookup is manipulated to
C.B.A.DEF.domain.tld (all other settings and options apply.) See
- http://www.freenum.org/ for more details on ISN lookups. In the
- unlikely event you wish to avoid ISN re-writes, put an "n" as the
- first digit of the search string - the "n" will be ignored for the search.
+ http://www.freenum.org/ for more details on ISN lookups.
+ In previous versions this feature was enable by default, now
+ you need to add an 'i' to the options to perform ISN-style lookups.
+
+
+ k) Carrier ENUM usage: If "r" is contained in the options field, then
+ the lookup will follow the Carrier ENUM rules as proposed in
+ ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberler-carrier-enum-01.txt
+ Summary: an additional label will be inserted into the ENUM domain
+ name to branch off the carrier tree from the default user-ENUM tree.
+
+ The label to insert is configured in enum.conf as:
+
+ [carrier]
+ branchlabel => carrier
+
+ Examples:
+ 4.9.7.1.carrier.e164.arpa
+ 4.9.7.carrier.1.e164.arpa
+ carrier.4.9.7.1.e164.arpa
+
+ The position of this label within the DNS tree is controlled by the blr_alg
+ parameter (also in enum.conf). Currently, there are two algorithms to
+ choose from:
+
+ blr_alg => cc
+ This algorithm always inserts the carrier label at the country-code level.
+ Examples: carrier.1.e164.arpa, carrier.3.4.e164.arpa, carrier.2.5.3.e164.arpa
+ This is the default.
+
+ blr_alg => txt
+ With this setting, ENUMLOOKUP will look for a TXT record at
+ <branchlabel>.<reverse-country-code>.<apex> to indicate after how many digits the
+ carrier label should in inserted. e.g. a
+
+ carrier.1.e164.arpa. IN TXT "4"
+
+ record will tell the module to look for carrier ENUM for +1 234 5678 999 at
+ 9.9.9.8.7.6.5.carrier.4.3.2.1.e164.arpa.
==EXAMPLES==
Modified: team/oej/test-this-branch/enum.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/enum.c?rev=10714&r1=10713&r2=10714&view=diff
==============================================================================
--- team/oej/test-this-branch/enum.c (original)
+++ team/oej/test-this-branch/enum.c Wed Feb 22 10:56:14 2006
@@ -27,6 +27,7 @@
* \arg Funding provided by nic.at
*/
+#include <sys/times.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -74,6 +75,12 @@
} *toplevs;
static int enumver = 0;
+static int enum_verbose = 0;
+static char carrier_branchlabel[32] = "carrier";
+/* how to do carrier enum branch location resolution? */
+#define ENUMLOOKUP_BLR_CC 0
+#define ENUMLOOKUP_BLR_TXT 1
+static int blr_alg = ENUMLOOKUP_BLR_CC;
AST_MUTEX_DEFINE_STATIC(enumlock);
@@ -81,6 +88,184 @@
unsigned short order;
unsigned short pref;
} __attribute__ ((__packed__));
+
+
+/*--- find_cclen: Determine the length of a country code when give a E.164 string ---*/
+/*
+ * Input: E.164 number w/o leading +
+ *
+ * Output: number of digits in the country code
+ * 0 on invalid number
+ *
+ * convention:
+ * 3 digits is the default length of a country code.
+ * country codes 1 and 7 are a single digit.
+ * the following country codes are two digits: 20, 27, 30-34, 36, 39,
+ * 40, 41, 43-49, 51-58, 60-66, 81, 82, 84, 86, 90-95, 98.
+ */
+static int cclen(const char *number)
+{
+ char d1,d2;
+
+ if (!number || (strlen(number) < 3))
+ return(0);
+
+ d1 = number[0];
+ d2 = number[1];
+
+ if (!isdigit(d2))
+ return(0);
+
+ switch(d1) {
+ case '1':
+ case '7':
+ return(1);
+ case '2':
+ if ((d2 == '0') || (d1 == '7'))
+ return(2);
+ break;
+ case '3':
+ if ((d2 >= '0') && (d1 <= '4'))
+ return(2);
+ if ((d2 == '6') || (d1 == '9'))
+ return(2);
+ break;
+ case '4':
+ if (d2 != '2')
+ return(2);
+ break;
+ case '5':
+ if ((d2 >= '1') && (d1 <= '8'))
+ return(2);
+ break;
+ case '6':
+ if (d1 <= '6')
+ return(2);
+ break;
+ case '8':
+ if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6'))
+ return(2);
+ break;
+ case '9':
+ if (d1 <= '5')
+ return(2);
+ if (d2 == '8')
+ return(2);
+ break;
+ default:
+ return(0);
+ }
+
+ return(3);
+}
+
+
+struct txt_context {
+ char txt[1024]; /* TXT record in TXT lookup */
+ int txtlen; /* Length */
+};
+
+/*--- txt_callback2: Callback for TXT record lookup, /ol version */
+static int txt_callback2(void *context, char *answer, int len, char *fullanswer)
+{
+ struct txt_context *c = (struct txt_context *)context;
+ unsigned int i;
+
+ c->txt[0] = 0; /* default to empty */
+ c->txtlen = 0;
+
+ if (answer == NULL) {
+ return 0;
+ }
+
+ /* RFC1035:
+ *
+ * <character-string> is a single length octet followed by that number of characters.
+ * TXT-DATA One or more <character-string>s.
+ *
+ * We only take the first string here.
+ */
+
+ i = *answer++;
+ len -= 1;
+
+ if (i > len) { /* illegal packet */
+ ast_log(LOG_WARNING, "txt_callback2: malformed TXT record.\n");
+ return 0;
+ }
+
+ if (i >= sizeof(c->txt)) { /* too long? */
+ ast_log(LOG_WARNING, "txt_callback2: TXT record too long.\n");
+ i = sizeof(c->txt) - 1;
+ }
+
+ ast_copy_string(c->txt, answer, i + 1);
+ c->txtlen = i;
+
+ return 1;
+}
+
+
+/*--- blr_txt: Determine the branch location record as stored in a TXT record ---*/
+/*
+ * Input: CC code
+ *
+ * Output: number of digits in the number before the carrier branch
+ *
+ * Algorithm: Build <carrier_branchlabel>.c.c.<suffix> and look for a TXT lookup.
+ * Return atoi(TXT-record).
+ * Return -1 on not found.
+ *
+ */
+static int blr_txt(const char *cc, const char *suffix)
+{
+ struct txt_context context;
+ char domain[128];
+ char *p1,*p2;
+ int ret;
+
+ ast_mutex_lock(&enumlock);
+ if (sizeof(domain) < (strlen(cc) * 2 + strlen(carrier_branchlabel) + strlen(suffix) + 2)) {
+ ast_mutex_unlock(&enumlock);
+ ast_log(LOG_WARNING, "ERROR: string sizing in blr_txt.\n");
+ return(-1);
+ }
+
+ strcpy(domain, carrier_branchlabel);
+ p1 = domain + strlen(domain);
+ ast_mutex_unlock(&enumlock);
+
+ *p1++ = '.';
+ *p1 = 0;
+
+ p2 = (char *) cc + strlen(cc) - 1;
+ while(p2 >= cc) {
+ if (isdigit(*p2)) {
+ *p1++ = *p2;
+ *p1++ = '.';
+ }
+ p2--;
+ }
+ strcat(p1, suffix);
+
+ if (enum_verbose > 4)
+ ast_verbose(VERBOSE_PREFIX_4 "blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
+
+ ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback2);
+ if (ret > 0) {
+ ret = atoi(context.txt);
+
+ if ((ret>=0) && (ret<20)) {
+ if (enum_verbose > 3)
+ ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
+ return(ret);
+ }
+ }
+ if (enum_verbose > 3)
+ ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
+ return(-1);
+}
+
/*! \brief Parse NAPTR record information elements */
static int parse_ie(char *data, int maxdatalen, char *src, int srclen)
@@ -161,6 +346,10 @@
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);
+ if (enum_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
+ naptrinput, flags, services, regexp, repl);
+
if (tolower(flags[0]) != 'u') {
ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
@@ -287,6 +476,10 @@
/* do not return requested value, just count RRs and return thei number in dst */
#define ENUMLOOKUP_OPTIONS_COUNT 1
+/* do an ISN style lookup */
+#define ENUMLOOKUP_OPTIONS_ISN 2
+/* do a carrier ENUM lookup */
+#define ENUMLOOKUP_OPTIONS_CARRIER 4
struct enum_naptr_rr {
struct naptr naptr; /* order and preference of RR */
@@ -386,10 +579,12 @@
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];
- int pos = strlen(number) - 1;
- int newpos = 0;
+ char tmp[512];
+ char domain[256];
+ char left[128];
+ char middle[128];
+
+ char naptrinput[128];
int ret = -1;
struct enum_search *s = NULL;
int version = -1;
@@ -399,12 +594,25 @@
int k = 0;
int i = 0;
int z = 0;
-
+ int spaceleft = 0;
+ struct timeval time_start, time_end;
+
+#if 0
if (number[0] == 'n') {
strncpy(naptrinput, number+1, sizeof(naptrinput));
} else {
- strncpy(naptrinput, number, sizeof(naptrinput));
- }
+ strncpy(naptrinput, number, sizeof(naptrinput)); }
+#endif
+
+ /*
+ * The "number" paramter 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, sizeof(naptrinput));
+ if (number[0] == '+')
+ number++;
context.naptrinput = naptrinput; /* The number */
context.dst = dst; /* Return string */
@@ -416,52 +624,128 @@
context.naptr_rrs = NULL;
context.naptr_rrs_count = 0;
+ /*
+ * Process options:
+ *
+ * c Return count, not URI
+ * i Do ISN transformation
+ * r Use carrier ENUM
+ * \d+ Return n-th URI
+ *
+ */
if (options != NULL){
- if (*options == 'c'){
- context.options = ENUMLOOKUP_OPTIONS_COUNT;
+ if (strchr(options,'i'))
+ context.options |= ENUMLOOKUP_OPTIONS_ISN;
+ else if (strchr(options,'r'))
+ context.options |= ENUMLOOKUP_OPTIONS_CARRIER;
+
+ if (strchr(options,'c')){
+ context.options |= ENUMLOOKUP_OPTIONS_COUNT;
context.position = 0;
} else {
- context.position = atoi(options);
+ char *digits = options;
+ while (*digits && (!isdigit(*digits)))
+ digits++;
+ context.position = atoi(digits);
if (context.position < 1)
context.position = 1;
}
}
- if (pos > 128)
- pos = 128;
+ if (enum_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "ENUM options(%s): pos=%d, options='%d'\n",
+ options, context.position, context.position);
+
+ /* default: the whole number will be flipped, no middle domain component */
+ ast_copy_string(left, number, sizeof(left));
+ middle[0] = '\0';
/* 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++;
+ 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)-2);
+ strcat(middle, ".");
+
+ if (enum_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "ISM ENUM: left=%s, middle='%s'\n",
+ left, middle);
+
+
+ /* Carrier ENUM rewrite */
+ } else if (context.options & ENUMLOOKUP_OPTIONS_CARRIER) {
+ int sdl=0;
+ char cc[8];
+ int cc_len = cclen(number);
+
+
+ switch(blr_alg) {
+ case ENUMLOOKUP_BLR_TXT:
+ strncpy(cc, number, cc_len); /* cclen() never returns more than 3 */
+ cc[cc_len] = 0;
+
+ /* carrier ENUM is only called via ENUMLOOKUP, thus we have a suffix */
+ 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, "CARRIER ENUM: subdomain location %d behind number %s\n", sdl, number);
+ return(0);
+ }
+
+ ast_copy_string(left, number+sdl, sizeof(left));
+
+ ast_mutex_lock(&enumlock);
+ ast_copy_string(middle, carrier_branchlabel, sizeof(middle) - 2);
+ strcat(middle, ".");
+ ast_mutex_unlock(&enumlock);
+
+ p1 = middle + strlen(middle);
+ p2 = (char *) number + sdl - 1;
+ while(p2 >= number) {
+ if (isdigit(*p2)) {
+ *p1++ = *p2;
+ *p1++ = '.';
}
- tmp[newpos++] = '.';
- }
-
- } else {
- while (pos >= k) {
- if (isdigit(number[pos])) {
- tmp[newpos++] = number[pos];
- tmp[newpos++] = '.';
- }
- pos--;
- }
- }
+ p2--;
+ }
+ *p1 = '\0';
+
+ if (enum_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "CARRIER ENUM: cclen=%d, left=%s, middle='%s'\n",
+ cc_len, left, middle);
+
+ }
+
+
+ if (strlen(left)*2 + 2 > sizeof(domain)) {
+ ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
+ return -1;
+ }
+
+ /* flip left into domain */
+ p1 = domain;
+ p2 = left + strlen(left);
+ while(p2 >= left) {
+ if (isdigit(*p2)) {
+ *p1++ = *p2;
+ *p1++ = '.';
+ }
+ p2--;
+ }
+ *p1 = '\0';
+
if (chan && ast_autoservice_start(chan) < 0)
return -1;
@@ -475,18 +759,37 @@
} else {
s = s->next;
}
+ spaceleft = sizeof(tmp) - 2;
+ ast_copy_string(tmp, domain, spaceleft);
+ spaceleft -= strlen(domain);
+ if (*middle) {
+ strncat(tmp, middle, spaceleft);
+ spaceleft -= strlen(middle);
+ }
+
+
if (suffix != NULL) {
- strncpy(tmp + newpos, suffix, sizeof(tmp) - newpos - 1);
+ strncat(tmp, suffix, spaceleft);
} else if (s) {
- strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
+ strncat(tmp, s->toplev, spaceleft);
}
ast_mutex_unlock(&enumlock);
if (!s)
break;
+
+ (void) gettimeofday(&time_start, NULL);
ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
+ (void) gettimeofday(&time_end, NULL);
+
+ if (enum_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "ast_get_enum() profiling: %s, %s, %ld usec\n",
+ (ret>0) ? "OK" : "FAIL", tmp,
+ (time_end.tv_sec - time_start.tv_sec) * 1000000 +
+ (time_end.tv_usec - time_start.tv_usec));
+
if (ret > 0)
break;
- if (suffix != NULL)
+ if (suffix != NULL) /* don't need to loop if apex was given */
break;
}
if (ret < 0) {
@@ -552,16 +855,13 @@
{
struct enum_context context;
char tmp[259 + 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);
-
- context.naptrinput = naptrinput;
+ context.naptrinput = NULL;
context.dst = dst;
context.dstlen = dstlen;
context.tech = tech;
@@ -589,7 +889,7 @@
s = s->next;
}
if (s) {
- strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
+ ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
}
ast_mutex_unlock(&enumlock);
if (!s)
@@ -625,6 +925,7 @@
struct ast_config *cfg;
struct enum_search *s, *sl;
struct ast_variable *v;
+ char *string;
/* Destroy existing list */
ast_mutex_lock(&enumlock);
@@ -637,10 +938,18 @@
toplevs = NULL;
cfg = ast_config_load("enum.conf");
if (cfg) {
+ if ((string=ast_variable_retrieve(cfg, "general", "verbose"))) {
+ enum_verbose = atoi(string);
+ } else {
+ enum_verbose = 0;
+ }
+
sl = NULL;
v = ast_variable_browse(cfg, "general");
while(v) {
if (!strcasecmp(v->name, "search")) {
+ if (enum_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "ast_enum_init() adding apex: %s\n", v->value);
s = enum_newtoplev(v->value);
if (s) {
if (sl)
@@ -652,6 +961,18 @@
}
v = v->next;
}
+ if (!sl) /* no search param in config file */
+ toplevs = enum_newtoplev(TOPLEV);
+
+ if ((string=ast_variable_retrieve(cfg, "carrier", "branchlabel"))) {
+ ast_copy_string(carrier_branchlabel, string, sizeof(carrier_branchlabel));
+ }
+
+ if ((string=ast_variable_retrieve(cfg, "carrier", "blr_alg"))) {
+ blr_alg = ENUMLOOKUP_BLR_CC; /* default */
+ if (!strcasecmp(string, "txt"))
+ blr_alg = ENUMLOOKUP_BLR_TXT;
+ }
ast_config_destroy(cfg);
} else {
toplevs = enum_newtoplev(TOPLEV);
More information about the asterisk-commits
mailing list