don't force a default zone for ENUM() lookups, use the configuration file (issue...
[asterisk/asterisk.git] / doc / enum.txt
1 README.enum
2
3 2005-09-06 
4 jtodd@loligo.com
5
6 The ENUMLOOKUP function is more complex than it first may appear, and
7 this guide is to give a general overview and set of examples that may
8 be well-suited for the advanced user to evaluate in their
9 consideration of ENUM or ENUM-like lookup strategies.  This document
10 assumes a familiarity with ENUM (RFC3761) or ENUM-like methods, as
11 well as familiarity with NAPTR DNS records (RFC2915, RFC3401-3404).
12 For an overview of NAPTR records, and the use of NAPTRs in the ENUM
13 global phone-number-to-DNS mapping scheme, please see
14 http://www.voip-info.org/tiki-index.php?page=ENUM for more detail.
15
16 Using ENUM within Asterisk can be simple or complex, depending on how
17 many failover methods and redundancy procedures you wish to utilize.
18 Implementation of ENUM paths is supposedly defined by the person
19 creating the NAPTR records, but the local administrator may choose to
20 ignore certain NAPTR response methods (URI types) or prefer some over
21 others, which is in contradiction to the RFC.  The ENUMLOOKUP method
22 simply provides administrators a method for determining NAPTR results
23 in either the globally unique ENUM (e164.arpa) DNS tree, or in other
24 ENUM-like DNS trees which are not globally unique.  The methods to
25 actually create channels ("dial") results given by the ENUMLOOKUP
26 function is then up to the administrator to implement in a way that
27 best suits their environment.
28
29 Function: ENUMLOOKUP(<number>[,pointer_type[,options[,zone_suffix]]])
30
31   Performs an ENUM tree lookup on the specified number, method type,
32   and (optionally) ordinal offset, and returns one of four different values:
33
34    1) post-parsed NAPTR of one method (URI) type
35    2) count of elements of one method (URI) type
36    3) count of all method types
37    4) full URI of method at a particular point in the list of all possible methods 
38
39 Arguments:
40
41 number = telephone number or search string.  Only numeric values
42 within this string are parsed; all other digits are ignored for
43 search, but are re-written during NAPTR regexp expansion.
44
45 service_type = tel, sip, h323, iax2, mailto, ...[any other string],
46      ALL. Default type is "sip".
47      Special name of "ALL" will create a list of method types across
48      all NAPTR records for the search number, and then put the results
49      in an ordinal list starting with 1. The position <number>
50      specified will then be returned, starting with 1 as the first
51      record (lowest value) in the list.  The service types are not
52      hardcoded in Asterisk except for the default (sip) if no other
53      service type specified; any method type string (IANA-approved or
54      not) may be used except for the string "ALL".  
55
56 options = optional specifiers.
57     c = count. Returns the number of records of this type are returned
58     (regardless of order or priority.)  If "ALL" is the specified
59     service_type, then a count of all methods will be returned for the
60     DNS record.
61     <integer> = The record in priority/order sequence based on the
62     total count of records passed back by the query. If a service_type
63     is specified, all entries of that type will be sorted into an
64     ordinal list starting with 1 (by order first, then priority).
65     The default of <options> is "1"
66  
67 zone_suffix = allows customization of the ENUM zone. If no zone_suffix is 
68     given the default zones are taken from enum.conf
69
70
71 EXAMPLE USES:
72
73 Let's use this ENUM list as an example (note that these examples exist
74 in the DNS, and will hopefully remain in place as example
75 destinations, but they may change or become invalid over time.  The
76 end result URIs are not guaranteed to actually work, since some of
77 these hostnames or SIP proxies are imaginary.  Of course, the tel:
78 replies go to directory assistance for New York City and San
79 Francisco...)  Also note that the complex SIP NAPTR at weight 30 will
80 strip off the leading "+" from the dialed string if it exists.  This
81 is probably a better NAPTR than hard-coding the number into the NAPTR,
82 and it is included as a more complex regexp example, though other
83 simpler NAPTRs will work just as well.
84
85
86 0.2.0.1.1.6.5.1.0.3.1.loligo.com. 3600 IN NAPTR 10 100 "u" "E2U+tel" "!^\\+13015611020$!tel:+12125551212!" .
87 0.2.0.1.1.6.5.1.0.3.1.loligo.com. 3600 IN NAPTR 21 100 "u" "E2U+tel" "!^\\+13015611020$!tel:+14155551212!" .
88 0.2.0.1.1.6.5.1.0.3.1.loligo.com. 3600 IN NAPTR 25 100 "u" "E2U+sip" "!^\\+13015611020$!sip:2203@sip.fox-den.com!" .
89 0.2.0.1.1.6.5.1.0.3.1.loligo.com. 3600 IN NAPTR 26 100 "u" "E2U+sip" "!^\\+13015611020$!sip:1234@sip-2.fox-den.com!" .
90 0.2.0.1.1.6.5.1.0.3.1.loligo.com. 3600 IN NAPTR 30 100 "u" "E2U+sip" "!^\\+*([^\\*]*)!sip:\\1@sip-3.fox-den.com!" .
91 0.2.0.1.1.6.5.1.0.3.1.loligo.com. 3600 IN NAPTR 55 100 "u" "E2U+mailto" "!^\\+13015611020$!mailto:jtodd@fox-den.com!" .
92
93 Example 1: Simplest case, using first SIP return (use all defaults
94 except for domain name)
95 exten => 100,1,Set(foo=${ENUMLOOKUP(+13015611020,,,loligo.com)})
96   returns: ${foo}="2203@sip.fox-den.com"
97
98 Example 2: What is the first "tel" pointer type for this number?
99 (after sorting by order/preference; default of "1" is assumed in
100 options field)
101 exten => 100,1,Set(foo=${ENUMLOOKUP(+13015611020,tel,,loligo.com)})
102   returns: ${foo}="+12125551212"
103
104 Example 3: How many "sip" pointer type entries are there for this number?
105 exten => 100,1,Set(foo=${ENUMLOOKUP(+13015611020,sip,c,loligo.com)})
106   returns: ${foo}=3
107
108 Example 4: For all the "tel" pointer type entries, what is the second
109 one in the list? (after sorting by preference)
110 exten => 100,1,Set(foo=${ENUMLOOKUP(+13015611020,tel,2,loligo.com)})
111   returns: ${foo}="+14155551212"
112
113 Example 5: How many NAPTRs (tel, sip, mailto, etc.) are in the list for this number?
114 exten => 100,1,Set(foo=${ENUMLOOKUP(+13015611020,ALL,c,loligo.com)})
115   returns: ${foo}=6
116
117 Example 6: Give back the second full URI in the sorted list of all NAPTR URIs:
118 exten => 100,1,Set(foo=${ENUMLOOKUP(+13015611020,ALL,2,loligo.com)})
119   returns: ${foo}="tel:+14155551212"  [note the "tel:" prefix in the string]
120
121 Example 7: Look up first SIP entry for the number in the default zone(s) from enum.conf 
122 exten => 100,1,Set(foo=${ENUMLOOKUP(+437203001721)})
123   returns: ${foo}="enum-test@sip.nemox.net"  [note: this result is
124   subject to change as it is "live" DNS and not under my control]
125
126
127 Example 8: Look up the ISN mapping in freenum.org alpha test zone
128 exten => 100,1,Set(foo=${ENUMLOOKUP(1234*256,,,freenum.org)})
129   returns: ${foo}="1234@204.91.156.10"  [note: this result is subject
130   to change as it is "live" DNS]
131
132 Example 9: Give back the first SIP pointer for a number in the
133 enum.yoydynelabs.com zone (invalid lookup)
134 exten => 100,1,Set(foo=${ENUMLOOKUP(1234567890,sip,1,enum.yoyodynelabs.com)})
135   returns: ${foo}=""
136
137
138 Usage notes and subtle features:
139
140   a) The use of "+" in lookups is confusing, and warrants further
141   explanation.  All E.164 numbers ("global phone numbers") by
142   definition need a leading "+" during ENUM lookup.  If you neglect to
143   add a leading "+", you may discover that numbers that seem to exist
144   in the DNS aren't getting matched by the system or are returned with
145   a null string result.  This is due to the NAPTR reply requiring a
146   "+" in the regular expression matching sequence.  Older versions of
147   Asterisk add a "+" from within the code, which may confuse
148   administrators converting to the new function.  Please ensure that
149   all ENUM (e164.arpa) lookups contain a leading "+" before lookup, so
150   ensure your lookup includes the leading plus sign.  Other DNS trees
151   may or may not require a leading "+" - check before using those
152   trees, as it is possible the parsed NAPTRs will not provide correct
153   results unless you have the correct dialed string.  If you get
154   console messages like "WARNING[24907]: enum.c:222 parse_naptr: NAPTR
155   Regex match failed." then it is very possible that the returned
156   NAPTR expects a leading "+" in the search string (or the returned
157   NAPTR is mis-formed.)
158
159   b) If a query is performed of type "c" ("count") and let's say you
160   get back 5 records and then some seconds later a query is made
161   against record 5 in the list, it may not be the case that the DNS
162   resolver has the same answers as it did a second or two ago - maybe
163   there are only 4 records in the list in the newest query.  The
164   resolver should be the canonical storage location for DNS records,
165   since that is the intent of ENUM.  However, some obscure future
166   cases may have wildly changing NAPTR records within several seconds.
167   This is a corner case, and probably only worth noting as a very rare
168   circumstance. (note: I do not object to Asterisk's dnsmgr method of
169   locally caching DNS replies, but this method needs to honor the TTL
170   given by the remote zone master.  Currently, the ENUMLOOKUP function
171   does not use the dnsmgr method of caching local DNS replies.)
172
173   c) If you want strict NAPTR value ordering, then it will be
174   necessary to use the "ALL" method to incrementally step through the
175   different returned NAPTR pointers.  You will need to use string
176   manipulation to strip off the returned method types, since the
177   results will look like "sip:12125551212" in the returned value.
178   This is a non-trivial task, though it is required in order to have
179   strict RFC compliance and to comply with the desires of the remote
180   party who is presenting NAPTRs in a particular order for a reason.
181
182   d) Default behavior for the function (even in event of an error) is
183   to move to the next priority, and the result is a null value.  Most
184   ENUM lookups are going to be failures, and it is the responsibility
185   of the dialplan administrator to manage error conditions within
186   their dialplan.  This is a change from the old app_enumlookup method
187   and it's arbitrary priority jumping based on result type or failure.
188
189   e) Anything other than digits will be ignored in lookup strings.
190   Example: a search string of "+4372030blah01721" will turn into
191   1.2.7.1.0.0.3.0.2.7.3.4.e164.arpa. for the lookup.  The NAPTR
192   parsing may cause unexpected results if there are strings inside
193   your NAPTR lookups.
194
195   f) If there exist multiple records with the same weight and order as
196   a result of your query, the function will RANDOMLY select a single
197   NAPTR from those equal results.
198
199   g) If a zone is given explicitely the function ignores the settings 
200   in enum.conf as the search zone name is now specified within the function, 
201   and the H323  driver can be chosen by the user via the dialplan. 
202
203   h) The function will digest and return NAPTRs which use older
204   (depricated) style, reversed method strings such as "sip+E2U"
205   instead of the more modern "E2U+sip"
206
207   i) There is no provision for multi-part methods at this time.  If
208   there are multiple NAPTRs with (as an example) a method of
209   "E2U+voice:sip" and then another NAPTR in the same DNS record with a
210   method of ""E2U+sip", the system will treat these both as method
211   "sip" and they will be separate records from the perspective of the
212   function.  Of course, if both records point to the same URI and have
213   equal priority/weight (as is often the case) then this will cause no
214   serious difficulty, but it bears mentioning.
215
216   j) ISN (ITAD Subscriber Number) usage:  If the search number is of
217   the form ABC*DEF (where ABC and DEF are at least one numeric digit)
218   then perform an ISN-style lookup where the lookup is manipulated to
219   C.B.A.DEF.domain.tld (all other settings and options apply.)  See
220   http://www.freenum.org/ for more details on ISN lookups.  In the
221   unlikely event you wish to avoid ISN re-writes, put an "n" as the
222   first digit of the search string - the "n" will be ignored for the search.
223
224
225 ==EXAMPLES==
226
227 All examples below except where noted use "e164.arpa" as the
228 referenced domain, which is the default domain name for ENUMLOOKUP if
229 'search => e164.arpa' is set in enum.conf.
230 All numbers are assumed to not have a leading "+" as dialed by the
231 inbound channel, so that character is added where necessary during
232 ENUMLOOKUP function calls.
233
234 ; example 1
235 ;
236 ; Assumes North American international dialing (011) prefix.
237 ; Look up the first SIP result and send the call there, otherwise
238 ;  send the call out a PRI.  This is the most simple possible
239 ;  ENUM example, but only uses the first SIP reply in the list of
240 ;  NAPTR(s). 
241 ;
242 exten => _011.,1,Set(enumresult=${ENUMLOOKUP(+${EXTEN:3})})
243 exten => _011.,n,Dial(SIP/${enumlookup})
244 exten => _011.,n,Dial(Zap/g1/${EXTEN})
245
246 ; end example 1
247
248 ; example 2
249 ;
250 ; Assumes North American international dialing (011) prefix.
251 ; Check to see if there are multiple SIP NAPTRs returned by 
252 ;  the lookup, and dial each in order.  If none work (or none
253 ;  exist) then send the call out a PRI, group 1.
254 ;
255 exten => _011.,1,Set(sipcount=${ENUMLOOKUP(${EXTEN:3},sip,c)}|counter=0)
256 exten => _011.,n,While($["${counter}"<"${sipcount}"])
257 exten => _011.,n,Set(counter=$[${counter}+1])
258 exten => _011.,n,Dial(SIP/${ENUMLOOKUP(+${EXTEN:3},sip,${counter})})
259 exten => _011.,n,EndWhile
260 exten => _011.,n,Dial(Zap/g1/${EXTEN})
261 ;
262 ; end example 2
263
264 ; example 3
265 ;
266 ; This example expects an ${EXTEN} that is an e.164 number (like
267 ;  14102241145 or 437203001721)
268 ; Search through e164.arpa and then also search through e164.org
269 ;  to see if there are any valid SIP or IAX termination capabilities.
270 ;  If none, send call out via Zap channel 1.
271 ;
272 ; Start first with e164.arpa zone...
273 ;
274 exten => _X.,1,Set(sipcount=${ENUMLOOKUP(+${EXTEN},sip,c,e164.arpa)}|counter=0)
275 exten => _X.,2,GotoIf($["${counter}"<"${sipcount}"]?3:6)
276 exten => _X.,3,Set(counter=$[${counter}+1])
277 exten => _X.,4,Dial(SIP/${ENUMLOOKUP(+${EXTEN},sip,${counter},e164.arpa)})
278 exten => _X.,5,GotoIf($["${counter}"<"${sipcount}"]?3:6)
279 ;
280 exten => _X.,6,Set(iaxcount=${ENUMLOOKUP(+${EXTEN},iax2,c,e164.arpa)}|counter=0)
281 exten => _X.,7,GotoIf($["${counter}"<"${iaxcount}"]?8:11)
282 exten => _X.,8,Set(counter=$[${counter}+1])
283 exten => _X.,9,Dial(IAX2/${ENUMLOOKUP(+${EXTEN},iax2,${counter},e164.arpa)})
284 exten => _X.,10,GotoIf($["${counter}"<"${iaxcount}"]?8:11)
285 ;
286 exten => _X.,11,NoOp("No valid entries in e164.arpa for ${EXTEN} - checking in e164.org")
287 ;
288 ; ...then also try e164.org, and look for SIP and IAX NAPTRs...
289 ;
290 exten => _X.,12,Set(sipcount=${ENUMLOOKUP(+${EXTEN},sip,c,e164.org)}|counter=0)
291 exten => _X.,13,GotoIf($["${counter}"<"${sipcount}"]?14:17)
292 exten => _X.,14,Set(counter=$[${counter}+1])
293 exten => _X.,15,Dial(SIP/${ENUMLOOKUP(+${EXTEN},sip,${counter},e164.org)})
294 exten => _X.,16,GotoIf($["${counter}"<"${sipcount}"]?14:17)
295 ;
296 exten => _X.,17,Set(iaxcount=${ENUMLOOKUP(+${EXTEN},iax2,c,e164.org)}|counter=0)
297 exten => _X.,18,GotoIf($["${counter}"<"${iaxcount}"]?19:22)
298 exten => _X.,19,Set(counter=$[${counter}+1])
299 exten => _X.,20,Dial(IAX2/${ENUMLOOKUP(+${EXTEN},iax2,${counter},e164.org)})
300 exten => _X.,21,GotoIf($["${counter}"<"${iaxcount}"]?19:22)
301 ;
302 ; ...then send out PRI.
303 ;
304 exten => _X.,22,NoOp("No valid entries in e164.org for ${EXTEN} - sending out via Zap")
305 exten => _X.,23,Dial(Zap/g1/${EXTEN})
306 ;
307 ; end example 3
308
309 ;
310 ;
311 ; An alternative to example 3 would be setting the search zones in enum.conf like
312 ; search => e164.arpa
313 ; search => e164.org
314 ;
315 ; Start start matching the default zones from configuration:
316 exten => _X.,1,Set(sipcount=${ENUMLOOKUP(+${EXTEN},sip,c)}|counter=0)
317 exten => _X.,2,GotoIf($["${counter}"<"${sipcount}"]?3:6)
318 exten => _X.,3,Set(counter=$[${counter}+1])
319 exten => _X.,4,Dial(SIP/${ENUMLOOKUP(+${EXTEN},sip,${counter})})
320 exten => _X.,5,GotoIf($["${counter}"<"${sipcount}"]?3:6)
321 ;
322 exten => _X.,6,Set(iaxcount=${ENUMLOOKUP(+${EXTEN},iax2,c)}|counter=0)
323 exten => _X.,7,GotoIf($["${counter}"<"${iaxcount}"]?8:11)
324 exten => _X.,8,Set(counter=$[${counter}+1])
325 exten => _X.,9,Dial(IAX2/${ENUMLOOKUP(+${EXTEN},iax2,${counter})})
326 exten => _X.,10,GotoIf($["${counter}"<"${iaxcount}"]?8:11)
327 ;
328 exten => _X.,11,NoOp("No valid entries in default zones from enum.conf for ${EXTEN}")
329 ;
330