iptables - กำหนดเป้าหมายไปยังแพ็กเก็ตเส้นทางไปยังส่วนต่อประสานเฉพาะ


25

เซิร์ฟเวอร์ภายในบ้านของฉันมีสองอินเตอร์เฟสหลักeth1(การเชื่อมต่ออินเทอร์เน็ตมาตรฐาน) และtun0(อุโมงค์ OpenVPN) ฉันต้องการที่จะใช้iptablesเพื่อบังคับให้แพ็คเก็ตทั้งหมดที่สร้างโดยกระบวนการในท้องถิ่นเป็นเจ้าของโดย UID 1002 เพื่อออกผ่านtun0และแพ็คเก็ตอื่น ๆ eth1ทั้งหมดเพื่อออกผ่าน

ฉันสามารถทำเครื่องหมายแพ็คเก็ตที่ตรงกันได้อย่างง่ายดาย:

iptables -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11

ตอนนี้ผมต้องการที่จะนำกฎบางอย่างในห่วงโซ่ POSTROUTING (ที่อาจจะฉีกของตาราง) เพื่อให้ตรงกับแพ็คเก็ตที่มีเครื่องหมายที่ 11 และส่งพวกเขาไปตามกฎที่ตรงกับแพ็กเก็ตทั้งหมดและส่งพวกเขาไปtun0eth1

ฉันพบเป้าหมายของ ROUTE แต่ดูเหมือนว่าจะเขียนอินเทอร์เฟซต้นฉบับใหม่เท่านั้น (เว้นแต่ฉันจะอ่านผิด)

iptables สามารถทำสิ่งนี้ได้หรือไม่? ฉันต้องยุ่งกับตารางเส้นทาง (ผ่านip routeหรือเพียงแค่routeคำสั่งดั้งเดิม) แทน?

แก้ไข: ฉันคิดว่าบางทีฉันควรให้ข้อมูลเพิ่มเติม ฉันไม่มีกฎ iptables อื่น ๆ ในปัจจุบัน (แม้ว่าฉันอาจสร้างกฎบางอย่างเพื่อทำงานที่ไม่เกี่ยวข้องในอนาคต) นอกจากนี้ผลลัพธ์ของip routeคือ:

default via 192.168.1.254 dev eth1  metric 203
10.32.0.49 dev tun0  proto kernel  scope link  src 10.32.0.50
85.17.27.71 via 192.168.1.254 dev eth1
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.73  metric 203

ฉันไม่ได้แตะตารางเส้นทาง - นี่เป็นเพียงวิธีปัจจุบัน (แม้ว่ามันจะดูค่อนข้างสกปรก) ฉันขอโทษ แต่ฉันไม่ได้routeติดตั้งคำสั่งดั้งเดิมบนเครื่องนี้

และผลลัพธ์ของip addr(แน่นอน, eth0 และ eth2 สามารถถูกเพิกเฉยได้ - มันเป็นนิคส์ที่ไม่ได้ใช้ในปัจจุบัน):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1c:6f:65:2a:73:3f brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast     state UP qlen 1000
    link/ether 00:1b:21:9d:4e:bb brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.73/24 brd 192.168.1.255 scope global eth1
    inet6 fe80::21b:21ff:fe9d:4ebb/64 scope link
       valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:6a:c0:4b brd ff:ff:ff:ff:ff:ff
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc     pfifo_fast state UNKNOWN qlen 100
    link/none
    inet 10.32.0.50 peer 10.32.0.49/32 scope global tun0

แก้ไข: ฉันได้รับบางสิ่งบางอย่างที่ทำงานเรียงกัน แต่มันไม่ได้ส่งต่อแพ็คเก็ตที่ทำเครื่องหมายเพื่อ tun0 โดยทั่วไปฉันเพิ่มตาราง (11) และใช้:

ip route add table 11 via 10.32.0.49 dev tun0
ip rule add priority 10000 fwmark 11 table 11

เมื่อฉันเพิ่งsudo -u user1000 wget -qO- whatismyip.orgฉันจะได้รับที่อยู่ IP ภายนอกของบ้านของฉัน แต่ถ้าฉันทำsudo -u user1002 wget -qO- whatismyip.orgฉันก็จะได้รับที่อยู่ IP ของบ้านของฉันด้วย (แต่ฉันควรจะได้รับ IP ที่ปลายอีกด้านหนึ่งของอุโมงค์ OpenVPN)

