在 Telephony42 中配置 E.164 ENUM
在此前,我们已经建立了一个去中心化的、横跨全球的自治网络 DN42,我们在这里交换 BGP 路由,各自跑着奇奇怪怪的协议和服务,并宣示着我们的数字主权。
但如果仅仅将互联停留在 IP 层面,未免有些无趣。
于是,笔者在内的一群 DN42 NOC 们开始探索在 DN42 上建立基于 VoIP 的电话网络的可能性。Telephony42 由此产生。
Telephony42 是如何工作的
电话网络的自治系统:PBX
PBX 即专用交换机(Private Branch Exchange),等价于 IP 网络上的路由器。在 Telephony42 中,每个 AS 节点需要自行搭建 PBX,目前社区内大部分节点基于 Asterisk 或 FreeSWITCH 等开源软件构建。节点内部的 SIP 话机或软电话客户端作为分机,直接注册到自己的 PBX 上。
传统的 PSTN 由于是电路交换,拨号通常需要先将呼叫转到某个集中的交换中心;而 Telephony42 就不需要这么麻烦了,当 PBX 向外呼叫另一个网络的号码时,可以直接根据号码找到对方 PBX 的 IP 地址,然后利用 DN42 的 IP 路由,以 PBX-to-PBX 的形式直接发起 SIP INVITE 请求,并建立 RTP 媒体流。
电话网络的 BIRD:Asterisk
作为一款历史悠久且功能强大的开源 PBX 软件,Asterisk 承担了 SIP 信令的交互、媒体流的建立以及拨号计划(Dialplan)的路由逻辑。
具体的安装部署本文不再赘述教程,这里假设你已经是一名合格的 NOC,掌握了 Asterisk 的基本操作,并且已经在自己的自治域内架设好了一套跑通内部分机的电话系统。
那么问题来了,在没有中心化的交换中心(如传统运营商的 IMS 核心网)的条件下,当话机拨出一串完全陌生的号码时,Asterisk 该如何知道要把这通 SIP 请求发往哪个服务器的 IP 呢?
E.164 与 ENUM
熟悉传统电信的老登们对 E.164 肯定不陌生。根据 RFC 2916 RFC 3761 RFC 6116,E.164 实际上定义了「国际公共电信编号计划」(即你最常见的 +86 138xxxx... 这种严格层级的格式)。
而在纯 IP 协议的世界里,我们需要一种机制将电话号码翻译成 PBX 的 IP 地址。ENUM (E.164 Number Mapping) 就是实现这一映射的协议。
它的工作原理基于现有的 DNS 系统:将电话号码翻转,加入点号分隔,再加上一个特定的域名后缀(在 IANA 的体系里,是 e164.arpa,这很像 rDNS 的解析方式)。然后还利用 DNS 的 NAPTR (Naming Authority Pointer) 记录,它是一个包含正则表达式的记录,可以将这串倒写的号码解析成 SIP URI。这样,交换机就知道该把 SIP INVITE 发往哪个 IP 了。
一条 ENUM 记录通常是这样的:
1 | |
当然,为了匹配前缀下的所有号码,也可以这样写:
1 | |
10:Order(优先级),数字越小越优先。100:Preference(权重),相同 Order 下数字越小越优先。"u":Flag,表示此记录的替换结果是一个合法的绝对 URI(Terminal Rule)。"E2U+sip":Service,指明该记录用于转换为 SIP 协议 URI。"!^.*$!sip:1001@pbx.yourdomain.dn42!":Regexp(正则表达式),将输入的任意匹配转换为 sip:1001@pbx.yourdomain.dn42。感叹号!只是作为正则的分隔符,类似于 sed 里的/- 最后的
.:Replacement 字段,当使用 Regexp 时此字段通常置为空(即单个点)。
通过这条记录,DN42 上的 PBX 就能知道 +424-0-1234-1001 这个号码要送到 pbx.yourdomain.dn42 去处理。
Telephony42 的临时共识
由于 DN42 没有 ITU 这样的中央机构来分配号码,我们需要一个既能保证唯一性、又能兼顾现有互联网络结构的编号方案。经过社区讨论,目前的临时共识是基于将号码与网络 ASN 绑定:
格式为:+424-X-YYYY-extension
424:可以视作 Telephony42 的专属地区代码。X:网络标识符。0代表 DN42 本网,1,2等数字保留给与 DN42 互联的其他网络(例如 NeoNetwork、CRXN 等)。YYYY:你在 DN42 里的 ASN 的后四位(例如你的 ASN 是4242421234,那这里就是1234)。extension:分机号。这部分交由你自己的 PBX 自由发挥,爱设几位设几位。
例如,某节点 ASN 为 4242421234,其下分配了一个分机号 1001,则其完整的 E.164 号码为 +424012341001。
e164.dn42 是如何工作的
正式的 ENUM 记录组织方式通常需要在 DN42 社区中取得广泛共识后再引入 Registry 中。但 e164.dn42 作为一个我突发奇想搞出的先行实验项目,目前是使用 e164.dn42 而非 e164.arpa 作为 TLD 进行测试。它目前部署在 Niantic Network (AS4242421331) 的 DNS 解析器上,只托管 NS 记录。
如果你有一个自己的 PBX 且希望加入,只需要通过 Kioubit Auth 登录 e164.dn42 的管理界面,设置 NS 记录指向的服务器,就可以将自己的 ASN 对应的 e164.dn42 域名 NS 委派到自己的权威 DNS 服务器上。
假设你的号码是 424012341001,你需要将号码反转为 1.0.0.1.4.3.2.1.0.4.2.4.e164.dn42.,并在 DNS 服务器的对应区域中添加 NAPTR 记录(如前文所示)。
注意:同时你需要确保
pbx.yourdomain.dn42在 DNS 中拥有正确的 A 或 AAAA 记录,指向你的 PBX 服务器 IP。

e164.dn42 配置,以 Asterisk 为例
要参与进来,你需要具备两个前置条件:
- 你的服务器已接入 DN42 网络(支持 IPv4/IPv6),并能正常路由目标网段。(目前仅支持 DN42 系统内
424242开头的 ASN,暂不支持其他互联外部网络)。 - 一个支持 ENUM 的、工作的 PBX 服务器。本文以 Asterisk(或基于其的 FreePBX)为例(同时建议使用基于 PJSIP 协议栈的较新版本)。理论上只要支持 SIP 协议和 ENUM 查询的系统都可以,但其他系统需要自行摸索。
呼出电话处理
呼出逻辑相对简单:在拨号计划中拦截特定前缀的未知号码,通过 ENUMLOOKUP 查询 SIP URI,并直接向目标发起 INVITE 请求。
第一步:新增 PJSIP Endpoint
在你的 pjsip.conf 中,新增一个专门用于 ENUM 呼出的 Endpoint。这里我们不需要认证,因为是直接向目标 IP 发起呼叫。
1 | |
第二步:配置 Dialplan
在 extensions.conf 中,配置处理 4240 开头号码的逻辑。
最佳实践: 作为一个 fallback 选项,应该优先匹配你已经明确配置了 Peer 的内部/已知规则,只有系统不认识的 424 号码,才丢给 ENUM 去解析。
1 | |
拨入电话处理
在 SIP 网络中,Caller ID(来电显示号码)包含在头部 From 字段,极易被伪造。为防止网络中的恶意节点伪造他人号码拨入,我们需要实现反向验证:通过查询来电者声称号码的 ENUM 记录,比对该记录指向的 IP 与当前实际信令来源的 IP 是否一致。
第一步:新增 PJSIP Endpoint
在 pjsip.conf 中,配置网段匹配,将所有来自 DN42 及其它互联网段的未知呼叫引入隔离上下文 context-enum。
1 | |
重要提示:在 pjsip.conf 的
[global]区块中,需明确 endpoint 标识的匹配顺序。若不配置,合法的内部分机(通过密码认证)如果在 DN42 网段内,可能会优先命中上述 match 规则,导致认证失效。
1
2[global]
endpoint_identifier_order=auth_username,username,ip
第二步:配置 Dialplan 与 AGI 调用
在 extensions.conf 中,我们将调用一个外部 Python 脚本来进行 DNS 反向验证。
1 | |
AGI 反向验证脚本
AGI (Asterisk Gateway Interface) 提供了 Asterisk 拨号计划与外部程序进行交互的标准接口。借助这个功能,可以轻松在 Asterisk 中利用外部程序实现一些高级功能。
该脚本依赖 dnspython 库(使用 apt install python3-dnspython 或 pip3 install dnspython 安装)。请确保脚本具有可执行权限。
脚本的逻辑依次为:清理数据 -> 构建 ENUM 域名 -> 查询 NAPTR 记录 -> 提取 Host -> 解析 A/AAAA 记录 -> 与实际来源 IP 碰撞比对。
1 | |
代码仅供参考,存在很多没有考虑到的情况。以后有时间我大概会写一个更完善的版本。
局限 1:这种校验机制假设了 SIP 呼入与呼出使用同一个 IP。如果网络采用了呼入呼出分离的方案,程序可能会误判。不过在现阶段大部分 DN42 PBX 节点均基于单机 Asterisk 部署的环境中,此策略已足够有效。
局限 2:此脚本也没有考虑到 NAPTR 可以设置s而非u模式从而将解析转发到一个 SRV 记录的情况。
E.164 加持下的 Telephony42 工作流
为说明上述机制的运行过程,我们推演一次从拨号到接通的完整时序:
- 假设 Alice 的 ASN 为
4242421111,PBX IP:fd00:1111::5600,分机号1001,Caller ID 为424011111001。 - 假设 Bob 的 ASN 为
4242422222,PBX IP:fd00:2222::5600,分机号2002,Caller ID 为424022222002。
此时 Alice 想要给素未谋面甚至之前都不认识的 Bob 打一通跨越 DN42 自治系统的电话。
在传统 SIP 对接中,Alice 和 Bob 的 NOC 必须互换 IP、配置 SIP Trunk Peer,甚至还要设置密码。
但在 Telephony42 with ENUM 中,这一切都不需要。
拨号与拦截 (Alice 端)
Alice 拿起桌上的 SIP 话机,拨下 424022222002。呼叫请求被送达 Alice 端的 Asterisk 服务器。Asterisk 发现该号码没有对应到已知的 SIP Trunk Peer,于是开始寻找 fallback 选项,最终匹配了 Dialplan 中的 _4240X. 规则,于是拦截下这通电话,准备进行 ENUM 解析。
ENUM DNS 查询 (Alice 端)
Alice 的 Asterisk 提取被叫号码,将其翻转并加上 e164 TLD,生成查询域名:2.0.0.2.2.2.2.2.0.4.2.4.e164.dn42。接着向 DN42 网络中的 DNS 发起 NAPTR 查询。
DNS 返回了一条记录,告诉 Alice:这个号码对应的 SIP URI 是 sip:2002@pbx.bob.dn42。DNS 顺带解析出 pbx.bob.dn42 的 IP 为 fd00:2222::5600。
发起动态呼叫 (Alice 端)
Alice 的 Asterisk 直接利用我们刚才配置的通用出口 [peer-enum-outbound],向 fd00:2222::5600 发送了一个标准的 SIP INVITE 请求。注意此时 Alice 的系统里根本不需要提前了解任何关于 Bob 的 SIP 信息。
入站与来源匹配 (Bob 端)
Bob 的 Asterisk 收到了来自 fd00:1111::5600 (Alice) 的 INVITE 请求。由于 Bob 系统里也没有配置 Alice 的 Peer,这个陌生 IP 被 [peer-enum-inbound] 的网段匹配规则(match=fd00::/8)捕获,并被扔进了隔离上下文 context-enum 中。
反向查找与防伪造验证 (Bob 端)
Bob 的 Asterisk 发现来电者声称自己是 424011111001 (Alice 的 Caller ID),于是触发了 Python 脚本 enum_verify.py。
脚本将 Alice 的号码翻转为 1.0.0.1.1.1.1.1.0.4.2.4.e164.dn42,向 DN42 网络中的 DNS 发起 NAPTR 查询,发现这个号码在 DNS 里登记了若干条 PBX URI (可能是 IP,也可能是域名)。
于是脚本按照优先级对这些 URI 进行依次解析和验证,直到查到 pbx.alice.dn42 解析出的 IP fd00:1111::5600 与来电者的 IP 完全吻合。最终脚本向 Asterisk 报告 PASS,证明这个 Caller ID 不是骚扰电话或伪造的。
放行与接通
验证通过后,Bob 的 Asterisk 将这通电话从 context-enum 中放出,路由到内部正常的 Dialplan。最后,Bob 的分机 2002 开始响铃。
Bob 接起电话,两人之间的 RTP 语音媒体流在 DN42 的网络中穿梭,双方开始聊天。
总结
在这个工作流的一切都在端到端(PBX to PBX)之间直接完成。只要每个人都在 e164.dn42 中维护好自己的 DNS 记录,并配置好 ENUM 呼入/呼出规则,各自的电话系统就能以近乎魔法的方式自动识别整个 DN42 网络里的所有 PBX 节点。
Telephony42 的未来
在传统电信巨头高度垄断、各种实名认证与网络监管日益严苛的今天,在 DN42 这样一个完全由社区支撑的网络里搭建属于自己的语音网络,是一件浪漫的事。
正如我一直强调的:
我们在哪里交换路由,哪里就是 Internet;
那么,我们在哪里传递 SIP 报文,哪里也就是我们自己的电话网络。
目前的 Telephony42 依然是一个充满着草台班子气息的实验项目,由于 DN42 网络的复杂性,电话可能偶尔会遇到单向接通、语音延迟和通话不稳定。但随着节点的增加和路由的优化,这张网络正在逐渐成型。也许在不久的将来,除了基本的语音互联,我们还能在这片数字飞地里实现去中心化的 T.38 传真、短信等通信方式。
这一切的边界,都等待着我们去亲手书写。