Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add flag to force use of local control host address #259

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

julianosk
Copy link

@julianosk julianosk commented Nov 12, 2024

The assumption in the enterPassiveModeIPv4 function (in src/transfer.ts:48) is that NAT is only used if the "control connection" uses a public IP address and the "data connection" uses a private IP address.

However, in our particular scenario this is not the case. Both the control connection and the data connection use an private IP address but we are using NAT. The correct behaviour in this case would be to ignore the IP address mentioned in the PASV-response and instead use the control IP address.

To ensure we don't change current behaviour, we would like to introduce a configuration option that always uses the IP address of the control connection, regardless of whether the IP address is public or private. This configuration flag, called alwaysUseControlHost, is passed in the contructor and defaults to false.

@julianosk julianosk changed the title feat: Add flag to use local control host address feat: Add flag to forse use of local control host address Nov 13, 2024
@julianosk julianosk changed the title feat: Add flag to forse use of local control host address feat: Add flag to force use of local control host address Nov 13, 2024
@stewartoallen
Copy link

stewartoallen commented Jan 29, 2025

funny, I was just preparing a PR for the same problem but a slightly different approach borrowed from lftp. I need this fixed to talk to Bambu printers over a NAT'd link.

/**
 * Prepare a data socket using passive mode over IPv4.
 */
export async function enterPassiveModeIPv4(ftp: FTPContext): Promise<FTPResponse> {
    const res = await ftp.request("PASV")
    const target = parsePasvResponse(res.message)
    if (!target) {
        throw new Error("Can't parse PASV response: " + res.message)
    }
    const controlHost = ftp.socket.remoteAddress
    // PASV over NAT'd connections results in invalid detected target host
    // Borrowing solution from lftp which simply falls back to the provided host
    if (target.host === '0.0.0.0' && controlHost) {
        ftp.log(`Invalid PASV host detected ${target.host}. Falling back to control host.`)
        target.host = controlHost
    }
    // If the host in the PASV response has a local address while the control connection hasn't,
    // we assume a NAT issue and use the IP of the control connection as the target for the data connection.
    // We can't always perform this replacement because it's possible (although unlikely) that the FTP server
    // indeed uses a different host for data connections.
    if (ipIsPrivateV4Address(target.host) && controlHost && !ipIsPrivateV4Address(controlHost)) {
        target.host = controlHost
    }
    await connectForPassiveTransfer(target.host, target.port, ftp)
    return res
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants