nftables와 함께 Linux를 라우터로 사용 - 응답을 전달하지 않는 척

nftables와 함께 Linux를 라우터로 사용 - 응답을 전달하지 않는 척

라우터로 사용하는 Linux 시스템이 있습니다. 여기에는 5개의 네트워크 인터페이스가 있습니다. 즉, 3개의 독립적인 LAN과 이들 사이에 라우팅되는 2개의 WAN이 있습니다. 현재 기본 경로로 하나의 WAN만 있고 다른 WAN은 실제로 아무 작업도 수행하지 않습니다. 저는 수년 동안 iptables와 IP 규칙을 사용하여 두 WAN이 모두 작동하도록 노력했지만 성공하지 못했습니다.

내가 겪고 있는 문제는 다음과 같습니다. WAN 2(NAT 필요)를 통해 핑을 라우팅하려고 하면 내 핑이 클라이언트 호스트에서 Linux 시스템으로 전송된 다음 Linux 시스템이 이를 WAN 2를 통해 올바르게 전달합니다. 응답을 다시 확인하지만 패킷을 내 클라이언트 컴퓨터로 다시 전달하지 않습니다. 많은 검색과 읽기 관련 질문에도 불구하고 왜 다시 전달되지 않는지 알 수 없었습니다. (WAN 1은 NAT가 외부 라우터에서 수행되므로 NAT가 필요하지 않습니다.)

며칠 전 iptables에서 nftables로 전환했습니다. 왜냐하면 a) 구성을 더 쉽게 읽을 수 있고 b) 실제로 규칙 평가를 추적하여 무슨 일이 일어나고 있는지 확인할 수 있기 때문입니다. 이로써 이제 질문할 시간이 충분해진 것 같습니다.

이 내 꺼야 /etc/nftables.conf:

table ip filter {
    chain INPUT {
            type filter hook input priority 0; policy accept;

            ip protocol icmp counter meta nftrace set 1

            # allow loopback
            iifname "lo" accept

            # allow established/related connections
            ct state {established, related} accept

            # allow ping
            ip protocol icmp accept

            # accept anything from local networks
            ip saddr {
                    172.23.0.0/24, # lan1
                    172.23.2.0/24, # routed through lan1
                    172.23.3.0/24, # routed through lan1
                    172.23.4.0/24, # lan2
                    172.23.5.0/24, # lan3
            } accept

            # ntp exploit protection
            udp sport ntp ct state {invalid, related, new, untracked} counter drop

            # accept SSH from anyone else
            ct state new tcp dport ssh accept

            # drop all other packets
            counter drop
    }

    chain FORWARD {
            type filter hook forward priority 0; policy accept;

            ip protocol icmp counter meta nftrace set 1

            # drop anything to old local network 172.23.1.0/24
            ip daddr 172.23.1.0/24 counter drop

            # accept all other packets
            counter accept
    }

    chain OUTPUT {
            type filter hook output priority 0; policy accept;

            # ntp exploit protection
            udp dport ntp ct state {invalid, related, untracked} counter drop
    }
}

table ip mangle {
    chain FORWARD {
            type filter hook forward priority -150; policy accept;

            ip protocol icmp counter meta nftrace set 1
    }

    chain OUTPUT {
            type filter hook output priority -150; policy accept;

            # send replies to WAN->HERE connections via the same route as where they were initiated from
            ct state related,established meta mark set ct mark
    }

    chain PREROUTING {
            type filter hook prerouting priority -150; policy accept;

            # trace ALL packets coming from enp6s0 (WAN 2)
            iifname enp6s0 counter meta nftrace set 1

            # send subsequent packets on forwarded connections via the same route as when they were initiated
            ct state related,established meta mark set ct mark

            # trace all packets with a packet mark
            meta mark != 0x0 counter meta nftrace set 1

            # all further processing is for new connections only - so everything else returns here
            ct state != new return

            # any new WAN->LAN connections from enp6s0 (WAN 2) go into route 3, for the initial and subsequent packets
            # the return on the end ensures we don't do any further processing, which checks outbound protocols
            iifname enp6s0 ct mark set 0x3 meta mark set 0x3 return

            # any new WAN->LAN connections from enp4s0 (WAN 1) shouldn't do further processing either
            iifname enp4s0 return

            # everything from this point onwards is for new outgoing LAN->WAN connections only

            # for testing - route specific protocols through WAN 2
            #tcp dport 443 ct mark set 0x3 meta mark set 0x3
            #tcp dport 80 ct mark set 0x3 meta mark set 0x3
            ip protocol icmp ct mark set 0x3 meta mark set 0x3 counter meta nftrace set 1
    }
}

table ip nat {
    chain POSTROUTING {
            type nat hook postrouting priority 100; policy accept;

            oifname enp6s0 counter meta nftrace set 1 masquerade
    }
}

ip -4 addr: (enp4s0은 WAN 1, enp6s0은 WAN 2, 나머지는 LAN입니다)

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 192.168.0.3/24 brd 192.168.0.255 scope global enp4s0
       valid_lft forever preferred_lft forever
3: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 172.23.4.3/24 brd 172.23.4.255 scope global enp5s0
       valid_lft forever preferred_lft forever
4: enp6s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet (redacted).117/22 brd 255.255.255.255 scope global enp6s0
       valid_lft forever preferred_lft forever
5: enp7s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    inet 172.23.5.3/24 brd 172.23.5.255 scope global enp7s0
       valid_lft forever preferred_lft forever
6: enp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 172.23.0.3/24 brd 172.23.0.255 scope global enp8s0
       valid_lft forever preferred_lft forever

ip route:

default via 192.168.0.1 dev enp4s0
(redacted).0/22 dev enp6s0 proto kernel scope link src (redacted).117 metric 204 mtu 1500
172.23.0.0/24 dev enp8s0 proto kernel scope link src 172.23.0.3
172.23.0.0/16 via 172.23.0.2 dev enp8s0
172.23.4.0/24 dev enp5s0 proto kernel scope link src 172.23.4.3
172.23.5.0/24 dev enp7s0 proto kernel scope link src 172.23.5.3 linkdown
192.168.0.0/24 dev enp4s0 proto kernel scope link src 192.168.0.3

ip route show table 3:

default via (redacted).1 dev enp6s0
(redacted).1 dev enp6s0 scope link src (redacted).117
172.23.0.0/24 dev enp8s0 proto kernel scope link src 172.23.0.3
172.23.0.0/16 via 172.23.0.2 dev enp8s0
172.23.4.0/24 dev enp5s0 proto kernel scope link src 172.23.4.3
172.23.5.0/24 dev enp7s0 proto kernel scope link src 172.23.5.3 linkdown
192.168.0.0/24 dev enp4s0 proto kernel scope link src 192.168.0.3

ip rule:

0:      from all lookup local
32764:  from all fwmark 0x3 lookup 3
32765:  from (redacted).117 lookup 3
32766:  from all lookup main
32767:  from all lookup default

nft monitor trace이제 흥미로운 점은 클라이언트(Windows) PC에서 8.8.8.8을 핑할 때의 출력은 다음과 같습니다.

trace id 8e85e085 ip mangle PREROUTING packet: iif "enp8s0" ether saddr dc:9f:db:16:42:b5 ether daddr 38:ea:a7:ab:f8:bc ip saddr 172.23.2.132 ip daddr 8.8.8.8 ip dscp cs0 ip ecn not-ect ip ttl 127 ip id 4170 ip length 60 icmp type echo-request icmp code 0 icmp id 1 icmp sequence 779
trace id 8e85e085 ip mangle PREROUTING rule ip protocol icmp ct mark set 0x00000003 mark set 0x00000003 counter packets 0 bytes 0 nftrace set 1 (verdict continue)
trace id 8e85e085 ip mangle PREROUTING verdict continue mark 0x00000003
trace id 8e85e085 ip mangle PREROUTING mark 0x00000003
trace id 8e85e085 ip mangle FORWARD packet: iif "enp8s0" oif "enp6s0" ether saddr dc:9f:db:16:42:b5 ether daddr 38:ea:a7:ab:f8:bc ip saddr 172.23.2.132 ip daddr 8.8.8.8 ip dscp cs0 ip ecn not-ect ip ttl 126 ip id 4170 ip length 60 icmp type echo-request icmp code 0 icmp id 1 icmp sequence 779
trace id 8e85e085 ip mangle FORWARD rule ip protocol icmp counter packets 0 bytes 0 nftrace set 1 (verdict continue)
trace id 8e85e085 ip mangle FORWARD verdict continue mark 0x00000003
trace id 8e85e085 ip mangle FORWARD mark 0x00000003
trace id 8e85e085 ip filter FORWARD packet: iif "enp8s0" oif "enp6s0" ether saddr dc:9f:db:16:42:b5 ether daddr 38:ea:a7:ab:f8:bc ip saddr 172.23.2.132 ip daddr 8.8.8.8 ip dscp cs0 ip ecn not-ect ip ttl 126 ip id 4170 ip length 60 icmp type echo-request icmp code 0 icmp id 1 icmp sequence 779
trace id 8e85e085 ip filter FORWARD rule ip protocol icmp counter packets 0 bytes 0 nftrace set 1 (verdict continue)
trace id 8e85e085 ip filter FORWARD rule counter packets 8 bytes 452 accept (verdict accept)
trace id 8e85e085 ip nat POSTROUTING packet: oif "enp6s0" ip saddr 172.23.2.132 ip daddr 8.8.8.8 ip dscp cs0 ip ecn not-ect ip ttl 126 ip id 4170 ip length 60 icmp type echo-request icmp code 0 icmp id 1 icmp sequence 779
trace id 8e85e085 ip nat POSTROUTING rule oifname "enp6s0" counter packets 0 bytes 0 nftrace set 1 masquerade (verdict accept)
trace id eae785df ip mangle PREROUTING packet: iif "enp6s0" ether saddr 00:01:5c:86:1a:47 ether daddr 00:e0:4c:68:12:d9 ip saddr 8.8.8.8 ip daddr (redacted).117 ip dscp cs0 ip ecn not-ect ip ttl 56 ip id 39719 ip length 60 icmp type echo-reply icmp code 0 icmp id 1 icmp sequence 779
trace id eae785df ip mangle PREROUTING rule iifname "enp6s0" counter packets 0 bytes 0 nftrace set 1 (verdict continue)
trace id eae785df ip mangle PREROUTING rule ct state established,related mark set ct mark (verdict continue)
trace id eae785df ip mangle PREROUTING rule mark != 0x00000000 counter packets 0 bytes 0 nftrace set 1 (verdict continue)
trace id eae785df ip mangle PREROUTING verdict return mark 0x00000003
trace id eae785df ip mangle PREROUTING mark 0x00000003
trace id eae785df ip filter INPUT packet: iif "enp6s0" ether saddr 00:01:5c:86:1a:47 ether daddr 00:e0:4c:68:12:d9 ip saddr 8.8.8.8 ip daddr (redacted).117 ip dscp cs0 ip ecn not-ect ip ttl 56 ip id 39719 ip length 60 icmp type echo-reply icmp code 0 icmp id 1 icmp sequence 779
trace id eae785df ip filter INPUT rule ip protocol icmp counter packets 0 bytes 0 nftrace set 1 (verdict continue)
trace id eae785df ip filter INPUT rule ct state { } accept (verdict accept)

출력의 관련 줄은 다음과 같습니다 conntrack -L.

icmp     1 15 src=172.23.2.132 dst=8.8.8.8 type=8 code=0 id=1 src=8.8.8.8 dst=(redacted).117 type=0 code=0 id=1 mark=3 use=1

아웃바운드 부분에는 내 클라이언트의 로컬 IP 소스와 내가 핑하는 외부 서버의 대상이 있지만 인바운드 부분에는 내 클라이언트의 로컬 IP가 아닌 전달을 수행하는 컴퓨터의 외부 IP가 있습니다. (이것이 문제를 나타내는지 확실하지 않습니다.)

보시다시피 echo-request 패킷은 패킷 태그와 conntrack 태그를 3으로 올바르게 설정한 다음 IP 규칙과 라우팅 테이블 3을 기반으로 올바른 출력 인터페이스를 선택한 다음 올바르게 가장하고 에코를 수신한 이후로 명확하게 도착합니다. 답장해 주세요. 온라인 상태였습니다. echo-reply 패킷은 conntrack 태그(여전히 3개)를 패킷 태그에 올바르게 복사합니다. 하지만 보시다시피 원래 수행했던 NAT를 역전시키지 않으므로 다시 전달되는 대신 INPUT 체인으로 들어갑니다. 내 클라이언트 컴퓨터에.

뭔가 빠졌다고 확신합니다. NAT 작업을 되돌리라는 규칙이 있어야 한다고 생각합니다. 하지만 LAN->WAN에서 NAT를 수행하는 방법을 설명하는 모든 페이지에는 필요한 유일한 규칙이 있다고 나와 있습니다. 인바운드 패킷의 백라우팅에 대한 초기 아웃 매스커레이딩 규칙(많은 가이드에서 인바운드 연결에 대한 포트 전달과 같은 다른 규칙을 제공하지만 이는 단순 아웃바운드 연결과 관련이 없습니다).

내가 무엇을 놓치고 있나요?

답변1

nftables 위키에서는 다음과 같이 말합니다.

"[...] 규칙이 없더라도 사전 경로/사후 경로 체인을 등록해야 합니다. 이러한 체인은 응답 방향에서 들어오는 패킷에 대해 NAT 엔진을 호출하기 때문입니다."https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)

필터 유형의 미리 라우팅된 체인이 있지만 NAT 유형은 아닌 것 같습니다. chain PREROUTING { type nat hook prerouting priority -150 ; } 파일 table ip nat { [...] }에 섹션을 추가해 보세요 /etc/nftable.conf.

답변2

문제는 NAT 포스트라우팅 체인의 우선순위가 -100이라는 것입니다. ~에 따르면nftables 위키, iptables의 DNAT는 우선순위 -100으로 실행되지만 iptables의 우선순위 (+)100에 해당하는 SNAT가 필요하다고 생각합니다. 이게 도움이 되길 바란다.

관련 정보