• 沒有找到結果。

網路電話資訊統計及分析程式

N/A
N/A
Protected

Academic year: 2021

Share "網路電話資訊統計及分析程式"

Copied!
64
0
0

加載中.... (立即查看全文)

全文

(1)

逢 甲 大 學

資 訊 工 程 學 系 專 題 報 告

網路電話資訊統計及分析程式

學 生:呂佳翰 (四甲)

邱自強 (四甲)

蔡宗翰 (四甲)

指 導 教 授 : 李維聰

中華民國九十一年十二月

(2)

目錄

目錄...I 圖目錄...III 摘要...IV 第一章 導論...1 1.1 前言...1 1.2 目的與動機...1 第二章 VoIP相關技術簡介 ...3 2.1 VoIP簡介...3 2.2 H.323...4 2.2.1 H.323 相關元件...5 2.2.2 H.323 相關協定...7 2.3 MGCP...12 2.3.1 MGCP 主要元件...14 2.3.2 MGCP 傳送流程...15 2.4 SIP...17 第三章 系統架構...21 3.1 硬體環境...21 3.2 軟體環境...22 第四章 軟體架構...27 4.1 系統架構...27 4.2 自訂結構...28 4.3 資料表...28 4.4 相關常數...30 4.5 程式流程...30 第五章 結論...33

(3)

II 5.2 應用與展望...34 參考文獻...36 附錄A...37 A.1 Ethernet標頭 ...38 A.2 IP 標頭 ... ...39 A.3 TCP 標頭...39 A.4 TPKT 標頭 ...39 A.5 Q.931 標頭...40 附錄B...41 B.1 PCAP Manual...41 附錄C...46 C.1 h323pcap.h...46 C.2 main.c...48 C.3 buff.c... ..50 C.4 pcap.c...53

(4)

圖目錄

圖 2.1.1 一般 VOIP 網路架構...4 圖 2.2.1 H.323 系統架構...5 圖 2.2.2 H.323 Terminal 架購...6 圖 2.2.3 直接傳遞...9 圖 2.2.4 間接傳遞...9 圖 2 . 2 . 5 C a l l F l o w. . . 1 1 圖 2.3.1 MGCP 的架構...13 圖 2 . 3 . 2 舉 例 多 媒 體 閘 道 器 的 類 型 . . . 1 4 圖 2 . 3 . 3 M G C P 系 統 初 始 化 . . . 1 5 圖 2. 3. 4 E n d p o i n t 1 打 電 話 給 E n d p o i n t 2 . . . 1 6 圖 2. 3.5 Endpoint 2 接 起 Endpoint 1 打 來 的 電 話 ...16 圖 2. 3. 6 E n d p o i n t 1 與 E n d p o i n t 2 結 束 通 話 . . . 1 7 圖 2. 4. 1 S I P 支 援 五 種 多 媒 體 通 訊 的 建 立 與 終 結 . . . 1 7 圖 2.4.2 SIP 透過 Proxy Server 的運作方式...18

圖 2. 4. 3 SIP 透 過 R e d i r e c t S e r v e r 的 運 作 方 式 . . . 1 9 圖 2. 4. 4 SIP 連 線 之 建 立 . . . .. . . .. . . 1 9 圖 2. 4. 5 SIP 透 過 Proxy Server 所建立之連線 ... ...20

圖 3 . 1 . 1 網 路 連 結 圖 . . . 2 1 圖 3 . 1 . 2 P C 規 格 . . . 2 1 圖 3.2.1 socket pair...23 圖 3 . 2 . 2 N A T 例 子 . . . 2 4 圖 3 . 2 . 3 N A T 的 工 作 原 理 . . . 2 5 圖 3 . 2 . 3 / e t c / r c . d / r c . l o c a l . . . 2 5 圖 3 . 2 . 4 / e t c / s y s c t l . c o n f . . . 2 5 圖 4 . 1 . 1 系 統 架 構 . . . 2 7 圖 4 . 3 . 1 資 料 表 H 2 2 5 與 C O N N . . . 2 9 圖 4. 5 . 1 檢 查 是 否 有 完 整 的 T P K T 封 包 . . . 3 1 圖 4 . 5 . 2 擷 取 封 包 至 解 讀 H . 2 2 5 . . . 3 2

(5)

IV

摘要

第一章 導論

包含前言以及專題的動機與目的。 第二章 VoIP 相關技術簡介

簡介 VoIP 的背景,及 VoIP 相關的技術,如 H.323、MGCP、SIP。 第三章 系統架構 說明硬體環境及軟體環境。 第四章 軟體架構 說明程式流程。 第五章 結論 包括專題實作心得與未來展望。

(6)

第一章 導論

1.1 前言

綜觀目前市面上的各家電信業者皆提供了用戶使用通話明細,以 便使用者查詢,而該通話明細中提供包括了以下各種欄位:日期、撥 打對象、撥打時間、通話時間、對方號碼、該次通話應繳費用等。這 項服務不僅僅可以提供使用者查詢的服務,而業者則可在發現該名使 用者有不正常的使用情況時,早點給予該位使用者此類的通知,如超 長的通話中狀態、或者是非常巨額電信通話費,業者都可以在第一時 間通知給用戶知道。此外,該項服務也能提供給檢警雙方追蹤一些棘 手的刑事案件來追查特定目標的動向以及所在位置、聯絡對象等等。 當然因為這項服務可能會侵犯用戶之隱私權,所以業者也並不能擅自 未經過用戶同意,而提供該項資訊給其他不相關人士。 隨著現在網路技術的成熟,網路的功能不僅僅止於單純的資料上 的傳遞,而現在線上的即時功能也已有不錯的發展,且已可以即時地 傳遞語音以及影像。而由於這樣的環境,使得網際網路電話也漸漸地 隨之成熟茁壯,這不只是科技上的成長,更是全人體人類的福祉;我 們可以藉著透過網路的連線,便可以與遠在國外的分公司、客戶洽談 生意或者是與家人朋友作聯繫,而不用再擔心會為了負擔沉重的長途 或國際電話費而被壓的喘不過氣。

1.2 動機與目的

由於目前日漸發達的網路科技,如今成能傳輸即時語音及影像等 多媒體資訊的管道已沒有太多技術上的問題。此外,由於網際網路使 用的普及,再加上收費低廉,所以開始有學者及專家,提出將傳統的 電 話 語 音 整 合 於 網 際 網 路 中, 也 就 是 所 謂 的 所 謂 的 Voice over IP(VOIP)。所謂的 VoIP,就是整合了電話對電話(Phone-to-Phone)、電 腦對電話(PC-to-Phone)以及傳真對傳真(Fax-to-Fax),而使用網際網路 技術來提供傳統電信類的服務。 可是即使現在傳輸上的技術沒有太大的問題了,不過對於網路管

(7)

2 處,因此我們便考慮開發一套系統,來處理這些問題,一方面可以提 供使用者查詢的功能,而透過查詢,使用者可以知道過去一段時間內 自己與哪些人做過通話的動作,或者是其他的資訊;另一方面也提供 網路管理者一些資訊,而管理者可藉此了解現在網路的使用情況,包 含了各個使用戶在什麼時候與使用網路是否佔據了大部分的頻寬,是 否該對某些特定的使用戶加收一些額外的價錢來確保該用戶的使用品 質。 綜合以上各種問題以及市面上所需要的再加上我們自己的想法, 所以我們便決定了著手來嘗試製作出這麼一套系統,希望不僅僅只是 提供一般的通話明細,更可以提供給網路管理者一個方便管理的系 統。雖然我們目前沒有太完整的技術,不過我相信在我們的努力之下 可以一步步的完成我們所做的設定完成我們最初所做的設定,來開發 出一套能帶給管理者及使用者方便的系統。

(8)

第二章 VoIP 相關技術簡介

2.1 VoIP 簡介

n 發展 VOIP(Voice over IP)的背景

網際網路電話( Internet Phone )是透過網際網路傳送語音服務的 一種運用,捨棄了以往利用昂貴的 PSTN 撥接方式,只要透過網際網 路的連接,分散在世界各地的客戶或公司彼此之間即可進行語音的對 談,而且可以配合辦公室的 PBX,使得辦公室的任何一支電話皆可透 過 IP 網路打電話至另一辦公室。而只需要付一般的 ISP 的網路費用, 因此可以作為長途電話的廉價替代方案,換句話說,只要能夠上網際 網路,就可以打電話到網際網路連接到任何地方,而費率就只有上網 的費用。一般普遍認為 VOIP 可以為企業省近 90%的電話成本,對企 業著實是個好消息。 由於網際網路連線的普及,並且收費低廉,所以開始有學者及專 家提出將傳統的電話語音整合於網際網路中,做到所謂的 VOIP。直覺 的觀念就是將類比的語音資料經過壓縮處理後,轉換成電腦所能使用 的數位資料,再將這些數位資料切割成一個一個的 IP 封包送入網路 中。到達對方後,再按照相反的步驟將資料還原成原來的聲音。所以 透過網路,你可以將你的聲音傳遞給任何人。如此一來,我們的聲音 不再只能透過傳統的電路交換網路(Circuit Switch Network)來和對方通 話,透過 VOIP 這項技術,我們也能利用分封交換網路(Packet Switch Network)來傳送我們的聲音。圖 1-1 中是一般 VOIP 網路的架構圖,其 重要的部份是網際網路電信閘道器(Internet Telephony Gateway ; ITG) 的設備,它扮演了轉換的角色,其目的是使得各種終端設備能夠互相 連接。ITG 利用多樣化的介面,整合了電話對電話(Phone-to-Phone)、 電腦對電話(PC-to-Phone)以及傳真對傳真(Fax-to-Fax)的各種重要通訊 功能。

(9)

4

INTERNET

Internet Telephony Gateway

Internet Telephony Gateway

PBX PSTN PBX Phone Ether Phone Ethernet PC Phone FAX Phone FAX Ethernet Phone Ether Phone PC T1/E1/PRI T1/E1/PRI

PC with Internet Phone

IP IP

n VOIP 主要協定介紹

在 VoIP 相關通信協定方面,目前主要有三大主要協定:一個是 ITU-T 所提出的 H.323,其它兩個為 IETF 所提出的 SIP 及 MGCP,此 三者皆己同時被建議作為網路電話的通訊協定。多媒體通訊協定提供 業界一個在不同網路上做通訊的標準,定義了在分封交換網路上,終 端機之間的壓縮標準、通話的程序以媒體傳輸等協定,使得不同廠商 所開發的終端機也能彼此交換語音、視訊以及資料。相信未來幾年內 可以朝著兩個組織的標準合併的目標前進,提早達到完全統一標準的 境界。

2.2 H.323

H.323 由 ITU-T 所制定,係定義在一個沒有提供服務品質保證的區 域網路環境中,各類資料型態所使用的標準,設立點對點間的溝通時 所使用的通話建立信號、撥號信號、通話控制信號等之程序與轉換, 以及其他在溝通建立後所需的諸如多媒體管理、頻寬管理等程序的制 定。 圖 2.1.1 一般 VOIP 網路架 構

(10)

2.2.1 H.323 相關元件

在 H.323 規範中描述了一個 H.323 系統所有可能的元件,包括終 端機(Terminal)、閘道(Gateway)、閘道管理者(GateKeeper)以及多方會 談控制單元(MCU)。它同時也描述了這些元件之間,以及這些元件與 外界元件之間彼此溝通所需的訊息與程序。圖 2.2.1 是 H.323 規範的整 體架構圖,涵括兩大部分,一是 H.323 規範的元件,其他則是與 H.323 規範元件相關的外界元件。

Non-Guaranteed QoS LAN

H.323 Scope of Gatekeeper H.323 H.323 Gateway H.323 Terminal H.323 Terminal (Note)

Note: A gateway may support one or more of the GSTN, N-ISDN B-ISDN H.320 Terminal H.321 Terminal H.321 Terminal H.310 terminal operating in H.321 mode H.323 Terminal GSTN H.324 Terminal H.322 Terminal Guaranteed QOS LAN Speech Terminal Speech Terminal

N-ISDN and/or B-ISDN connections. H.323 MCU V.70 Terminal

n 終端機(Terminal)

終端機的主要功能是讓使用者在網路上雙向傳遞即時性的語音、 視訊以及非即時性的資料。架構如圖 2.2.2。 一個終端機最主要一定要有 G.711 語音壓縮解壓縮的能力。而其他 的 H.261 則為視訊壓解壓縮功能如有做視訊傳送功能時才需具備。 為了讓終端機與其他元件能有標準的溝通方式,終端機必須支援 圖 2.2.1 H.323 系統架構 圖

(11)

6

n 閘道(Gateway)

閘道在 H.323 系統中是一個選配元件。只有當終端機要與外界元 件通話時才需要閘道的存在。由圖 2.2.1 H.323 系統架構可知閘道是連 接分封交換網路與線路交換網路的橋樑,負責轉換兩種網路之間傳輸 格式以及溝通程序上的差異。除此之外也可能負責語音及視訊壓縮解 壓縮格式的轉換。

n 閘道管理者(Gate Keeper)

閘道管理者在 H.323 系統中亦是一個選配元件。它負責管理終端 機、閘道、以及多方會談控制單元。閘道管理者有兩個主要功能: 位址 轉換以及頻寬管理。位址轉換類似查號台的功能,在區域內的所有 H.323 元件在啟動時必須先向閘道管理者註冊其別名與網路位址, H.323 元件可以根據一個別名向閘道管理者查詢另一 H.323元件的網路 位址,有了網路位址後雙方才能建立通話管道。 H.323 元件在與其他元件建立通話管道前必須先向閘道管理者提 出使用頻寬的請求,閘道管理者可以根據目前頻寬使用的情況來批准 圖 2.2.2 H.323 Terminal 架構 圖

(12)

或拒絕其請求。

n 多方會談控制元件(MCU)

H.323 規範中除了基本的雙方通話外,也提供了多方會談的功能。 多方會談意指三個以上的終端機能彼此同時交談,而多方會談控制元 件就是用來控制這些終端機的中心元件。

2.2.2 H.323 相關協定

H.323 這些元件之間若要通話必須仰賴下列協定:RAS 協定、H.225 通話建立協定、H.245 控制協定以及媒體傳輸協定。

n RAS 協定:

RAS 協定是 H.323 元件與閘道管理者之間的協定。RAS 是註冊 (Registration)、加入(Admission)、以及狀態查詢(Status)三個英文的縮 寫,也代表了這個協定的三大功能。 註冊:當 H.323 元件啟動時,必須先向閘道管理者登記其別名與 網路位址。 其功能指令: RRQ:要求註冊 RCF:同意註冊 RRJ:拒絕註冊 URQ:要求取消註冊 UCF:同意取消註冊 URJ:拒絕取消註冊 加入:H.323 元件在與其他元件建立通話管道之前必須先告知閘道 管理者通話所需頻寬與對別名,閘道管理者依據目前頻寬使用狀況准 許或請求,並告之對方的網路位址。

(13)

8 ARQ:要求加入 ACF:同意加入 ARJ:拒絕加入 狀態查詢:閘道管理者可以查詢 H.323 元件是否正常運作以及其 通話狀態。 其功能指令: IRQ:查詢狀態 IRR:回報狀態

n H.225 通話建立協定:

H.225 其目的是讓呼叫端與被呼叫端之間建立通話管道。H.225 協 定事實上是由 Q.931 協定所修改而來,故大部分的運作方式與訊息格 式是差不多的。 以下列出 H.225 的主要指令: Setup:要求建立通話管道 Call Proceeding:通話管道建立中 Alerting:振鈴中 Connect:通話管道建立成功 Release Complete:中斷通話管道 H.225 訊息傳遞方式有兩種:

第 一 種 是 呼 叫 端 與 被 呼 叫 端 直 接 傳 遞 (Direct Endpoint Call Signaling) ,如圖 2.2.3。

(14)

第 二 種 則 是 呼 叫 端 與 被 呼 叫 端 之 間 透 過 閘 道 管 理 者 傳 遞 (Gatekeeper Routed Call Signaling),如圖 2.2.4。

圖 2.2.3 直接傳遞 圖

圖 2.2.4 間接傳遞 圖

(15)

10

n H.245 控制協定

H.245 控制協定主要功能有:交換能力資訊(Capability Exchange)、 決定主從關係 (Master/Slave Determination)以及開閉邏輯管道(Logical Channel)。因為每一個 H.323 元件可能擁有許多種壓縮解壓縮能力,因 此在雙方實際傳輸語音、視訊或資料前必須先了解對方所能使用的壓 縮解壓縮格式,然後進一步找出雙方都能接受的格式,這個過程即交 換能力資訊。之前我們提到過多方會談必須由多點控制器來協調控制 才能達成,且一個多方會談只能由一個多點控制器來協調。因此若通 話雙方都有多點控制器時,則必須依賴 H.245 來決定哪一個是主,哪 一個是從,然後由主多點控制器來長控多方會談。通話雙方若要傳輸 語音、視訊或資料,則必須使用邏輯管道和媒體管道。媒體管道指的 是實際的傳輸線路,而開啟邏輯管道的過程是為了讓彼此能了解對方 媒體管道的傳輸位址。

n 媒體傳輸協定:

在 H.323 規範中,語音或視訊等即時性媒體是透過 RTP/RTCP 協 定來傳輸,而非即時性的資料則是透過 T.120 資料傳輸協定。RTP (Real Time Protocol)及 RTCP(RTP Control Protocl)協定工作在 IP 網路的傳輸 層,是一種處理即時性傳輸的通信協定。

以一個 Call Flow 為例子。圖 2.2.5 所描述的是二個終端機互相通 話的一種可能過程,這二個終端機屬同一個區域。

(16)

RAS Message H.225 Message H.245 Message 圖 2.2.5 Call Flow

Open Logical Channel

Open Logical Channel Ack Terminal Capability Set

Terminal Capability Set Terminal Capability Set Ack

Terminal Capability Set Ack

Open Logical Channel

Open Logical Channel Ack

(17)

12

1.一開始 Endpoint1 向閘道管理者送出一 ARQ 訊息,告知閘道管 理者我要和 Endpoint2 通話。

2.閘道管理者根據目前頻寬使用狀態,同意了 Endpoint1 的要求並 送一 ACF 訊息告知 Endpoint2 的 Call Signaling Channel Transport Address。

3.Endpoint1 收到 ACF 訊息後便根據收到的 Transport Address 送一 Setup 訊息給 Endpoint2。

4.Endpoint2 收 到 Setup 訊 息 後 會 送 一 Call proceeding 告 知 Endpoint1。

5.Endpoint2 送一 ARQ 給閘道管理者要求頻寬。 6.閘道管理者同意後回送 ACF。

7.Endpoint2 送出 Alerting 訊息通知 Endpoint1 產生振鈴。

8.Endpoint2 送出 Connect 訊息並告知 Endpoint1 自己的 H.245 Control Channel Transport Address 以便接下來的 H.245 協定溝 通。 9.接著雙方建立 H.245 管道,交換能力資訊以及決定主從關係,之 後雙方各自開啟 RTP 管道以及 RTCP 管道並且互相開? 一條邏 輯管道,以便開始做雙向通話。

2.3 MGCP

MGCP 採取主從式( Master-Slave )的架構,如圖 2.3.1 所示。在 MGCP 的架構裡,主要組成單元包含一個 Call Agent (CA)和一個以上 的 Media Gateway (MG)。 也有人稱 CA 為 MGC( Media Gateway Control;MGC )。CA 具有指揮所有的 MGs 信號處理和通話處理的功 能 , MG 則 著 重 在 語 音 的 傳 輸 ( Transmission ) 和 封 包 轉 換 ( Packetization )。而 MGCP 就是定義 CA 和 MG 之間的協定。

(18)

CA 它扮演的角色就好比是 ITU-T H.323 裡的 Gatekeeper,每一個 通話的建立、修改、刪除,或是要告知 MG 的事件( 例如:請 MG 對 Endpoint 產生 Ring、Tone… 等,或是 MG 要告知 CA 某一個 Endpoint 目前的狀態是 Off Hook、On Hook… 等 ),都得藉由 CA 來做指揮及控 制。在 ITU-T 所提出的 H.323 架構裡,閘道器必須不但要具備 Call Signaling( Q.931 )的機制,在呼叫端和被呼尖端之間建立通話管道,還 要具備 Call Control( H.245 )的機制,用來做能力資訊交換( Capability Exchange )、決定主從關係( Master/Slave Determination )、開閉邏輯管 道( Logical Channel ),所以一個閘道器的負擔蠻大的,能夠支援的使用 者有限。但是在 MGCP 裡的,MG 只要負責幾個語音訊號的命令,其 他控制訊號的部分,就全部交由 CA 專門負責。簡單的說在 MGCP 裡, MG 只需要負責將電話網路中( 如 PSTN )的聲音訊號和 IP 網路中的聲 訊封包做轉換工作,以及根據 CA 所下的命令做對應的動作,因此 MGCP 並沒有直接和用戶端做實體溝通。 圖 2.3.1 MGCP 的架構

(19)

14 圖 2.3.2 舉例多媒體閘道器的類型

2.3.1 MGCP 主要元件

n Media Gateway

主要負責三件事:一是對 CA 所下的命令,作適當的處理及回應; 或是有事件發生時要告知 CA。二是語音以及視訊的壓縮與解壓縮 ( CODECs ),例如可將 G.711 64Kbps 語音壓縮轉換成為 G.723.1 6.3Kb/s;反之,6.3 Kb/s 也可以解壓縮成為 64 Kb/s 的語音。三是在 VoIP 的封包網路和電話電路之間做資料封包和語音信號的轉換。如圖 2.3.2 所表示,即為幾個 MG 的類型。 Trunking Gateway 就是用來提供一種介於傳統交換電話網路 (PSTN)及 VOIP 網路之間的介面,用來提供 IP 網路與電話網路(如 PSTN )之間的媒體對應 ( Mapping )及轉換。

Voice over ATM Gateway 它的功能和 Trunking Gateway 類似,只是 介面換成 ATM 網路而已。

Residential Gateway 提供傳統類比介面 RJ11 和 VOIP 網路之間的 轉換。

Access Gateway 提供傳統類比介面 RJ11 或是數位 PBX 介面與 VOIP 網路之間的轉換。

(20)

圖 2.3.3 MGCP 系統初始化

n Call Agent

負責控制所有的 MGs,給予 MG 適當的命令。例如要告知 MG 要 注意某一個 Endpoint 是否有 Off Hook / On Hook 的事件、或是要告知 MG 準備偵測從 Endpoint 傳來的 Digital Tone、或是發生命令請 MG 回 應每一個 Endpoints 目前的狀態、或是命令 MG 對某一個 Endpoint 做建 立(修改、刪除)通話等。

2.3.3 MGCP 傳送流程

n MGCP 系統初始化

圖 2.3.3 所表示的是 MGCP 系統初始化的幾個操作流程。

n 開始通話

圖 2.3.4所表示的是 Endpoint 1打電話給 Endpoint 2幾個操作流程。

(21)

16

圖 2.3.4 Endpoint 1 打電話給 Endpoint 2

圖 2.3.5 Endpoint 2 接起 Endpoint 1 打來的電話

圖 2.3.5 所表示的是 Endpoint 2 接起 Endpoint 1 打來的電話幾個操 作流程。

(22)

圖 2.3.6 Endpoint1 與 Endpoint2 結束通話 User Location 決定使用於通訊的終端系統 User Capability 決定使用的媒體與媒體參數 User Availability 決定受話方式否有意願加入通訊 Call Setup 建立撥號方與受話方兩端的通話參數 圖 2.3.6 所表示的是結束通話的幾個操作流程。

2.4 SIP

SIP 是由 IETF( Internet Engineering Task Force )所制定的,可以說 是網際網路會議或是網路電話彼此之間溝通的一種簡單的信號傳輸協 定。

SIP 是網路應用層的控制協定,其功能包含了建立、修改與結束多 媒體的交流與通話,而多媒體包含網路電話、多媒體會議與遠距教學 等等。SIP 支援了五種多媒體通訊的建立與終結,如圖 2.4.1

(23)

18

圖 2.4.2 SIP 透過 Proxy Server 的運作方式

SIP 在架構上是 peer-to-peer 的通訊協定,欲通話的雙方可以自行 決定建立修改參數或取消該通話。不像 MGCP 架構中有一個專職控制 媒體閘道控制器( Media Gateway Controller ),因此雙方的通話必須是 一個智慧型的終端機( Smart Terminal ),並在內部維護一個個別的狀態 機( State Machine )。 當建立通話時,撥號方必須先尋找適當的伺服器位址,然後再傳 送 SIP 的需求(Request)。當要回應一需求的時候,伺服器會發送一個 SIP 回應的訊息以告知要如何去處理此一需求。 若發話方想要建立議程時,可藉由發送出 INVITE 訊息來進行,過 程中可以透過一些代理伺服器(Proxy Server) 或者是轉寄伺服器 (Redirect Proxy)找到議程的相關參與者。其流程則可以參考圖 2.4.2 與圖 2.4.3。

(24)

圖 2.4.3 SIP 透過 Redirect Server 的運作方式 一個成功的議會邀約包含了邀約(INVITE)訊息與回覆的確認 (ACK)訊息,邀約訊息邀請了受話方加入一個特定會議或建立雙方 連線,若受話方同意加入的話,撥號方為確認收到回覆的便會送出 ACK 訊息;若是受話方不想加入的話,便會發送一個 BYE 的訊息,如圖 2.4.4 所示。

(25)

20

圖 2.4.5 SIP 透過 Proxy Server 所建立之連線 而圖 2.4.5 則是透過 Proxy Server 所建立連線的流程圖。

(26)

第三章 系統架構

3.1 硬體環境

圖 3.1.1 為網路環境之示意圖、圖 3.1.2 則為各 PC 規格,而初期的 測試環境及發展環境,便是架在此架構上。 (Eth1) Static 192.168.1.1

A

Static 192.168.1.12 Static 192.168.1.24

C

B

圖 3.1.1 網路連結圖 (Eth0) DHCP 10.1.80.174 CPU Memory OS P.S. A K6-2-350 256MB RH Linux 7.2 Desktop PC B C-1.2G 512MB Windows XP Pro Desktop PC C P3-500 192MB Windows XP Pro Laptop PC

(27)

22

對外為一 private IP(10.1.80.174),而我們利用 A 作為 NAT (net address translation) server、Ethernet 的連結則是使用 hub。在此環境下, A 擁有兩張 Ethernet NIC,Eth0 對外、Eth1 對內,而 NAT 的部份則是 透過 iptables 及相關的設定檔而完成(NAT 及 iptables 在 3.2 節將有較

詳細的說明)。

3.2 軟體環境

以下將介紹 GCC、NAT 與 iptables。GCC 是我們實作專題所使用 之 C compiler,而 iptables 則是產生 NAT server 的程式。

n GCC

GCC 可以說是 Richard Stallman 所創立的 GNU 計畫中最重要的作 品之一,它提供了自由軟體世界高品質的編譯器,實現了我們在自由 軟體平台上開發程式的夢想。如果沒有 GCC,恐怕今日我們也不會有 這麼多形形色色的自由軟體可用。 早期 GCC 的發展方向是以 C/C++與 Objective C 等語言為主,故 「GCC」的函義即為「GNU C Compiler」。但發展到現在,GCC 的內 函已不只是 C 與類似 C 的程式語言而已了,它同時還包含了許多其他 語言的編譯器,例如 GNU Ada Translator(gnat)、Java(gcj)、Fortran 77

(g77)、Modula-2、Chill、Pascal(gpc)等等,有些發展已接近成熟, 有些尚在發展中,而有的則因為沒有人在用,故已不再維護了。除此 之外,Cobal 與 Fortran 95 的編譯器則還在早期規劃階段。這些編譯器 全部共用同一組程式編譯最佳化的引擎、使用相同的浮點數運算模 組、同時也都享有 GCC 高移植性的特色。因此,GCC 事實上包含了 一個很大的編譯器家族,而「GCC」的函義也隨之轉變為「GNU Compiler Collection」。 GCC 一個很大的特色是高度可移植性,目前已知有超過三十種硬 體平台與作業系統可以執行 GCC,其中硬體平台包括了:x86、ia64、 alpha、hppa、m68k、Power PC、mips、IBM rs6000、sparc/sparc64 等, 而作業系統則從 Microsoft 平台(DOS/Win32)到 IBM OS/2 到各家的 UNIX 都有。此高度可移植性正是 GCC 廣為流傳散佈的主要原因。在 許多商業版的 UNIX 系統中,如果沒有特別買其專屬的編譯器的話(其

(28)

是自由軟體計畫開發出來的,但其所編譯出來的程式品質並不輸給商 業版的編譯器,甚至在某些平台上所編譯出來程式有更好的執行效能。

n NAT 與 iptables

首先,讓我們了解一下什麼是 socket pair。所謂 socket,就是一個 IP 位址,再加上一個 TCP/UDP Port,而則代表了一個連線與哪台機器 (IP 位址)、及與機器上那一個 port 相連的。我們同時也知道,一個連 線必須有兩個端點,source 和 destination 。換句話說,我們一個連線 就是與一對 socket 相連著,分別是 source socket (source IP address and source port) 與 destination socket (destination IP address and destination port),合起來我們稱之為 socket pair。圖 3.2.1 為 socket pair 的示意圖。

我們一般所說的 NAT,事實上只是一個 socket 的替換機制:將 source socket 替換掉、將 destination socket 替換掉、或者是將兩者同時 換掉。通常而言,當 NAT 替換的是 source socket,我們稱之為 SNAT (source NAT);如果是替換 destination socket 的話,則稱為 DNAT (destination NAT )。圖 3.2.2 為一個利用 iptables 實作 NAT 的例子。

(29)

24

事實上,這是一個 SNAT 的經典例子了。當 NAT 處理一個封包的 時候,如果發現它是來自 192.168.100.0/24 這個網路,並且經由 ppp0 送出的話,那麼它的來源位址則換成 ppp0 的 IP 位址。至於 socket 的 另一元素(TCP/UDP port)的替換,得視 NAT 當時 port 的使用情況而 定。聰明的 NAT 都會盡量保留原有的 port 數值,除非這個 port 已經被 別的 socket 使用了。不過,也有些 NAT 不管怎樣,都同時將 IP 位址 與 port 給換掉。然而,不管哪種情形,只要 socket 元素之一經過修改, 那就是另外一個新的 socket。此外,NAT 必須為這個動作進行記錄, 而此類記錄通常會保存在 NAT Table 中。

當被修改過 socket 的封包送給遠端主機的時候,對方只認得被替 換之後的 socket。換句話說,對方的回應只會送回 NAT 的外部 socket, 此時,回應封包的 source 與 destination 位置將會調換過來。因為 NAT 已經有這個 socket 的 NAT 記錄,所以,當這個回應封包送回到該 socket 的時候,NAT 會根據記錄將 destination 修改為原來的 socket(也就是 被修改了的 source socket),然後再送回給原本的內部主機。也就是因 為 NAT 的緣故,所以在整個連線過程中,無論內部的主機,或是外部 的遠端主機,都能在不知道 NAT 主機的存在下正常地運作。圖 3.2.3 所示,為 NAT 的工作原理。

iptables -t nat -A POSTROUTING -o ppp0 \ -s 192.168.100.0/24 -j MASQUERADE

(30)

而在我們的專題裡,則是使用 iptables 來完成 NAT 的部份。基本 上,得設定兩個檔案:/etc/rc.d/rc.local(圖 3.2.4)、/etc/sysctl.conf(圖 3.2.5)。 touch /var/lock/subsys/local rmmod pegasus insmod /root/pegasus.o

iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 –j \ MASQUERADE /usr/local/apache2/bin/apachectl start 圖 3.2.3 /etc/rc.d/rc.local net.ipv4.ip_forward = 1 net.ipv4.conf.default.rp_filter = 1 kernel.sysrq = 0 kernel.core_uses_pid = 1 圖 3.2.3 NAT 的工作原理

(31)

26

在/etc/rc.d/rc.local 中的「iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 –j MASQUERADE」,-t nat 是指定一個 NAT table;-A POSTROUTING 中的-A 是增加一個防火牆規則,而這個將被加入的規 則則是 POSTROUTING;-o eth0 中的-o 指的是輸出裝置,也就是對外 的網路裝置,而在這則是 eth0;-s 192.168.1.0/24 中的-s 則是指定來源, 而 這 裡 所 代 表 的 是 指 來 至 192.168.1.0 這 個 網 域 的 封 包 ; -j MASQUERADE 表示將封包加上 MASQUERADE 偽裝功能。所以這整 行代表網域為 192.168.1.0 的封包可以經過 iptables NAT routing 後,再 加上 MASQUERADE 的功能,並輸出到 eth0 裝置。而在/etc/sysctl.conf 中的「net.ipv4.ip_forward = 1」,是把致能 IP forward 到 Internet 的功能。

(32)

第四章 軟體架構

4.1 系統架構

圖 4.1.1 為系統整體的架構圖。我們採用網頁的方式,提供查詢通 話資訊的介面。而這個部分,除了需要 HTTP 外,還得藉助 PHP,透 過 MySQL PHP API,我們透過網頁對 MySQL 提出 INSERT 或 SELECT 之類的動作。 至於封包分析程式的部分,則是以 C 撰寫而成。向下透過 PCAP API 擷取封包,往上透過 MySQL C API 對資料庫裡的資料作所需之動作。 MySQL Web 介面 區域網路 MySQL PHP API 封包分析程式 MySQL PHP API PCAP API

(33)

28

4.2 自訂結構

由於得解讀到 H.225 的資訊,所以底層協定的解讀是必須得做的。 這些協定包括:Ethernet、IP、TCP、TPKT、Q.931。而為了方便以及 程式上的需要,與標頭格式相對應的結構(struct),便成了不可缺少的 一環。在 Linux、GCC 的環境下,Ethernet、IP、TCP 這三部分的標頭 已有定義,而 TPKT 與 Q.931 的部份則沒有。所以,這兩個部分的結 構是得自行定義的。而這個部份,我們將在訂於 h323pcap.h(附錄 C.1)。 此外,還有一些結構是需要定義的:儲存 TCP 節區(segment)的 暫存結構。由於 TCP 會適度將資料切節,所以這部分的結構定義也是 不可或缺的。與暫存相關的結構,亦定義於 h323pcap.h(附錄 C.1)。

4.3 資料表

圖 4.3.1 為所用到的資料表。資料表 H225 會記錄下所有 H225 的 封包資訊,而 CONN 裡的每筆資料,則為每通電話的發話端、受話端、 通話起迄時間及經歷時間。

(34)

H225

欄位 型態 屬性 Null 預設值 id int(11) 否 source varchar(20) 否 dest varchar(20) 否 type enum('Setup', 'CallProceeding', ‘Alerting','Connect', 'ReleaseComplete') 否 Setup

datetime timestamp(14) 是 NULL

CONN

欄位 型態 屬性 Null 預設值 id int(11) 否 source varchar(20) 否 dest varchar(20) 否 begin datetime 否 0000-00-00 00:00:00 end datetime 否 0000-00-00 00:00:00 duration time 否 00:00:00 圖 4.3.1 資料表 H225 與 CONN

(35)

30

4.4 相關常數

除了定義有關的結構外,還得定義解讀 H.225 封包時,會用到的

常數,這些常數亦定義於 h323pcap.h(附錄 C.1)。相關定義如下:Setup

(0x05)、CallProceeding(0x02)、Alerting(0x01)、Connet(0x07)、 ReleaseComplete(0x5A),此外,再配合檢查 Q.931 標頭中,Message Type 的欄位,便可得知此封包屬於哪類型的 H.225。

4.5 程式流程

封包分析程式基本上由兩個主要流程所組成:檢查是否有完整的 TPKT 封包(圖 4.3.1),以及擷取封包至解讀 H.225 的部份(圖 4.3.2)。

檢 查 是 否 有 完 整 的 TPKT 封 包 的 部 份 ,主 要 為 pcap.c 中 的 getTPKT( )。而擷取封包至封包解讀則是分布於 main.c 中的 main( )與 pcap.c 的 callback( )。至於 buff.c 則是處理 TCP 節區的相關函式。完整 的程式碼請參閱附錄 C。

(36)

有完整之 TPKT 封包 無完整之 TPKT 封包 Y 檢查 buffer裡的位元組數是 否大於等於 TPKT header 裡 的 Length 無完整之 TPKT 封包 N Y N 圖 4.5.1 檢查是否有完整的 TPKT 封包 解讀 TPKT header 檢查是否可解讀 TPKT header

(37)

32

檢查 port number 是否為 1720 抓取封包

解讀 Ethernet header 及 IP header

過濾出 TCP 封包 解讀 TCP header Y 檢查是否有完整的 TPKT 封包 解讀 Q.931 header 寫入資料庫 Y 解讀 TPKT header 處理 segment N N 圖 4.5.2 擷取封包至解讀 H.225

(38)

第五章 結論

5.1 過程與心得

專題報告前前後後換了兩次題目。原本是在 Windows 2K/XP 的環 境 下 , 利 用 Microsoft 所 提 供 的 TAPI (Telephony Application Programming Interface),實作出 H.323 Client,卻因進度停滯換了專題 題目。第二個題目則是在 Linux 環境下,將一般 Wireless NIC Driver (USB) 中加上省電功能,但專題難度超出能力,所以還是決定換題目。 於是,最後決定,實作個能統計及分析 H.323 網路電話資訊的程式。 剛開始的時候,花了不少的時間在安裝 Linux 上。原本對於 Linux 的安裝與操作不甚熟悉,雖然之前的專題,是架構在 Linux 之上,但 仍無法使得我們對於 Linux 熟悉到某種程度,於是,花費了不少時間 把 Linux 的環境架起來。

除了安裝 Linux 外,還得處理與 NAT (Net Address Translation)相關 的設定及套件,及安裝 PCAP。在 NAT 方面,原本是採用 ipchains,後 來則是改用 iptables;不論是何者,我們都花了一些時間了解它的使用 方式及其所能提供的功能。而在 PCAP 方面,則是很順利地把其 API 安裝起來。 等把整個系統及軟體環境都架起來後,便開始進入實作的階段。 由於做的是 H.323 網路電話資訊的蒐集,當然就得對整個通話過程、 H.323 所包含的協定做整體的認識與了解,並得由此決定實作的深度、 廣度。通話過程是假設在沒有 Gatekeeper 的環境下。至於 H.323 的包 含的協定方面,在蒐集資料之後才深深體會,H.323 裡所包含的協定並 非之前所想像的那麼簡單;裡面包括了 H.225、H.245、RTP,而 H.225 部分還是個根據 Q.931 所定出來的協定。 在蒐集了 H.225 的資料之後,我們決定了專題的實作方向:擷取 H.225 封包裡的資訊。於此,展開了對於 H.225 封包進一步的研讀,包 括了 H.225 本身以及 Q.931。經過一番的努力,對於 H.225 封包的格式 以及如何擷取我們所要的資訊,終於有個初步的了解。之後,經由 PCAP 所抓取的封包,經過一層層的解讀,再加上對於 H.225 封包的解讀,

(39)

34

在這個過程當中,處理 Ethernet 標頭、IP 標頭、TCP/UDP 標頭的 subroutine 都能在不算長的時間內完成,而至於 TCP 的 Payload 部分, 是其中最棘手的。雖然在概念上,只要做個 buffer 把 segmented data 暫 存起來就可以了,但對於此類資料結構不熟悉之故,這部分花了我們 不少的時間。此外,還得實作多個 buffer,以便同時紀錄多個連線,我 們也付出些時間在這上面。 在原本的計畫中,打算把通話過程中,語音所使用的 codec 及總通 話位元組數統計出來。但由於 H.245 比起 H.225 複雜許多,再加上專 題發表時間的逼近,對於這部分,雖然我們有著執著與熱忱,不過礙 於現實,只好忍痛將這部分從專題目標中刪除。 最後,不論是專題的完成、或者是從中所得到的學習及收穫,都 得深深感謝在這過程當中,給我們許多幫助的前輩們。在 TAPI 階段帶 領及讓我們得到很多收穫的 Kelly 學姊、Driver 階段給予我們指導的天 王學長、PCAP 階段與我們討論的鏡坪學長,以及從頭到尾都默默支持 我們、並給我們各方面幫助及指導的李維聰老師,如果沒有這些前輩 們,那在這樣一個難得的學習過程當中,我們可能無法得的那麼多、 得的那麼充實。最後,還是得再次謝謝這些前輩們,你們辛苦了。

5.2 應用與展望

n 網路電話資訊統計資料庫

如果能與 database 相連(如 MySQL),應能提供更強大的功能與 服務。第一,database 本身可以提供更完善的查詢服務。第二,可與 Web 的環境做結合,提供使用者或管理者更方便的操作環境。 當然,如果把 H.245 的分析再加上去,定可提供使用者或管理者 更多的資訊,如總通話位元組、語音所使用之 codec 等。

n 網路電話計費系統

配合以上所述之統計資料庫(包含 H.245 的分析),將能精確地統

計出 VoIP 用戶總通話位元組、及顯示語音所使用之 codec,而 VoIP 服 務之提供者便能依據這兩項資訊訂出公平的計費方式,並能有效實作

(40)

出合適的計費系統。

n 頻寬管理

網路電話通話過程中,通話品質是個很大的變數,而其中頻寬則 是影響品質的一大主因。 若將網路電話資訊監控與頻寬管理的相關技術作結合,便能將現 有頻寬作更適當的管理。如網路電話通話數多,而頻寬明顯不足時, 頻寬管理系統便能依照適當的頻寬分配比例,將一般大流量的頻寬使 用(如 FTP)作適當的現流,如此一來,便能使得網路電話的品質達 到一定的水準,而其他的頻寬使用又不至於因網路電話而完全被禁用。

(41)

36

參考文獻

[1] 楊文誌,深入 Linux 建構與管理-第三版,旗標出版股份有限公 司,2002 年 2 月。

[2] W. Richand Stevens,TCP/IP Illustrated, Volume 1, The Protocols 國際 中文版,和碩科技文化有限公司,2000 年 9 月初版。

[3] Paul DuBois、Michael Widenius,劉春成、蔣鐙緯、趙柏強,MySQL 徹底研究,博碩文化股份有限公司,2000 年 10 月初版。

[4] Tim Converse、Joyce Park,張維國,精通 PHP,博碩文化股份有 限公司,2001 年 11 月初版。

(42)

附錄 A

(43)

38

(44)

A.3 TCP 標頭

A.4 TPKT 標頭

1 15 16 32 版本 保留 長度 資料 1 位元組

(45)

40

A.5 Q.931 標頭

Protocol Discriminator Length (bytes) of Call Reference

Call Reference (1-15 bytes) Message Type

(46)

附錄 B

n B.1 PCAP Manual

NAME

pcap - Packet Capture library SYNOPSIS

#include <pcap.h>

pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)

pcap_t *pcap_open_offline(char *fname, char *ebuf)

pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname) char errbuf[PCAP_ERRBUF_SIZE];

char *pcap_lookupdev(char *errbuf)

int pcap_lookupnet(char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf)

int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) void pcap_dump(u_char *user, struct pcap_pkthdr *h, u_char *sp)

int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask)

int pcap_setfilter(pcap_t *p, struct bpf_program *fp) u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h) int pcap_datalink(pcap_t *p)

int pcap_snapshot(pcap_t *p) int pcap_is_swapped(pcap_t *p) int pcap_major_version(pcap_t *p) int pcap_minor_version(pcap_t *p)

int pcap_stats(pcap_t *p, struct pcap_stat *ps) FILE *pcap_file(pcap_t *p)

int pcap_fileno(pcap_t *p)

(47)

42

void pcap_close(pcap_t *p)

void pcap_dump_close(pcap_dumper_t *p) DESCRIPTION

The Packet Capture library provides a high level interface to packet capture systems. All packets on the network, even those destined for other hosts, are accessible through this mechanism.

ROUTINES

pcap_open_live() is used to obtain a packet capture descriptor to look at packets on the network. device is a string that specifies the network device to open. snaplen specifies the maximum number of bytes to capture. promisc specifies if the interface is to be put into promiscuous mode. (Note that even if this parameter is false, the interface could well be in promiscuous mode for some other reason.) to_ms specifies the read timeout in milliseconds. ebuf is used to return error text and is only set when pcap_open_live() fails and returns NULL.

pcap_open_offline() is called to open a ‘savefile’ for reading. fname specifies the name of the file to open. The file has the same format as those used by tcpdump(1) and tcpslice(1). The name ‘-‘ in a synonym for stdin. ebuf is used to return error text and is only set when pcap_open_offline() fails and returns NULL.

pcap_dump_open() is called to open a ‘savefile’ for writing. The name ‘-‘ in a synonym for stdout. NULL is returned on failure. p is a pcap struct as returned by pcap_open_offline() or pcap_open_live(). fname specifies the name of the file to open. If NULL is returned, pcap_geterr() can be used to get the error text.

pcap_lookupdev() returns a pointer to a network device suitable for use with pcap_open_live() and pcap_lookupnet(). If there is an error, NULL is returned and errbuf is filled in with with an appropriate error message. pcap_lookupnet() is used to determine the network number and mask associated with the network device device. Both netp and maskp are

(48)

errbuf is filled in with with an appropriate error message.

pcap_dispatch() is used to collect and process packets. cnt specifies the maximum number of packets to process before returning. A cnt of -1 processes all the packets received in one buffer. A cnt of 0 processes all packets until an error occurs, EOF is reached, or the read times out (when doing live reads and a non-zero read timeout is specified). callback specifies a routine to be called with three arguments: a u_char pointer which is passed in from pcap_dispatch(), a pointer to the pcap_pkthdr struct (which precede the actual network headers and data), and a u_char pointer to the packet data. The number of packets read is returned. Zero is returned when EOF is reached in a ‘savefile.’ A return of -1 indicates an error in which case pcap_perror() or pcap_geterr() may be used to display the error text.

pcap_dump() outputs a packet to the ‘savefile’ opened with pcap_dump_open(). Note that its calling arguments are suitable for use with pcap_dispatch().

pcap_compile() is used to compile the string str into a filter program.

program is a pointer to a bpf_program struct and is filled in by

pcap_compile(). optimize controls whether optimization on the resulting code is performed. netmask specifies the netmask of the local net. pcap_setfilter() is used to specify a filter program. fp is a pointer to an array of bpf_program struct, usually the result of a call to pcap_compile(). -1 is returned on failure; 0 is returned on success.

pcap_loop() is similar to pcap_dispatch() except it keeps reading packets until cnt packets are processed or an error occurs. It does not return when live read timeouts occur. Rather, specifying a non-zero read timeout to pcap_open_live() and then calling pcap_dispatch() allows the reception and processing of any packets that arrive when the timeout occurs. A negative cnt causes pcap_loop() to loop forever (or at least until an error occurs).

(49)

44

pcap_datalink() returns the link layer type, e.g. DLT_EN10MB.

pcap_snapshot() returns the snapshot length specified when pcap_open_live was called.

pcap_is_swapped() returns true if the current ‘savefile’ uses a different byte order than the current system.

pcap_major_version() returns the major number of the version of the pcap used to write the savefile.

pcap_minor_version() returns the minor number of the version of the pcap used to write the savefile.

pcap_file() returns the name of the ‘savefile.’

int pcap_stats() returns 0 and fills in a pcap_stat struct. The values represent packet statistics from the start of the run to the time of the call. If there is an error or the under lying packet capture doesn't support packet statistics, -1 is returned and the error text can be obtained with pcap_perror() or pcap_geterr().

pcap_fileno() returns the file descriptor number of the ‘savefile.’

pcap_perror() prints the text of the last pcap library error on stderr, prefixed by prefix.

pcap_geterr() returns the error text pertaining to the last pcap library error.

pcap_strerror() is provided in case strerror(1) isn't available.

pcap_close() closes the files associated with p and deallocates resources. pcap_dump_close() closes the ‘savefile.’

(50)

SEE ALSO

tcpdump(1), tcpslice(1) AUTHORS

Van Jacobson, Craig Leres and Steven McCanne, all of the Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. The current version is available via anonymous ftp:

ftp://ftp.ee.lbl.gov/libpcap.tar.Z BUGS

(51)

46

附錄 C

n C.1 h323pcap.h

#include <netinet/ip.h> #include <netinet/in.h> #include <time.h> //定義與 H.225 相關的常數 #define H225_SETUP 0x05 #define H225_CALLPROCEEDING 0x02 #define H225_ALERTING 0x01 #define H225_CONNET 0x07 #define H225_RELEASECOMPLETE 0x5a //定義與 Q.931 相關的常數

#define Q931_UUIE 0x7e //定義最大通話數為 10

#define MAXCONN 10

//存 TCP segment 的 buffer struct TCPSegBuff

{

struct in_addr sAddr, dAddr; int len; u_char buff[2048]; }; struct TCPSegBuffList { int valid[MAXCONN];

struct TCPSegBuff tcpSegBuff[MAXCONN]; }; //TPKT 的 header struct tpkthdr { u_int8_t tpkt_ver; u_int8_t tpkt_res; u_int16_t tpkt_len; };

(52)

//Q.931 的 header struct q931hdr { u_int8_t q931_dis; u_int8_t q931_vlen; u_int16_t q931_v; u_int8_t q931_message; };

(53)

48

n C.2 main.c

#include <stdio.h> #include <stdlib.h> #include <pcap.h> #include <errno.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <netinet/if_ether.h>

extern void callback(u_char*, const struct pcap_pkthdr*, const u_char*); int main(int argc, char **argv)

{ char *dev; char *net; char *mask; pcap_t* pd; int ret; char errbuf[PCAP_ERRBUF_SIZE]; char strbuf[256]; bpf_u_int32 netp; bpf_u_int32 maskp; struct bpf_program fp; struct in_addr addr; if (argc < 2)

exit(1); dev = argv[1];

printf("DEV: %s\n",dev);

if ( (pd = pcap_open_live(dev, BUFSIZ, 1, -1, errbuf)) == NULL) {

printf("%s\n", errbuf); exit(1);

}

if ( (ret = pcap_lookupnet(dev, &netp, &maskp, errbuf)) == -1) {

printf("%s\n", errbuf); exit(1);

(54)

addr.s_addr = netp;

if ( (net = inet_ntoa(addr)) == NULL) { perror("inet_ntoa"); exit(1); } printf("NET: %s\n", net); addr.s_addr = maskp;

if ( (mask = inet_ntoa(addr)) == NULL) { perror("inet_ntoa"); exit(1); } printf("MASK: %s\n", mask); (void) sprintf(strbuf, "tcp");

if (pcap_compile(pd, &fp, strbuf, 0, netp) == -1) {

fprintf(stderr, "Error calling pcap_compile\n"); exit(1);

}

if (pcap_setfilter(pd, &fp) == -1) {

fprintf(stderr, "Error setting filter\n"); exit(1);

}

pcap_loop(pd, -1, callback, NULL); return 0;

(55)

50

n C.3 buff.c

#include "h323pcap.h" #include <stdio.h> //////////////////// //External Functions

void initTCPSegBuffList(struct TCPSegBuffList*); int selectTCPSegBuff(struct TCPSegBuffList*,

struct ip*,

struct TCPSegBuff**);

int unselectTCPSegBuff(struct TCPSegBuffList*, const struct ip*);

//////////////////// //Internal Functions

int checkIPAddr(const struct ip*, const struct TCPSegBuff*); void setIPAddr(const struct ip*, struct TCPSegBuff*);

///////////////////// //Function Definition

void initTCPSegBuffList(struct TCPSegBuffList* pTcpSegBuffList) {

int i;

for (i = 0; i < MAXCONN; i++) {

pTcpSegBuffList->valid[i] = 0;

pTcpSegBuffList->tcpSegBuff[i].len = 0; }

}

int checkIPAddr(const struct ip* pIpHdr, const struct TCPSegBuff* pTcpSegBuff) {

if ( (pTcpSegBuff->sAddr.s_addr == pIpHdr->ip_src.s_addr) &&

(pTcpSegBuff->dAddr.s_addr == pIpHdr->ip_dst.s_addr))

return 1; else

(56)

return 0; }

void setIPAddr(const struct ip* pIpHdr, struct TCPSegBuff* pTcpSegBuff) {

pTcpSegBuff->sAddr.s_addr = pIpHdr->ip_src.s_addr; pTcpSegBuff->dAddr.s_addr = pIpHdr->ip_dst.s_addr; }

int selectTCPSegBuff(struct TCPSegBuffList* pTcpSegBuffList, struct ip* pIpHdr,

struct TCPSegBuff** pTcpSegBuff) {

int i, matchOne, emptyOne; matchOne = -1;

emptyOne = -1;

for (i = 0; (i < MAXCONN) && (matchOne == -1); i++) {

if ( (checkIPAddr(pIpHdr, &pTcpSegBuffList->tcpSegBuff[i])) && (pTcpSegBuffList->valid[i]))

matchOne = i;

else if ( (emptyOne == -1) && (pTcpSegBuffList-> valid[i] == 0)) emptyOne = i;

}

//We get what matches the one we wanted. if (matchOne != -1) { *pTcpSegBuff = &pTcpSegBuffList->tcpSegBuff[matchOne]; return 1; }

//We need an empty one. else if(emptyOne != -1) {

*pTcpSegBuff = &pTcpSegBuffList->tcpSegBuff[emptyOne]; (*pTcpSegBuff)->len = 0;

(57)

52 return 1;

}

return 0; }

int unselectTCPSegBuff(struct TCPSegBuffList* pTcpSegBuffList, const struct ip* pIpHdr)

{

int matchOne; int i;

matchOne = -1;

for (i = 0; (i < MAXCONN) && (matchOne == -1); i++) {

if ( (checkIPAddr(pIpHdr, &pTcpSegBuffList->tcpSegBuff[i])) && (pTcpSegBuffList->valid[i])) matchOne = i; } if (matchOne != -1) { pTcpSegBuffList->valid[matchOne] = 0; pTcpSegBuffList->tcpSegBuff[matchOne].len = 0; return 1; } else return -1; }

(58)

n C.4 pcap.c

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <pcap.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netinet/if_ether.h> #include <mysql.h> #include "h323pcap.h" pcap_t* pd; long int npkt = 1;

extern void initTCPSegBuffList(struct TCPSegBuffList*); extern int selectTCPSegBuff(struct TCPSegBuffList*,

struct ip*,

struct TCPSegBuff**);

extern int unselectTCPSegBuff(struct TCPSegBuffList*, const struct ip*);

extern do_connect(char* host_name, char* user_name, char* password, char* db_name, unsigned int port_num, char* socket_name, unsigned int flags);

void refEthHdr(const u_char*, struct ether_header**); void refIPHdr(const struct ether_header*, struct ip**); void refTCPHdr(const struct ip*, struct tcphdr**); void refTPKTHdr(const u_char*, struct tpkthdr**);

void refQ931Hdr(const struct tpkthdr*, struct q931hdr**); void refFirstIE(const struct q931hdr*, u_char**);

void refNextIE(const u_char*, u_char**, int); void find_refUUIE(const u_char*, u_char**); void refH323UI(const u_char*, u_char**); int getTPKTPkt(struct TCPSegBuff*, u_char[]); int getIEType(const u_char*);

int getIELen(const u_char*);

(59)

54 void write2File(const FILE*, const struct ip*, int);

//Place the pointer of ethernet header into approciate position. inline void refEthHdr( const u_char* ppkt,

struct ether_header** pethhdr) {

(*pethhdr) = (struct ether_header*) ppkt; }

//Place the pointer of IP header into approciate position.

inline void refIPHdr( const struct ether_header* pethhdr,

struct ip** piphdr)

{

(*piphdr) = (struct ip*) ( (u_char*) pethhdr + 14); }

inline void refTCPHdr( const struct ip* piphdr, struct tcphdr** ptcphdr)

{

(*ptcphdr) = (struct tcphdr*)

( (u_char*) piphdr + piphdr->ip_hl * 4); }

inline void refTPKTHdr(const u_char* buff, struct tpkthdr** ptpkthdr) {

(*ptpkthdr) = (struct tpkthdr*) buff; }

inline void refQ931Hdr(const struct tpkthdr* ptpkthdr, struct q931hdr** pq931hdr) {

(*pq931hdr) = (struct q931hdr*) ( (u_char*) ptpkthdr + 4); }

inline void refFirstIE(const struct q931hdr* pq931hdr,

u_char** pFirstIE)

{

(*pFirstIE) = (u_char*) pq931hdr + 5; }

(60)

{

(*pNextIE) = (u_char*)pIE + 2 + len; }

inline void refH323UI(const u_char* pUUIE, u_char** pH323UI) {

(*pH323UI) = (u_char*)pUUIE + 4; }

inline int getIEType(const u_char* pIE) {

return (u_int8_t)(*pIE); }

inline int getIELen(const u_char* pIE) {

int type = getIEType(pIE); if (type == Q931_UUIE)

return ntohs(*( (u_int16_t*) (pIE + 1))); else

return *(pIE + 1); }

void find_refUUIE(const u_char* pIE, u_char** pUUIE) {

u_char* pNextIE = (u_char*)pIE;

while ( getIEType(pNextIE) != Q931_UUIE) { fprintf(stdout, "%d\n", getIELen(pNextIE)); refNextIE(pNextIE, &pNextIE, getIELen(pNextIE) ); } fprintf(stdout, "%d\n", getIELen(pNextIE)); (*pUUIE) = pNextIE; }

(61)

56 {

int tcppllen = ntohs(piphdr->ip_len) - piphdr->ip_hl*4 - ptcphdr->doff*4; if (tcppllen > 0)

{

memcpy( ptcpSegBuff->buff + ptcpSegBuff->len, (u_char*) ptcphdr + ptcphdr->doff * 4, tcppllen); ptcpSegBuff->len += tcppllen; } fprintf(stdout, "(%s:", inet_ntoa(piphdr->ip_src)); fprintf(stdout, "%s):", inet_ntoa(piphdr->ip_dst)); fprintf(stdout, "tcppllen = %d", tcppllen);

fprintf(stdout, "\tlen = %d\n", ptcpSegBuff->len); }

int getTPKTPkt(struct TCPSegBuff* pTcpSegBuff, u_char tpktPkt[]) { int tpktLen; struct tpkthdr* ptpkthdr; if (pTcpSegBuff->len >= 4) { refTPKTHdr(pTcpSegBuff->buff, &ptpkthdr); tpktLen = ntohs(ptpkthdr->tpkt_len);

//fprintf(stdout, "TPKTLen = %d\n", tpktLen);

//fprintf(stdout, "pTcpSegBuff->len = %d", pTcpSegBuff->len); //fprintf(stdout, "\ttpktLen = %d\n", tpktLen);

if (pTcpSegBuff->len >= tpktLen) {

memcpy(tpktPkt, pTcpSegBuff->buff, tpktLen + 4); memmove(pTcpSegBuff->buff,

pTcpSegBuff->buff + tpktLen, pTcpSegBuff->len - tpktLen);

pTcpSegBuff->len = pTcpSegBuff->len - tpktLen; //fprintf(stdout, "Yes\n");

(62)

return 1; }

}

return 0; }

void callback(u_char *args, const struct pcap_pkthdr *phdr, const u_char *ppkt)

{

static struct TCPSegBuffList* pTcpSegBuffList = NULL; static MYSQL* conn = NULL;

struct TCPSegBuff* pTcpSegBuff = NULL; struct ether_header* pethhdr;

struct ip* piphdr; struct tcphdr* ptcphdr; struct tpkthdr* ptpkthdr; struct q931hdr* pq931hdr; char query[256]; char src[20]; char dst[20]; int msgType; u_char* pFirstIE; u_char* pUUIE; u_char* pH323UI; u_char tpktPkt[2048]; if (pTcpSegBuffList == NULL) {

pTcpSegBuffList = (struct TCPSegBuffList*)

malloc(sizeof(struct TCPSegBuffList)); initTCPSegBuffList(pTcpSegBuffList);

}

if (conn == NULL) {

conn = (MYSQL*)do_connect(NULL, NULL, NULL, "PCAP_DB", 0, NULL, 0); }

(63)

58 refIPHdr(pethhdr, &piphdr);

refTCPHdr(piphdr, &ptcphdr);

//fprintf(stdout, "SOURCE: %s ", inet_ntoa(piphdr->ip_src)); //fprintf(stdout, "DEST: %s\n", inet_ntoa(piphdr->ip_dst)); if (checkPort(ptcphdr, 1720) > 0)

{

//fprintf(stdout, "SOURCE: %s ", inet_ntoa(piphdr->ip_src)); //fprintf(stdout, "DEST: %s\n", inet_ntoa(piphdr->ip_dst)); (void) selectTCPSegBuff(pTcpSegBuffList, piphdr, &pTcpSegBuff); putIntoTCPSegBuff(piphdr, ptcphdr, pTcpSegBuff); while (getTPKTPkt(pTcpSegBuff, tpktPkt)) { refTPKTHdr(tpktPkt, &ptpkthdr); refQ931Hdr(ptpkthdr, &pq931hdr); refFirstIE(pq931hdr, &pFirstIE); switch (pq931hdr->q931_message) { case H225_SETUP: fprintf(stdout, "Setup"); msgType = 1; break; case H225_CALLPROCEEDING: fprintf(stdout, "CallProceeding"); msgType = 2; break; case H225_ALERTING: fprintf(stdout, "Alerting"); msgType = 3; break; case H225_CONNET: fprintf(stdout, "Connect"); msgType = 4; break; case H225_RELEASECOMPLETE: fprintf(stdout, "ReleaseComplete"); msgType = 5; (void) unselectTCPSegBuff(pTcpSegBuffList, piphdr); break; default:

(64)

}

sprintf(src, inet_ntoa(piphdr->ip_src)); sprintf(dst, inet_ntoa(piphdr->ip_dst)); sprintf(query,

"INSERT INTO H225

(source, dest, type, datetime) VALUES('%s', '%s', '%d', NOW())", src, dst, msgType); mysql_query(conn, query); fprintf(stdout, "\n"); } } }

int checkPort(const struct tcphdr* ptcphdr, const u_int16_t port) {

if( (ntohs(ptcphdr->source) == port) || (ntohs(ptcphdr->dest) == port))

return 1; else return 0; }

數據

圖 2.2.3 直接傳遞  圖
圖 2.3.3 MGCP 系統初始化 n  Call Agent
圖 2.3.5 Endpoint 2 接起 Endpoint 1 打來的電話
圖 2.3.6  Endpoint1 與 Endpoint2 結束通話  User Location  決定使用於通訊的終端系統  User Capability  決定使用的媒體與媒體參數  User Availability  決定受話方式否有意願加入通訊  Call Setup  建立撥號方與受話方兩端的通話參數 圖 2.3.6 所表示的是結束通話的幾個操作流程。 2.4 SIP
+6

參考文獻

相關文件

– The The readLine readLine method is the same method used to read method is the same method used to read  from the keyboard, but in this case it would read from a 

The main disadvantage of the Derman-Kani tree is the invalid transition probability problem, in which the transition probability may become greater than one or less than zero.

The writer is convinced that Seng-chao’s concept of the Saint should be interpreted as an activity which is, in a sense, similar to the basic nature of NG Yu-kwan’s concept of Pure

Study the following statements. Put a “T” in the box if the statement is true and a “F” if the statement is false. Only alcohol is used to fill the bulb of a thermometer. An

In summary, the main contribution of this paper is to propose a new family of smoothing functions and correct a flaw in an algorithm studied in [13], which is used to guarantee

3.1(c) again which leads to a contradiction to the level sets assumption. 3.10]) which indicates that the condition A on F may be the weakest assumption to guarantee bounded level

(It is also acceptable to have either just an image region or just a text region.) The layout and ordering of the slides is specified in a language called SMIL.. SMIL is covered in

1 After computing if D is linear separable, we shall know w ∗ and then there is no need to use PLA.. Noise and Error Algorithmic Error Measure. Choice of