Asterisk E164 Call Routing

How to Store Asterisk Call Routing Information in the DNS


One of the limitations of Asterisk is the dialplan definition. While using wildcards such as NXX can be reasonably flexible, for a flexible dialplan, where you might want to send calls in different directions very granularly it does not scale very well. For example, for a TSP using Asterisk, to have an asterisk gateway in every NPA would require several hundred dialplan entries, mostly identical on each gateway. Further, if you add one gateway you must update the configuration on each of the others, which could be quite a headache from an administrative point of view.

Fortunately, there is a solution to this called ENUM. It relies on DNS, is an IETF standard and can be made to scale quite nicely.

As an example, let's say we have two Asterisk servers, one in 514 (Montreal), the other in 416 (Toronto), and some 3rd party long distance, FooFone, for off-net calls.

Each gateway has some sort of zaptel interface for calling the PSTN so they would each have entries in extensions.conf for local calling:

exten => _1514NXXXXXX,1,Dial(Zap/1/${EXTEN:1})
exten => _1514NXXXXXX,2,Congestion

on mtl-gateway and

exten => _1416NXXXXXX,1,Dial(Zap/1/${EXTEN:1})
exten => _1416NXXXXXX,2,Congestion

on tor-gateway.

For calls between the gateways, say someone in Toronto wanting to reach someone in Montreal, we need to tell the Toronto gateway how to route the call. Normally this is done directly in extensions.conf, but not with Enum (E.164).

Instead we make a DNS zone called e164.example.com. In reality, it would be better to use the, ITU/IETF specified e164.arpa, but good luck getting a delegation from them if you're not a giant telephone company. Fortunately, Mark Spencer of Digium foresaw this and made the lookup domain configurable in enum.conf.

The DNS zone file for e164.example.com will contain records that look like this:


*.4.1.5.1 IN NAPTR 100 10 "u" "E2U+IAX2" "!^\\+*(.*)$!iax2:mtl-gateway/\\1!" .

*.6.1.4.1 IN NAPTR 100 10 "u" "E2U+IAX2" "!^\\+*(.*)$!iax2:tor-gateway/\\1!" .

*.1 IN NAPTR 100 10 "u" "E2U+IAX2" "!^\\+*.*$!iax2:foofone/\\1!" .


These require a bit of explanation. The first part, *.4.1.5.1 is the telephone number reversed, with a wild card at the end. For example, if we try to call 15145551212, that will get transformed to 2.1.2.1.5.5.5.4.1.5.1 and that will be looked up in the dns — or actually, 2.1.2.1.5.5.5.4.1.5.1.e164.example.com will get looked up.

The record that is returned is a NAPTR record which has 5 parts:

  • 100 — order — a sequencing field, describing the sequence in which records are processed. You can have more than one record for the same E164 number, but as far as I know this is unimplemented in asterisk.
  • 10 — priority — a second sequencing field used for ordering where the order field is the same.
  • "u" — this is always "u"
  • "E2U+IAX2" — technology — this means that when we map the E164 number to a URI (E2U) what we will get is information for how toroute the call using IAX2
  • "!^\\+*(.*)$!iax2:mtl-gateway/\\1!" — regexp and replacement. The format is !<search>!<replace>! where the <search> is a regular expression and <replace> is what to replace it with. The \1 gets replaced with the pattern patched inside the round brackets () — in this case, everything except a possible leading +. In this example, the whole number gets matched, and what gets returned by Asterisk cmd EnumLookup is IAX2/mtl-gateway/number, which is a string that can be passed to Dial in order to call.

note: in the BIND zone file, the character '\' is considered an escape character, so if you want a '\' in your record itself, you must escape it, so it becomes '\\'

also note: the period '.' at the end of the NAPTR records


The protocol needn't be IAX2, it could just as easily be SIP or H323 or the special protocol TEL, which basically forwards to another extension.

The example above will work for NANPA, but can be easily extended to other numbering systems.