การรันiptables -vLยืนยันว่าแพ็กเก็ตได้รับการจับคู่โดยกฎการทำเครื่องหมาย แต่ดูเหมือนว่าจะไม่เป็นไปตามกฎการกำหนดเส้นทาง

แก้ไข: ฉันใช้เวลานานในการนี้และแม้ว่ามันยังไม่ทำงานฉันคิดว่าฉันใกล้

กฎ iptables จะต้องอยู่ในmangleห่วงโซ่เอาท์พุทของตาราง ฉันคิดว่าฉันยังต้องการกฎ MASQUERADE ในnatโซ่ POSTROUTING ของตารางเพื่อตั้งค่าที่อยู่ต้นทาง อย่างไรก็ตามการกำหนดเส้นทางใหม่ที่เกิดขึ้นหลังจาก mangle ของ OUTPUT ไม่ทำงานอย่างถูกต้อง

ฉันใช้เวลา 5 ชั่วโมงในตอนนี้ดังนั้นฉันจึงหยุดพักและอาจจะกลับมาอีกในคืนนี้หรือพรุ่งนี้

คำตอบ:


26

ฉันเพิ่งพบปัญหาที่คล้ายกันแม้ว่าจะแตกต่างกันเล็กน้อย ฉันต้องการกำหนดเส้นทางเฉพาะพอร์ต TCP 25 (SMTP) ผ่านอินเตอร์เฟส tap0 ของ OpenVPN ในขณะที่กำหนดเส้นทางการรับส่งข้อมูลอื่น ๆ ทั้งหมด (แม้แต่สำหรับโฮสต์เดียวกัน) ผ่านอินเตอร์เฟสเริ่มต้น

ในการทำเช่นนั้นฉันต้องทำเครื่องหมายแพ็คเก็ตและตั้งกฎสำหรับจัดการมัน ขั้นแรกให้เพิ่มกฎที่ทำแพ็กเก็ตเส้นทางเคอร์เนลที่ทำเครื่องหมายด้วย2ถึงตาราง3(อธิบายภายหลัง):

ip rule add fwmark 2 table 3

คุณอาจเพิ่มชื่อสัญลักษณ์ลงไป/etc/iproute2/rt_tablesแต่ฉันก็ไม่อยากทำเช่นนั้น จำนวน2และ3เลือกแบบสุ่ม ที่จริงแล้วสิ่งเหล่านี้อาจเหมือนกัน แต่เพื่อความชัดเจนฉันไม่ได้ทำในตัวอย่างนี้ (แม้ว่าฉันจะตั้งค่าเอง)

เพิ่มเส้นทางสำหรับการเปลี่ยนเส้นทางการรับส่งข้อมูลบนอินเทอร์เฟซอื่นโดยสมมติว่าเกตเวย์เป็น10.0.0.1ดังนี้:

ip route add default via 10.0.0.1 table 3

สำคัญมาก! ล้างแคชเส้นทางของคุณมิฉะนั้นคุณจะไม่ได้รับการตอบกลับและนั่งด้วยมือของคุณในเส้นผมของคุณเป็นเวลาหลายชั่วโมง:

ip route flush cache

ตอนนี้ตั้งค่ากฎไฟร์วอลล์สำหรับการทำเครื่องหมายแพ็คเก็ตที่กำหนด:

iptables -t mangle -A OUTPUT -p tcp --dport 465 -j MARK --set-mark 2

กฎข้างต้นใช้เฉพาะในกรณีที่แพ็คเก็ตมาจากเครื่องท้องถิ่น ดูhttp://inai.de/images/nf-packet-flow.png ปรับให้เข้ากับความต้องการของคุณ ตัวอย่างเช่นหากคุณต้องการกำหนดเส้นทางการรับส่งข้อมูล HTTP ขาออกผ่านtap0อินเทอร์เฟซให้เปลี่ยน 465 เป็น 80

เพื่อป้องกันไม่ให้แพ็กเก็ตที่ส่งผ่านtap0การรับที่อยู่ LAN ของคุณเป็น IP ต้นทางให้ใช้กฎต่อไปนี้เพื่อเปลี่ยนเป็นที่อยู่อินเทอร์เฟซของคุณ (สมมติว่า10.0.0.2เป็นที่อยู่ IP สำหรับอินเทอร์เฟซtap0):

iptables -t nat -A POSTROUTING -o tap0 -j SNAT --to-source 10.0.0.2

ในที่สุดผ่อนคลายการตรวจสอบแหล่งที่มาของเส้นทางย้อนกลับ บางคนแนะนำให้คุณสามารถตั้งค่าให้0แต่2ดูเหมือนว่าทางเลือกที่ดีตามhttps://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt หากคุณข้ามสิ่งนี้คุณจะได้รับแพ็คเก็ต (ซึ่งสามารถยืนยันได้โดยใช้tcpdump -i tap0 -n) แต่แพ็คเก็ตไม่ได้รับการยอมรับ คำสั่งเพื่อเปลี่ยนการตั้งค่าเพื่อรับแพ็กเก็ต:

sysctl -w net.ipv4.conf.tap0.rp_filter=2

ทำไมคุณถึงใช้ SNAT แทน MASQUERADE MASQUERADE ไม่ทำสิ่งเดียวกันยกเว้นที่อยู่ IP จะถูกรวบรวมจากส่วนต่อประสานที่ "runtime" และไม่ได้ฮาร์ดโค้ดลงในไฟล์ปรับแต่ง
Ethan

6
@Ethan จากman iptables: ควรใช้กับการเชื่อมต่อ IP (dialup) ที่กำหนดแบบไดนามิกเท่านั้น: หากคุณมีที่อยู่ IP แบบคงที่คุณควรใช้เป้าหมาย SNAT การปลอมตัวนั้นเทียบเท่ากับการระบุการแมปไปยังที่อยู่ IP ของอินเทอร์เฟซที่แพ็คเก็ตกำลังจะออกไป แต่ก็มีผลกระทบที่การเชื่อมต่อจะถูกลืมเมื่ออินเตอร์เฟสหยุดทำงาน คุณพูดถูก แต่เนื่องจาก IP ของฉันจะไม่เปลี่ยนแปลงฉันจึงตัดสินใจใช้ SNAT ตามคำแนะนำโดย manpage
Lekensteyn

ฉันคิดว่า (แม้ว่าจะไม่ได้ทดสอบ) ขั้นตอนสุดท้าย (การตรวจสอบแหล่งที่มาของเส้นทางย้อนกลับ) ไม่จำเป็น คุณสามารถเพิ่มกฎอื่น ๆ ลงในPREROUTINGเชนเพื่อDNATไปยังแหล่งที่อยู่ที่ถูกต้อง (ตามเกตเวย์เริ่มต้นของคุณ)
Christian Wolf

7

ฉันแก้ไขสิ่งนี้ ปัญหาเกิดขึ้นจากกฎการจัดเส้นทางในตารางที่ 11 ตารางที่ 11 ได้รับผลกระทบ แต่กฎการกำหนดเส้นทางทำให้ไม่สามารถใช้งานได้ สคริปต์นี้เป็นสิ่งที่ฉันใช้ในตอนนี้และดูเหมือนว่าจะทำงานได้ดี (แม้ว่าจะชัดเจนโดยเฉพาะกับการตั้งค่าของฉัน) นอกจากนี้ฉันได้สร้างตารางใหม่ 21 เพื่อรองรับการอัปลิงค์หลัก (eth1)

# Add relevant iptables entries.
iptables -t mangle -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

# Flush ALL THE THINGS.
ip route flush table main
ip route flush table 11
ip route flush table 21
ip rule flush

# Restore the basic rules and add our own.
ip rule add lookup default priority 32767
ip rule add lookup main priority 32766
ip rule add fwmark 11 priority 1000 table 11
# This next rule basically sends all other traffic down eth1.
ip rule add priority 2000 table 21

# Restore the main table.  I flushed it because OpenVPN does weird things to it.
ip route add 127.0.0.0/8 via 127.0.0.1 dev lo
ip route add 192.168.1.0/24 dev eth1 src 192.168.1.73
ip route add default via 192.168.1.254

# Set up table 21.  This sends all traffic to eth1.
ip route add 192.168.1.0/24 dev eth1 table 21
ip route add default via 192.168.1.254 dev eth1 table 21

# Set up table 11.  I honestly don't know why 'default' won't work, or
# why the second line here is needed.  But it works this way.
ip route add 10.32.0.49/32 dev tun0 table 11
ip route add 10.32.0.1 via 10.32.0.50 dev tun0 table 11
ip route add 0.0.0.0/1 via 10.32.0.50 dev tun0 table 11

ip route flush cache

## MeanderingCode แก้ไข (เพราะฉันยังไม่สามารถแสดงความคิดเห็นได้)

ขอบคุณสำหรับคำตอบนี้! ดูเหมือนว่าสิ่งนี้อาจยุ่งเพราะคุณจะต้องเก็บรักษาข้อมูลเส้นทางไว้ที่นี่ (อาจทำซ้ำหรือทำลายสิ่งอื่น ๆ ที่อาจต้องการกำหนดเส้นทาง

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

ในกรณีที่อดีตคุณสามารถแก้ไขการกำหนดค่า OpenVPN ของคุณและใส่ในโฆษณาที่มี "เส้นทาง nopull"
ในระยะหลังการกำหนดค่าการตรวจสอบ OpenVPN หรือห่อหุ้มใด ๆ (เครือข่ายผู้จัดการ OpenVPN เช่นในหลายปัจจุบัน distros เดสก์ทอปลินุกซ์)
ใน ไม่ว่าในกรณีใดการกำจัดการกำหนดค่าการกำหนดเส้นทางที่จะได้รับการตั้งค่านั้นสะอาดและปลอดภัยกว่าการล้างตารางทั้งนี้ขึ้นอยู่กับเมื่อคุณเรียกใช้สคริปต์นี้และสิ่งที่ระบบของคุณกำลังทำอยู่

ไชโย!


2

ฉันคิดว่าคุณต้องการ:

/sbin/ip route add default via 10.32.0.49 dev tun0 table 11
/sbin/ip rule add priority 10000 fwmark 11 table 11

http://lartc.org/howto/lartc.netfilter.html

แต่ฉันไม่ได้ทดสอบด้านบน


คำสั่งแรกส่งกลับ "ข้อผิดพลาด: อย่างใดอย่างหนึ่ง" ถึง "ซ้ำกันหรือ" 10.32.0.49 "เป็นขยะ"
Ethan

ขออภัยลืมผ่านระหว่างค่าเริ่มต้นและ IP
mfarver

ฉันลองแล้ว ดูเหมือนว่าจะมีผลเช่นเดียวกับการออกจากdefaultคำหลัก
อีธาน

หากต้องการกำจัดตัวเลือกคุณอาจลองทำการจับแพ็คเก็ตใน tun0 และดูว่าแพ็กเก็ตนั้นสิ้นสุดบนอินเตอร์เฟสนั้นหรือไม่ tcpdump -i tun0 .. อีกทางหนึ่งคุณต้องยึดตาม ID ผู้ใช้หรือไม่? คุณสามารถทำตามที่อยู่ IP ปลายทาง (ง่ายกว่า) ได้ไหม เส้นทางเพิ่ม <remote host> ผ่าน 10.32.0.49
mfarver

ฉันไม่สามารถอ้างอิงได้หากปิดที่อยู่ IP ปลายทาง - จะมีหลายอย่าง ฉันสามารถใช้เหตุผลในการปิด pid ได้ แต่มันก็ยากกว่าเพราะฉันไม่รู้ pid จนกระทั่ง daemon เริ่มต้น
Ethan

0

สิ่งนี้สามารถทำได้โดยไม่มีคำสั่ง iptables ดำเนินการคำสั่ง ip แบบง่าย

สำหรับ uid 1002:

ip rule add uidrange 1002-1002 table 502

เพิ่มเส้นทางเริ่มต้นสำหรับตาราง 502 ผ่านส่วนต่อประสานที่คุณต้องการพูด

eth0 ip rule add default via a.b.c.d dev eth0

ฉันทดสอบคำสั่งนั้นแล้ว แต่ก็ไม่ทำงาน:Error: argument "uidrange" is wrong: Failed to parse rule type
kasperd

@kasperd คุณต้องทำสิ่งที่ผิดเพราะมันใช้ได้ดีสำหรับฉัน
horseyguy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.