คู่มือเกมแลค › ต้นเหตุของการส่งซ้ำใน TCP
อุปกรณ์กลางทางตัด TCP option ทิ้ง Middlebox strips TCP options
ID สาเหตุ rt-sack-stripped · ผู้รับผิดชอบหลัก อินฟราเครือข่าย (ทีมอินฟรา) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
ถ้าไฟร์วอลล์หรืออุปกรณ์เร่งความเร็วบางตัวลบหรือแก้ TCP option เมื่อแพ็กเก็ตหายหลายตัว จะกู้คืนได้แค่ตัวเดียวต่อหนึ่งรอบไปกลับ หรือ window (ปริมาณที่ส่งได้ในครั้งเดียว) จะเล็กลงจนช้า
ทำไม “TCP normalization” ของไฟร์วอลล์ หรืออุปกรณ์เร่งความเร็วรุ่นเก่าลบ option SACK, timestamps และ window scaling → ผลคือ ถ้าแพ็กเก็ตหายหลายตัว จะกู้คืนได้ทีละตัวต่อรอบไปกลับ, window ถูกจำกัดไว้ที่ 64 KB → บนหน้าจอ ทุกครั้งที่หายจะค้างนานขึ้นมาก (ไม่มี SACK ก็ใช้ RACK-TLP ไม่ได้) แล้วตามด้วยอาการกรอเร็ว การส่งข้อมูลปริมาณมากอย่างแพตช์ก็ช้า
- อาการ
- ค้าง, กรอเร็ว
- ปัจจัย
- การหยุดชะงัก, ความหน่วง
- ใครเจอ
- บางพื้นที่/บาง ISP, ทั้งเซิร์ฟเวอร์
- เกิดเมื่อไร
- ตลอดเวลา
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก อินฟราเครือข่าย (ทีมอินฟรา) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา)
- งานฝั่งทีมอินฟรา
- เครือข่าย: ปิดการตั้งค่า TCP normalization ของอุปกรณ์นั้น, ตรวจ sequence randomization ของไฟร์วอลล์ด้วย, เทียบ option ใน SYN จาก packet capture ที่ปลายทั้งสองฝั่ง เครื่องเซิร์ฟเวอร์/OS: ตรวจว่าการเชื่อมต่อที่ไม่มี sack และ wscale ใน ss -ti กระจุกที่เส้นทางใดหรือไม่ (PC Windows บางเครื่องไม่ใช้ ts ตามการตั้งค่า การที่ขาดแค่ ts จึงอาจเป็นเรื่องปกติ), ตรวจว่า net.ipv4.tcp_sack ของเซิร์ฟเวอร์เป็น 1
- บนกราฟ
- สูงตลอดตั้งแต่แรก · จำนวนการกู้คืนที่เริ่มโดยไม่มี SACK (TcpExtTCPRenoRecovery)
- จุดที่ต้องดู
- ดูว่าแต่ละการเชื่อมต่อใน ss -ti มี sack และ wscale หรือไม่ ดูสัดส่วน TcpExtTCPRenoRecovery (การกู้คืนที่เริ่มโดยไม่มี SACK) ต่อ TcpExtTCPSackRecovery และ TcpExtTCPSACKDiscard (จำนวน SACK block ที่ทิ้งเพราะตัวเลขไม่สอดคล้องกัน) ใน nstat เส้นทางที่สงสัยให้ capture SYN ที่ปลายทั้งสองฝั่งแล้วเทียบ option (เช่น tcp.options.sack_perm ใน Wireshark)
- สัญญาณว่าใช่
- เฉพาะการเชื่อมต่อที่ผ่านเส้นทางหรืออุปกรณ์หนึ่งที่ไม่มี sack และ wscale และสัดส่วน TcpExtTCPRenoRecovery สูง option อนุญาต SACK ที่มีใน SYN ฝั่งส่งไม่มีใน SYN ฝั่งรับ ถ้าสาเหตุคือ sequence randomization option จะยังอยู่ แต่ TcpExtTCPSACKDiscard เพิ่มขึ้น
- สัญญาณว่าไม่ใช่
- ทุกการเชื่อมต่อไม่มี sack: ตรวจค่า net.ipv4.tcp_sack ของเซิร์ฟเวอร์ก่อน ถ้า option ครบและ TcpExtTCPSACKDiscard ไม่ขยับ การกู้คืนช้ามาจากที่อื่น (“thin stream กู้คืนช้า”)
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
- รายละเอียดเพิ่มเติม
- ถึง option ยังอยู่ SACK ก็อาจเสียได้ ถ้า sequence randomization ของไฟร์วอลล์เปลี่ยนแค่ sequence number ใน header แต่ไม่แก้ตัวเลขใน SACK ฝั่งส่งจะทิ้ง SACK ที่ตัวเลขไม่สอดคล้องกัน กรณีที่ปิด tcp_sack=0 บนเซิร์ฟเวอร์ไว้ตอนเกิดปัญหาความปลอดภัยของ SACK ในปี 2019 แล้วลืมเปิดคืน ก็ให้ผลแบบเดียวกัน
แหล่งอ้างอิง
- RFC 2018: TCP Selective Acknowledgment Options IETF
ถ้าไม่มี SACK และมีแค่ cumulative ACK จะรู้ได้แค่แพ็กเก็ตที่หายหนึ่งตัวต่อรอบไปกลับ - RFC 7323: TCP Extensions for High Performance IETF
ถ้าไม่มี option window scaling window จะใหญ่สุด 2^16 = 64 KiB - RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
RACK-TLP ต้องใช้ SACK - net/ipv4/tcp_output.c Linux kernel
TLP ของ Linux ถูกตั้งเวลาเฉพาะในการเชื่อมต่อที่ใช้ SACK - IP Sysctl Linux kernel
tcp_sack ค่าเริ่มต้น 1 (เปิด) - misc/ss.c iproute2
ss -ti แสดง ts, sack, wscale:ส่ง,รับ ตาม option ที่การเชื่อมต่อใช้ - tcp: limit payload size of sacked skbs Linux kernel
commit แก้ช่องโหว่การจัดการ SACK ปี 2019 (CVE-2019-11477) - Linux and FreeBSD Kernel: Multiple TCP-based remote denial of service vulnerabilities (NFLX-2019-001) Netflix
ตอนนั้นมีการแนะนำ tcp_sack=0 (ปิดการจัดการ SACK) เป็นมาตรการชั่วคราว - SNMP counter Linux kernel
TcpExtTCPRenoRecovery (เริ่มกู้คืนโดยไม่มี SACK) และ TcpExtTCPSackRecovery (เริ่มกู้คืนด้วย SACK), TcpExtTCPSACKDiscard (จำนวน SACK block ที่ไม่ถูกต้อง) - Display Filter Reference: Transmission Control Protocol Wireshark
display filter tcp.options.sack_perm (option อนุญาต SACK ใน SYN)
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: ต้นเหตุของการส่งซ้ำใน TCP
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (ค้าง)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง