กำหนดค่า nft เพื่อทำให้เซิร์ฟเวอร์ NATed FTP ในเครื่องพร้อมใช้งานแบบสาธารณะ
ทุกอย่างจะอยู่ในเครือข่ายแยกส่วนความปลอดภัยไม่ใช่ปัญหา
eth0 เชื่อมต่อกับเครือข่าย "สาธารณะ" ที่อยู่ที่กำหนดโดย DHCP
eth1 เชื่อมต่อกับเซิร์ฟเวอร์ "เครือข่ายส่วนตัว" ที่ให้ ssh, telnet, "others" และ ftp
เซิร์ฟเวอร์นี้จะมี IP คงที่ (192.168.1.2) ในตัวอย่างนี้
เกตเวย์กำลังเรียกใช้เดเบียนบัสเตอร์และเคอร์เนลลินุกซ์ 4.19.94
nft ใช้กับ NAT
นี่คือการกำหนดค่า nft "เกตเวย์" ของฉันในตอนนี้:
table ip my_nat {
chain my_prerouting { type nat hook prerouting priority 0;
tcp dport { 2222 } dnat to :22 # 2222 backdoor for ssh to the gateway
tcp dport { 1-1023 } dnat to 192.168.1.2
}
chain my_postrouting {
type nat hook postrouting priority 100;
ip daddr 192.168.1.2 masquerade
}
}
ฉันต้องเพิ่มอะไรเพื่อให้ FTP ทำงานได้
คำตอบ
TL; ดร
# nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'
# nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
# nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming
# modprobe nf_nat_ftp
พร้อมรายละเอียดเพิ่มเติมด้านล่าง ...
โมดูลตัวช่วยโปรโตคอลสำหรับโปรโตคอลที่มีปัญหา
FTP เป็นโปรโตคอลแบบเก่าและไม่เป็นมิตรกับไฟร์วอลล์: คำสั่งบนช่องคำสั่ง FTP (21 / TCP) ต่อรองพอร์ตชั่วคราวเพื่อใช้สำหรับคำสั่งโอนต่อไป ด้วยเหตุนี้ไฟร์วอลล์ที่มีสถานะจึงต้องสอดแนมคำสั่งเหล่านั้นและตอบกลับเพื่ออนุญาตให้ใช้พอร์ตที่เพียงพอล่วงหน้าชั่วคราว
บน Linux สิ่งนี้จัดเตรียมโดยโมดูลตัวช่วยเฉพาะโปรโตคอลซึ่งเป็นปลั๊กอินสำหรับคอนแทร็กระบบย่อย Netfilter ติดตามการเชื่อมต่อสำหรับ NAT และไฟร์วอลล์แบบ stateful ด้วย FTP เมื่อมีการเจรจาพอร์ต (ส่วนใหญ่เป็น PORT, EPRT, PASV หรือ EPSV) สำหรับการถ่ายโอนครั้งต่อไปได้เห็นบนพอร์ตคำสั่ง FTP ผู้ช่วยจะเพิ่มรายการที่มีอายุสั้นในตารางคอนแทร็กพิเศษ( ตารางความคาดหวังคอนแทร็ก ) ซึ่งจะ รอการเชื่อมต่อข้อมูลที่เกี่ยวข้องและที่คาดไว้ถัดไป
คำตอบของฉันใช้ที่ทันสมัย "เชื่อถือได้" จัดการตามที่อธิบายไว้ในบล็อกนี้เกี่ยวกับiptablesสำหรับ generalities และในnftablesวิกิพีเดียและman nft
การจัดการในnftablesซึ่งแตกต่างจากiptables
การใช้กฎตัวช่วยและ nftables อย่างปลอดภัย
เคอร์เนลลินุกซ์ 4.7+ (ซึ่งรวมถึง 4.19) กำลังใช้วิธีการรักษาความปลอดภัยโดยค่าเริ่มต้น: การโหลดโมดูลตัวช่วย (ที่นี่ FTP) จะไม่ทำให้การสอดแนมแพ็กเก็ตทั้งหมดที่มีต้นทาง TCP หรือพอร์ตปลายทาง 21 อีกต่อไปจนกว่าจะระบุnftables (หรือiptables ) บอกว่ามันควรสอดแนมในกรณีใด (จำกัด ) วิธีนี้หลีกเลี่ยงการใช้งาน CPU ที่ไม่จำเป็นและอนุญาตให้เปลี่ยนได้ตลอดเวลาที่พอร์ต FTP เพื่อสอดแนมเพียงแค่เปลี่ยนกฎ (หรือชุด) เล็กน้อย
ส่วนแรกคือการประกาศกระแสที่สามารถกระตุ้นการสอดแนม มันแตกต่างกันในการจัดการnftablesกว่าในiptables ที่นี่มีการประกาศโดยใช้ct helper
วัตถุที่มีสถานะและตัวกรองเพื่อเปิดใช้งานจะต้องทำหลังจากconntrack (ในขณะที่iptablesต้องมีการดำเนินการก่อน) man nft
บอก:
ไม่เหมือนกับ iptables การกำหนดตัวช่วยจำเป็นต้องดำเนินการหลังจากการค้นหาคอนแทร็กเสร็จสิ้นแล้วตัวอย่างเช่นโดยมีลำดับความสำคัญของ hook 0 เริ่มต้น
nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'
nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming
ฉันเลือกตารางเดียวกัน แต่สามารถสร้างขึ้นในตารางอื่นได้ตราบใดที่การประกาศออบเจ็กต์ที่ระบุสถานะและกฎที่อ้างถึงอยู่ในตารางเดียวกัน
แน่นอนเราสามารถเลือกกฎที่เข้มงวดน้อยกว่าได้ การแทนที่กฎสุดท้ายด้วยกฎต่อไปนี้จะมีผลเช่นเดียวกับโหมดเดิม:
nft add rule ip my_nat my_helpers tcp dport 21 ct helper set ftp-incoming
สำหรับการอ้างอิงเท่านั้นโหมดดั้งเดิมที่ไม่ควรใช้อีกต่อไปไม่จำเป็นต้องใช้กฎข้างต้น แต่เป็นเพียงการสลับนี้ (และการโหลดโมดูลเคอร์เนลที่เกี่ยวข้องด้วยตนเอง):
sysctl -w net.netfilter.nf_conntrack_helper=1
nf_nat_ftp
โหลดความมั่นใจแล้ว
โมดูลเคอร์เนลจะโหลดโดยอัตโนมัติด้วยการพึ่งพาที่สร้างขึ้นโดยnf_conntrack_ftp
ct helper ... type "ftp"
นั่นไม่ใช่กรณีnf_nat_ftp
แต่จำเป็นต้องเปิดใช้งานการเชื่อมต่อแพ็คเก็ตในพอร์ตคำสั่งเมื่อเสร็จสิ้น NAT บนพอร์ตกระแสข้อมูล
ตัวอย่างเช่นหากต้องการnf_nat_ftp
ดึงโมดูลเมื่อใดก็ตามที่nf_conntrack_ftp
มีการโหลดไฟล์/etc/modprobe.d/local-nat-ftp.conf
สามารถเพิ่มด้วยเนื้อหานี้:
install nf_conntrack_ftp /sbin/modprobe --ignore-install nf_conntrack_ftp; /sbin/modprobe --ignore-install nf_nat_ftp
หรือเพียงแค่เพิ่มตัวอย่างเช่น/etc/modules-load.d/local-nat-ftp.conf
:
nf_nat_ftp
อย่างไรก็ตามตอนนี้ควรทำคำสั่งนี้เพื่อให้แน่ใจว่าโหลดแล้ว:
modprobe nf_nat_ftp
เกี่ยวกับไฟร์วอลล์
นี่คือหมายเหตุเพิ่มเติมสำหรับไฟร์วอลล์ นอกจากนี้ยังสามารถไฟร์วอลล์กฎระเบียบที่มีข้อ จำกัด บางอย่างแทนที่จะปล่อยให้ไหลใหม่ ๆ ติดแท็กเป็นที่เกี่ยวข้องโดยconntrack
ตัวอย่างเช่นแม้ว่าโมดูลตัวช่วย FTP จะจัดการทั้งโหมดพาสซีฟและโหมดแอคทีฟหากด้วยเหตุผลบางประการเราต้องการอนุญาตเฉพาะโหมดพาสซีฟ (ที่มีการเชื่อมต่อข้อมูลจากไคลเอนต์ไปยังเซิร์ฟเวอร์) และไม่ "ใช้งานอยู่" ftp (การเชื่อมต่อข้อมูลจากพอร์ตต้นทางของเซิร์ฟเวอร์ 20 ถึง ไคลเอนต์) สามารถใช้ตัวอย่างเช่นกฎเหล่านี้ในส่วนของไฟร์วอลล์ของชุดกฎแทนที่จะเป็นแบบปกติct state established,related accept
:
ct state established accept
ct state related ct helper "ftp" iif eth0 oif eth1 tcp sport 1024-65535 accept
ct state related ct helper "ftp" drop
ct state related accept
ยอมรับโฟลว์ที่เกี่ยวข้องประเภทอื่น ๆที่ไม่เกี่ยวข้องกับ FTP (หรืออาจแยกเพิ่มเติมอีกต่างหาก)
ตัวอย่างการจัดการโดยผู้ช่วยเหลือ
ที่นี่ (ในสภาพแวดล้อมจำลอง) สองเป็นconntrackรายการของเหตุการณ์ที่วัดบนความคาดหวังของตารางและconntrackตารางที่มีกฎของ OP + กฎข้างต้นเพิ่มเติมกับลูกค้าอินเทอร์เน็ต 203.0.113.101 ทำ FTP ในโหมดเรื่อย ๆ กับที่อยู่ IP ของเราเตอร์สาธารณะ 192.0 2.2 และใช้คำสั่ง LIST หลังจากเข้าสู่ระบบ:
# conntrack -E expect
[NEW] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp
[DESTROY] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp
พร้อมกัน:
# conntrack -E
[NEW] tcp 6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
[UPDATE] tcp 6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
[UPDATE] tcp 6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 [ASSURED] helper=ftp
[NEW] tcp 6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
[UPDATE] tcp 6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
[UPDATE] tcp 6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
[UPDATE] tcp 6 120 FIN_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
[UPDATE] tcp 6 30 LAST_ACK src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
[UPDATE] tcp 6 120 TIME_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
การเริ่มต้นของความคาดหวังproto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157
บอกว่าการเชื่อมต่อ TCP ถัดไปจาก 203.0.113.101:* ถึง 192.0.2.2:37157 จะเชื่อมโยง (สถานะที่เกี่ยวข้อง ) กับการเชื่อมต่อ FTP ไม่สามารถมองเห็นได้โดยตรง แต่เนื่องจากมีการโหลดโมดูลตัวช่วย NAT FTP ด้วยเช่นกันข้อมูลจริงที่ส่งโดยเซิร์ฟเวอร์เพื่อตอบสนองต่อคำสั่ง PASV / EPSV จึงถูกดักจับและแปลดังนั้นไคลเอนต์จึงเชื่อมต่อกับ 192.0.2.2 แทนที่จะเป็น 192.168.1.2 ซึ่งจะมี แน่นอนล้มเหลวในไคลเอนต์
แม้ว่าโฟลว์ที่สอง ( บรรทัดใหม่ที่สอง) จะไม่มีกฎที่ชัดเจนในmy_preroutingแต่ก็ประสบความสำเร็จ DNAT ไปยังเซิร์ฟเวอร์หลังเราเตอร์
หมายเหตุ
หากพอร์ตควบคุม FTP ถูกเข้ารหัส (
AUTH TLS
... ) โมดูลตัวช่วยจะไม่สามารถสอดแนมพอร์ตที่เจรจาได้อีกต่อไปและไม่สามารถใช้งานได้ เราต้องใช้การกำหนดค่าช่วงของพอร์ตที่สงวนไว้ทั้งในการกำหนดค่าเซิร์ฟเวอร์ FTP และเราเตอร์ไฟร์วอลล์ / NAT และกำหนดค่าเซิร์ฟเวอร์เพื่อให้ส่งที่อยู่ IP ที่ถูกต้อง (สาธารณะ) เมื่อทำการเจรจาแทนที่จะเป็นของตัวเอง และโหมด FTP ที่ใช้งานอยู่จะไม่สามารถใช้งานได้หากเซิร์ฟเวอร์ไม่มีเส้นทางไปยังอินเทอร์เน็ต (ตามที่ปรากฏที่นี่)nitpicking: ลำดับความสำคัญของการกำหนดเส้นทางล่วงหน้าที่ 10 ทำให้มั่นใจได้ว่าแม้กระทั่งสำหรับเคอร์เนล <4.18 แต่ NAT ก็เกิดขึ้นแล้วสำหรับโฟลว์ใหม่ (OP เลือก hook prerouting priority 0 แทนที่จะเป็น -100 ตามปกติเนื่องจากสิ่งนี้ไม่ค่อยมีความสำคัญใน nftables) ดังนั้นจึงสามารถใช้งาน
daddr 192.168.1.2
ได้ หากลำดับความสำคัญคือ 0 (หรือต่ำกว่า 0) อาจเป็นไปได้ (ไม่ได้รับการตรวจสอบ) กฎจะเห็นแพ็กเก็ตแรกที่ยังไม่ได้ระบุด้วยที่อยู่ปลายทาง IP สาธารณะ แต่จะจับแพ็กเก็ตต่อไปนี้ของโฟลว์เดียวกันเนื่องจากมีการจัดการ โดยตรงโดยconntrackที่ลำดับความสำคัญ -200 รักษาความปลอดภัยและใช้งานได้ดีขึ้น 10 อันที่จริงสิ่งนี้ไม่เกี่ยวข้องเนื่องจากเคอร์เนล 4.18 (ดูการอ้างอิงการกระทำในแพตช์ที่รอดำเนินการนี้ ) ซึ่งลำดับความสำคัญของ NAT จะเกี่ยวข้องเฉพาะสำหรับการเปรียบเทียบระหว่างกลุ่ม Nat หลายตัวเท่านั้น (และอนุญาตให้ผสม NAT ใน iptables ดั้งเดิมกับ nftables)
หลังจากการลองผิดลองถูกฉันได้พบกับ nftables.conf ต่อไปนี้ซึ่งทำงานได้ตามที่ตั้งใจไว้และรองรับ NAT ทั้งสองทิศทางรวมทั้งส่งออกพอร์ตทั้งหมดยกเว้นพอร์ตเดียวบนเซิร์ฟเวอร์ของฉันไปยังเครือข่าย พอร์ต 2222 ยังคงใช้เป็น "แบ็คดอร์" ไปยังเกตเวย์เพื่อใช้ถ้าฉันต้องการเข้าถึงอีกครั้ง :-)
table ip my_nat {
ct helper ftp-incoming {
type "ftp" protocol tcp
l3proto ip
}
chain my_prerouting {
type nat hook prerouting priority 0; policy accept;
iifname "eth0" tcp dport { 2222 } dnat to :ssh
iifname "eth0" tcp dport { 1-2221, 2223-65535 } dnat to 192.168.0.2
}
chain my_postrouting {
type nat hook postrouting priority 100; policy accept;
ip daddr 192.168.0.2 masquerade
oifname "eth0" masquerade
}
chain my_helpers {
type filter hook prerouting priority 10; policy accept;
iif "eth0" ip daddr 192.168.0.2 tcp dport ftp ct helper set "ftp-incoming"
}
}