ไคลเอนต์เชื่อมต่อไปยังเซิร์ฟเวอร์ OpenVPN บน VM ของ Compute Engine หน้าสถานะบอกว่าเชื่อมต่อแล้ว แต่ ping ไปยังโฮสต์ภายใน VPC ก็ยังไม่ไปถึงไหน สัญชาตญาณคือการเพิ่มบรรทัด push อีกบรรทัด ซึ่งไม่เคยแก้ปัญหาได้จริง Compute Engine ตัดสินใจว่าแพ็กเก็ตจะไปที่ไหนจากตารางเส้นทางของตัวเองและจากแอดเดรสที่อินเทอร์เฟซของ VM ถืออยู่จริง ดังนั้นพูลอุโมงค์ที่ VM ไม่ได้เป็นเจ้าของก็คือพูลที่ไม่มีใครส่งถึง

ตามแพ็กเก็ตที่ล้มเหลวไปแทนที่จะตามไฟล์คอนฟิก แล้วชิ้นส่วนที่ขาดหายจะปรากฏขึ้นตามลำดับ

เริ่มที่แพ็กเก็ตที่ตาย

SYN ออกจากไคลเอนต์ เข้าสู่อุโมงค์ และไปถึง VM ในรูปแพ็กเก็ตที่ถูกห่อหุ้มสำหรับปลายทางภายใน VPC OpenVPN ถอดการห่อหุ้มแล้วพยายามส่งต่อออกทาง eth0 ซึ่งเฟบริกจะถามคำถามหนึ่งข้อก่อนสิ่งอื่นใด: อินสแตนซ์นี้เป็นเจ้าของแอดเดรสปลายทางหรือไม่ พูลอุโมงค์ที่ตัดมาจากซับเน็ตของคนอื่นจะตกคำถามนี้ และแพ็กเก็ตจะถูกทิ้งก่อนที่จะมีการตรวจเส้นทางหรือกฎไฟร์วอลล์ใด ๆ

ดังนั้นทิศทางจากไคลเอนต์ไปยัง VPC จึงมีข้อกำหนดแยกกันสองข้อ และไม่มีข้อใดเป็นคำสั่ง push เลย VM ต้องมีช่วง alias ที่ครอบคลุมพูลอุโมงค์ ซึ่งเป็นสิ่งที่ทำให้มันเป็นเจ้าของแอดเดรสเหล่านั้นอย่างชอบธรรม VPC ต้องมีเส้นทางที่ระบุ VM เป็น next hop สำหรับแต่ละคำนำหน้าที่ได้รับการป้องกัน พลาดข้อใดข้อหนึ่งแล้วแพ็กเก็ตจะตายคนละที่ แต่ไคลเอนต์เห็นความเงียบแบบเดียวกัน

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

อินสแตนซ์เป็นเจ้าของพูลอุโมงค์หรือไม่

ให้ช่วงทุติยภูมิแก่ VM ภายในซับเน็ตของตัวเอง แล้วทำให้ OpenVPN แจกแอดเดรสจากช่วงนั้นพอดี บนอินสแตนซ์ที่มีแอดเดรสหลักเป็น 10.156.0.10/20 alias ขนาด /28 จะแยกพูลออกจากแอดเดรสที่อินสแตนซ์อื่นถืออยู่แล้ว:

gcloud compute instances network-interfaces update openvpn-vm \
  --zone=europe-west1-b \
  --aliases=eth0:10.156.1.0/28

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

server 10.156.1.0 255.255.255.240

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

ip -4 addr show dev eth0

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

ให้ next hop แก่ทราฟฟิกขากลับ

การตอบกลับจากโฮสต์ใน VPC ส่งไปยังแอดเดรสไคลเอนต์ในพูลอุโมงค์ ซึ่งไม่เป็นของซับเน็ตใดที่ VPC รู้จัก หากไม่มีเส้นทางสำหรับพูลนั้น การตอบกลับจะหยุดที่ฮอปแรกที่ไม่มีการจับคู่ และคำขออาจสำเร็จที่ปลายทางไกลแล้วก็ได้

gcloud compute routes create openvpn-return \
  --network=prod-vpc \
  --destination-range=192.168.127.0/24 \
  --next-hop-instance=openvpn-vm \
  --next-hop-instance-zone=europe-west1-b \
  --priority=800

เส้นทางเดียวกันนี้จำเป็นสำหรับคำนำหน้าใด ๆ ที่อยู่หลังไคลเอนต์แทนที่จะอยู่ใน VPC คำนำหน้าเหล่านั้นยังต้องมีรายการ iroute ในไฟล์ ccd ของไคลเอนต์นั้น รายการนั้นคือการลงบัญชีฝั่งเซิร์ฟเวอร์: มันบอกเซิร์ฟเวอร์ว่าไคลเอนต์ใดเป็นเจ้าของคำนำหน้า และไม่ได้ติดตั้งสิ่งใดบนไคลเอนต์เอง

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

ไฟร์วอลล์ การส่งต่อ และฮอปที่อยู่ระหว่างนั้น

ไฟร์วอลล์ของ VPC ตรวจแพ็กเก็ตที่ถอดการห่อหุ้มแล้ว ดังนั้นกฎขาเข้าต้องอนุญาตพูลอุโมงค์และคำนำหน้าของไซต์ใด ๆ ที่มาถึง VM ทางนั้น ท่าทีปฏิเสธโดยค่าเริ่มต้นจะล้มเหลวอย่างเงียบ ๆ ที่นี่: แพ็กเก็ตถูกทิ้งหลังถอดการห่อหุ้ม และล็อกของ OpenVPN แสดงเซสชันที่แข็งแรง

บนโฮสต์ Linux ใด ๆ ที่ส่งต่อแทนที่จะเป็นปลายทาง ให้ตรวจว่า net.ipv4.ip_forward เปิดอยู่ กฎความเป็นเจ้าของใช้ที่นั่นเช่นกัน: เครื่องที่ส่งต่อให้ซับเน็ตที่ตัวเองไม่ได้ถือจะทิ้งแพ็กเก็ตเหมือนที่ VM ทำ อ่านค่าก่อนจะโทษอุโมงค์

เมื่อคำนำหน้าล้มเหลวเพียงหนึ่งเดียว

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

gcloud compute routes list --filter=destination-range~10.164.0.0
 gcloud compute instances describe openvpn-vm --format=get(networkInterfaces[0].aliasIpRanges)

เส้นทางที่ขาดหายแสดงตัวว่าไม่มี next hop สำหรับคำนำหน้า ขณะที่ alias ที่ขาดหายแสดงตัวว่าแพ็กเก็ตถูกทิ้งที่อินเทอร์เฟซ; สองอย่างนี้ดูคล้ายกันจากฝั่งไคลเอนต์และต่างกันโดยสิ้นเชิงในผลลัพธ์สองรายการนั้น หากมีทั้งสองอย่าง ผู้ต้องสงสัยที่เหลือคือ iroute ใน ccd ของไคลเอนต์ที่อ้างคำนำหน้านั้น

จดค่าทั้งสี่ไว้ข้างอุโมงค์: ช่วง alias, พูลของเซิร์ฟเวอร์, คำนำหน้าที่ push, เส้นทางใน VPC alias ที่เก่าทำให้ทุกแอดเดรสในพูลพัง เส้นทางที่เก่าทำให้ทิศทางหนึ่งพัง push ที่ขาดทำให้ไคลเอนต์มองไม่เห็นคำนำหน้า และ iroute ที่ผิดส่งคำนำหน้าไปยังพีร์ที่ผิด คนถัดไปที่เพิ่มซับเน็ตต้องมีทั้งสี่อย่างในที่เดียว และบันทึกนั้นถูกกว่าหนึ่งคืน

บทความที่เกี่ยวข้อง