這是透過大華 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。0x17
0x18
0x19
:身份驗證。0x1a
: 0x19
之後的伺服器回應。0x1b
: 0x1a
之後的客戶端回應。 該項目受到以下項目和人員的啟發和影響: