Wednesday, March 11, 2020

Bug in UCDialplans North American Rulesets

I was troubleshooting an issue where people couldn't dial US/CA toll-free numbers in Teams the other day, when using Direct Routing. Initially, the root issue wasn't that easy to solve, due to the lack of a Voice Routing Test Case tester like we have in Skype for Business. Normally, one of the first things I do when troubleshooting issues like this, is to make sure the user is actually ALLOWED to make such phone calls, based on their assigned voice policy. Teams doesn't have an equivalent to the SfB voice route tester. If it did, I would have found it much sooner.

The first thing that I did was look at the user's call history in the Teams Admin Centre. Sure enough, every toll-free call made by the user failed with the below error logged in Teams:

"The destination failed because it doesn't exist"

No information about this error came up in a search. Reviewing logs from the SBC showed the call never got to the SBC. Client logs didn't provide any usable information. Finally, I looked deeper into the applied dialplan. At this point, I saw the problem, and it was me.

Of course, I had applied a ruleset generated by Everybody was automatically assigned the global voice policy, which was set to allow dialing only within the US. This utilizes a feature in where you can decide exactly what constitutes a "National" call.

If you're not familiar with the intricacies of the North American dialplan (NANPA), just know that the US, Canada and 26 Caribbean countries share the country code +1.  Each country has its own set of one or more area codes. There is no way to distinguish whether a number is in the US, Canada or a Caribbean country just by looking at it. can configure your National voice policy so that a "National" call can include any number that starts with +1, limit to US/CA or limit it to US OR CA. When creating the ruleset, has a drop-down option where you decide what you want to "Treat as National".

If you select "In-Country Only" (which is the default option), will create a national voice route that only includes the area codes for the selected country. The current US example is below, which explicitly details every area code in the US, and is derived programmatically from the current list of area codes:


For the US/Canada option, rather than explicitly including every area code, it EXCLUDES Caribbean area codes, which is a much smaller list. Similarly, for US/Canada/Caribbean there is no need to exclude any area code (except premium), so the list is even smaller.

In an effort to reduce route selection time and processing overhead, the National voice policy doesn't explicitly include PSTN usages for local dialing, UNLESS least-cost routing is being used. For the US/Canada and US/Canada/Caribbean route options, toll-free numbers are captured by the route pattern because they're NOT in the exclusion list of Caribbean area codes. Unfortunately, I didn't account for toll-free numbers in the US or Canada Only route options, which means that toll-free numbers can't be dialed if you use the default options.

You could fix this by adding the Local PSTN usage to your voice policies, but that adds unnecessary overhead. A better option is to explicitly include toll-free numbers in the computed route.


The latest version of does this now, but if you've previously applied a ruleset using the "In-Country Only" option, you can either manually update your National voice route, or you can run one of the below scripts, which will seek out any US/CA-National voice route and apply the fix. If you use any of the other options, you aren't affected.

How can I tell which option was used?

Easily. The voice route for either of the other options are MUCH smaller in size. If your voice routes look like this, you are not affected.

US/Canada: (?!(24[26]|26[48]|284|345|441|473|649|664|721|[67]58|767|784|8[024]9|86[89]|876|900|976))[2-9]\d\d[2-9]\d{6}

US/Canada/Caribbean: (?!(900|976))[2-9]\d\d[2-9]\d{6}

The Fix is In

The below PS commands will append tollfree prefixes to the problematic voice route. Run whichever is appropriate for your environment, and BACKUP before you run this.

Skype for Business Fix

$Routes = Get-CsVoiceRoute | Where {($_.Identity -eq 'US-National' -or $_.Identity -eq 'CA-National') -and $_.NumberPattern -notlike '*[2-9]\d\d[2-9]\d{6}' -and $_.NumberPattern -notlike '*8(00|33|44|55|66|77|88)*'}; ForEach ($Route in $Routes) {Set-CsVoiceRoute -Identity $Route.Identity -NumberPattern $Route.NumberPattern.replace(")[2-9]\d{6}","|8(00|33|44|55|66|77|88))[2-9]\d{6}")}

Microsoft Teams Fix

$Routes = Get-CsOnlineVoiceRoute | Where {($_.Identity -eq 'US-National' -or $_.Identity -eq 'CA-National') -and $_.NumberPattern -notlike '*[2-9]\d\d[2-9]\d{6}' -and $_.NumberPattern -notlike '*8(00|33|44|55|66|77|88)*'}; ForEach ($Route in $Routes) {Set-CsOnlineVoiceRoute -Identity $Route.Identity -NumberPattern $Route.NumberPattern.replace(")[2-9]\d{6}","|8(00|33|44|55|66|77|88))[2-9]\d{6}")}

My apologies to anyone caught up by this bug. If you see me in the streets, feel free to slap me.

No comments:

Post a Comment