เบราว์เซอร์ขอ https://203.0.113.10:8443 พร็อกซียอมรับการเชื่อมต่อ แต่บริการบน WireGuard peer ไม่ตอบกลับเลย กฎ DNAT ทำงานของมันอยู่ ส่วนที่ล้มเหลวคือคำตอบ ตามแพ็กเก็ตผ่านการแปลงทั้งสองครั้งแล้วกฎที่ขาดหายจะชัดเจนขึ้น การแก้ไขคือคำสั่ง NAT เพิ่มอีกหนึ่งบรรทัดใน hook ที่ถูกต้อง ไม่ใช่อุโมงค์ใหม่

ตามคำขอหนึ่งรายการตั้งแต่ต้นจนจบ

คำขอมาถึงอินเทอร์เฟซสาธารณะของพร็อกซี โดยมีแอดเดรสสาธารณะของไคลเอนต์เป็นต้นทางและแอดเดรสของพร็อกซีเป็นปลายทาง ใน nat PREROUTING กฎ DNAT เขียนปลายทางใหม่เป็นแอดเดรสอุโมงค์ของ peer คือ 10.90.0.2 จากนั้นการตัดสินใจเส้นทางส่งแพ็กเก็ตออกผ่าน wg0 และเส้นทางการส่งต่อก็สมบูรณ์

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

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

เพิ่มการแปลงขากลับ

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

iptables -t nat -A PREROUTING -p tcp -m multiport --dports 8080,8443 -j DNAT --to-destination 10.90.0.2
iptables -t nat -A POSTROUTING -d 10.90.0.2 -o wg0 -p tcp -m multiport --dports 8080,8443 -j SNAT --to-source 10.90.0.1

กฎ POSTROUTING ถูกจำกัดอย่างตั้งใจ ให้ตรงกับปลายทางที่แปลงแล้วและอินเทอร์เฟซอุโมงค์ จึงไม่เขียนทับทราฟฟิกที่ไม่เกี่ยวข้องซึ่งบังเอิญออกผ่าน wg0 กฎ masquerade แบบกว้าง ก็จะซ่อนแอดเดรสของไคลเอนต์ด้วย แต่จะทำกับทุกโฟลว์และทำให้ตรวจสอบตาราง NAT ได้ยากขึ้น

วางกฎในจุดที่มีอุโมงค์อยู่

กฎที่อ้างถึงแอดเดรสหรืออินเทอร์เฟซของอุโมงค์ต้องทำงานหลังจาก wg-quick ตั้งค่าแล้ว อินเทอร์เฟซถูกสร้างก่อน PreUp แต่แอดเดรส MTU DNS และเส้นทางถูกนำไปใช้หลังจากนั้น และ PostUp ทำงานเมื่อทุกอย่างพร้อม ใส่ส่วนเพิ่มใน PostUp และส่วนลบใน PreDown

PostUp = iptables -t nat -A PREROUTING -p tcp -m multiport --dports 8080,8443 -j DNAT --to-destination 10.90.0.2
PostUp = iptables -t nat -A POSTROUTING -d 10.90.0.2 -o wg0 -p tcp -m multiport --dports 8080,8443 -j SNAT --to-source 10.90.0.1
PreDown = iptables -t nat -D PREROUTING -p tcp -m multiport --dports 8080,8443 -j DNAT --to-destination 10.90.0.2
PreDown = iptables -t nat -D POSTROUTING -d 10.90.0.2 -o wg0 -p tcp -m multiport --dports 8080,8443 -j SNAT --to-source 10.90.0.1

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

ตรวจสอบผลลัพธ์ด้วย iptables -t nat -S หลังการเชื่อมต่อใหม่ หากกฎเดียวกันปรากฏสองครั้ง แสดงว่าบรรทัด PreDown ไม่ตรงและการล้างข้อมูลล้มเหลวอย่างเงียบ ๆ

การส่งต่อ การกรอง และ NAT อีกตัว

เปิดใช้การส่งต่อ IPv4 อย่างถาวร แล้วอนุญาตโฟลว์ที่ถูกส่งต่อในตารางฟิลเตอร์ DNAT เกิดขึ้นก่อนเชน FORWARD ดังนั้นกฎฟิลเตอร์จึงตรงกับปลายทางที่แปลงแล้ว ไม่ใช่แอดเดรสสาธารณะ หาก UFW จัดการไฟร์วอลล์ ให้แสดงการอนุญาตเป็นกฎเส้นทาง กฎโฮสต์ธรรมดาไม่ครอบคลุมทราฟฟิกที่ถูกส่งต่อ

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

บน NAT VPS ผู้ให้บริการแมปพอร์ตสาธารณะไปยังแอดเดรสส่วนตัว การแมปต้องตรงกับพอร์ตที่คุณประกาศ และความไม่ตรงกันดูเหมือนอุโมงค์ที่เสียหาย ยืนยันการแมปของผู้ให้บริการก่อนเปลี่ยนการตั้งค่า WireGuard

ตรวจสอบเส้นทางขากลับและยอมรับค่าใช้จ่าย

เชื่อมต่อจากเครือข่ายที่ไม่ใช่ LAN ของพร็อกซี แล้วตรวจสอบคู่การแปลงขณะเชื่อมต่ออยู่:

conntrack -L -p tcp --dport 8080
tcpdump -ni any tcp port 8080

รายการ conntrack ควรแสดงทูเพิลต้นฉบับ ทูเพิลที่แปลงแล้ว และทิศทางของคำตอบ หากคำตอบหายไป peer ไม่ได้ส่งผ่านอุโมงค์ ซึ่งมักหมายความว่ากฎ SNAT ไม่ถูกนำไปใช้หรือไฟร์วอลล์ของ peer เองทิ้งโฟลว์นั้น

รีบูตหนึ่งครั้งเพื่อพิสูจน์ว่า PostUp นำกฎไปใช้ใหม่ จากนั้นหยุดอุโมงค์และยืนยันว่า PreDown ลบกฎเหล่านั้น กฎที่ตายแล้วแต่ยังอยู่หลังการตัดการเชื่อมต่อคือสาเหตุที่การเปลี่ยนแปลงภายหลังทำงานไม่แน่นอน

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

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