DN42 asterisk PBX Peering

想在拖拉机网络上和别的小可爱互通电话吗~

安装 asterisk

(方法1) 使用debian bullseye:

apt install --install-recommends asterisk

(方法2) 使用docker

FROM debian:bullseye

RUN apt update -qq && \
    DEBIAN_FRONTEND=noninteractive apt -o Dpkg::Options::=--force-confold install -y --install-recommends asterisk asterisk-mp3 asterisk-opus && \
    apt clean && rm -rf /var/lib/apt/lists/*

VOLUME ["/etc/asterisk", "/var/lib/asterisk", "/var/log/asterisk"]
WORKDIR /var/lib/asterisk
CMD ["/usr/sbin/asterisk", "-fp", "-U", "asterisk"]

或者…

docker pull isjerryxiao/asterisk

有了image之后 run的时候不要忘记创建三个命名卷保存pbx的数据

docker run -d --restart always \
    --mount "type=volume,dst=/etc/asterisk,src=asterisk1" \
    --mount "type=volume,dst=/var/lib/asterisk,src=asterisk2" \
    --mount "type=volume,dst=/var/log/asterisk,src=asterisk3" \
    isjerryxiao/asterisk

*可选部分: 创建一个docker network分一段 /30 和 /126 专门给pbx用 或者直接使用host network,以避免端口转发

docker network create --subnet 172.21.80.84/30 --gateway 172.21.80.87 \
    --ipv6 --subnet fd07:d34:7969:2f::/126 --gateway fd07:d34:7969:2f::2 pbxnet
docker run --network pbxnet {...}

配置 asterisk

(1) 配置pjsip

禁用老旧的 chan_sip 模块以正常使用 pjsip

编辑 /etc/asterisk/modules.conf 并且在[modules]块下方加入

noload => chan_sip.so

编辑 /etc/asterisk/pjsip.conf

[global]
type=global

[transport4]
type=transport
protocol=udp
bind=0.0.0.0:5060

[transport6]
type=transport
protocol=udp
bind=[::]:5060

;=============TEMPLATE==============

[endpoint-template](!)
type=endpoint
context=mycontext
allow=!all,opus,speex,ulaw,alaw
rtp_symmetric=no
force_rport=yes
rewrite_contact=yes

[peers-endpoint-template](!,endpoint-template)
context=peerscontext
allow=!all,ulaw,alaw,opus,speex

[auth-template](!)
type=auth

[aor-template](!)
type=aor
max_contacts=1
remove_existing=yes

;=============PHONES==============

[mydevice1](endpoint-template)
auth = mydevice1
aors = mydevice1
callerid=JerryXiao1 <424036180001>
[mydevice1](auth-template)
auth_type=userpass
username=mydevice1
password=12345678
[mydevice1](aor-template)

[mydevice2](endpoint-template)
auth = mydevice2
aors = mydevice2
callerid=JerryXiao2 <424036180002>
[mydevice2](auth-template)
auth_type=userpass
username=mydevice2
password=87654321
[mydevice2](aor-template)

;=============PEERS==============

[mypeer1](peers-endpoint-template)
aors=mypeer1
identify_by=ip
[mypeer1](aor-template)
contact=sip:172.2x.xxx.xxx:5060
[mypeer1]
type=identify
endpoint=mypeer1
match=172.2x.xxx.xxx

[mypeer2](peers-endpoint-template)
aors=mypeer2
identify_by=ip
[mypeer2](aor-template)
contact=sip:[fd00:xxxx::]:5060
[mypeer2]
type=identify
endpoint=mypeer2
match=fd00:xxxx::

上述配置包括了 自己的sip客户端(手机/sip电话等设备) 和 外部sip peer 两部分,自己的sip客户端通过用户名密码验证,外部sip peer通过ip地址来相互区分。pjsip的语法相较chan_sip即使大量使用模板还是显得比较繁杂。pjsip的众多其他配置选项咱无法一一介绍,若有其他需求请移步此处

(2) 配置dialplan context

配好了sip,这时候还不能打电话哦。我们要告诉pbx号码和sip peer的映射关系。

基本的dialplan语法介绍:

[mycontext]
;新建名为 users 的扩展组(Dialplan extension context)
;扩展组中含有n>=1条扩展语句
;扩展组至少有两种方式被调用,被频道调用(如pjsip),或被其他扩展语句调用。

; 这是一条扩展语句
exten => 6001,1,Dial(PJSIP/demo-alice,20)
;格式为 exten => 号码,优先级,应用或方法(参数1,参数2...)

; 假设有以下扩展语句
exten => 6123,1,do something ;行1
exten => 6123,1,do something again ;行2
exten => 6123,2,do something else ;行3
exten => 6123,4,do something different ;行4
;asterisk执行扩展组时,会先搜寻匹配呼叫号码,且优先级为1的扩展,如果无法找到,则执行终止(呼叫也终止)
;找到并且执行优先级1的扩展(行1)后,寻找的优先级自增(现在寻找优先级为2的扩展行),行2由于优先级仍然是1被跳过。
;行3被执行,接着由于优先级为3的扩展不存在,电话挂断,行4不会被执行。

; same语法糖
exten => 6123,1,NoOp()
same  =>      n,Verbose("Do something!")
same => n,Verbose("Do something different!")
;以上行等同于
exten => 6123,1,NoOp()
exten => 6123,2,Verbose("Do something!")
exten => 6123,3,Verbose("Do something different!")

; 号码匹配
; 1.显式号码匹配,只能匹配 6123
exten => 6123,1,NoOp()

; 2.模式号码匹配,能匹配 6123, 6123123, 6123**##abc
exten => _6123!,1,NoOp()
; 模式匹配语法
;  前导 "_" 告诉 asterisk 这是模式匹配号码
;  例: _12XZN[1-3][1-346]
;  [0-9]表示匹配数字0到9
;  [46]表示匹配数字4和6
;  X为[0-9]的缩写 Z为[1-9] N为[2-9]
;  [1-346]表示匹配[1-3] 或 [46]
;  特殊字符 "." 和 "!"
;  _123XXX. 匹配 1234567 和 123456* 但是不能匹配 123456
;  末尾 "." 表示匹配至少一个任意字符
;  末尾 "!" 表示匹配零或多个任意字符
; 关于模式匹配规则排序、模式匹配安全性问题,请参阅
; https://wiki.asterisk.org/wiki/display/AST/Pattern+Matching

; 3.Includes / Switches
; 感觉用处不大,就不介绍了(
; https://wiki.asterisk.org/wiki/display/AST/Include+Statements+Basics
; https://wiki.asterisk.org/wiki/display/AST/Switch+Statements

; 变量
;https://wiki.asterisk.org/wiki/display/AST/Variables
变量替换 exten => 1,1,Verbose( ${varname} ) ; 打印varname变量的值
方法求值 exten => 1,1,Verbose( $[MAX(1,2)] ) ; 求MAX(1,2)的值并且打印
赋值方法 exten => 1,1,Set(varname=value) ; 设置varname的值为 "value"

; 常用应用和方法
1. NoOp(注释) 不做任何事情,占一个优先级
2. Verbose(内容) 打印一点内容到log
3. Wait(秒) 等待若干秒(浮点数)
4. Dial(资源..) 呼叫另一个设备
5. Playback(文件名去掉扩展名&文件2&文件3) 播放 /var/lib/asterisk/sounds 中的音频
6. Goto(扩展组名,号码,优先级) Goto(号码,优先级) Goto(优先级) 前往指定组(或同组,如省略),指定号码(或同号码,如省略),指定优先级 执行相应位置的扩展

; 标签
exten => 6123,1(tag1),NoOp()
same  =>      n(tag2),NoOp()
;此时tag1为1, tag2为2, 可以用 Goto(6123,tag1) 前往tag1所在行

; 匹配呼叫者号码(callerid)
;呼叫者号码可以用模式匹配来区分
;格式 号码匹配/呼叫者号码匹配
exten => 6123/_1234X,1,NoOp()
;匹配呼叫 6123 的号码为 12345 的呼叫者

dialplan的更多强大功能在此就不过多介绍了,请自行查阅手册

打开 /etc/asterisk/extensions.conf 进行编辑

[general]
static=yes
writeprotect=no
clearglobalvars=no

[mycontext]
;自己的电话会进入这个context

;请更改以下行中的3618
exten => _4240XXXX.,1,Goto(extpeers,${EXTEN},5)
exten => _0XXXX.   ,1,Goto(extpeers,424${EXTEN},5)
exten => _X!       ,1,Goto(extpeers,42403618${EXTEN},5)


[peerscontext]
;peer打来的电话会进入这个context
;主要目的:不允许任何peer使用你的号码呼入
exten => invalidcaller,100,Playback(silence/1&sorry-youre-having-problems)
 same =>                 n,Hangup()

;请更改以下行中的3618
exten => _X!/_42403618X!,1,Goto(invalidcaller,100)
exten => _X!            ,1,NoOp()
exten => _4240XXXX.,2,Goto(extpeers,${EXTEN},5)
exten => _0XXXX.   ,2,Goto(extpeers,424${EXTEN},5)
exten => _X!       ,2,Goto(extpeers,42403618${EXTEN},5)

[extpeers]
;上述两个扩展组都会跳转到这里的5号扩展

;请更改以下行中的3618
;分离出自己的号码并且跳转到extmyself
exten => _42403618.,5,Answer()
 same =>            n,Goto(extmyself,${EXTEN:8},5)

;呼叫下面的peer
;请更改以下行中的内容
exten => _42401234.,5,Dial(PJSIP/${EXTEN}@mypeer1)
exten => _42401235.,5,Dial(PJSIP/${EXTEN}@mypeer2)

[extmyself]
;自己的号码会跳转到这里的5号扩展
exten => 0000,5,Playback(silence/1&hello-world&silence/1)

;呼叫我的设备
exten => 0001,5,Dial(PJSIP/mydevice1)
exten => 0002,5,Dial(PJSIP/mydevice2)

;读出对方的号码
exten => 3618,5,Playback(silence/1&your&number&is)
same  =>      n,SayAlpha(${CALLERID(num)})
same  =>      n,Playback(silence/1)

;处理不存在的号码
exten => _X! ,5,Playback(im-sorry&check-number-dial-again)

至此基本配置就完成了,可以reload整个asterisk (asterisk -r 并执行reload),然后可以在手机上配置sip,或者寻找一个sip软件(如jami-gnome)互相拨打电话哦。

与我peer

我的pbx实例位于 pbx.jerry.dn42 / pbx.jerry.neo

号码段 42403618.

更多

我的配置文件 https://git.jerryxiao.cc/Jerry/asterisk-config

如需了解更多,请参阅文档,也可以在下方留言帮助完善本页面。

https://wiki.asterisk.org/wiki/display/AST/Dialplan

附加说明

目前对于是否支持可变长度号码社区仍存在争议,读者可前往 #dn42-sip@hackint 讨论。本文已经更新以支持可变长度号码,但是不排除参考旧配置的用户仍在使用 4240XXXXXXXX 的不可变长度dialplan.

4 4 votes
Article Rating
Published
Categorized as Posts
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments