nftables cgroup bypass ต้องแก้ที่อยู่ต้นทางด้วย
การทำเครื่องหมายให้ cgroup หนึ่งส่งมันไปยังอีกตารางหนึ่ง และซ็อกเก็ตยังคงใช้ที่อยู่เดิมที่มันมีอยู่แล้ว จัดประเภท กำหนดเส้นทาง และแปลเป็นสามขั้นตอนแยกกัน
การทำเครื่องหมายทราฟฟิกจาก cgroup หนึ่งเป็นส่วนที่ง่าย การตัดสินใจสามอย่างแยกกันต้องสอดคล้องกันก่อนที่แอปพลิเคชันหนึ่งจะออกผ่านอินเทอร์เฟซกายภาพในขณะที่ทุกอย่างยังอยู่ในอุโมงค์: ซ็อกเก็ตใดอยู่ในข้อยกเว้น การค้นหาเส้นทางใดที่เครื่องหมายกระตุ้น และที่อยู่ต้นทางใดที่แพ็กเก็ตบรรทุกเมื่อออกไป ความพยายามที่ล้มเหลวส่วนใหญ่ทำข้อแรกถูก ทำข้อที่สองครึ่งเดียว และไม่เคยดูข้อที่สาม
สามการตัดสินใจ ไม่ใช่หนึ่ง
การจัดประเภทตอบว่าใครได้รับการยกเว้น การกำหนดเส้นทางตอบว่าแพ็กเก็ตที่ทำเครื่องหมายไปที่ใดแทน การเลือกต้นทางตอบว่าปลายทางไกลจะเห็นอะไรและคำตอบควรกลับไปที่ใด
สิ่งเหล่านี้ล้มเหลวอย่างเป็นอิสระ แพ็กเก็ตอาจถูกจัดประเภท ถูกกำหนดเส้นทางใหม่ไปยังอินเทอร์เฟซกายภาพ และยังคงบรรทุกที่อยู่ส่วนตัวที่เราเตอร์ต้นน้ำใดก็ตามไม่สามารถส่งกลับได้ ซึ่งทำให้เกิดการหมดเวลาที่ดูเหมือนการบล็อกของไฟร์วอลล์ทุกประการ ไม่มีอะไรในขั้นตอนการจัดประเภทเตือนคุณเรื่องนี้ ไม่มีอะไรในขั้นตอนการกำหนดเส้นทางเช่นกัน
ลำดับก็สำคัญ การจัดประเภทเกิดขึ้นเมื่อแพ็กเก็ตถูกสร้าง การกำหนดเส้นทางเกิดหลังจากนั้น และการแปลเกิดที่จุดออก
ถ้าคุณระบุไม่ได้ว่าขั้นตอนใดในสามขั้นตอนเสีย คุณไม่ได้ดีบัก คุณกำลังจัดเรียงกฎใหม่และหวัง
จับคู่ cgroup ที่จะยังมีอยู่พรุ่งนี้
nftables สามารถทดสอบการเป็นสมาชิก cgroup v2 ของซ็อกเก็ตได้ ซึ่งมีประโยชน์จริงเพราะมันติดตามโพรเซสไม่ใช่ปลายทาง กับดักคือตัวระบุ แอปพลิเคชันเดสก์ท็อปที่เปิดจากเมนูมักอาศัยอยู่ใน scope ชั่วคราวที่ชื่อเปลี่ยนเมื่อเปิดครั้งถัดไป
nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroupการคัดลอกชื่อ scope จากเซสชันหนึ่งแล้วเขียนตายตัวจะสร้างกฎที่ใช้ได้วันนี้และหยุดจับคู่อย่างเงียบในวันพรุ่งนี้ ให้วางแอปพลิเคชันในบริบทการทำงานที่ตั้งใจและมั่นคงแทน เช่น scope หรือ unit เฉพาะที่คุณควบคุม และจับคู่กับสิ่งนั้น กฎก็จะอยู่รอดผ่านการรีบูตและการอัปเดตแพ็กเกจ มันยังกลายเป็นสิ่งที่เพื่อนร่วมงานคิดตามได้โดยไม่ต้องมีประวัติเซสชันของคุณ
จงแม่นยำด้วยว่าคุณใช้กลไกใด การจัดประเภท net_cls ของ cgroup v1 และการจับคู่ซ็อกเก็ตของ cgroup v2 เป็นคนละสิ่ง และฟิลด์ชื่อคล้ายกันในเอกสารไม่ได้ทำให้มันใช้แทนกันได้
เชน route คือสิ่งที่กระตุ้นการค้นหาครั้งที่สอง
สำหรับทราฟฟิกที่สร้างขึ้นในเครื่อง ชนิดของเชนตัดสินว่ามีอะไรเกิดขึ้นหลังจากตั้งเครื่องหมายแล้ว เชน output ชนิด filter สามารถทำเครื่องหมายแพ็กเก็ตได้และเคอร์เนลจะใช้เส้นทางที่มันเลือกไว้แล้วต่อไป เชนชนิด route คือกลไกที่ขอการค้นหาใหม่
table inet bypass {
chain mark {
type route hook output priority mangle; policy accept;
socket cgroupv2 level 2 "app.slice" meta mark set 0x1 comment "app bypass"
}
}
ip rule add fwmark 0x1 lookup 200
ip route add default via 203.0.113.1 dev wlan0 table 200จากนั้นเครื่องหมายต้องมีกฎนโยบายที่ส่งมันไปยังตาราง และตารางนั้นต้องสมบูรณ์: เส้นทางเริ่มต้น จุดหมายภายในที่แอปพลิเคชันยังต้องการ และเกตเวย์ต้นน้ำที่ตอบสนองจริง
เลือกค่าเครื่องหมายอย่างตั้งใจ WireGuard ใช้ fwmark ของตัวเองสำหรับทราฟฟิกการขนส่งภายนอก และการลงเอยที่หมายเลขเดียวกันโดยบังเอิญอาจรบกวนข้อยกเว้นเส้นทางของอุโมงค์เองในแบบที่วินิจฉัยได้ยาก
ที่อยู่ต้นทางไม่ตามเส้นทาง
ซ็อกเก็ตที่เลือกที่อยู่ต้นทางสำหรับเส้นทางอุโมงค์ไว้แล้วจะยังคงที่อยู่นั้นหลังจากกำหนดเส้นทางใหม่ ไม่มีอะไรในการเปลี่ยนเส้นทางเขียนทับมัน นั่นคือเหตุผลที่แพ็กเก็ตออกจากอินเทอร์เฟซกายภาพพร้อมต้นทางส่วนตัวที่เครือข่ายต้นน้ำไม่สามารถส่งกลับได้
อาการที่มองเห็นได้คือแอปพลิเคชันที่ดูเหมือนส่งข้อมูลและไม่เคยได้รับคำตอบ และบันทึกไฟร์วอลล์ที่ไม่แสดงอะไรเพราะแพ็กเก็ตไม่เคยกลับมา
การแก้ไขที่แคบคือกฎการแปลต้นทางที่จำกัดเฉพาะเครื่องหมายของแอปพลิเคชันนั้นและอินเทอร์เฟซขาออกจริงของมัน ผสานกับ NAT ที่มีอยู่แล้วแทนการแทนที่:
table inet bypass {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
meta mark 0x1 oifname "wlan0" masquerade
}
}แปลเฉพาะข้อยกเว้นและไม่มีอย่างอื่น กฎ masquerade แบบเหมารวมแก้ไขอาการและทำลายความสามารถในการบอกว่าทราฟฟิกใดใช้เส้นทางใด จับคู่ที่เครื่องหมาย อินเทอร์เฟซขาออกจริง และถ้าทำได้ ที่อยู่ของแอปพลิเคชันเอง กฎกว้างเขียนง่ายและแทบเป็นไปไม่ได้ที่จะตรวจสอบภายหลัง
อะไรยังหลุดจากข้อยกเว้น
การแปลงชื่ออาจมาจากโพรเซส resolver แยกใน cgroup อื่น ดังนั้นการจัดประเภทซ็อกเก็ตของเบราว์เซอร์ไม่ได้จัดประเภทการค้นหาของมัน ถ้าคำถามของ resolver อยู่ในอุโมงค์ในขณะที่การเชื่อมต่อออกไปข้างนอก คำตอบ split-horizon อาจไม่ตรงกับเส้นทาง ความไม่ตรงกันนั้นทำให้เกิดความล้มเหลวที่ดูเหมือนบั๊ก DNS และไม่ใช่
โพรเซสลูกสืบทอด cgroup ในการตั้งค่าส่วนใหญ่ แต่ตัวช่วยที่ย้ายตัวเองไปยัง scope ของตัวเองไม่สืบทอด ตรวจสอบแทนการสันนิษฐาน โดยเฉพาะกับทุกสิ่งที่รันตัวเองใหม่
สุดท้าย ตัดสินใจว่าควรเกิดอะไรขึ้นเมื่ออุโมงค์ล่ม ข้อยกเว้นที่กลายเป็น bypass เต็มรูปแบบอย่างเงียบ ๆ เป็นท่าทีความปลอดภัยที่ต่างจากข้อยกเว้นที่ปิดเมื่อล้มเหลว และมีเพียงอย่างเดียวเท่านั้นที่คุณตั้งใจ