這是透過大華 P2P 協定實現 RTSP 的概念驗證。它可與大華及其衍生攝影機/NVR 配合使用。
大華P2P協定用於遠端存取大華設備。它通常被大華應用程式使用,例如 Android 上的 gDMSS Lite 或 Windows 上的 SmartPSS、KBiVMS。
在我的具體場景中,我有一個 KBVision CCTV 系統。雖然我可以使用 KBiVMS 用戶端存取攝影機,但我主要使用非 Windows 平台。因此,我想探索使用更廣泛支援的 RTSP 用戶端串流視訊的替代選項。於是,我決定嘗試重新實作大華P2P協定。
src/*.rs - Rust 原始檔Cargo.toml - Rust 依賴項main.py - 主腳本helpers.py - 輔助函數requirements.txt - Python 依賴項dh-p2p.lua - 大華 P2P 協定的 Wireshark 解析器Rust 實作利用非同步程式設計和訊息傳遞模式,使其更有效率和靈活。
A PoC implementation of TCP tunneling over Dahua P2P protocol.
Usage: dh-p2p [OPTIONS] <SERIAL>
Arguments:
<SERIAL> Serial number of the camera
Options:
-p, --port <[bind_address:]port:remote_port>
Bind address, port and remote port. Default: 127.0.0.1:1554:554
-h, --help
Print help
DH-P2P 的 Python 實作是一種簡單直接的方法。由於其快速且易於編寫的特性,它用於起草和測試目的。此外,實現更加線性,遵循自上而下的執行流程,更容易理解。 Python 作為一種流行的程式語言,進一步提高了開發人員對其的可訪問性和熟悉度。
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run
python main.py [CAMERA_SERIAL]
# Stream (e.g. with ffplay) rtsp://[username]:[password]@127.0.0.1/cam/realmonitor?channel=1&subtype=0
ffplay -rtsp_transport tcp -i " rtsp://[username]:[password]@127.0.0.1/cam/realmonitor?channel=1&subtype=0 "若要將腳本與建立頻道時需要驗證的裝置一起使用,請使用-t 1選項。
在--debug模式下執行或--type > 0 時, USERNAME和PASSWORD參數是必需的。此外,啟用偵錯模式時,請確保ffplay位於系統路徑中。
usage: main.py [-h] [-u USERNAME] [-p PASSWORD] [-d] serial
positional arguments:
serial Serial number of the camera
options:
-h, --help show this help message and exit
-d, --debug Enable debug mode
-t TYPE, --type TYPE Type of the camera
-u USERNAME, --username USERNAME
Username of the camera
-p PASSWORD, --password PASSWORD
Password of the camer
ffplay和-rtsp_transport tcp選項可以更好地工作為了對協定進行逆向工程,我使用 Wireshark 和 KBiVMS V2.02.0 作為 Windows 上的用戶端。使用dh-p2p.lua解析器,您可以更輕鬆地查看Wireshark中的協定。
對於 RTSP 用戶端,可以使用 VLC 或 ffplay 來更輕鬆地控制訊號。
圖LR
應用程式[[此腳本]]
服務[Easy4IPCloud]
設備[攝影機/NVR]
應用程式 -- 1 --> 服務
服務 -- 2 --> 設備
應用<-. 3 .-> 設備
大華P2P協議以P2P握手發起。此過程涉及透過第三方服務 Easy4IPCloud 使用其序號 (SN) 來定位裝置:
圖LR
設備[攝影機/NVR]
應用程式[[此腳本]]
客戶端1[RTSP客戶端1]
客戶端2[RTSP客戶端2]
客戶端 n[RTSP 客戶端 n]
客戶端1 -- TCP --> 應用程式
客戶端2 -- TCP --> 應用程式
客戶端 -- TCP --> 應用程式
應用<-. UDPnPTCP 協定 .-> 設備
P2P 握手之後,腳本開始偵聽連接埠 554 上的 RTSP 連線。本質上,該腳本充當客戶端和設備之間的隧道,透過 PTCP 封裝促進通訊。
序列圖
參與者 A 作為此腳本
參與者 B 作為 Easy4IPCloud
參與者C1作為P2P伺服器
參與者C2作為中繼伺服器
參與者C3作為代理伺服器
參與者 D 作為攝影機/NVR
A->>B:/probe/p2psrv
B-->>A: ;
A->>B: /online/p2psrv/{SN}
B-->>A: p2psrv 訊息
A->>C1:/探針/設備/{SN}
C1-->>A: ;
A->>B: /線上/中繼
B-->>A:中繼訊息
A->>B: /device/{SN}/p2p-channel (*)
標竿
A->>C2: /relay/agent
C2-->>A:代理資訊+令牌
A->>C3: /relay/start/{token}
C3-->>A: ;
結尾
B-->>A:設備資訊
A->>B: /device/{SN}/relay-channel + 座席資訊
C3-->>A:伺服器NAT資訊!
A->>C3:PTCP SYN
A->>C3:PTCP請求標誌
C3-->>A:PTCP標誌
A->>D:PTCP 握手 (*)
注意:標示(*)的兩個連接以及與設備的所有後續連接必須使用相同的 UDP 本機連接埠。
PTCP(PhonyTCP)是大華開發的專有協定。它的目的是將 TCP 封包封裝在 UDP 封包中,從而能夠在客戶端和 NAT 後面的裝置之間建立隧道。
請注意,PTCP 的官方文件不可用。此處提供的資訊是基於逆向工程。
PTCP包頭是固定的24位元組結構,如下所示:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| magic |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sent |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| recv |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| pid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| lmid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rmid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
magic :一個常數值, PTCP 。sent和recv :分別追蹤發送和接收的位元組數。pid :資料包 ID。lmid :本地 ID。rmid :先前接收到的資料包的本機 ID。資料包主體的大小會根據資料包類型而變化(0、4、12 位元組或更多)。其架構如下:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| type | len |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| realm |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type :指定封包類型。len : data欄位的長度。realm :連接的領域 ID。padding :填充字節,始終設定為 0。data :資料包資料。資料包類型:
0x00 :SYN,主體始終為 4 位元組0x00030100 。0x10 :TCP數據,其中len是TCP數據的長度。0x11 :綁定連接埠請求。0x12 :連線狀態,其中資料為CONN或DISC 。realm設定為 0):0x13 :心跳,其中len始終為 0。0x170x180x19 :身份驗證。0x1a : 0x19之後的伺服器回應。0x1b : 0x1a之後的客戶端回應。 該項目受到以下項目和人員的啟發和影響: