【2023年9月版】NAT環境で、PASVモードのFTPサーバ構築【Ubuntu22.04】

# はじめに

NAT環境でFTPサーバ構築しよう。
NATの設定してすぐにできそう。ftpはpasvモードで余裕でいけるでしょ。

curl コマンドで。。。アクセスできる。
ftp コマンドで。。。あれ？ ls コマンドが帰ってこない。。。pasvモードになってるのに。。。

なんか、PASVモードで接続できるクライアントとできないクライアントがあるぞ。。。

からの、ChatGPTに質問しながら、NAT環境でPASVモードによるFTPサーバ構築のメモ

# 環境

```plantuml
@startuml
node "FTPサーバ" as ftp_server
node "NATサーバ" as napt_server
node "FTPクライアント" as ftp_client
ftp_server "10.10.10.100" -- "10.10.10.254" napt_server
napt_server "192.168.100.254" -- "192.168.100.10" ftp_client
@enduml
```

## FTPサーバ

- Windows Server 2019 + IIS (10.10.10.100)

## NATサーバ

- Ubuntu22.04 + iptables (10.10.10.254, 192.168.100.254)

## FTP クライアント

- Ubuntu22.04 (192.168.100.10)
    - curl
    - ftp

# うまくいかなかったパターン

単にNAPTサーバでNATを構成したパターン

## パッケットのフォワードができるように設定

```terminal
$ echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
net.ipv4.ip_forward = 1
```

## iptables を設定

```terminal
$ sudo iptables -F -t nat && sudo iptables -F
$ sudo iptables -t nat -A PREROUTING -d 192.168.100.254 -p tcp --dport 21 -j DNAT --to-destination 10.10.10.100
$ sudo iptables -t nat -A PREROUTING -d 192.168.100.254 -p tcp --dport 1024:65535 -j DNAT --to-destination 10.10.10.100
$ sudo iptables -t nat -A POSTROUTING -d 10.10.10.254 -j MASQUERADE
```

## FTPクラアントからアクセス

- curl OK
    - `curl ftp://192.168.100.254`
- ftp NG
    - `ftp 192.168.100.254`

アクセスできない理由は、`tcpdump` でFTPコマンドを覗けばすぐわかる。 
FTPサーバからのPASVのアクセス先が、`192.168.100.254`ではなく、`10.10.10.100`(NATされる前の元IP)で返されるから。
curlはそのあたりを理解して、アクセス先IPに自動で変換してくれる。
以下は ftp でうまくいかないパターン
```terminal
$ ftp 192.168.100.254
Connected to 192.168.100.254 (192.168.100.254).
220 Microsoft FTP Service
Name (192.168.100.254:dev): ftpuser
331 Password required
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
227 Entering Passive Mode (10.10.10.100,243,215).
150 Opening ASCII mode data connection.
425 Cannot open data connection.
ftp> exit
```
以下は crul でうまくいくパターンの抜粋、元のIPアドレスを再利用してくれている。
```terminal
> PASV
* Connect data stream passively
* ftp_perform ends with SECONDARY: 0
< 227 Entering Passive Mode (10.10.10.100,240,151).
* Skip 10.10.10.100 for data connection, re-use 192.168.100.254 instead
* Connecting to 192.168.100.254 (192.168.100.254) port 61591
*   Trying 192.168.100.254:61591...
```

# うまくいったパターン

カーネルモジュール `ip_conntrack_ftp` と `ip_nat_ftp` を導入する。

## conntrack インストール

`ip_conntrack_ftp` と `ip_nat_ftp` による接続を確認するためのツール

```terminal
$ sudo apt install conntrack
```

## パッケットのフォワード、`ip_conntrack_ftp`、`ip_nat_ftp` が利用できるように設定

```terminal
$ echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
$ echo "net.netfilter.nf_conntrack_helper = 1" | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
net.ipv4.ip_forward = 1
net.netfilter.nf_conntrack_helper = 1
$ echo "ip_conntrack_ftp" | sudo tee -a /etc/modules
$ echo "ip_nat_ftp" | sudo tee -a /etc/modules
$ sudo modprobe ip_conntrack_ftp
$ sudo modprobe ip_nat_ftp
```

## iptables を設定

```terminal
$ sudo iptables -F -t nat && sudo iptables -F
$ sudo iptables -t nat -A PREROUTING -d 192.168.100.254 -p tcp --dport 21 -j DNAT --to-destination 10.10.10.100
$ sudo iptables -t nat -A POSTROUTING -d 10.10.10.254 -j MASQUERADE
```

## FTPクラアントからアクセス

- curl OK
    - `curl ftp://192.168.100.254`
- ftp OK
    - `ftp 192.168.100.254`

NAPTサーバで、FTPのPASVの返りを加工してくれるようになるので、アクセスできる

以下は ftp でうまくいったパターン

```terminal
$ ftp 192.168.100.254
Connected to 192.168.100.254 (192.168.100.254).
220 Microsoft FTP Service
Name (192.168.100.254:dev): ftpuser
331 Password required
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
227 Entering Passive Mode (192.168.100.254,251,57).
125 Data connection already open; Transfer starting.
08-14-23  12:01PM       <DIR>          abc
08-14-23  12:01PM                    9 test.txt
226 Transfer complete.
ftp> exit
```

# うまくいかないとき

`conntrack` コマンドで `ftp` で検索し、pssvモードのftp接続を行った時にエントリが表示されているか確認する

```terminal
$ sudo conntrack -L | grep ftp    # pasvモードでftp接続してから確認、エントリが表示される
conntrack v1.4.6 (conntrack-tools): 11 flow entries have been shown.
tcp      6 431998 ESTABLISHED src=192.168.100.10 dst=192.168.100.254 sport=53110 dport=21 src=10.10.10.100 dst=10.10.10.254 sport=21 dport=53110 [ASSURED] mark=0 helper=ftp use=2
```

# iptables の設定の保存

iptables-persistent を使う

```terminal
$ sudo apt install iptables-persistent
$ sudo mkdir /etc/iptables
$ sudo sh -c "iptables-save > /etc/iptables/rules.v4"
```

# さいごに

かんたんでしたね