淺談OpenSER(收錄自Sam's linux study)淺談OpenSER(一)VoIP這種應用已經常識了很多年,卻似乎一直沒有太大的成果,當然這涉及到很多的問題,不過以SIP為基礎的原則也越來越確定(好啦,我知道妳用 Skype)。很多人對於VoIP總是感覺像是高不可攀的技術,但其實它並不如此的困難,尤其是有了自由軟體世界的努力,很多Project都可以讓妳輕 鬆的完成你的VoIP規劃。當然VoIP是一個很廣泛的稱乎,舉凡用網路即時傳遞交換語音訊號其實都可以稱為Voice over Internet,但是VoIP還必須要涉入一些電信的領域,也就是signaling的動作。 就如同PSTN一般,VoIP也需要一個傳遞訊號的機制來建立通訊的兩端,SIP便負責了這件工作。一個SIP的register server可以讓妳每一個SIP client來交換訊息,當你要打電話給另一個朋友,在網路上妳必須要能先找到他,也就是對方的網路位置,但是當你的網路位置會改變的時候,一個可以記錄 你的網路位置的SIP register server便可以發揮功能。妳可以從在自由軟體裏面的OpenSER這個project可以幫 妳架構一個SIP server,當然OpenSER可以做到的更多,這邊我們先簡單的介紹一下吧。OpenSER是一個以C寫成的project,他可以處理SIP message,主要依據一個設定檔來決定OpenSER如何反映接收到的SIP message,這邊說設定檔其實不太正確,因為這個設定檔(openser.cfg)雖然是一個純文字檔,但其實它是個lex與yacc的輸入格式,在 OpenSER的source裏面妳可以找到cfg.lex與cfg.y這兩個lex與yacc的source,因此他也不是一個shell script,而是一個必須符合OpenSER的token rule的文字檔。OpenSER大量使用dlopen來動態載入模組,因此他可以由openser.cfg決定要載入的模組或甚至加上妳自己寫的模組。首 先讓我們來安裝OpenSER吧,妳可以由http://www.openser.org/來下載openser的source來安裝,寫這篇文章的時候 OpenSER剛剛釋出1.1.1版本,妳可以去抓最新的source。解開tar ball後進去source的目錄妳會發現裏面沒有configure,不過不太需要擔心,因為OpenSER相依的library不多。基本上make all;make install可以幫妳完成大多數的工作,但是如果妳希望安裝的目錄不是/usr/local/的話,妳必須告訴make你的安裝根目錄,譬如make prefix=/ allmake prefix=/ install記 得make all的時候也要將路徑指定,因為這個路徑會直接coding進去binary成為預設路徑。剛剛提過OpenSER大多數的功能都模組化了,因此決定妳 要使用的模組比較有意義,妳可以參考INSTALL檔案裏面的說明會告訴妳如何指定要編譯的模組。不過我的作法是直接修改Makefile,妳可以找到 "exclude_modules?=................."這行這行指定了妳不要的模組,因此如果有妳需要的模組,就將他從這行移除就 是。不過要注意的是因為沒有configure去幫妳check dependency,所以有需要的library要自己先裝上,例如radius模組需要radiusclient-ng。當你需要用radius來當 成你的認證方式時,必須確保你的相關library與程式存在,然後進到acc模組目錄("source"/modules/acc),妳可以看看 Makefile裏面,原本預設的帳號管理是用MySQL資料庫儲存account資料,要使用radius請更改相關的設定,例如DEFS+=DRAD_ACCLIBS=-lradiusclient-ng這邊我的radiusclient-ng是裝在系統目錄下,所以我沒有指定library path,如果妳裝在別處,請指定library path。這樣妳就可以很簡單的將OpenSER安裝到你的系統上去了,接下來只要設定好你的OpenSER的設定行為,也就是修改openser.cfg這個檔案,我們留到下次再說吧.......打字累了.....ㄏㄏ淺談OpenSER(二)如果妳打開openser.cfg這個檔案,第1眼印象妳可能會以為它是一個script檔案,其實這樣說也沒有不對,但是之前說過這個script其實是lex的輸入文檔,因此妳必須滿足它的字彙規則,讓我們先簡單看一下這個檔案。這個設定OpenSER的動作檔案簡單可以分成4個部份,分別如下1. Global的參數設定2. 選擇模組載入3. 相關模組參數設定4. routing規則基 本上了解這個設定檔妳便可以讓OpenSER照你希望的方式去運作,首先在全域參數的部份妳可以設定一些整個程式的執行模式與相關環境設定,例如妳可以用 debug=3來決定執行時的debug level,這如同妳直接在command line下面執行openser給的參數-dddddd來決定debug level(跟asterisk一樣是吧) ,其他還有listen port的設定(預設是SIP的標準port 5060)。OpenSER使用一個fifo來接受外部給它的指令動作,因此妳可以指定這個named fifo的位置如下fifo="/tmp/openser_fifo" 如果妳要用MySQL,妳也必須在這裡指定連接資料庫的相關資訊fifo_db_url="mysql://user:passwd@host/dbname"自己替換掉相關的部份(user: 資料庫帳號,passwd: 密碼,host: 資料庫位置,dbname: 資料庫名稱),就可以利用OpenSER的資料庫模組把相關資料放在資料庫中,這裡是用MySQL為例,當然妳可以使用其他資料庫。第二個部份是決定妳要載入哪些模組,這邊比較單純,只要選定妳要的載入就可以,惟一要注意的是模組間的相依性就是,載入的方式很簡單loadmodule "//lib/openser/modules/mysql.so"上面就是載入MySQL的模組,妳可以自行看看你的模組目錄中有哪些模組可以載入(這根據妳如何選擇編譯OpenSER)。第三個部份來指定每一個模組的相關參數,方式很簡單modparam("usrloc", "db_url", "mysql://user:passwd@host/dbname")這 裡指定存放user位置的參數db_url,指定成MySQL的位置。每一個模組都有一些相關的參數可以設定,妳可以去OpenSER的官網看每一個模組 的說明文件,不然妳也可以自己去source下面看看,在原始檔的modules目錄下面每一個目錄都是一個模組,妳可以找尋一個struct名為 param_export_t的地方,通常如下static param_export_t mod_params[] = { {"param1", STR_PARAM, &p1}, {"param2", STR_PARAM, &p2}, {0,0,0}每一個模組有自己的相關參數妳可以在這邊找到,至於這些參數要做啥的,妳就要由相對映的變數(在上例中p1與p2)在原始碼中的作用去判斷,這樣會累死對吧....ㄏㄏ,沒關係,其實OpenSER的網站相關說明文件還挺清楚的。最後是routing規則的部份,這裡是主要OpenSER接收到SIP message的時候他如何去反應的動作,所有的message都會由route {................................開始,在裏面妳可以去安排所有反應。當然妳可以延伸其他規則如下route[1] {.................................route[2] {.................................在主要的規則裏面妳可以跳到其他規則去route {......其他處理或判斷......route(1);......其他處理或判斷......route(2);} 這樣妳就可以建構出一個自己的SIP message處理流程來架構你的VoIP server。 淺談OpenSER(三)在整個openser.cfg中最重要的大概就是你怎麼處理route裏面的規則,這裡給你做一個簡單的示範。通常一開始會先檢查SIP message是否是合法的,因此我們對SIP message的forward header與message長度作檢查。if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit;};if (msg:len >= 2048 ) { sl_send_reply("513", "Message too big"); exit;};這部份應該大家都一樣,單純的檢查SIP message。SIP是一個signalling的機制,每一個message都代表要做某一個動作,因此通常我們必須先判別每一次的SIP message所要求的method。is_method是一個讓我們判別的function,簡單的示範如下:if (is_method("REGISTER|INVITE|MESSAGE")) {......................你 可以去檢查每一次SIP message是否是你要處理的method,這個例子中我們對於REGISTER、INVITE、MESSAGE做出反應,當然你可以自行決定哪些 method是你要處理的(ACK、BYE、NOTIFY、PRACK.....)。因為OpenSER本身當作sip proxy的可能很大,因此你通常可以將所有除了REGISTER的method紀錄起來。if (!method=="REGISTER") record_route();有 些SIP message本身便會帶route set(例如reINVITE),因此你必須先處理這些route set,不過不用擔心,OpenSER只要使用loose_route便可以解決這個問題,loose_route會依據message中有無route set,若有則會回傳true,反之回傳false。因此我們可以用下面的方式處理if (loose_route()) {...................... route(1);這樣的處理可以直接在處理完後跳到你設定的route rule 1之處。如 果你的OpenSER也要當作sip register server用,你就必須處理REGISTER的message,處理方式也很簡單,判別是否為REGISTER的message然後驗證使用者之後利用 register module所提供的save(domain)來紀錄就可以完成。if (uri==myself) { if (method=="REGISTER") { if (!radius_www_authorize("votel-tech.com")) { www_challenge("votel-tech.com", "0"); xlog("L_INFO", "radius authorize failed\n"); exit; }; save("location"); exit; };.......................這 裡首先我們看到先判別SIP message裏面的URI是不是給我們這台server,如果不是就別忙了。然後判定method如果是REGISTER的話,開始認證使用者。在 OpenSER中可以把使用者資訊直接存在datebase中(例如MySQL),但是這樣的作法通常安全性較低,而且缺乏集中管理帳號的好處,因此我這 邊使用後端的RADIUS server當作認證方式,如果認證過只要使用save("localtion")便可以完成註冊的動作。在SIP message之中另一個最重要的method就是INVITE了,VoIP當然最重要的是能夠邀請別人溝通,因此處理INVITE的訊息也是一項重要工作if (method=="INVITE"){ if (uri=~"sip:0[0-9]+@.*") { if (!radius_www_authorize("votel-tech.com")) { www_challenge("votel-tech.com", "0"); sl_send_reply("400", "Only legal user can call out"); exit; }; if (!avp_check("$avp(group)", "eq/s:pstn/ig")) { sl_send_reply("400", "Not Allow to Call Out"); exit; }; strip(1); prefix("886"); route(2); exit; } else { if (!lookup("location")) { sl_send_reply("404", "Not Found"); exit; }; route(1); };當 我們遇到INVITE的訊息時,很多的VoIP系統會有所謂播打外線的動作,或許是連接到IP-PBX系統(例如asterisk),如果你希望能夠判別 這個,我們通常會在播號時加上前置碼以區別一般的invite與call out invite。在此例中我用了0當成前置碼,因此所有以0開始的SIP URI都會被我當成call out。這邊一個比較不一樣的是在這邊我再次作了一次認證的動作,這裡作認證的用意是很多公司都會希望能限制播打外線的功能,最簡單的作法是用族群來管 理,只允許某些族群的使用者可以call out,如果你不想設限,這裡可以拿掉。至於如何作族群屬性判斷呢,我的作法是在RADIUS server裏面設定一個group的屬性,利用屬性回傳來判斷使用者是哪一個group,據我所知openser的radius modules裏面有了group check的function可以使用,不過我沒有用過,請自行探索。設定了另一個route rule為2的規則讓call out使用,如果你的gateway的SIP URI有特殊格式,你也可以在route之前做好加減碼,例如用strip減碼而用prefix加碼。至於正常的sip call只要用lookup找到後便可以。大 致上一個OpenSER的設置檔並不複雜,重點逝去熟悉每一個module所提供的function。希望這幾篇簡單的說明能讓你大概了解OpenSER 的運作方式,網路上有很多的設置檔範例,多多嘗試後你會發現用OpenSER架設自己的SIP server一點也不複雜呢。 Original source: Sam's linux study.
- Dec 30 Fri 2011 03:06
-
淺談OpenSER(收錄自Sam's linux study)