นี่เป็นข้อพิสูจน์ถึงการนำแนวคิด RTSP ไปใช้ผ่านโปรโตคอล Dahua P2P ทำงานร่วมกับ Dahua และกล้อง/NVR ที่ได้รับมา
โปรโตคอล Dahua P2P ใช้สำหรับการเข้าถึงอุปกรณ์ Dahua จากระยะไกล โดยทั่วไปจะใช้โดยแอป Dahua เช่น gDMSS Lite บน Android หรือ SmartPSS, KBiVMS บน Windows
ในสถานการณ์เฉพาะของฉัน ฉันมีระบบ CCTV KBVision แม้ว่าฉันจะสามารถเข้าถึงกล้องโดยใช้ไคลเอนต์ KBiVMS ได้ แต่ฉันใช้แพลตฟอร์มที่ไม่ใช่ Windows เป็นหลัก ดังนั้น ฉันจึงต้องการสำรวจตัวเลือกอื่นสำหรับการสตรีมวิดีโอโดยใช้ไคลเอนต์ RTSP ซึ่งได้รับการสนับสนุนอย่างกว้างขวางมากขึ้น ด้วยเหตุนี้ ฉันจึงตัดสินใจทดลองใช้โปรโตคอล Dahua P2P อีกครั้ง
src/*.rs - ไฟล์ต้นฉบับสนิมCargo.toml - การพึ่งพาของสนิมmain.py - สคริปต์หลักhelpers.py - ฟังก์ชั่นตัวช่วยrequirements.txt - การพึ่งพา Pythondh-p2p.lua - ตัวแยก Wireshark สำหรับโปรโตคอล Dahua P2P การใช้งาน 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
การใช้งาน Python ของ DH-P2P เป็นแนวทางที่ง่ายและตรงไปตรงมา ใช้สำหรับการร่างและการทดสอบเนื่องจากมีลักษณะการเขียนที่รวดเร็วและง่ายดาย นอกจากนี้ การใช้งานจะเป็นเส้นตรงมากขึ้นและเป็นไปตามโฟลว์การดำเนินการจากบนลงล่าง ทำให้เข้าใจได้ง่ายขึ้น 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 .-> อุปกรณ์
โปรโตคอล Dahua P2P เริ่มต้นด้วยการจับมือ P2P กระบวนการนี้เกี่ยวข้องกับการค้นหาอุปกรณ์โดยใช้หมายเลขซีเรียล (SN) ผ่านบริการของบุคคลที่สาม Easy4IPCloud:
กราฟ LR
อุปกรณ์[กล้อง/NVR]
แอป[[สคริปต์นี้]]
ลูกค้า 1 [ไคลเอ็นต์ RTSP 1]
ไคลเอ็นต์2[ไคลเอ็นต์ RTSP 2]
ลูกค้า [ไคลเอ็นต์ RTSP n]
ลูกค้า 1 -- TCP --> แอป
ไคลเอนต์2 -- TCP --> แอป
ลูกค้า -- TCP --> แอป
แอพ <-. โปรโตคอล UDPnPTCP .-> อุปกรณ์
หลังจากการจับมือ P2P สคริปต์จะเริ่มฟังการเชื่อมต่อ RTSP บนพอร์ต 554 เมื่อเชื่อมต่อไคลเอนต์ สคริปต์จะเริ่มต้นขอบเขตใหม่ภายในโปรโตคอล PTCP โดยพื้นฐานแล้ว สคริปต์นี้ทำหน้าที่เป็นช่องสัญญาณระหว่างไคลเอนต์และอุปกรณ์ ซึ่งอำนวยความสะดวกในการสื่อสารผ่านการห่อหุ้ม PTCP
ลำดับไดอะแกรม
ผู้เข้าร่วม A เป็นสคริปต์นี้
ผู้เข้าร่วม B เป็น Easy4IPCloud
ผู้เข้าร่วม C1 เป็นเซิร์ฟเวอร์ P2P
ผู้เข้าร่วม C2 เป็นเซิร์ฟเวอร์รีเลย์
ผู้เข้าร่วม C3 เป็น Agent Server
ผู้เข้าร่วม D เป็นกล้อง/NVR
A->>B: /โพรบ/p2psrv
ข-->>ก: ;
A->>B: /ออนไลน์/p2psrv/{SN}
B-->>A: ข้อมูล p2psrv
A->>C1: /โพรบ/อุปกรณ์/{SN}
C1-->>ก: ;
A->>B: /ออนไลน์/รีเลย์
B-->>A: ข้อมูลรีเลย์
A->>B: /อุปกรณ์/{SN}/p2p-channel (*)
พาร์
A->>C2: /relay/agent
C2-->>A: ข้อมูลตัวแทน + โทเค็น
A->>C3: /รีเลย์/เริ่มต้น/{โทเค็น}
C3-->>ก: ;
จบ
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) เป็นโปรโตคอลที่เป็นกรรมสิทธิ์ซึ่งพัฒนาโดย Dahua มีวัตถุประสงค์ในการห่อหุ้มแพ็กเก็ต 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 : ค่าคงที่ PTCPsent and recv : ติดตามจำนวนไบต์ที่ส่งและรับตามลำดับpid : ID แพ็กเก็ตlmid : รหัสท้องถิ่นrmid : Local 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 : ความยาวของเขต datarealm : Realm ID ของการเชื่อมต่อpadding : padding bytes ตั้งค่าเป็น 0 เสมอdata : ข้อมูลแพ็กเก็ตประเภทแพ็คเก็ต:
0x00 : SYN เนื้อความจะมีขนาด 4 ไบต์เสมอ 0x000301000x10 : ข้อมูล TCP โดยที่ len คือความยาวของข้อมูล TCP0x11 : คำขอพอร์ตการเชื่อมโยง0x12 : สถานะการเชื่อมต่อ โดยที่ข้อมูลเป็น CONN หรือ DISCrealm เป็น 0):0x13 : Heartbeat โดยที่ len จะเป็น 0 เสมอ0x170x180x19 : การรับรองความถูกต้อง0x1a : การตอบสนองของเซิร์ฟเวอร์หลังจาก 0x190x1b : การตอบสนองของลูกค้าหลังจาก 0x1a โครงการนี้ได้รับแรงบันดาลใจและได้รับอิทธิพลจากโครงการและบุคคลดังต่อไปนี้: