ล็อกของไคลเอนต์นั้นยอดเยี่ยมมาก ตราบเท่าที่มันยังบอกอะไรบางอย่างกับเรา แต่แล้ววันหนึ่งคุณก็ชนกำแพง: แอปพลิเคชันเขียนแค่ connection reset สั้นๆ พร็อกซีในล็อกของตัวเองเงียบสนิท และเซิร์ฟเวอร์ปลายทางก็ยืนยันว่าทุกอย่างปกติดี ใครโกหก? ไม่มีใครโกหกหรอก แค่คุณกำลังมองปัญหาจากชั้นบนสุด แต่ความจริงซ่อนอยู่ที่ระดับแพ็กเก็ต และคุณต้องลงไปดูตรงนั้น

บทความนี้คือคู่มือวิศวกรรมฉบับละเอียดสำหรับการทำงานกับ tcpdump และ Wireshark ในกรณีที่ทราฟฟิกไหลผ่านพร็อกซี เราจะมาดูว่าผู้สังเกตเห็นอะไรบ้างก่อนพร็อกซีและหลังพร็อกซี ทำไมภายในทันเนล HTTPS ถึงเห็นแค่คำขอ CONNECT แล้วไม่มีอะไรเลย และวิธีแยกแยะจากดัมป์เดียวว่าการตัดการเชื่อมต่อเกิดฝั่งเรา หรือเกิดฝั่งเซิร์ฟเวอร์ปลายทาง นี่ไม่ใช่เรื่องการดักจับหรือสวมรอย HTTPS ระดับแอปพลิเคชัน แต่เป็นเรื่องระดับแพ็กเก็ตและการวินิจฉัยการตัดการเชื่อมต่ออย่างตรงไปตรงมา

บทนำ: เมื่อล็อกของไคลเอนต์ไม่เพียงพออีกต่อไป

ลองนึกภาพโครงสร้างพื้นฐานทั่วไป แอปของคุณเรียก API ภายนอกผ่านพร็อกซี HTTP อย่าง Proxeon ปกติทุกอย่างก็ทำงานได้ แต่ห้าเปอร์เซ็นต์ของคำขอกลับล้มเหลวด้วยข้อผิดพลาด และคุณก็ไม่เข้าใจว่าทำไม ล็อกแอปบอกแค่ fact ว่าการเชื่อมต่อขาด ล็อกพร็อกซีบอกว่าทันเนลถูกสร้างขึ้นแล้ว เซิร์ฟเวอร์ปลายทางอยู่นอกเหนือการควบคุมของคุณ คุณติดอยู่ระหว่างกล่องดำสามใบ

นี่แหละคือจุดที่การวินิจฉัยระดับแพ็กเก็ตเริ่มต้นขึ้น แพ็กเก็ตดัมป์คือบันทึกคำต่อคำของการสนทนาระหว่างเครื่องจักร บันทึกตรงๆ ไม่มีการตีความ และไม่มีสิทธิ์โกหก แพ็กเก็ตจะมาหรือไม่มาก็เท่านั้น ฟлаг RST จะตั้งหรือไม่ตั้งก็เท่านั้น TCP ไม่รู้จักการแสร้งทำ และถ้าคุณอ่านบันทึกนี้เป็น คุณจะเลิกเดาสุ่ม

จากคู่มือนี้คุณจะได้เรียนรู้: วิธีเก็บดัมป์ด้วยคำสั่ง tcpdump โดยไม่ทำให้ดิสก์เต็มไปด้วยกิกะไบต์, ฟิลเตอร์แสดงผลใดใน Wireshark ที่ช่วยประหยัดเวลาหลายชั่วโมง, วิธีอ่าน TLS แฮนด์เชกแม้ไม่ถอดรหัส, วิธีระบุตัวผู้ตัดการเชื่อมต่อจากแฟล็ก และวิธีถอดรหัสทราฟฟิกของตัวเองอย่างถูกกฎหมายผ่านตัวแปร SSLKEYLOGFILE ปิดท้ายด้วยเช็กลิสต์พร้อมใช้สำหรับติดต่อฝ่ายสนับสนุนและ FAQ ฉบับละเอียด

พื้นฐาน: สามเซกเมนต์ของการเชื่อมต่อเดียว

สิ่งแรกที่ต้องฝังในหัว: เมื่อไคลเอนต์ทำงานผ่านพร็อกซี นี่ไม่ใช่การเชื่อมต่อเดียว แต่เป็นการเชื่อมต่อ TCP อย่างน้อยสองอัน อันหนึ่งจากไคลเอนต์ถึงพร็อกซี อีกอันจากพร็อกซีถึงเซิร์ฟเวอร์ปลายทาง นี่คือรากฐาน ถ้าไม่เข้าใจตรงนี้ การวิเคราะห์ต่อไปก็ไม่มีความหมาย

ดัมป์คืออะไรและมีโครงสร้างอย่างไร

แพ็กเก็ตดัมป์คือลำดับของแพ็กเก็ตเครือข่ายที่ถูกจับบนอินเทอร์เฟซเครือข่ายเฉพาะของเครื่องเฉพาะ คำสำคัญคือ เฉพาะ คุณจะเห็นแค่ทราฟฟิกที่ผ่านจุดจับจริงๆ เท่านั้น เก็บดัมป์บนไคลเอนต์คุณเห็นบทสนทนาไคลเอนต์-พร็อกซี เก็บบนพร็อกซีคุณเห็นทั้งสองฝั่ง บนเซิร์ฟเวอร์ปลายทางเห็นแค่บทสนทนาพร็อกซี-เซิร์ฟเวอร์

แต่ละแพ็กเก็ตมีเฮดเดอร์ของแต่ละชั้น: Ethernet, IP, TCP หรือ UDP และเพย์โหลด สำหรับการวินิจฉัยการตัดการเชื่อมต่อ เราสนใจระดับ TCP เป็นหลัก: หมายเลขพอร์ต หมายเลขลำดับ (sequence) การตอบรับ (ACK) และแฟล็ก SYN, ACK, FIN, RST, PSH

โมเดลพร็อกซี: สองการเชื่อมต่อแทนที่จะเป็นหนึ่ง

มาดูเส้นทางของทราฟฟิกเมื่อทำงานกับพร็อกซี HTTP ในโหมดทันเนล:

  • เซกเมนต์ A (ไคลเอนต์ - พร็อกซี). ไคลเอนต์เปิดการเชื่อมต่อ TCP ไปยัง IP และพอร์ตของพร็อกซี ผ่านช่องทางนี้มันส่งคำสั่งให้สร้างทันเนล
  • เซกเมนต์ B (พร็อกซี - เซิร์ฟเวอร์ปลายทาง). พร็อกซีเปิดการเชื่อมต่อ TCP แยกต่างหากไปยังเซิร์ฟเวอร์ปลายทางในนามของตัวเอง นี่คือ src-IP อื่น src-พอร์ตอื่น สถานะอื่น
  • ทันเนลเชิงตรรกะ. หลังสร้างเสร็จ พร็อกซีเริ่มย้ายไบต์จากเซกเมนต์ A ไปเซกเมนต์ B และกลับกันแบบตาบอด มันไม่สนใจว่าข้างในคืออะไร

ทำไมสิ่งนี้สำคัญต่อการวินิจฉัย? เพราะการตัดการเชื่อมต่ออาจเกิดขึ้นบนเซกเมนต์ใดก็ได้ และจากมุมมองของไคลเอนต์ อาการจะเหมือนกัน - การเชื่อมต่อล่ม แต่สาเหตุและวิธีแก้ต่างกัน

พร็อกซี HTTP, SOCKS และการทำทันเนล

ในการขอ HTTP แบบไม่เข้ารหัส พร็อกซีจะเห็นทั้งเมธอด URL และเฮดเดอร์ แต่พอเป็น HTTPS ภาพก็เปลี่ยน ไคลเอนต์ไม่สามารถส่งคำขอแบบไม่เข้ารหัสให้พร็อกซีได้ - ไม่งั้นการเข้ารหัสก็ไร้ความหมาย จึงใช้กลไกทันเนล: ไคลเอนต์บอกพร็อกซีว่า เชื่อมฉันกับโฮสต์นี้ที่พอร์ตนี้ แล้วหลังจากนั้นอย่ายุ่ง คำสั่งนี้คือ CONNECT

เจาะลึก: ทำไมในทันเนลถึงเห็นแค่ CONNECT

นี่อาจเป็นสาเหตุที่พบบ่อยที่สุดของความงุนงงสำหรับวิศวกรที่เปิดดัมป์ทราฟฟิก HTTPS ผ่านพร็อกซีครั้งแรก คุณคาดว่าจะเห็นคำขอและคำตอบ แต่กลับเห็นแค่บรรทัดเดียวแล้วก็ตามด้วยข้อมูลอ่านไม่ออก มาดูกันว่าทำไม และทำไมมันถึงถูกต้องแล้ว

กายวิภาคของ CONNECT

เมื่อไคลเอนต์ต้องการสร้างการเชื่อมต่อแบบป้องกันผ่านพร็อกซี มันจะส่งคำขอแบบเปิดเผยให้พร็อกซีแบบนี้:

CONNECT api.example.com:443 HTTP/1.1\r\nHost: api.example.com:443\r\n\r\n

พร็อกซีเปิดการเชื่อมต่อ TCP ไปยัง api.example.com พอร์ต 443 และถ้าสำเร็จก็ตอบไคลเอนต์ว่า:

HTTP/1.1 200 Connection established\r\n\r\n

จากจุดนี้พร็อกซีกลายเป็นท่อโง่ๆ ทุกอย่างที่ไคลเอนต์ส่งต่อ พร็อกซีจะส่งต่อไปยังเซิร์ฟเวอร์แบบไบต์ต่อไบต์ และกลับกัน แล้วไคลเอนต์ส่งอะไรต่อไป? TLS ClientHello เริ่มการจับมือ การแลกเปลี่ยนแบบเข้ารหัส พร็อกซีไม่มีคีย์และไม่สามารถมองข้างในได้จริงๆ

สิ่งนี้หมายความว่าอย่างไรสำหรับผู้สังเกตที่มีดัมป์

ถ้าคุณเก็บดัมป์บนไคลเอนต์หรือบนพร็อกซี คุณจะเห็น:

  • การสร้างการเชื่อมต่อ TCP ไปยังพร็อกซี (SYN, SYN-ACK, ACK)
  • ข้อความเปิดเผยของคำขอ CONNECT พร้อมชื่อโฮสต์ปลายทางและพอร์ต
  • การตอบกลับของพร็อกซีเกี่ยวกับสถานะการสร้างทันเนล
  • จากนั้นมีแค่ TLS เรกคอร์ด สตรีมเข้ารหัส ซึ่งด้วยตาเปล่าอ่านได้แค่เมตาดาต้าของแฮนด์เชก

นี่คือข้อมูลเชิงลึกสำคัญ: ชื่อโฮสต์ปลายทางในดัมป์เห็นได้เสมอ - ในบรรทัด CONNECT แม้ไม่มีไบต์ที่ถอดรหัสได้เลย คุณก็รู้ว่าไคลเอนต์พยายามจะไปที่ไหน นี่คือข้อมูลล้ำค่าสำหรับการวินิจฉัย เพราะตัดคำถามที่ว่า คำขอไปที่นั่นจริงหรือเปล่า ออกไปได้ทันที

TLS SNI: แหล่งที่สองของชื่อโฮสต์

แม้ไม่มี CONNECT (เช่นในการเชื่อมต่อตรงโดยไม่มีพร็อกซี) ชื่อโฮสต์ก็มักเห็นได้ในฟิลด์ SNI ภายใน ClientHello Server Name Indication ถูกส่งแบบเปิดเผยที่จุดเริ่มต้นของการจับมือ Wireshark แสดงมันได้อย่างสวยงาม ในเครือข่ายสมัยใหม่ Encrypted Client Hello ที่ซ่อน SNI กำลังเป็นที่นิยมขึ้น แต่เมื่อทำงานผ่านทันเนล CONNECT มันก็ไม่รบกวนการวินิจฉัย เพราะชื่อโฮสต์ถูกบอกไว้แล้วใน CONNECT เอง

tcpdump ในทางปฏิบัติ: เก็บดัมป์โดยไม่ให้เป็นกิกะไบต์

มาลงมือกัน tcpdump คือยูทิลิตี้บรรทัดคำสั่งสำหรับจับแพ็กเก็ต มีให้ใช้ในระบบแบบ Unix เกือบทุกตัว ทรงพลัง เบา และขาดไม่ได้บนเซิร์ฟเวอร์ที่ไม่มี GUI มาดูสถานการณ์สำคัญๆ

การจับพื้นฐานบนอินเทอร์เฟซที่ต้องการ

ก่อนอื่นดูรายการอินเทอร์เฟซ:

tcpdump -D

จับบนอินเทอร์เฟซเฉพาะและแสดงบนหน้าจอ:

tcpdump -i eth0 -n

แฟล็ก -n ปิดการแปลงชื่อ เพื่อให้ tcpdump ไม่ช้าลงเพราะ DNS และแสดง IP ดิบ สิ่งนี้สำคัญ: การแปลงชื่อแบบเรียลไทม์บิดเบือนภาพและทำให้การจับช้าลง

การกรองตามโฮสต์และพอร์ต

จับทราฟฟิกทั้งหมดของอินเทอร์เฟซบนเซิร์ฟเวอร์ที่มีโหลดสูงคือทางสู่กิกะไบต์ขยะ กรองตั้งแต่แรก จับทราฟฟิกไปยังพร็อกซีเฉพาะตาม IP และพอร์ต:

tcpdump -i eth0 -n host 203.0.113.10 and port 8080

จับเฉพาะไปยังเซิร์ฟเวอร์ปลายทาง (มีประโยชน์ฝั่งพร็อกซี):

tcpdump -i eth0 -n host api.example.com and port 443

รวมกัน: ทราฟฟิกไปพร็อกซี หรือ เซิร์ฟเวอร์ปลายทาง:

tcpdump -i eth0 -n "(host 203.0.113.10 and port 8080) or (host 198.51.100.5 and port 443)"

สังเกตเครื่องหมายคำพูด: เมื่อในนิพจน์มีวงเล็บและตัวดำเนินการทางตรรกะ ให้ห่อฟิลเตอร์ด้วยเครื่องหมายคำพูด เพื่อให้เชลล์ไม่ตีความอักขระพิเศษ

เขียนลงไฟล์และรูปแบบที่ถูกต้อง

สำหรับการวิเคราะห์ใน Wireshark ในภายหลังต้องมีไฟล์รูปแบบ pcap แฟล็ก -w เขียนแพ็กเก็ตดิบลงไฟล์:

tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -w dump.pcap

