feat: allow dynamic pasv_url depending on remote address (#269)
Co-authored-by: Matt Forster <hey@mattforster.ca>
This commit is contained in:
26
README.md
26
README.md
@@ -73,7 +73,31 @@ _Note:_ The hostname must be the external IP address to accept external connecti
|
||||
__Default:__ `"ftp://127.0.0.1:21"`
|
||||
|
||||
#### `pasv_url`
|
||||
This **must** be the external WAN **IP address** that the FTP server is bound to. `FTP-srv` provides this IP address to the client when a `PASV` command is received in the handshake for a passive connection. Reference [PASV verb](https://cr.yp.to/ftp/retr.html#pasv).
|
||||
`FTP-srv` provides an IP address to the client when a `PASV` command is received in the handshake for a passive connection. Reference [PASV verb](https://cr.yp.to/ftp/retr.html#pasv). This can be one of two options:
|
||||
- A function which takes one parameter containing the remote IP address of the FTP client. This can be useful when the user wants to return a different IP address depending if the user is connecting from Internet or from an LAN address.
|
||||
```js
|
||||
const {Netmask} = require('netmask');
|
||||
const networks = {
|
||||
'$GATEWAY_IP/32': `${public_ip}`,
|
||||
'10.0.0.0/8' : `${lan_ip}`
|
||||
}
|
||||
|
||||
const resolverFunction = (address) => {
|
||||
for (const network in networks) {
|
||||
try {
|
||||
const mask = new Netmask(network);
|
||||
if (mask.contains(address)) return networks[network];
|
||||
}
|
||||
catch (err) {
|
||||
logger.error('Error checking source network', err);
|
||||
}
|
||||
}
|
||||
return '127.0.0.1';
|
||||
}
|
||||
|
||||
new FtpSrv({pasv_url: resolverFunction});
|
||||
- A static IP address (ie. an external WAN **IP address** that the FTP server is bound to). In this case, only connections from localhost are handled differently returning `127.0.0.1` to the client.
|
||||
|
||||
If not provided, clients can only connect using an `Active` connection.
|
||||
|
||||
#### `pasv_min`
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const Promise = require('bluebird');
|
||||
const PassiveConnector = require('../../connector/passive');
|
||||
const {isLocalIP} = require('../../helpers/is-local');
|
||||
|
||||
@@ -11,12 +12,17 @@ module.exports = {
|
||||
this.connector = new PassiveConnector(this);
|
||||
return this.connector.setupServer()
|
||||
.then((server) => {
|
||||
let address = this.server.options.pasv_url;
|
||||
// Allow connecting from local
|
||||
if (isLocalIP(this.ip)) {
|
||||
address = this.ip;
|
||||
}
|
||||
const {port} = server.address();
|
||||
let pasvAddress = this.server.options.pasv_url;
|
||||
if (typeof pasvAddress === "function") {
|
||||
return Promise.try(() => pasvAddress(this.ip))
|
||||
.then((address) => ({address, port}));
|
||||
}
|
||||
// Allow connecting from local
|
||||
if (isLocalIP(this.ip)) pasvAddress = this.ip;
|
||||
return {address: pasvAddress, port};
|
||||
})
|
||||
.then(({address, port}) => {
|
||||
const host = address.replace(/\./g, ',');
|
||||
const portByte1 = port / 256 | 0;
|
||||
const portByte2 = port % 256;
|
||||
|
||||
Reference in New Issue
Block a user