มีคำสั่งอยู่คำสั่งหนึ่งที่คนทำงานเครือข่ายพิมพ์ทุกวัน พิมพ์มาแล้วสี่สิบปี และจะยังพิมพ์ต่อไป มันคือคำสั่งแรกที่ทุกคนได้เรียน และเป็นคำสั่งแรกที่ทุกคน หยิบมาใช้เวลาอะไรสักอย่างพัง
ปัญหาคือคนส่วนใหญ่หยุดเรียนรู้มันตรงที่ "ตอบก็คือดี ไม่ตอบก็คือพัง" ซึ่งผิดทั้งสองครึ่ง
หน้านี้เริ่มจากศูนย์จริง ๆ แล้วไล่ลงไปจนถึงจุดที่คนทำงานสายนี้มาสิบปีก็ยัง เผลอเข้าใจผิดกันอยู่
ถ้ายังไม่เคยพิมพ์มาก่อน เริ่มตรงนี้
เปิดหน้าต่างคำสั่งของเครื่องคุณ — Terminal บน macOS หรือ Linux, Command Prompt หรือ PowerShell บน Windows — แล้วพิมพ์
ping 8.8.8.8
ถ้าเครื่องคุณต่อเน็ตอยู่ จะได้ผลประมาณนี้ (บน Linux หรือ macOS)
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=115 time=12.3 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=115 time=11.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=115 time=12.1 ms
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 11.8/12.1/12.3/0.2 ms
บน Linux และ macOS มันจะส่งไปเรื่อย ๆ จนกว่าจะกด Ctrl-C หยุด บน Windows มันส่งสี่ครั้งแล้วหยุดเอง
สิ่งที่เพิ่งเกิดขึ้นคือ เครื่องคุณตะโกนถามไปหาเครื่องปลายทางว่า "ได้ยินไหม" สามครั้ง และปลายทางตะโกนตอบกลับมาครบสามครั้ง ใช้เวลาไปกลับครั้งละประมาณ 12 มิลลิวินาที
เท่านี้ก็ใช้งานได้แล้ว ที่เหลือของหน้านี้คือเรื่องที่ว่า ทำไม
กรกฎาคม 1983 ที่นอร์เวย์ — จุดเริ่มที่ไม่ใช่โครงการ
เพื่อให้เห็นภาพว่าปี 1983 เป็นปีแบบไหน: วันที่ 1 มกราคมของปีนั้นคือวันที่ ARPANET ตัดจากโพรโทคอลเดิมชื่อ NCP มาเป็น TCP/IP ทั้งเครือข่ายในวันเดียว เหตุการณ์ที่คนเรียกกันว่า flag day
แปลว่าตอนที่เรื่องนี้เกิดขึ้น TCP/IP บนเครือข่ายจริงมีอายุยังไม่ถึงหนึ่งปี เครือข่ายทำตัวแปลก ๆ ทุกวัน และแทบไม่มีเครื่องมืออะไรให้ใช้หาสาเหตุเลย
เดือนกรกฎาคม 1983 ในการประชุมของ DARPA ที่ประเทศนอร์เวย์ Dr. David L. Mills เล่าให้ฟังแบบผ่าน ๆ ถึงงานที่เขาทำบนเครื่อง Fuzzball LSI-11 ของเขา ว่าเขาวัดความหน่วงของเส้นทางด้วยการจับเวลา แพ็กเก็ต ICMP Echo
Mike Muuss ซึ่งอยู่ในที่ประชุมนั้นจำมันไว้
ชื่อ Mills ควรค่าแก่การจำไว้ด้วยตัวมันเอง เขาคือคนที่ต่อมาสร้าง NTP โพรโทคอลที่ทำให้นาฬิกาของเครื่องทั้งอินเทอร์เน็ตตรงกัน คำพูดผ่าน ๆ ของคนที่ทำให้เวลาบนอินเทอร์เน็ตแม่นยำ กลายเป็นเครื่องมือวัดเวลา บนอินเทอร์เน็ตที่คนใช้มากที่สุด
ธันวาคม 1983 — เขียนเสร็จก่อนฟ้าสาง
Muuss ทำงานอยู่ที่ Ballistic Research Laboratory ของกองทัพบกสหรัฐ ที่ Aberdeen Proving Ground รัฐแมริแลนด์ เดือนธันวาคมปีนั้นเขานั่งลงเขียน สิ่งที่เขาเรียกเองว่า "a little thousand-line hack" บน 4.2a BSD UNIX
แต่มีอุปสรรคหนึ่งที่คนเล่าเรื่องนี้มักข้ามไป — ตอนนั้นระบบปฏิบัติการยังส่ง แพ็กเก็ต ICMP จากโปรแกรมของผู้ใช้ไม่ได้เลย ไม่มี raw ICMP socket ให้ใช้
Muuss จึงเขียนส่วนที่ขาดลงไปในเคอร์เนลเสียก่อน แล้วค่อยเขียนโปรแกรมที่ใช้มัน และเขาบันทึกไว้ว่าทำทั้งหมดนั้นเสร็จ ก่อนพระอาทิตย์ขึ้น
รายละเอียดข้อนี้สำคัญกว่าที่ดู เพราะมันบอกว่า ping ไม่ได้เป็นแค่โปรแกรม มันมาพร้อมกับความสามารถใหม่ของระบบปฏิบัติการ ซึ่งเป็นความสามารถที่ เครื่องมือเครือข่ายรุ่นหลังแทบทุกตัวยังยืนอยู่บนมันจนถึงวันนี้
จุดที่คนมักเข้าใจผิดอีกข้อคือ Muuss ไม่ได้เป็นคนคิด ICMP Echo ขึ้นมา ตัวโพรโทคอลมีอยู่ก่อนแล้ว นิยามไว้ใน RFC 792 ตั้งแต่กันยายน 1981 โดย Jon Postel สิ่งที่ Muuss ทำคือเขียนเครื่องมือที่ทำให้ความสามารถ ที่มีอยู่แล้วนั้นกลายเป็นสิ่งที่คนเดินดินใช้ได้จริงในบรรทัดเดียว
ping ลงมาในระบบปฏิบัติการที่แจกจ่ายเป็นทางการครั้งแรกใน 4.3BSD และรุ่นแรกที่ปล่อยออกมาเป็น public domain ไม่มีใครเป็นเจ้าของ ซึ่งเป็นเหตุผลหนึ่งที่มันแพร่ไปอยู่ในทุกระบบปฏิบัติการบนโลกได้เร็วขนาดนั้น
Muuss ยังเป็นคนสร้าง BRL-CAD, เครื่องมือวัดปริมาณงานเครือข่ายชื่อ TTCP, และมีส่วนในแนวคิด default route ที่ทุกเครื่องบนโลกใช้อยู่ทุกวันนี้ เขาได้รับรางวัล Lifetime Achievement จาก USENIX ในปี 1993 และเสียชีวิตจากอุบัติเหตุรถยนต์บนทางหลวง Interstate 95 เมื่อวันที่ 20 พฤศจิกายน 2000 อายุ 42 ปี
ทำไมถึงชื่อ ping
คำตอบตรงไปตรงมากว่าที่หลายคนคิด Muuss เขียนไว้เองว่า
ผมตั้งชื่อมันตามเสียงที่โซนาร์ทำ โดยได้แรงบันดาลใจจากหลักการของ การหาตำแหน่งด้วยเสียงสะท้อนทั้งหมด
โซนาร์ของเรือดำน้ำทำงานแบบนี้ — ปล่อยเสียงออกไปหนึ่งพัลส์ เสียงวิ่งไปชน อะไรสักอย่างแล้วสะท้อนกลับมา จับเวลาที่ใช้ไปกลับ ก็รู้ว่าของสิ่งนั้น อยู่ไกลแค่ไหน ping ทำแบบเดียวกันเป๊ะ เพียงแค่เปลี่ยนจากเสียงเป็นแพ็กเก็ต
ส่วนคำว่า "Packet InterNet Groper" ที่เห็นตามหนังสือเรียนบ่อย ๆ นั้น เป็นคำที่มาตั้งย้อนหลังให้เข้ากับตัวอักษร ไม่ใช่ที่มาจริง และเรื่องตลกคือ ตามบันทึกของ Muuss เอง คนที่เสนอให้ขยายตัวอักษรแบบนั้นคือ Dave Mills — คนเดียวกับที่คำพูดของเขาทำให้โปรแกรมนี้เกิดขึ้น
Muuss ปฏิเสธชัดเจนว่าสำหรับเขา PING ไม่ใช่ตัวย่อ แต่เป็นการเปรียบเทียบ กับโซนาร์ ทั้งสองเรื่องจริงพร้อมกันได้ — ชื่อมาจากเสียง ส่วนตัวย่อ มาทีหลังและติดปากจนแยกไม่ออก
มันทำงานอย่างไร
ping ส่งข้อความชนิดหนึ่งชื่อ ICMP Echo Request ออกไป แล้วรอข้อความชื่อ ICMP Echo Reply กลับมา
ICMP ย่อมาจาก Internet Control Message Protocol เป็นโพรโทคอลที่อยู่คู่กับ IP สำหรับส่งข้อความ "แจ้งเรื่อง" ระหว่างเครื่อง ไม่ได้ใช้ส่งข้อมูลของผู้ใช้ มันไม่ได้วิ่งบน TCP หรือ UDP แต่นั่งอยู่บน IP โดยตรง ในหมายเลขโพรโทคอลที่ 1
ตัวเลข "type" คือชนิดของข้อความ สำหรับ IPv4
- type 8 คือ Echo Request — คำถาม
- type 0 คือ Echo Reply — คำตอบ
ที่น่าสนใจคือสิ่งนี้ไม่ใช่ทางเลือก RFC 1122 ซึ่งเป็นเอกสารกำหนดว่า เครื่องที่ต่ออินเทอร์เน็ตต้องทำอะไรได้บ้าง ระบุไว้ในหัวข้อ 3.2.2.6 ว่า
ทุกโฮสต์ ต้อง ทำหน้าที่เป็น ICMP Echo server และตอบ ICMP Echo request ที่ส่งมาถึงตัวมันเอง
คำว่า "ต้อง" ในเอกสารมาตรฐานเป็นคำที่มีน้ำหนักทางเทคนิค ไม่ใช่คำแนะนำ เครื่องที่ไม่ตอบ ping จึงเป็นเครื่องที่มีคนตั้งใจปิดมัน ไม่ใช่เครื่องที่ ทำตามมาตรฐาน — จำข้อนี้ไว้ เดี๋ยวจะได้ใช้
ในซองมีอะไรอยู่บ้าง
นี่คือที่มาของเลข 64 ในบรรทัด 64 bytes from ... — มันคือ 56 ไบต์ของ ข้อมูลบวกกับ 8 ไบต์ของหัว ICMP ส่วนบนสายจริง ๆ แพ็กเก็ตยาว 84 ไบต์ เพราะมีหัว IP อีก 20 ไบต์ที่ ping ไม่นับให้
Identifier กับ Sequence Number มีไว้ทำไม
สองฟิลด์นี้แก้ปัญหาคนละอย่างกัน
Identifier ตอบคำถามว่า "คำตอบนี้เป็นของใคร" ถ้าคุณเปิด ping สามหน้าต่างพร้อมกันไปหาปลายทางเดียวกัน คำตอบทั้งหมดวิ่งกลับมาที่เครื่อง เดียวกัน ระบบปฏิบัติการต้องแยกให้ออกว่าอันไหนของหน้าต่างไหน โดยทั่วไป โปรแกรมจะใส่หมายเลขโปรเซสของตัวเองลงไปในฟิลด์นี้
Sequence Number ตอบคำถามว่า "นี่คือครั้งที่เท่าไหร่" มันเพิ่มขึ้นทีละหนึ่ง ทุกครั้งที่ส่ง และนี่คือฟิลด์ที่ทำให้คุณ เห็น ปัญหาได้ ไม่ใช่แค่เดา
- เลขข้ามไป เช่น 1, 2, 4 — แพ็กเก็ตที่ 3 หายไประหว่างทาง
- เลขมาไม่เรียง เช่น 1, 3, 2 — เส้นทางส่งของสลับลำดับ ซึ่งบางทีเป็นสัญญาณ ว่ามีการกระจายโหลดหลายเส้นทางอยู่
- เลขซ้ำ พร้อมคำว่า
(DUP!)— มีคนตอบซ้ำ มักเกิดจากส่งไปที่ที่อยู่ broadcast หรือมีลูปในเลเยอร์สอง
เวลาที่วัดได้มาจากไหน
คำถามที่คนถามบ่อยคือ ถ้าจะวัดเวลาไปกลับ นาฬิกาของสองเครื่องต้องตรงกันไหม
คำตอบคือ ไม่ต้อง และวิธีที่ใช้เลี่ยงปัญหานี้ฉลาดมาก
ตอนส่ง ping จะเขียนเวลาปัจจุบันของ ตัวเอง ลงไปในส่วน payload ของ แพ็กเก็ต ตามมาตรฐานแล้วปลายทางต้องคัดลอก payload ที่ได้รับกลับมาทั้งก้อน โดยไม่แก้ไข เมื่อคำตอบวิ่งกลับมาถึง ping ก็แค่อ่านเวลาที่ตัวเองเขียนไว้ ออกมา แล้วลบออกจากเวลาปัจจุบัน
เวลาทั้งสองค่าจึงมาจากนาฬิกาเรือนเดียวกัน ไม่ว่านาฬิกาของปลายทางจะเพี้ยน แค่ไหนก็ไม่มีผล
แนวคิดการออกแบบ — ทำไมมันถูกสร้างมาแบบนี้
โปรแกรมพันบรรทัดที่เขียนเสร็จในคืนเดียว ไม่น่าจะอยู่ได้สี่สิบปีถ้าการตัดสินใจ ตั้งต้นไม่ถูกต้อง หัวข้อนี้คือเหตุผลเบื้องหลังการตัดสินใจแต่ละข้อ และเป็นส่วนที่มีค่าที่สุดถ้าคุณเขียนเครื่องมือของตัวเองอยู่
1. ไม่สร้างโพรโทคอลใหม่ ใช้ของที่ทุกเครื่องถูกบังคับให้มี
นี่คือการตัดสินใจที่สำคัญที่สุด และเป็นเหตุผลเดียวที่ ping ใช้ได้จริง
ถ้า Muuss ออกแบบโพรโทคอลใหม่ เขาจะต้องมีโปรแกรมฝั่งปลายทางไปติดตั้งบน ทุกเครื่องที่อยากทดสอบ ซึ่งแปลว่ามันจะใช้ไม่ได้กับเครื่องที่คุณไม่ได้เป็น เจ้าของ — และเครื่องที่มีปัญหาส่วนใหญ่ก็คือเครื่องที่คุณไม่ได้เป็นเจ้าของ
การเลือก ICMP Echo ซึ่ง RFC บังคับให้ทุกโฮสต์ต้องตอบอยู่แล้ว แปลว่า ไม่ต้องติดตั้งอะไรที่ปลายทางเลย คุณ ping เครื่องที่ไม่เคยรู้จักคำว่า ping ได้ ping เราเตอร์ของผู้ให้บริการรายอื่นได้ ping เครื่องที่ผลิตขึ้นหลังจาก Muuss เสียชีวิตไปแล้วยี่สิบปีได้
เครื่องมือที่ต้องการความร่วมมือจากอีกฝ่าย คือเครื่องมือที่ใช้ไม่ได้ในวันที่ คุณต้องการมันที่สุด
2. ผู้ส่งไม่เก็บสถานะอะไรเลย
วิธีที่ตรงไปตรงมาในการวัดเวลาไปกลับ คือจดไว้ในตารางว่าส่งหมายเลขไหนไป ตอนกี่โมง แล้วพอคำตอบกลับมาก็ไปเปิดตารางดู
ping ไม่ทำแบบนั้น มันเขียนเวลาลงไป ในตัวแพ็กเก็ต แล้วปล่อยให้แพ็กเก็ต ถือมันไปเอง ผลที่ตามมามีมากกว่าที่คิด
- หน่วยความจำไม่โต ต่อให้ ping ค้างไว้เป็นเดือน
- คำตอบที่มาช้ามากหรือมาสลับลำดับ ก็ยังคำนวณเวลาได้ถูกต้อง
- โปรแกรมล่มแล้วเปิดใหม่ ไม่มีสถานะอะไรให้กู้
- และโค้ดสั้นพอที่จะเขียนเสร็จก่อนฟ้าสาง
นี่คือรูปแบบที่คนออกแบบระบบเรียกว่า self-describing message — ให้ข้อความพกทุกอย่างที่จำเป็นต่อการตีความมันเองไปด้วย
3. บังคับให้คัดลอก payload กลับมาทั้งก้อน
RFC 792 ระบุว่าปลายทางต้องส่งข้อมูลที่ได้รับกลับมาโดยไม่แก้ไข ข้อกำหนดข้อนี้ทำให้ ping ได้ความสามารถแถมมาฟรี ๆ ที่ไม่ได้ตั้งใจตั้งแต่แรก
ในเมื่อสิ่งที่ส่งไปกับสิ่งที่ได้กลับมาต้องเหมือนกันทุกบิต การเปรียบเทียบสองอย่างนี้ จึงกลายเป็น การทดสอบความถูกต้องของข้อมูลบนเส้นทาง ไม่ใช่แค่ทดสอบว่าถึงหรือไม่ถึง
คู่มือของ Linux เขียนเรื่องธง -p ไว้ตรง ๆ ว่ามีไว้เพื่อ "วินิจฉัยปัญหาที่ขึ้นกับ รูปแบบข้อมูลในเครือข่าย" หัวข้อตัวอย่างข้างล่างมีกรณีจริงของเรื่องนี้
4. Identifier ทำหน้าที่แทนหมายเลขพอร์ต
ICMP ไม่มีพอร์ต เพราะมันไม่ใช่โพรโทคอลสำหรับส่งข้อมูลของผู้ใช้ แต่ปัญหาเดิมยังอยู่ — เครื่องหนึ่งเครื่องอาจมี ping ทำงานอยู่พร้อมกันหลายตัว และคำตอบทุกอันวิ่งกลับมาที่เดียวกัน
ฟิลด์ Identifier จึงถูกใช้เป็นพอร์ตจำแลง โดยแต่ละโปรเซสใส่หมายเลขของตัวเองลงไป เป็นการแก้ปัญหาโดยไม่ต้องแก้โพรโทคอล ซึ่งเป็นลายเซ็นของงานออกแบบยุคนั้น
5. ทำให้ "เห็น" การสูญหาย ไม่ใช่ "อนุมาน"
ถ้า ping พิมพ์แค่บรรทัดสรุปตอนจบว่าหายไปกี่เปอร์เซ็นต์ คุณจะรู้ว่ามีปัญหา แต่ไม่รู้ว่าปัญหามีรูปร่างแบบไหน
การพิมพ์ทีละบรรทัดพร้อมหมายเลขลำดับ ทำให้ รูปแบบ ของความเสียหายมองเห็นได้ หายกระจัดกระจายทีละอันคือสัญญาณรบกวน หายติดกันเป็นชุดคือลิงก์สะดุดหรือ เส้นทางเปลี่ยน หายเป็นจังหวะสม่ำเสมอคือ rate limit
ข้อมูลชุดเดียวกัน แต่รูปแบบการนำเสนอต่างกัน ให้คำตอบคนละคำถาม
6. รายงานสิ่งที่เห็น ไม่ตีความแทนคุณ
ping ไม่เคยพูดว่า "เครือข่ายปกติดี" หรือ "เซิร์ฟเวอร์ล่ม" มันบอกแค่ว่า ส่งอะไรออกไป ได้อะไรกลับมา และใช้เวลาเท่าไหร่ การสรุปเป็นหน้าที่ของคน
นี่ฟังดูเหมือนความขี้เกียจ แต่มันคือเหตุผลที่เครื่องมือนี้ไม่มีวันผิด เครื่องมือที่ตีความให้ จะตีความผิดในวันที่เครือข่ายทำตัวนอกกรอบที่ผู้เขียนคิดไว้ ส่วนเครื่องมือที่รายงานอย่างเดียว จะยังถูกต้องเสมอ แม้ในสถานการณ์ที่ ผู้เขียนไม่เคยจินตนาการถึง — ซึ่งสี่สิบปีมานี้มีเยอะมาก
7. เอาต์พุตเป็นข้อความ จึงต่อท่อกับอะไรก็ได้
Muuss เล่าไว้เองว่ามีผู้ดูแลระบบคนหนึ่งเอาเอาต์พุตของ ping ต่อเข้ากับ โปรแกรมสังเคราะห์เสียง แล้วปล่อยออกลำโพง จากนั้นก็เดินไปตามอาคาร ฟังว่าเสียงหยุดตรงไหน แล้วเจอจุดที่สายอีเทอร์เน็ตเสียแบบเป็น ๆ หาย ๆ
ไม่มีใครออกแบบ ping มาเพื่อรองรับกรณีนี้ มันเป็นไปได้เพราะเอาต์พุตเป็น ข้อความธรรมดา บรรทัดละหนึ่งเหตุการณ์ เท่านั้นเอง
เชิงอรรถ: จากที่ต้องแก้เคอร์เนล มาถึงวันที่ไม่ต้องเป็น root
ตอนปี 1983 Muuss ต้องเพิ่ม raw ICMP socket เข้าไปในเคอร์เนลก่อน และ raw socket เป็นสิทธิ์ระดับสูง ping จึงต้องเป็นโปรแกรม setuid root มาตลอดหลายสิบปี ซึ่งเป็นเรื่องที่คนทำงานความปลอดภัยไม่สบายใจมาตลอดเช่นกัน
ลินุกซ์ยุคใหม่มีทางที่สามคือ ICMP datagram socket ซึ่งให้สิทธิ์เฉพาะการส่ง Echo Request เท่านั้น ไม่ใช่ ICMP ทั้งหมด ควบคุมด้วยค่านี้
sysctl net.ipv4.ping_group_range
ถ้ากลุ่มของผู้ใช้อยู่ในช่วงนี้ ping ทำงานได้โดยไม่ต้องมีสิทธิ์พิเศษใด ๆ ระบบส่วนใหญ่ทุกวันนี้ตั้งค่าแบบนั้นแล้ว
ค่าที่เกี่ยวข้องอีกชุดคือการจำกัดอัตราการตอบของตัวเครื่องเอง
net.ipv4.icmp_echo_ignore_all ปิดการตอบ ping ทั้งหมด
net.ipv4.icmp_echo_ignore_broadcasts ไม่ตอบ ping ที่ส่งมาแบบ broadcast
net.ipv4.icmp_ratelimit จำกัดอัตราการส่ง ICMP ออก
net.ipv4.icmp_ratemask เลือกว่าชนิดไหนบ้างที่ถูกจำกัด
ค่ากลุ่มหลังนี้คือคำอธิบายของอาการที่เจอบ่อยมาก — ping ไปที่เครื่องหนึ่ง แล้วเห็นการสูญหายเป็นจังหวะสม่ำเสมอเกินกว่าจะเป็นเรื่องบังเอิญ นั่นไม่ใช่เครือข่ายมีปัญหา นั่นคือเครื่องปลายทางกำลังจำกัดอัตราการตอบอยู่
อ่านผลลัพธ์ให้ออกทุกฟิลด์
64 bytes from 8.8.8.8: icmp_seq=1 ttl=115 time=12.3 ms
| | | | |
| | | | +-- RTT
| | | +-- TTL left
| | +-- sequence
| +-- who answered
+-- ICMP size (56 payload + 8 header)
ฟิลด์ที่คนมองข้ามบ่อยที่สุดคือ "ใครตอบ" เพราะโดยปกติมันก็คือคนที่เราถาม แต่ไม่เสมอไป ถ้าที่อยู่ที่ตอบกลับมาไม่ใช่ที่อยู่ที่คุณพิมพ์ไป นั่นเป็นข้อมูล สำคัญ — อาจมีเราเตอร์ตัวหนึ่งตอบแทนว่า "ไปต่อไม่ได้"
บรรทัดสรุปตอนท้ายมีค่าที่ควรอ่านสี่ค่า
- min เวลาที่ดีที่สุด — คือค่าที่ใกล้เคียงกับ "ระยะทางจริง" มากที่สุด
- avg ค่าเฉลี่ย
- max ค่าที่แย่ที่สุด
- stddev หรือ mdev คือความกระจาย
ค่าสุดท้ายสำคัญกว่าที่หน้าตามันดู เส้นทางที่ได้ 50 ms ทุกครั้งเป๊ะ ๆ ใช้งานดีกว่าเส้นทางที่เฉลี่ย 30 ms แต่แกว่งอยู่ระหว่าง 5 ถึง 200 ms มาก เพราะการประชุมทางวิดีโอและเสียงพังเพราะความแกว่ง ไม่ได้พังเพราะความช้า
ttl= บอกอะไรได้บ้าง
ttl ที่เห็นในคำตอบ ไม่ใช่ค่าที่คุณส่งไป แต่เป็นค่าที่เหลืออยู่ในแพ็กเก็ต ขากลับ ตอนที่มันมาถึงเครื่องคุณ
TTL ย่อมาจาก Time To Live เป็นตัวเลขในหัว IP ที่เราเตอร์ทุกตัวที่แพ็กเก็ต วิ่งผ่านจะลดลงหนึ่ง มันมีไว้กันแพ็กเก็ตวิ่งวนไม่รู้จบเวลาเส้นทางผิดพลาด
ประโยชน์คือค่าตั้งต้นของแต่ละระบบปฏิบัติการต่างกันและเป็นเลขที่รู้กัน
64 Linux, macOS, และ BSD ส่วนใหญ่
128 Windows
255 อุปกรณ์เครือข่ายจำนวนมาก เช่น Cisco IOS
เห็น ttl=115 แล้วเดาได้ทันทีว่าค่าตั้งต้นคือ 128 แล้วผ่านเราเตอร์มา 13 ตัว และปลายทางน่าจะเป็น Windows เห็น ttl=52 ก็เดาว่าตั้งต้นที่ 64 ผ่านมา 12 ตัว และน่าจะเป็นเครื่องตระกูล Unix
เป็นการเดา ไม่ใช่การพิสูจน์ ผู้ดูแลระบบเปลี่ยนค่าตั้งต้นได้ และบางคนก็เปลี่ยน เพื่อไม่ให้ใครเดาได้แบบนี้ แต่มันถูกบ่อยพอที่จะเป็นเบาะแสแรกที่ดี
เมื่อ TTL หมด แล้วเกิดอะไรขึ้น
เราเตอร์ที่ลด TTL แล้วได้ศูนย์ จะทิ้งแพ็กเก็ตนั้น แล้วส่งข้อความ ICMP อีกชนิดกลับมาบอกต้นทางว่า "ของคุณหมดอายุที่ผมนะ" ข้อความนั้นคือ ICMP Time Exceeded หรือ type 11
และนี่คือกลไกทั้งหมดของ traceroute
TTL=1 --> R1 : becomes 0 -> drop + Time Exceeded from R1
TTL=2 --> R1 -> R2 : Time Exceeded from R2
TTL=3 --> R1 -> R2 -> R3 : Time Exceeded from R3
TTL=4 --> reaches the target -> Echo Reply -> done
traceroute ไม่ได้มีความสามารถวิเศษอะไร มันแค่ยิงซ้ำ ๆ โดยเพิ่ม TTL ทีละหนึ่ง แล้วจดว่าใครเป็นคนบ่นกลับมาในแต่ละรอบ ที่อยู่ของคนบ่นก็คือเส้นทางนั่นเอง
ลองเองได้ด้วย ping ธรรมดา
ping -t 1 8.8.8.8 # macOS/BSD ใช้ -m 1
จะได้คำตอบจากเราเตอร์ตัวแรกที่ออกจากบ้านคุณ แทนที่จะได้จากปลายทาง
ธงที่ใช้จริง
Linux (iputils)
-c N ส่ง N ครั้งแล้วหยุด
-i SEC เว้นระยะกี่วินาทีต่อครั้ง
-s BYTES ขนาด payload (ค่าปกติ 56)
-t TTL ตั้ง TTL ขาออก
-W SEC รอคำตอบแต่ละครั้งนานเท่าไหร่
-w SEC เลิกทั้งหมดหลังกี่วินาที
-D พิมพ์ timestamp ทุกบรรทัด
-M do ตั้ง DF ห้ามแตกแฟรกเมนต์
-n ไม่ต้องแปลงเป็นชื่อ
-f flood ต้องเป็น root
-p HEX ถม payload ด้วยรูปแบบนี้
-I NAME ส่งออกจากอินเทอร์เฟซหรือที่อยู่นี้
macOS และ BSD
-c 4 สี่ครั้ง เหมือน Linux
-s 1472 ขนาด payload เหมือน Linux
-D ตั้ง DF <-- ไม่ใช่ timestamp
-t 5 หยุดหลัง 5 วินาที <-- ไม่ใช่ TTL
-m 64 ตั้ง TTL ขาออก <-- อันนี้ต่างหากคือ TTL
-g 1400 -G 1500 -h 8 ไล่ขนาดขึ้นทีละ 8 เพื่อหา MTU
นี่คือกับดักข้ามแพลตฟอร์มที่กัดคนมาเยอะที่สุด -D กับ -t ทำคนละเรื่อง กันสิ้นเชิงบน Linux กับ macOS สคริปต์ที่เขียนบนเครื่อง Linux แล้วเอาไปรัน บน Mac จะไม่ error แต่จะทำอย่างอื่นเงียบ ๆ
Windows
ping -n 4 host สี่ครั้ง
ping -t host ส่งไปเรื่อย ๆ จนกด Ctrl-C
ping -l 1472 host ขนาด payload
ping -f host ตั้ง DF ห้ามแตกแฟรกเมนต์
ping -i 64 host ตั้ง TTL ขาออก
ping -w 2000 host รอคำตอบกี่มิลลิวินาที
ping -4 host บังคับใช้ IPv4
ping -6 host บังคับใช้ IPv6
สังเกตว่า -t บน Windows แปลว่า "ส่งไม่หยุด" ส่วน -t บน Linux แปลว่า TTL และ -i บน Windows แปลว่า TTL ส่วน -i บน Linux แปลว่าระยะเวลาระหว่างครั้ง สลับกันหมด อ่าน man page ของเครื่องที่กำลังนั่งอยู่เสมอ
ใช้ ping หา MTU ของเส้นทาง
MTU คือขนาดใหญ่ที่สุดของแพ็กเก็ตที่เส้นทางหนึ่งรับได้ ปกติบนอีเทอร์เน็ต คือ 1500 ไบต์ แต่ถ้ามีอุโมงค์ VPN หรือ PPPoE อยู่กลางทาง ตัวเลขจะเล็กลง และนั่นคือต้นเหตุของอาการคลาสสิก — เว็บบางเว็บเปิดได้ บางเว็บค้างครึ่งหน้า
วิธีหาคือส่งแพ็กเก็ตใหญ่ ๆ พร้อมสั่งห้ามแตกแฟรกเมนต์ (ตั้งบิต DF)
ping -M do -s 1472 8.8.8.8 -> 1472 + 8 + 20 = 1500 ผ่าน
ping -M do -s 1473 8.8.8.8 -> 1501 ไบต์ ใหญ่เกิน
เราเตอร์ทิ้ง แล้วส่งกลับมา
ICMP type 3 code 4 พร้อมบอก mtu
จำเลข 28 ไว้ นั่นคือ 20 ไบต์ของหัว IP บวก 8 ไบต์ของหัว ICMP ดังนั้น MTU ที่ต้องการเท่ากับค่า -s บวก 28 เสมอ
- MTU 1500 อีเทอร์เน็ตปกติ ใช้
-s 1472 - MTU 1492 PPPoE ใช้
-s 1464 - MTU 1400 อุโมงค์ VPN หลายชนิด ใช้
-s 1372
บน Windows ใช้ ping -f -l 1472 host และบน macOS ใช้ ping -D -s 1472 host
IPv6
ทุกอย่างข้างบนใช้ได้กับ IPv6 หมด เปลี่ยนแค่ตัวเลข
- type 128 คือ Echo Request
- type 129 คือ Echo Reply
- อยู่ในหมายเลขโพรโทคอลที่ 58 ไม่ใช่ 1
- MTU ต่ำสุดที่มาตรฐานรับประกันคือ 1280 ไบต์ ไม่ใช่ 576 แบบ IPv4
บนระบบใหม่ ๆ ไม่ต้องใช้คำสั่ง ping6 แยกอีกแล้ว ping ตัวเดียวจัดการ ทั้งสองตระกูล ใช้ -4 หรือ -6 บังคับได้ถ้าต้องการ
ลูกเล่นที่มีประโยชน์มากและไม่มีใน IPv4 คือการ ping ที่อยู่มัลติแคสต์ ff02::1 ซึ่งหมายถึง "ทุกเครื่องบนสายเส้นนี้"
ping -6 ff02::1%en0
ทุกเครื่องที่อยู่บนวงเดียวกันจะตอบกลับมาหมด เป็นวิธีสำรวจว่ามีอะไรอยู่บนสาย บ้างโดยไม่ต้องสแกน ส่วนที่ตามหลัง % คือชื่ออินเทอร์เฟซ ซึ่งจำเป็น เพราะที่อยู่ระดับลิงก์ของ IPv6 ซ้ำกันได้ในแต่ละสาย เครื่องจึงต้องรู้ว่า จะให้ส่งออกทางไหน
อีกข้อที่ต่างกันคือ IPv6 ไม่มี ARP มันใช้ Neighbor Discovery ซึ่งทำงานบน ICMPv6 นั่นแปลว่า ICMPv6 ไม่ใช่ของเสริมที่ปิดทิ้งได้ ถ้าปิดหมด เครือข่ายจะไม่ทำงานเลย ไม่ใช่แค่ ping ไม่ได้
เมื่อ ping โกหก
ถึงตรงนี้คือส่วนที่แยกคนที่ใช้ ping เป็น ออกจากคนที่พิมพ์ ping ได้
1. เราเตอร์ตอบช้า ไม่ได้แปลว่าเส้นทางช้า
เราเตอร์สมัยใหม่ส่งต่อแพ็กเก็ตด้วยฮาร์ดแวร์เฉพาะทางที่เร็วมาก แต่การ ตอบ ping เป็นงานที่ต้องส่งขึ้นไปให้ซีพียูของตัวเครื่องทำ ซึ่งเป็นคนละ เส้นทางกันโดยสิ้นเชิง และเป็นเส้นทางที่ถูกจัดลำดับความสำคัญไว้ต่ำ
ผลคือ traceroute ที่แสดงว่าฮอปกลางทางหน่วงเป็นร้อยมิลลิวินาที แต่ปลายทางสุดท้ายกลับเร็ว เป็นเรื่องปกติและไม่ได้แปลว่ามีปัญหา เราเตอร์ตัวนั้นแค่ไม่ถือว่าการตอบ ping เป็นงานสำคัญ
กฎง่าย ๆ คือ ดูเวลาที่ปลายทางสุดท้าย ไม่ใช่ที่ฮอปกลางทาง และให้เชื่อตัวเลขที่ เพิ่มขึ้นแล้วไม่ลดลงอีก เท่านั้น
2. ไม่ตอบ ไม่ได้แปลว่าตาย
มาตรฐานบอกว่าต้องตอบ แต่ผู้ดูแลระบบจำนวนมากปิดมัน ไฟร์วอลล์องค์กร เกือบทุกที่ทิ้ง ICMP จากภายนอก และผู้ให้บริการคลาวด์หลายรายปิดไว้ตั้งแต่ต้น
ping ไม่ตอบจึงพิสูจน์ได้แค่ว่า ping ไม่ตอบ ไม่ได้พิสูจน์ว่าเครื่องดับ ถ้าเป็นเว็บเซิร์ฟเวอร์ ให้ลองต่อพอร์ต 443 ตรง ๆ ก่อนจะสรุปอะไร
3. ที่อยู่เดียวกัน อาจเป็นคนละเครื่อง
8.8.8.8 ไม่ใช่เครื่องเดียวในโลก มันเป็นที่อยู่แบบ anycast ซึ่งประกาศ จากศูนย์ข้อมูลหลายสิบแห่งพร้อมกัน แล้วเราเตอร์จะพาคุณไปที่ใกล้ที่สุด
คุณกับเพื่อนที่อยู่คนละประเทศ ping ที่อยู่เดียวกัน แต่คุยกับคนละเครื่อง และถ้าเส้นทางเปลี่ยนกลางคัน คุณอาจเปลี่ยนเครื่องที่คุยด้วยระหว่าง ping ค้างอยู่ก็ได้ โดยไม่มีอะไรบอกคุณเลย
4. RTT ไม่ใช่สองเท่าของขาไป
ping วัดเวลาไปกลับ ไม่ได้วัดขาเดียว และเส้นทางขาไปกับขากลับ ไม่จำเป็นต้องเป็นเส้นเดียวกัน ในอินเทอร์เน็ตจริงมันมักไม่ใช่ด้วยซ้ำ
ดังนั้นการเอา RTT หารสองแล้วบอกว่านั่นคือเวลาขาไป เป็นการเดาที่ผิดได้มาก และเป็นเหตุผลที่การวัดความหน่วงขาเดียวจริง ๆ ต้องใช้เครื่องมือที่มีนาฬิกา ตรงกันทั้งสองฝั่ง
5. ping ตอนว่าง กับ ping ตอนใช้งานจริง คนละเรื่อง
ping ที่ 10 ms ตอนไม่มีใครใช้เน็ต แล้วพุ่งเป็น 800 ms ตอนมีคนดาวน์โหลด ไม่ใช่ความผิดของเส้นทาง แต่คือคิวในอุปกรณ์ของคุณเองที่บวมขึ้น อาการนี้มีชื่อเรียกว่า bufferbloat
วิธีทดสอบคือเปิด ping ค้างไว้ แล้วเริ่มดาวน์โหลดไฟล์ใหญ่ ถ้าตัวเลข กระโดดขึ้นสิบเท่า คุณเจอมันแล้ว และคำตอบไม่ใช่เน็ตที่เร็วขึ้น แต่คือการจัดการคิวที่ดีขึ้น
เรื่องความปลอดภัย
Smurf
สมัยก่อนถ้าส่ง Echo Request ไปที่ที่อยู่ broadcast ของเครือข่ายหนึ่ง เครื่องทุกเครื่องในนั้นจะตอบกลับมาหมด ผู้โจมตีจึงปลอมที่อยู่ต้นทาง เป็นเหยื่อ แล้วยิงไปที่ broadcast ของเครือข่ายใหญ่ ๆ ทำให้คำตอบนับพัน ถล่มเหยื่อพร้อมกัน
วิธีแก้อยู่ใน RFC 2644 ซึ่งเปลี่ยนค่าตั้งต้นของเราเตอร์ให้ ไม่ ส่งต่อ directed broadcast อีกต่อไป ทุกวันนี้จึงแทบไม่เจอแล้ว แต่มันเป็นเหตุผล ที่ค่าตั้งต้นบางอย่างเป็นแบบที่เป็นอยู่
Ping of Death
ช่องโหว่ยุคกลางทศวรรษ 1990 ที่ส่งแพ็กเก็ต ICMP ซึ่งเมื่อประกอบแฟรกเมนต์ กลับเข้าด้วยกันแล้วใหญ่เกิน 65535 ไบต์ ทำให้ระบบปฏิบัติการยุคนั้นค้าง หรือรีบูต ปัจจุบันปิดไปหมดแล้ว แต่ชื่อยังติดปากอยู่
การลักลอบส่งข้อมูลผ่าน ICMP
payload ของ ping บรรจุอะไรก็ได้ และไม่มีใครสนใจว่ามันคืออะไร เครื่องมือประเภทหนึ่งจึงใช้ช่องนี้ขนข้อมูลออกจากเครือข่ายที่บล็อกทุกอย่าง ยกเว้น ping ถ้าคุณเห็น ICMP ปริมาณมากผิดปกติวิ่งออกนอกองค์กร นั่นควรเป็นเรื่องที่ต้องดู ไม่ใช่เรื่องที่มองข้าม
ทำไมการบล็อก ICMP ทั้งหมดเป็นความคิดที่แย่
นี่คือข้อที่สำคัญที่สุดในหัวข้อนี้
การค้นหา MTU ของเส้นทางอัตโนมัติ ทำงานได้ด้วยข้อความ ICMP type 3 code 4 ที่แปลว่า "ใหญ่เกิน ต้องแตกแฟรกเมนต์ แต่คุณห้ามไว้" ถ้าไฟร์วอลล์ทิ้ง ข้อความนี้ ต้นทางจะไม่มีวันรู้ว่าต้องส่งเล็กลง มันจะส่งขนาดเดิมซ้ำไปเรื่อย ๆ และแพ็กเก็ตจะหายเงียบทุกครั้ง
อาการที่ได้คือสิ่งที่เรียกว่า PMTU black hole — การเชื่อมต่อเริ่มต้นได้ ปกติ จับมือ TCP สำเร็จ เปิดหน้าเว็บเล็ก ๆ ได้ แต่พอเจอหน้าที่ใหญ่ขึ้น ก็ค้างไปเฉย ๆ เป็นอาการที่ตามหาสาเหตุยากมาก และต้นเหตุคือกฎไฟร์วอลล์ บรรทัดเดียวที่เขียนว่า "ทิ้ง ICMP ทั้งหมด"
สำหรับ IPv6 ยิ่งหนักกว่า เพราะ ICMPv6 ทำงานพื้นฐานของเครือข่ายด้วย RFC 4890 มีไว้เพื่อบอกโดยเฉพาะว่าข้อความชนิดไหนบล็อกได้ ชนิดไหนห้ามบล็อก ถ้าต้องเขียนกฎไฟร์วอลล์สำหรับ IPv6 อ่านฉบับนั้นก่อน
ตัวอย่างจริงจากงานจริง
หัวข้อนี้เขียนสำหรับคนที่ต้องแก้ปัญหาให้จบภายในเวลาที่กำหนด แต่ละกรณีมีโครงเดียวกัน — สถานการณ์ คำสั่ง ผลที่ได้ วิธีอ่าน และข้อสุดท้ายที่สำคัญที่สุดคือ สิ่งที่หลักฐานชิ้นนี้ยังไม่ได้พิสูจน์
กรณีที่ 1 — "เน็ตช้า" ที่ไม่ใช่เน็ต
ผู้ใช้แจ้งว่าระบบภายในช้ามากตั้งแต่เช้า ทีมเครือข่ายถูกเรียกก่อนเสมอ
$ ping -c 20 app.internal
20 packets transmitted, 20 received, 0% packet loss
rtt min/avg/max/mdev = 0.412/0.470/0.612/0.052 ms
$ curl -o /dev/null -s \
-w 'connect=%{time_connect} ttfb=%{time_starttransfer}\n' \
https://app.internal/
connect=0.002 ttfb=4.311
อ่านอย่างไร เส้นทางไปกลับใช้เวลาไม่ถึงครึ่งมิลลิวินาที ไม่มีการสูญหาย และค่าความแกว่งต่ำมาก การเชื่อมต่อ TCP เสร็จใน 2 มิลลิวินาที แต่กว่าจะได้ไบต์แรกของคำตอบใช้เวลา 4.3 วินาที
ช่องว่างระหว่าง 2 มิลลิวินาที กับ 4.3 วินาที ไม่ได้อยู่ในเครือข่าย มันอยู่ในแอปพลิเคชันหรือฐานข้อมูลข้างหลังมัน
สิ่งที่ยังไม่ได้พิสูจน์ เรายังไม่รู้ว่าช้าเพราะอะไร รู้แค่ว่าไม่ใช่เพราะ เส้นทาง และการวัดนี้เป็นตัวแทนของ ช่วงเวลาที่วัด เท่านั้น ถ้าอาการเป็น ๆ หาย ๆ ต้องวัดค้างไว้ ไม่ใช่วัดครั้งเดียว
กรณีที่ 2 — MTU black hole ในอุโมงค์ VPN
อาการคลาสสิกที่สุด ผู้ใช้ผ่าน VPN บอกว่าเข้าเว็บภายในได้ หน้า login ขึ้นปกติ แต่พอกดเข้าไปหน้าที่มีข้อมูลเยอะ เบราว์เซอร์ค้างจนหมดเวลา
$ ping -c 3 -M do -s 1472 10.20.0.5
PING 10.20.0.5 (10.20.0.5) 1472(1500) bytes of data.
From 10.0.0.1 icmp_seq=1 Frag needed and DF set (mtu = 1400)
From 10.0.0.1 icmp_seq=2 Frag needed and DF set (mtu = 1400)
เจอตัวแล้วในสามวินาที เราเตอร์ที่ 10.0.0.1 บอกตรง ๆ ว่าเส้นทางนี้รับได้ แค่ 1400 ไบต์ ยืนยันด้วยการไล่ขนาด
$ for s in 1372 1373 1400 1472; do
> printf '%5d ' "$s"
> ping -M do -s "$s" -c 1 -W 1 10.20.0.5 >/dev/null 2>&1 \
> && echo ok || echo fail
> done
1372 ok
1373 fail
1400 fail
1472 fail
อ่านอย่างไร 1372 บวก 28 เท่ากับ 1400 พอดี ผ่าน ส่วน 1373 ไม่ผ่าน MTU จริงของเส้นทางคือ 1400 การจับมือ TCP ใช้แพ็กเก็ตเล็กจึงสำเร็จเสมอ ปัญหาโผล่เฉพาะตอนส่งข้อมูลก้อนใหญ่ ซึ่งตรงกับอาการที่ผู้ใช้เล่า
กรณีที่แย่กว่าคือไม่ได้บรรทัด Frag needed เลย — เงียบสนิท นั่นแปลว่ามีไฟร์วอลล์ตัวใดตัวหนึ่งกลางทางทิ้ง ICMP type 3 code 4 ทิ้ง ต้นทางจึงไม่มีวันรู้ว่าต้องส่งเล็กลง นี่คือ PMTU black hole ตัวจริง และวิธีหา MTU ในกรณีนั้นคือไล่ขนาดเอาแบบข้างบน เพราะไม่มีใครบอกให้
สิ่งที่ยังไม่ได้พิสูจน์ เรารู้ค่า MTU ของเส้นทาง นี้ ณ ตอนนี้ เส้นทางขากลับอาจต่างออกไป และถ้าเป็นเครือข่ายที่มีหลายเส้นทาง ค่าที่ได้อาจเปลี่ยนเมื่อการกระจายโหลดพาไปอีกเส้น
กรณีที่ 3 — IP ซ้ำ ที่มองไม่เห็นด้วยตาเปล่า
เครื่องหนึ่งเข้าถึงได้บ้างไม่ได้บ้าง แบบไม่มีรูปแบบ
$ ping -c 3 192.168.10.50
64 bytes from 192.168.10.50: icmp_seq=1 ttl=64 time=0.42 ms
64 bytes from 192.168.10.50: icmp_seq=1 ttl=128 time=1.90 ms (DUP!)
64 bytes from 192.168.10.50: icmp_seq=2 ttl=64 time=0.39 ms
64 bytes from 192.168.10.50: icmp_seq=2 ttl=128 time=2.11 ms (DUP!)
อ่านอย่างไร คำถามหนึ่งข้อ ได้คำตอบสองอัน และที่สำคัญกว่านั้นคือ ค่า ttl ไม่เท่ากัน 64 กับ 128 ไม่ได้มาจากเครื่องเดียวกันแน่นอน เพราะมันคือค่าตั้งต้นของระบบปฏิบัติการคนละตระกูล
มีสองเครื่องถือที่อยู่เดียวกันอยู่ ยืนยันต่อด้วยตารางเพื่อนบ้าน
$ ip neigh show 192.168.10.50
192.168.10.50 dev eth0 lladdr 00:1b:21:3a:5c:9e REACHABLE
$ ip neigh show 192.168.10.50
192.168.10.50 dev eth0 lladdr 4c:52:62:11:07:d3 REACHABLE
MAC address เปลี่ยนไปมาระหว่างสองค่า ปิดคดี
สิ่งที่ยังไม่ได้พิสูจน์ (DUP!) ไม่ได้แปลว่า IP ซ้ำเสมอไป มันเกิดจากลูปในเลเยอร์สอง หรือจากการ ping ที่อยู่ broadcast ได้ด้วย ตัวชี้ขาดในกรณีนี้คือ ttl ที่ต่างกัน ไม่ใช่คำว่า DUP เอง
กรณีที่ 4 — การสูญหายที่ไม่มีอยู่จริง
ผลจากระบบเฝ้าระวังบอกว่าเราเตอร์กลางทางตัวหนึ่งสูญเสียแพ็กเก็ต 29% ทุกคนตื่นตระหนก
$ ping -c 100 -i 0.2 203.0.113.1 # ถามตัวเราเตอร์เอง
100 packets transmitted, 71 received, 29% packet loss
$ ping -c 100 -i 0.2 203.0.113.200 # ถามเครื่องที่อยู่ถัดจากมันไป
100 packets transmitted, 100 received, 0% packet loss
อ่านอย่างไร ถ้าเราเตอร์ตัวนั้นทำแพ็กเก็ตหายจริง เครื่องที่อยู่หลังมัน จะต้องหายด้วย เพราะทุกอย่างต้องวิ่งผ่านมัน แต่ปลายทางได้ครบ 100 จาก 100
แปลว่าเส้นทางไม่ได้ทำอะไรหาย สิ่งที่หายคือ คำตอบที่ตัวเราเตอร์ต้องสร้างเอง ซึ่งเป็นงานของซีพียูมันและถูกจำกัดอัตราไว้ ตรงกับค่า icmp_ratelimit ในหัวข้อก่อนหน้าพอดี
นี่คือกฎที่ควรจำ — วัดเสมอผ่านอุปกรณ์ ไม่ใช่วัดที่ตัวอุปกรณ์
สิ่งที่ยังไม่ได้พิสูจน์ ยังเป็นไปได้ที่เราเตอร์ตัวนั้นมีปัญหาจริง แต่มีปัญหาเฉพาะกับทราฟฟิกบางประเภทที่ ping ไม่ได้จำลอง หลักฐานชุดนี้ตัดออกได้แค่ข้อกล่าวหาว่า "ทำแพ็กเก็ตที่วิ่งผ่านหาย"
กรณีที่ 5 — จับ bufferbloat ให้เห็นกับตา
ผู้ใช้บอกว่าประชุมออนไลน์กระตุกทุกครั้งที่มีคนอัปโหลดไฟล์
เปิดสองหน้าต่าง หน้าต่างแรกปล่อย ping ค้างไว้พร้อมประทับเวลา
$ ping -D -i 0.2 8.8.8.8
[1756500000.101] 64 bytes from 8.8.8.8: icmp_seq=12 ttl=115 time=11.9 ms
[1756500000.301] 64 bytes from 8.8.8.8: icmp_seq=13 ttl=115 time=12.1 ms
... เริ่มอัปโหลดไฟล์ใหญ่ในหน้าต่างที่สอง ...
[1756500004.902] 64 bytes from 8.8.8.8: icmp_seq=35 ttl=115 time=612 ms
[1756500005.104] 64 bytes from 8.8.8.8: icmp_seq=36 ttl=115 time=845 ms
อ่านอย่างไร ความหน่วงขึ้นจาก 12 เป็น 845 มิลลิวินาที โดยไม่มีการสูญหาย ถ้าเป็นปัญหาของเส้นทางหรือของแบนด์วิดท์ จะเห็นการสูญหายด้วย การที่ ไม่หายเลยแต่ช้าลงมหาศาล คือลายเซ็นของคิวที่บวม แพ็กเก็ตทุกอันยังไปถึง แค่ต้องต่อแถวยาวขึ้นมาก
ธง -D สำคัญตรงนี้เพราะมันผูกตัวเลขเข้ากับเวลาจริง ทำให้เทียบกับ ช่วงเวลาที่เริ่มอัปโหลดได้ ไม่ต้องเดา
สิ่งที่ยังไม่ได้พิสูจน์ เรายังไม่รู้ว่าคิวที่บวมอยู่ตรงไหน อาจเป็นเราเตอร์ที่บ้าน อาจเป็นอุปกรณ์ของผู้ให้บริการ ต้องยิงไปหลายจุดบนเส้นทางเพื่อหาว่าอาการเริ่มที่ฮอปไหน
กรณีที่ 6 — ลิงก์ที่พังเฉพาะบางรูปแบบข้อมูล
กรณีที่หายากแต่เมื่อเจอแล้วจะเสียเวลามากถ้าไม่รู้จัก ลิงก์หนึ่งดูปกติทุกอย่าง ping ธรรมดาผ่านหมด แต่บางแอปพลิเคชันพังเป็นประจำ
$ ping -c 200 -p 00 10.30.0.9
200 packets transmitted, 200 received, 0% packet loss
$ ping -c 200 -p ff 10.30.0.9
200 packets transmitted, 200 received, 0% packet loss
$ ping -c 200 -p 55 10.30.0.9
200 packets transmitted, 173 received, 13.5% packet loss
อ่านอย่างไร ข้อมูลที่เป็นศูนย์ล้วนหรือหนึ่งล้วนผ่านหมด แต่รูปแบบ 55 ซึ่งเลขฐานสองคือ 01010101 สลับกันถี่ที่สุด กลับหายไป 13.5%
ความผิดพลาดที่ขึ้นกับรูปแบบข้อมูลแบบนี้เกือบทั้งหมดเป็นปัญหาชั้นกายภาพ — สายที่ไม่ได้มาตรฐาน โมดูล SFP ที่กำลังจะเสีย ระยะทางเกินสเปก หรือวงจรกู้สัญญาณนาฬิกาที่ทำงานไม่ไหวเมื่อสัญญาณสลับถี่ ๆ
นี่คือความสามารถที่เกิดจากข้อกำหนดที่ว่าปลายทางต้องคัดลอก payload กลับมา ทั้งก้อน ตามที่เขียนไว้ในหัวข้อแนวคิดการออกแบบ
สิ่งที่ยังไม่ได้พิสูจน์ ยังไม่รู้ว่าอยู่ช่วงไหนของสาย ขั้นถัดไปคือดูตัวนับข้อผิดพลาดของอินเทอร์เฟซทั้งสองฝั่ง และค่ากำลังแสงถ้าเป็นไฟเบอร์
กรณีที่ 7 — เขียนสคริปต์เฝ้าระวังให้ถูกต้อง
จุดที่สคริปต์ตรวจสอบสุขภาพระบบพลาดกันมากที่สุด
ปัญหาแรก ใช้แพ็กเก็ตเดียวตัดสิน ping -c 1 แปลผลเป็นผ่านหรือไม่ผ่าน เท่านั้น เครือข่ายที่ปกติดีก็ทำแพ็กเก็ตหายได้เป็นครั้งคราว ระบบเฝ้าระวังแบบนั้นจะปลุกคุณตอนตีสามด้วยเรื่องที่ไม่มีอยู่จริง
วัดเป็นสัดส่วนแทน
$ ping -c 5 -i 0.2 -W 1 10.0.0.8 | awk -F', ' '/packet loss/{print $3}'
0% packet loss
ปัญหาที่สอง exit code ไม่เหมือนกันข้ามระบบ ข้อนี้กัดคนเยอะ
Linux (iputils) 0 = ได้คำตอบอย่างน้อยหนึ่ง
1 = ไม่ได้คำตอบเลย
2 = ข้อผิดพลาดอื่น
macOS และ BSD 0 = ได้คำตอบอย่างน้อยหนึ่ง
2 = ส่งได้แต่ไม่ได้คำตอบเลย
อื่น ๆ = ข้อผิดพลาด
สคริปต์ที่เขียนว่า if [ $? -eq 1 ] เพื่อจับกรณีไม่ตอบ จะทำงานถูกบน Linux และ ไม่มีวันเข้าเงื่อนไขเลยบน macOS โดยไม่มี error ให้เห็น ถ้าต้องรองรับทั้งสอง ให้ตรวจว่าเท่ากับศูนย์หรือไม่เท่ากับศูนย์เท่านั้น
ปัญหาที่สาม สับสนระหว่าง -W กับ -w บน Linux ตัวพิมพ์ใหญ่คือเวลารอ คำตอบแต่ละครั้ง ตัวพิมพ์เล็กคือเวลารวมทั้งคำสั่ง สคริปต์เฝ้าระวังควรใส่ ตัวพิมพ์เล็กเสมอ ไม่งั้นวันที่ปลายทางเงียบสนิท คำสั่งจะค้างนานกว่าที่ตั้งใจ
$ ping -c 5 -i 0.2 -W 1 -w 3 10.0.0.8
ปัญหาที่สี่ ping ไม่ได้บอกว่าบริการยังทำงานอยู่ เครื่องตอบ ping ได้สบายมากในขณะที่ฐานข้อมูลบนเครื่องนั้นตายไปแล้ว ping ตรวจว่าเครื่องยังหายใจ ไม่ได้ตรวจว่ามันยังทำงานได้
เมื่อ ping ไม่พออีกต่อไป
ping ตอบได้แค่ว่าถึงหรือไม่ถึง และนานแค่ไหน เมื่อคำถามลึกกว่านั้น ใช้เครื่องมือที่ออกแบบมาเพื่อคำถามนั้น
- traceroute หรือ tracert — ไม่ถึงแล้วมันไปตายตรงไหน
- mtr — traceroute ที่ยิงต่อเนื่อง เห็นสถิติการสูญหายของทุกฮอป พร้อมกัน เป็นเครื่องมือที่คุ้มค่าเวลาเรียนที่สุดถ้าจะเรียนเพิ่มอีกตัวเดียว
- hping3 หรือ nping — ping ด้วย TCP หรือ UDP เมื่อ ICMP ถูกบล็อก
- iperf3 — วัดปริมาณงานที่ส่งได้จริง ซึ่ง
pingวัดไม่ได้เลย - tcpdump หรือ Wireshark — ดูของจริงบนสาย เมื่อเลิกเดาแล้ว
ping ยังอยู่มาสี่สิบปีไม่ใช่เพราะไม่มีใครคิดของที่ดีกว่า แต่เพราะมัน ตอบคำถามที่ถูกต้องที่สุดคำถามเดียว ด้วยวิธีที่ง่ายที่สุดที่เป็นไปได้ — ตะโกนออกไป แล้วฟังว่ามีเสียงสะท้อนกลับมาไหม
เหมือนที่โซนาร์ทำมาก่อนหน้านั้นหลายสิบปี และเหมือนที่ Mike Muuss ตั้งใจไว้ตั้งแต่คืนนั้นในเดือนธันวาคม 1983
อ้างอิง
เอกสารมาตรฐาน
- RFC 792 — Internet Control Message Protocol Jon Postel, กันยายน 1981 — นิยาม ICMP และ Echo Request/Reply
- RFC 1122 — Requirements for Internet Hosts ตุลาคม 1989 — หัวข้อ 3.2.2.6 ระบุว่าทุกโฮสต์ต้องตอบ Echo Request
- RFC 4443 — ICMPv6 มีนาคม 2006 — Echo Request/Reply สำหรับ IPv6 (type 128/129)
- RFC 1191 — Path MTU Discovery
- RFC 8201 — Path MTU Discovery สำหรับ IPv6
- RFC 8200 — IPv6 Specification กำหนด MTU ต่ำสุด 1280 ไบต์
- RFC 1812 — Requirements for IP Version 4 Routers
- RFC 2644 — Changing the Default for Directed Broadcasts in Routers BCP 34 — มาตรการที่ปิดฉาก Smurf
- RFC 4890 — การกรอง ICMPv6 ในไฟร์วอลล์
ประวัติ
- Mike Muuss, The Story of the PING Program — บันทึกจากปากผู้เขียนเอง เดิมเผยแพร่ที่
ftp.arl.army.mil/~mike/ping.htmlปัจจุบันหน้าดั้งเดิม ปิดไปแล้ว หาอ่านได้จากสำเนาที่มีผู้เก็บไว้ - Ping (networking utility) — Wikipedia
- Mike Muuss — Wikipedia
ซอร์สโค้ดและคู่มือ
- iputils — ping ที่ลินุกซ์ส่วนใหญ่ใช้
man pingบนเครื่องที่คุณกำลังนั่งอยู่ ซึ่งเป็นแหล่งที่ถูกต้องที่สุด เสมอสำหรับธงที่ระบบนั้นรองรับ