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

กฎนี้อธิบายชั้นการขนส่ง ไม่ใช่แอปพลิเคชัน

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

nft add rule inet mangle output tcp dport { 80, 443 } meta mark set 0x1
ip rule add fwmark 0x1 table 100
ip route add default dev wg0 table 100

ผลลัพธ์สองอย่างตามมาทันที ตัวอัปเดตซอฟต์แวร์ที่ติดต่อ TCP 443 ได้รับการปฏิบัติเช่นเดียวกับเบราว์เซอร์ ซึ่งอาจจะโอเคหรืออาจเป็นการหยุดชะงักที่รอรอบอัปเดตถัดไป และบริการเว็บที่เผยแพร่บนพอร์ตอื่นโดยเจตนา เช่น 8443 จะหลุดออกจากกฎทั้งหมด ทั้งที่ยังเป็นทราฟฟิกเว็บที่ผู้ใช้สนใจ

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

HTTP/3 แอบออกจากกฎ TCP ของคุณ

HTTP/3 ทำงานบน QUIC และ QUIC ถูกบรรทุกใน UDP กฎที่ตรงกับ TCP เท่านั้นมองไม่เห็น ดังนั้นเบราว์เซอร์เดียวกันที่ผ่านหน้าทดสอบของคุณสามารถส่งคำขอในภายหลังผ่าน UDP และข้ามทันเนลได้โดยไม่มีใครเปลี่ยนการตั้งค่า RFC 9114 อธิบาย HTTP/3 ว่าเป็นโปรโตคอลที่อิง QUIC และ QUIC ใช้ UDP ที่มีพอร์ตเริ่มต้น 443 ในการติดตั้งทั่วไป

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

curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'

บรรทัด curl พิมพ์เวอร์ชันที่เจรจาได้ ดังนั้น 3 ยืนยันว่าใช้เส้นทาง UDP แล้ว รายการซ็อกเก็ตแสดงว่าการเชื่อมต่อนั้นผูกกับอินเทอร์เฟซของทันเนลหรือของจริง หาก curl ที่คุณสร้างไม่มี HTTP/3 แฟล็กจะล้มเหลวอย่างดังแทนที่จะถอยกลับอย่างเงียบ ๆ ซึ่งเป็นความเมตตาเล็ก ๆ ของมันเอง

DNS คือการตัดสินใจแยกต่างหากที่คุณต้องทำ

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

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

จากนั้นตรวจสอบด้วยตัวแปลงไม่ใช่ด้วยหน้าเว็บ:

resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'

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

สามขอบเขต สามกลไกที่ต่างกัน

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

What you actually wantMechanism that fitsWhat it does not cover
These transport ports use this exitFirewall mark plus policy routeApplications, HTTP/3 over UDP, DNS
This browsing session stays separateApplication-aware VPN, or a separate network namespace plus a proxyOther applications in the same session
Only these private sites are reachableDestination-based routes with private DNSPublic sites on the same address family

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

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

ทดสอบโฟลว์ที่คุณอ้างว่าครอบคลุม

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

ip route get 203.0.113.40
curl -sS -o /dev/null -w 'v4 %{http_version} %{remote_ip}\n' https://example.com
nft list ruleset | grep -A2 'dport'

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

บันทึกผลลัพธ์ทั้งสามพร้อมตราเวลาและเก็บไว้กับการเปลี่ยนแปลง เมื่อมีคนรายงานในภายหลังว่า «VPN ทำให้อินทราเน็ตพัง» ความแตกต่างระหว่างขอบเขตที่ตั้งใจและที่ใช้งานจริงจะปรากฏในบันทึกนั้น และการแก้ไขจะเป็นการเปลี่ยนกฎไม่ใช่การโต้เถียง

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