로컬 NAT FTP 서버를 공개적으로 사용 가능하게 만드는 nft 구성

로컬 NAT FTP 서버를 공개적으로 사용 가능하게 만드는 nft 구성

모든 것이 격리된 네트워크에 있으므로 보안은 문제가 되지 않습니다.
eth0은 "공용" 네트워크에 연결되어 있습니다. DHCP에 의해 할당된 주소입니다.
eth1은 ssh, telnet, "others" 및 ftp를 제공하는 "개인 네트워크" 서버에 연결됩니다.
이 예에서 이 서버는 고정 IP(192.168.1.2)를 갖습니다.

게이트웨이는 Debian Buster 및 Linux 커널 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를 작동시키려면 무엇을 추가해야 합니까?

답변1

TL;DR

# 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에서 이는 플러그인인 프로토콜별 도우미 모듈에 의해 제공됩니다.콘트랙, NAT 및 상태 저장 방화벽에 대한 연결을 추적하는 Netfilter 하위 시스템입니다. FTP를 사용하면 다음 전송을 위한 포트 협상(주로 PORT, EPRT, PASV 또는 EPSV)이 FTP 명령 포트에서 확인되면 도우미는 특수 항목에 단기 항목을 추가합니다.콘트랙테이블(기대를 따르다테이블)은 다음 관련 및 예상 데이터 연결을 기다립니다.

내 대답은 다음에 설명된 대로 최신 "보안" 처리를 사용합니다.이 블로그에 대해iptables일반사항과nftables위키그리고man nft처리를 위해nftables이는 다음과 다르다iptables.

도우미 및 nftables 규칙의 안전한 사용

Linux 커널 4.7+(4.19 포함)는 기본적으로 보안 접근 방식을 사용합니다. (여기서는 FTP) 도우미 모듈을 로드해도 특정 시점까지 TCP 소스 또는 대상 포트 21이 있는 모든 패킷을 더 이상 스누핑할 수 없습니다.nftables(또는iptables) 문은 어떤 (제한된) 경우에 스누핑해야 하는지 알려줍니다. 이렇게 하면 불필요한 CPU 사용을 방지하고 몇 가지 규칙(또는 세트)만 변경하여 언제든지 FTP 포트를 스누핑하도록 변경할 수 있습니다.

첫 번째 부분은 스누핑을 트리거할 수 있는 흐름을 선언하는 것입니다. 에서는 다르게 처리됩니다.nftables에서보다iptables. 여기서는 상태 저장 개체를 사용하여 선언되었으며 ct helper이를 활성화하기 위한 필터는 이후에 수행되어야 합니다.콘트랙(하는 동안iptables이전에 수행된 작업이 필요합니다).man nft말한다:

iptables와 달리 도우미 할당은 conntrack 조회가 완료된 후 수행되어야 합니다(예: 기본 후크 우선순위 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

방화벽 정보

다음은 방화벽에 대한 추가 참고 사항입니다. 다음과 같이 태그가 지정된 새로운 흐름을 허용하는 대신 몇 가지 제한 사항이 있는 방화벽 규칙이 있을 수도 있습니다.관련된~에 의해콘트랙.

예를 들어, 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와 관련되지 않은 흐름은 허용된 상태로 유지됩니다(또는 별도로 추가로 분할될 수 있음).


도우미의 처리 예

여기(시뮬레이션된 환경에서) 두 가지가 있습니다.콘트랙측정된 이벤트 목록기대테이블과콘트랙OP 규칙이 포함된 표 + 인터넷 클라이언트 203.0.113.101이 라우터의 공용 IP 주소 192.0.2.2로 수동 모드에서 FTP를 수행하고 로그인 후 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=37157203.0.113.101:*에서 192.0.2.2:37157까지의 다음 TCP 연결이 연결될 것임을 알려줍니다(상태관련된) FTP 연결을 사용합니다. 직접적으로 표시되지는 않지만 NAT FTP 도우미 모듈도 로드되므로 PASV/EPSV 명령에 대한 응답으로 서버에서 보낸 실제 데이터가 가로채서 변환되어 클라이언트가 192.168.1.2 대신 192.0.2.2에 연결됩니다. 물론 클라이언트에서는 실패했습니다.

두 번째 흐름에도 불구하고(두 번째새로운라인) 명시적인 규칙이 없습니다.my_prerouting, 라우터 뒤의 서버에 성공적으로 DNATed되었습니다.


노트

  • FTP 제어 포트가 암호화된 경우( AUTH TLS...) 도우미 모듈은 더 이상 협상된 포트를 스누핑할 수 없으며 작동하지 않습니다. FTP 서버 구성과 방화벽/NAT 라우터 모두에서 예약된 포트 범위를 구성해야 하며, 협상할 때 자체 IP 주소 대신 올바른 (공용) IP 주소를 보내도록 서버를 구성해야 합니다. 그리고 서버에 인터넷 경로가 없으면 활성 FTP 모드를 사용할 수 없습니다(여기서 나타나는 경우).

  • nitpicking: 사전 라우팅 우선순위 10은 커널 < 4.18에서도 NAT가 이미 새로운 흐름에 대해 발생했음을 보장하므로 OP는 nftables에서는 거의 중요하지 않기 때문에 일반적인 -100 대신 후크 사전 라우팅 우선순위 0을 선택했습니다. 따라서 사용이 daddr 192.168.1.2가능합니다. 우선 순위가 0(또는 0보다 낮음)인 경우 규칙은 첫 번째 패킷이 여전히 공용 IP 대상 주소와 NAT되지 않은 것으로 확인하지만 처리되기 때문에 동일한 흐름의 다음 패킷을 포착할 가능성이 있습니다(확인되지 ​​않음). 직접적으로콘트랙우선순위 -200. 안전을 유지하고 10을 사용하는 것이 좋습니다. 실제로 이것은 커널 4.18 이후로 관련이 없습니다(참조저지르다참조이것보류 중인 패치) 여기서 NAT 우선순위는 여러 nat 체인 간의 비교에만 관련됩니다(그리고 nftables를 따라 iptables 레거시에서 NAT를 혼합할 수 있습니다).

답변2

몇 번의 시행착오 끝에 다음 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"
        }

}

관련 정보