nftables: ทำซ้ำแพ็กเก็ตออกอากาศระหว่างเซ็กเมนต์

Aug 18 2020

เรามีกล่อง Debian Buster (nftables 0.9.0, kernel 4.19) ที่แนบมากับกลุ่มเครือข่ายที่แตกต่างกันสี่กลุ่ม สามส่วนเหล่านี้เป็นที่ตั้งของอุปกรณ์ที่ใช้ Syncthing ซึ่งเรียกใช้การค้นพบในเครื่องของตัวเองผ่านการออกอากาศไปยังพอร์ต UDP 21027 ดังนั้นอุปกรณ์ทั้งหมดจึงไม่สามารถ "มองเห็น" ซึ่งกันและกันได้เนื่องจากการแพร่ภาพไม่ได้ข้ามส่วน กล่อง Buster เองไม่ได้มีส่วนร่วมในคลัสเตอร์การซิงค์

แม้ว่าเราจะแก้ปัญหานี้ได้ด้วยการเรียกใช้เซิร์ฟเวอร์การค้นพบหรือรีเลย์ของ Syncthing ในกล่อง Buster แต่ก็มีการร้องขอให้เราไม่ใช้มัน (เหตุผลเกี่ยวกับการกำหนดค่าและอุปกรณ์ที่เดินทางไปยังไซต์อื่น) ดังนั้นเรากำลังมองหาโซลูชันที่ใช้ nftables ความเข้าใจของฉันคือปกติแล้วสิ่งนี้ไม่ได้ทำ แต่เพื่อให้ทำงานนี้เราต้อง:

  • จับคู่แพ็กเก็ตขาเข้าบน UDP 21027
  • คัดลอกแพ็กเก็ตเหล่านั้นไปยังอินเทอร์เฟซเซกเมนต์อื่นที่ต้องการให้เห็น
  • เปลี่ยน IP ปลายทางของแพ็กเก็ตใหม่เพื่อให้ตรงกับที่อยู่การออกอากาศของเซ็กเมนต์ใหม่ (ในขณะที่รักษา IP ต้นทางเนื่องจากโปรโตคอลการค้นพบสามารถพึ่งพาได้)
  • ปล่อยการออกอากาศใหม่โดยไม่ให้ซ้ำกันอีก

มีเพียงสามกลุ่มที่แนบมาเท่านั้นที่เข้าร่วมกับอุปกรณ์ ทั้งหมดเป็นซับเน็ตมาสก์เป็น / 24

  • ไม่ควรส่งต่อส่วน A (eth0, 192.168.0.1)
  • เซ็กเมนต์ B (eth1, 192.168.1.1) ควรถูกส่งต่อไปยังเซ็กเมนต์ A เท่านั้น
  • ควรส่งต่อส่วน C (eth2, 192.168.2.1) ไปยังทั้ง A และ B

สิ่งที่ใกล้เคียงที่สุดที่เราต้องมีกับกฎการทำงานสำหรับสิ่งนี้คือ (DNAT / MASQ อื่น ๆ และกฎการกรองในพื้นที่ถูกละไว้เพื่อความกะทัดรัด):

table ip mangle {
    chain repeater {
        type filter hook prerouting priority -152; policy accept;
        ip protocol tcp return
        udp dport != 21027 return
        iifname "eth1" ip saddr 192.168.2.0/24 counter ip daddr set 192.168.1.255 return
        iifname "eth0" ip saddr 192.168.2.0/24 counter ip daddr set 192.168.0.255 return
        iifname "eth0" ip saddr 192.168.1.0/24 counter ip daddr set 192.168.0.255 return
        iifname "eth2" ip saddr 192.168.2.0/24 counter dup to 192.168.0.255 device "eth0" nftrace set 1
        iifname "eth2" ip saddr 192.168.2.0/24 counter dup to 192.168.1.255 device "eth1" nftrace set 1
        iifname "eth1" ip saddr 192.168.1.0/24 counter dup to 192.168.0.255 device "eth0" nftrace set 1
    }
}

ตัวนับแสดงให้เห็นว่ามีการตีกฎแม้ว่าจะไม่มีdaddr setกฎที่อยู่การออกอากาศจะยังคงเหมือนเดิมในส่วนต้นทาง nft monitor traceแสดงให้เห็นว่าอย่างน้อยแพ็กเก็ตบางส่วนกำลังเข้าถึงอินเทอร์เฟซที่ต้องการด้วย IP ปลายทางที่ถูกต้อง แต่จากนั้นจะเชื่อมโยงไปถึงในเบ็ดอินพุตสำหรับกล่องเองและอุปกรณ์อื่น ๆ ในเซ็กเมนต์นั้นจะไม่เห็น

ผลลัพธ์ที่เรากำลังมองหาที่นี่เป็นไปได้ในทางปฏิบัติหรือไม่และถ้าเป็นเช่นนั้นกฎใด

คำตอบ

1 A.B Aug 21 2020 at 03:53

ยังคงเป็นไปได้ที่จะใช้ nftables ในตระกูลnetdev (แทนที่จะเป็นตระกูลip ) สำหรับกรณีนี้เนื่องจากจำเป็นต้องใช้เฉพาะทางเข้าเท่านั้น(nftables ยังไม่มีขาออก ) ลักษณะการทำงานของdupและfwdในการเข้าเบ็ดเป็นเหมือนกับTC-mirred 's และmirrorredirect

ฉันยังกล่าวถึงรายละเอียดเล็กน้อย: เขียนที่อยู่ต้นทางอีเธอร์เน็ตไปยังที่อยู่ MAC ของอินเทอร์เฟซขาออกอีเทอร์เน็ตใหม่เช่นเดียวกับที่เคยทำมาสำหรับแพ็กเก็ตที่กำหนดเส้นทางอย่างแท้จริงแม้ว่าจะเหมาะกับคุณหากไม่มีสิ่งนี้ก็ตาม ดังนั้นจึงต้องทราบที่อยู่ MAC ของอินเทอร์เฟซล่วงหน้า ฉันใส่สองสิ่งที่จำเป็น ( eth0 's และeth1 ' s) ในตัวแปร / นิยามมาโครซึ่งควรแก้ไขด้วยค่าที่ถูกต้อง

define eth0mac = 02:0a:00:00:00:01
define eth1mac = 02:0b:00:00:00:01

table netdev statelessnat
delete table netdev statelessnat

table netdev statelessnat {
    chain b { type filter hook ingress device eth1 priority 0;
        pkttype broadcast ether type ip ip daddr 192.168.1.255 udp dport 21027 jump b-to-a
        
    }

    chain c { type filter hook ingress device eth2 priority 0;
        pkttype broadcast ether type ip ip daddr 192.168.2.255 udp dport 21027 counter jump c-to-b-a
    }

    chain b-to-a {
        ether saddr set $eth0mac ip daddr set 192.168.0.255 fwd to eth0 } chain c-to-b-a { ether saddr set $eth1mac ip daddr set 192.168.1.255 dup to eth1 goto b-to-a
    }
}
1 T2PS Aug 19 2020 at 21:44

แก้ไข: สำหรับใครก็ตามที่พบสิ่งนี้ในภายหลังคำตอบที่ยอมรับจาก AB จะให้วิธีแก้ปัญหาอย่างหมดจด

ขอบคุณคำแนะนำของ AB ตอนนี้ใช้งานได้โดยใช้ tc แทนที่จะเป็นกฎ nftables ล้วนๆ:

tc qdisc add dev eth2 ingress
tc filter add dev eth2 ingress \
    protocol ip u32 \
    match ip dst 192.168.2.255 \
    match ip protocol 17 0xff \
    match ip dport 21027 0xffff \
    action nat ingress 192.168.2.255/32 192.168.0.255 \
    pipe action mirred egress mirror dev eth0 \
    pipe action nat ingress 192.168.0.255/32 192.168.1.255 \
    pipe action mirred egress redirect dev eth1

tc qdisc add dev eth1 ingress
tc filter add dev eth1 ingress \
    protocol ip u32 \
    match ip dst 192.168.1.255 \
    match ip protocol 17 0xff \
    match ip dport 21027 0xffff \
    action nat ingress 192.168.1.255/32 192.168.0.255 \
    pipe action mirred egress redirect dev eth0

ความเข้าใจของฉันเกี่ยวกับตัวกรองเหล่านี้คือจับคู่แพ็กเก็ตการออกอากาศขาเข้าสำหรับพอร์ต UDP 21027 NAT กับที่อยู่ออกอากาศสำหรับเครือข่ายย่อยอื่น ๆ ที่ต้องการ ( ingressเพื่อเปลี่ยน IP ปลายทางแทนที่จะเป็น IP ต้นทางที่nat egressจะเปลี่ยนแปลง) จากนั้นทำซ้ำ / เปลี่ยนเส้นทาง แพ็กเก็ต NATted ไปยังคิวเอาต์พุตของอินเทอร์เฟซอื่น ๆ

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