จุดสำคัญมาก: -s 0 หรือพฤติกรรมเริ่มต้นสมัยใหม่จะจับแพ็กเก็ตทั้งหมด (snaplen) เวอร์ชันเก่าตัดแพ็กเก็ต ถ้าต้องการข้อมูลเต็ม ตรวจสอบว่า snaplen เพียงพอ:

tcpdump -i eth0 -n -s 0 host 203.0.113.10 and port 8080 -w dump.pcap

ถ้าต้องการแค่เฮดเดอร์สำหรับวินิจฉัยการตัดการเชื่อมต่อ (แฟล็ก, seq, ack) ไม่ใช่เนื้อหา ให้จำกัด snaplen เพื่อให้ไฟล์กะทัดรัดขึ้น:

tcpdump -i eth0 -n -s 96 host 203.0.113.10 and port 8080 -w headers.pcap

การหมุนไฟล์: ไม่ให้ดิสก์เต็ม

ในการวินิจฉัยปัญหาที่เกิดเป็นครั้งคราวเป็นเวลานาน การจับอาจดำเนินไปหลายชั่วโมง เพื่อไม่ให้ได้ไฟล์ใหญ่ยักษ์ไฟล์เดียว ใช้การหมุนตามขนาดและจำนวนไฟล์ แฟล็ก -C กำหนดขนาดไฟล์เป็นเมกะไบต์ -W จำนวนไฟล์ในบัฟเฟอร์วงแหวน:

tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -w dump-%Y%m%d-%H%M%S.pcap -C 100 -W 10

คำสั่งนี้จะสร้างไฟล์สูงสุดสิบไฟล์ ไฟล์ละร้อยเมกะไบต์ เมื่อไฟล์ที่สิบเต็ม tcpdump จะเริ่มเขียนทับไฟล์แรก วิธีนี้คุณจะเก็บทราฟฟิกล่าสุดประมาณหนึ่งกิกะไบต์เสมอ และไม่ทำให้ดิสก์เต็ม รูปแบบเวลาในชื่อไฟล์ทำให้อ่านคลังได้

ทางเลือกคือหมุนตามเวลา แฟล็ก -G กำหนดช่วงเวลาเป็นวินาที หลังจากนั้นสร้างไฟล์ใหม่:

tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -G 3600 -w dump-%Y%m%d-%H%M%S.pcap

ทุกชั่วโมงไฟล์ใหม่ สะดวกเมื่อต้องหา ช่วงเวลาที่เกิดเหตุในภายหลัง

จับรอบเหตุการณ์: ดักการตัดการเชื่อมต่อที่หายาก

สถานการณ์ที่ร้ายกาจที่สุดคือปัญหาที่เกิดชั่วโมงละครั้งและคาดเดาไม่ได้ เริ่มบัฟเฟอร์วงแหวนแล้วรอ เมื่อแอปบันทึกข้อผิดพลาด จดเวลาที่แน่นอนและหยุดการจับ แล้วในการวิเคราะห์ไปที่วินาทีนั้น เคล็ดลับในทางปฏิบัติ: ให้แอปเขียน timestamp ที่มีมิลลิวินาทีลงล็อกเมื่อเกิดข้อผิดพลาด - นั่นคือสมอของคุณในดัมป์

กรองตามแฟล็ก TCP ใน tcpdump เลย

บางครั้งมีประโยชน์ที่จะจับเฉพาะแพ็กเก็ตที่มีแฟล็กที่ต้องการ เช่น เฉพาะแพ็กเก็ตที่มีแฟล็ก RST เพื่อดูทันทีว่า reset วิ่งไปมาหรือเปล่า:

tcpdump -i eth0 -n "tcp[tcpflags] & tcp-rst != 0"

เฉพาะ SYN - สะดวกสำหรับติดตามความพยายามสร้างการเชื่อมต่อ:

tcpdump -i eth0 -n "tcp[tcpflags] & tcp-syn != 0"

รวม RST หรือ FIN เพื่อมอนิเตอร์การสิ้นสุดการเชื่อมต่อกับพร็อกซี:

tcpdump -i eth0 -n "host 203.0.113.10 and (tcp[tcpflags] & (tcp-rst|tcp-fin) != 0)"

Wireshark: อ่านดัมป์เหมือนหนังสือเปิด

tcpdump จับ Wireshark อ่าน นี่คือตัววิเคราะห์แบบกราฟิกที่มีระบบฟิลเตอร์แสดงผลและตัวถอดรหัสโปรโตคอลอันมั่งคั่ง เปิดไฟล์ pcap ที่บันทึกไว้และเริ่มสืบสวน มาดูเครื่องมือที่จำเป็นจริงๆ สำหรับงานของเรา

ฟิลเตอร์แสดงผล vs ฟิลเตอร์จับ

อย่าสับสน ฟิลเตอร์จับ (อันที่อยู่ใน tcpdump) กรองแพ็กเก็ตก่อนบันทึก - อันไหนจับไม่ได้ก็ไม่มี ฟิลเตอร์แสดงผลใน Wireshark เป็นเพียงเลนส์: มันแค่ซ่อนส่วนเกินจากไฟล์ที่โหลดแล้ว ไม่ลบอะไร ไวยากรณ์ต่างกัน ต่อไปนี้คือฟิลเตอร์แสดงผล

ฟิลเตอร์แสดงผลพื้นฐาน

แสดงเฉพาะทราฟฟิกไปยัง IP เฉพาะ:

ip.addr == 203.0.113.10

เฉพาะ TCP พอร์ตของพร็อกซี:

tcp.port == 8080

รวมโฮสต์และพอร์ต:

ip.addr == 203.0.113.10 && tcp.port == 8080

แสดงเฉพาะแพ็กเก็ตที่มีแฟล็ก RST - เห็น reset ของการเชื่อมต่อทั้งหมดทันที:

tcp.flags.reset == 1

เฉพาะแพ็กเก็ตที่มี FIN:

tcp.flags.fin == 1

เฉพาะ SYN ที่ไม่มี ACK - ความพยายามเปิดการเชื่อมต่อ:

tcp.flags.syn == 1 && tcp.flags.ack == 0

ค้นหา CONNECT และเฮดเดอร์ HTTP

เพื่อหา CONNECT เองในดัมป์:

http.request.method == "CONNECT"

การตอบของพร็อกซีเกี่ยวกับการสร้างทันเนลเห็นเป็น HTTP response กรองคำขอ HTTP ทั้งหมด:

http.request

คำตอบ HTTP ทั้งหมดที่มีรหัส:

http.response

Follow TCP Stream: รวมบทสนทนาเข้าเป็นหนึ่ง

นี่อาจเป็นฟีเจอร์ที่มีค่าที่สุดของ Wireshark สำหรับงานของเรา คลิกขวาที่แพ็กเก็ตใดก็ได้ของการเชื่อมต่อ แล้วเลือก Follow แล้ว TCP Stream Wireshark จะรวบรวมการแลกเปลี่ยนสองทางทั้งหมดในหน้าต่างเดียว ที่ข้อมูลของไคลเอนต์และเซิร์ฟเวอร์แสดงด้วยสีต่างกัน สำหรับทราฟฟิกที่ไม่เข้ารหัสคุณจะเห็นข้อความล้วน: คำขอ CONNECT, การตอบของพร็อกซี, แล้วหลังจากนั้นไบต์ TLS ที่อ่านไม่ออก

ใน Follow Stream นี่แหละที่คุณเห็นการหยุดที่ CONNECT อย่างชัดเจน บรรทัดแรกอ่านเป็นข้อความมนุษย์ได้ จากนั้นเข้าสู่พื้นที่เข้ารหัส นี่ ยืนยันว่า: ทันเนลถูกสร้างแล้ว หลังจากนั้นคือการเข้ารหัส และถ้าไม่มีคีย์ก็มองลึกกว่านี้ไม่ได้ - ซึ่งเป็นเรื่องปกติโดยสิ้นเชิง

อ่าน TLS แฮนด์เชกโดยไม่ถอดรหัส

แม้ไม่มีคีย์ TLS แฮนด์เชกก็เล่าเรื่องได้มาก กรองเรกคอร์ดการจับมือ:

tls.handshake

หา ClientHello ที่ไคลเอนต์แนะนำตัวต่อเซิร์ฟเวอร์:

tls.handshake.type == 1

หา ServerHello การตอบของเซิร์ฟเวอร์:

tls.handshake.type == 2

คู่นี้ให้อะไร? ถ้าคุณเห็น ClientHello แต่ไม่เคยเห็น ServerHello - เซิร์ฟเวอร์ไม่ตอบการจับมือ สาเหตุ: เซิร์ฟเวอร์ปลายทางไม่พร้อมใช้งานหลังพร็อกซี หรือการตัดการเชื่อมต่อเกิดขึ้นก่อนการตอบ ถ้าเห็นทั้งคู่ แต่หลังจากนั้นขาด - ปัญหาลึกกว่า ใน การแลกเปลี่ยนที่เข้ารหัสหรือระดับแอปพลิเคชัน

ภายใน ClientHello โดยไม่ต้องถอดรหัสก็อ่านฟิลด์ SNI ได้ - ชื่อโฮสต์ที่เรียก:

tls.handshake.extensions_server_name == "api.example.com"

คุณยังเห็นเวอร์ชัน TLS และชุดรหัสที่เสนอ ถ้าเซิร์ฟเวอร์ตอบ Alert แทน ServerHello หมายความว่าการจับมือถูกปฏิเสธ - เช่น ความไม่เข้ากันของเวอร์ชันหรือรหัส ฟิลเตอร์สำหรับ alert:

tls.alert_message

การวินิจฉัยจากดัมป์: ใครตัดการเชื่อมต่อจริงๆ

เรามาถึงหัวใจของบทความ การเชื่อมต่อล่ม - คำถามคือใครตัดมันและทำไม TCP ทิ้งร่องรอยไว้ และจากร่องรอยนั้นเราสรุปคำตัดสินได้ มาดูสัญญาณสำคัญ

การสิ้นสุดปกติ: FIN

การปิดการเชื่อมต่อตามปกติเกิดขึ้นผ่านการแลกเปลี่ยนแพ็กเก็ต FIN ฝ่ายหนึ่งพูดว่า ฉันส่งเสร็จแล้ว อีกฝ่ายยืนยันและส่ง FIN ด้วย นี่คือการอำลาอย่างสุภาพ ถ้าในดัมป์คุณเห็นการแลกเปลี่ยน FIN-ACK-FIN-ACK เรียบร้อย การเชื่อมต่อปิดอย่างถูกต้อง คำถามคือแค่ไคลเอนต์ของคุณคาดหวังการปิดนี้หรือเปล่า ถ้าเซิร์ฟเวอร์ส่ง FIN หลังส่งคำตอบครบแล้ว ทุกอย่างดี ถ้า FIN มาท่ามกลางข้อมูลที่คาดว่าจะได้ เซิร์ฟเวอร์ปิดก่อนเวลา

การสิ้นสุดฉุกเฉิน: RST

แฟล็ก RST คือการตัดฉับๆ ไม่ใช่การอำลา แต่เป็นกระแทกประตูปิด RST หมายถึง: การเชื่อมต่อนี้ไม่ถูกต้องแล้ว ลืมมันซะเดี๋ยวนี้ สาเหตุมีหลายแบบ:

  • พอร์ตปิด - ไม่มีใครฟังอยู่ฝั่งนั้น RST มาถึงเกือบจะทันทีหลัง SYN
  • แอปพลิเคชันฝั่งนั้นปิดซ็อกเก็ตอย่างผิดปกติ
  • อุปกรณ์กลางทาง (ไฟร์วอลล์, โหลดบาลานเซอร์, พร็อกซีเอง) บังคับตัดการเชื่อมต่อตามไทม์เอาต์หรือนโยบาย
  • ฝ่ายใดฝ่ายหนึ่งได้รับแพ็กเก็ตสำหรับการเชื่อมต่อที่มันลืมไปแล้ว

กุญแจไขปริศนาคือ ใครส่ง RST ดูที่ source IP ของแพ็กเก็ตที่มี RST ถ้า RST มาจาก IP พร็อกซี - พร็อกซีหรืออะไรระหว่างพร็อกซีกับคุณตัด ถ้ามาจาก IP เซิร์ฟเวอร์ปลายทาง - หมายความว่าเซกเมนต์พร็อกซี-เซิร์ฟเวอร์ไปถึงเซิร์ฟเวอร์แล้ว และเซิร์ฟเวอร์หรืออุปกรณ์ข้างๆ มันเป็นคนตัด

แต่อย่าลืมเรื่องสองเซกเมนต์ เก็บดัมป์บนไคลเอนต์คุณเห็น RST แค่จาก IP พร็อกซี เพราะคุณไม่ได้สื่อสารกับเซิร์ฟเวอร์โดยตรง - มีพร็อกซีคั่นอยู่ ถ้าจะเข้าใจว่าเกิดอะไรในเซกเมนต์ B ต้องมีดัมป์ฝั่งพร็อกซี เราจะพูดถึงเรื่องนี้ในหัวข้อเช็กลิสต์

การส่งซ้ำ: retransmission

Wireshark ทำเครื่องหมายการส่งซ้ำโดยอัตโนมัติ ฟิลเตอร์:

tcp.analysis.retransmission

การส่งซ้ำหมายความว่าผู้ส่งไม่ได้รับ ACK สำหรับเซกเมนต์ที่ส่งไปในเวลาที่กำหนด จึงส่งอีกครั้ง การส่งซ้ำครั้งคราวเป็นเรื่องปกติของอินเทอร์เน็ต แต่ถล่มการส่งซ้ำคืออาการแพ็กเก็ตหายในเส้นทาง พบมากเป็นพิเศษในเครือข่ายมือถือและเครือข่ายที่ไม่เสถียร

ฟิลเตอร์ที่เกี่ยวข้องซึ่งมีประโยชน์ ACK ซ้ำที่บอกถึงเซกเมนต์ที่หายไป:

tcp.analysis.duplicate_ack

เหตุการณ์ที่มีปัญหาทั้งหมดที่ Wireshark ตรวจจับได้:

tcp.analysis.flags

ถ้าคุณเห็นชุดการส่งซ้ำตามด้วย RST ภาพก็ชัดเจน: แพ็กเก็ตหาย ฝ่ายใดฝ่ายหนึ่งเบิกรอจนทนไม่ไหวและตัดการเชื่อมต่อ นี่คือเรื่องราวคลาสสิกของช่องสัญญาณไม่ดี

Zero Window: ผู้รับรับไม่ทัน

TCP มีกลไกควบคุมการไหลผ่านหน้าต่างรับ ถ้าผู้รับประมวลผลไม่ทัน มันจะประกาศ zero window - บัฟเฟอร์เต็ม ชะลอหน่อย ฟิลเตอร์:

tcp.analysis.zero_window

Zero window ไม่ใช่การสูญเสียในเครือข่าย แต่เป็นสัญญาณว่าแอปพลิเคชันฝั่งรับอ่านจากซ็อกเก็ตช้า ตัวอย่างเช่นไคลเอนต์ของคุณได้รับคำตอบขนาดใหญ่ แต่ประมวลผลแบบเธรดเดียวและตามไม่ทัน ผู้ส่งรอ หน้าต่างไม่เปิด และสุดท้ายไทม์เอาต์อาจทำงาน ถ้าหลัง zero window มี window update ทุกอย่างกลับเป็นปกติ ถ้าหลัง zero window เงียบแล้วตามด้วย RST - ผู้รับค้างหรือล่ม

สัญญาณที่เกี่ยวข้องคือ window full เมื่อผู้ส่งชนหน้าต่างที่ประกาศและส่งต่อไม่ได้:

tcp.analysis.window_full

เมทริกซ์คำตัดสิน

มารวบรวมตรรกะเป็นเฟรมเวิร์กที่ใช้ได้จริง ดูแพ็กเก็ตสุดท้ายของการเชื่อมต่อที่ยังมีชีวิตก่อนการตัด:

  • มี SYN ไม่มี SYN-ACK แล้วตามด้วย RST หรือเงียบ การเชื่อมต่อไม่ถูกสร้าง จุดปลายทางไม่พร้อมใช้งานหรือพอร์ตปิด เมื่อทำงานผ่านพร็อกซี RST จะมาจากพร็อกซีถ้าเซิร์ฟเวอร์หลังมันไม่พร้อม
  • สร้างเสร็จ ส่ง CONNECT แล้วไม่มีการตอบ พร็อกซียอมรับคำสั่ง แต่ไปไม่ถึงเซิร์ฟเวอร์ปลายทางหรือมันเงียบ รอไทม์เอาต์
  • มี ClientHello ไม่มี ServerHello เซิร์ฟเวอร์ปลายทางไม่ตอบการจับมือ ปัญหาอยู่ในเซกเมนต์พร็อกซี-เซิร์ฟเวอร์
  • ข้อมูลไหล แล้วตามด้วย RST จากเซิร์ฟเวอร์ เซิร์ฟเวอร์ปิดการเชื่อมต่ออย่างฉุกเฉิน - โหลดเกิน ข้อผิดพลาดแอปพลิเคชัน ไทม์เอาต์ฝั่งมัน
  • ข้อมูลไหล แล้วตามด้วย FIN จากเซิร์ฟเวอร์ท่ามกลางคำตอบ เซิร์ฟเวอร์ปิดอย่างถูกต้อง แต่ก่อนที่ไคลเอนต์จะคาด - น่าจะเป็นลิมิตขนาดคำตอบหรือไทม์เอาต์ของคำขอ
  • ถล่ม retransmission แล้วตามด้วย RST แพ็กเก็ตหายในช่องสัญญาณ มองหาปัญหาในเครือข่าย - การเชื่อมต่อมือถือ เส้นทางที่โหลดเกิน
  • Zero window แล้วตามด้วยเงียบ ไคลเอนต์ของคุณไม่ได้อ่านข้อมูลเร็วพอ ปัญหาอยู่ฝั่งเราที่การประมวลผล

ถอดรหัสทราฟฟิกของตัวเองผ่าน SSLKEYLOGFILE

บางครั้งเมตาดาต้าไม่พอ - ต้องเห็นเนื้อหาของการแลกเปลี่ยนที่เข้ารหัส สิ่งนี้ถูกต้องตามกฎหมายและเหมาะสมเฉพาะเมื่อทราฟฟิกเป็นของคุณเอง: ไคลเอนต์ของคุณ คีย์ของคุณ แอปของคุณ เราไม่ดักจับของคนอื่นและไม่สวมรอยใบรับรอง เราแค่ขอให้ไคลเอนต์ของเราเขียนคีย์เซสชันลงไฟล์อย่างสุภาพ เพื่อป้อนให้ Wireshark

มันทำงานอย่างไร

ไลบรารีไคลเอนต์ TLS หลายตัวรองรับตัวแปรสภาพแวดล้อม SSLKEYLOGFILE ถ้าตั้งไว้ ไลบรารีจะเขียนความลับของเซสชันลงไฟล์ที่ระบุในรูปแบบมาตรฐาน Wireshark อ่านไฟล์นี้และถอดรหัสเซสชันที่สอดคล้องในดัมป์ได้ ไม่มีเวทมนตร์และไม่มีการแฮก - ไคลเอนต์ยอมมอบคีย์ของตัวเองเพราะคุณเจ้าของไคลเอนต์สั่งเช่นนั้น

ตัวอย่างสำหรับบรรทัดคำสั่งและเบราว์เซอร์บนเอนจินที่รองรับ

ตั้งค่าตัวแปรก่อนเปิดแอปในระบบแบบ Unix:

export SSLKEYLOGFILE=/home/user/tls-keys.log

เปิดไคลเอนต์ เช่น curl ที่รองรับตัวแปรนี้เมื่อคอมไพล์กับไลบรารีที่เหมาะสม:

SSLKEYLOGFILE=/home/user/tls-keys.log curl -x http://203.0.113.10:8080 https://api.example.com/status

ที่นี่แฟล็ก -x กำหนดพร็อกซี Proxeon และ SSLKEYLOGFILE ทำให้เขียนคีย์เซสชัน ในขณะเดียวกันก็เก็บดัมป์ผ่าน tcpdump หลังจากนั้นคุณมีทั้ง pcap และไฟล์คีย์

เชื่อมคีย์ใน Wireshark

ใน Wireshark เปิดการตั้งค่า หาส่วนของโปรโตคอล TLS ระบุพาธไปยังไฟล์คีย์ในฟิลด์สำหรับไฟล์ล็อกของ pre-master secret จากนั้นอ่านดัมป์ใหม่ TLS เรกคอร์ดที่อ่านไม่ออกก่อนหน้านี้จะกลายเป็นถอดรหัสแล้ว: คุณจะเห็นคำขอและคำตอบ HTTP จริงภายในทันเนล ตอนนี้ Follow TLS Stream จะแสดงการแลกเปลี่ยนระดับแอปพลิเคชันทั้งหมด

ขอบเขตการใช้งานที่สำคัญ

  • ถอดรหัสได้เฉพาะทราฟฟิกที่คีย์ของมันอยู่ในไฟล์ เซสชันของคนอื่นยังคงเข้ารหัส - และนั่นถูกต้องแล้ว
  • คีย์อ่อนไหว ไฟล์ tls-keys.log จริงๆ แล้วเปิดเนื้อหาของเซสชันของคุณ เก็บมันเป็นความลับ ลบหลังดีบัก
  • วิธีการนี้ใช้สำหรับดีบักแอปพลิเคชันของตัวเอง ไม่ใช่สำหรับสอดส่องทราฟฟิกของคนอื่น นี่คือเส้นแบ่งทางจริยธรรมและกฎหมายที่เป็นหลักการ

ภาพการตัดการเชื่อมต่อทั่วไปและวิธีอ่าน

ทฤษฎีที่ไม่ผูกกับแพตเทิร์นที่รู้จักจะจางหายไปเร็ว มาดูสถานการณ์หลายอย่างที่เป็นลักษณะเฉพาะที่คุณจะเจอครั้งแล้วครั้งเล่า ฝึกให้รู้จักได้ในพริบตา

ไทม์เอาต์การเชื่อมต่อ: เซิร์ฟเวอร์หลังพร็อกซีไม่พร้อม

ภาพในดัมป์บนไคลเอนต์: TCP ไปพร็อกซีสร้างเสร็จปกติ ไคลเอนต์ส่ง CONNECT แล้วก็เงียบ ไม่มีการตอบ 200 จากพร็อกซี ต่อมาอาจมี RST จากพร็อกซี หรือแอปปิดการเชื่อมต่อเองตามไทม์เอาต์ของตัวเอง

นี่หมายความว่า: พร็อกซียอมรับคำสั่ง พยายามเปิดเซกเมนต์ B ไปยังเซิร์ฟเวอร์ปลายทาง แต่ไม่มีการตอบ เซิร์ฟเวอร์ปลายทางล่ม พอร์ตปิด หรือเส้นทางไปถึงมันขาด ฝั่งคุณและพร็อกซีทำงานปกติ การดำเนินการ: ตรวจสอบการเข้าถึงโฮสต์ปลายทาง และถ้าจำเป็นเก็บดัมป์ฝั่งพร็อกซีเพื่อดูเซกเมนต์ B

ตัดการเชื่อมต่อท่ามกลางคำตอบ

ภาพ: ทันเนลสร้างเสร็จ TLS ทำงาน ข้อมูลเริ่มไหล ได้คำตอบบางส่วน แล้วทันใดนั้น FIN หรือ RST จากฝั่งเซิร์ฟเวอร์ ไคลเอนต์ได้คำตอบไม่ครบและบ่นเรื่องเนื้อหาถูกตัด

ถ้าเป็น FIN เซิร์ฟเวอร์ปิดถูกต้องแต่ก่อนเวลา - อาจเป็นลิมิตเวลาสร้างคำตอบหรือลิมิตขนาดฝั่งมัน ถ้าเป็น RST เซิร์ฟเวอร์หรืออุปกรณ์ข้างๆ มันตัดฉุกเฉิน การดำเนินการ: ถ้าปัญหาเกิดซ้ำกับคำตอบใหญ่ - มองหาไทม์เอาต์และลิมิต การถอดรหัสทราฟฟิกของตัวเองผ่าน SSLKEYLOGFILE จะช่วยให้เห็นว่าได้รับ HTTP เฮดเดอร์แล้วหรือไม่และบอดี้มาได้แค่ไหน

การสูญหายในเครือข่ายมือถือ

ภาพ: แพ็กเก็ตจำนวนมากถูกทำเครื่องหมายเป็น retransmission พบ duplicate ack และเห็นความต่างของเวลาระหว่างแพ็กเก็ตอย่างชัดเจน การเชื่อมต่อทั้งช้ามากอย่างทรมาน หรือสุดท้ายขาดตามไทม์เอาต์

นี่คือคลาสสิกของช่องสัญญาณวิทยุที่ไม่เสถียร แพ็กเก็ตหาย TCP ส่งซ้ำ ความเร็วตก เครือข่ายมือถือยังมักตัดการเชื่อมต่อที่ว่างนานผ่าน NAT ไทม์เอาต์ของอุปกรณ์กลางของผู้ให้บริการ: ท่ามกลางความเงียบ จู่ๆ RST ก็ปรากฏ เมื่อฝ่ายใดฝ่ายหนึ่งพยายามกลับมาแลกเปลี่ยนบนการเชื่อมต่อที่ผู้ให้บริการลืมไปแล้ว การดำเนินการ: ตั้งค่า keep-alive และไทม์เอาต์ที่สมเหตุสมผล ลองซ้ำที่ระดับแอปพลิเคชัน ไม่ถือการเชื่อมต่อที่ว่างนาน

พร็อกซีไม่พร้อมเลย

ภาพ: ไคลเอนต์ส่ง SYN ไปยัง IP และพอร์ตพร็อกซี แต่ไม่ได้รับ SYN-ACK หรือเงียบและการส่งซ้ำ SYN หรือ RST ทันที ถ้าเงียบ - อะไรระหว่างคุณกับพร็อกซีกรองแพ็กเก็ตหรือพร็อกซีไม่ฟัง ถ้า RST ทันที - ไม่มีใครตอบที่พอร์ตนั้น การดำเนินการ: ตรวจสอบที่อยู่และพอร์ตพร็อกซี การเข้าถึงเครือข่าย ความถูกต้องของการกำหนดค่า

ไคลเอนต์ช้า: zero window

ภาพ: การแลกเปลี่ยนดำเนินไป แต่เป็นครั้งคราวไคลเอนต์ประกาศ zero window ผู้ส่งหยุดชั่วคราว แล้ว window update ทำให้สตรีมกลับมา ถ้าเกิดซ้ำบ่อย แอปของคุณอ่านจากซ็อกเก็ตช้ากว่าเซิร์ฟเวอร์ส่ง การดำเนินการ: ปรับปรุงการประมวลผลคำตอบ อ่านสตรีมในเธรดแยก เพิ่มบัฟเฟอร์

ข้อผิดพลาดทั่วไปในการเก็บและอ่านดัมป์

ประสบการณ์คือคอลเลกชันของรอยฟกช้ำ มารวบรวมข้อผิดพลาดที่พบบ่อยที่สุดเพื่อให้คุณไม่ทำซ้ำ

  • เก็บดัมป์ผิดที่ หาการตัดการเชื่อมต่อในเซกเมนต์พร็อกซี-เซิร์ฟเวอร์ แต่เก็บดัมป์บนไคลเอนต์ที่มองไม่เห็นเซกเมนต์นั้นเลย คิดเสมอว่าต้องการเซกเมนต์ไหน และเก็บดัมป์ที่จุดที่ถูกต้อง
  • จับทุกอย่าง ไม่มีฟิลเตอร์บนเซิร์ฟเวอร์ที่มีโหลดสูงคุณจะได้กิกะไบต์และจมอยู่ในนั้น กรองตามโฮสต์และพอร์ตตั้งแต่แรก
  • snaplen สั้นเกินไปตอนที่ต้องการข้อมูล ถ้าต้องการเห็นเนื้อหา แต่ตั้ง snaplen สั้น เพย์โหลดจะถูกตัด และ Follow Stream จะแสดงแค่เศษ
  • เปิดการแปลงชื่อไว้ ลืมแฟล็ก -n แล้ว tcpdump ช้าลงเพราะ DNS บิดเบือนไทม์มิ่ง ใช้ -n เสมอเมื่อจับ
  • เพิกเฉยทิศทางของ RST เห็น RST แล้วสรุปโดยไม่ดูว่าใครส่ง source IP ของแพ็กเก็ต RST คือครึ่งหนึ่งของคำตอบ
  • สับสน FIN ปกติกับอุบัติเหตุ FIN คือการปิดปกติ สิ่งที่ต้องตกใจไม่ใช่ FIN เอง แต่คือ FIN ที่มาก่อนจุดสิ้นสุดข้อมูลที่คาดไว้
  • ลืมเรื่องเขตเวลาและเวลาที่แน่นอน ล็อกแอปและดัมป์ต้องซิงค์เวลากัน ไม่งั้นหาจุดที่ต้องการไม่เจอ ดูแล NTP ให้ดี
  • เก็บไฟล์คีย์ SSLKEYLOGFILE หลังดีบักต้องลบ มันคือความลับที่เปิดเนื้อหาเซสชันของคุณ
  • สรุปจากการเชื่อมต่อเดียว ปัญหาที่เกิดเป็นครั้งคราวต้องใช้สถิติ คำขอที่ล่มครั้งเดียวอาจเป็นเรื่องบังเอิญ แพตเทิร์นจากสิบครั้งคือการวินิจฉัย

