Dealing with phone numbers

“Project: Wolowizard [1] only supports NANP (North American Numbering Plan) numbers, but since those numbers come via The Protocol Stack From Hell [2] clearly marked as NANP, it's easy to determine there if a number is NANP or not. It's not quite as simple in “Project: Sippy-Cup [3]” since SIP (Session Initiation Protocol) [4] is … a bit loose with the data formatting.

There, the numbers are formatted as a tel: URI (Uniform Resource Identifier) [5] (or a sip: URI [6] but the differences are minor). If the number is “global,” it's easy to determine a NANP number because it will be marked with a “+1” (“1” being the country code for North America). So, tel:+1-501-555-1212 is most definitely a NANP number, while tel:+501-555-1212 is not.

Things get a bit more muddy when we receive a so-called “local” number. RFC (Request For Comments)-3966 (The tel URI for Telephone Numbers) [7] clearly states that a “local” tel: URI MUST (as defined in RFC-2119 (Key words for use in RFCs to Indicate Requirement Levels) [8]) contain a phone-context attribute—except when it doesn't (I swear—the RFC contradicts itself on that point; tel:8005551212 is valid, even though it's a “local” number and missing a phone-context attribute because it's a “national freephone number”). So tel:555-1212;phone-context=+1501 is NANP, while tel:555-1212;phone-context=+501 is not (look closely at the two—one has a country code of “1” while the other has a country code of “501”). It's worse though, because while tel:555-1212;phone-context=+1501 is NANP, you cannot use the phone-context attribute to reconstruct a global number (the RFC contains the following example: tel:863-1234;phone-context=+1-914-555—um … yeah).

To further complicate things, the phone-context attribute does not have to contain digits—it can be a domain name. So tel:555-1212;phone-context=example.com is a valid number. Is it NANP? International? Who knows?

So what does “Project: Sippy-Cup” do? If it receives a “local” number with a “+1” country code in the phone-context attribute, it's marked as NANP; any other country code is it marked as non-NANP. If the phone-context attribute contains a domain name, it is treated as a NANP number (based on what I saw in production). And if there's a missing phone-context attribute for a “local” number, “Project: Sippy-Cup” treats it as a NANP number if it has at least 10 digits.

Now, why do I care about this? Because we want to avoid doing an expensive database query for non-NANP and invalid NANP numbers, but “Project: Heimdall [9]” wants all the numbers for tracking potentially fraudulent calls.

[1] /boston/2010/10/11.1

[2] /boston/2012/01/31.1

[3] /boston/2014/03/05.1

[4] https://en.wikipedia.org/wiki/Session_Initiation_Protocol

[5] https://www.ietf.org/rfc/rfc3966.txt

[6] https://www.ietf.org/rfc/rfc3261.txt

[7] https://www.ietf.org/rfc/rfc3966.txt

[8] https://www.ietf.org/rfc/rfc2119.txt

[9] /boston/2019/04/23.1

Gemini Mention this post

Contact the author