voip – 在水一方 https://blog.vic.mh4u.org 蒹葭蒼蒼,白露為霜。所謂伊人,在水一方。 Sat, 27 Oct 2018 13:51:48 +0000 zh-TW hourly 1 https://wordpress.org/?v=6.7.1 asterisk安全性設定 https://blog.vic.mh4u.org/2017/1664 https://blog.vic.mh4u.org/2017/1664#comments Thu, 16 Mar 2017 09:55:02 +0000 http://blog.vic.mh4u.org/?p=1664 閱讀全文 ]]> 若你的 asterisk 使用預設定的 5060 port 的話,一定會受到不少騷擾,底下就介紹怎樣針對這些騷擾做防護。

首先要說明的是,基於安全考量,請您盡量避免使用預設的 5060 port ,這樣您的系統會安全許多,也可少做很多防護,當然事情都有例外,可能要跟你對接的一類、二類電信業者他們只能接受 5060 port 跟你對接,你要用他們的服務的話,那你也只能配合他們的要求,這篇文章所要介紹的就是你不得不使用5060 port的情況下,怎樣保護你的 asterisk 系統。

先從最簡單的方法講起

(1).鎖固定IP

要跟你對接一、二類電信業者,他們一定都會有固定IP,你就可以針對他們的IP來開放5060 port這樣就可避免你的5060 port被別人騷擾。

底下是使用 iptables 鎖5060 port 固定IP的設定範例

#放行所有的內網IP
-A INPUT -s 192.168.0.0/16 -j ACCEPT
#針對是方電訊IP,開放5060,和rtp port範圍10000~20000
-A INPUT -i eth0 -s 202.153.167.30 -p udp  -i eth1 -m multiport --dports 5060,10000:20000  -j ACCEPT
#一般使用上面這條規則就可以了,該開放的port位都有開到,但你在與他們對接時仍有問題的話,可考慮改用下方這條規則,針對UDP協定 port 位全開。
#針對是方電訊IP,udp協定全開放
#-A INPUT -i eth0 -s 202.153.167.30 -p udp -j ACCEPT

這是最簡單的設定方法,保護了你的5060 port不被不明人士騷擾。
以上的方法,需要你的使用者(sip client)都在內網才行,你的使用者都在內網來連你的asterisk這是最單純、最簡單的設定環境。

若將來你的使用者需要使用到sip soft phone(軟體電話)來連接你的asterisk時怎麼辦?
這問題很快就會遇到,因為現在智慧型手機很普遍了,不用軟體電話的話,等於是asterisk的武功被廢了一半,有這樣的功能和這樣的需求,你就要想辦法幫使用者解決問題。

我建議的解法是,再架一台 asterisk ,取名叫sip2,把5060port改掉,你自己挑一個port跟使用者公佈即可。
而原本和一、二類電信業者對接的那台我們叫sip1
底下只講做法概念,不講設定細節,因為互連的設定細節講起來會花太大篇幅,設定細節可參考我的另一篇筆記
sip1 5060port只放開特定IP
sip2 要跟sip1對接,你可走sip協定,也可走iax2協定這兩種方法都可以。
我成功的案例是用iax2對接,因為在你要使用sip協定來與sip1對接的時候你會發現 sip1是5060port,而sip2非5060port,這個設定起來可能就有些麻煩,當初我為了要避開這麻煩,所以我就挑了 iax2 協定來對接。
但在使用 iax2 設定時,發現 iax.conf 這裡面的帳號設定,若帳號少的話,只有一兩個你可能還不會發現這問題,iax帳號一旦多了的話,你就會發現它的帳號名稱會亂對應,這是個麻煩的地方。

設定好的架構會是這樣
軟體電話→→sip非5060port→→sip2server→→4569port(iax協定)→→sip1server→→sip5060port→→一、二類電信業者

上面所介紹的是比較簡單的情況,底下要介紹的是,你對接的電信業者和你的使用者都要使用5060port來跟你連線,通常這是很不得已的情況,你應盡量避免這樣的情況。我遇到的情況是接手一台已經上線多年的 asterisk ,眾多的使用者們使用5060port來連線已經多年了,要通知到這些眾多的使用者修改連線設定的難度太大,只能從server端的安全性下手加強。

(2).使用5060port時的各項防護

前面的最後一段已經介紹了我們不得不使用5060port來連線的狀況,接下來我們就來真正的面對它會遇到的問題

1.sip帳號會被暴力破解
2.匿名使用者撥打電話
3.DOS攻擊

針對上面的問題一一說明解法

1.sip帳號暴力破解

針對這個問題,我們可以使用fail2ban來抵擋,參考這一頁有詳細的設定說明。

2.匿名使用者撥打電話

白話一點講就是使用者不用註冊帳密就可以撥打電話,這個安全性問題分兩個層面要注意。

① dialplan設定
就是別人撥進你的asterisk總機系統之後,聽到IVR(語音提示)
IVR說:請直撥分機號碼,或撥9由總機為您服務
但是撥進來的人,這時候他不撥分機,也不撥9接聽總機,而是直接撥手機號碼或撥國際電話之類的…
你就要避免這種情況發生,簡單說就是 dialplan 設計的不夠嚴謹所產生的安全問題
若你還不曾意識到這個問題的話,趕快按我說的方法去測試一下你的系統是不是能就這樣直撥外線呢,若可以的話,你就得趕快的修改一下你的dialplan了。

② sip.conf 安全設定

[general]
useragent=JustPBX
;不透露asterisk版本訊息
alwaysauthreject=yes 
;指沒有註冊的帳號不能撥打電話
allowguest=no
;不允許匿名使用者撥打電話

3.DOS攻擊

這個問題一般人不太容易遇到。我遇到的情況是跟我對接的cisco設備,他要送話務給我,而我的 sip.conf 裡面不能設定底下這個參數
allowguest=no
我必須把上面那個設定給註解掉或刪掉,才能正常的接他傳過來的話務,否則就接不了它的送來的話務。但把那行設定刪掉之後,就變成任何沒有帳號的人都可以送話務到我的 asterisk 裡來了,再加上我的5060 port 沒有鎖固定IP,這樣的話,5060 port 被騷擾的事就會經常的發生。這是一個我不得不放開allowguest所遇到的麻煩,另外一個問題是大家都會遇到的,我從後台觀察到,有直接送話務過來的、有來試帳號的…不管怎樣,它們都有一個共通的最大的問題,就是因為他們沒有註冊所以log裡不會有IP記錄,也就很難用fail2ban來擋他們。

直接引用osslab一段話
重大安全威脅事件
[2011-6-3] 連 Fail2Ban 都無法阻擋的攻擊方式,當攻擊者在未註冊狀態下直接撥 Asterisk 的分機時,不管分機存在與否,Asterisk 都不會紀錄來源 IP,以致於無法使用 fail2ban 進行阻擋,攻擊者可藉此做出類似 DDos 攻擊以癱瘓 Asterisk 主機。(目前尚未有合適的解決方案 可修改dialplan 來改善)

查看 /var/log/asterisk/message 常出現這樣的訊息