เครื่องมือและแหล่งข้อมูลของวิศวกร

มารวบรวมคลังอาวุธที่ควรมีติดตัวเมื่อทำงานกับทราฟฟิกพร็อกซี

การจับ

  • tcpdump - เครื่องมือจับหลักบนเซิร์ฟเวอร์และในคอนโซล เบา ใช้ได้เสมอ ฟิลเตอร์ยืดหยุ่น
  • dumpcap - ยูทิลิตี้คอนโซลจากชุด Wireshark ที่ปรับแต่งมาเพื่อการจับที่มีประสิทธิภาพพร้อมการหมุน
  • tshark - Wireshark คอนโซล ช่วยใช้ฟิลเตอร์แสดงผลโดยไม่ต้องมีกราฟิก สะดวกสำหรับสคริปต์และเซิร์ฟเวอร์ระยะไกล

การวิเคราะห์

  • Wireshark - ตัววิเคราะห์กราฟิก ตัวถอดรหัสหลายร้อยโปรโตคอล ระบบฟิลเตอร์ทรงพลัง Follow Stream สถิติการเชื่อมต่อ
  • ข้อมูลผู้เชี่ยวชาญของ Wireshark - แผงในตัวที่ไฮไลต์ความผิดปกติ: การส่งซ้ำ reset zero window เริ่มสืบสวนจากตรงนี้เลย
  • สถิติการสนทนา - ตารางการเชื่อมต่อ TCP ทั้งหมดในดัมป์พร้อมไบต์และระยะเวลา เห็นได้เร็วว่าการเชื่อมต่อใดสั้นผิดปกติ

เทคนิคบรรทัดคำสั่งที่มีประโยชน์

ดูเนื้อหา pcap ในคอนโซลผ่าน tshark อย่างรวดเร็วด้วยฟิลเตอร์แสดงผล:

tshark -r dump.pcap -Y "tcp.flags.reset == 1"

แสดงเฉพาะคำขอ CONNECT จากไฟล์:

tshark -r dump.pcap -Y "http.request.method == \"CONNECT\""

ดูการส่งซ้ำทั้งหมด:

tshark -r dump.pcap -Y "tcp.analysis.retransmission"

คำสั่งเหล่านี้ล้ำค่าเมื่อไม่มีกราฟิก แต่ต้องไขเรื่องเดี๋ยวนี้ ผ่าน ssh

เคสและผลลัพธ์จากการใช้งาน

ไม่มีอะไรโน้มน้าวได้ดีไปกว่าเรื่องราวจริง มาดูเคสที่รวบรวมมา สะท้อนการปฏิบัติจริงของวิศวกรในการวินิจฉัยทราฟฟิกพร็อกซี

เคส 1: ห้าเปอร์เซ็นต์ของคำขอล้มเหลวตอนกลางคืน

ทีมอินทิเกรชันบ่น: ประมาณห้าเปอร์เซ็นต์ของคำขอไป API ภายนอกผ่านพร็อกซีล้มเหลวด้วยคำตอบถูกตัด ส่วนใหญ่ตอนกลางคืน ล็อกแอปแสดงเนื้อหาไม่ครบ ล็อกพร็อกซี - ทันเนลที่สร้างเสร็จไม่มีข้อผิดพลาด

เก็บดัมป์บนไคลเอนต์ด้วยการหมุนวงแหวนหลายชั่วโมงและจุดอ้างอิงข้อผิดพลาดที่แน่นอนจากล็อก ในขณะเกิดเหตุเห็น: ทันเนลสร้างเสร็จ TLS ทำงาน บอดีคำตอบมาบางส่วน แล้วตามด้วย FIN จากพร็อกซี การถอดรหัสทราฟฟิกของตัวเองผ่าน SSLKEYLOGFILE แสดง: HTTP เฮดเดอร์มาถูกต้องพร้อมขนาดบอดี แต่บอดี้ขาดกลางทาง สรุป: เซิร์ฟเวอร์ปลายทางปิดการเชื่อมต่อตามไทม์เอาต์สร้างรายงานกลางคืนขนาดใหญ่ วิธีแก้ฝั่งอินทิเกรชัน - ขอข้อมูลแบบแบ่งหน้าเป็นส่วนเล็กๆ ปัญหาหมดไปทั้งหมด

เคส 2: RST ทันทีลึกลับ

วิศวกรอีกคนได้รับการตัดทันทีหลังส่ง CONNECT สำหรับโฮสต์เฉพาะโฮสต์เดียว ขณะที่โฮสต์อื่นทำงานปกติ ข้อสงสัยแรกพุ่งไปที่พร็อกซี

ดัมป์บนไคลเอนต์แสดง: CONNECT ส่งออกไป และเกือบจะทันทีได้ RST กลับมาจาก IP พร็อกซี แต่ความทันทีนั้นน่าสงสัย - ปกติการไม่พร้อมใช้งานของเซิร์ฟเวอร์ให้ไทม์เอาต์ ไม่ใช่ reset ทันที เก็บดัมป์ฝั่งพร็อกซีและเห็นเซกเมนต์ B: พร็อกซีเปิดการเชื่อมต่อไปโฮสต์ปลายทางที่พอร์ตที่ต้องการ และเซิร์ฟเวอร์ปลายทางตอบ RST ต่อ SYN - พอร์ตปิด พร็อกซีแค่ส่งต่อการปฏิเสธนั้นให้ไคลเอนต์อย่างซื่อสัตย์ กลายเป็นว่าบริการปลายทางเพิ่งเปลี่ยนพอร์ต สรุป: RST ทันทีส่วนใหญ่คือพอร์ตปิด ไม่ใช่ปัญหาพร็อกซี พอร์ตที่ถูกต้องคืนการทำงาน

เคส 3: การเสื่อมสภาพในเซกเมนต์มือถือ

แอปบนอุปกรณ์มือถือที่ทำงานผ่านพร็อกซี ผู้ใช้บางส่วนสูญเสียการเชื่อมต่อเป็นประจำ ดัมป์จากอุปกรณ์ในพื้นที่ครอบคลุมที่มีปัญหาแสดงภาพคลาสสิก: ชุดการส่งซ้ำ ACK ซ้ำ ช่วงเวลาที่เพิ่มขึ้น และสุดท้าย RST หลังว่างนาน - ผลจาก NAT ไทม์เอาต์ของผู้ให้บริการ

สรุป: เครือข่าย ไม่ใช่พร็อกซีและไม่ใช่เซิร์ฟเวอร์ วิธีแก้ - เพิ่มการลองซ้ำแบบปรับตัวที่ระดับแอปพลิเคชัน keep-alive ที่สมเหตุสมผล และการจัดการการตัดการเชื่อมต่ออย่างสง่างามด้วยการสร้างการเชื่อมต่อใหม่ จำนวนข้อผิดพลาดที่ผู้ใช้เห็นลดลงหลายเท่า แม้ช่องสัญญาณวิทยุจะเหมือนเดิม แพ็กเก็ตดัมป์ช่วยให้ไม่เสียเวลากับสมมติฐานผิดเรื่องพร็อกซีและโฟกัสที่สาเหตุจริง

ข้อมูลเชิงลึกทั่วไปจากเคส

ในทั้งสามเรื่อง ดัมป์ประหยัดเวลาหลายสัปดาห์ของการโต้ตอบและกล่าวโทษกันระหว่างทีม แพ็กเก็ตไม่โกหก ทันทีที่มีดัมป์บนโต๊ะที่แสดงทิศทางของ RST การมีหรือไม่มี ServerHello และภาพการส่งซ้ำ การโต้เถียงเรื่องผู้กระทำผิดก็จบในไม่กี่นาที นี่คือคุณค่าหลักของวิธีการ: มันย้ายการวินิจฉัยจากระนาบของความคิดเห็นไปสู่ระนาบของข้อเท็จจริง

เช็กลิสต์เก็บดัมป์เพื่อติดต่อฝ่ายสนับสนุน

เมื่อคุณติดต่อฝ่ายสนับสนุน - ไม่ว่าจะเป็นผู้ให้บริการพร็อกซี Proxeon หรือเจ้าของ API ปลายทาง - ดัมป์ที่เก็บอย่างถูกต้องเร่งการแก้ปัญหาได้หลายเท่า นี่คือเช็กลิสต์ที่ควรทำก่อนติดต่อ

ก่อนจับ

  • บันทึกเวลาที่แน่นอนของการเริ่มวินิจฉัยและซิงค์นาฬิกาผ่าน NTP บนเครื่องที่เกี่ยวข้องทั้งหมด
  • กำหนดจุดจับ: อย่างน้อยบนไคลเอนต์ ถ้าเป็นไปได้ - และฝั่งที่คุณเข้าถึงได้
  • รวบรวมข้อมูลเบื้องต้น: IP และพอร์ตพร็อกซี ชื่อและพอร์ตโฮสต์ปลายทาง พฤติกรรมที่คาดหวังและที่เกิดขึ้นจริง

ระหว่างจับ

  • เริ่ม tcpdump ด้วยฟิลเตอร์ตามโฮสต์พร็อกซีและพอร์ตปลายทาง พร้อม snaplen เต็มและการหมุน:
    tcpdump -i eth0 -n -s 0 "host 203.0.113.10 and port 8080" -w support-%Y%m%d-%H%M%S.pcap -C 100 -W 10
  • ทำซ้ำปัญหาและบันทึกเวลาที่แน่นอนของเหตุการณ์พร้อมมิลลิวินาทีจากล็อกแอป
  • อย่าลืมบันทึกล็อกแอปในช่วงเวลาเดียวกันด้วย

สิ่งที่ต้องแนบมากับคำขอ

  • ไฟล์ pcap เอง ตัดให้เหลือช่วงเวลาที่เกี่ยวข้อง เพื่อไม่ให้ส่งกิกะไบต์
  • timestamp ที่แน่นอนของเหตุการณ์และเขตเวลา
  • IP และพอร์ตพร็อกซี ชื่อและพอร์ตโฮสต์ปลายทาง คำอธิบายสถานการณ์
  • ส่วนของล็อกแอปที่มีข้อผิดพลาด
  • การวิเคราะห์เบื้องต้นของคุณ: ใครส่ง RST หรือ FIN มี ServerHello หรือไม่ พบการส่งซ้ำหรือเปล่า สิ่งนี้แสดงว่าคุณทำการบ้านมาแล้ว

วิธีตัด pcap ให้เหลือช่วงเวลาที่ต้องการ

ไฟล์ใหญ่สามารถตัดตามเวลาผ่าน tshark หรือ editcap ตัวอย่างการตัดตามหมายเลขแพ็กเก็ตหรือตามฟิลเตอร์:

tshark -r big.pcap -Y "frame.time >= \"2026-01-01 03:00:00\" && frame.time <= \"2026-01-01 03:05:00\"" -w small.pcap

ดัมป์ที่เรียบร้อยและโฟกัสแบบนี้ ฝ่ายสนับสนุนจะประมวลผลได้เร็ว เพราะไม่ต้องหาเข็มในกองหญ้า

FAQ: คำถามที่พบบ่อยเกี่ยวกับดัมป์ผ่านพร็อกซี

ทำไมในดัมป์ทราฟฟิก HTTPS ผ่านพร็อกซีฉันเห็นแค่ CONNECT แล้วหลังจากนั้นอ่านไม่ออก?

เพราะหลังสร้างทันเนล พร็อกซีแค่ส่งต่อไบต์ TLS ที่เข้ารหัส โดยไม่มีคีย์ ข้อความเปิดเผยมีแค่คำสั่ง CONNECT พร้อมชื่อโฮสต์และการตอบของพร็อกซีเกี่ยวกับการสร้าง ที่เหลือถูกป้องกันด้วยการเข้ารหัส - และนั่นคือเหตุผลที่ HTTPS มีอยู่ ในการดูเนื้อหาทราฟฟิกของตัวเอง ใช้ SSLKEYLOGFILE

จะรู้ได้อย่างไรว่าการเชื่อมต่อถูกตัดโดยเซิร์ฟเวอร์ปลายทาง ไม่ใช่พร็อกซี?

ดู source IP ของแพ็กเก็ตที่มี RST หรือ FIN แต่จำเรื่องสองเซกเมนต์: บนดัมป์จากไคลเอนต์คุณเห็นแค่ IP พร็อกซี เพราะไม่ได้สื่อสารกับเซิร์ฟเวอร์โดยตรง ในการระบุการตัดไปที่เซิร์ฟเวอร์ปลายทางอย่างแน่นอน ต้องมีดัมป์ฝั่งพร็อกซีที่เห็นเซกเมนต์พร็อกซี-เซิร์ฟเวอร์ ถ้า RST ในเซกเมนต์ B มาจาก IP เซิร์ฟเวอร์ - มันเป็นคนตัด

retransmission ต่างจาก RST ในเชิงการวินิจฉัยอย่างไร?

Retransmission คือการส่งเซกเมนต์ที่ไม่ได้รับการยืนยันซ้ำ สัญญาณของแพ็กเก็ตหายในช่องสัญญาณ แต่การเชื่อมต่อยังมีชีวิตและยังสู้อยู่ RST คือการสิ้นสุด คำสั่งให้ลืมการเชื่อมต่อ ถล่มการส่งซ้ำที่เปลี่ยนเป็น RST อ่านได้ว่า: ช่องสัญญาณแพ็กเก็ตหาย ฝ่ายนั้นเหนื่อยรอและตัด การส่งซ้ำครั้งคราวเป็นเรื่องปกติของอินเทอร์เน็ต

zero window หมายถึงอะไร และพร็อกซีมีความผิดหรือไม่?

Zero window ประกาศโดยผู้รับที่บัฟเฟอร์รับเต็ม เพราะแอปพลิเคชันประมวลผลช้า

เกี่ยวกับผู้เขียน

Andrey Kokh

Andrey Kokh

Leading Expert and Business Consultant

ประสบการณ์ทำงาน: Leading expert with 12 years of experience. Consults Forbes-listed companies, author of 3 books. Teaches at HSE and SKOLKOVO. His methodologies are used by hundreds of companies across Russia. RBC and Forbes expert on strategic development and digital transformation.
การศึกษา: Higher School of Economics. Faculty of Economics, Master's Program
ความเชี่ยวชาญ:
Strategic Consulting Digital Transformation Change Management Business Strategy Innovation Management Organizational Development Lean Management Agile Transformation

แชร์บทความ: