Asterisk權威指南/第七章 外部連通性

維基教科書,自由的教學讀本

7.1幹線(Trunking)基礎[編輯]

幹線(Trunking)的目的是在兩個實體間提供一個共享連接。舉例來說,公路幹線是把 兩個鎮子連接起來的高速公路。鐵路上廣泛的使用術語「幹線(trunk)」,來指代那些將支 線鐵路連接到一起的主要線路。

同樣地,在電信領域,幹線用於將兩個系統連接起來。電信運營商利用通訊幹線把他們 的網絡連接到一起,而對 PBX 來說,將 PBX 與外部世界連接起來的線路一般就被稱作幹線 (儘管電信運營商一般不會認為這些是幹線)。從技術的觀點看,PBX 幹線的定義並不像其 它例子那麼清晰(PBX 幹線使用了與終端線路完全不同的技術),但作為一個概念,幹線仍 然是非常重要的。舉例來說,在 VoIP 系統中,一切通訊實際上是點對點的(所以從技術的 觀點看,並不真實的存在幹線),但是這個概念仍然是有用的,它可以幫助我們區分連接到 外部世界的 VoIP 資源和連接到用戶分機(例如一部 SIP 電話機)的 VoIP 資源。

大概最容易的理解方式是把幹線理解為一組提供外線路由的線路集合。所以,在 Asterisk PBX 中,你可能有 VoIP 服務商提供長途呼叫的幹線,有連接 PSTN 線路的幹線,以及將你的 不同地點的辦公室連接在一起的幹線。這些幹線可能實際上是通過同一個網絡連接,但在你 的 dialplan 中,你可以用完全不同的方法處理它們。

儘管我們相信 VoIP 最終將完全取代 PSTN,許多 VoIP 線路使用的概念(例如電話號碼) 繼續存在更多是由於歷史原因而不是技術需求,但是我們認為,在我們完全進入 VoIP 時代 前,討論一下在 Asterisk 中如何使用傳統 PSTN 線路還是非常有用的。 如果你的 Asterisk 系統計劃只使用 VoIP 線路,那也沒問題,請直接閱讀本章的 VoIP 部 分,我們會告訴你應當怎麼做。不過我們強烈建議閱讀 PSTN 部分,因為其中包含了很多有 用的基礎知識,雖然這些並不是理解和使用 Asterisk 所必須的。

7.2 用於外線連接的基本 Dialplan[編輯]

在傳統 PBX 中,訪問外線一般都需要通過撥打一個號碼前綴來實現注 1。我們一般用數字 9 作為這個前綴。

在 Asterisk 中,同樣可以指定 9 作為外線路由前綴,但是由於 Asterisk dialplan 要智能的 多,完全沒有必要強制用戶在呼叫外線前加撥 9。典型地,你會為你的系統配置一個分機范 圍(如100-199),以及一個feature code範圍(*00到*99)。任何這個範圍之外的,匹配 了你設定的國家碼和區域碼的呼叫,都會被視為外線呼叫。 如果你通過一個電信運營商提供全部的外線資源,你可以通過幾條簡單的樣式匹配處理 外線呼叫。本節提供的例子是針對 NANP(North American Numbering Plan)的。如果你的國 家不在 NANP 中(NANP 服務於加拿大,美國,以及幾個加勒比海國家),你可能會需要不同 的樣式匹配。

在 [globals] 部分中包含兩個變量,叫做 LOCAL 和 TOLL 注 2。這些變量的目的是當你 需要更換電信運營商時簡化你的 dialplan 管理。它們允許你只修改 dialplan 的一個地方,但 會對所有引用這個 channel 的地方生效:

 [globals]
 LOCAL=DAHDI/Go ; assuming you have a PSTN card in your system
 TOLL=SIP/YourVoipCarrier ; as defined in sip.conf

在 [external] 部分中包含實際的 dialplan 代碼,這些代碼將識別呼叫的號碼並將它們傳 遞給 Dial() application 注 3:

 [external]
 exten => _NXXNXXXXXX,1,Dial(${LOCAL}/${EXTEN})  ; NANP 的 10 位号码样式匹配
 exten => _NXXXXXX,1,Dial(${LOCAL}/${EXTEN}) ; NANP 的 7 位号码样式匹配
 exten => _1NXXNXXXXXX,1, Dial(${LOCAL}/${EXTEN}) ; NANP 的长途号码样式匹配
 exten => _011.,1, Dial(${TOLL}/${EXTEN}) ; NANP 的国际电话号码样式匹配
 ; 这部分的功能与上面相同。
 ; 这是为了喜欢拨外线前先拨“9”的用户设计的
 exten => _9NXXNXXXXXX,1, Dial(${LOCAL}/${EXTEN:1})
 exten => _9NXXXXXX,1,    Dial(${LOCAL}/${EXTEN:1})
 exten => _91NXXNXXXXXX,1, Dial(${LOCAL}/${EXTEN:1})
 exten => _9011.,1, Dial(${LOCAL}/${EXTEN:1})

在任意分機或設備使用的 context 中,你可以用一個 include=> 指令來允許訪問 external context:

 [LocalSets]
 include => external

非常重要的一點是,不要在可能處理來電的任何 context 中包含訪問外線 的代碼。風險在於仿冒機器人程序將最終獲得訪問你外線的方法(你將被 這種仿冒機器人程序的常見所嚇到)。 我們怎麼強調都不過分的是,你一定要保證沒有外部資源可以訪問你的付 費電話線路。

7.3 PSTN 線路[編輯]

公共交換電話網絡(PSTN – Public Switched Telephone Network)已經存在超過一個世紀 了。它是許多對我們今天有重大影響的技術的先驅,從 Internet 到 MP3 播放器。

7.3.1 傳統 PSTN 幹線[編輯]

固定電話運營商採用兩種技術交付電話線路:模擬的和數字的。

7.3.1.1 模擬電話[編輯]

最初的電話系統完全是模擬的。你通過聲音發出的音頻信號,被用於產生一種運載到通 話的另一端的電訊號。這種電訊號具有與原始聲音一樣的特性。 模擬線路具有一些與其它你可能想連接到 Asterisk 的線路所不同的特性:

  没有信令通道 —— 大部分信令是机电信号
  断线监测通常会延迟数秒,而其并不是完全可靠的
  极少的远端监测(例如,应答监测就不充分)
  线路差异性,这意味着不同线路的音频特性是不同的,并且需要调试 

你希望連接到你的 Asterisk 系統的模擬線路需要連接到 Foreign eXchange Office (FXO)埠。 由於標準計算機並沒有這種 FXO 埠,所以你必須購買 FXO 板卡並安裝到你的系統上以實 現連接傳統模擬電話線注 4。

FXO 和 FXS 對任何模擬線路來說,存在兩個端點:局端(office 端,典型指 PSTN 的中心局),和終 端(station 端,典型指電話,也包括板卡,如 Modem 板卡或 PBX 系統的線路板卡)。

中心局(the central office)負責提供:

  提供馈电(通常是48V直流)
  提供振铃电压(通常是90V交流)  产生拨号音
  检测摘机状态(摘机或挂机)
  发送补充信令,如主叫号码(Caller ID)

終端(the station)負責:

  提供振铃器(或者至少能够以某种方法处理铃流电压)
  提供拨号盘(或者其它发送DTMF的方法)
  提供一个叉簧开关(hook switch)以指示线路的状态

一個 Foreign eXchange (FX) 埠通過它與什麼連接而命名,而不是它做什麼。所以,舉 例來說,一個 Foreign eXchange Office (FXO) 埠實際上是終端:它連接到中心局。一個 Foreign eXchange Station (FXS) 埠實際上是提供中心局服務的埠(換句話說,你可以把一 個模擬終端插入到 FXS 埠上)。

正是由於這個原因,在 Asterisk 配置文件里的信令設置好像是反的:FXO 埠使用 FXS 信令; FXS 埠使用 FXO 信令。當你理解了物理埠類型的命名是基於它與什麼連接時,在 Asterisk 中的信令名就更加容易理解了:由於 FXO 埠連接到中心局,所以它需要表現的像個終端, 因此需要 FXS 信令。

注意,將 FXO 埠換成 FXS 埠,並不是你簡單的做一些配置就可以實現的。FXS 埠 和 FXO 埠需要完全不同的電路。大部分支持 Asterisk 的模擬板卡都支持通過安裝在主板卡 上的子卡來提供正確的 channel 類型,這就意味著你在定義你板卡的埠類型時具備了一些 靈活性。

模擬埠通常不用於中型和大型系統。它們通常用於小型辦公室(小於 10 根外線;少 於 30 部電話)。你決定使用模擬線路可能是基於如下因素:

  你所在区域的数字线路有限
  费用(模拟线路在低密度时较便宜,但在高密度时较贵)
  后勤因素(如果你已经安装的模拟线路,你可能希望保留它们)

從技術的觀點看,你一般應當更傾向於選擇數字線路而不是模擬線路。但是,現實並不 總是順應技術的發展,所以模擬線路還會繼續存在一些年。

7.3.1.2 數字電話[編輯]

數字電話技術被開發出來是為了克服模擬電話的一些限制。數字線路的一些優點包括:

  经过长距离后没有幅度衰减
  减少了线路噪音(尤其是长途线路)
  在一根线路上承载多个通话的能力
  更快的呼叫建立和拆除速度
  更丰富的信令信息(尤其是使用ISDN时)  对电信运营商而言费用更低
  对用户而言费用更低(在高密度情况下)

在 Asterisk 系統中(或任何 PBX 系統),有如下幾種數字線路你可能會用到:

 T1(24 channels)
 在加拿大和美国使用(大多数用于 ISDN‐PRI) 
 E1(32 channels)
 在世界上其它地区使用(ISDN‐PRI 或 MFC/R2) 
  
 BRI(2 channels)
 用于 ISDN‐BRI 线路(Euro‐ISDN)

注意,物理線路可以進一步通過運行在其上的協議來定義。舉例來說,T1 線路可以被用於 ISDN‐PRI,或者 CAS;而 E1 線路可以被用於 ISDN‐PRI,CAS,或者 MFC/R2。我們將在下一節 討論這些不同的協議。





7.3.2 安裝 PSTN 幹線(PSTN Trunks)[編輯]

基於你已經安裝的硬體的不同,安裝 PSTN 板卡的過程也會不同。我們將按照一般情況 討論安裝,這將適合於所有的 Digium PSTN 板卡。其它製造商也會提供基於他們硬體的安裝 腳本,這將自動處理你的大部分工作。

7.3.2.1 下載和安裝 DAHDI[編輯]

DAHDI 接口是 Digium Asterisk Hardware Device Interface 的縮寫,DAHDI 定義了 PSTN 板 卡和 Asterisk 之間通信的軟體框架。即使你沒有任何 PSTN 硬體,我也推薦你安裝 DAHDI, 因為這是獲得一個有效時鐘源的簡單、可靠的方法注 5。完整的 DAHDI 安裝指導可以在第 3 章找到。

禁止加載額外的 DAHDI Modules

DAHDI 默認會加載所有編譯好的 modules 到內存。由於這不是必須的,讓我們從現在開 始禁止加載任何硬體 modules。如果在配置文件中沒有任何 module 被加載,DAHDI 就會加 載 dahdi_dummy 驅動,這個驅動為 Asterisk 提供了一個從核心獲得時鐘的接口,從而使諸 如 MeetMe 和 IAX2 這樣時鐘依賴的 modules 可以正常工作。

從 DAHDI2.3.0 起,通過加載 dahdi_dummy 獲得時鐘的要求不再存在。 相關的功能現在集成到 dahdi kernel module 中去了。

定義 DAHDI 會加載哪些 modules 的配置文件位於/etc/dahdi/modules。為了禁止加載額 外的 modules,我們需要做的事就是編輯 modules 文件並通過在每一行前面加#號注釋掉所 有的 modules。當你完成了這一點,你的 modules 配置文件應當看起來如下:

你也可以利用 dahdi_genconf modules 來生成適當的空配置文件。 dahdi_genconf application 會搜索你的系統硬體,如果什麼都沒有找到, 會創建一個不會加載任何硬體 modules 的 modules 文件。

然後你可以通過重啟你的 DAHDI 來卸載任何已經加載的現有驅動,並且只在初始化腳 本中加載 dahdi_dummy modules:

 sudo  /etc/init.d/dahdi restart

在你可以使用你的硬體之前,你還需要配置 /etc/dahdi/system.conf 文件;這一過程在本章 下兩節描述。

7.3.2.2配置數字線路[編輯]

電信運營商開發數字電話技術是為了減少長途線路費用,同時提升傳輸質量。整個 PSTN 骨幹網已經完全實現數位化多年了。數字線路的關鍵是實現聲音信號的數位化。不過數字干 線也會允許更複雜和更可靠的信令。幾個標準被不斷開發出來,對每個標準而言,只是有部 分的區別。

你可以使用 dahai_hardware 和 lsdahdi 幫助你確定你的系統包含那些電 話技術硬體。你也可以使用 dahdi‐genconf modules 來產生一個 /etc/asterisk/modules 文件,該文件是基於找到的硬體產生的。

7.3.2.2.1 PRI ISDN[編輯]

Primary Rate Interface ISDN(一般稱為PRI)是一個設計為主要運行於DS1(T1或E1) 線路上的,用於運營商與客戶之間的協議。PRI 使用一個 DS0 信道作為信令通道(稱為 D 信 道)。一個典型的 PRI 信道是劃分為一組 B 信道(實際承載呼叫的承載信道),和一個用於信 令的 D 信道。儘管最常見的作法是 PRI 線路承載在單一的物理線路上(例如 T1 和 E1),但 是把 PRI 線路分散在多個 DS1 線路上也是可行的,甚至於有多個 D 信道注 6。

儘管有許多不同的配置 PRI 的方法,我們希望避免這些選擇把你弄糊塗(許多方法已經 過時了或至少不再通用),並且提供了一些通用配置方法的例子。

當安裝電話板卡硬體時,請確保升級了 /etc/dahdi/modules 文件以使能 與你的硬體適應的 modules,然後通過初始化腳本(/etc/init.d/dahdi)重 載 DAHDI。你也可以使用 dahdi_genconf modules 命令生成 modules 文件。

大部分用於北美的 PRI 線路都使用具有下列特性的 T1 線路:

  Line code: B8ZS ( bipolar with 9‐zero substitution )
  Framing: ESF ( extended superframe )

你還需要配置兩個文件。其中 /etc/dahdi/system.conf 應按如下配置:

 loadzone = us

defaultzone = us

span = 1,1,0,esf,n8zs bchan = 1‐23 enchocanceller = mg2,1‐23 hardhdlc =24

另一個 /etc/asterisk/chan_dahdi.conf 應按如下配置:

 [trunkgroups]
[channels]
usecallerid = yes
hidecallerid = no
callwaiting = yes
callwaitingcallerid = yes
threeewaycalling = yes
transfer = yes
canpark = yes
cancallforward = yes
callreturn = yes
echocancel = yes
echocancelwhenbridge = yes
relaxdemf = yes
rxgain = 0.0
txgain = 0.0
group = 1
callgroup = 1
pickgroup = 1
pickupgroup = 1
immediate = no
switchtype = national ; commonly referenced to as NI2
context = from‐pstn
group = 0
echocancel = yes
signaling = pri_cpe
channel => 1‐23

某些運營商採用 Nortel 的 DMS 交換機,這種交換機一般採用 DMS100 協議而不是標準的 ISDN 協議。在這種情況下,你需要把 switchtype 設置為 DMS100:

 switchtype = dms100

在美國和加拿大之外,PRI 線路主要承載在 E1 線路上。 在歐洲,用於 PRI 的 E1 線路一般具有如下特性:

  Line code: CCS
  Framing: HDB3 (high‐density bipolar)

並且 /etc/asterisk/chan_dahdi.conf 應當看起來如下:

 [trunkgroups]
[channels]
usecallerid = yes
hidecallerid = no
callwaiting = yes
usecallingpres = yes
callwaitingcallerid = yes
threewaycalling = yes
transfer = yes
canpark = yes
cancallforward = yes
callreturn = yes
echocancel = yes
echocancelwhenbridged = yes
relaxdtmf = yes
rxgain = 0.0
txgain = 0.0
group = 1
callgroup = 1
pickupgroup = 1
immediate = no
switchtype = qsig
context = pri_incoming
group = 0
signalling = pri_cpe
channel => 1-15,17-31

7.3.2.2.2 BRI ISDN[編輯]

Basic Rate Interface ISDN(通常稱作 BRI,或者直接稱作 ISDN)可以看作 PRI 的一個小兄 弟。BRI 只提供 2 個 64Kbps 的 B 通道和一個 16Kbps 的 D 通道。BRI 在北美地區很少使用(我 們不推薦使用 BRI,不管出於什麼原因),但是在一些歐洲國家 BRI 廣泛應用,甚至已經基本 取代了模擬線路。

在 Asterisk 下的 BRI 支持主要取決於你安裝了何種 BRI 板卡。BRI 板卡的廠商會提供專門 的安裝指導。

当安装电话板卡硬件时,请确保升级了 /etc/dahdi/modules 文件以使能

與你的硬體適應的 modules,然後通過初始化腳本(/etc/init.d/dahdi)重 載 DAHDI。你也可以使用 dahdi_genconf modules 命令生成 modules 文件。

7.3.2.2.3 MFC/R2[編輯]

MFC/R2 協議可以被認為是 ISDN 協議的先驅。它首先用在模擬線路上,但是現在也大量 應用在 E1 線路上,E1 線路也用於承載 ISDN‐BRI。MFC/R2 協議在加拿大、美國和西歐並不常見,但是它在某些地區非常流行(特別是拉丁美洲和亞洲),主要是因為它適合於運 營商提供較為廉價的服務。

這個協議有許多不同的風格,在每個國家都由不同的變體。

OpenR2 項目提供了 libopenr2 庫,為了你的 Asterisk 系統能支持 R2 線路,你需要安裝 這個庫。在安裝 libopenr2 之前,你需要完成 DAHDI 的安裝。 編譯和安裝的順序是:

 1. DAHDI
 2. Libopenr2
 3. Asterisk

一旦安裝了 OpenR2 ,你就可以使用 r2test application 來查看一下支持的變體列表:

 $ r2test -l
Variant Code Country AR Argentina
BR Brazil
CN China
CZ Czech Republic
CO Colombia
EC Ecuador
ITU International Telecommunication Union MX Mexico
PH Philippines
VE Venezuela

關於更多在 Asterisk 中配置 R2 的信息,請參閱 Asterisk 源碼目錄下(搜索 「mfcr2」)的 configs/chan_dahdi.conf.sample 。

此外,OpenR2 包含一些在不同國家實現 Asterisk 與網絡連接的配置例子文件。如果需 要閱讀關於不同國家變體的信息,搜索 /doc/asterisk 目錄並查看相應目錄下的文檔:

$ ls doc/asterisk/
ar br ec mx ve

作為一個例子,OpenR2 提供了一個用於在墨西哥連接 Telmex 或 Axtel 的例子配置文件。 我們逐步展示這個例子。首先,你必須通過修改 /etc/dahdi/system.conf 來配置 DAHDI,如 下所示:

loadzone = us
defaultzone = us
span = 1,1,0,cas,hdb3
cas = 1-15:1101
cas = 17-31:1101
span = 2,1,0,cas,hdb3
cas = 32-46:1101
cas = 48-62:1101

下一步,你必須通過修改 /etc/astereisk/chan_dahdi.conf 來配置 Asterisk,如下所示:

signalling = mfcr2
mfcr2_variant = mx
mfcr2_get_ani_first = no
mfcr2_max_ani = 10
mfcr2_max_dnis = 4
mfcr2_category = national_subscriber
mfcr2_mfback_timeout = -1
mfcr2_metering_pulse_timeout = -1
; this is for debugging purposes
mfcr2_logdir = log
mfcr2_logging = all
 ; end debugging configuration
channel => 1-15
channel => 17-31


7.3.2.3 配置模擬線路[編輯]

有許多公司生產用於 Asterisk 的 PSTN 板卡。這些板卡需要安裝驅動程序,這樣 Linux 才可以識別它們(DAHDI 包含了 Digium 的板卡驅動)。從這一點看,配置是被 Asterisk module chan_dahdi 處理的。

你可以使用 dahdi_hardware 和 lsdahdi 來確定你的系統包含哪些電話 板卡硬體。

當安裝電話板卡硬體時,請確保升級了 /etc/dahdi/modules 文件以使能 與你的硬體適應的 modules,然後通過初始化腳本(/etc/init.d/dahdi)重 載 DAHDI。你也可以使用 dahdi_genconf modules 命令生成 modules 文件。

為了配置一張 FXO 板卡能夠在 Asterisk 上工作,需要兩個文件。

第一個文件並不是 Asterisk 配置文件,而是位於 /etc/dahdi 目錄下的文件注 7。這個文件, system.conf,允許你定義一些基本參數,同時指定在系統中有效的 channels。我們的例子假 設是一張有 4 個 FXO 埠的板卡,但是其它不同的組合也是可以的,這取決於你的硬體。

loadzone = us     ; tonezone defines sounds the interface must produce
                            ; (dialtone, busy signal, ringback, etc.)
defaultzone = us ; define a default tonezone
fxsks = 1-4          ; which channels on the card will have these parameters

一旦你的板卡和 Channels 被系統識別,你還必須通過文件 /etc/asterisk/chan_dahdi.conf 在 Asterisk 中配置它們:

[channels]
; To apply other options to these channels, put them before "channel". 
signalling = fxs_ks ; in Asterisk, FXO channels use FXS signaling
                              ; (and yes, FXS channels use FXO signaling)
channel => 1-4 ; apply all the previously defined settings to this channel

在這個例子中,我們告訴 Asterisk,系統中的頭 4 個 DAHDI channels 是 FXO 埠。


7.3.2.3.1 The s extension[編輯]

如果你使用模擬 channels 連接 PSTN,那麼我們需要解釋下 extension s 。當一個來電進 入一個context,但是沒有指定目的 extension 時(例如,通過PSTN網絡振鈴一個FXO埠), 它會被傳遞給 s extension。(這裡 s 的意思是「start」,這個 extension 是當沒有攜帶 extension 信息的來電的起始入口)。這個 extension 在 dialplan 中實現從一個部分到另一個部分的跳轉 時也十分有用。舉例來說,如果我們對一系列 DID 號碼的處理都是跳轉到同一個地方,我們 就可以將它們都跳轉到 s extension 處理,而不是為每一個 DID 拷貝同樣的 dialplan 代碼。

因為這實在是我們的 dialplan 中需要的,讓我們把它添加進去。我們將對來電執行三個 動作(應答,播放一個聲音文件,然後掛機),所以我們的 s extension 將需要 3 個 priorities。 我們把這 3 個 priorities 放在[incoming]下面,因為我們決定所有的來電都從這個 context 開 始注 8:

 [incoming]
 exten => s,1,Answer()
   same => n,Playback(tt-weasels)
   same => n,Hangup()

顯然的,你一般不會想應答一個電話然後掛掉。典型的,一個來電要麼被一個自動應答機應 答,要麼直接振鈴一部電話(或一組電話)。

7.4 VoIP[編輯]

在電信世界裡,VoIP 還是相對比較新的概念。在上個世紀或 VoIP 出現之前,把你和 PSTN 網絡聯繫起來的唯一辦法是利用本地電話公司提供的專用線路。現在,VoIP 允許你把兩個 用戶聯繫起來而根本不引入 PSTN(儘管在大部分 VoIP 場景,仍舊存在 PSTN 元素,特別是 在使用傳統 E.164 號碼的場合)。

7.4.1 PSTN 終結(termination)[編輯]

在 VoIP 完全取代 PSTN 之前,我們都會需要將呼叫從 VoIP 網絡連接到 PSTN 網絡。這個 過程稱為終結(termination)。這意思是說,在 VoIP 網絡上的某些點,連接 PSTN 的網關需 要從 VoIP 網絡接收呼叫並把它們連接到 PSTN 網絡上。從 PSTN 網絡的角度看,這些呼叫看 起來就是從「終結點」發起的。

Asterisk 可以被用作終結設備。事實上,由於 Asterisk 非常方便處理協議轉換,用作終 結設備是 Asterisk 系統一種非常適合的應用。

為了提供 PSTN 終結,Asterisk 設備需要能夠處理所有連接的 PSTN 網絡的協議。一般來 說,這意味著你的 Asterisk 設備需要 PRI 線路來處理 PSTN 連接,以及 SIP channels 來處理來 自 VoIP 網絡的呼叫。基本原理是相同的,無論你是運行一個為完全部署 VoIP 電話的辦公室 提供PSTN trunks的小型系統,還是運行一個在關鍵地點部署網關設備並為數千個用戶提供 PSTN 終結服務的複雜網絡。

來自 VoIP 網絡的呼叫會進入 Dialplan 中為 SIP 來電指定的 context,並且 dialplan 會將呼 叫中繼到 PSTN 接口。這非常簡單,支持 PSTN 終結的部分 dialplan 代碼如下:

 [from-voip-network]
 exten => _X.,1,Verbose(2, Call from VoIP network to ${EXTEN})
   same => n,Dial(DAHDI/g0/${EXTEN})

在現實中,你一般需要處理更複雜的路由計劃,需要考慮諸如地理位置、合作政策、費用、 可用的資源等等。

由於大部分 PSTN 線路都允許你撥叫世界上的任意位置的任意號碼,而且 你都需要為已發生的費用買單,所以加強 PSTN 終結網關的安全性是怎麼 強調其重要性都不過分的事情。犯罪分子花費了很多努力去破解電話系統 (特別是沒有很好設置安全性的 Asterisk 系統),如果你沒有很小心的關 注安全性的各個方面,那麼你很容易成為話費欺詐的犧牲品。這只是時間 早晚問題而已。

千萬不要允許任何不安全的 VoIP 連接訪問包含 PSTN 終結的 context。

7.4.1 PSTN 再生[編輯]

顯然的,如果你希望將呼叫從 VoIP 網絡轉到 PSTN 網絡,那麼你可以也希望可以從 PSTN 接受呼叫到你的 VoIP 網絡。這個過程一般稱作再生(origination)。這簡單的指出呼叫是從 PSTN 網絡產生的。

為了實現再生,電話號碼是必須的。因此你需要從本地電話公司獲得用於連接到你的 Asterisk 系統的線路。根據你所在國家和地區的不同,有幾種不同的線路可以提供用於 PSTN 再生,從最基本的 POTS 線路到運營商級的 SS7 線路。

用於 PSTN 再生目的的電話號碼一般稱為直接拔入號碼(DIDs)。這種叫法 在某些場合併不嚴謹(例如,傳統模擬線路的號碼就不能被認為是 DID), 但是這個術語這麼用已經非常流行了。從歷史上說,DID 專指連接到客戶 端設備(CPE)的幹線關聯的號碼。

由於電話號碼是被傳統電信業控制的,你要麼從運營商直接獲取電話號碼,要麼從那些 大批購入號碼再拆成較小的塊轉賣的公司處獲得。如果你獲得了諸如 PRI 這樣的線路,你一 般可以購買與這個線路一起交付的 DID 號碼。

為了接受來自你用於 PSTN 再生的線路的呼叫,你一般需要能處理被叫號碼。這是因為 PSTN 幹線一般不止一個號碼,並且運營商需要指出那個號碼是被叫,這樣你的 Asterisk 系統才知道如何路由這個呼叫。這個被叫號碼一般稱作被叫號碼識別服務(DINS,Dialed Number Identification Service)號碼。DINS號碼和DID號碼不一定必須一致注9,但一般它們 是一致的。當你向運營商購買線路時,你需要要求它們發送 DNIS(如果他們不理解這個要 求,你可能需要考慮其它運營商了)。

在 Dialplan 中,處理呼入線路的 context 需要知道如何處理呼入號碼。如下例所示:

[from-pstn]
; This is the context that would be listed in the config file
; for the circuit (i.e. chan_dahdi.conf)

exten => _X.,1,Verbose(2,Incoming call to ${EXTEN})
  same => n,Goto(number-mapping,${EXTEN},1)

[number-mapping]
; This context is not strictly required, but will make it easier
; to keep track of your DIDs in a single location in your dialplan.
; From here you can pass the call to another part of the dialplan
; where the actual dialplan work will take place.
exten => 4165551234,1,Dial(SIP/0000FFFF0001)
exten => 4165554321,1,Goto(autoattendant-context,start,1)
exten => 4165559876,1,VoiceMailMain() ; a handy back door for listening
                                             ; to voice messages
exten => i,1,Verbose(2,Incoming call to invalid number)

在number‐mapping context中,明白的列出了所有需要處理的DID號碼,再加上對未列出 的 DID 號碼的無效號碼處理句柄(你可以把無效號碼轉給前台,或者自動應答機,或者任意 播放一段無效提示的 context)。

7.4.3 VoIP to VoIP[編輯]

最終,對 PSTN 的需要可能消失,大部分語音通訊將通過網絡進行。

隱藏在 SIP 協議後的原始思想是它曾經是一個點到點(Peer‐to‐Peer)協議。從技術上講, 它今日仍舊是。然而,事情現在已經變得非常複雜了。諸如安全、隱私、公司政策、一體化、 集中管理等等把事情變得非常複雜,遠遠超過了簡單的在一部 SIP 話機里輸入一個 URL 而其 它地方的另一部 SIP 話機就會振鈴響應的應用。

SIP 協議變得膨脹而複雜。實現一套基於 SIP 的系統和網絡變得比實現傳統電話 PBX 網 絡複雜的多。注 10

我們並不打算在本書中討論複雜的 VOIP 系統的設計和實現問題,但是我們會討論一些 將 Asterisk 系統配置為支持 VOIP 系統之間互聯的方法。

7.4.4 配置 VoIP 幹線(VoIP Trunks)[編輯]

在 Asterisk 中,並不需要單獨安裝 VoIP 模塊(除非由於某種原因,你沒有編譯 Asterisk 要求的模塊)。有幾種不同的 VoIP 協議都可以用於 Asterisk,但我們將集中討論兩種最流行 的:SIP 和 IAX。

7.4.4.1 在 Asterisk 系統之間配置 SIP 幹線(SIP Trunks)[編輯]

SIP 是最流行的 VoIP 協議——它是如此流行以至於許多人以為其它的 VoIP 協議已經作 廢了(它們並沒有作廢,但是這並不能否認 SIP 已經統治 VoIP 領域許多年了)。

SIP 協議是點對點(peer‐to‐peer)協議,而且並沒有正式的幹線特性。這意思是說,無 論你將一部 SIP 話機連接到你的 SIP 伺服器,還是把兩個 SIP 伺服器連接起來,對 SIP 連接來 說都是一樣的。

7.4.4.1.1 通過SIP連接兩個Asterisk系統[編輯]

將兩個 Asterisk 系統連接起來,並允許在它們彼此間呼叫的需要是很普遍的需求。比如 你有一家公司有兩個辦公地點並在每個地點部署了一台 PBX,或者比如你是一家公司的 PBX 管理員,而你非常喜歡 Asterisk 並在家裡也架設了一個。本節對配置兩個 Asterisk 伺服器能 夠通過 SIP 互通提供了一個快速指導。在我們的例子中,我們將這兩個伺服器稱為 serverA 和 serverB 。

首先必須修改的文件是 /etc/asterisk/sip.conf 。這是配置 SIP 帳號的主要配置文件。首 先,如下內容必須被添加到 serverA 的 sip.conf 中。它定義了對端伺服器需要使用的 SIP 帳號:

[serverB]
;
; Specify the SIP account type as 'peer'. This means that incoming
; calls will be matched on IP address and port number. So, when Asterisk
; receives a call from 192.168.1.102 and the standard SIP port of 5060,
; it will match this entry in sip.conf. It will then request authentication
; and expect the password to match the 'secret' specified here.
;
type = peer
;
; This is the IP address for the remote box (serverB). This option can also
; be provided a hostname.
;
host = 192.168.1.102
;
; When we send calls to this SIP peer and must provide authentication,
; we use 'serverA' as our username. ;
username = serverA
;
; This is the shared secret with serverB. It will be used as the password
; when either receiving a call from serverB, or sending a call to serverB. ;
secret = apples
;
; When receiving a call from serverB, match it against extensions
; in the 'incoming' context of extensions.conf.
;
context = incoming
;
; Start by clearing out the list of allowed codecs. ;
disallow = all
;
; Only allow the ulaw codec.
;
allow= ulaw

請注意修改 host 選項以匹配你自己系統配置的 IP 位址

然後將下述代碼輸入到 serverB 的 /etc/asterisk/sip.conf 中。它差不多和我們在 serverA 中的代碼一樣,除了帳戶名稱和 IP 位址不同:

[serverA]
type = peer
host = 192.168.1.101
username = serverB
secret = apples
context = incoming
disallow = all
allow = ulaw

現在你應該通過 Asterisk CLI 命令驗證一下這些配置是否已經成功載入 Asterisk 了。首先可以 試一下 sip show peers 命令。如同這個命令名字所暗示的,它可以顯示所有已經配置的 SIP 帳號:

*CLI> sip show peers
Name/username Host                Dyn Forcerport ACL Port  Status
serverB/serverA 192.168.1.101                                  5060  Unmonitored
1 sip peers [Monitored: 0 online, 0 offline Unmonitored: 1 online, 0 offline]

你也可以在 serverB 上試一下 sip show peers 命令。這個命令可以顯示很 多細節。

在兩個 Asterisk 伺服器之間配置 SIP 呼叫的最後一步是修改 /etc/asterisk/extensions.conf 的 dialplan 文件。舉例來說,如果你希望在 serverA 上向 6000 到 6999 發起的呼叫都被傳遞 給 serverB,你需要在 serverA 的 dialplan 中增加如下一行:

exten => _6XXX,1,Dial(SIP/${EXTEN}@serverB)

7.4.4.1.2 將Asterisk系統連接到一個SIP服務提供商[編輯]

如果你註冊了一個 SIP 服務提供商,你或許已經獲得了撥出或接受電話呼叫的服務。這 種配置會根據你選擇服務提供商的不同而稍有不同。理想情況下,你註冊的 SIP 服務提供商 會提供 Asterisk 的配置示例以幫助你儘快聯通系統。如果他們沒有提供,那麼,我們將嘗試 給你提供一些通用配置以幫助你開始。

如果你能從你的 SIP 服務提供商收到呼叫,那麼服務提供商一般會要求你的伺服器能夠 註冊到他們的伺服器上。為了做到這一點,你必須在 /etc/asterisk/sip.conf 的 [general] 部 分中增加註冊行:

[general]
...
register => username:password@your.provider.tld
...

下一步,你需要在 sip.conf 中為你的服務提供商創建一個入口點。如下例所示:

[myprovider]
type = peer
host = your.provider.tld
username = username
secret = password
; Most providers won't authenticate when they send calls to you,
; so you need this line to just accept their calls.
insecure = invite
dtmfmode = rfc2833
disallow = all
allow = ulaw

現在已經完成了帳號定義,你還必須在 dialplan 中增加幾行以允許你向服務提供商發起呼叫:

exten => _1NXXNXXXXXX,1,Dial(SIP/${EXTEN}@myprovider)

7.4.4.1.3 加密SIP呼叫[編輯]

Asterisk 支持 TLS 加密 SIP 信令,以及 SRTP 加密媒體流。在本節中,我們將在兩台 Asterisk 之間利用 SIP TLS 和 SRTP 建立呼叫。第一步是確保所有依賴軟體都已經安裝好了。確保你已 經安裝了 OpenSSL 和 LibSRTP。如果任何一個沒有安裝,請先安裝這些依賴軟體,然後再重 裝 Asterisk 以確保 Asterisk 已經包含了對 TLS 和 SRTP 的支持。一旦完成,請確保 res_srtp modules已經被編譯並安裝。要安裝OpenSSL,CentOS下的安裝包是 openssl‐devel ,Ubuntu 下的安裝包是 libssl‐dev。要安裝 LibSRTP,CentOS 下的安裝包是 libsrtp‐devel,Ubuntu 下 的安裝包是 libsrtp0‐dev。

下一步我們將配置 SIP TLS。你必須通過雙方伺服器上 /etc/asterisk/sip.conf 中[general] 部分中的 tlsenable 來使能 TLS。你可以指定一個 IP 位址來綁定 TLS 的偵聽 IP。這個例子中, 我們採用 IPv6 的通配符地址,意思是允許 TLS 連接到系統的所有 IPv4 和 IPv6 地址上:

[general]
tlsenable = yes
tlsbindaddr = ::

再下一步就是獲取證書了。為了驗證配置和功能的目的,我們打算利用隨 Asterisk 發布的 helper 腳本生成自簽發(self‐signed)證書。如果你是在真實環境中使用,你可能不希望使 用自簽發證書。可是,如果你想做,有不少應用程式可以幫助你很容易的管理你自己的認證 授權(CA),比如 TinyCA。

我們需要用到的腳本是 ast_tls_cert,它在Asterisk源文件的 contrib./scripts/directory 目 錄下。我們需要生成一個 CA 證書和兩個伺服器證書。首先利用 ast_tls_cert 生成 CA 證書和 serverA 的伺服器證書。然後再利用 ast_tls_cert 生成 serverB 的伺服器證書:

$ cd contrib/scripts
$ mkdir certs
$ ./ast_tls_cert -d certs -C serverA -o serverA
$ ./ast_tls_cert -d certs -C serverB -o serverB -c certs/ca.crt -k certs/ca.key
$ ls certs
ca.cfg ca.crt ca.key serverA.crt serverA.csr serverA.key serverA.pem
serverB.crt serverB.csr serverB.key serverB.pem tmp.cfg

現在證書已經創建好了,它們需要被移動到 serverA 和 serverB 上的適當位置。我們將使用 /var/lib/asterisk/keys/ 目錄來存放證書。將下列文件移動到 serverA:

 ca.crt
 serverA.pem

將下列文件移動到 serverB:

 ca.crt
 server.pem

將認證文件準備好後,我們就可以完成 Asterisk 的配置了。我們需要告訴 Asterisk 我們剛剛 創建的伺服器證書。雖然我們採用的是自簽發證書,我們仍然需要指出證書的位置。在 serverA 中 /etc/asterisk/sip.conf 的[general]部分中,增加如下內容:

[general]
tlscertfile = /var/lib/asterisk/keys/serverA.pem
tlscafile = /var/lib/asterisk/keys/ca.crt

在 serverB 做同樣的修改:

[general]
tlscertfile = /var/lib/asterisk/keys/serverB.pem
tlscafile = /var/lib/asterisk/keys/ca.crt

當你創建伺服器證書時,Common Name 欄位必須與伺服器主機的 hostname 一致。如果你採用 ast_tls_cert 腳本,這可以通過‐C 選項實現。 如果呼叫時發生了伺服器證書驗證問題,你可能需要修復 Common Name 欄位。另一個選擇是,出於測試目的,你可以將/etc/asterisk/sip.conf 里 [general]部分中的 tlsdont verify server 選項設置為 yes,這樣 Asterisk 即 使在伺服器證書驗證失敗的情況下也會允許呼叫進行。

在 7.4.4.1.1 一節,我們創建了在 serverA 和 serverB 之間呼叫電話的必要配置。現在我們修 改一下這些配置文件,以讓 Asterisk 知道在這兩個伺服器之間的呼叫是需要加密的。唯一的 變化是在每個伺服器的入口配置中增加 transport = tls 選項。

在 serverA 上:

[serverB]
type = peer
host = 192.168.1.102
username = serverA
secret = apples
context = incoming
disallow = all
allow = ulaw
transport = tls

在 serverB 上:

[serverA]
type = peer
host = 192.168.1.101
username = serverB
secret = apples
context = incoming
disallow = all
allow = ulaw
transport = tls

現在,當你利用 Dial(SIP/server) 或 Dial(SIP/server) 發起呼叫時,SIP 信令就會被加密。你可 以通過修改 dialplan 設置 CHANNEL(secure_bridge_signaling)=1 來強制所有外呼呼叫被加密。

[default]
exten => 1234,1,Set(CHANNEL(secure_bridge_signaling)=1)
  same => n,Dial(SIP/1234@serverB)

在接收呼叫側,你可以利用 CHANNEL(secure_signaling) dialplan 函數來檢查呼入呼叫的信令 是否被加密,參見下面的例子:

[incoming]
exten => _X.,1,Answer()
   same => n,GotoIf($["${CHANNEL(secure_signaling)}" = "1"]?secure:insecure) same => n(secure),NoOp(Signaling is encrypted.)
   same => n,Hangup()
   same => n(insecure),NoOp(Signaling is not encrypted.)
   same => n,Hangup()

當呼叫從採用這種配置的 serverA 發送到 serverB 時,你可以通過 Asterisk 控制台輸出看到 dialplan 判斷呼入呼叫的信令是加密的:

 -- Executing [1234@incoming:1] Answer("SIP/serverA-00000000", "") in new stack -- Executing [1234@incoming:2] GotoIf("SIP/serverA-00000000",
 "1?secure:insecure") in new stack
 -- Goto (incoming,1234,3)
 -- Executing [1234@incoming:3] NoOp("SIP/serverA-00000000",
 "Signaling is encrypted.") in new stack
 -- Executing [1234@incoming:4] Hangup("SIP/serverA-00000000", "") in new stack

現在 SIP TLS 已經配置好了,我們還需要配置 SRTP 以實現媒體流的加密。幸運的是,與 SIP TLS 的配置相比,它非常容易配置。首先,確保 res_srtp module 已經被 Asterisk 加載了:

*CLI> module show like res_srtp.so
Module Description Use Count
res_srtp.so Secure RTP (SRTP) 0
1 modules loaded

為了使能 SRTP,配置 CHANEL(secure_bridge_media)函數為 1:

[default]
exten => 1234,1,Set(CHANNEL(secure_bridge_signaling)=1)
    same => n,Set(CHANNEL(secure_bridge_media)=1)
    same => n,Dial(SIP/1234@serverB)

這個配置指出呼出呼叫需要加密媒體。當呼叫通過 SIP 發出時,Asterisk 將要求 SRTP 被使用, 否則呼叫會失敗。

通過所有這些工具,你可以確保兩個 Asterisk 伺服器之間的呼叫是完全加密的。同樣的 技術也可以被用於加密 Asterisk 和 SIP 話機之間的呼叫。

Dialplan 函數提供了驗證呼入呼叫是否加密以及強制呼出呼叫加密的機制。然而,請記 住這些工具只能提供控制在呼叫路徑上「一跳」(one hop)的加密。如果這個呼叫經過多個 伺服器,這些工具並不能保證整個呼叫路徑都是加密的。仔細考慮加密呼叫的需求並執行所 有必須的步驟以確保這些需求在整個呼叫路徑上都被考慮到是非常重要的。安全性是複雜、 艱苦的工作。

7.5 結論[編輯]

最終,我們相信 PSTN 將整個消失。然而,在這一切發生之前,我們需要一個被廣泛使 用和信任的發布機制,這個機制允許組織和個人發布他們的地址信息,從而使得他們能夠被 找到。我們將在第 12 章研究一些可能的方法。

注釋:

注1. 在按鍵電話系統中,每條外線在每部電話上都有一個對應的按鍵,對每條外線的訪問通過按下對應的 按鍵(line key)實現。

注2. 你可以命名為任何你希望的名字。名字「local」和「toll」對於 Asterisk dialplan 沒有任何內建的意思。

注3. 更多關於樣式匹配的信息,請參閱第 6 章。

注4. 如果你希望把你的傳統家庭電話線連接到你的 Asterisk 系統上,你需要完全相同的板卡。

注5. 獲得時鐘源也有一些其它方法,如果你真的希望一個很緊湊的系統,運行一個不包含 DAHDI 的 Asterisk

 系统是可能的,但是它不是我们想在这里讨论的。

注6.有時線路會根據它包含了多少B信道和D信道來命名,所以一個單獨的運行在北美PRI協議的T1可以 被稱作 23B+D,一個雙 T1 線路加上一個備份 D 信道可以被稱為 46B+2D。我們也見過 PRI 線路被稱為 nB+nD,儘管這有點書呆子氣了。

注7. 理論上,這些板卡可以用於任何支持 DAHDI 的軟體;因此,基本的板卡配置文件就不應該是 Asterisk 的一部分。

注8. Context 的名字沒有任何指定的名字。我們也可以命名這個 context 為[stuff_that_comes_in],只要這個 context 在 channel 定義文件 sip.conf, iax.conf, chan‐dahdi.conf, 等等中有指向,某個 channel 將通過這個 context 進入 dialplan。雖然這麼說,我們仍然強烈建議你命名的 context 名字能夠幫助你理解它們的目 的。一些好的 context 名字包括 [incoming], [local_calls], [long_distance], [sip_telephones], [user_services], [experimental], [remote_locations],等等。請一直記住context決定一個channel如何進入dialplan,所 以起個相關的名字。

注9. 在傳統 PBX 系統中,DID 號碼的作用是允許直接聯繫辦公室中的一個分機。許多 PBX 系統並不支持號 碼翻譯或變長號碼等概念,因此電信運營商不得不通過 DID 號碼來傳遞分機號,而不是實際撥打的號 碼(DNIS 號碼)。舉例來說,電話號碼 416‐555‐1234 已經被映射到分機 100,因此運營商需要發送號 碼 100 給 PBX 而不是 DINS 號碼 4165551234。如果你已經把老式的 PBX 更換為 Asterisk 系統,你會在適 當的位置找到這段翻譯,而且你需要獲得一個主叫撥打的號碼和運營商發個 PBX 的號碼之間的映射表。 運營商只發送 DINS 的後四位號碼也很常見,此時 PBX 就把它翻譯為內部號碼。

注10.市場上有許多專用的 PBX 系統,它們通過基本的配置就可以很好的工作。Asterisk 的部署要靈活得多, 但是一點也不簡單。