Multimedia Network Protocols คือกลุ่มของโปรโตคอลที่ออกแบบมาเฉพาะสำหรับการส่งข้อมูลเสียง (Voice) และวิดีโอ (Video) แบบ real-time ผ่านเครือข่าย IP ซึ่งแตกต่างจากการส่งข้อมูลทั่วไปตรงที่ต้องการ ความหน่วงต่ำ (Low Latency) และ ความต่อเนื่อง (Continuity) มากกว่าความถูกต้องสมบูรณ์ 100%
ลักษณะพิเศษของ Real-time Traffic:
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'secondaryColor': '#3c3836', 'tertiaryColor': '#504945', 'background': '#282828', 'mainBkg': '#282828', 'nodeBorder': '#928374', 'clusterBkg': '#3c3836', 'titleColor': '#ebdbb2', 'edgeLabelBackground': '#3c3836', 'attributeBackgroundColorEven': '#3c3836', 'attributeBackgroundColorOdd': '#504945'}}}%%
flowchart TD
subgraph APP["Application Layer (ชั้นแอปพลิเคชัน)"]
A1["🎤 Voice/Video Application - Softphone, Video Conferencing"]
end
subgraph SIG["Signaling Protocols (โปรโตคอลส่งสัญญาณ)"]
S1["SIP - Session Initiation Protocol"]
S2["H.323 - ITU-T Standard"]
end
subgraph MEDIA["Media Transport (การส่งข้อมูลสื่อ)"]
M1["RTP - Real-time Transport Protocol"]
M2["SRTP - Secure RTP"]
M3["RTCP - RTP Control Protocol"]
end
subgraph TRANS["Transport Layer (ชั้น Transport)"]
T1["UDP - User Datagram Protocol"]
end
subgraph NET["Network Layer (ชั้น Network)"]
N1["IP - Internet Protocol"]
end
APP --> SIG
SIG --> MEDIA
MEDIA --> TRANS
TRANS --> NET
style APP fill:#458588,color:#ebdbb2,stroke:#83a598
style SIG fill:#d79921,color:#282828,stroke:#fabd2f
style MEDIA fill:#98971a,color:#ebdbb2,stroke:#b8bb26
style TRANS fill:#cc241d,color:#ebdbb2,stroke:#fb4934
style NET fill:#689d6a,color:#ebdbb2,stroke:#8ec07c
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
flowchart TB
subgraph ERA1["ยุคที่ 1: ต้นกำเนิด (1990s)"]
E1A["1996 - H.323 v1 - ITU-T Standard"]
E1B["1996 - RTP RFC 1889 - IETF Standard"]
end
subgraph ERA2["ยุคที่ 2: SIP (Late 1990s - 2000s)"]
E2A["1999 - SIP RFC 2543 - เริ่มต้น SIP"]
E2B["2002 - SIP RFC 3261 - Stable Version"]
E2C["2004 - SRTP RFC 3711 - Secure RTP"]
end
subgraph ERA3["ยุคที่ 3: WebRTC & Modern (2010s+)"]
E3A["2012 - WebRTC - Browser-based VoIP"]
E3B["2018 - SIP over WebSocket - Unified Comms"]
E3C["2020+ - Video Conferencing - Zoom, Teams, Meet"]
end
ERA1 --> ERA2 --> ERA3
style ERA1 fill:#504945,color:#ebdbb2,stroke:#665c54
style ERA2 fill:#3c3836,color:#ebdbb2,stroke:#504945
style ERA3 fill:#282828,color:#ebdbb2,stroke:#3c3836
RTP (Real-time Transport Protocol) คือโปรโตคอลมาตรฐานสำหรับการส่งข้อมูลเสียงและวิดีโอแบบ real-time ผ่านเครือข่าย IP กำหนดในมาตรฐาน RFC 3550 โดย IETF
RTP ทำงานบน UDP เป็นหลัก เนื่องจาก:
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836', 'nodeBorder': '#d79921'}}}%%
packet-beta
0-1: "V=2"
2: "P"
3: "X"
4-7: "CC"
8: "M"
9-15: "PT (Payload Type)"
16-31: "Sequence Number (เลขลำดับ)"
32-63: "Timestamp (ตราเวลา)"
64-95: "SSRC (Synchronization Source)"
96-127: "CSRC (Contributing Source) [optional]"
128-159: "Extension Header [optional]"
160-191: "Payload Data (ข้อมูลเสียง/วิดีโอ)"
คำอธิบายฟิลด์สำคัญใน RTP Header:
RTCP (RTP Control Protocol) เป็นโปรโตคอลคู่กับ RTP ทำหน้าที่ตรวจสอบคุณภาพการส่งข้อมูล โดยปกติจะส่งบน Port ถัดจาก RTP +1
| ประเภท RTCP Packet | ชื่อเต็ม | หน้าที่ |
|---|---|---|
| SR (200) | Sender Report | สถิติจากผู้ส่ง: packets sent, bytes sent, timestamp |
| RR (201) | Receiver Report | สถิติจากผู้รับ: packet loss, jitter, delay |
| SDES (202) | Source Description | ข้อมูลผู้ส่ง: CNAME, NAME, EMAIL |
| BYE (203) | Goodbye | แจ้งการสิ้นสุด session |
| APP (204) | Application-Defined | ข้อมูล custom ของแอปพลิเคชัน |
RTP Timestamp ไม่ได้แสดงเวลาจริง แต่เป็น จำนวน sampling unit นับจากจุดเริ่มต้น
สูตรคำนวณ Timestamp:
โดยที่:
ตัวอย่างการคำนวณ:
สมมติใช้ codec G.711 (PCMU) ที่มี sampling rate 8,000 Hz และส่งข้อมูลทุก 20ms (0.02 วินาที)
12345 (random start)12345 + 160 = 1250512505 + 160 = 12665การคำนวณ Jitter (ความไม่สม่ำเสมอของ Delay):
โดยที่ D(i-1, i) คือความต่างของ relative transit time ระหว่างแพ็กเก็ตสองชุด
import struct
import socket
import time
from dataclasses import dataclass
from typing import Optional
@dataclass
class RTPPacket:
"""
โครงสร้างข้อมูลสำหรับ RTP Packet
ตาม RFC 3550 - Real-time Transport Protocol
"""
version: int # รุ่น RTP (ควรเป็น 2)
padding: bool # มี padding หรือไม่
extension: bool # มี extension header หรือไม่
marker: bool # marker bit
payload_type: int # ประเภทของ codec
sequence_number: int # เลขลำดับแพ็กเก็ต
timestamp: int # RTP timestamp
ssrc: int # Synchronization Source ID
payload: bytes # ข้อมูลเสียง/วิดีโอ
def parse_rtp_packet(data: bytes) -> Optional[RTPPacket]:
"""
แปลง raw bytes เป็น RTP Packet object
Args:
data: ข้อมูล bytes ของ RTP packet ที่รับมา
Returns:
RTPPacket object หากแปลงสำเร็จ, None หากข้อมูลไม่ถูกต้อง
"""
# ตรวจสอบขนาดขั้นต่ำของ RTP header (12 bytes)
if len(data) < 12:
print(f"[ERROR] ข้อมูลสั้นเกินไป: {len(data)} bytes (ต้องการอย่างน้อย 12 bytes)")
return None
# แกะ RTP header (12 bytes แรก) ด้วย struct.unpack
# Format: !BBHII = network byte order, 2 bytes, 2 bytes, 4 bytes, 4 bytes
first_byte, second_byte, seq_num, timestamp, ssrc = struct.unpack('!BBHII', data[:12])
# ดึงค่าจาก byte แรก
version = (first_byte >> 6) & 0x03 # bits 7-6
padding = bool((first_byte >> 5) & 0x01) # bit 5
extension = bool((first_byte >> 4) & 0x01) # bit 4
cc = first_byte & 0x0F # bits 3-0 (CSRC count)
# ดึงค่าจาก byte ที่สอง
marker = bool((second_byte >> 7) & 0x01) # bit 7
payload_type = second_byte & 0x7F # bits 6-0
# ตรวจสอบ version
if version != 2:
print(f"[WARNING] RTP Version ไม่ถูกต้อง: {version} (คาดหวัง 2)")
return None
# คำนวณตำแหน่งเริ่มต้นของ payload (ข้ามส่วน CSRC)
header_length = 12 + (cc * 4) # Header + CSRC identifiers
payload = data[header_length:]
return RTPPacket(
version=version,
padding=padding,
extension=extension,
marker=marker,
payload_type=payload_type,
sequence_number=seq_num,
timestamp=timestamp,
ssrc=ssrc,
payload=payload
)
def get_codec_name(payload_type: int) -> str:
"""
แปลง Payload Type number เป็นชื่อ codec
ตาม RFC 3551
"""
# ตารางการแม็ปของ standard payload types
codec_map = {
0: "PCMU (G.711 µ-law, 8kHz)",
3: "GSM (6.10, 8kHz)",
4: "G.723 (8kHz)",
8: "PCMA (G.711 A-law, 8kHz)",
9: "G.722 (16kHz)",
18: "G.729 (8kHz)",
26: "JPEG Video",
31: "H.261 Video",
34: "H.263 Video",
96: "Dynamic (ต้องดูจาก SDP)", # 96-127 = dynamic
}
if 96 <= payload_type <= 127:
return f"Dynamic Payload Type {payload_type} (ดูจาก SDP)"
return codec_map.get(payload_type, f"Unknown PT={payload_type}")
def monitor_rtp_stream(host: str = "0.0.0.0", port: int = 5004, duration: int = 10):
"""
ตรวจสอบและวิเคราะห์ RTP stream แบบ real-time
Args:
host: IP address ที่จะรับฟัง (0.0.0.0 = ทุก interface)
port: UDP port สำหรับ RTP (ค่าเริ่มต้น 5004)
duration: ระยะเวลาการตรวจสอบ (วินาที)
"""
# สร้าง UDP socket สำหรับรับ RTP packets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((host, port))
sock.settimeout(1.0) # timeout 1 วินาที
print(f"🎧 กำลังตรวจสอบ RTP stream บน {host}:{port}")
print(f"⏱️ ระยะเวลา: {duration} วินาที")
print("-" * 60)
# ตัวแปรสำหรับเก็บสถิติ
packets_received = 0
packets_lost = 0
last_seq = None
start_time = time.time()
while time.time() - start_time < duration:
try:
data, addr = sock.recvfrom(4096) # รับข้อมูลสูงสุด 4096 bytes
packet = parse_rtp_packet(data)
if packet:
packets_received += 1
# ตรวจสอบ packet loss โดยดู sequence number
if last_seq is not None:
expected_seq = (last_seq + 1) % 65536 # wraps around ที่ 65535
if packet.sequence_number != expected_seq:
lost = (packet.sequence_number - expected_seq) % 65536
packets_lost += lost
print(f" ⚠️ Packet loss! คาดว่า seq={expected_seq}, ได้รับ seq={packet.sequence_number}")
print(f" สูญหายไป {lost} packet(s)")
last_seq = packet.sequence_number
# แสดงข้อมูล packet
codec = get_codec_name(packet.payload_type)
print(f"📦 Packet #{packets_received:4d} | "
f"Seq: {packet.sequence_number:5d} | "
f"TS: {packet.timestamp:10d} | "
f"SSRC: {packet.ssrc:08X} | "
f"Codec: {codec}")
except socket.timeout:
continue # ไม่มีข้อมูลมาใน 1 วินาที, วนซ้ำ
# สรุปสถิติ
sock.close()
total = packets_received + packets_lost
loss_rate = (packets_lost / total * 100) if total > 0 else 0
print("\n" + "=" * 60)
print("📊 สรุปผลการตรวจสอบ RTP Stream")
print(f" รับได้: {packets_received} packets")
print(f" สูญหาย: {packets_lost} packets")
print(f" Loss Rate: {loss_rate:.2f}%")
print(f" คุณภาพ: {'✅ ดี' if loss_rate < 1 else '⚠️ ปานกลาง' if loss_rate < 5 else '❌ แย่'}")
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
# จำลองการแปลง RTP packet จาก raw bytes
# สร้าง RTP packet ตัวอย่างด้วยมือ
sample_rtp = struct.pack('!BBHII',
0x80, # V=2, P=0, X=0, CC=0
0x00, # M=0, PT=0 (PCMU)
1234, # Sequence Number
12345678, # Timestamp
0xDEADBEEF # SSRC
) + b'\x00' * 160 # 160 bytes of audio payload (20ms of G.711)
print("=== ทดสอบ RTP Packet Parser ===")
packet = parse_rtp_packet(sample_rtp)
if packet:
print(f"Version: {packet.version}")
print(f"Payload Type: {packet.payload_type} → {get_codec_name(packet.payload_type)}")
print(f"Sequence Number: {packet.sequence_number}")
print(f"Timestamp: {packet.timestamp}")
print(f"SSRC: {packet.ssrc:08X}")
print(f"Payload Size: {len(packet.payload)} bytes")
| Codec | Payload Type | Sampling Rate | Bitrate | ใช้สำหรับ |
|---|---|---|---|---|
| G.711 PCMU | 0 | 8 kHz | 64 kbps | VoIP คุณภาพ telephony |
| G.711 PCMA | 8 | 8 kHz | 64 kbps | VoIP คุณภาพ telephony (A-law) |
| G.722 | 9 | 16 kHz | 64 kbps | HD Voice, Wideband |
| G.729 | 18 | 8 kHz | 8 kbps | VoIP ประหยัด bandwidth |
| G.723.1 | 4 | 8 kHz | 5.3/6.3 kbps | Low bandwidth VoIP |
| Opus | Dynamic | 8-48 kHz | 6-510 kbps | Modern WebRTC, ยืดหยุ่นสูง |
| H.264 | Dynamic | - | Variable | Video conferencing |
| VP8 | Dynamic | - | Variable | WebRTC video |
RTP ดั้งเดิมไม่มีการเข้ารหัสข้อมูล ทำให้เสี่ยงต่อ:
SRTP (Secure RTP) กำหนดในมาตรฐาน RFC 3711 (2004) แก้ไขปัญหาเหล่านี้โดยเพิ่ม:
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
flowchart TB
subgraph SENDER["ฝั่งผู้ส่ง (Sender)"]
P1["🎤 Audio/Video - Payload"]
P2["RTP Packet - Assembly"]
P3["AES Counter Mode - Encryption - (เข้ารหัส Payload)"]
P4["HMAC-SHA1 - Authentication - (สร้าง MAC)"]
P5["📤 SRTP Packet - (พร้อมส่ง)"]
end
subgraph KEYS["Key Management - (จัดการ Key)"]
K1["Master Key - (128/256 bit)"]
K2["Key Derivation - Function (KDF)"]
K3["Session Keys: - • Cipher Key - • Salt Key - • Auth Key"]
end
subgraph RECEIVER["ฝั่งผู้รับ (Receiver)"]
R1["📥 SRTP Packet"]
R2["Replay Check - (ตรวจ seq window)"]
R3["HMAC Verify - (ตรวจ integrity)"]
R4["AES Decrypt - (ถอดรหัส)"]
R5["🔊 Audio/Video - Output"]
end
P1 --> P2 --> P3 --> P4 --> P5
K1 --> K2 --> K3
K3 --> P3
K3 --> P4
P5 -.->|"Network"| R1
R1 --> R2 --> R3 --> R4 --> R5
style SENDER fill:#98971a,color:#ebdbb2,stroke:#b8bb26
style KEYS fill:#d79921,color:#282828,stroke:#fabd2f
style RECEIVER fill:#458588,color:#ebdbb2,stroke:#83a598
SRTP ใช้ AES Counter Mode (AES-CTR) ในการเข้ารหัส payload:
การสร้าง Keystream:
โดยที่:
การสร้าง Authentication Tag:
โดยที่:
| วิธีการแลกเปลี่ยน Key | มาตรฐาน | ความปลอดภัย | ใช้ในระบบ |
|---|---|---|---|
| SDES (SDP Security Descriptions) | RFC 4568 | ปานกลาง (key ใน SDP) | Legacy SIP systems |
| DTLS-SRTP | RFC 5764 | สูง (Perfect Forward Secrecy) | WebRTC (บังคับใช้) |
| MIKEY (Multimedia Internet KEYing) | RFC 3830 | สูง | IMS, Enterprise VoIP |
| ZRTP | RFC 6189 | สูงมาก (ไม่ต้องการ PKI) | Zfone, Signal |
SRTCP เป็นส่วนขยายของ SRTP สำหรับรักษาความปลอดภัยของ RTCP packets:
SIP (Session Initiation Protocol) คือโปรโตคอลมาตรฐานสำหรับการ Signaling ในการสร้าง, ปรับเปลี่ยน, และยุติ multimedia session กำหนดในมาตรฐาน RFC 3261 SIP เป็น text-based protocol คล้าย HTTP ทำให้เข้าใจและ debug ได้ง่าย
SIP ทำหน้าที่ เฉพาะ Signaling — ไม่ส่งข้อมูลเสียงหรือวิดีโอ ข้อมูลจริงส่งผ่าน RTP/SRTP
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
flowchart TB
subgraph CLIENTS["SIP Clients (User Agents)"]
UA1["📱 Alice's SIP Phone - UA: sip:alice@example.com"]
UA2["💻 Bob's Softphone - UA: sip:bob@example.com"]
end
subgraph SERVERS["SIP Servers"]
PROXY["🔄 SIP Proxy Server - (ส่งต่อ requests)"]
REG["📋 Registrar Server - (เก็บ location ของ UA)"]
REDIR["↩️ Redirect Server - (แนะนำ route ใหม่)"]
B2B["🔀 B2BUA - (Back-to-Back User Agent)"]
end
subgraph INFRA["Infrastructure"]
DNS["🌐 DNS/ENUM - (ค้นหา SIP URI)"]
DB["🗄️ Location Service - (IP: port ของ UA)"]
end
UA1 <-->|"SIP Signaling"| PROXY
UA2 <-->|"SIP Signaling"| PROXY
PROXY <--> REG
PROXY <--> REDIR
PROXY <--> B2B
REG <--> DB
PROXY <--> DNS
UA1 <-.->|"RTP Media (Audio/Video)"| UA2
style CLIENTS fill:#689d6a,color:#ebdbb2,stroke:#8ec07c
style SERVERS fill:#458588,color:#ebdbb2,stroke:#83a598
style INFRA fill:#504945,color:#ebdbb2,stroke:#665c54
SIP ใช้ข้อความแบบ text ซึ่งแบ่งเป็น Requests และ Responses:
SIP Request Methods:
| Method | หน้าที่ | RFC |
|---|---|---|
| INVITE | ชวน/เริ่ม session | RFC 3261 |
| ACK | ยืนยันการรับ final response | RFC 3261 |
| BYE | ยุติ session | RFC 3261 |
| CANCEL | ยกเลิก pending request | RFC 3261 |
| REGISTER | ลงทะเบียน location กับ Registrar | RFC 3261 |
| OPTIONS | ถาม capabilities | RFC 3261 |
| SUBSCRIBE | subscribe to event | RFC 3265 |
| NOTIFY | แจ้ง event ให้ subscriber | RFC 3265 |
| REFER | ให้ UA โทรหาคนอื่น (call transfer) | RFC 3515 |
| MESSAGE | ส่ง instant message | RFC 3428 |
SIP Response Codes:
| Code Range | ความหมาย | ตัวอย่าง |
|---|---|---|
| 1xx | Provisional (กำลังดำเนินการ) | 100 Trying, 180 Ringing |
| 2xx | Success (สำเร็จ) | 200 OK |
| 3xx | Redirection (เปลี่ยนทาง) | 302 Moved Temporarily |
| 4xx | Client Error (ผิดพลาดจากฝั่ง client) | 403 Forbidden, 404 Not Found |
| 5xx | Server Error (ผิดพลาดจาก server) | 500 Server Internal Error |
| 6xx | Global Failure (ล้มเหลวทุกที่) | 603 Decline |
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
sequenceDiagram
participant A as "📱 Alice (Caller)"
participant P as "🔄 SIP Proxy"
participant B as "💻 Bob (Callee)"
Note over A,B: ขั้นตอนที่ 1: Registration (ลงทะเบียน)
A->>P: REGISTER sip:proxy.example.com
P-->>A: 200 OK
Note over A,B: ขั้นตอนที่ 2: Call Setup (สร้างสาย)
A->>P: INVITE sip:bob@example.com
P->>B: INVITE sip:bob@example.com
B-->>P: 100 Trying
P-->>A: 100 Trying
B-->>P: 180 Ringing 🔔
P-->>A: 180 Ringing 🔔
B-->>P: 200 OK
P-->>A: 200 OK
A->>P: ACK
P->>B: ACK
Note over A,B: ขั้นตอนที่ 3: Media Exchange (สนทนา)
A-->>B: 🔊 RTP/SRTP Media Stream
Note over A,B: ขั้นตอนที่ 4: Call Teardown (วางสาย)
B->>P: BYE
P->>A: BYE
A-->>P: 200 OK
P-->>B: 200 OK
SIP ใช้ SDP (Session Description Protocol) ตาม RFC 4566 เพื่อบอกรายละเอียด session เช่น codec, port, IP address
ตัวอย่าง SDP Offer จาก Alice:
v=0
o=alice 2890844526 2890844527 IN IP4 192.168.1.10
s=Phone Call
c=IN IP4 192.168.1.10
t=0 0
m=audio 49170 RTP/AVP 0 8 18
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=ptime:20
a=sendrecv
คำอธิบาย SDP fields:
v= — version (ต้องเป็น 0)o= — origin (username, session-id, version, nettype, addrtype, address)s= — session namec= — connection info (network type, address type, IP)t= — timing (start, stop = 0,0 หมายถึง unbounded)m= — media (type, port, protocol, payload types)a=rtpmap: — แม็ป payload type เข้ากับ codeca=ptime: — packetization time (ms ต่อแพ็กเก็ต)SIP มีช่องโหว่ด้านความปลอดภัยหลายประการ:
1. SIP Digest Authentication:
SIP ใช้ HTTP Digest Authentication ตาม RFC 3261:
ปัญหา: ใช้ MD5 ซึ่งปัจจุบันถือว่า ไม่ปลอดภัย (สามารถ brute-force ได้) ควรใช้ SIP over TLS แทน
2. การส่ง SIP บน TLS:
sips:alice@example.com (S = Secure)H.323 คือมาตรฐานของ ITU-T (International Telecommunication Union) สำหรับระบบการสื่อสารมัลติมีเดียบนเครือข่าย packet-based ออกมาตั้งแต่ปี 1996 ก่อน SIP มาก H.323 เป็น suite ของโปรโตคอลที่ประกอบด้วยส่วนต่าง ๆ หลายชิ้น
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
flowchart TD
H323["H.323 Suite - (ชุดโปรโตคอล)"]
H323 --> TERM["📱 Terminal - (อุปกรณ์ปลายทาง)"]
H323 --> GK["🔑 Gatekeeper - (ควบคุมการเข้าถึง)"]
H323 --> GW["🌉 Gateway - (เชื่อม PSTN)"]
H323 --> MCU["🎛️ MCU - (Multipoint Control Unit)"]
H323 --> PROTOCOLS["โปรโตคอลภายใน"]
PROTOCOLS --> H225["H.225.0 - Call Signaling - (TCP port 1720)"]
PROTOCOLS --> H245["H.245 - Media Control - (capability exchange)"]
PROTOCOLS --> H235["H.235 - Security"]
PROTOCOLS --> H239["H.239 - Dual Video Stream"]
H323 --> CODECS["Codecs ที่รองรับ"]
CODECS --> AUDIO["เสียง: G.711, G.722, G.723.1, G.728, G.729"]
CODECS --> VIDEO["วิดีโอ: H.261, H.263, H.264, H.265"]
CODECS --> DATA["ข้อมูล: T.120 - (application sharing)"]
style H323 fill:#d79921,color:#282828,stroke:#fabd2f
style PROTOCOLS fill:#458588,color:#ebdbb2,stroke:#83a598
style CODECS fill:#98971a,color:#ebdbb2,stroke:#b8bb26
| คุณสมบัติ | H.323 | SIP |
|---|---|---|
| ผู้กำหนดมาตรฐาน | ITU-T | IETF |
| รูปแบบข้อความ | Binary (ASN.1) | Text (คล้าย HTTP) |
| ความซับซ้อน | สูงมาก | ปานกลาง |
| การ setup | ช้า (หลาย round trips) | เร็วกว่า |
| NAT Traversal | ยาก | ยากแต่มีทางออกมากกว่า |
| Scalability | จำกัด | ดีกว่า |
| Extensibility | ยาก | ง่ายกว่า |
| การใช้งานปัจจุบัน | Legacy, ลดลง | ครองตลาด |
| Interoperability | ดี (ใช้มานาน) | ดี (ecosystem ใหญ่) |
| ตัวอย่างใช้งาน | ระบบ Video Conference เก่า | PBX, softphone, WebRTC |
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
mindmap
root((VoIP Threats\nภัยคุกคาม VoIP))
Eavesdropping
RTP Stream Capture
SIP Message Interception
Credential Theft
Denial of Service
SIP Flood
RTP Flood
Resource Exhaustion
Fraud & Abuse
Toll Fraud / SPIT
Caller ID Spoofing
Vishing attacks
Man-in-the-Middle
SIP Hijacking
RTP Injection
Registration Hijacking
Quality Attacks
Jitter Injection
Packet Dropping
Delay Attacks
เนื่องจาก RTP ปกติไม่เข้ารหัส ผู้โจมตีที่อยู่ในเครือข่ายเดียวกันสามารถ:
rtp หรือ udp.port >= 10000 && udp.port <= 20000ตัวอย่าง Wireshark capture filter สำหรับ RTP:
udp && (udp.port >= 10000 && udp.port <= 65535)
ผู้โจมตีส่ง REGISTER message ปลอมเพื่อ overwrite location ของเหยื่อ:
REGISTER sip:example.com SIP/2.0
Via: SIP/2.0/UDP attacker.evil.com:5060;branch=z9hG4bKnasty
From: "Bob" <sip:bob@example.com>;tag=hijack123
To: <sip:bob@example.com>
Contact: <sip:bob@attacker.evil.com> ← แทนที่ด้วย IP ของผู้โจมตี
Expires: 3600
Content-Length: 0
ผลลัพธ์: สายโทรที่มาหา Bob จะถูกส่งไปยังผู้โจมตีแทน
VoIP มักใช้ Voice VLAN แยกต่างหาก ผู้โจมตีสามารถ:
ผู้โจมตีพยายาม brute-force SIP credentials เพื่อใช้ระบบโทรศัพท์โทรไปยังหมายเลขระหว่างประเทศ:
ขั้นตอนการวิเคราะห์ VoIP traffic ใน Wireshark:
sip || rtp
# ทดสอบ SIP server ด้วย INVITE flood
sipp -sn uac -d 30000 -l 10 -r 5 192.168.1.100:5060
# พารามิเตอร์:
# -sn uac = ใช้ script สำหรับ UAC (caller)
# -d 30000 = duration ของแต่ละ call = 30 วินาที
# -l 10 = จำนวน calls พร้อมกันสูงสุด 10
# -r 5 = rate 5 calls ต่อวินาที
# ตัวอย่าง: ตรวจสอบว่า SIP endpoint รองรับ SRTP หรือไม่
import socket
import ssl
def check_sip_tls_support(host: str, port: int = 5061) -> dict:
"""
ตรวจสอบว่า SIP server รองรับ TLS หรือไม่
Args:
host: hostname หรือ IP ของ SIP server
port: port (5061 สำหรับ SIP/TLS)
Returns:
dict ที่มีข้อมูล TLS certificate และการรองรับ
"""
result = {
"host": host,
"port": port,
"tls_supported": False,
"cipher": None,
"cert_subject": None,
"cert_expiry": None,
"error": None
}
try:
# สร้าง SSL context
context = ssl.create_default_context()
context.check_hostname = False # สำหรับ testing เท่านั้น
context.verify_mode = ssl.CERT_NONE # สำหรับ testing เท่านั้น
# สร้าง TCP connection
raw_sock = socket.create_connection((host, port), timeout=5)
# Wrap ด้วย TLS
tls_sock = context.wrap_socket(raw_sock, server_hostname=host)
# ดึงข้อมูล TLS
result["tls_supported"] = True
result["cipher"] = tls_sock.cipher()
cert = tls_sock.getpeercert()
if cert:
result["cert_subject"] = dict(
x[0] for x in cert.get('subject', [])
)
result["cert_expiry"] = cert.get('notAfter')
tls_sock.close()
except ConnectionRefusedError:
result["error"] = "Connection refused — อาจไม่รองรับ TLS"
except ssl.SSLError as e:
result["error"] = f"SSL Error: {e}"
except Exception as e:
result["error"] = f"Error: {e}"
return result
def check_srtp_in_sdp(sdp_content: str) -> dict:
"""
วิเคราะห์ SDP เพื่อตรวจสอบการรองรับ SRTP
Args:
sdp_content: ข้อมูล SDP ที่ได้รับจาก SIP INVITE/200 OK
Returns:
dict ที่มีผลการวิเคราะห์
"""
lines = sdp_content.strip().split('\n')
result = {
"srtp_supported": False,
"rtp_only": False,
"crypto_suites": [],
"media_ports": [],
"codecs": []
}
for line in lines:
line = line.strip()
# ตรวจหา SRTP ใน media description
# m=audio 5004 RTP/SAVP ... (SAVP = Secure AVP)
if line.startswith('m='):
parts = line.split()
if len(parts) >= 3:
protocol = parts[2]
if 'SAVP' in protocol: # Secure Audio/Video Profile
result["srtp_supported"] = True
elif 'AVP' in protocol: # ปกติ (ไม่ปลอดภัย)
result["rtp_only"] = True
# เก็บ port
if len(parts) >= 2:
try:
result["media_ports"].append(int(parts[1]))
except ValueError:
pass
# ตรวจหา crypto suites (SDES)
# a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:...
elif line.startswith('a=crypto:'):
parts = line.split()
if len(parts) >= 3:
result["crypto_suites"].append(parts[1])
# ตรวจหา codec
elif line.startswith('a=rtpmap:'):
# a=rtpmap:0 PCMU/8000
codec_part = line.split(':', 1)[1] if ':' in line else ''
parts = codec_part.split()
if len(parts) >= 2:
result["codecs"].append(parts[1])
return result
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
# ทดสอบ SRTP detection ใน SDP
sample_sdp = """v=0
o=alice 2890844526 2890844527 IN IP4 192.168.1.10
s=Secure Call
c=IN IP4 192.168.1.10
t=0 0
m=audio 5004 RTP/SAVP 0 8
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3jek7Ti1iGqtq/sNJJx1S4jF0
a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=ptime:20
"""
print("=== วิเคราะห์ SRTP ใน SDP ===")
analysis = check_srtp_in_sdp(sample_sdp)
print(f"รองรับ SRTP: {analysis['srtp_supported']}")
print(f"ใช้ RTP ปกติ: {analysis['rtp_only']}")
print(f"Crypto Suites: {analysis['crypto_suites']}")
print(f"Media Ports: {analysis['media_ports']}")
print(f"Codecs: {analysis['codecs']}")
if analysis['srtp_supported']:
print("\n✅ ดี: Session นี้ใช้ SRTP — เสียงถูกเข้ารหัส")
else:
print("\n❌ เตือน: Session นี้ใช้ RTP ปกติ — เสียงไม่ได้เข้ารหัส!")
| มาตรการ | รายละเอียด | ระดับความสำคัญ |
|---|---|---|
| ใช้ SRTP | เข้ารหัส media stream ทั้งหมด | 🔴 สูงมาก |
| ใช้ SIP/TLS | เข้ารหัส signaling | 🔴 สูงมาก |
| VLAN Separation | แยก Voice VLAN ออกจาก Data VLAN | 🔴 สูงมาก |
| Strong Passwords | ใช้รหัสผ่านที่ซับซ้อนสำหรับ SIP accounts | 🔴 สูงมาก |
| Rate Limiting | จำกัดจำนวน REGISTER/INVITE ต่อวินาที | 🟠 สูง |
| Firewall/SBC | ใช้ Session Border Controller | 🟠 สูง |
| Fail2Ban สำหรับ SIP | block IP ที่ login ผิดพลาดหลายครั้ง | 🟠 สูง |
| Disable Unused Codecs | จำกัดเฉพาะ codec ที่ต้องการ | 🟡 ปานกลาง |
| QoS & DSCP Marking | รับประกันคุณภาพเสียง | 🟡 ปานกลาง |
| Log Analysis | ตรวจสอบ CDR log หาพฤติกรรมผิดปกติ | 🟡 ปานกลาง |
| NAT Traversal (STUN/TURN) | แก้ปัญหา one-way audio | 🟢 พื้นฐาน |
| Network Monitoring | ตรวจสอบ VoIP traffic ด้วย RTCP | 🟢 พื้นฐาน |
SBC (Session Border Controller) คืออุปกรณ์ที่ทำหน้าที่เป็น security gateway สำหรับ VoIP:
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#928374', 'lineColor': '#d5c4a1', 'background': '#282828', 'mainBkg': '#3c3836'}}}%%
flowchart LR
subgraph EXTERNAL["Internet / Untrusted Zone"]
EXT1["📱 Remote SIP Phone"]
EXT2["☎️ External SIP Trunk"]
EXT3["👿 Attacker"]
end
subgraph SBC_ZONE["Session Border Controller"]
SBC["🛡️ SBC - • NAT Traversal - • Topology Hiding - • DoS Protection - • Media Transcoding - • Encryption Enforcement - • Rate Limiting"]
end
subgraph INTERNAL["Internal Network / Trusted Zone"]
INT1["🖥️ SIP PBX Server"]
INT2["💻 IP Phones"]
INT3["📟 SIP Softphone"]
end
EXT1 <-->|"SIP/TLS + SRTP\n(encrypted)"| SBC
EXT2 <-->|"SIP Trunk"| SBC
EXT3 -->|"Attack traffic\n(blocked)"| SBC
SBC <-->|"SIP (plaintext OK)\n+ RTP"| INT1
INT1 <--> INT2
INT1 <--> INT3
style EXTERNAL fill:#cc241d,color:#ebdbb2,stroke:#fb4934
style SBC_ZONE fill:#d79921,color:#282828,stroke:#fabd2f
style INTERNAL fill:#98971a,color:#ebdbb2,stroke:#b8bb26
# /etc/fail2ban/filter.d/asterisk.conf
# กฎสำหรับตรวจจับ SIP brute force
[Definition]
# ตรวจหา log patterns ที่บ่งบอกว่ามีการพยายาม login ผิดพลาด
failregex = NOTICE.* .*: Registration from '.*' failed for '<HOST>:.*' - Wrong password
NOTICE.* .*: Registration from '.*' failed for '<HOST>:.*' - No matching peer found
NOTICE.* .*: Registration from '.*' failed for '<HOST>:.*' - Username/auth name mismatch
SECURITY.* .*: Invalid SIP message from <HOST>
ignoreregex =
# /etc/fail2ban/jail.local
# [asterisk]
# enabled = true
# port = 5060,5061
# filter = asterisk
# logpath = /var/log/asterisk/messages
# maxretry = 5 ← ผิดพลาดได้ไม่เกิน 5 ครั้ง
# findtime = 21600 ← ภายใน 6 ชั่วโมง
# bantime = 86400 ← แบนเป็นเวลา 24 ชั่วโมง
ขั้นตอนที่ 1: Capture SIP/RTP Traffic
# Capture ด้วย tcpdump บน Linux
sudo tcpdump -i eth0 -w voip_capture.pcap 'port 5060 or (udp and portrange 10000-20000)'
# พารามิเตอร์:
# -i eth0 = interface ที่ต้องการ capture
# -w voip_capture = บันทึกเป็นไฟล์ pcap
# port 5060 = SIP port
# portrange 10000-20000 = RTP port range ที่ใช้บ่อย
ขั้นตอนที่ 2: วิเคราะห์ใน Wireshark
Display Filter สำหรับ VoIP analysis:
1. ดู SIP calls ทั้งหมด: sip
2. ดูเฉพาะ INVITE: sip.Method == "INVITE"
3. ดู SIP errors: sip.Status-Code >= 400
4. ดู RTP stream: rtp
5. ดู RTCP statistics: rtcp
6. ดู SIP + RTP รวม: sip || rtp
7. ดู SRTP (encrypted RTP): srtp
ขั้นตอนที่ 3: วิเคราะห์ RTP Statistics
ไปที่ Wireshark menu: Telephony → RTP → RTP Streams
ข้อมูลที่ได้:
Multimedia Network Protocols เป็นส่วนสำคัญของระบบการสื่อสารสมัยใหม่ โดยมีประเด็นสำคัญที่ควรจำ:
ด้านโปรโตคอลหลัก:
ด้านความปลอดภัย:
ความสัมพันธ์ระหว่าง Protocol:
Application (Softphone)
→ ใช้ SIP/H.323 สำหรับ Signaling (negotiate codec, exchange IPs)
→ ใช้ RTP/SRTP สำหรับส่ง Media จริง ๆ
→ ใช้ RTCP เพื่อ monitor คุณภาพ
→ ทั้งหมดวิ่งบน UDP/IP
RFC 3550 — Schulzrinne, H., Casner, S., Frederick, R., & Jacobson, V. (2003). RTP: A Transport Protocol for Real-Time Applications. IETF.
URL: https://tools.ietf.org/html/rfc3550
RFC 3711 — Baugher, M., McGrew, D., Naslund, M., Carrara, E., & Norrman, K. (2004). The Secure Real-time Transport Protocol (SRTP). IETF.
URL: https://tools.ietf.org/html/rfc3711
RFC 3261 — Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A., Peterson, J., Sparks, R., Handley, M., & Schooler, E. (2002). SIP: Session Initiation Protocol. IETF.
URL: https://tools.ietf.org/html/rfc3261
RFC 4566 — Handley, M., Jacobson, V., & Perkins, C. (2006). SDP: Session Description Protocol. IETF.
URL: https://tools.ietf.org/html/rfc4566
RFC 3551 — Schulzrinne, H., & Casner, S. (2003). RTP Profile for Audio and Video Conferences with Minimal Control. IETF.
URL: https://tools.ietf.org/html/rfc3551
ITU-T H.323 — International Telecommunication Union. (2009). Packet-based Multimedia Communications Systems. ITU-T Recommendation H.323.
URL: https://www.itu.int/rec/T-REC-H.323
RFC 5764 — McGrew, D., & Rescorla, E. (2010). Datagram Transport Layer Security (DTLS) Extension to Establish Keys for the Secure Real-time Transport Protocol (SRTP). IETF.
URL: https://tools.ietf.org/html/rfc5764
RFC 6189 — Zimmermann, P., Johnston, A., & Callas, J. (2011). ZRTP: Media Path Key Agreement for Unicast Secure RTP. IETF.
URL: https://tools.ietf.org/html/rfc6189
Stallings, W. (2017). Network Security Essentials: Applications and Standards (6th ed.). Pearson.
Collier, M., & Endler, D. (2006). Hacking Exposed VoIP: Voice Over IP Security Secrets & Solutions. McGraw-Hill.
Porter, T. (2006). Practical VoIP Security. Syngress.