Fwd: [Asterisk-Dev] ENUM multiple records handling

John Todd jtodd at loligo.com
Tue Jul 5 09:45:36 MST 2005


[sorry for top-posting; the original post was fairly long]

Edwin -
  I saw from the Mantis notes on this that it wasn't implemented, because of unfortunate timing (conversion from apps to functions, and Kevin desired this as a function instead of an app.) 

  I have some real interest in getting ENUM to work more intelligently than it does now, since I think ENUM holds great promise (though is also fundamentally broken, as well, but that's a different story.)  I'd put $100 towards getting this done as a function, if you (or someone) could re-write it.  I also have another request, as well, if that is to be done: I'd like to see the ENUM zone able to be specified from the function call, so I can customize which zone I'd like to do the lookup in.  This is different than your linked list idea, but it relies more on "hard" requests rather than "soft" looping array pointers which have their count values hidden from the administrator and which may get very confusing.

  This function is different than any of the previous incarnations of EnumLookup (either in CVS or patches that have been submitted) because it does NOT assume a limited array of pointer types, and it also allows the dialplan designer to intelligently select or incrementally cascade through a list of pointer types and pointer preferences,  and by doing so become more in sync with the goals of ENUM in general.  Some of the flaws in my implementation are that I jumble some of the pointer types in the most simplistic methods of use, but there is a second method I show (the "ALL" incremental counter) which allows the administrator to really get their hands dirty and get the full query return values.




Function: EnumLookup(<number>[,pointer_type[,options[,zone_suffix]]])
  Performs an ENUM tree lookup on the specified number/pointer type and optional ordinal offset, and returns one of four different values (NAPTR of one pointer type, count of elements of one pointer type, count of all pointer types, or type of pointer.

<number> = e164 number

pointer_type = tel, sip, h323, iax2, mailto, ...[others], ALL.  Default type is "sip". 
     Special name of "ALL" will create a list of pointer_types across all orders, run a "uniq" pass across them, and then put the results in an ordinal list starting with 1.  The <number> specified will then be returned. If ALL is specified and there is no following <integer> or no pointers in the list, the routine returns a null value.  (see Example 6, below.)  The pointer types are not hardcoded in Asterisk except for the default if no other pointer type specified; any valid pointer type may be used except for the string "ALL".

<options> = optional specifiers. 
    c = count.  Returns the number of records of this type are returned (regardless of order or priority)
    <integer> = The record in priority/order sequence based on the total count of records passed back by the query.  If a pointer type is specified, all entries of that type will be sorted into an ordinal list starting with 1 (by order first, then priority).
    The default of <options> is "1"
 
zone_suffix = allows customization of the ENUM zone.  Default is e164.arpa.


EXAMPLE USES:

Let's use this ENUM list as an example (note the slight order/priority changes from the real world, and pardon my poor NAPTR regexp processing if I've made any errors in return values):

9.9.1.6.1.8.3.0.5.6.1.mavetju.org. 3600 IN NAPTR 10 100 "u" "tel+E2U" "!^\\+16503816199$!tel:+5551!" .
9.9.1.6.1.8.3.0.5.6.1.mavetju.org. 3600 IN NAPTR 21 100 "u" "tel+E2U" "!^\\+16503816199$!tel:+5553!" .
9.9.1.6.1.8.3.0.5.6.1.mavetju.org. 3600 IN NAPTR 25 100 "u" "sip+E2U" "!^\\+16503816199$!sip:5554 at barnet.com.au!" .
9.9.1.6.1.8.3.0.5.6.1.mavetju.org. 3600 IN NAPTR 25 100 "u" "sip+E2U" "!^\\+16503816199$!sip:5555 at barnet.com.au!" .
9.9.1.6.1.8.3.0.5.6.1.mavetju.org. 3600 IN NAPTR 55 100 "u" "mailto+E2U" "!^\\+16503816199$!mailto:5552 at mavetju.org!" .

Example 1: Simplest case, using first SIP return (all defaults)
exten => 100,1,Set(foo=EnumLookup(16503816199))
  returns:  ${foo}="5554 at barnet.com.au"

Example 2: What is the first "tel" pointer type for this number?  (after sorting by order/preference)
exten => 100,1,Set(foo=EnumLookup(16503816199,tel))
  returns: ${foo}="+5551"

Example 3: How many "sip" pointer type entries are there for this number?
exten => 100,1,Set(foo=EnumLookup(16503816199,sip,c))
  returns: ${foo}=2

Example 4: For all the "tel" pointer type entries, what is the second one in the list? (after sorting by preference)
exten => 100,1,Set(foo=EnumLookup(16503816199,tel,2))
  returns: ${foo}="+5553"

Example 5: What is the first pointer type referenced for this number? (after sorting by order/preference)
exten => 100,1,Set(foo=EnumLookup(16503816199,POINTERS))
  returns: ${foo}="tel"

Example 6: What is the third pointer type referenced for this number? (after sorting by order/preference)
exten => 100,1,Set(foo=EnumLookup(16503816199,POINTERS,3))
  returns: ${foo}="mailto"

Example 7: How many pointer types (tel, sip, mailto, etc.) are in the list for this number?
exten => 100,1,Set(foo=EnumLookup(16503816199,POINTERS,c))
  returns: ${foo}=3

Example 8: Give back the first SIP pointer for the number in the enum.yoydynelabs.com zone (invalid lookup)
exten => 100,1,Set(foo=EnumLookup(16503816199,sip,1,enum.yoyodynelabs.com))
  returns: ${foo}=[null]


With this method, you could discover:
  1) If there were any ENUM entries at all for the channel types you support
  2) If there are entries for more than 1 channel type you support, you can discover what they are, in order of preference
  3) If there is more than one priority for a channel type you support, you can discover what they are, in order of preference

This may take some looping within the dialplan, but it's actually not all that complex.  No more or less complex than writing it into an AGI, and certainly a lot more portable.

Warnings: 
  a) If a query is performed of type "count" (let's say you get back 5 records) and then some seconds later a query is made against #5 in the list, it may not be the case that the DNS resolver has the same answers as it did a second or two ago.  The resolver should be the canonical storage location for DNS records, since that is the intent of ENUM.  However, some obscure future cases may have wildly changing NAPTR records within several seconds.  This is a corner case, and probably only worth noting as a very rare circumstance.  (note: I do not object to the dnsmgr method of locally caching DNS replies, but they need to honor the TTL given by the remote zone master.)

  b) The "h323" specifier in the enum.conf file becomes irrelevant, and that whole config file can go away now since we can do sequential zone lookups from within the dialplan by referencing the EnumLookup function iteratively in the dialplan.

  c) It is difficult, if not impossible, to sort a list of ordered URIs that have recurring types out of order (i.e.: 10 tel, 20 sip, 30 tel)

  d) Default behavior (even in event of an error) should be to jump to the next priority.  Leaping to +101 or +53 or whatever, sucks.  Most ENUM lookups are going to be failures.  Anyone trying to get ENUM to work should have somewhat clueful programming skills, so checking the value of the variable should be sufficient to determine if a successful lookup has happened (which is, I believe, one of the whole points for moving to functions in the first place.)


JT



>Date: Fri, 11 Feb 2005 02:10:57 +1100
>From: Edwin Groothuis <edwin at mavetju.org>
>To: Asterisk-Dev at lists.digium.com
>Cc: Anton Holleman <anton.holleman at nominum.com>
>Subject: [Asterisk-Dev] ENUM multiple records handling
>Reply-To: Asterisk Developers Mailing List <asterisk-dev at lists.digium.com>
>
>Hello,
>
>Just tried to play around with EnumLookup() and it seems it has a
>funny behaviour when using multiple NAPTR records with different
>preferences and priorities.
>
>After some debugging, it seems always to return the first entry the
>answer section of the DNS reply.
>
>How do NAPTR records look like:
>    order preference flags service regexp replacement
>
>The records should be processed in order sort, then on preference.
>
>Right now if you do a NAPTR lookup for something which has more
>than one NAPTR record (for example: 9.9.1.6.1.8.3.0.5.6.1.mavetju.org),
>it will always use the first record. Debugging and TCP output has
>confirmed this:
>
>-----
>15:35:43.801587 202.83.176.1.domain > 10.10.10.4.33429:  52325* 5/2/2 NAPTR , NAPTR , NAPTR , NAPTR , NAPTR  (473)
>0x0000   4500 01f5 ead1 0000 4011 ffc3 ca53 b001        E....... at ....S..
>0x0010   0a0a 0a04 0035 8295 01e1 922a cc65 8580        .....5.....*.e..
>0x0020   0001 0005 0002 0002 0139 0139 0131 0136        .........9.9.1.6
>0x0030   0131 0138 0133 0130 0135 0136 0131 076d        .1.8.3.0.5.6.1.m
>0x0040   6176 6574 6a75 036f 7267 0000 2300 01c0        avetju.org..#...
>0x0050   0c00 2300 0100 000e 1000 3200 0a00 6401        ..#.......2...d.
>0x0060   7507 7465 6c2b 4532 5522 215e 5c2b 3136        u.tel+E2U"!^\+16
>0x0070   3530 3338 3136 3139 3924 2174 656c 3a2b        503816199$!tel:+
>0x0080   3631 3239 3532 3733 3532 3721 00c0 0c00        61295273527!....
>
>Feb 10 15:35:43 NOTICE[7231]: app_enumlookup.c:123 enumlookup_exec: tel: ENUM set to "61295273527"
>    -- Executing NoOp("SIP/10.10.12.2-0815b2a0", "TEL") in new stack
>    -- Executing NoOp("SIP/10.10.12.2-0815b2a0", "61295273527") in new stack
>
>-----
>15:36:40.362791 202.83.176.1.domain > 10.10.10.4.33429:  31650* 5/2/2 NAPTR , NAPTR , NAPTR , NAPTR , NAPTR  (473)
>0x0000   4500 01f5 2b75 0000 4011 bf20 ca53 b001        E...+u.. at ....S..
>0x0010   0a0a 0a04 0035 8295 01e1 7e52 7ba2 8580        .....5....~R{...
>0x0020   0001 0005 0002 0002 0139 0139 0131 0136        .........9.9.1.6
>0x0030   0131 0138 0133 0130 0135 0136 0131 076d        .1.8.3.0.5.6.1.m
>0x0040   6176 6574 6a75 036f 7267 0000 2300 01c0        avetju.org..#...
>0x0050   0c00 2300 0100 000e 1000 3900 1e00 6401        ..#.......9...d.
>0x0060   7507 7369 702b 4532 5529 215e 5c2b 3136        u.sip+E2U)!^\+16
>0x0070   3530 3338 3136 3139 3924 2173 6970 3a65        503816199$!sip:e
>0x0080   6477 696e 4062 6172 6e65 742e 636f 6d2e        dwin at barnet.com.
>0x0090   6175 2100 c00c 0023 0001 0000 0e10 0032        au!....#.......2
>
>Feb 10 15:36:40 DEBUG[7270]: enum.c:120 parse_naptr: input='+16503816199', flags='u', services='sip+E2U', regexp='!^\+16503816199$!sip:edwin at barnet.com.au!', repl=''
>    -- Executing NoOp("SIP/10.10.12.2-0815b2a0", "SIP") in new stack
>    -- Executing NoOp("SIP/10.10.12.2-0815b2a0", "SIP/edwin at barnet.com.au") in new stack
>
>
>-----
>15:40:15.604325 202.83.176.1.domain > 10.10.10.4.33429:  51499* 5/2/2 NAPTR , NAPTR , NAPTR , NAPTR , NAPTR  (473)
>0x0000   4500 01f5 3857 0000 4011 b23e ca53 b001        E...8W.. at ..>.S..
>0x0010   0a0a 0a04 0035 8295 01e1 52a7 c92b 8580        .....5....R..+..
>0x0020   0001 0005 0002 0002 0139 0139 0131 0136        .........9.9.1.6
>0x0030   0131 0138 0133 0130 0135 0136 0131 076d        .1.8.3.0.5.6.1.m
>0x0040   6176 6574 6a75 036f 7267 0000 2300 01c0        avetju.org..#...
>0x0050   0c00 2300 0100 000e 1000 3f00 1900 6401        ..#.......?...d.
>0x0060   7507 7369 702b 4532 552f 215e 5c2b 3136        u.sip+E2U/!^\+16
>0x0070   3530 3338 3136 3139 3924 2173 6970 3a36        503816199$!sip:6
>0x0080   3132 3933 3335 3330 3135 4062 6172 6e65        1293353015 at barne
>0x0090   742e 636f 6d2e 6175 2100 c00c 0023 0001        t.com.au!....#..
>
>Feb 10 15:40:15 DEBUG[7739]: enum.c:120 parse_naptr: input='+16503816199', flags='u', services='sip+E2U', regexp='!^\+16503816199$!sip:61293353015 at barnet.com.au!', repl=''
>    -- Executing NoOp("SIP/10.10.12.2-0815b2a0", "SIP") in new stack
>    -- Executing NoOp("SIP/10.10.12.2-0815b2a0", "SIP/61293353015 at barnet.com.au") in new stack
>
>
>
>I have changed asterisk/enum.c a little bit and it now supports
>multiple NAPTR records and takes the order and preference into
>account. It works as follows: The first time EnumLookup() is called,
>it loads all NAPTR records in a linked list and returns the first
>entry (order and preference wise). Every next call to EnumLookup()
>returns the next one (order and preference wise).
>
>How long does this linked list exist? Each element in the list has
>the PID of the thread which asked for the lookup first and it has
>a timer and after 15 minutes they get cleaned up. Is 15 minutes a
>lot? Yes/No. Yes because if you do a lot of lookups, it can grow a
>bit. No because you have to take timeouts into account, so if you
>have four phone numbers in it, you need a timeout of say 4x45 seconds
>which already makes 3 minutes. I can probably set it to 5 minutes
>or so, it just has to be determined later.
>
>
>A test program would be: Do a lookup, echo the type, echo the ENUM
>variable and jump back to the lookup until it fails.
>
>    exten => 700,1,NoOp(ENUM TEST)
>    exten => 700,n,EnumLookup(16503816199)
>    exten => 700,n,NoOp(SIP)
>    exten => 700,n,NoOp(${ENUM})
>    exten => 700,n,GoTo(2)
>    exten => 700,53,NoOp(TEL)
>    exten => 700,n,NoOp(${ENUM})
>    exten => 700,n,GoTo(2)
>    exten => 700,103,NoOp(FAIL)
>    exten => 700,n,Hangup()
>
>
>This will print all NAPTR records for (16503816199).mavetju.org,
>and in the right order:
>
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "ENUM TEST") in new stack
>	-- Executing EnumLookup("SIP/128.177.195.13-08144708", "16503816199") in new stack
>[...]
>    ENUM got '1'
>    Feb 11 02:03:06 NOTICE[29941]: app_enumlookup.c:124 enumlookup_exec: tel: ENUM set to "61295273527"
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "TEL") in new stack
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "61295273527") in new stack
>	-- Executing Goto("SIP/128.177.195.13-08144708", "2") in new stack
>	-- Goto (barnet-from-internet,700,2)
>	-- Executing EnumLookup("SIP/128.177.195.13-08144708", "16503816199") in new stack
>    ENUM got '1'
>    Feb 11 02:03:06 NOTICE[29941]: app_enumlookup.c:124 enumlookup_exec: tel: ENUM set to "61409227633"
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "TEL") in new stack
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "61409227633") in new stack
>	-- Executing Goto("SIP/128.177.195.13-08144708", "2") in new stack
>	-- Goto (barnet-from-internet,700,2)
>	-- Executing EnumLookup("SIP/128.177.195.13-08144708", "16503816199") in new stack
>    ENUM got '1'
>    Feb 11 02:03:06 NOTICE[29941]: app_enumlookup.c:83 enumlookup_exec: sip: ENUM set to "SIP/61293353015 at barnet.com.au"
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "SIP") in new stack
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "SIP/61293353015 at barnet.com.au") in new stack
>	-- Executing Goto("SIP/128.177.195.13-08144708", "2") in new stack
>	-- Goto (barnet-from-internet,700,2)
>	-- Executing EnumLookup("SIP/128.177.195.13-08144708", "16503816199") in new stack
>    ENUM got '1'
>    Feb 11 02:03:06 NOTICE[29941]: app_enumlookup.c:83 enumlookup_exec: sip: ENUM set to "SIP/edwin at barnet.com.au"
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "SIP") in new stack
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "SIP/edwin at barnet.com.au") in new stack
>	-- Executing Goto("SIP/128.177.195.13-08144708", "2") in new stack
>	-- Goto (barnet-from-internet,700,2)
>	-- Executing EnumLookup("SIP/128.177.195.13-08144708", "16503816199") in new stack
>    ENUM got '0'
>	-- Executing NoOp("SIP/128.177.195.13-08144708", "FAIL") in new stack
>	-- Executing Hangup("SIP/128.177.195.13-08144708", "") in new stack
>
>(verbose 3 is happy spamming here :-)
>
>
>I have made patches against the latest HEAD and the full new enum.c:
>
>	http://www.mavetju.org/~edwin/patch-enum.c
>	http://www.mavetju.org/~edwin/enum.c
>
>If you are interested, please test and let me know if it works. I
>will test it further on production machines and submit a patch to
>the bugs database.
>
>Edwin
>
>--
>Edwin Groothuis      |            Personal website: http://www.mavetju.org
>edwin at mavetju.org    |          Weblog: http://weblog.barnet.com.au/edwin/
>_______________________________________________
>Asterisk-Dev mailing list
>Asterisk-Dev at lists.digium.com
>http://lists.digium.com/mailman/listinfo/asterisk-dev
>To UNSUBSCRIBE or update options visit:
>   http://lists.digium.com/mailman/listinfo/asterisk-dev




More information about the asterisk-dev mailing list