[2013-04-21 14:59:33] NOTICE[1466] chan_sip.c: Sending fake auth rejection for device 1000;tag=04cd6231
[2013-04-21 14:59:33] NOTICE[1466] chan_sip.c: Sending fake auth rejection for device 1000;tag=04cd6231
[2013-04-21 14:59:34] NOTICE[1466] chan_sip.c: Sending fake auth rejection for device 1000;tag=a0029e1f
[2013-04-21 14:59:34] NOTICE[1466] chan_sip.c: Sending fake auth rejection for device 1000;tag=a0029e1f
[2013-04-21 14:59:34] NOTICE[1466] chan_sip.c: Sending fake auth rejection for device 1000;tag=18696bd1

參考資料:Missing ip address in logAsterisk not logging originating IP of a brute force attackFail2ban False sense of securitysip error logging

請參考上面的參考資料,簡單說就是某些情況的入侵行為 asterisk log 裡沒有辦法記錄到入侵者的IP,所以也就沒有辦法使用 fail2ban 來擋它,這是個壞消息,因為我曾看過我的server裡,入侵者一秒內就可以發出上百個連線,就算它沒有入侵成功,也嚴重的在消耗我的系統資源,若不做些處理方法的話,那他就可以用這招DOS的方式來搞垮我的服務。我估計一台DOS就能搞垮我的服務了,還不需動用到DDOS,嗯所以會是個滿嚴重的問題。

解決方法要從 dialplan 說起,一般我們的 asterisk 要接收別人的sip話務,都會有一個對外的context,你可以叫它 public、from-pstn、default 或 incoming 都行,不同版本的 asterisk 它的預設名稱還不一樣,但你隨時可在sip.conf 裡的 gereral 區段修改這個參數 context=public

我們就叫它 public 好了,這個 public 就是外線進來的第一個context

底下是extensions.conf設定範例

[public]

;從遠傳接收話務
exten => 4495123,1,Goto(ivr1,s,1)

;從亞太電信收話務
exten => 40580999,1,Goto(ivr2,s,1)

;從voip gateway接收話務
exten => fromGateway,1,Goto(ivr3,s,1)

;其它的號碼全掛斷
exten => _X.,1,Hangup

[ivr1]
;撥放語音提示:XXX您好,請直撥分機號,或按9由總機為您服務。
.....

[ivr2]
;撥放語音提示:XXX您好,請直撥分機號,或按9由總機為您服務。
.....

說明一下上面設定的意義,我們跟電信公司申請了兩個代表號,遠傳4495123跟亞太40580999,透過sip trunk跟我們對接,所以我們的public只有這兩個號碼進來才是正常的,其它進來的都是異常的,直接掛斷。這樣做就能起到一定的防護作用,至少你的內部分機不會接到騷擾電話,俗稱”鬼來電” 因為入侵者都是用程式在試分機號,試對分機號了,分機就響了,但程式不會講話,所以就叫鬼來電。這裡也說明了一個很重要的概念,若你的話務進來的方式非跟電信業者直接用sip trunk對接,而是用asterik卡,或voip gateway之類的將PSTN線路透過你的設備進入你的asterisk,你也要注意,不要讓這些話務直接就能撥通你內部的分機,否則你的內部分機就會有鬼來電的困擾,可參考我上面的設定範例。

上面是 dialplan 比較正確的設定方法,可有效的解決鬼來電的問題,但仍沒解決fail2ban不起作用的問題,重點在那個”其它號碼全掛斷”的地方我們要改寫一下,參考底下設定

;其它號碼全掛斷之前,記下它們的IP
exten => _X.,1,Noop(ip:${CHANNEL(recvip)})
 same => n,Log(NOTICE,bad incoming call ip:${SIPCHANINFO(recvip)})
 same => n,Waitexten(3)
 same => n,Hangup
;可用此指令core show function SIPCHANINFO 來看詳細用法
;SIPCHANINFO此指令已棄用,建議改用CHANNEL()

exten => t,1,Hangup

按上面的方式,我們就可以把入侵者的IP記錄到log裡了,那些指令都是asterisk內建的指令,所以解法早就有了,只是你會不會運用而已,這就看個人的功力了。

log已有記錄到入侵者的IP了, fail2ban 就能起作用了,當然 fail2ban 你得設定一下才行,新增filter規則之類的。

注意: asterisk function SIPCHANINFO
此 functions 從 asterisk 10~12 版都有,但在13版拿掉此功能了
https://wiki.asterisk.org/wiki/display/AST/Upgrading+to+Asterisk+13
建議改用 CHANNEL 此 function

]]>
https://blog.vic.mh4u.org/2017/1664/feed 2
dial備用路由 https://blog.vic.mh4u.org/2017/1567 https://blog.vic.mh4u.org/2017/1567#respond Fri, 10 Feb 2017 09:45:12 +0000 http://blog.vic.mh4u.org/?p=1567 閱讀全文 ]]> 我們在asterisk裡面若有不只一個外撥路由的話,我們該怎樣設定比較好?

若你想要查找更多這方便的資料,可試試試這些關鍵字 asterisk dial fail over

外撥路由,指的是我們撥打到PSTN的那一段路由。

一般若沒有加任何判斷式,會是這樣子的設定

[Call_out]
exten => _XXX.,1,Noop
 same => n,Dial(SIP/sip1/${EXTEN},60,XxWw)
 same => n,Dial(SIP/sip2/${EXTEN},60,XxWw)
 same => n,Hangup

直接就將兩個外撥路由給設定上去了,這是最簡單無腦式的設定方法。
缺點是,在某些情況下,同一個號碼會被撥兩次,比如對方拒絕你的來電又沒有設定語音信箱,就會撥兩次。

若你的外撥路由是在內網,或者你只需要擔心它ping得通不通的問題,可加入一點簡單的判斷式,底下的判斷式是參考此頁所寫。


#sip.conf 裡的設定
[sip1]
---
---
;先在這裡設定檢查存活
qualify=yes
qualifyfreq=30 
;檢查存活頻率
; Qualification: How often to check for the host to be up in seconds
; and reported in milliseconds with sip show settings.
; Set to low value if you use low timeout for NAT of UDP sessions
; 預設 60 秒
qualifygap=60 ; Number of milliseconds between each group of peers being qualified
; Default: 100

[sip2]
---
---
qualify=yes


#extensions.conf 裡的設定
[Call_out]
exten => _XXX.,1,Noop
 ;設定變數名稱 sip1status
 same => n,Set(sip1status=${SIPPEER(sip1,status)})
 ;same => n,Set(sip1status=${IAXPEER(sip1,status)})
 ;若你的 sip1 是使用IAX協定的話,上面的變數也要記得改成 IAXPEER
 ;語法 GotoIf(條件指定?真值名稱:假值名稱)
 same => n,Gotoif($[ "${sip1status}" = "UNREACHABLE" ]?sip2)
 ;條件判斷,若sip1斷線,則跳往sip2
 same => n,Dial(SIP/sip1/${EXTEN},60,XxWw)
 same => n,Hangup
 same => n(sip2),Dial(SIP/sip2/${EXTEN},60,XxWw)
 same => n,Hangup

若你的外撥路由是跟二類電信申請的SIP trunk的話,這些路由大多都有一個問題,就是超賣。比如說他們只申請了 T1 專線,有24路電話訊號,也就是同時間可供24人通話,但他們不可能只賣給24個客戶來使用這些線路,他可能會是賣給100個客戶,大家共同來擠這24線,這樣我們上面的判斷式就會有一個問題了,雖然這個 sip trunk 是ping得通的,但是對方的線路太忙了,擠不上,就會撥出失敗,所以上面的判斷式針對這種情況就不太適用,得改一下。底下的判斷式是參考此頁所修改的。

[Call_outbound]
exten => _XXX.,1,Noop
 same => n,Dial(SIP/sip1/${EXTEN},60,XxWw)
 same => n,GotoIf($[${DIALSTATUS}=CHANUNAVAIL | ${DIALSTATUS}=CONGESTION]?dial2)
 same => n,Hangup
 same => n(dial2),Noop(啟用備用路由)
 same => n,Dial(SIP/sip2/${EXTEN},60,XxWw)
 same => n,Hangup

上面的判斷式只簡單的檢查物 dial status 的兩個狀態 CHANUNAVAIL 和 CONGESTION 這兩個都會是sip trunk 忙線或有狀況時常會出現的狀態,當然你也可以自己多加一點 dial status 狀態進來。
Dial() 的傳回狀態有幾種:
ANSWER, BUSY, NOANSWER, CANCEL, CONGESTION, CHANUNAVAIL, DONTCALL, TORTURE, INVALIDARGS

基本上,以上的判斷式大概就夠用了,但我在查資料時發現還有另一種寫法,它是使用巨集的方式來寫的,記下來參考用。
底下的語法是經我測試過可行的,我在網路上查到的,可能是它的asterisk版本過舊,直接照它的語法copy來用不了,所以我仿照它的方式修改如下:


[globals]
ROUTE1 = SIP/sip1/
ROUTE2 = SIP/sip2/#前綴碼1
ROUTE3 = SIP/sip3/#前綴碼2
ROUTE4 = SIP/sip4/#前綴碼3
MAX_ROUTE = 4

[macro-direct-dial]
exten => s,1,Set(CALL_ATTEMPT=1)
exten => s,2,Set(OUT=${ROUTE1})
exten => s,3,Dial(${OUT}${ARG1},60,XxWw)
exten => s,4,GotoIf($["${CALL_ATTEMPT}" >= "${MAX_ROUTE}"]?s-CANCEL,1)
; 若變數 CALL_ATTEMP 大於 ${MAX_ROUTE} 則跳往 s-CANCEL 標,取消撥號
exten => s,5,Set(CALL_ATTEMPT=$[ ${CALL_ATTEMPT} + 1])
;變數 CALL_ATTEMP 加1
exten => s,6,Goto(${DIALSTATUS})
 same => n(CHANUNAVAIL),Set(OUT=${EVAL(${ROUTE${CALL_ATTEMPT}})})
 same => n,Noop(${OUT})
 same => n,Goto(s,3)
 same => n(CONGESTION),Set(OUT=${EVAL(${ROUTE${CALL_ATTEMPT}})})
 same => n,Noop(${EVAL(${ROUTE${CALL_ATTEMPT}})})
 same => n,Goto(s,3)
 same => n(BUSY),Noop()
 same => n(NOANSWER),Noop()
 same => n,Hangup()
exten => s-CANCEL,1,Hangup()


[Call_outbound]
exten => _XXX.,1,Noop
 same => n,Macrol(direct-dial,${EXTEN})
 same => n,Hangup

以上的方式經我反覆的測試,修正了語法錯誤之後,確定是可行的,但是對我來說不好用,最後沒用上,為什麼呢? 雖然不同的二類電信業者要帶不同的前綴碼給他們的這個問題我解決了,但是,外撥的號碼,有些是要加02、03…這些區碼,送去二類電信時,就得把這些0給拿掉,但送去一類電信時,又要加上0,一會兒加0,一會兒減0…算了,反正前面的判斷式夠我用就可以了,這個問題,暫時就不去傷腦筋了。

]]>
https://blog.vic.mh4u.org/2017/1567/feed 0
bash處理csv檔 https://blog.vic.mh4u.org/2015/1490 https://blog.vic.mh4u.org/2015/1490#respond Thu, 03 Sep 2015 07:39:49 +0000 http://blog.vic.mh4u.org/?p=1490 閱讀全文 ]]> 由於asterisk的CDR是csv格式,想要分析特定欄位,如帳單秒數,我們可以使用底下的指令

cat Master.csv|cut -d, -f14

上面那行指令的意思是列出第14個欄位
若想要指定日期範圍的話,可增加一些指令

egrep “2015-08” Master.csv|cut -d, -f14
上面是指定2015年08月份的資料,只顯示第14個欄位

原本以為這樣就可以了,可是後來發現不夠,因為凡事總有例外,底下的內容就是例外:

"this, is the first entry", this is the second, 34.5
"Dial","SIP/a2/886980xxxxxx,60,XxWw","2015-09-03 14:04:23"

有沒有看到上面那兩行的例子,都是在兩個 ” 引號的中間有逗號,這就使我們單純的使用 cut 這個工具按 , 逗號來算第幾個欄位會出錯,因為算出來的欄位數是不一樣的,所以我們就需要專門處理csv的工具,它能把兩個引號中間的逗號給忽略掉。

所以我們要先安裝csvtool這個套件
aptitude install csvtool
用法簡介:
csvtool col 14 Master.csv
上的意思是指定顯示第14個欄位,若你想要使用管線搭配其它程式使用的話,那麼檔名你就要改成 – (減號),這樣它就支援stdin(標準輸入)

底下是搭配csvtool套件所寫的script

#!/bin/bash
#1確定檔名
logname=/var/log/asterisk/cdr-csv/$1.csv
#2指定日期範圍
dateRange=$2
#3指定欄位
column=$3

#使用說明:本程式後面要帶3個參數,分別用空格隔開
#語法: cdrchk.sh log檔名 指定日期範圍 指定欄位數字
#範例: cdrchk.sh A0000000013 2015-08 14

#日期範圍說明:一定要填,可指定年月日,語法: 年-月-日 ,若只想指定年月,語法:年-月
#若不想指定範圍則需填入 .*

if [ "${1}" == "" -o "${1}" == "help" -o "${1}" == "h" ] ;then
echo 使用說明:本程式後面要帶3個參數,分別用空格隔開
echo "語法: cdrchk.sh log檔名 指定日期範圍 指定欄位數字"
echo "範例: cdrchk.sh A0000000013 2015-08 14"
echo "日期範圍說明:一定要填,可指定年月日,語法1:年-月-日 語法2:年-月"
echo "若不想指定日期範圍則需填入 .*"
exit
fi
#egrep "$dateRange" $logname | cut -d, -f$column
egrep "$dateRange" $logname | csvtool col $column -

簡介:此程式後面要帶3個參數,若不帶任何參數的話,則會顯示使用說明,若帶 help 參數也會顯示使用說明。

]]>
https://blog.vic.mh4u.org/2015/1490/feed 0
DID號碼設定 https://blog.vic.mh4u.org/2014/1425 https://blog.vic.mh4u.org/2014/1425#comments Tue, 02 Dec 2014 10:26:34 +0000 http://blog.vic.mh4u.org/?p=1425 閱讀全文 ]]> DID= (Direct Inward Dialing)直接撥入
DID–直接撥入(在歐洲叫DDI)
簡言之, DID號碼就是直播專線,使用DID,需要申請一條ISDN或數位化線路,而公司這端則需要具有DID功能的設備,其中包括BRI、E1 或T1卡或閘道。

情境簡介:
當我們向電話公司申請了10條電話線路,這10條線路是count current的數字,也就是同一時間能撥打只有10線,第11個人想要撥進或撥出就會出現忙線的狀況,那他就得等一等了,等有人掛斷之後他才能再撥。

業務同仁反應一個問題,每次撥電話給客戶時都是用公司的線路撥出去,顯示在客戶的手機上面都是公司的代表號,客戶回撥時都只能聽到公司的IVR,不知是誰找他,每次都要總機小姐問個老半天才知是誰找,有沒有好的解決方法呢?

最好的解決方法就是給每一位業務同仁一條專線,撥出去時都顯示他自己那條專線的號碼。

但申請一條專線給每位業務的話,又好象不太實際,除非他話務量真的很大,不然的話,一條專線總是空在那裡,沒能充份利用,每月的月租費(300元左右)又不便宜,怎辦?

DID號碼就是個解決方案,DID號碼實際上是個虛擬門號,你可以申請50個DID號碼,而只用10條count current的線路。你可以向中華電信、亞太電信….一般的電信業者都有提供這樣的服務。

亞太電信的DID門號,一次就要申請10組,每一門號月租費要90元,所以一申請,每個月最少就要付900元

它的使用概念就是將某一個DID號碼設定在分機上面的Caller ID,讓此分機以此Caller ID 撥出去即可。前提是你要跟那些電信業者使用 sip 串接,能夠直接送 sip 訊號給他們才行。

好了,底下就開始介紹 asterisk 怎樣設定 DID 號碼給各分機使用。

當我們向電信業者申請了did號碼之後,他會給我們號碼長的象這樣
22650001
22650002
22650003
22650004
22650005
….
….
….
22650030
通常是連號的

sip.conf 裡的設定

[in](!)
type=friend
context=callout
host=dynamic
dtmfmode=rfc2833
canreinvite=yes
directmedia=yes
directrtpsetup=yes
qualify=yes

[4001](in) 
secret=4001
cid_number = 22650001

[4002](in) 
secret=4002
cid_number = 22650002

[4003](in) 
secret=4003
cid_number = 22650003

extension.conf

[callin]
exten => 22650001,1,Dial(sip/4001,30,m)
exten => 22650002,1,Dial(sip/4002,30,m)
;既設了did號碼,那麼就要指定別人回撥時要送到哪個分機去

[callout]
exten => _XX.,1,Noop(${CALLERID(num):0:4}) ;說明:0:4 是指從第0位數之後開始,只取4個數字
 same => n,GotoIf($["${CALLERID(num):0:4}" = "2265" ]?did)
 ;檢查caller ID 是否已有設定,前4個數字若為 2265 則直接跳往 did 這個priority
 same => n,Set(CALLERID(num)=22650000) ;設定公司代表號
 same => n,Dial(SIP/中華電信/${EXTEN},35,XxWw)
 same => n(did),Dial(SIP/callout1/did${EXTEN},35,XxWw)
;轉到另一台專撥外線的機器callout1上去

;底下是另一台專撥外線的機器上callout1的設定
[callout]
exten => _didXXX.,1,Noop
 same => n,Dial(SIP/亞太電信/${EXTEN:3},60,XW) ;取掉前3個字,did的字樣

;;;;底下皆為test dial plan
exten => 7798,1,Noop(${CALLERID(num)})
 same => n,Noop(${CALLERID(num):1:5}) ;說明:1:5 從第1位數之後開始,保留5個數字,其餘全刪掉
 same => n,GotoIf($["${CALLERID(num):1:5}" = "2650" ]?ok)
 same => n,hangup
 same => n(ok),playback(beep)

說明:平常一般同仁是用公司的代表號,中華電信的線路撥出去的。一但設定了did號碼的話,就會走亞太電信的線路出去,並帶自己的Caller ID號碼出去

上面的範例是檢查 Caller ID 的前4碼是否為2265,若是則前綴帶did撥出去

範例二

底下範例則是要檢查另一個地方 CallerID name,這個設定範例比上一個精簡,也比較不容易出錯

sip.conf 裡的設定

[in](!)
type=friend
context=callout
host=dynamic
dtmfmode=rfc2833
canreinvite=yes
directmedia=yes
directrtpsetup=yes
qualify=yes

[4001](in) 
secret=4001
callerid= "didUser"
cid_number = 22650001
;在個人分機上即設定好did號碼,並將 CallerID name設為 "didUser"

[4002](in) 
secret=4002
callerid= "didUser"
cid_number = 22650002

說明:你可以在asterisk終端機畫面下這樣的指令 sip show peer 4001 就可以看到它顯示的caller id會是這樣的 Callerid : “didUser” <22650001>

extension.conf

[callin]
exten => 22650001,1,Dial(sip/4001,30,m)
exten => 22650002,1,Dial(sip/4002,30,m)
;既設了did號碼,那麼就要指定別人回撥時要送到哪個分機去

[callout]
exten => _XX.,1,Noop(${CALLERID(name)}) ;檢查CallerIDname是否為 didUser
 same => n,GotoIf($["${CALLERID(name)}" = "didUser" ]?did)
 ;檢查CALLERID(name)是否設為 didUser,若有 則直接跳往 did 這個priority
 same => n,Set(CALLERID(num)=22650000) ;設定公司代表號
 same => n,Dial(SIP/中華電信/${EXTEN},35,XxWw)
 same => n(did),Dial(SIP/亞太電信/${EXTEN},35,XxWw)
 ;說明:若分機已有設定didUser的話,則會略過 "設定公司代表號" 這個步驟,直接撥外線了,為何不需要設caller id 號碼呢? 因為我們在個人分機那兒已經設定過了。
]]>
https://blog.vic.mh4u.org/2014/1425/feed 4
GotoIfTime指令 https://blog.vic.mh4u.org/2014/1411 https://blog.vic.mh4u.org/2014/1411#respond Fri, 24 Oct 2014 13:56:36 +0000 http://blog.vic.mh4u.org/?p=1411 閱讀全文 ]]> asterisk 裡有一個很好用的指令,可針對不同的時間做不同的事,可惜說明文件裡範例不多…

所以只能靠自己來摸索了。

範例1

底下是常用範例,下班時間撥放”我們下班了”的語音提示,其餘時間則撥放正常的IVR

[callIN]
exten => s,1,Playback(silence/1)
  ;這是播放語音提示前的標準動作,可避免最初的幾毫秒提示音被忽略。
  ;GotoIfTime 語法 (時間,星期,日,月?要跳到的context,分機,priority順序)
  ;GotoIfTime 語法 上面的時段,若是全時段的話,可用*星號代替
  same => n,GotoIfTime(17:00-08:59,mon-fri,*,*?callIN,s,offtime)
  ;撥放現在是下班時間提醒,上班時間 09:00-17:00 週一至五 除此之外都是下班時間
  same => n,GotoIfTime(*,sat-sun,*,*?callIN,s,offtime)        ;六日休 
  same => n,GotoIfTime(*,*,10,oct?callIN,s,offtime)           ;雙十節
  ;same => n,GotoIfTime(*,*,25,dec?callIN,s,offtime)          ;12/25
  same => n,GotoIfTime(*,*,1,jan?callIN,s,offtime)            ;1/1元旦
  same => n,Background(IVR)
  ;撥放IVR:XX公司您好,請直撥分機號碼....
  same => n,WaitExten(20)
  ;20秒等待輸入分機號,時間一到,自動跳總機
  same => n,Goto(0,1)   ;自動跳總機
  same => n(offtime),Background(offtime)
  ;撥放offtime IVR:XX公司您好!現在是下班時間 , 請直撥分機或於上班時間再來電...
  ;說明,這裡的priority順序很特別,我們採用了 priority命名的方式,所以你會看到 n(offtime) 這樣的寫法
  same => n,WaitExten(15)
  same => n,Background(custom/tks4call) ;謝謝您的來電
  same => n,Hangup()
;規則說明: 1接聽電話 2語音宣告 3等待分機輸入若15秒後沒有輸入任何分機則進行下一動 4掛斷

範例2

下班時間則不讓員工撥打手機電話了

[callOut]
exten => _09XXXXXXXX,1,Set(VOLUME(RX)=5)
 ;GotoIfTime 語法 (時間,星期,日,月?要跳到的context,分機,priority順序)
 same => n,GotoIfTime(18:00-07:59,*,*,*?callOut,${EXTEN},5)
 ;時段限定,18點至早上8點前都不能打電話了
 same => n,Dial(SIP/gateway1/${EXTEN},60)
 same => 4,Hangup
 same => n,Playback(offtime-setting)
 ;撥放語音提示:現在是下班時間,你不能打電話了
 same => n,Hangup

這個範例與前面不同的是,分機採用了變數 ${EXTEN} 可以比較靈活。而priority順序卻是寫死的,寫成5,這樣的寫法比較不好,不夠靈活。因為萬一我們要修改什麼,加入或刪除一行的話,那整個priority的順序就都不一樣了,所以請參考上一個範例,使用priority命名的方式來寫會比較。

]]>
https://blog.vic.mh4u.org/2014/1411/feed 0
Call Park https://blog.vic.mh4u.org/2014/960 https://blog.vic.mh4u.org/2014/960#respond Tue, 22 Jul 2014 08:54:26 +0000 http://blog.vic.mh4u.org/?p=960 閱讀全文 ]]> asterisk 有一個功能叫 Call park 中文翻譯沒有一個統一的名稱,有叫電話停泊、有叫電話駐留的….
這個功能挺好用的,但台灣人用的少,國外的人用的多,習慣問題吧。

先簡單的說明一下此功能的應用時機和使用方法:
比如說,當我接到一通電話時,要請對方稍待幾秒鐘,或者是要將此通電話轉給別人接聽,傳統的做法是按Hold(保留通話),或者是按Tran(轉接電話)。而 Call Park具有以上兩種特性。與傳統的Hold和Tran比較起來功能強多了,它可以Hold不只一線,然後由別的分機接起來。減少Tran失敗的機率,萬一對方一直沒有接起來或沒人應答,電話會再響回來。

下文將 Call Park 翻譯成停車場,便於理解它的用途。

Call Park使用方法:
當我接到一通電話時,需要請對方稍待一下,我按 Tran 之後再按700就將對方轉到停車場(Call Park)裡去了,這時會聽到一個語音報號701(記住這個車位號碼,一會兒取車時需要這個號碼,下回不一定報這個號)。然後呢,我可以做什麼呢?
1.我可以查一下對方所要的資料,晚點再接起這通電話,若是不小心查的太久忘了對方還在停車場裡,時間到了(預設45秒,可改)我的分機還會再響一次,接起來直接就是和對方通話。
2.或者是我可以到2F的會議室裡去接聽這隻電話,那裡比較沒人。因此我只要到2F會議室那隻分機旁,再撥701分機就可以接起這通電話。或其它任何有分機的地方,直撥701就可接起這通電話。
3.或者是我可以將這通電話轉給別人,打電話給我的同事,告訴他,701分機有電話找你,請你接一下。

要啟用此功能也不難,主要修改有兩個設定檔 features.conf 和 extensions.conf

先說比較簡單的 extensions.conf 你只要在你公司內部分機所在的區段(context)加上底下內容即可

include => parkedcalls
;啟用call park 功能

再來說 features.conf 此檔,所有 call park 要細調的功能都在此檔內

[general]
parkext => 700		;停車場
parkpos => 701-720	;停車位的號碼
context => parkedcalls	;請保留預設值不要改,若改的話,會造成直撥701分機無法接起通話,得另外編dialplan
;parkinghints = no		;與BLF燈號有關,預設值是no,不用特別修改此參數。
parkingtime => 180		;停車場停留時間,預設是45秒。超過時間它會回call將它送進停車場的人。
comebacktoorigin = yes	;超過停留時間回撥是否響鈴(我不確定的翻譯)
findslot => next			;找尋空的停車位的方式,預設值是'first' 第一個空的停車位。

[featuremap]
parkcall => #72		; 精簡通話進停車場步驟,直接按#72就能把通話轉入停車場,此功能必須配合 Dial 撥號指令加入參數K或k才行。

這樣你就可以使用Call Park功能了。

[note]
參考文獻:call parking介紹ParkedCall指令ParkAndAnnounce指令
[/note]

]]>
https://blog.vic.mh4u.org/2014/960/feed 0
asterisk BLF https://blog.vic.mh4u.org/2014/1363 https://blog.vic.mh4u.org/2014/1363#respond Mon, 21 Jul 2014 12:55:29 +0000 http://blog.vic.mh4u.org/?p=1363 閱讀全文 ]]>
BLF = Busy Lamp Field
有些較高級的話機,如總機小姐專用的那種話機,上面有許多的燈號,那些燈號可以監視其它話機的通話狀態,英文簡稱BLF,所以asterisk若要使用這種功能的話,首先得要你的話機能夠支援BLF功能才行,底下示範使用 yealink T28 這隻話機來設定 BLF。

vim /etc/asterisk/sip.conf

[general]
;底下是開啟BLF功能
subscribecontext=BLF
allowsubscribe=yes
notifyringing=yes
notifyhold=yes
notifycid=yes
;以上是開啟BLF功能

;另外還要在每一個分機設定 call-limit=2 或任何大於1的數字,這是關鍵!
;範例:
[internal](!)
type=friend
context=outbound
deny=0.0.0.0/0
permit=192.168.0.0/16
host=dynamic
dtmfmode=rfc2833
canreinvite=yes
directmedia=yes
directrtpsetup=yes
qualify=yes
nat=no
disallow=all
allow = ulaw,alaw,g729,g723,gsm
call-limit=2
;要注意,若有分機咬線掛不斷時,也不要隨意增加這個 cll-limit 的數字,而應當找出問題來
;若只是單純的增加limit數字,問題還存在,不處理的話日後問題會更嚴重
;應急解法:可在 asterisk console端下指令 core show channels 來觀察咬線頻道
;再用此指令 hangup request ? 來自動補足後面的參數,即可掛斷該頻道


[2168](internal)
secert=1234

[2169](internal)
secert=1234

[2170](internal)
secert=1234

vim /etc/asterisk/extensions.conf

[BLF]
exten => 2168,hint,SIP/2168
exten => 2169,hint,SIP/2169
exten => 2170,hint,SIP/2170
;若是想要監視call park停車位是否被佔用,可按底下格式設定
exten => 701,hint,park:701@parkedcalls
exten => 702,hint,park:702@parkedcalls
exten => 703,hint,park:703@parkedcalls

設定好之後,reload astrerisk 設定檔,然後你就可以在 asterisk console 畫面裡執行底下的執行來觀察分機狀態

core show hints

此時你一邊打電話給你要監看的分機,一邊執行上面那行指令來觀察分機狀態是否有改變,若沒有改變的話,請重新檢查一次前面的設定是否有誤,若分機狀態有改變的話,說明你設定成功了,接下來我們接設定 t28 這隻分機的 BLF 燈號

分機狀態大概有這幾種 unavailable, in-use, busy, ringing,依據響鈴、通話中、忙線中…等等不同狀態會有不同的燈號,其實也沒多少燈號,依據 yealink t28 原廠說明書大概就4種燈號
恆亮綠燈:所監視的分機處於閒置狀態
閃紅燈:所監視的分機有電話進來
恆亮紅燈:所監視的分機處於通話中狀態
熄燈:分機不在線

參照下圖設定
t28

特別說明:上圖右方 Extension 這個欄位,依不同的韌內版本功能也有所不同,Firmware Version 2.72.0.30 時,此欄位為截答功能,請參考此頁來設定截答功能,此欄位我們雖填了 *8 但是按下BLF鍵時卻會送出 *82168 這樣的撥號,而舊版的韌體則會直接送出*8這樣的撥號。

另外這裡提到了,當我們所監視的分機呈離線狀態時,BLF燈號卻不會熄掉,仍呈現恆亮綠燈。簡單說,目前無解。較完整的說法是,Subscription 的定義不同。

[note]
參考資料:voip-infoExpressInterconnect
[/note]

]]>
https://blog.vic.mh4u.org/2014/1363/feed 0
asterisk原始碼安裝 https://blog.vic.mh4u.org/2014/1228 https://blog.vic.mh4u.org/2014/1228#respond Thu, 12 Jun 2014 07:07:24 +0000 http://blog.vic.mh4u.org/?p=1228 閱讀全文 ]]> 安裝參考資料

安裝必備套件

安裝過程會問你輸入國家代碼,台灣請輸入886
apt-get build-dep asterisk
aptitude install ncurses-dev libxml2 libxml2-dev libsqlite3-dev subversion

下載原始碼

底下請挑一個你需要的版本下載來編譯安裝

wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-11-current.tar.gz
tar zxvf asterisk-11-current.tar.gz

wget http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-14.6.0.tar.gz
tar zxvf asterisk-14.6.0.tar.gz
cd asterisk-14.6.0

註:若你是使用asterisk13版本,則還需要另外安裝底下這兩個包
aptitude install uuid-dev libjansson-dev

編譯指令

./configure
抓 mp3 套件
apt install subversion
contrib/scripts/get_mp3_source.sh
make menuselect 
#若要增加額外功能,如SRTP(預設已有)和fax就要下此指令選擇相關模組
#fax模組分別在Applications裡的app_fax選了之後這裡就要做一次save&exit的動作,然後到 Resource Modules裡的res_fax、res_fax_spandsp選了這兩個之後,還要再做一次save&exit的動作才行。
#後來發現Applications裡的fax功能和Resource裡的fax功能好象是相衝突的,選了一個,另一個就會被自動的取消。
make 
make install
安裝範例設定檔(若此動作不做的話 /etc/asterisk 底下會空白)
make samples
若要(此動作可省略)安裝說明文件(413MB),請下指令 (需要另外安裝套件 aptitude install doxygen)
make progdocs
增加 opus codecs
cd /usr/local/src 
sudo wget http://downloads.digium.com/pub/telephony/codec_opus/asterisk-14.0/x86-64/codec_opus-14.0_1.1.0-x86_64.tar.gz 
sudo tar zvxf codec_opus-14.0_1.1.0-x86_64.tar.gz 
cd /usr/local/src/codec_opus-14.0_1.1.0-x86_64 
sudo cp -a *.so /usr/lib/asterisk/modules/ 
sudo cp -a codec_opus_config-en_US.xml /var/lib/asterisk/documentation/thirdparty 

vim /etc/asterisk/codecs.conf
加入 
[opus] 
type = opus"

asterisk -rx 'reload' 
asterisk -rx 'core show translation' 

設定開機啟動

=================笨方法=====================
vim /etc/init.d/asterisk.sh
#!/bin/bash
/usr/sbin/asterisk
update-rc.d asterisk.sh defaults
=================笨方法=====================

=================推薦方法======================
設開機自動執行
cp contrib/init.d/etc_default_asterisk /etc/default/asterisk
cp contrib/init.d/rc.debian.asterisk /etc/init.d/asterisk
vim /etc/init.d/asterisk

找到底下內容
DAEMON=__ASTERISK_SBIN_DIR__/asterisk
ASTVARRUNDIR=__ASTERISK_VARRUN_DIR__
ASTETCDIR=__ASTERISK_ETC_DIR__
修改底下內容 (填入正確路徑)
DAEMON=/usr/sbin/asterisk
ASTVARRUNDIR=/var/run/asterisk
ASTETCDIR=/etc/asterisk

update-rc.d asterisk start 99 2 3 4 5 . stop 01 0 1 6 .

debian8的啟動方式不太一樣了
update-rc.d asterisk defaults
or
update-rc.d asterisk enable 2 3 4 5
=================推薦方法======================

註:這裡的內容是debian剛使用了新的啟動方式時有一些不穩定的狀況,需要自己手動排除這些問題,現在比較穩定了,就比較沒有這些問題了,因此這部份的內容僅留作舊資料參考用。
說明:由於 update-rc.d 新版本的參數下法有些不太一樣,所以上面的指令在新版的 update-rc.d就不適用了。
update-rc.d 新版指令:
update-rc.d -n asterisk defaults 90 01
update-rc.d asterisk defaults 90 01
乾跑,可先測試結果,結果ok的話拿掉 -n 這個參數再執行一次

但由於 update-rc.d 此版本仍不是個穩定版,仍有許多問題,所以可能按上述的指令執行仍會遇到無效的情況。

上述的指令無效只好手動,底下是手動設定的指令
cd /etc/rc0.d
ln -s ../init.d/asterisk K01asterisk
cd ../rc6.d
ln -s ../init.d/asterisk K01asterisk
cd ../rcS.d
ln -s ../init.d/asterisk S90asterisk
cd ../rc2.d/
ln -s ../init.d/asterisk S90asterisk
cd ../rc3.d/
ln -s ../init.d/asterisk S90asterisk
cd ../rc4.d/
ln -s ../init.d/asterisk S90asterisk
cd ../rc5.d/
ln -s ../init.d/asterisk S90asterisk




建帳號給asterisk用

useradd -U asterisk -r -c "Asterisk PBX daemon" -d /var/lib/asterisk -s /bin/false
chown -R asterisk.asterisk /var/lib/asterisk 
chown -R asterisk.asterisk /var/spool/asterisk
chown -R asterisk.asterisk /var/run/asterisk
chown -R asterisk.asterisk /usr/lib/asterisk
chown -R asterisk.asterisk /var/log/asterisk
chown -R asterisk.asterisk /etc/asterisk

若啟動失敗時,要記得檢查
vim /etc/default/asterisk
AST_USER="asterisk"
AST_GROUP="asterisk"
上面這兩行是否被註解掉

再看這兒的權限
ls -al /var/run/asterisk


logrotate 設定

vim /etc/logrotate.d/asterisk-cdr
貼上底下內容,底下內容範例有兩個,擇一用之

======================範例1================================
/var/log/asterisk/cdr-csv/Master.csv {
weekly
missingok
rotate 52
create 0640 asterisk asterisk
postrotate
/usr/sbin/asterisk -rx 'logger reload' > /dev/null 2> /dev/null
endscript
}
======================範例1================================
======================範例2================================
var/log/asterisk/cdr-csv/Master.csv {
weekly
missingok
rotate 52
create 0640 asterisk asterisk
size 102400k
copytruncate
postrotate
endscript
}
#102400K=100MB 意指log大到100MB時才會輪替
======================範例2================================
#weekly 指定轉儲周期為每周
#missingok 表示如果找不到log文件也沒OK
#rotate 52
#prerotate/endscript 在轉儲以前需要執行的命令可以放入這個對,這兩個關鍵字必須單獨成行
#postrotate/endscript 在轉儲以後需要執行的命令可以放入這個對,這兩個關鍵字必須單獨成行

CDR內的時間問題修正

由於我們linux系統所使用的時間是北京時間,在查CDR時卻發現了它所記錄的時間與我們系統上的時間差了8小時.後來才發現調整的方法:
vim /etc/asterisk/cdr.conf

[csv]
;usegmtime=yes    ; log date/time in GMT.  Default is "no"
;將上面那一行給註解掉,也就是我們不要使用gmt時間,這樣CDR的時間就會準確了。

asterisk設定檔在vim內語法高亮

檔案位於原始碼內
asterisk-10.7.0/contrib/editors/

vim /usr/share/vim/vim72/filetype.vim
在最後加上底下內容
” Asterisk config file
au BufNewFile,BufRead *asterisk*/*voicemail.conf* setf asterisk_voicemail
au BufNewFile,BufRead *asterisk/*.conf* setf asterisk
au BufNewFile,BufRead *asterisk/*.ael* setf asterisk

基本上它會將位於 /etc/asterisk 此目錄底下所有的 .conf 檔 都當成是 “asterisk” type 來做語法高亮.
You could make it more specific and this will naturally just pickup the .conf files in certain directories, but I found it more convenient than anything else.

參考資料:voipvim語法高亮

如果不知道配置文件及脚本的位置,可以在vim中使用命令 :scriptnames ,将显示如下路径
/etc/vimrc
/usr/share/vim/vim72/syntax/syntax.vim
/usr/share/vim/vim72/syntax/synload.vim
/usr/share/vim/vim72/syntax/syncolor.vim
/usr/share/vim/vim72/filetype.vim
/usr/share/vim/vim72/ftplugin.vim
/home/kdj/.vimrc

如果不知道vim配置文件的搜索位置,请输入 :version ,将显示
系统vimrc文件:”/etc/vimrc”
用户vimrc文件:”$HOME/.vimrc”
用户exrc文件:”$HOME/.exrc”
$VIM预设值:”/usr/share/vim”


asterisk 移除方法

參考資料

killall -9 safe_asterisk
killall -9 asterisk
rm -rf /etc/asterisk
rm -f /etc/zaptel.conf
rm -rf /var/log/asterisk
rm -rf /var/lib/asterisk
rm -rf /var/spool/asterisk
rm -rf /usr/lib/asterisk


bug 修正

In main/utils.c there is a line (1126) that reads like this –

ast_log(LOG_ERROR, “write() returned error: %s\n”, strerror(errno));

change ERROR to NOTICE – 修改錯誤等級

ast_log(LOG_NOTICE, “write() returned error: %s\n”, strerror(errno));

and do make && make install. This will remove this message.

]]>
https://blog.vic.mh4u.org/2014/1228/feed 0
asterisk fax https://blog.vic.mh4u.org/2014/1189 https://blog.vic.mh4u.org/2014/1189#respond Thu, 29 May 2014 03:03:01 +0000 http://blog.vic.mh4u.org/?p=1189 閱讀全文 ]]> asterisk 10 版以後內建支援 T.38 協定傳真,只要你的 voip gateway 有支援 T.38 格式, asterisk 就可直接收傳真。

首先說明 voip gateway 設定的部份,請參考下圖
底下的voip gateway 是偉僑 WellGate 2680

voip fax 設定

voip gateway fax 設定

voip fax 設定

G7.11設定請選 u-law

底下是另一台voip gateway 訊詠科技 IXP_SP1700,傳真的部份基本上是保持預設值沒有更改
sp1700

接著說明 asterisk 設定的部份

/etc/asterisk/sip.conf

[general]
;fax WellGate 2680 傎真設定方式
;t38pt_udptl=yes
;faxdetect=yes
;訊詠科技 IXP_SP1700 傎真設定方式
t38pt_udptl=yes,redundancy
faxdetect=t38

這裡有提到, FAX detect 是給類比訊號使用的,不是給 T.38使用的,T.38 使用faxdetect=yes 此參數的話,會搞亂它的訊號。

/etc/asterisk/extensions.conf

;傳真接收測試
;exten => 02999996,1,Answer()
;  same => n,Wait(1)
;  same => n,ReceiveFax(/tmp/faxtest.tiff)
;底下是將接收的檔案使用變數檔名來儲存
exten => 02999996,1,Answer()
  same => n,Wait(1)
  same => n,ReceiveFax(/tmp/fax-${STRFTIME(${EPOCH},,%F-%H時%M分%S秒)}_${CALLERID(number)}.tiff)

上面使用變數的檔名存檔後的長這樣
fax-2014-07-18-16時12分31秒_922691556.tiff

說明: 02999996 是 hotline 分機,也可是設定為 DID 號碼 (據說DID是虛擬號碼,有可能使用DID無法正常接收傳真,得測試過才知道)

這樣設定之後,雖然可以正常的收到傳真檔案,但在asterisk後台會看到這樣的錯誤訊息:
chan_sip.c:9809 process_sdp_o: Call 80c13800-fb06a8c0-2390-45026-cb-2a60ab06-cb responded to our T.38 reinvite without changing SDP version; ‘ignoresdpversion’ should be set for this peer.

解決方法,可在 sip.conf 裡的那條線路裡設定底下參數
[myfax-peer]
ignoresdpversion=yes

[note]
參考資料:voip-info:asterisk faxasterisk wiki如何設定fax debugt.30與t.38的區別T.38協定規範、[/note]

專有名詞說明:
T.30:是傳真在PSTN上的協定。
軟件像傳真交換協議一樣是面向傳真應用的。它可以建立和控制兩個傳真調制解調器之間的通信。一共會涉及5個階段:呼叫建立,信息預處理程序(選擇通信方式),信息傳輸(包括相位同步),發布信息程序和呼叫釋放.

T.30E:簡單說就是T.30彩色版。asterisk並不支援T.30E協定。
軟件執行連續色調彩色圖像文件傳真發送的G3傳真步驟。利用T.30E,可以在通用電話交換網和其他網絡中高效率的傳輸高質量,全彩色和灰度圖像.

T38:是傳真PSTN 到IP中繼的協定

]]>
https://blog.vic.mh4u.org/2014/1189/feed 0
bash更改行列順序 https://blog.vic.mh4u.org/2013/1110 https://blog.vic.mh4u.org/2013/1110#respond Wed, 16 Oct 2013 07:41:10 +0000 http://blog.vic.mh4u.org/?p=1110 閱讀全文 ]]> 目地:由於修改asterisk設定檔內的路由順序的次數很頻繁,因此就寫了一個小程式來協助完成此工作

asterisk 的設定檔如下:

[outbound-route]
exten => s,1,Noop()
;設定動態功能鍵 Set(DYNAMIC_FEATURES=vicGroup)
exten => s,n,set(_MainRoomNum=${CALLERID(number)})
  same => n,Gosub(設定來電顯示,cell${RAND(4,9)},1)
  same => n,Dial(SIP/路由1/235${x},32,gCX)
  same => n,Dial(SIP/路由2/7852${x},32,gCX)
  same => n,Dial(SIP/路由3/9957${x},32,gCX)
  same => n,Dial(SIP/路由4/9967${x},32,gCX)
  same => n,Dial(SIP/路由5/9867${x},32,gCX)
  same => n,Return

希望透過使用者按簡單的數字來改變路由順序,而不改動到其它的字。
比如說:當我按下3之後,內容會變成這樣,路由3跑到第1行去了,其它行則不動。

[outbound-route]
exten => s,1,Noop()
;設定動態功能鍵 Set(DYNAMIC_FEATURES=vicGroup)
exten => s,n,set(_MainRoomNum=${CALLERID(number)})
  same => n,Gosub(設定來電顯示,cell${RAND(4,9)},1)
  same => n,Dial(SIP/路由3/9957${x},32,gCX)
  same => n,Dial(SIP/路由1/235${x},32,gCX)
  same => n,Dial(SIP/路由2/7852${x},32,gCX)
  same => n,Dial(SIP/路由4/9967${x},32,gCX)
  same => n,Dial(SIP/路由5/9867${x},32,gCX)
  same => n,Return

需注意的是,此設定檔內有許多特殊符號,如大於、等號、空格…等,因此會使得變數在處理上變得很麻煩、困難重重。

針對以上需求,寫出了兩個版本的shell script。

第1個版本,使用sed本身強大的功能,透過一些複雜的參數,實現了兩行資料直接對換的功能。此版本得以實現是完全參照此頁所寫出來的。

#!/bin/bash
file="outbound.conf"
old=$IFS
IFS=' '
#此行將檔案內容存入變數
content=$(cat $file)
#計算有 Dial 這樣的字串有幾行
length=$(echo $content | grep -o 'Dial' | wc -l)
#計算 Dial 這樣的字串 第一次出現時是位於第幾行
mainroute=$(echo $content | grep -n 'Dial' | head -n1 | cut -d ':' -f1)
headlength=$(( $mainroute -1 ))
IFS=$old
#echo $length

echo "目前路由順序如下:"
echo "$content" |grep Dial |nl
#grep Dial $file|nl -v0
echo "  參照上方的路由表輸入你要設定主要路由的號碼"
read -p "  請輸入數字(1,2,3,4...):" num

echo ""
if [ "$mainroute" -eq "$(($num+$headlength))" ]; then
echo "已經是主要路由了"
exit 0
fi
echo " "
echo "底下是修改後的路由表"
#sed -n "$mainroute! {p;d};:1;$(($num+$headlength-1))! {N;b1};h;n;p;g;p" $file
sed -ni "$mainroute! {p;d};:1;$(($num+$headlength-1))! {N;b1};h;n;p;g;p" $file
grep Dial $file|nl

/usr/sbin/asterisk -r -x "reload"
echo "路由變更完成"


#line=3
#cat bound.conf  | sed -n "6! {p;d};:1;$(($line+5-1))! {N;b1};h;n;p;g;p"
#說明:  此指令為兩行資料互相對調, 6!  代表你要修改的那一行  $line 代表另一行

第2個版本,主要使用陣列,加上簡單的sed功能實現:

#!/bin/bash
IFS=$'\n'
#由於我們所使用的變數內容內含空格 如:same => n,Dial(SIP/路由/5131${x},32,gCX)
#這樣在我們將此變數塞入陣列時容易出錯,因為空格的關係,此變數會被塞進3個陣列元素之中
#所以我們要更改 IFS 預設的分隔符號為換行符號 $'\n\ 這樣它才能將整行(內含空格)的變數塞入同一個陣列元素之中
#IFS 中的第一個預設字符來作為每個位置參數之間的分隔符號,而這個預設字符通常為空白字元
#參考資料:http://www.suse.url.tw/sles10/lesson10.htm

#定義變數
file1=./outbound.conf
#此行將檔案內容存入變數
content=$(cat $file1)
last=(`tail -n1 $file1`)
#計算 Dial 這樣的字串 第一次出現時是位於第幾行
#mainroute=$(cat $file1 | grep -n 'Dial' | head -n1 | cut -d ':' -f1)

echo "目前路由順序如下:"
echo "$content" | grep Dial |nl -v0

#宣告陣列 route1,並將路由分別資料存入陣列之中
declare -a route1=(`echo "$content" | grep Dial`)
declare -a route2
read -p "請輸入數字(1,2,3...):" keyin
#將使用者所選的路由存到陣列 route2 裡的第0個元素去
route2[0]=${route1[$keyin]}
#將陣列 route1 裡的資料分別存入 陣列 route2
#特別注意的是 route2[0] 裡面的資料剛剛已經存入了使用者所選擇的路由,所以要從 route2[1]開始存放
#即按 route1[0]=route2[1]  這樣的方式存入
#而陣列 route1[*] 裡的資料又不能全存入,得剔掉使用者所選的那個路由,是變數 $keyin
for (( i=0; i<=${#route1[@]}-1; i=i+1 ))
do
      if [ $i != $keyin ]; then route2[$i+1]=${route1[$i]}
      fi
done
#echo print array 所有內容
#echo  "${route2[*]}"
#echo 計算 array 總數
#echo  "${#route2[@]}"
#echo print 陣列元素 2
#echo "${route2[2]}"

#刪除從 Dial 這行開始後面的所有資料
sed -i '/Dial/,$d' $file1 
#底下是使用另一種刪除法,從主要路由哪一行開始,刪除後面所有資料
#sed -i ''$mainroute',$d' $file1
#sed 注意事項: 若要在 sed 內使用變數,請在變數左右加單引號

#開始注入新的路由資料,即 route2[*] 的內容倒回原設定檔內
for item in ${route2[*]}
  do
  echo $item >> $file1
done
#注入最後一行資料
echo $last >> $file1
#顯示修改結果
echo ""
echo "路由更新結果如下:"
grep Dial $file1 |nl -v0
/usr/sbin/asterisk -r -x "reload"
echo "路由變更完成"

程式設計的思惟:
第1步將路由資料存入陣列route1之中
第2步讓使用者選擇某一個路由,再將使用者所選的路由存入陣列route2的第0個元素之中。
第3步將route1陣列裡的資料,存入route2陣列中
第4步刪除原設定檔內的路由資料,開始注入route2的內容
第5步reload asterisk

此程式最困難的地方在於變數的處理,由於路由資料那一行內含有一些特殊符號,使得路由資料轉為變數存入陣列時有很多問題要克服,而好不容易存入陣列中了,要讀出來的時候,所有的陣列元素全部變成只有一行輸出,而不是我想要的一個路由資料就是一行,因此在解決這些問題上面花了不少時間,這也才明白了 bash 對於程式的語法要求是很嚴格的,差一點都不行的。

]]>
https://blog.vic.mh4u.org/2013/1110/feed 0