Ok, so now that we've got our call routing in the DNS, how do we glue it into extensions.conf? Easy. To cover the entire NANPA area with E164 lookups, we need to use the EnumLookup application. I use this:

exten => _1NXNNXXXXXX,1,EnumLookup(${EXTEN})
exten => _1NXNNXXXXXX,2,Dial(${ENUM})  ;; lookup was successful
exten => _1NXNNXXXXXX,3,Congestion
exten => _1NXNNXXXXXX,52,Goto(${ENUM}|1) ;; got a TEL record, so forward
exten => _1NXNNXXXXXX,102,Congestion   ;; lookup failed

Please observe

By implementing your local ENUM-alike DNS system to support E.164 reverse phone number lookups in DNS, you disable the possibility to lookup in the global ENUM-tree that is implemented in some countries around the world. To configure ENUM lookup in multiple domains, add your Enum-alike DNS root domain before the Enum designated domain, e164.arpa in Asterisk config enum.conf.


; /etc/asterisk/enum.conf

[general]
;
; The search list for domains may be customized.  Domains are searched
; in the order they are listed here.
;

; first search your company's local e164 zone, then try the free e164 org route, and finally fall back to the officlal ITU root.

search => e164.yourcompany.com
search => e164.org
search => e164.arpa



(Note: Steve Davies would recommend to put your private e164 zone *after* the public ones line e164.org and e164.arpa. The reason is as follows: the purpose of the public e164 services is to tell you how to reach certain numbers over VOIP. Now if you have used wildcard DNS in your private e164 zone as shown above, then the lookup in your private zone will get a match for *all* numbers in the wildcarded area code - that match will mean that the Asterisk will not check the public e164 zones and that IAX2 or SIP entry in there for your dialled number will never be seen. So you'll route to your other Asterisk server and dial-out, whilst you could have seen the peer's enum entry and simply connected directly over IP.)

See also

How to Store Asterisk Call Routing Information in the DNS


One of the limitations of Asterisk is the dialplan definition. While using wildcards such as NXX can be reasonably flexible, for a flexible dialplan, where you might want to send calls in different directions very granularly it does not scale very well. For example, for a TSP using Asterisk, to have an asterisk gateway in every NPA would require several hundred dialplan entries, mostly identical on each gateway. Further, if you add one gateway you must update the configuration on each of the others, which could be quite a headache from an administrative point of view.

Fortunately, there is a solution to this called ENUM. It relies on DNS, is an IETF standard and can be made to scale quite nicely.

As an example, let's say we have two Asterisk servers, one in 514 (Montreal), the other in 416 (Toronto), and some 3rd party long distance, FooFone, for off-net calls.

Each gateway has some sort of zaptel interface for calling the PSTN so they would each have entries in extensions.conf for local calling:

exten => _1514NXXXXXX,1,Dial(Zap/1/${EXTEN:1})
exten => _1514NXXXXXX,2,Congestion

on mtl-gateway and

exten => _1416NXXXXXX,1,Dial(Zap/1/${EXTEN:1})
exten => _1416NXXXXXX,2,Congestion

on tor-gateway.

For calls between the gateways, say someone in Toronto wanting to reach someone in Montreal, we need to tell the Toronto gateway how to route the call. Normally this is done directly in extensions.conf, but not with Enum (E.164).

Instead we make a DNS zone called e164.example.com. In reality, it would be better to use the, ITU/IETF specified e164.arpa, but good luck getting a delegation from them if you're not a giant telephone company. Fortunately, Mark Spencer of Digium foresaw this and made the lookup domain configurable in enum.conf.

The DNS zone file for e164.example.com will contain records that look like this:


*.4.1.5.1 IN NAPTR 100 10 "u" "E2U+IAX2" "!^\\+*(.*)$!iax2:mtl-gateway/\\1!" .

*.6.1.4.1 IN NAPTR 100 10 "u" "E2U+IAX2" "!^\\+*(.*)$!iax2:tor-gateway/\\1!" .

*.1 IN NAPTR 100 10 "u" "E2U+IAX2" "!^\\+*.*$!iax2:foofone/\\1!" .


These require a bit of explanation. The first part, *.4.1.5.1 is the telephone number reversed, with a wild card at the end. For example, if we try to call 15145551212, that will get transformed to 2.1.2.1.5.5.5.4.1.5.1 and that will be looked up in the dns — or actually, 2.1.2.1.5.5.5.4.1.5.1.e164.example.com will get looked up.

The record that is returned is a NAPTR record which has 5 parts:

  • 100 — order — a sequencing field, describing the sequence in which records are processed. You can have more than one record for the same E164 number, but as far as I know this is unimplemented in asterisk.
  • 10 — priority — a second sequencing field used for ordering where the order field is the same.
  • "u" — this is always "u"
  • "E2U+IAX2" — technology — this means that when we map the E164 number to a URI (E2U) what we will get is information for how toroute the call using IAX2
  • "!^\\+*(.*)$!iax2:mtl-gateway/\\1!" — regexp and replacement. The format is !<search>!<replace>! where the <search> is a regular expression and <replace> is what to replace it with. The \1 gets replaced with the pattern patched inside the round brackets () — in this case, everything except a possible leading +. In this example, the whole number gets matched, and what gets returned by Asterisk cmd EnumLookup is IAX2/mtl-gateway/number, which is a string that can be passed to Dial in order to call.

note: in the BIND zone file, the character '\' is considered an escape character, so if you want a '\' in your record itself, you must escape it, so it becomes '\\'

also note: the period '.' at the end of the NAPTR records


The protocol needn't be IAX2, it could just as easily be SIP or H323 or the special protocol TEL, which basically forwards to another extension.

The example above will work for NANPA, but can be easily extended to other numbering systems.

Ok, so now that we've got our call routing in the DNS, how do we glue it into extensions.conf? Easy. To cover the entire NANPA area with E164 lookups, we need to use the EnumLookup application. I use this:

exten => _1NXNNXXXXXX,1,EnumLookup(${EXTEN})
exten => _1NXNNXXXXXX,2,Dial(${ENUM})  ;; lookup was successful
exten => _1NXNNXXXXXX,3,Congestion
exten => _1NXNNXXXXXX,52,Goto(${ENUM}|1) ;; got a TEL record, so forward
exten => _1NXNNXXXXXX,102,Congestion   ;; lookup failed

Please observe

By implementing your local ENUM-alike DNS system to support E.164 reverse phone number lookups in DNS, you disable the possibility to lookup in the global ENUM-tree that is implemented in some countries around the world. To configure ENUM lookup in multiple domains, add your Enum-alike DNS root domain before the Enum designated domain, e164.arpa in Asterisk config enum.conf.


; /etc/asterisk/enum.conf

[general]
;
; The search list for domains may be customized.  Domains are searched
; in the order they are listed here.
;

; first search your company's local e164 zone, then try the free e164 org route, and finally fall back to the officlal ITU root.

search => e164.yourcompany.com
search => e164.org
search => e164.arpa



(Note: Steve Davies would recommend to put your private e164 zone *after* the public ones line e164.org and e164.arpa. The reason is as follows: the purpose of the public e164 services is to tell you how to reach certain numbers over VOIP. Now if you have used wildcard DNS in your private e164 zone as shown above, then the lookup in your private zone will get a match for *all* numbers in the wildcarded area code - that match will mean that the Asterisk will not check the public e164 zones and that IAX2 or SIP entry in there for your dialled number will never be seen. So you'll route to your other Asterisk server and dial-out, whilst you could have seen the peer's enum entry and simply connected directly over IP.)

See also

Created by: ww, Last modification: Thu 04 of Nov, 2010 (03:51 UTC) by admin
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+