FTP passive-mode data channel fails: proxy attempts to connect to 0.0.0.0 from upstream PASV (connect('0.0.0.0', port))
## Summary
When using PandaProxy’s FTPS/FTP proxy with a Bambu printer, passive-mode FTP operations fail because PandaProxy attempts to open the upstream data connection to `0.0.0.0:<port>` (taken from the printer’s `PASV` response). `0.0.0.0` is not a valid remote destination address, so the data channel cannot be established and clients fail to list/download/upload files.
Direct FTPS from the client (Bambuddy) to the printer works correctly, so the failure appears to be in PandaProxy’s FTP passive data handling.
## Environment
- PandaProxy image: `ghcr.io/karaktaka/pandaproxy:latest`
- Repo/commit referenced: https://github.com/karaktaka/pandaproxy/blob/99f436fa1ff6ba09b6e278703b503d0a400b20e3/docker-compose.yml
- Deployment: Docker Compose, macvlan network, static IP on LAN
- Client: Bambuddy (self-hosted printer manager) using Python `ftplib` FTPS in passive mode
- Printer model: P1S (LAN-only + developer mode enabled)
## Network layout
- Printer IP: `192.168.50.28`
- PandaProxy IP (macvlan): `192.168.1.50`
- Client host (running Bambuddy): `192.168.1.77`
## Steps to reproduce
1. Run PandaProxy with FTPS enabled (default services include `ftp`).
2. Connect a passive-mode FTPS client to PandaProxy `ftps://192.168.1.50:990` (Bambuddy does this automatically; it forces passive mode via `ftplib.set_pasv(True)`).
3. Attempt any operation that requires an FTP data channel (e.g. `LIST`, `RETR`, etc.).
## Expected behavior
Passive-mode FTPS should work end-to-end through the proxy:
- Client connects to PandaProxy control channel (990)
- Client connects to PandaProxy-advertised passive data endpoint
- PandaProxy connects upstream to printer’s passive endpoint using the printer’s real IP
## Actual behavior
PandaProxy rewrites the PASV response for the client correctly, but fails when creating the upstream data connection because it attempts to connect to `0.0.0.0:<port>`:
Example logs:
`[INFO] pandaproxy.ftp_proxy: Rewrote PASV: 227 (0,0,0,0,7,232) -> 227 (192,168,1,50,167,207) [ERROR] pandaproxy.ftp_proxy: Data proxy error: [Errno 111] Connect call failed ('0.0.0.0', 2024)`
`2024` corresponds to the upstream PASV port `7*256 + 232`.
## Additional notes
- Setting `BIND_ADDRESS=192.168.1.50` (instead of `0.0.0.0`) does not resolve this, because the `0.0.0.0` appears to originate from the printer’s upstream PASV tuple.
- Direct Bambuddy → printer FTPS works correctly (same printer, same access code), which points to PandaProxy’s PASV upstream handling as the issue.
## Proposed fix / suggestion
When PandaProxy parses the upstream PASV reply:
- If the host portion is `0.0.0.0`, substitute the known `printer_ip` as the upstream data connection destination.
- i.e., connect upstream to `(printer_ip, pasv_port)` rather than `(0.0.0.0, pasv_port)`.
- Alternatively (and arguably better), always connect upstream data sockets to `printer_ip` and only use PASV for the port.
This would mirror the common NAT/proxy handling for FTP where upstream servers often return `0.0.0.0` or an unroutable/private address in `PASV`.
## Why this matters
Clients like Bambuddy (and other Bambu LAN tooling) use passive FTPS for retrieving files from the printer. With the current behavior, FTP operations through PandaProxy fail even though MQTT/camera proxying works.
issue